@alexjbarnes/cockpit 0.2.0 → 0.3.1

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 (695) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +16 -3
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +99 -3
  5. package/.next/react-loadable-manifest.json +18 -2
  6. package/.next/required-server-files.js +3 -0
  7. package/.next/required-server-files.json +3 -0
  8. package/.next/routes-manifest.json +86 -0
  9. package/.next/server/app/(app)/agents/[name]/page.js +2 -2
  10. package/.next/server/app/(app)/agents/[name]/page.js.nft.json +1 -1
  11. package/.next/server/app/(app)/agents/[name]/page_client-reference-manifest.js +1 -1
  12. package/.next/server/app/(app)/agents/page.js +2 -2
  13. package/.next/server/app/(app)/agents/page.js.nft.json +1 -1
  14. package/.next/server/app/(app)/agents/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/(app)/changes/page.js +2 -2
  16. package/.next/server/app/(app)/changes/page.js.nft.json +1 -1
  17. package/.next/server/app/(app)/changes/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/(app)/claude-md/edit/page.js +2 -2
  19. package/.next/server/app/(app)/claude-md/edit/page.js.nft.json +1 -1
  20. package/.next/server/app/(app)/claude-md/edit/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/(app)/claude-md/page.js +2 -2
  22. package/.next/server/app/(app)/claude-md/page.js.nft.json +1 -1
  23. package/.next/server/app/(app)/claude-md/page_client-reference-manifest.js +1 -1
  24. package/.next/server/app/(app)/commands/[name]/page.js +2 -2
  25. package/.next/server/app/(app)/commands/[name]/page.js.nft.json +1 -1
  26. package/.next/server/app/(app)/commands/[name]/page_client-reference-manifest.js +1 -1
  27. package/.next/server/app/(app)/commands/page.js +2 -2
  28. package/.next/server/app/(app)/commands/page.js.nft.json +1 -1
  29. package/.next/server/app/(app)/commands/page_client-reference-manifest.js +1 -1
  30. package/.next/server/app/(app)/files/page.js +2 -2
  31. package/.next/server/app/(app)/files/page.js.nft.json +1 -1
  32. package/.next/server/app/(app)/files/page_client-reference-manifest.js +1 -1
  33. package/.next/server/app/(app)/hooks/[event]/page.js +3 -3
  34. package/.next/server/app/(app)/hooks/[event]/page.js.nft.json +1 -1
  35. package/.next/server/app/(app)/hooks/[event]/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/(app)/hooks/page.js +2 -2
  37. package/.next/server/app/(app)/hooks/page.js.nft.json +1 -1
  38. package/.next/server/app/(app)/hooks/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/(app)/inbox/[id]/page.js +2 -2
  40. package/.next/server/app/(app)/inbox/[id]/page.js.nft.json +1 -1
  41. package/.next/server/app/(app)/inbox/[id]/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/(app)/inbox/page.js +2 -2
  43. package/.next/server/app/(app)/inbox/page.js.nft.json +1 -1
  44. package/.next/server/app/(app)/inbox/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app/(app)/jobs/[id]/edit/page.js +2 -2
  46. package/.next/server/app/(app)/jobs/[id]/edit/page.js.nft.json +1 -1
  47. package/.next/server/app/(app)/jobs/[id]/edit/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/(app)/jobs/[id]/page.js +2 -2
  49. package/.next/server/app/(app)/jobs/[id]/page.js.nft.json +1 -1
  50. package/.next/server/app/(app)/jobs/[id]/page_client-reference-manifest.js +1 -1
  51. package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page.js +2 -2
  52. package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page.js.nft.json +1 -1
  53. package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/(app)/jobs/page.js +2 -2
  55. package/.next/server/app/(app)/jobs/page.js.nft.json +1 -1
  56. package/.next/server/app/(app)/jobs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/(app)/mcp-servers/[name]/page.js +2 -2
  58. package/.next/server/app/(app)/mcp-servers/[name]/page.js.nft.json +1 -1
  59. package/.next/server/app/(app)/mcp-servers/[name]/page_client-reference-manifest.js +1 -1
  60. package/.next/server/app/(app)/mcp-servers/page.js +2 -2
  61. package/.next/server/app/(app)/mcp-servers/page.js.nft.json +1 -1
  62. package/.next/server/app/(app)/mcp-servers/page_client-reference-manifest.js +1 -1
  63. package/.next/server/app/(app)/page.js +2 -2
  64. package/.next/server/app/(app)/page.js.nft.json +1 -1
  65. package/.next/server/app/(app)/page_client-reference-manifest.js +1 -1
  66. package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page.js +10 -10
  67. package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page.js.nft.json +1 -1
  68. package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page_client-reference-manifest.js +1 -1
  69. package/.next/server/app/(app)/reviews/[owner]/[repo]/page.js +2 -2
  70. package/.next/server/app/(app)/reviews/[owner]/[repo]/page.js.nft.json +1 -1
  71. package/.next/server/app/(app)/reviews/[owner]/[repo]/page_client-reference-manifest.js +1 -1
  72. package/.next/server/app/(app)/reviews/page.js +2 -2
  73. package/.next/server/app/(app)/reviews/page.js.nft.json +1 -1
  74. package/.next/server/app/(app)/reviews/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/(app)/sessions/[id]/page.js +2 -2
  76. package/.next/server/app/(app)/sessions/[id]/page.js.nft.json +1 -1
  77. package/.next/server/app/(app)/sessions/[id]/page_client-reference-manifest.js +1 -1
  78. package/.next/server/app/(app)/settings/appearance/page.js +2 -0
  79. package/.next/server/app/(app)/settings/appearance/page.js.nft.json +1 -0
  80. package/.next/server/app/(app)/settings/appearance/page_client-reference-manifest.js +1 -0
  81. package/.next/server/app/(app)/settings/notifications/page.js +2 -2
  82. package/.next/server/app/(app)/settings/notifications/page.js.nft.json +1 -1
  83. package/.next/server/app/(app)/settings/notifications/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/(app)/settings/page.js +2 -2
  85. package/.next/server/app/(app)/settings/page.js.nft.json +1 -1
  86. package/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
  87. package/.next/server/app/(app)/settings/providers/[id]/page.js +2 -0
  88. package/.next/server/app/(app)/settings/providers/[id]/page.js.nft.json +1 -0
  89. package/.next/server/app/(app)/settings/providers/[id]/page_client-reference-manifest.js +1 -0
  90. package/.next/server/app/(app)/settings/providers/new/page.js +2 -0
  91. package/.next/server/app/(app)/settings/providers/new/page.js.nft.json +1 -0
  92. package/.next/server/app/(app)/settings/providers/new/page_client-reference-manifest.js +1 -0
  93. package/.next/server/app/(app)/settings/providers/page.js +2 -0
  94. package/.next/server/app/(app)/settings/providers/page.js.nft.json +1 -0
  95. package/.next/server/app/(app)/settings/providers/page_client-reference-manifest.js +1 -0
  96. package/.next/server/app/(app)/settings/session/page.js +2 -0
  97. package/.next/server/app/(app)/settings/session/page.js.nft.json +1 -0
  98. package/.next/server/app/(app)/settings/session/page_client-reference-manifest.js +1 -0
  99. package/.next/server/app/(app)/skills/[name]/page.js +3 -3
  100. package/.next/server/app/(app)/skills/[name]/page.js.nft.json +1 -1
  101. package/.next/server/app/(app)/skills/[name]/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/(app)/skills/page.js +2 -2
  103. package/.next/server/app/(app)/skills/page.js.nft.json +1 -1
  104. package/.next/server/app/(app)/skills/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/_global-error/page.js +3 -3
  106. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  107. package/.next/server/app/_global-error.html +1 -1
  108. package/.next/server/app/_global-error.rsc +1 -1
  109. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  110. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  111. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  112. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  113. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  114. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  115. package/.next/server/app/_not-found/page.js +2 -2
  116. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/_not-found.html +1 -1
  118. package/.next/server/app/_not-found.rsc +2 -2
  119. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  120. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  121. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  122. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  123. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  124. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  125. package/.next/server/app/agents.html +1 -1
  126. package/.next/server/app/agents.rsc +4 -4
  127. package/.next/server/app/agents.segments/!KGFwcCk/agents/__PAGE__.segment.rsc +2 -2
  128. package/.next/server/app/agents.segments/!KGFwcCk/agents.segment.rsc +1 -1
  129. package/.next/server/app/agents.segments/!KGFwcCk.segment.rsc +2 -2
  130. package/.next/server/app/agents.segments/_full.segment.rsc +4 -4
  131. package/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  132. package/.next/server/app/agents.segments/_index.segment.rsc +2 -2
  133. package/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
  134. package/.next/server/app/api/agents/[name]/route.js +1 -1
  135. package/.next/server/app/api/agents/route.js +1 -1
  136. package/.next/server/app/api/auth/check/route.js +1 -1
  137. package/.next/server/app/api/auth/login/route.js +1 -1
  138. package/.next/server/app/api/auth/setup/route.js +1 -1
  139. package/.next/server/app/api/auth/ws-token/route.js +1 -1
  140. package/.next/server/app/api/btw/route.js +2 -2
  141. package/.next/server/app/api/claude-md/route.js +1 -1
  142. package/.next/server/app/api/commands/[name]/route.js +1 -1
  143. package/.next/server/app/api/commands/route.js +1 -1
  144. package/.next/server/app/api/defaults/route.js +1 -1
  145. package/.next/server/app/api/filesystem/browse/route.js +1 -1
  146. package/.next/server/app/api/filesystem/files/route.js +1 -1
  147. package/.next/server/app/api/filesystem/mkdir/route.js +1 -1
  148. package/.next/server/app/api/filesystem/read/route.js +1 -1
  149. package/.next/server/app/api/git/clone/route.js +1 -1
  150. package/.next/server/app/api/git/commit/route.js +1 -1
  151. package/.next/server/app/api/git/diff/route.js +1 -1
  152. package/.next/server/app/api/git/discard/route.js +1 -1
  153. package/.next/server/app/api/git/generate-message/route.js +2 -2
  154. package/.next/server/app/api/git/push/route.js +1 -1
  155. package/.next/server/app/api/git/status/route.js +1 -1
  156. package/.next/server/app/api/github/file-content/route.js +1 -1
  157. package/.next/server/app/api/github/orgs/route.js +1 -1
  158. package/.next/server/app/api/github/prs/checks/route.js +1 -1
  159. package/.next/server/app/api/github/prs/diff/route.js +1 -1
  160. package/.next/server/app/api/github/prs/review/route.js +1 -1
  161. package/.next/server/app/api/github/prs/route.js +1 -1
  162. package/.next/server/app/api/github/prs/view/route.js +1 -1
  163. package/.next/server/app/api/github/repos/route.js +1 -1
  164. package/.next/server/app/api/github/review-session/route.js +1 -1
  165. package/.next/server/app/api/github/review-session/route.js.nft.json +1 -1
  166. package/.next/server/app/api/health/route.js +1 -1
  167. package/.next/server/app/api/hooks/route.js +1 -1
  168. package/.next/server/app/api/inbox/[id]/route.js +2 -2
  169. package/.next/server/app/api/inbox/route.js +2 -2
  170. package/.next/server/app/api/jobs/[id]/route.js +1 -1
  171. package/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -1
  172. package/.next/server/app/api/jobs/[id]/runs/[runId]/route.js +1 -1
  173. package/.next/server/app/api/jobs/[id]/runs/[runId]/transcript/route.js +1 -1
  174. package/.next/server/app/api/jobs/[id]/runs/route.js +1 -1
  175. package/.next/server/app/api/jobs/[id]/trigger/route.js +1 -1
  176. package/.next/server/app/api/jobs/[id]/trigger/route.js.nft.json +1 -1
  177. package/.next/server/app/api/jobs/mcp-discover/route.js +1 -1
  178. package/.next/server/app/api/jobs/mcp-discover/route.js.nft.json +1 -1
  179. package/.next/server/app/api/jobs/route.js +1 -1
  180. package/.next/server/app/api/jobs/route.js.nft.json +1 -1
  181. package/.next/server/app/api/jobs/status/route.js +1 -1
  182. package/.next/server/app/api/mcp-servers/[name]/route.js +1 -1
  183. package/.next/server/app/api/mcp-servers/[name]/test/route.js +1 -1
  184. package/.next/server/app/api/mcp-servers/route.js +1 -1
  185. package/.next/server/app/api/notifications/route.js +1 -1
  186. package/.next/server/app/api/notifications/test/route.js +1 -1
  187. package/.next/server/app/api/providers/[id]/route.js +1 -0
  188. package/.next/server/app/api/providers/[id]/route.js.nft.json +1 -0
  189. package/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -0
  190. package/.next/server/app/api/providers/route.js +1 -0
  191. package/.next/server/app/api/providers/route.js.nft.json +1 -0
  192. package/.next/server/app/api/providers/route_client-reference-manifest.js +1 -0
  193. package/.next/server/app/api/reviews/pinned/route.js +1 -1
  194. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  195. package/.next/server/app/api/sessions/[id]/mcp/route.js +1 -1
  196. package/.next/server/app/api/sessions/[id]/mcp/route.js.nft.json +1 -1
  197. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  198. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  199. package/.next/server/app/api/sessions/[id]/search/route.js +1 -1
  200. package/.next/server/app/api/sessions/[id]/tabs/route.js +1 -0
  201. package/.next/server/app/api/sessions/[id]/tabs/route.js.nft.json +1 -0
  202. package/.next/server/app/api/sessions/[id]/tabs/route_client-reference-manifest.js +1 -0
  203. package/.next/server/app/api/sessions/bulk-delete/route.js +1 -1
  204. package/.next/server/app/api/sessions/bulk-delete/route.js.nft.json +1 -1
  205. package/.next/server/app/api/sessions/by-ids/route.js +1 -1
  206. package/.next/server/app/api/sessions/by-ids/route.js.nft.json +1 -1
  207. package/.next/server/app/api/sessions/group/route.js +1 -1
  208. package/.next/server/app/api/sessions/group/route.js.nft.json +1 -1
  209. package/.next/server/app/api/sessions/pinned/route.js +1 -1
  210. package/.next/server/app/api/sessions/route.js +1 -1
  211. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  212. package/.next/server/app/api/sessions/search/route.js +1 -1
  213. package/.next/server/app/api/sessions/thinking/route.js +1 -0
  214. package/.next/server/app/api/sessions/thinking/route.js.nft.json +1 -0
  215. package/.next/server/app/api/sessions/thinking/route_client-reference-manifest.js +1 -0
  216. package/.next/server/app/api/skills/[name]/route.js +1 -1
  217. package/.next/server/app/api/skills/route.js +1 -1
  218. package/.next/server/app/api/terminal/[id]/route.js +1 -0
  219. package/.next/server/app/api/terminal/[id]/route.js.nft.json +1 -0
  220. package/.next/server/app/api/terminal/[id]/route_client-reference-manifest.js +1 -0
  221. package/.next/server/app/api/terminal/route.js +1 -0
  222. package/.next/server/app/api/terminal/route.js.nft.json +1 -0
  223. package/.next/server/app/api/terminal/route_client-reference-manifest.js +1 -0
  224. package/.next/server/app/api/usage/route.js +1 -1
  225. package/.next/server/app/api/version/changelog/route.js +1 -0
  226. package/.next/server/app/api/version/changelog/route.js.nft.json +1 -0
  227. package/.next/server/app/api/version/changelog/route_client-reference-manifest.js +1 -0
  228. package/.next/server/app/api/version/cockpit/changelog/route.js +1 -0
  229. package/.next/server/app/api/version/cockpit/changelog/route.js.nft.json +1 -0
  230. package/.next/server/app/api/version/cockpit/changelog/route_client-reference-manifest.js +1 -0
  231. package/.next/server/app/api/version/cockpit/route.js +1 -1
  232. package/.next/server/app/api/version/route.js +2 -2
  233. package/.next/server/app/changes.html +1 -1
  234. package/.next/server/app/changes.rsc +4 -4
  235. package/.next/server/app/changes.segments/!KGFwcCk/changes/__PAGE__.segment.rsc +2 -2
  236. package/.next/server/app/changes.segments/!KGFwcCk/changes.segment.rsc +1 -1
  237. package/.next/server/app/changes.segments/!KGFwcCk.segment.rsc +2 -2
  238. package/.next/server/app/changes.segments/_full.segment.rsc +4 -4
  239. package/.next/server/app/changes.segments/_head.segment.rsc +1 -1
  240. package/.next/server/app/changes.segments/_index.segment.rsc +2 -2
  241. package/.next/server/app/changes.segments/_tree.segment.rsc +2 -2
  242. package/.next/server/app/claude-md/edit.html +1 -1
  243. package/.next/server/app/claude-md/edit.rsc +4 -4
  244. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit/__PAGE__.segment.rsc +2 -2
  245. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit.segment.rsc +1 -1
  246. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
  247. package/.next/server/app/claude-md/edit.segments/!KGFwcCk.segment.rsc +2 -2
  248. package/.next/server/app/claude-md/edit.segments/_full.segment.rsc +4 -4
  249. package/.next/server/app/claude-md/edit.segments/_head.segment.rsc +1 -1
  250. package/.next/server/app/claude-md/edit.segments/_index.segment.rsc +2 -2
  251. package/.next/server/app/claude-md/edit.segments/_tree.segment.rsc +2 -2
  252. package/.next/server/app/claude-md.html +1 -1
  253. package/.next/server/app/claude-md.rsc +4 -4
  254. package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md/__PAGE__.segment.rsc +2 -2
  255. package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
  256. package/.next/server/app/claude-md.segments/!KGFwcCk.segment.rsc +2 -2
  257. package/.next/server/app/claude-md.segments/_full.segment.rsc +4 -4
  258. package/.next/server/app/claude-md.segments/_head.segment.rsc +1 -1
  259. package/.next/server/app/claude-md.segments/_index.segment.rsc +2 -2
  260. package/.next/server/app/claude-md.segments/_tree.segment.rsc +2 -2
  261. package/.next/server/app/commands.html +1 -1
  262. package/.next/server/app/commands.rsc +4 -4
  263. package/.next/server/app/commands.segments/!KGFwcCk/commands/__PAGE__.segment.rsc +2 -2
  264. package/.next/server/app/commands.segments/!KGFwcCk/commands.segment.rsc +1 -1
  265. package/.next/server/app/commands.segments/!KGFwcCk.segment.rsc +2 -2
  266. package/.next/server/app/commands.segments/_full.segment.rsc +4 -4
  267. package/.next/server/app/commands.segments/_head.segment.rsc +1 -1
  268. package/.next/server/app/commands.segments/_index.segment.rsc +2 -2
  269. package/.next/server/app/commands.segments/_tree.segment.rsc +2 -2
  270. package/.next/server/app/files.html +1 -1
  271. package/.next/server/app/files.rsc +4 -4
  272. package/.next/server/app/files.segments/!KGFwcCk/files/__PAGE__.segment.rsc +2 -2
  273. package/.next/server/app/files.segments/!KGFwcCk/files.segment.rsc +1 -1
  274. package/.next/server/app/files.segments/!KGFwcCk.segment.rsc +2 -2
  275. package/.next/server/app/files.segments/_full.segment.rsc +4 -4
  276. package/.next/server/app/files.segments/_head.segment.rsc +1 -1
  277. package/.next/server/app/files.segments/_index.segment.rsc +2 -2
  278. package/.next/server/app/files.segments/_tree.segment.rsc +2 -2
  279. package/.next/server/app/hooks.html +1 -1
  280. package/.next/server/app/hooks.rsc +4 -4
  281. package/.next/server/app/hooks.segments/!KGFwcCk/hooks/__PAGE__.segment.rsc +2 -2
  282. package/.next/server/app/hooks.segments/!KGFwcCk/hooks.segment.rsc +1 -1
  283. package/.next/server/app/hooks.segments/!KGFwcCk.segment.rsc +2 -2
  284. package/.next/server/app/hooks.segments/_full.segment.rsc +4 -4
  285. package/.next/server/app/hooks.segments/_head.segment.rsc +1 -1
  286. package/.next/server/app/hooks.segments/_index.segment.rsc +2 -2
  287. package/.next/server/app/hooks.segments/_tree.segment.rsc +2 -2
  288. package/.next/server/app/inbox.html +1 -1
  289. package/.next/server/app/inbox.rsc +4 -4
  290. package/.next/server/app/inbox.segments/!KGFwcCk/inbox/__PAGE__.segment.rsc +2 -2
  291. package/.next/server/app/inbox.segments/!KGFwcCk/inbox.segment.rsc +1 -1
  292. package/.next/server/app/inbox.segments/!KGFwcCk.segment.rsc +2 -2
  293. package/.next/server/app/inbox.segments/_full.segment.rsc +4 -4
  294. package/.next/server/app/inbox.segments/_head.segment.rsc +1 -1
  295. package/.next/server/app/inbox.segments/_index.segment.rsc +2 -2
  296. package/.next/server/app/inbox.segments/_tree.segment.rsc +2 -2
  297. package/.next/server/app/index.html +1 -1
  298. package/.next/server/app/index.rsc +4 -4
  299. package/.next/server/app/index.segments/!KGFwcCk/__PAGE__.segment.rsc +2 -2
  300. package/.next/server/app/index.segments/!KGFwcCk.segment.rsc +2 -2
  301. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  302. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  303. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  304. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  305. package/.next/server/app/jobs.html +1 -1
  306. package/.next/server/app/jobs.rsc +4 -4
  307. package/.next/server/app/jobs.segments/!KGFwcCk/jobs/__PAGE__.segment.rsc +2 -2
  308. package/.next/server/app/jobs.segments/!KGFwcCk/jobs.segment.rsc +1 -1
  309. package/.next/server/app/jobs.segments/!KGFwcCk.segment.rsc +2 -2
  310. package/.next/server/app/jobs.segments/_full.segment.rsc +4 -4
  311. package/.next/server/app/jobs.segments/_head.segment.rsc +1 -1
  312. package/.next/server/app/jobs.segments/_index.segment.rsc +2 -2
  313. package/.next/server/app/jobs.segments/_tree.segment.rsc +2 -2
  314. package/.next/server/app/login/page.js +2 -2
  315. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  316. package/.next/server/app/login.html +1 -1
  317. package/.next/server/app/login.rsc +2 -2
  318. package/.next/server/app/login.segments/_full.segment.rsc +2 -2
  319. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  320. package/.next/server/app/login.segments/_index.segment.rsc +2 -2
  321. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  322. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  323. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  324. package/.next/server/app/mcp-servers.html +1 -1
  325. package/.next/server/app/mcp-servers.rsc +4 -4
  326. package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers/__PAGE__.segment.rsc +2 -2
  327. package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers.segment.rsc +1 -1
  328. package/.next/server/app/mcp-servers.segments/!KGFwcCk.segment.rsc +2 -2
  329. package/.next/server/app/mcp-servers.segments/_full.segment.rsc +4 -4
  330. package/.next/server/app/mcp-servers.segments/_head.segment.rsc +1 -1
  331. package/.next/server/app/mcp-servers.segments/_index.segment.rsc +2 -2
  332. package/.next/server/app/mcp-servers.segments/_tree.segment.rsc +2 -2
  333. package/.next/server/app/reviews.html +1 -1
  334. package/.next/server/app/reviews.rsc +4 -4
  335. package/.next/server/app/reviews.segments/!KGFwcCk/reviews/__PAGE__.segment.rsc +2 -2
  336. package/.next/server/app/reviews.segments/!KGFwcCk/reviews.segment.rsc +1 -1
  337. package/.next/server/app/reviews.segments/!KGFwcCk.segment.rsc +2 -2
  338. package/.next/server/app/reviews.segments/_full.segment.rsc +4 -4
  339. package/.next/server/app/reviews.segments/_head.segment.rsc +1 -1
  340. package/.next/server/app/reviews.segments/_index.segment.rsc +2 -2
  341. package/.next/server/app/reviews.segments/_tree.segment.rsc +2 -2
  342. package/.next/server/app/settings/appearance.html +1 -0
  343. package/.next/server/app/settings/appearance.meta +17 -0
  344. package/.next/server/app/settings/appearance.rsc +23 -0
  345. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance/__PAGE__.segment.rsc +9 -0
  346. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance.segment.rsc +5 -0
  347. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings.segment.rsc +5 -0
  348. package/.next/server/app/settings/appearance.segments/!KGFwcCk.segment.rsc +7 -0
  349. package/.next/server/app/settings/appearance.segments/_full.segment.rsc +23 -0
  350. package/.next/server/app/settings/appearance.segments/_head.segment.rsc +6 -0
  351. package/.next/server/app/settings/appearance.segments/_index.segment.rsc +5 -0
  352. package/.next/server/app/settings/appearance.segments/_tree.segment.rsc +2 -0
  353. package/.next/server/app/settings/notifications.html +1 -1
  354. package/.next/server/app/settings/notifications.rsc +4 -4
  355. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications/__PAGE__.segment.rsc +2 -2
  356. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications.segment.rsc +1 -1
  357. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings.segment.rsc +1 -1
  358. package/.next/server/app/settings/notifications.segments/!KGFwcCk.segment.rsc +2 -2
  359. package/.next/server/app/settings/notifications.segments/_full.segment.rsc +4 -4
  360. package/.next/server/app/settings/notifications.segments/_head.segment.rsc +1 -1
  361. package/.next/server/app/settings/notifications.segments/_index.segment.rsc +2 -2
  362. package/.next/server/app/settings/notifications.segments/_tree.segment.rsc +2 -2
  363. package/.next/server/app/settings/providers/new.html +1 -0
  364. package/.next/server/app/settings/providers/new.meta +18 -0
  365. package/.next/server/app/settings/providers/new.rsc +23 -0
  366. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new/__PAGE__.segment.rsc +9 -0
  367. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new.segment.rsc +5 -0
  368. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
  369. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings.segment.rsc +5 -0
  370. package/.next/server/app/settings/providers/new.segments/!KGFwcCk.segment.rsc +7 -0
  371. package/.next/server/app/settings/providers/new.segments/_full.segment.rsc +23 -0
  372. package/.next/server/app/settings/providers/new.segments/_head.segment.rsc +6 -0
  373. package/.next/server/app/settings/providers/new.segments/_index.segment.rsc +5 -0
  374. package/.next/server/app/settings/providers/new.segments/_tree.segment.rsc +2 -0
  375. package/.next/server/app/settings/providers.html +1 -0
  376. package/.next/server/app/settings/providers.meta +17 -0
  377. package/.next/server/app/settings/providers.rsc +23 -0
  378. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers/__PAGE__.segment.rsc +9 -0
  379. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
  380. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings.segment.rsc +5 -0
  381. package/.next/server/app/settings/providers.segments/!KGFwcCk.segment.rsc +7 -0
  382. package/.next/server/app/settings/providers.segments/_full.segment.rsc +23 -0
  383. package/.next/server/app/settings/providers.segments/_head.segment.rsc +6 -0
  384. package/.next/server/app/settings/providers.segments/_index.segment.rsc +5 -0
  385. package/.next/server/app/settings/providers.segments/_tree.segment.rsc +2 -0
  386. package/.next/server/app/settings/session.html +1 -0
  387. package/.next/server/app/settings/session.meta +17 -0
  388. package/.next/server/app/settings/session.rsc +23 -0
  389. package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session/__PAGE__.segment.rsc +9 -0
  390. package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session.segment.rsc +5 -0
  391. package/.next/server/app/settings/session.segments/!KGFwcCk/settings.segment.rsc +5 -0
  392. package/.next/server/app/settings/session.segments/!KGFwcCk.segment.rsc +7 -0
  393. package/.next/server/app/settings/session.segments/_full.segment.rsc +23 -0
  394. package/.next/server/app/settings/session.segments/_head.segment.rsc +6 -0
  395. package/.next/server/app/settings/session.segments/_index.segment.rsc +5 -0
  396. package/.next/server/app/settings/session.segments/_tree.segment.rsc +2 -0
  397. package/.next/server/app/settings.html +1 -1
  398. package/.next/server/app/settings.rsc +4 -4
  399. package/.next/server/app/settings.segments/!KGFwcCk/settings/__PAGE__.segment.rsc +2 -2
  400. package/.next/server/app/settings.segments/!KGFwcCk/settings.segment.rsc +1 -1
  401. package/.next/server/app/settings.segments/!KGFwcCk.segment.rsc +2 -2
  402. package/.next/server/app/settings.segments/_full.segment.rsc +4 -4
  403. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  404. package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  405. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  406. package/.next/server/app/skills.html +1 -1
  407. package/.next/server/app/skills.rsc +4 -4
  408. package/.next/server/app/skills.segments/!KGFwcCk/skills/__PAGE__.segment.rsc +2 -2
  409. package/.next/server/app/skills.segments/!KGFwcCk/skills.segment.rsc +1 -1
  410. package/.next/server/app/skills.segments/!KGFwcCk.segment.rsc +2 -2
  411. package/.next/server/app/skills.segments/_full.segment.rsc +4 -4
  412. package/.next/server/app/skills.segments/_head.segment.rsc +1 -1
  413. package/.next/server/app/skills.segments/_index.segment.rsc +2 -2
  414. package/.next/server/app/skills.segments/_tree.segment.rsc +2 -2
  415. package/.next/server/app-paths-manifest.json +16 -3
  416. package/.next/server/chunks/1002.js +18 -0
  417. package/.next/server/chunks/1011.js +1 -0
  418. package/.next/server/chunks/1659.js +1 -1
  419. package/.next/server/chunks/1979.js +2 -2
  420. package/.next/server/chunks/2408.js +1 -1
  421. package/.next/server/chunks/{7627.js → 3006.js} +3 -3
  422. package/.next/server/chunks/3434.js +1 -0
  423. package/.next/server/chunks/{5920.js → 4342.js} +1 -1
  424. package/.next/server/chunks/4352.js +1 -0
  425. package/.next/server/chunks/4445.js +1 -1
  426. package/.next/server/chunks/7782.js +6 -0
  427. package/.next/server/chunks/8148.js +1 -0
  428. package/.next/server/chunks/9599.js +11 -0
  429. package/.next/server/middleware-build-manifest.js +1 -1
  430. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  431. package/.next/server/pages/404.html +1 -1
  432. package/.next/server/pages/500.html +1 -1
  433. package/.next/server/server-reference-manifest.json +1 -1
  434. package/.next/static/I-rxZaJEzhe3ZUTjSqB11/_buildManifest.js +1 -0
  435. package/.next/static/chunks/{35922.5bdf78a760129504.js → 13541.056c34ca7fde6869.js} +1 -1
  436. package/.next/static/chunks/26126-97874904b42befb8.js +1 -0
  437. package/.next/static/chunks/31010-6e87f77b97544424.js +1 -0
  438. package/.next/static/chunks/3765-d323c6675307a63e.js +20 -0
  439. package/.next/static/chunks/{11242-d240a18d4e59390b.js → 41487-d802643f4a8fad3c.js} +5 -5
  440. package/.next/static/chunks/48273-fb393846bb4333c0.js +6 -0
  441. package/.next/static/chunks/63606.a387b0261d6523ab.js +1 -0
  442. package/.next/static/chunks/6935-f436a624267529fb.js +1 -0
  443. package/.next/static/chunks/{69427.0f379c6bdea95405.js → 69427.a0b463c808aa54c8.js} +1 -1
  444. package/.next/static/chunks/86939-dfc6f8eb395caa89.js +1 -0
  445. package/.next/static/chunks/app/(app)/agents/[name]/page-8bdd0359043537d4.js +8 -0
  446. package/.next/static/chunks/app/(app)/agents/page-6fcfd7ab6781814e.js +1 -0
  447. package/.next/static/chunks/app/(app)/changes/page-4549a5bd72d77e3e.js +1 -0
  448. package/.next/static/chunks/app/(app)/claude-md/edit/page-08e6e120e71979f4.js +1 -0
  449. package/.next/static/chunks/app/(app)/claude-md/page-cd9e2176a12ba241.js +1 -0
  450. package/.next/static/chunks/app/(app)/commands/[name]/page-7cdfdef29ded0aa0.js +6 -0
  451. package/.next/static/chunks/app/(app)/commands/page-f126b608b04747ac.js +1 -0
  452. package/.next/static/chunks/app/(app)/files/page-f526eb95821e000e.js +1 -0
  453. package/.next/static/chunks/app/(app)/hooks/[event]/page-28038323fd29adfa.js +6 -0
  454. package/.next/static/chunks/app/(app)/hooks/page-f1f39284e53c0344.js +1 -0
  455. package/.next/static/chunks/app/(app)/inbox/[id]/page-bc1ff3a0db0114a4.js +1 -0
  456. package/.next/static/chunks/app/(app)/inbox/page-82e03870103ce9bd.js +1 -0
  457. package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-7fb788f772ff2129.js +1 -0
  458. package/.next/static/chunks/app/(app)/jobs/[id]/page-a5856b9ae967ff59.js +1 -0
  459. package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-b7c513402db11db6.js +1 -0
  460. package/.next/static/chunks/app/(app)/jobs/page-e9bbd6c116b9699f.js +1 -0
  461. package/.next/static/chunks/app/(app)/{layout-81c1899969de11e6.js → layout-ce9e1be301c60fe5.js} +1 -1
  462. package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-d6d805a27ec0b0c0.js +1 -0
  463. package/.next/static/chunks/app/(app)/mcp-servers/page-4b7276d43451cd43.js +1 -0
  464. package/.next/static/chunks/app/(app)/page-027a5382da30ddb9.js +1 -0
  465. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-9ab2955c455bb5fa.js +13 -0
  466. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/{page-c7473a899c7c59c3.js → page-c5fd013309ab3eba.js} +1 -1
  467. package/.next/static/chunks/app/(app)/reviews/{page-0e6e7395a4f62b50.js → page-47530d93bb9d4a76.js} +1 -1
  468. package/.next/static/chunks/app/(app)/sessions/[id]/page-94f891e1b54fd05f.js +1 -0
  469. package/.next/static/chunks/app/(app)/settings/appearance/page-95902da748ac5f1e.js +1 -0
  470. package/.next/static/chunks/app/(app)/settings/notifications/{page-a28db2ebc9fd0de8.js → page-229f1db6beb1d19c.js} +1 -1
  471. package/.next/static/chunks/app/(app)/settings/page-8ed16a66fdde10cd.js +1 -0
  472. package/.next/static/chunks/app/(app)/settings/providers/[id]/page-13654263246617b3.js +1 -0
  473. package/.next/static/chunks/app/(app)/settings/providers/new/page-e1798e321ccbc6df.js +1 -0
  474. package/.next/static/chunks/app/(app)/settings/providers/page-0bb4c1db2ee35b3d.js +1 -0
  475. package/.next/static/chunks/app/(app)/settings/session/page-ab216a8fa37a0f76.js +1 -0
  476. package/.next/static/chunks/app/(app)/skills/[name]/page-8ab85d5090967ee4.js +6 -0
  477. package/.next/static/chunks/app/(app)/skills/page-c52773eacb27c04e.js +1 -0
  478. package/.next/static/chunks/app/_global-error/page-fc747760bd4c8a4b.js +1 -0
  479. package/.next/static/chunks/app/api/agents/[name]/route-fc747760bd4c8a4b.js +1 -0
  480. package/.next/static/chunks/app/api/agents/route-fc747760bd4c8a4b.js +1 -0
  481. package/.next/static/chunks/app/api/auth/check/route-fc747760bd4c8a4b.js +1 -0
  482. package/.next/static/chunks/app/api/auth/login/route-fc747760bd4c8a4b.js +1 -0
  483. package/.next/static/chunks/app/api/auth/setup/route-fc747760bd4c8a4b.js +1 -0
  484. package/.next/static/chunks/app/api/auth/ws-token/route-fc747760bd4c8a4b.js +1 -0
  485. package/.next/static/chunks/app/api/btw/route-fc747760bd4c8a4b.js +1 -0
  486. package/.next/static/chunks/app/api/claude-md/route-fc747760bd4c8a4b.js +1 -0
  487. package/.next/static/chunks/app/api/commands/[name]/route-fc747760bd4c8a4b.js +1 -0
  488. package/.next/static/chunks/app/api/commands/route-fc747760bd4c8a4b.js +1 -0
  489. package/.next/static/chunks/app/api/defaults/route-fc747760bd4c8a4b.js +1 -0
  490. package/.next/static/chunks/app/api/filesystem/browse/route-fc747760bd4c8a4b.js +1 -0
  491. package/.next/static/chunks/app/api/filesystem/files/route-fc747760bd4c8a4b.js +1 -0
  492. package/.next/static/chunks/app/api/filesystem/mkdir/route-fc747760bd4c8a4b.js +1 -0
  493. package/.next/static/chunks/app/api/filesystem/read/route-fc747760bd4c8a4b.js +1 -0
  494. package/.next/static/chunks/app/api/git/clone/route-fc747760bd4c8a4b.js +1 -0
  495. package/.next/static/chunks/app/api/git/commit/route-fc747760bd4c8a4b.js +1 -0
  496. package/.next/static/chunks/app/api/git/diff/route-fc747760bd4c8a4b.js +1 -0
  497. package/.next/static/chunks/app/api/git/discard/route-fc747760bd4c8a4b.js +1 -0
  498. package/.next/static/chunks/app/api/git/generate-message/route-fc747760bd4c8a4b.js +1 -0
  499. package/.next/static/chunks/app/api/git/push/route-fc747760bd4c8a4b.js +1 -0
  500. package/.next/static/chunks/app/api/git/status/route-fc747760bd4c8a4b.js +1 -0
  501. package/.next/static/chunks/app/api/github/file-content/route-fc747760bd4c8a4b.js +1 -0
  502. package/.next/static/chunks/app/api/github/orgs/route-fc747760bd4c8a4b.js +1 -0
  503. package/.next/static/chunks/app/api/github/prs/checks/route-fc747760bd4c8a4b.js +1 -0
  504. package/.next/static/chunks/app/api/github/prs/diff/route-fc747760bd4c8a4b.js +1 -0
  505. package/.next/static/chunks/app/api/github/prs/review/route-fc747760bd4c8a4b.js +1 -0
  506. package/.next/static/chunks/app/api/github/prs/route-fc747760bd4c8a4b.js +1 -0
  507. package/.next/static/chunks/app/api/github/prs/view/route-fc747760bd4c8a4b.js +1 -0
  508. package/.next/static/chunks/app/api/github/repos/route-fc747760bd4c8a4b.js +1 -0
  509. package/.next/static/chunks/app/api/github/review-session/route-fc747760bd4c8a4b.js +1 -0
  510. package/.next/static/chunks/app/api/health/route-fc747760bd4c8a4b.js +1 -0
  511. package/.next/static/chunks/app/api/hooks/route-fc747760bd4c8a4b.js +1 -0
  512. package/.next/static/chunks/app/api/inbox/[id]/route-fc747760bd4c8a4b.js +1 -0
  513. package/.next/static/chunks/app/api/inbox/route-fc747760bd4c8a4b.js +1 -0
  514. package/.next/static/chunks/app/api/jobs/[id]/route-fc747760bd4c8a4b.js +1 -0
  515. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-fc747760bd4c8a4b.js +1 -0
  516. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-fc747760bd4c8a4b.js +1 -0
  517. package/.next/static/chunks/app/api/jobs/[id]/runs/route-fc747760bd4c8a4b.js +1 -0
  518. package/.next/static/chunks/app/api/jobs/[id]/trigger/route-fc747760bd4c8a4b.js +1 -0
  519. package/.next/static/chunks/app/api/jobs/mcp-discover/route-fc747760bd4c8a4b.js +1 -0
  520. package/.next/static/chunks/app/api/jobs/route-fc747760bd4c8a4b.js +1 -0
  521. package/.next/static/chunks/app/api/jobs/status/route-fc747760bd4c8a4b.js +1 -0
  522. package/.next/static/chunks/app/api/mcp-servers/[name]/route-fc747760bd4c8a4b.js +1 -0
  523. package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-fc747760bd4c8a4b.js +1 -0
  524. package/.next/static/chunks/app/api/mcp-servers/route-fc747760bd4c8a4b.js +1 -0
  525. package/.next/static/chunks/app/api/notifications/route-fc747760bd4c8a4b.js +1 -0
  526. package/.next/static/chunks/app/api/notifications/test/route-fc747760bd4c8a4b.js +1 -0
  527. package/.next/static/chunks/app/api/providers/[id]/route-fc747760bd4c8a4b.js +1 -0
  528. package/.next/static/chunks/app/api/providers/route-fc747760bd4c8a4b.js +1 -0
  529. package/.next/static/chunks/app/api/reviews/pinned/route-fc747760bd4c8a4b.js +1 -0
  530. package/.next/static/chunks/app/api/sessions/[id]/context/route-fc747760bd4c8a4b.js +1 -0
  531. package/.next/static/chunks/app/api/sessions/[id]/mcp/route-fc747760bd4c8a4b.js +1 -0
  532. package/.next/static/chunks/app/api/sessions/[id]/route-fc747760bd4c8a4b.js +1 -0
  533. package/.next/static/chunks/app/api/sessions/[id]/search/route-fc747760bd4c8a4b.js +1 -0
  534. package/.next/static/chunks/app/api/sessions/[id]/tabs/route-fc747760bd4c8a4b.js +1 -0
  535. package/.next/static/chunks/app/api/sessions/bulk-delete/route-fc747760bd4c8a4b.js +1 -0
  536. package/.next/static/chunks/app/api/sessions/by-ids/route-fc747760bd4c8a4b.js +1 -0
  537. package/.next/static/chunks/app/api/sessions/group/route-fc747760bd4c8a4b.js +1 -0
  538. package/.next/static/chunks/app/api/sessions/pinned/route-fc747760bd4c8a4b.js +1 -0
  539. package/.next/static/chunks/app/api/sessions/route-fc747760bd4c8a4b.js +1 -0
  540. package/.next/static/chunks/app/api/sessions/search/route-fc747760bd4c8a4b.js +1 -0
  541. package/.next/static/chunks/app/api/sessions/thinking/route-fc747760bd4c8a4b.js +1 -0
  542. package/.next/static/chunks/app/api/skills/[name]/route-fc747760bd4c8a4b.js +1 -0
  543. package/.next/static/chunks/app/api/skills/route-fc747760bd4c8a4b.js +1 -0
  544. package/.next/static/chunks/app/api/terminal/[id]/route-fc747760bd4c8a4b.js +1 -0
  545. package/.next/static/chunks/app/api/terminal/route-fc747760bd4c8a4b.js +1 -0
  546. package/.next/static/chunks/app/api/usage/route-fc747760bd4c8a4b.js +1 -0
  547. package/.next/static/chunks/app/api/version/changelog/route-fc747760bd4c8a4b.js +1 -0
  548. package/.next/static/chunks/app/api/version/cockpit/changelog/route-fc747760bd4c8a4b.js +1 -0
  549. package/.next/static/chunks/app/api/version/cockpit/route-fc747760bd4c8a4b.js +1 -0
  550. package/.next/static/chunks/app/api/version/route-fc747760bd4c8a4b.js +1 -0
  551. package/.next/static/chunks/e868780c.f24b6da08e62c7b2.js +18 -0
  552. package/.next/static/chunks/next/dist/client/components/builtin/app-error-fc747760bd4c8a4b.js +1 -0
  553. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-fc747760bd4c8a4b.js +1 -0
  554. package/.next/static/chunks/next/dist/client/components/builtin/not-found-fc747760bd4c8a4b.js +1 -0
  555. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-fc747760bd4c8a4b.js +1 -0
  556. package/.next/static/chunks/webpack-e31bb45fa59caed8.js +1 -0
  557. package/.next/static/css/3f8af4ae6f812d5c.css +1 -0
  558. package/README.md +12 -3
  559. package/bin/cockpit-hook-bridge.mjs +170 -0
  560. package/dist/server.js +11 -1
  561. package/dist/src/lib/models.js +48 -7
  562. package/dist/src/server/auth.js +32 -10
  563. package/dist/src/server/claude-settings.js +153 -0
  564. package/dist/src/server/cli-init-fetch.js +86 -0
  565. package/dist/src/server/cron-utils.js +16 -5
  566. package/dist/src/server/debug-logger.js +2 -2
  567. package/dist/src/server/defaults.js +16 -7
  568. package/dist/src/server/fs-watcher.js +50 -0
  569. package/dist/src/server/hook-bridge-path.js +34 -0
  570. package/dist/src/server/hook-event-translator.js +211 -0
  571. package/dist/src/server/hook-router.js +150 -0
  572. package/dist/src/server/inbox.js +14 -10
  573. package/dist/src/server/job-lock.js +103 -0
  574. package/dist/src/server/job-scheduler.js +23 -8
  575. package/dist/src/server/job-storage.js +28 -13
  576. package/dist/src/server/notification-settings.js +13 -9
  577. package/dist/src/server/paths.js +23 -0
  578. package/dist/src/server/plans.js +8 -5
  579. package/dist/src/server/providers.js +128 -0
  580. package/dist/src/server/pty-runtime.js +324 -0
  581. package/dist/src/server/pty-session.js +178 -0
  582. package/dist/src/server/session-manager.js +727 -144
  583. package/dist/src/server/session-prefs.js +33 -8
  584. package/dist/src/server/singleton.js +18 -0
  585. package/dist/src/server/stream-processor.js +61 -48
  586. package/dist/src/server/terminal-manager.js +153 -0
  587. package/dist/src/server/todo-watcher.js +178 -0
  588. package/dist/src/server/transcript-watcher.js +91 -0
  589. package/dist/src/server/transcript.js +177 -11
  590. package/dist/src/server/ws-handler.js +235 -61
  591. package/next.config.ts +1 -0
  592. package/package.json +10 -3
  593. package/public/fonts/symbols-nerd-font-mono.woff2 +0 -0
  594. package/.next/server/chunks/1941.js +0 -9
  595. package/.next/server/chunks/2444.js +0 -6
  596. package/.next/static/brzairTqHmHwvfgKpdkYX/_buildManifest.js +0 -1
  597. package/.next/static/chunks/3765-a4c7a493ec83f918.js +0 -20
  598. package/.next/static/chunks/75866-76a3987dda1295ae.js +0 -1
  599. package/.next/static/chunks/93273-87110c1449e1e7fd.js +0 -6
  600. package/.next/static/chunks/app/(app)/agents/[name]/page-3ec9a3460e8e9006.js +0 -8
  601. package/.next/static/chunks/app/(app)/agents/page-d6d504e7d7757ea2.js +0 -1
  602. package/.next/static/chunks/app/(app)/changes/page-a09bf4742aa8b5ce.js +0 -1
  603. package/.next/static/chunks/app/(app)/claude-md/edit/page-ab42921ba2618dc3.js +0 -1
  604. package/.next/static/chunks/app/(app)/claude-md/page-c4c8b20aa002a94a.js +0 -1
  605. package/.next/static/chunks/app/(app)/commands/[name]/page-2124ffed9a4e95a3.js +0 -6
  606. package/.next/static/chunks/app/(app)/commands/page-d5bf1bddd17e31dd.js +0 -1
  607. package/.next/static/chunks/app/(app)/files/page-04e4e5bf1ca89945.js +0 -1
  608. package/.next/static/chunks/app/(app)/hooks/[event]/page-d988623e739973b5.js +0 -6
  609. package/.next/static/chunks/app/(app)/hooks/page-818242d7db432578.js +0 -1
  610. package/.next/static/chunks/app/(app)/inbox/[id]/page-c33dc94e309ff117.js +0 -1
  611. package/.next/static/chunks/app/(app)/inbox/page-ca3e1724b5072734.js +0 -1
  612. package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-3a1c927d76333bf0.js +0 -1
  613. package/.next/static/chunks/app/(app)/jobs/[id]/page-8e698e00b90968b0.js +0 -1
  614. package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-f942df0b7c1d280b.js +0 -1
  615. package/.next/static/chunks/app/(app)/jobs/page-7a88cc6ac34550c2.js +0 -1
  616. package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-3541bf3ccdef9145.js +0 -1
  617. package/.next/static/chunks/app/(app)/mcp-servers/page-3927dfd03d921040.js +0 -1
  618. package/.next/static/chunks/app/(app)/page-594120e0ea1df527.js +0 -1
  619. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-74c23b04f5c3ff88.js +0 -13
  620. package/.next/static/chunks/app/(app)/sessions/[id]/page-435e9fb4dd34007d.js +0 -1
  621. package/.next/static/chunks/app/(app)/settings/page-f8ada7997c0d5b03.js +0 -1
  622. package/.next/static/chunks/app/(app)/skills/[name]/page-5dbe1e7682880145.js +0 -6
  623. package/.next/static/chunks/app/(app)/skills/page-fd1986ad7e060f4d.js +0 -1
  624. package/.next/static/chunks/app/_global-error/page-65c661eddfc65f5b.js +0 -1
  625. package/.next/static/chunks/app/api/agents/[name]/route-65c661eddfc65f5b.js +0 -1
  626. package/.next/static/chunks/app/api/agents/route-65c661eddfc65f5b.js +0 -1
  627. package/.next/static/chunks/app/api/auth/check/route-65c661eddfc65f5b.js +0 -1
  628. package/.next/static/chunks/app/api/auth/login/route-65c661eddfc65f5b.js +0 -1
  629. package/.next/static/chunks/app/api/auth/setup/route-65c661eddfc65f5b.js +0 -1
  630. package/.next/static/chunks/app/api/auth/ws-token/route-65c661eddfc65f5b.js +0 -1
  631. package/.next/static/chunks/app/api/btw/route-65c661eddfc65f5b.js +0 -1
  632. package/.next/static/chunks/app/api/claude-md/route-65c661eddfc65f5b.js +0 -1
  633. package/.next/static/chunks/app/api/commands/[name]/route-65c661eddfc65f5b.js +0 -1
  634. package/.next/static/chunks/app/api/commands/route-65c661eddfc65f5b.js +0 -1
  635. package/.next/static/chunks/app/api/defaults/route-65c661eddfc65f5b.js +0 -1
  636. package/.next/static/chunks/app/api/filesystem/browse/route-65c661eddfc65f5b.js +0 -1
  637. package/.next/static/chunks/app/api/filesystem/files/route-65c661eddfc65f5b.js +0 -1
  638. package/.next/static/chunks/app/api/filesystem/mkdir/route-65c661eddfc65f5b.js +0 -1
  639. package/.next/static/chunks/app/api/filesystem/read/route-65c661eddfc65f5b.js +0 -1
  640. package/.next/static/chunks/app/api/git/clone/route-65c661eddfc65f5b.js +0 -1
  641. package/.next/static/chunks/app/api/git/commit/route-65c661eddfc65f5b.js +0 -1
  642. package/.next/static/chunks/app/api/git/diff/route-65c661eddfc65f5b.js +0 -1
  643. package/.next/static/chunks/app/api/git/discard/route-65c661eddfc65f5b.js +0 -1
  644. package/.next/static/chunks/app/api/git/generate-message/route-65c661eddfc65f5b.js +0 -1
  645. package/.next/static/chunks/app/api/git/push/route-65c661eddfc65f5b.js +0 -1
  646. package/.next/static/chunks/app/api/git/status/route-65c661eddfc65f5b.js +0 -1
  647. package/.next/static/chunks/app/api/github/file-content/route-65c661eddfc65f5b.js +0 -1
  648. package/.next/static/chunks/app/api/github/orgs/route-65c661eddfc65f5b.js +0 -1
  649. package/.next/static/chunks/app/api/github/prs/checks/route-65c661eddfc65f5b.js +0 -1
  650. package/.next/static/chunks/app/api/github/prs/diff/route-65c661eddfc65f5b.js +0 -1
  651. package/.next/static/chunks/app/api/github/prs/review/route-65c661eddfc65f5b.js +0 -1
  652. package/.next/static/chunks/app/api/github/prs/route-65c661eddfc65f5b.js +0 -1
  653. package/.next/static/chunks/app/api/github/prs/view/route-65c661eddfc65f5b.js +0 -1
  654. package/.next/static/chunks/app/api/github/repos/route-65c661eddfc65f5b.js +0 -1
  655. package/.next/static/chunks/app/api/github/review-session/route-65c661eddfc65f5b.js +0 -1
  656. package/.next/static/chunks/app/api/health/route-65c661eddfc65f5b.js +0 -1
  657. package/.next/static/chunks/app/api/hooks/route-65c661eddfc65f5b.js +0 -1
  658. package/.next/static/chunks/app/api/inbox/[id]/route-65c661eddfc65f5b.js +0 -1
  659. package/.next/static/chunks/app/api/inbox/route-65c661eddfc65f5b.js +0 -1
  660. package/.next/static/chunks/app/api/jobs/[id]/route-65c661eddfc65f5b.js +0 -1
  661. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-65c661eddfc65f5b.js +0 -1
  662. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-65c661eddfc65f5b.js +0 -1
  663. package/.next/static/chunks/app/api/jobs/[id]/runs/route-65c661eddfc65f5b.js +0 -1
  664. package/.next/static/chunks/app/api/jobs/[id]/trigger/route-65c661eddfc65f5b.js +0 -1
  665. package/.next/static/chunks/app/api/jobs/mcp-discover/route-65c661eddfc65f5b.js +0 -1
  666. package/.next/static/chunks/app/api/jobs/route-65c661eddfc65f5b.js +0 -1
  667. package/.next/static/chunks/app/api/jobs/status/route-65c661eddfc65f5b.js +0 -1
  668. package/.next/static/chunks/app/api/mcp-servers/[name]/route-65c661eddfc65f5b.js +0 -1
  669. package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-65c661eddfc65f5b.js +0 -1
  670. package/.next/static/chunks/app/api/mcp-servers/route-65c661eddfc65f5b.js +0 -1
  671. package/.next/static/chunks/app/api/notifications/route-65c661eddfc65f5b.js +0 -1
  672. package/.next/static/chunks/app/api/notifications/test/route-65c661eddfc65f5b.js +0 -1
  673. package/.next/static/chunks/app/api/reviews/pinned/route-65c661eddfc65f5b.js +0 -1
  674. package/.next/static/chunks/app/api/sessions/[id]/context/route-65c661eddfc65f5b.js +0 -1
  675. package/.next/static/chunks/app/api/sessions/[id]/mcp/route-65c661eddfc65f5b.js +0 -1
  676. package/.next/static/chunks/app/api/sessions/[id]/route-65c661eddfc65f5b.js +0 -1
  677. package/.next/static/chunks/app/api/sessions/[id]/search/route-65c661eddfc65f5b.js +0 -1
  678. package/.next/static/chunks/app/api/sessions/bulk-delete/route-65c661eddfc65f5b.js +0 -1
  679. package/.next/static/chunks/app/api/sessions/by-ids/route-65c661eddfc65f5b.js +0 -1
  680. package/.next/static/chunks/app/api/sessions/group/route-65c661eddfc65f5b.js +0 -1
  681. package/.next/static/chunks/app/api/sessions/pinned/route-65c661eddfc65f5b.js +0 -1
  682. package/.next/static/chunks/app/api/sessions/route-65c661eddfc65f5b.js +0 -1
  683. package/.next/static/chunks/app/api/sessions/search/route-65c661eddfc65f5b.js +0 -1
  684. package/.next/static/chunks/app/api/skills/[name]/route-65c661eddfc65f5b.js +0 -1
  685. package/.next/static/chunks/app/api/skills/route-65c661eddfc65f5b.js +0 -1
  686. package/.next/static/chunks/app/api/usage/route-65c661eddfc65f5b.js +0 -1
  687. package/.next/static/chunks/app/api/version/cockpit/route-65c661eddfc65f5b.js +0 -1
  688. package/.next/static/chunks/app/api/version/route-65c661eddfc65f5b.js +0 -1
  689. package/.next/static/chunks/next/dist/client/components/builtin/app-error-65c661eddfc65f5b.js +0 -1
  690. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-65c661eddfc65f5b.js +0 -1
  691. package/.next/static/chunks/next/dist/client/components/builtin/not-found-65c661eddfc65f5b.js +0 -1
  692. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-65c661eddfc65f5b.js +0 -1
  693. package/.next/static/chunks/webpack-3461a05957b13f46.js +0 -1
  694. package/.next/static/css/f04f303b5708dd90.css +0 -1
  695. /package/.next/static/{brzairTqHmHwvfgKpdkYX → I-rxZaJEzhe3ZUTjSqB11}/_ssgManifest.js +0 -0
@@ -4,21 +4,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SessionManager = void 0;
7
- exports.extractTodosFromHistory = extractTodosFromHistory;
8
7
  const node_child_process_1 = require("node:child_process");
9
8
  const node_events_1 = require("node:events");
10
9
  const node_fs_1 = require("node:fs");
11
- const node_os_1 = require("node:os");
12
10
  const node_path_1 = __importDefault(require("node:path"));
13
11
  const uuid_1 = require("uuid");
14
12
  const models_1 = require("../lib/models");
13
+ const paths_1 = require("../server/paths");
14
+ const providers_1 = require("../server/providers");
15
15
  const debug_logger_1 = require("./debug-logger");
16
16
  const defaults_1 = require("./defaults");
17
17
  const event_parser_1 = require("./event-parser");
18
18
  const plans_1 = require("./plans");
19
+ const pty_runtime_1 = require("./pty-runtime");
19
20
  const session_prefs_1 = require("./session-prefs");
21
+ const singleton_1 = require("./singleton");
20
22
  const stream_processor_1 = require("./stream-processor");
23
+ const todo_watcher_1 = require("./todo-watcher");
21
24
  const transcript_1 = require("./transcript");
25
+ const transcript_watcher_1 = require("./transcript-watcher");
26
+ function defaultRuntime() {
27
+ return "stream";
28
+ }
29
+ let resolvedClaudeBin = null;
30
+ function getClaudeBin() {
31
+ if (resolvedClaudeBin)
32
+ return resolvedClaudeBin;
33
+ const cmd = process.platform === "win32" ? "where" : "which";
34
+ try {
35
+ resolvedClaudeBin = (0, node_child_process_1.execFileSync)(cmd, ["claude"], { encoding: "utf-8" }).trim().split("\n")[0];
36
+ }
37
+ catch {
38
+ resolvedClaudeBin = "claude";
39
+ }
40
+ return resolvedClaudeBin;
41
+ }
22
42
  const smLog = (sessionId, msg) => {
23
43
  if (!(0, debug_logger_1.isDebugEnabled)())
24
44
  return;
@@ -32,9 +52,9 @@ class SessionManager {
32
52
  // Periodically check for sessions stuck in "running" with a dead process
33
53
  setInterval(() => {
34
54
  for (const [id, session] of this.sessions) {
35
- if (session.info.status === "running" && !session.process) {
55
+ if (session.info.status === "running" && !session.process && !session.ptyRuntime?.isAlive) {
36
56
  const short = id.slice(0, 8);
37
- (0, debug_logger_1.debugLog)(`[session:${short}] stale check: status=running but process=null, correcting to idle`);
57
+ (0, debug_logger_1.debugLog)(`[session:${short}] stale check: status=running but no live process, correcting to idle`);
38
58
  (0, debug_logger_1.logDiag)(id, "idle:stale-check");
39
59
  session.info.status = "idle";
40
60
  session.emitter.emit("status", id, "idle");
@@ -46,6 +66,8 @@ class SessionManager {
46
66
  const id = (0, uuid_1.v4)();
47
67
  const now = Date.now();
48
68
  const defaults = (0, defaults_1.getDefaults)();
69
+ const modelSlots = { main: defaults.modelSlots.main ?? "sonnet" };
70
+ const rt = options?.runtime ?? defaultRuntime();
49
71
  const info = {
50
72
  id,
51
73
  name: name || node_path_1.default.basename(cwd) || cwd,
@@ -53,7 +75,9 @@ class SessionManager {
53
75
  createdAt: now,
54
76
  lastActiveAt: now,
55
77
  status: "idle",
56
- model: defaults.model || undefined,
78
+ model: modelSlots.main,
79
+ contextSize: defaults.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE,
80
+ runtime: rt,
57
81
  pendingRequestCount: 0,
58
82
  };
59
83
  this.sessions.set(id, {
@@ -71,27 +95,42 @@ class SessionManager {
71
95
  thinkingLevel: defaults.thinkingLevel,
72
96
  streamState: null,
73
97
  contextUsage: null,
74
- contextWindowSize: 200_000,
98
+ contextWindowSize: (0, models_1.contextSizeToWindow)(info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE),
75
99
  todoItems: [],
76
100
  pendingRequests: new Map(),
77
101
  controlCallbacks: new Map(),
78
102
  streamingSnapshot: null,
79
103
  queuedMessages: [],
80
104
  queuePaused: false,
105
+ modelSlots,
81
106
  transcriptBuffer: [],
82
107
  transcriptByteOffset: 0,
83
108
  transcriptTotalSize: 0,
84
109
  bufferCliSessionId: id,
85
110
  paginationPrevIds: [],
111
+ runtime: rt,
112
+ ptyRuntime: null,
113
+ transcriptWatcher: null,
114
+ todoWatcher: null,
115
+ attachmentPaths: [],
116
+ totalTokens: { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 },
86
117
  });
118
+ (0, session_prefs_1.setSessionPrefs)(id, { runtime: rt });
87
119
  return info;
88
120
  }
89
121
  ensureSession(id, cwd) {
90
122
  let session = this.sessions.get(id);
91
123
  if (!session) {
92
124
  const prefs = (0, session_prefs_1.getSessionPrefs)(id);
125
+ const cliId = prefs?.cliSessionId || id;
126
+ const prevIds = prefs?.previousCliSessionIds || [];
127
+ const short = id.slice(0, 8);
128
+ (0, debug_logger_1.debugLog)(`[session:${short}] ensureSession: cliSessionId=${cliId.slice(0, 8)}, prevIds=[${prevIds.map((p) => p.slice(0, 8)).join(",")}], hasPrefs=${!!prefs}`);
93
129
  const defaults = (0, defaults_1.getDefaults)();
94
130
  const now = Date.now();
131
+ const modelSlots = prefs?.modelSlots ?? (prefs?.model ? { main: prefs.model } : { main: defaults.modelSlots.main ?? "sonnet" });
132
+ const restoredRuntime = prefs?.runtime ?? defaultRuntime();
133
+ const restoredContextSize = prefs?.contextSize ?? prefs?.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE;
95
134
  session = {
96
135
  info: {
97
136
  id,
@@ -100,24 +139,28 @@ class SessionManager {
100
139
  createdAt: now,
101
140
  lastActiveAt: now,
102
141
  status: "idle",
103
- model: prefs?.model || defaults.model || undefined,
142
+ model: modelSlots.main,
143
+ contextSize: restoredContextSize,
144
+ runtime: restoredRuntime,
104
145
  pendingRequestCount: 0,
105
146
  },
106
147
  process: null,
107
148
  stdin: null,
108
149
  emitter: new node_events_1.EventEmitter(),
109
150
  hasSpawnedBefore: true,
110
- cliSessionId: prefs?.cliSessionId || id,
111
- previousCliSessionIds: prefs?.previousCliSessionIds || [],
151
+ cliSessionId: cliId,
152
+ previousCliSessionIds: prevIds,
112
153
  bypassAllPermissions: prefs?.bypassAllPermissions ?? defaults.bypassAllPermissions,
113
154
  planMode: prefs?.planMode ?? false,
114
155
  pendingPlanReminder: prefs?.planMode ?? false,
115
156
  needsRespawnForPermissions: false,
116
157
  compacting: false,
117
- thinkingLevel: prefs?.thinkingLevel ?? (0, models_1.recommendedEffort)((0, models_1.resolveModel)(prefs?.model || defaults.model)) ?? defaults.thinkingLevel,
158
+ thinkingLevel: prefs?.thinkingLevel ??
159
+ (0, models_1.recommendedEffort)((0, models_1.resolveModel)((prefs?.model || defaults.modelSlots.main) ?? "sonnet")) ??
160
+ defaults.thinkingLevel,
118
161
  streamState: null,
119
162
  contextUsage: null,
120
- contextWindowSize: 200_000,
163
+ contextWindowSize: (0, models_1.contextSizeToWindow)(restoredContextSize),
121
164
  todoItems: [],
122
165
  pendingRequests: new Map(),
123
166
  controlCallbacks: new Map(),
@@ -125,11 +168,18 @@ class SessionManager {
125
168
  streamingSnapshot: null,
126
169
  queuedMessages: [],
127
170
  queuePaused: false,
171
+ modelSlots,
128
172
  transcriptBuffer: [],
129
173
  transcriptByteOffset: 0,
130
174
  transcriptTotalSize: 0,
131
- bufferCliSessionId: prefs?.cliSessionId || id,
175
+ bufferCliSessionId: cliId,
132
176
  paginationPrevIds: [],
177
+ runtime: restoredRuntime,
178
+ ptyRuntime: null,
179
+ transcriptWatcher: null,
180
+ todoWatcher: null,
181
+ attachmentPaths: [],
182
+ totalTokens: { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 },
133
183
  };
134
184
  this.sessions.set(id, session);
135
185
  }
@@ -157,24 +207,22 @@ class SessionManager {
157
207
  let { messages, byteOffset, totalSize, lastUsage } = result;
158
208
  session.bufferCliSessionId = session.cliSessionId;
159
209
  if (willStitch) {
160
- const currentMessages = messages;
161
210
  for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
162
211
  const prevId = session.previousCliSessionIds[i];
163
212
  const prevResult = await (0, transcript_1.loadTranscript)(prevId, session.info.cwd, { tailLines: 150 });
164
213
  if (prevResult.messages.length > 0) {
165
214
  const marker = {
166
- id: "clear-boundary-" + Date.now(),
215
+ id: `clear-boundary-${i}`,
167
216
  role: "system",
168
217
  content: "__context_reset__",
169
218
  toolUses: [],
170
219
  blocks: [],
171
220
  timestamp: Date.now(),
172
221
  };
173
- messages = [...prevResult.messages, marker, ...currentMessages];
222
+ messages = [...prevResult.messages, marker, ...messages];
174
223
  byteOffset = prevResult.byteOffset;
175
224
  lastUsage = lastUsage || prevResult.lastUsage;
176
225
  session.bufferCliSessionId = prevId;
177
- break;
178
226
  }
179
227
  }
180
228
  }
@@ -195,7 +243,20 @@ class SessionManager {
195
243
  session.info.name = firstUser.content.slice(0, 120);
196
244
  }
197
245
  }
198
- return { info: session.info, messages: clientMessages, hasMore, lastUsage };
246
+ const allCliIds = [...session.previousCliSessionIds, session.cliSessionId];
247
+ const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, session.info.cwd)));
248
+ const seen = new Set();
249
+ const allPrompts = [];
250
+ for (const arr of historyArrays) {
251
+ for (const p of arr) {
252
+ if (seen.has(p))
253
+ continue;
254
+ seen.add(p);
255
+ allPrompts.push(p);
256
+ }
257
+ }
258
+ const normalized = lastUsage ? { used: lastUsage.used, total: session.contextWindowSize } : null;
259
+ return { info: session.info, messages: clientMessages, hasMore, lastUsage: normalized, promptHistory: allPrompts };
199
260
  }
200
261
  async getSessionByCwd(id, cwd) {
201
262
  this.ensureSession(id, cwd);
@@ -206,24 +267,22 @@ class SessionManager {
206
267
  let { messages, byteOffset, totalSize, lastUsage } = result;
207
268
  session.bufferCliSessionId = session.cliSessionId;
208
269
  if (willStitch) {
209
- const currentMessages = messages;
210
270
  for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
211
271
  const prevId = session.previousCliSessionIds[i];
212
272
  const prevResult = await (0, transcript_1.loadTranscript)(prevId, cwd, { tailLines: 150 });
213
273
  if (prevResult.messages.length > 0) {
214
274
  const marker = {
215
- id: "clear-boundary-" + Date.now(),
275
+ id: `clear-boundary-${i}`,
216
276
  role: "system",
217
277
  content: "__context_reset__",
218
278
  toolUses: [],
219
279
  blocks: [],
220
280
  timestamp: Date.now(),
221
281
  };
222
- messages = [...prevResult.messages, marker, ...currentMessages];
282
+ messages = [...prevResult.messages, marker, ...messages];
223
283
  byteOffset = prevResult.byteOffset;
224
284
  lastUsage = lastUsage || prevResult.lastUsage;
225
285
  session.bufferCliSessionId = prevId;
226
- break;
227
286
  }
228
287
  }
229
288
  }
@@ -245,7 +304,20 @@ class SessionManager {
245
304
  session.info.name = firstUser.content.slice(0, 120);
246
305
  }
247
306
  }
248
- return { info: session.info, messages: clientMessages, hasMore, lastUsage };
307
+ const allCliIds = [...session.previousCliSessionIds, session.cliSessionId];
308
+ const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, cwd)));
309
+ const seen = new Set();
310
+ const allPrompts = [];
311
+ for (const arr of historyArrays) {
312
+ for (const p of arr) {
313
+ if (seen.has(p))
314
+ continue;
315
+ seen.add(p);
316
+ allPrompts.push(p);
317
+ }
318
+ }
319
+ const normalized = lastUsage ? { used: lastUsage.used, total: session.contextWindowSize } : null;
320
+ return { info: session.info, messages: clientMessages, hasMore, lastUsage: normalized, promptHistory: allPrompts };
249
321
  }
250
322
  async getCliSessionView(cliId, cwd) {
251
323
  if (!(0, transcript_1.transcriptExists)(cliId, cwd))
@@ -256,21 +328,19 @@ class SessionManager {
256
328
  const result = await (0, transcript_1.loadTranscript)(cliId, cwd, willStitch ? undefined : { tailLines: 150 });
257
329
  let { messages, lastUsage } = result;
258
330
  if (willStitch) {
259
- const currentMessages = messages;
260
331
  for (let i = prevIds.length - 1; i >= 0; i--) {
261
332
  const prevResult = await (0, transcript_1.loadTranscript)(prevIds[i], cwd, { tailLines: 150 });
262
333
  if (prevResult.messages.length > 0) {
263
334
  const marker = {
264
- id: "clear-boundary-" + Date.now(),
335
+ id: `clear-boundary-${i}`,
265
336
  role: "system",
266
337
  content: "__context_reset__",
267
338
  toolUses: [],
268
339
  blocks: [],
269
340
  timestamp: Date.now(),
270
341
  };
271
- messages = [...prevResult.messages, marker, ...currentMessages];
342
+ messages = [...prevResult.messages, marker, ...messages];
272
343
  lastUsage = lastUsage || prevResult.lastUsage;
273
- break;
274
344
  }
275
345
  }
276
346
  }
@@ -283,11 +353,27 @@ class SessionManager {
283
353
  name = firstUser.content.slice(0, 120);
284
354
  }
285
355
  }
356
+ const allCliIds = [...prevIds, cliId];
357
+ const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, cwd)));
358
+ const seen = new Set();
359
+ const allPrompts = [];
360
+ for (const arr of historyArrays) {
361
+ for (const p of arr) {
362
+ if (seen.has(p))
363
+ continue;
364
+ seen.add(p);
365
+ allPrompts.push(p);
366
+ }
367
+ }
368
+ const prefs = (0, session_prefs_1.getSessionPrefs)(cliId);
369
+ const viewSize = prefs?.contextSize ?? prefs?.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE;
370
+ const normalized = lastUsage ? { used: lastUsage.used, total: (0, models_1.contextSizeToWindow)(viewSize) } : null;
286
371
  return {
287
372
  info: { id: cliId, name, cwd, createdAt: Date.now(), lastActiveAt: Date.now(), status: "idle" },
288
373
  messages: clientMessages,
289
374
  hasMore: messages.length > PAGE,
290
- lastUsage,
375
+ lastUsage: normalized,
376
+ promptHistory: allPrompts,
291
377
  };
292
378
  }
293
379
  async getMoreHistory(sessionId, beforeMessageId) {
@@ -362,9 +448,21 @@ class SessionManager {
362
448
  isCompacting(id) {
363
449
  return this.sessions.get(id)?.compacting ?? false;
364
450
  }
451
+ getRuntime(id) {
452
+ return this.sessions.get(id)?.runtime ?? "stream";
453
+ }
454
+ getSessionCwd(id) {
455
+ return this.sessions.get(id)?.info.cwd ?? null;
456
+ }
457
+ getCliSessionId(id) {
458
+ return this.sessions.get(id)?.cliSessionId ?? null;
459
+ }
460
+ getSessionModel(id) {
461
+ return this.sessions.get(id)?.info.model ?? null;
462
+ }
365
463
  listActiveSessions() {
366
464
  return Array.from(this.sessions.values())
367
- .filter((s) => s.process !== null)
465
+ .filter((s) => s.process !== null || !!s.ptyRuntime?.isAlive)
368
466
  .map((s) => s.info);
369
467
  }
370
468
  listKnownSessions() {
@@ -386,15 +484,15 @@ class SessionManager {
386
484
  }
387
485
  isProcessAlive(id) {
388
486
  const session = this.sessions.get(id);
389
- return !!session?.process;
487
+ return !!session?.process || !!session?.ptyRuntime?.isAlive;
390
488
  }
391
489
  hasRunningProcess(id) {
392
490
  const session = this.sessions.get(id);
393
- return !!session?.process;
491
+ return !!session?.process || !!session?.ptyRuntime?.isAlive;
394
492
  }
395
493
  fixStaleStatus(id) {
396
494
  const session = this.sessions.get(id);
397
- if (session && session.info.status === "running" && !session.process) {
495
+ if (session && session.info.status === "running" && !session.process && !session.ptyRuntime?.isAlive) {
398
496
  session.info.status = "idle";
399
497
  session.pendingRequests.clear();
400
498
  this.notifyPendingChanged(session, id);
@@ -409,6 +507,9 @@ class SessionManager {
409
507
  return false;
410
508
  }
411
509
  this.killProcess(session);
510
+ if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
511
+ session.hasSpawnedBefore = false;
512
+ }
412
513
  session.pendingRequests.clear();
413
514
  this.notifyPendingChanged(session, sessionId);
414
515
  session.streamingSnapshot = null;
@@ -425,6 +526,20 @@ class SessionManager {
425
526
  if (session.process) {
426
527
  this.endProcess(session, "session_destroyed");
427
528
  }
529
+ if (session.ptyRuntime) {
530
+ const runtime = session.ptyRuntime;
531
+ session.ptyRuntime = null;
532
+ runtime.kill().catch(() => { });
533
+ }
534
+ if (session.transcriptWatcher) {
535
+ session.transcriptWatcher.stop();
536
+ session.transcriptWatcher = null;
537
+ }
538
+ if (session.todoWatcher) {
539
+ session.todoWatcher.stop();
540
+ session.todoWatcher = null;
541
+ }
542
+ this.cleanupAttachments(session);
428
543
  session.emitter.removeAllListeners();
429
544
  this.sessions.delete(id);
430
545
  return true;
@@ -441,8 +556,10 @@ class SessionManager {
441
556
  }
442
557
  onStatus(id, listener) {
443
558
  const session = this.sessions.get(id);
444
- if (!session)
559
+ if (!session) {
560
+ smLog(id, "onStatus: session not in memory, returning null");
445
561
  return null;
562
+ }
446
563
  const handler = (_sessionId, status) => {
447
564
  listener(status);
448
565
  };
@@ -469,19 +586,55 @@ class SessionManager {
469
586
  session.emitter.on("error", handler);
470
587
  return () => session.emitter.off("error", handler);
471
588
  }
589
+ onTranscript(id, listener) {
590
+ const session = this.sessions.get(id);
591
+ if (!session)
592
+ return null;
593
+ const handler = (_sessionId, messages) => listener(messages);
594
+ session.emitter.on("transcript", handler);
595
+ return () => session.emitter.off("transcript", handler);
596
+ }
472
597
  interrupt(id) {
473
598
  const session = this.sessions.get(id);
474
- if (!session?.process) {
475
- (0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession: !!session });
599
+ if (!session) {
600
+ (0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession: false });
476
601
  return false;
477
602
  }
478
603
  // Pause the queue atomically with the interrupt so
479
604
  // flushQueuedMessage (called on message_done) becomes a no-op.
480
- // This prevents a race where message_done fires before a
481
- // separate pause_queue WS message can arrive.
482
605
  if (session.queuedMessages.length > 0) {
483
606
  session.queuePaused = true;
484
607
  }
608
+ if (session.runtime === "pty") {
609
+ if (!session.ptyRuntime?.isAlive) {
610
+ (0, debug_logger_1.logDiag)(id, "interrupt:no-pty");
611
+ return false;
612
+ }
613
+ (0, debug_logger_1.logDiag)(id, "interrupt:pty-esc");
614
+ session.ptyRuntime.interrupt();
615
+ // Esc cancels the claude TUI turn but may not produce a Stop hook if it
616
+ // arrived before any response. Force-idle so the UI unsticks; the PTY
617
+ // process stays alive at its REPL prompt and accepts the next message.
618
+ if (session.info.status === "running") {
619
+ session.info.status = "idle";
620
+ session.streamingSnapshot = null;
621
+ if (session.streamState) {
622
+ session.streamState.pendingBlocks.length = 0;
623
+ session.streamState.pendingToolUses.length = 0;
624
+ session.streamState.agentStack.length = 0;
625
+ session.streamState.currentAssistantMsgId = null;
626
+ session.streamState.flushedOnMessageDone = false;
627
+ }
628
+ session.emitter.emit("status", id, "idle");
629
+ }
630
+ session.pendingRequests.clear();
631
+ this.notifyPendingChanged(session, id);
632
+ return true;
633
+ }
634
+ if (!session.process) {
635
+ (0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession: true });
636
+ return false;
637
+ }
485
638
  // Send a control_request interrupt via stdin instead of SIGINT.
486
639
  // SIGINT kills the process, forcing a full respawn + transcript reload
487
640
  // on the next message. The control_request interrupt aborts the current
@@ -495,11 +648,15 @@ class SessionManager {
495
648
  };
496
649
  (0, debug_logger_1.logDiag)(id, "interrupt:stdin", { requestId: request.request_id });
497
650
  session.stdin.write(JSON.stringify(request) + "\n");
651
+ session.pendingRequests.clear();
652
+ this.notifyPendingChanged(session, id);
498
653
  return true;
499
654
  }
500
655
  // Fallback: if stdin is gone, kill the process group
501
656
  (0, debug_logger_1.logDiag)(id, "interrupt:kill-fallback");
502
657
  this.killProcessGroup(session.process);
658
+ session.pendingRequests.clear();
659
+ this.notifyPendingChanged(session, id);
503
660
  return true;
504
661
  }
505
662
  addPendingRequest(sessionId, request) {
@@ -512,7 +669,12 @@ class SessionManager {
512
669
  removePendingRequest(sessionId, requestId) {
513
670
  const session = this.sessions.get(sessionId);
514
671
  if (session) {
672
+ const had = session.pendingRequests.has(requestId);
673
+ const wasQuestion = session.pendingRequests.get(requestId)?.type === "question";
515
674
  session.pendingRequests.delete(requestId);
675
+ if (wasQuestion) {
676
+ console.log(`[question-debug] removePendingRequest: session=${sessionId.slice(0, 8)}, requestId=${requestId}, existed=${had}, remaining=${session.pendingRequests.size}`);
677
+ }
516
678
  this.notifyPendingChanged(session, sessionId);
517
679
  }
518
680
  }
@@ -527,7 +689,18 @@ class SessionManager {
527
689
  }
528
690
  respondToPermission(sessionId, requestId, allowed, toolInput, permissionSuggestions, denyReason) {
529
691
  const session = this.sessions.get(sessionId);
530
- if (!session?.stdin)
692
+ if (!session)
693
+ return false;
694
+ if (session.runtime === "pty") {
695
+ if (!session.ptyRuntime?.isAlive)
696
+ return false;
697
+ session.pendingRequests.delete(requestId);
698
+ this.notifyPendingChanged(session, sessionId);
699
+ return session.ptyRuntime.notifyPermissionDecision(requestId, allowed
700
+ ? { behavior: "allow", ...(toolInput ? { updatedInput: toolInput } : {}) }
701
+ : { behavior: "deny", message: denyReason ?? "User denied" });
702
+ }
703
+ if (!session.stdin)
531
704
  return false;
532
705
  session.pendingRequests.delete(requestId);
533
706
  this.notifyPendingChanged(session, sessionId);
@@ -589,7 +762,7 @@ class SessionManager {
589
762
  // session state, guaranteeing the next message runs in the right mode.
590
763
  // If a message is in flight, defer until message_done so we don't orphan it.
591
764
  scheduleRespawnForPermissions(session) {
592
- if (!session.process)
765
+ if (!session.process && !session.ptyRuntime?.isAlive)
593
766
  return;
594
767
  if (session.info.status === "idle") {
595
768
  this.killProcess(session);
@@ -599,6 +772,17 @@ class SessionManager {
599
772
  session.needsRespawnForPermissions = true;
600
773
  }
601
774
  }
775
+ setRuntime(sessionId, runtime) {
776
+ const session = this.sessions.get(sessionId);
777
+ if (!session || session.runtime === runtime)
778
+ return false;
779
+ session.runtime = runtime;
780
+ session.info.runtime = runtime;
781
+ (0, session_prefs_1.setSessionPrefs)(sessionId, { runtime });
782
+ this.killProcess(session);
783
+ this.emitInfoUpdated(session, sessionId);
784
+ return true;
785
+ }
602
786
  isBypassActive(sessionId) {
603
787
  const session = this.sessions.get(sessionId);
604
788
  return session?.bypassAllPermissions ?? false;
@@ -612,7 +796,7 @@ class SessionManager {
612
796
  (0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: true });
613
797
  // Kill process so it restarts without --allow-dangerously-skip-permissions,
614
798
  // which lets the CLI natively enforce plan mode tool restrictions.
615
- if (session.process) {
799
+ if (session.process || session.ptyRuntime?.isAlive) {
616
800
  this.killProcess(session);
617
801
  session.info.status = "idle";
618
802
  session.emitter.emit("status", sessionId, "idle");
@@ -630,7 +814,7 @@ class SessionManager {
630
814
  (0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: false });
631
815
  // Kill process so it restarts with --allow-dangerously-skip-permissions,
632
816
  // restoring bypass capability for build mode.
633
- if (session.process) {
817
+ if (session.process || session.ptyRuntime?.isAlive) {
634
818
  this.killProcess(session);
635
819
  session.info.status = "idle";
636
820
  session.emitter.emit("status", sessionId, "idle");
@@ -649,19 +833,41 @@ class SessionManager {
649
833
  const session = this.sessions.get(sessionId);
650
834
  return session?.planMode ?? false;
651
835
  }
652
- setModel(sessionId, model) {
836
+ setModel(sessionId, model, contextSize) {
653
837
  const session = this.sessions.get(sessionId);
654
- if (!session || session.info.model === model)
838
+ this.log(sessionId, `setModel: requested=${model} size=${contextSize ?? "(unspecified)"}, current=${session?.info.model} currentSize=${session?.info.contextSize ?? "(unset)"}, hasStdin=${!!session?.stdin}, hasPty=${!!session?.ptyRuntime}`);
839
+ if (!session)
655
840
  return;
656
- // Detect 200K↔1M flip. The CLAUDE_CODE_DISABLE_1M_CONTEXT env var is
657
- // applied at spawn, so toggling the [1m] suffix mid-session needs a CLI
658
- // restart for the new context window to actually take effect.
659
- const has1m = (m) => !!m && /\[1m\]/i.test(m);
660
- const contextChanged = has1m(session.info.model) !== has1m(model);
841
+ const currentSize = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
842
+ const requestedSize = contextSize ?? currentSize;
843
+ const resolvedSize = (() => {
844
+ const sizes = (0, models_1.resolveModel)(model)?.contextSizes;
845
+ if (!sizes || sizes.length === 0)
846
+ return requestedSize;
847
+ return sizes.includes(requestedSize) ? requestedSize : sizes[0];
848
+ })();
849
+ // CLAUDE_CODE_DISABLE_1M_CONTEXT is applied at spawn, so a context-size
850
+ // change mid-session requires a CLI restart to take effect.
851
+ const contextChanged = currentSize !== resolvedSize;
852
+ if (session.info.model === model && !contextChanged) {
853
+ this.log(sessionId, `setModel: skipping (already ${model} with size ${resolvedSize})`);
854
+ return;
855
+ }
661
856
  session.info.model = model;
662
- (0, session_prefs_1.setSessionPrefs)(sessionId, { model });
857
+ session.info.contextSize = resolvedSize;
858
+ session.modelSlots = { ...session.modelSlots, main: model, mainContext: resolvedSize };
859
+ (0, session_prefs_1.setSessionPrefs)(sessionId, { model, contextSize: resolvedSize, modelSlots: session.modelSlots });
663
860
  const nextEntry = (0, models_1.resolveModel)(model);
664
- const coerced = (0, models_1.coerceEffort)(session.thinkingLevel, nextEntry);
861
+ const coerced = nextEntry
862
+ ? (0, models_1.coerceEffort)(session.thinkingLevel, nextEntry)
863
+ : (() => {
864
+ const levels = this.modelEffortLevels(model);
865
+ if (levels.length === 0)
866
+ return null;
867
+ if (levels.includes(session.thinkingLevel))
868
+ return session.thinkingLevel;
869
+ return levels[levels.length - 1];
870
+ })();
665
871
  const levelChanged = coerced !== null && coerced !== session.thinkingLevel;
666
872
  if (levelChanged) {
667
873
  session.thinkingLevel = coerced;
@@ -669,13 +875,14 @@ class SessionManager {
669
875
  this.emitSystem(session, sessionId, `__thinking_level::${coerced}`);
670
876
  }
671
877
  if (session.stdin && !contextChanged) {
878
+ this.log(sessionId, `setModel: sending control_request set_model=${model}`);
672
879
  const request = {
673
880
  type: "control_request",
674
881
  request_id: `model-${Date.now()}`,
675
882
  request: { subtype: "set_model", model },
676
883
  };
677
884
  session.stdin.write(JSON.stringify(request) + "\n");
678
- if ((0, models_1.allowedEffortLevels)(nextEntry).length > 0) {
885
+ if (this.modelEffortLevels(model).length > 0) {
679
886
  const effortRequest = {
680
887
  type: "control_request",
681
888
  request_id: `effort-${Date.now()}`,
@@ -685,13 +892,44 @@ class SessionManager {
685
892
  }
686
893
  }
687
894
  else {
895
+ this.log(sessionId, `setModel: killing process (hasStdin=${!!session.stdin}, contextChanged=${contextChanged})`);
688
896
  this.killProcess(session);
897
+ if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
898
+ session.hasSpawnedBefore = false;
899
+ }
689
900
  session.queuedMessages.length = 0;
690
901
  session.queuePaused = false;
691
902
  session.info.status = "idle";
692
903
  session.emitter.emit("status", sessionId, "idle");
693
904
  }
694
905
  this.emitInfoUpdated(session, sessionId);
906
+ if (contextChanged) {
907
+ session.contextWindowSize = (0, models_1.contextSizeToWindow)(resolvedSize);
908
+ }
909
+ const cur = session.contextUsage;
910
+ if (cur) {
911
+ session.emitter.emit("usage", sessionId, { used: cur.used, total: session.contextWindowSize });
912
+ }
913
+ }
914
+ setModelSlot(sessionId, slot, modelId) {
915
+ const session = this.sessions.get(sessionId);
916
+ if (!session)
917
+ return;
918
+ const slots = { ...session.modelSlots };
919
+ slots[slot] = modelId;
920
+ session.modelSlots = slots;
921
+ (0, session_prefs_1.setSessionPrefs)(sessionId, { modelSlots: slots });
922
+ if (slot === "main") {
923
+ this.setModel(sessionId, modelId);
924
+ }
925
+ else {
926
+ this.killProcess(session);
927
+ session.queuedMessages.length = 0;
928
+ session.queuePaused = false;
929
+ session.info.status = "idle";
930
+ session.emitter.emit("status", sessionId, "idle");
931
+ this.emitInfoUpdated(session, sessionId);
932
+ }
695
933
  }
696
934
  getModel(sessionId) {
697
935
  return this.sessions.get(sessionId)?.info.model || "sonnet";
@@ -702,7 +940,7 @@ class SessionManager {
702
940
  return;
703
941
  session.thinkingLevel = level;
704
942
  (0, session_prefs_1.setSessionPrefs)(sessionId, { thinkingLevel: level });
705
- const supportsEffort = (0, models_1.allowedEffortLevels)((0, models_1.resolveModel)(session.info.model)).length > 0;
943
+ const supportsEffort = this.modelEffortLevels(session.info.model).length > 0;
706
944
  if (session.stdin && supportsEffort) {
707
945
  const request = {
708
946
  type: "control_request",
@@ -904,45 +1142,33 @@ class SessionManager {
904
1142
  session.emitter.on("init", handler);
905
1143
  return () => session.emitter.off("init", handler);
906
1144
  }
907
- handleTodoWrite(session, sessionId, toolInput) {
908
- try {
909
- const input = JSON.parse(toolInput);
910
- const todos = input.todos;
911
- if (!Array.isArray(todos))
912
- return;
913
- session.todoItems = todos
914
- .filter((t) => t.content && t.status)
915
- .map((t) => ({
916
- content: t.content,
917
- status: t.status,
918
- activeForm: t.activeForm || undefined,
919
- }));
920
- session.emitter.emit("todos", sessionId, [...session.todoItems]);
921
- }
922
- catch {
923
- // invalid input, ignore
924
- }
925
- }
926
- rebuildTodosFromHistory(sessionId, messages) {
1145
+ loadTodosFromFiles(sessionId) {
927
1146
  const session = this.sessions.get(sessionId);
928
1147
  if (!session)
929
1148
  return;
930
- // If there's already a live todo state (set during the current process),
931
- // don't overwrite it from history.
932
1149
  if (session.todoItems.length > 0)
933
1150
  return;
934
- const todos = extractTodosFromHistory(messages);
1151
+ const watcher = new todo_watcher_1.TodoWatcher(session.cliSessionId, () => { });
1152
+ const todos = watcher.readOnce();
935
1153
  if (todos.length === 0)
936
1154
  return;
937
1155
  session.todoItems = todos;
938
1156
  session.emitter.emit("todos", sessionId, [...session.todoItems]);
939
1157
  }
1158
+ startTodoWatcher(session, sessionId) {
1159
+ if (session.todoWatcher) {
1160
+ session.todoWatcher.stop();
1161
+ }
1162
+ const watcher = new todo_watcher_1.TodoWatcher(session.cliSessionId, (todos) => {
1163
+ session.todoItems = todos;
1164
+ session.emitter.emit("todos", sessionId, [...todos]);
1165
+ });
1166
+ session.todoWatcher = watcher;
1167
+ watcher.start();
1168
+ }
940
1169
  extractUsage(session, sessionId, line) {
941
1170
  try {
942
1171
  const raw = JSON.parse(line.trim());
943
- if (raw.type === "result" && raw.modelUsage) {
944
- this.extractContextWindowSize(session, raw.modelUsage);
945
- }
946
1172
  if (raw.type !== "assistant" || !raw.message?.usage)
947
1173
  return;
948
1174
  // Skip synthetic responses (e.g. /context) that have all-zero usage
@@ -953,19 +1179,15 @@ class SessionManager {
953
1179
  const usage = { used, total: session.contextWindowSize };
954
1180
  session.contextUsage = usage;
955
1181
  session.emitter.emit("usage", sessionId, usage);
1182
+ session.totalTokens.input += u.input_tokens || 0;
1183
+ session.totalTokens.output += u.output_tokens || 0;
1184
+ session.totalTokens.cacheCreate += u.cache_creation_input_tokens || 0;
1185
+ session.totalTokens.cacheRead += u.cache_read_input_tokens || 0;
956
1186
  }
957
1187
  catch {
958
1188
  // not valid JSON, ignore
959
1189
  }
960
1190
  }
961
- extractContextWindowSize(session, modelUsage) {
962
- for (const model of Object.values(modelUsage)) {
963
- if (model.contextWindow && model.contextWindow > 0) {
964
- session.contextWindowSize = model.contextWindow;
965
- return;
966
- }
967
- }
968
- }
969
1191
  killProcessGroup(proc) {
970
1192
  if (!proc.pid)
971
1193
  return;
@@ -1010,6 +1232,11 @@ class SessionManager {
1010
1232
  session.process = null;
1011
1233
  session.stdin = null;
1012
1234
  }
1235
+ if (session.ptyRuntime) {
1236
+ const runtime = session.ptyRuntime;
1237
+ session.ptyRuntime = null;
1238
+ runtime.kill().catch(() => { });
1239
+ }
1013
1240
  session.compacting = false;
1014
1241
  }
1015
1242
  emitSystem(session, sessionId, text) {
@@ -1023,6 +1250,10 @@ class SessionManager {
1023
1250
  session.emitter.emit("pending", sessionId, count);
1024
1251
  }
1025
1252
  applyProcessedResult(session, sessionId, result) {
1253
+ const eventTypes = result.emit.map((e) => e.type).join(", ");
1254
+ if (eventTypes) {
1255
+ console.log(`[sm] applyProcessedResult for ${sessionId.slice(0, 8)}: events=[${eventTypes}], statusChange=${result.statusChange ?? "none"}, currentStatus=${session.info.status}`);
1256
+ }
1026
1257
  for (const msg of result.intermediateMessages) {
1027
1258
  session.emitter.emit("event", sessionId, { type: "message_done", message: msg });
1028
1259
  if (msg.toolUses.some((t) => t.name === "Agent")) {
@@ -1030,6 +1261,37 @@ class SessionManager {
1030
1261
  }
1031
1262
  }
1032
1263
  for (const sysMsg of result.systemMessages) {
1264
+ if (sysMsg === "__tool_use_start") {
1265
+ session.info.status = "running";
1266
+ console.log(`[sm] emit status running (via tool_use_start) for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
1267
+ session.emitter.emit("status", sessionId, "running");
1268
+ continue;
1269
+ }
1270
+ if (sysMsg === "__compact::hook_start") {
1271
+ if (!session.compacting) {
1272
+ (0, debug_logger_1.logDiag)(sessionId, "compact:hook-start");
1273
+ session.compacting = true;
1274
+ this.emitSystem(session, sessionId, "__compact::start");
1275
+ }
1276
+ continue;
1277
+ }
1278
+ if (sysMsg === "__compact::hook_done") {
1279
+ if (session.compacting) {
1280
+ (0, debug_logger_1.logDiag)(sessionId, "compact:hook-done");
1281
+ session.compacting = false;
1282
+ this.emitSystem(session, sessionId, "__compact::done");
1283
+ const postCompactEstimate = {
1284
+ used: Math.round(session.contextWindowSize * 0.1),
1285
+ total: session.contextWindowSize,
1286
+ };
1287
+ session.contextUsage = postCompactEstimate;
1288
+ session.emitter.emit("usage", sessionId, postCompactEstimate);
1289
+ session.info.status = "idle";
1290
+ session.emitter.emit("status", sessionId, "idle");
1291
+ this.flushQueuedMessage(session, sessionId);
1292
+ }
1293
+ continue;
1294
+ }
1033
1295
  const permModePrefix = "__permission_mode::";
1034
1296
  if (sysMsg.startsWith(permModePrefix)) {
1035
1297
  const mode = sysMsg.slice(permModePrefix.length);
@@ -1052,9 +1314,14 @@ class SessionManager {
1052
1314
  for (const errMsg of result.errors) {
1053
1315
  session.emitter.emit("error", sessionId, errMsg);
1054
1316
  }
1055
- for (const todoInput of result.todoInputs) {
1056
- this.handleTodoWrite(session, sessionId, todoInput);
1057
- }
1317
+ // After exiting plan mode the CLI process is killed and respawned with the
1318
+ // correct --permission-mode flag (see needsRespawnForPermissions). Between
1319
+ // the plan exit and the message_done that triggers the respawn, the old
1320
+ // process may still send permission_request events. The server auto-approves
1321
+ // these so the CLI isn't blocked, but we must also suppress the events from
1322
+ // reaching the UI -- otherwise the user sees phantom permission prompts that
1323
+ // don't actually gate anything.
1324
+ const bypassedRequestIds = new Set();
1058
1325
  for (const pa of result.permissionActions) {
1059
1326
  if (pa.type === "auto_approve") {
1060
1327
  this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
@@ -1062,16 +1329,18 @@ class SessionManager {
1062
1329
  else if (pa.type === "auto_deny") {
1063
1330
  this.respondToPermission(sessionId, pa.requestId, false, undefined, undefined, pa.denyReason);
1064
1331
  }
1065
- else if (session.bypassAllPermissions && !session.planMode) {
1066
- // CLI was spawned without bypass capability (e.g. after exiting plan
1067
- // mode) but the session has bypass enabled. Auto-approve server-side
1068
- // until the process respawns with the right flags.
1332
+ else if (session.bypassAllPermissions && !session.planMode && pa.toolName !== "AskUserQuestion") {
1069
1333
  this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
1334
+ bypassedRequestIds.add(pa.requestId);
1070
1335
  }
1071
1336
  else {
1072
1337
  const planPath = pa.toolName === "ExitPlanMode" ? (0, plans_1.findLatestPlanFile)() : undefined;
1338
+ const reqType = pa.toolName === "AskUserQuestion" ? "question" : "permission";
1339
+ if (reqType === "question") {
1340
+ console.log(`[question-debug] adding pending question: session=${sessionId.slice(0, 8)}, requestId=${pa.requestId}, total=${session.pendingRequests.size + 1}`);
1341
+ }
1073
1342
  session.pendingRequests.set(pa.requestId, {
1074
- type: pa.toolName === "AskUserQuestion" ? "question" : "permission",
1343
+ type: reqType,
1075
1344
  requestId: pa.requestId,
1076
1345
  toolName: pa.toolName,
1077
1346
  toolInput: pa.toolInput || "",
@@ -1086,6 +1355,12 @@ class SessionManager {
1086
1355
  if (result.compactDone) {
1087
1356
  session.compacting = false;
1088
1357
  this.emitSystem(session, sessionId, "__compact::done");
1358
+ const postCompactEstimate = {
1359
+ used: Math.round(session.contextWindowSize * 0.1),
1360
+ total: session.contextWindowSize,
1361
+ };
1362
+ session.contextUsage = postCompactEstimate;
1363
+ session.emitter.emit("usage", sessionId, postCompactEstimate);
1089
1364
  }
1090
1365
  if (result.emit.length > 0) {
1091
1366
  const listeners = session.emitter.listenerCount("event");
@@ -1094,6 +1369,9 @@ class SessionManager {
1094
1369
  }
1095
1370
  }
1096
1371
  for (const event of result.emit) {
1372
+ // Skip phantom permission events that were already bypass-approved above
1373
+ if (event.type === "permission_request" && event.requestId && bypassedRequestIds.has(event.requestId))
1374
+ continue;
1097
1375
  session.emitter.emit("event", sessionId, event);
1098
1376
  }
1099
1377
  session.streamingSnapshot = result.snapshot;
@@ -1111,6 +1389,7 @@ class SessionManager {
1111
1389
  }
1112
1390
  if (result.statusChange === "idle") {
1113
1391
  session.info.status = "idle";
1392
+ console.log(`[sm] emit status idle for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
1114
1393
  session.emitter.emit("status", sessionId, "idle");
1115
1394
  this.flushQueuedMessage(session, sessionId);
1116
1395
  }
@@ -1177,6 +1456,7 @@ class SessionManager {
1177
1456
  this.emitSystem(session, sessionId, `__model_picker::${current}`);
1178
1457
  return true;
1179
1458
  }
1459
+ this.log(sessionId, `/model command: args="${args}", was=${session.info.model}`);
1180
1460
  this.killProcess(session);
1181
1461
  session.info.model = args;
1182
1462
  session.info.status = "idle";
@@ -1203,18 +1483,148 @@ class SessionManager {
1203
1483
  " /clear, /reset, /new - Clear conversation and start fresh",
1204
1484
  " /model [name] - Show or switch model",
1205
1485
  " /rename <name> - Rename this session",
1486
+ " /cost - Show session token usage",
1487
+ " /context - Show context window usage",
1488
+ " /status - Show session status",
1206
1489
  " /help - Show this help message",
1207
1490
  "",
1208
- "All other slash commands (/compact, /cost, /context, /commit,",
1209
- "/review, /analyze, etc.) are passed directly to Claude.",
1491
+ "Other commands (/compact, /commit, /review, etc.) are passed to Claude when possible.",
1210
1492
  ].join("\n");
1211
1493
  this.emitSystem(session, sessionId, helpText);
1212
1494
  return true;
1213
1495
  }
1496
+ case "/cost": {
1497
+ const t = session.totalTokens;
1498
+ const lines = [
1499
+ `Input tokens: ${t.input.toLocaleString()}`,
1500
+ `Output tokens: ${t.output.toLocaleString()}`,
1501
+ `Cache write tokens: ${t.cacheCreate.toLocaleString()}`,
1502
+ `Cache read tokens: ${t.cacheRead.toLocaleString()}`,
1503
+ ];
1504
+ this.emitSystem(session, sessionId, lines.join("\n"));
1505
+ return true;
1506
+ }
1507
+ case "/context": {
1508
+ if (!session.contextUsage) {
1509
+ this.emitSystem(session, sessionId, "Context usage data not available yet.");
1510
+ return true;
1511
+ }
1512
+ const pct = session.contextWindowSize > 0 ? Math.round((session.contextUsage.used / session.contextWindowSize) * 100) : 0;
1513
+ this.emitSystem(session, sessionId, `Context window: ${session.contextUsage.used.toLocaleString()} / ${session.contextWindowSize.toLocaleString()} (${pct}%)`);
1514
+ return true;
1515
+ }
1516
+ case "/status": {
1517
+ const model = session.info.model || "sonnet";
1518
+ const runtime = session.runtime;
1519
+ const plan = session.planMode ? " [plan]" : "";
1520
+ this.emitSystem(session, sessionId, `Model: ${model} Runtime: ${runtime}${plan}`);
1521
+ return true;
1522
+ }
1523
+ }
1524
+ // In PTY mode, intercept commands that render CLI dialogs to prevent hangs
1525
+ if (session.ptyRuntime?.isAlive) {
1526
+ const dialogCmd = cmd.replace("/", "");
1527
+ if (SessionManager.DIALOG_COMMANDS.has(dialogCmd)) {
1528
+ this.emitSystem(session, sessionId, `"${cmd}" opens an interactive CLI dialog that isn't available in remote mode.`);
1529
+ return true;
1530
+ }
1214
1531
  }
1215
1532
  // All other slash commands pass through to Claude
1216
1533
  return false;
1217
1534
  }
1535
+ static DIALOG_COMMANDS = new Set([
1536
+ "config",
1537
+ "usage",
1538
+ "session",
1539
+ "stats",
1540
+ "doctor",
1541
+ "diff",
1542
+ "mcp",
1543
+ "permissions",
1544
+ "hooks",
1545
+ "tasks",
1546
+ "agents",
1547
+ "skills",
1548
+ "memory",
1549
+ "theme",
1550
+ "fast",
1551
+ "feedback",
1552
+ "copy",
1553
+ "branch",
1554
+ "plan",
1555
+ "chrome",
1556
+ "desktop",
1557
+ "ide",
1558
+ "mobile",
1559
+ "bridge",
1560
+ "sandbox",
1561
+ "export",
1562
+ "login",
1563
+ "logout",
1564
+ "upgrade",
1565
+ "rate-limit-options",
1566
+ "privacy-settings",
1567
+ "terminal-setup",
1568
+ "install-github-app",
1569
+ "remote-env",
1570
+ "remote-setup",
1571
+ "resume",
1572
+ "add-dir",
1573
+ "btw",
1574
+ "extra-usage",
1575
+ "passes",
1576
+ "think-back",
1577
+ "ultrareview",
1578
+ "tag",
1579
+ "exit",
1580
+ "effort",
1581
+ "color",
1582
+ "files",
1583
+ ]);
1584
+ static MEDIA_EXT = {
1585
+ "image/png": ".png",
1586
+ "image/jpeg": ".jpg",
1587
+ "image/gif": ".gif",
1588
+ "image/webp": ".webp",
1589
+ "application/pdf": ".pdf",
1590
+ };
1591
+ writeAttachments(images, documents) {
1592
+ if (!images?.length && !documents?.length)
1593
+ return [];
1594
+ const dir = node_path_1.default.join((0, paths_1.getCockpitCacheDir)(), "attachments");
1595
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
1596
+ const paths = [];
1597
+ for (const img of images ?? []) {
1598
+ const ext = SessionManager.MEDIA_EXT[img.mediaType] || ".png";
1599
+ const p = node_path_1.default.join(dir, `${(0, uuid_1.v4)()}${ext}`);
1600
+ (0, node_fs_1.writeFileSync)(p, Buffer.from(img.data, "base64"));
1601
+ paths.push(p);
1602
+ }
1603
+ for (const doc of documents ?? []) {
1604
+ const ext = SessionManager.MEDIA_EXT[doc.mediaType] || ".pdf";
1605
+ const p = node_path_1.default.join(dir, `${(0, uuid_1.v4)()}${ext}`);
1606
+ (0, node_fs_1.writeFileSync)(p, Buffer.from(doc.data, "base64"));
1607
+ paths.push(p);
1608
+ }
1609
+ return paths;
1610
+ }
1611
+ cleanupAttachments(session) {
1612
+ for (const p of session.attachmentPaths) {
1613
+ try {
1614
+ (0, node_fs_1.unlinkSync)(p);
1615
+ }
1616
+ catch {
1617
+ // file already cleaned up
1618
+ }
1619
+ }
1620
+ session.attachmentPaths = [];
1621
+ }
1622
+ buildPtyText(text, attachmentPaths) {
1623
+ if (attachmentPaths.length === 0)
1624
+ return text;
1625
+ const refs = attachmentPaths.map((p) => `[Attached image: ${p}]`).join("\n");
1626
+ return `${refs}\n${text}`;
1627
+ }
1218
1628
  buildContent(session, text, images, documents) {
1219
1629
  const reminder = session.pendingPlanReminder ? this.planModeReminderText() : null;
1220
1630
  if (session.pendingPlanReminder)
@@ -1308,7 +1718,10 @@ Additional Cockpit rules beyond the CLI's defaults:
1308
1718
  this.emitSystem(session, sessionId, "__compact::start");
1309
1719
  session.info.status = "running";
1310
1720
  session.emitter.emit("status", sessionId, "running");
1311
- if (session.process && session.stdin) {
1721
+ if (session.ptyRuntime?.isAlive) {
1722
+ session.ptyRuntime.sendText("/compact").catch(() => { });
1723
+ }
1724
+ else if (session.process && session.stdin) {
1312
1725
  const compactInput = { type: "user", message: { role: "user", content: "/compact" } };
1313
1726
  session.stdin.write(JSON.stringify(compactInput) + "\n");
1314
1727
  }
@@ -1331,9 +1744,27 @@ Additional Cockpit rules beyond the CLI's defaults:
1331
1744
  session.emitter.emit("queued", sessionId, session.queuedMessages.length);
1332
1745
  return true;
1333
1746
  }
1334
- (0, debug_logger_1.logDiag)(sessionId, "running:send", { hasProcess: !!session.process, hasStdin: !!session.stdin });
1747
+ (0, debug_logger_1.logDiag)(sessionId, "running:send", {
1748
+ hasProcess: !!session.process,
1749
+ hasStdin: !!session.stdin,
1750
+ runtime: session.runtime,
1751
+ ptyAlive: !!session.ptyRuntime?.isAlive,
1752
+ });
1335
1753
  session.info.status = "running";
1754
+ console.log(`[sm] emit status running for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
1336
1755
  session.emitter.emit("status", sessionId, "running");
1756
+ if (session.runtime === "pty" && session.ptyRuntime?.isAlive) {
1757
+ if (session.streamState)
1758
+ session.streamState.thinkingStartedAt = Date.now();
1759
+ this.cleanupAttachments(session);
1760
+ const attachments = this.writeAttachments(images, documents);
1761
+ session.attachmentPaths.push(...attachments);
1762
+ const ptyText = this.buildPtyText(text, attachments);
1763
+ session.ptyRuntime.sendText(ptyText).catch((err) => {
1764
+ this.log(sessionId, `pty sendText failed: ${err instanceof Error ? err.message : String(err)}`);
1765
+ });
1766
+ return true;
1767
+ }
1337
1768
  if (session.process && session.stdin) {
1338
1769
  if (session.streamState)
1339
1770
  session.streamState.thinkingStartedAt = Date.now();
@@ -1353,11 +1784,27 @@ Additional Cockpit rules beyond the CLI's defaults:
1353
1784
  }
1354
1785
  ensureProcess(sessionId) {
1355
1786
  const session = this.sessions.get(sessionId);
1356
- if (!session || session.process)
1787
+ if (!session || session.process || session.ptyRuntime?.isAlive)
1357
1788
  return;
1358
1789
  this.spawnProcess(session, sessionId);
1359
1790
  }
1791
+ /** Check effort levels for built-in models or custom provider models. */
1792
+ modelEffortLevels(modelId) {
1793
+ if (!modelId)
1794
+ return [];
1795
+ const builtin = (0, models_1.resolveModel)(modelId);
1796
+ if (builtin)
1797
+ return (0, models_1.allowedEffortLevels)(builtin);
1798
+ const resolved = (0, providers_1.resolveProviderModel)(modelId);
1799
+ if (resolved)
1800
+ return resolved.model.effortLevels;
1801
+ return [];
1802
+ }
1360
1803
  spawnProcess(session, sessionId, text, images, documents) {
1804
+ if (session.runtime === "pty") {
1805
+ this.spawnPtyProcess(session, sessionId, text, images, documents);
1806
+ return;
1807
+ }
1361
1808
  this.log(sessionId, `spawning CLI process (resume=${session.hasSpawnedBefore}, model=${session.info.model || "sonnet"})`);
1362
1809
  const args = ["-p", "--verbose", "--output-format", "stream-json", "--input-format", "stream-json"];
1363
1810
  // In plan mode, omit --allow-dangerously-skip-permissions so the CLI
@@ -1380,25 +1827,35 @@ Additional Cockpit rules beyond the CLI's defaults:
1380
1827
  else {
1381
1828
  args.push("--session-id", session.cliSessionId);
1382
1829
  }
1383
- if (session.info.model) {
1384
- args.push("--model", session.info.model);
1830
+ const resolved = (0, providers_1.resolveProviderModel)(session.info.model ?? "sonnet");
1831
+ const cliModel = resolved ? resolved.model.modelId : session.info.model;
1832
+ this.log(sessionId, `spawn: info.model=${session.info.model}, resolved=${resolved ? `${resolved.provider.id}:${resolved.model.modelId}` : "null"}, cliModel=${cliModel}`);
1833
+ if (cliModel) {
1834
+ args.push("--model", cliModel);
1385
1835
  }
1386
- if ((0, models_1.allowedEffortLevels)((0, models_1.resolveModel)(session.info.model)).length > 0) {
1836
+ if (this.modelEffortLevels(session.info.model).length > 0) {
1387
1837
  args.push("--effort", session.thinkingLevel);
1388
1838
  }
1389
1839
  const env = { ...process.env };
1390
1840
  delete env.CLAUDECODE;
1391
1841
  delete env.CLAUDE_CODE_ENTRYPOINT;
1392
- // Claude Code defaults to a model's full context window (1M for Opus 4.7,
1393
- // Sonnet 4.6) when no [1m] suffix is present, ignoring the suffix as the
1394
- // gate. CLAUDE_CODE_DISABLE_1M_CONTEXT is the only switch that forces 200K
1395
- // back regardless of model capability set it when the user picked 200K.
1396
- if (session.info.model && !/\[1m\]/i.test(session.info.model)) {
1842
+ if (resolved) {
1843
+ Object.assign(env, resolved.provider.envVars);
1844
+ }
1845
+ // CLAUDE_CODE_DISABLE_1M_CONTEXT is the only switch that forces a model
1846
+ // back to 200K regardless of its capability. Set it when the user picked
1847
+ // 200K for this session.
1848
+ const sizeKey = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
1849
+ if (models_1.CONTEXT_SIZES[sizeKey].disableEnv) {
1397
1850
  env.CLAUDE_CODE_DISABLE_1M_CONTEXT = "1";
1398
1851
  }
1852
+ if (session.modelSlots.subagent && session.modelSlots.subagent !== session.modelSlots.main) {
1853
+ const resolvedSub = (0, providers_1.resolveProviderModel)(session.modelSlots.subagent);
1854
+ env.ANTHROPIC_SMALL_FAST_MODEL = resolvedSub ? resolvedSub.model.modelId : session.modelSlots.subagent;
1855
+ }
1399
1856
  (0, node_fs_1.mkdirSync)(session.info.cwd, { recursive: true });
1400
1857
  const isWin = process.platform === "win32";
1401
- const proc = (0, node_child_process_1.spawn)("claude", args, {
1858
+ const proc = (0, node_child_process_1.spawn)(getClaudeBin(), args, {
1402
1859
  cwd: session.info.cwd,
1403
1860
  env,
1404
1861
  stdio: ["pipe", "pipe", "pipe"],
@@ -1408,6 +1865,7 @@ Additional Cockpit rules beyond the CLI's defaults:
1408
1865
  session.stdin = proc.stdin;
1409
1866
  session.hasSpawnedBefore = true;
1410
1867
  this.log(sessionId, `CLI process spawned (pid=${proc.pid})`);
1868
+ this.startTodoWatcher(session, sessionId);
1411
1869
  // Send initialize control request before the first user message to get
1412
1870
  // model capabilities, account info, and command metadata from the CLI.
1413
1871
  const initRequest = {
@@ -1508,6 +1966,12 @@ Additional Cockpit rules beyond the CLI's defaults:
1508
1966
  (0, debug_logger_1.logDiag)(sessionId, "compact:done-on-close");
1509
1967
  session.compacting = false;
1510
1968
  this.emitSystem(session, sessionId, "__compact::done");
1969
+ const postCompactEstimate = {
1970
+ used: Math.round(session.contextWindowSize * 0.1),
1971
+ total: session.contextWindowSize,
1972
+ };
1973
+ session.contextUsage = postCompactEstimate;
1974
+ session.emitter.emit("usage", sessionId, postCompactEstimate);
1511
1975
  }
1512
1976
  if (session.todoItems.length > 0 && session.todoItems.every((t) => t.status === "completed")) {
1513
1977
  session.todoItems = [];
@@ -1531,6 +1995,153 @@ Additional Cockpit rules beyond the CLI's defaults:
1531
1995
  this.flushQueuedMessage(session, sessionId);
1532
1996
  });
1533
1997
  }
1998
+ spawnPtyProcess(session, sessionId, text, images, documents) {
1999
+ if (session.ptyRuntime?.isAlive) {
2000
+ const existing = session.ptyRuntime;
2001
+ session.ptyRuntime = null;
2002
+ existing.kill().catch(() => { });
2003
+ }
2004
+ const hookRouter = (0, singleton_1.getHookRouter)();
2005
+ if (!hookRouter) {
2006
+ const msg = "PTY runtime requires the hook router; server boot did not register one";
2007
+ this.log(sessionId, msg);
2008
+ session.info.status = "idle";
2009
+ session.emitter.emit("status", sessionId, "idle");
2010
+ session.emitter.emit("error", sessionId, msg);
2011
+ return;
2012
+ }
2013
+ this.log(sessionId, `spawning PTY claude (resume=${session.hasSpawnedBefore}, model=${session.info.model || "sonnet"})`);
2014
+ (0, node_fs_1.mkdirSync)(session.info.cwd, { recursive: true });
2015
+ const streamState = (0, stream_processor_1.createStreamState)();
2016
+ session.streamState = streamState;
2017
+ streamState.thinkingStartedAt = Date.now();
2018
+ const extraArgs = [];
2019
+ if (session.hasSpawnedBefore || (0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
2020
+ extraArgs.push("--resume", session.cliSessionId);
2021
+ }
2022
+ else {
2023
+ extraArgs.push("--session-id", session.cliSessionId);
2024
+ }
2025
+ const resolvedPty = (0, providers_1.resolveProviderModel)(session.info.model ?? "sonnet");
2026
+ const cliModelPty = resolvedPty ? resolvedPty.model.modelId : session.info.model;
2027
+ if (cliModelPty)
2028
+ extraArgs.push("--model", cliModelPty);
2029
+ if (this.modelEffortLevels(session.info.model).length > 0) {
2030
+ extraArgs.push("--effort", session.thinkingLevel);
2031
+ }
2032
+ if (session.planMode) {
2033
+ extraArgs.push("--permission-mode", "plan");
2034
+ }
2035
+ else if (session.bypassAllPermissions) {
2036
+ extraArgs.push("--permission-mode", "bypassPermissions");
2037
+ }
2038
+ const extraEnv = {};
2039
+ if (resolvedPty)
2040
+ Object.assign(extraEnv, resolvedPty.provider.envVars);
2041
+ const sizeKeyPty = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
2042
+ if (models_1.CONTEXT_SIZES[sizeKeyPty].disableEnv) {
2043
+ extraEnv.CLAUDE_CODE_DISABLE_1M_CONTEXT = "1";
2044
+ }
2045
+ if (session.modelSlots.subagent && session.modelSlots.subagent !== session.modelSlots.main) {
2046
+ const resolvedSub = (0, providers_1.resolveProviderModel)(session.modelSlots.subagent);
2047
+ extraEnv.ANTHROPIC_SMALL_FAST_MODEL = resolvedSub ? resolvedSub.model.modelId : session.modelSlots.subagent;
2048
+ }
2049
+ const runtime = new pty_runtime_1.PtyRuntime({
2050
+ sessionId,
2051
+ cwd: session.info.cwd,
2052
+ cliSessionId: session.cliSessionId,
2053
+ hookRouter,
2054
+ claudeBin: getClaudeBin(),
2055
+ extraArgs,
2056
+ extraEnv,
2057
+ onEvents: (events) => {
2058
+ const types = events.map((e) => e.type).join(", ");
2059
+ console.log(`[sm] pty onEvents for ${sessionId.slice(0, 8)}: [${types}]`);
2060
+ const result = (0, stream_processor_1.processEvents)(events, streamState, { planMode: session.planMode, compacting: session.compacting });
2061
+ this.applyProcessedResult(session, sessionId, result);
2062
+ },
2063
+ onError: (err) => {
2064
+ this.log(sessionId, `pty runtime error: ${err}`);
2065
+ session.emitter.emit("error", sessionId, err);
2066
+ },
2067
+ onExit: ({ exitCode, signal }) => {
2068
+ this.log(sessionId, `PTY claude exited (code=${exitCode}, signal=${signal ?? "none"})`);
2069
+ if (session.ptyRuntime !== runtime)
2070
+ return;
2071
+ session.ptyRuntime = null;
2072
+ session.streamingSnapshot = null;
2073
+ (0, debug_logger_1.logDiag)(sessionId, "idle:pty-exit", { exitCode, flushedOnMessageDone: streamState.flushedOnMessageDone });
2074
+ if (session.transcriptWatcher) {
2075
+ session.transcriptWatcher.stop();
2076
+ session.transcriptWatcher = null;
2077
+ }
2078
+ session.info.status = "idle";
2079
+ session.emitter.emit("status", sessionId, "idle");
2080
+ if (session.compacting) {
2081
+ (0, debug_logger_1.logDiag)(sessionId, "compact:done-on-pty-exit");
2082
+ session.compacting = false;
2083
+ this.emitSystem(session, sessionId, "__compact::done");
2084
+ const postCompactEstimate = {
2085
+ used: Math.round(session.contextWindowSize * 0.1),
2086
+ total: session.contextWindowSize,
2087
+ };
2088
+ session.contextUsage = postCompactEstimate;
2089
+ session.emitter.emit("usage", sessionId, postCompactEstimate);
2090
+ }
2091
+ if (session.todoItems.length > 0 && session.todoItems.every((t) => t.status === "completed")) {
2092
+ session.todoItems = [];
2093
+ session.emitter.emit("todos", sessionId, []);
2094
+ }
2095
+ if (!streamState.flushedOnMessageDone) {
2096
+ this.flushQueuedMessage(session, sessionId);
2097
+ }
2098
+ },
2099
+ });
2100
+ session.ptyRuntime = runtime;
2101
+ session.hasSpawnedBefore = true;
2102
+ this.cleanupAttachments(session);
2103
+ const attachments = this.writeAttachments(images, documents);
2104
+ session.attachmentPaths.push(...attachments);
2105
+ const ptyText = text ? this.buildPtyText(text, attachments) : text;
2106
+ const watcher = new transcript_watcher_1.TranscriptWatcher(session.cliSessionId, session.info.cwd, (messages, lastUsage) => {
2107
+ session.emitter.emit("transcript", sessionId, messages);
2108
+ if (lastUsage) {
2109
+ const usage = { used: lastUsage.used, total: session.contextWindowSize };
2110
+ session.contextUsage = usage;
2111
+ session.emitter.emit("usage", sessionId, usage);
2112
+ }
2113
+ if (session.compacting && messages.some((m) => m.content === "__compacted__")) {
2114
+ (0, debug_logger_1.logDiag)(sessionId, "compact:done-on-transcript");
2115
+ session.compacting = false;
2116
+ this.emitSystem(session, sessionId, "__compact::done");
2117
+ const postCompactEstimate = {
2118
+ used: Math.round(session.contextWindowSize * 0.1),
2119
+ total: session.contextWindowSize,
2120
+ };
2121
+ session.contextUsage = postCompactEstimate;
2122
+ session.emitter.emit("usage", sessionId, postCompactEstimate);
2123
+ session.info.status = "idle";
2124
+ session.emitter.emit("status", sessionId, "idle");
2125
+ this.flushQueuedMessage(session, sessionId);
2126
+ }
2127
+ });
2128
+ session.transcriptWatcher = watcher;
2129
+ this.startTodoWatcher(session, sessionId);
2130
+ runtime
2131
+ .start(ptyText)
2132
+ .then(() => {
2133
+ this.log(sessionId, `PTY claude ready (pid=${runtime.pid})`);
2134
+ watcher.start();
2135
+ })
2136
+ .catch((err) => {
2137
+ const msg = err instanceof Error ? err.message : String(err);
2138
+ this.log(sessionId, `pty runtime start failed: ${msg}`);
2139
+ session.ptyRuntime = null;
2140
+ session.info.status = "idle";
2141
+ session.emitter.emit("status", sessionId, "idle");
2142
+ session.emitter.emit("error", sessionId, msg);
2143
+ });
2144
+ }
1534
2145
  async loadAgentChildren(session, sessionId, messageId, cwd) {
1535
2146
  try {
1536
2147
  const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd);
@@ -1554,12 +2165,15 @@ Additional Cockpit rules beyond the CLI's defaults:
1554
2165
  }
1555
2166
  }
1556
2167
  exports.SessionManager = SessionManager;
1557
- const MCP_CACHE_PATH = node_path_1.default.join((0, node_os_1.homedir)(), ".cockpit", "mcp-servers.json");
2168
+ function mcpCachePath() {
2169
+ return node_path_1.default.join((0, paths_1.getCockpitDir)(), "mcp-servers.json");
2170
+ }
1558
2171
  function loadMcpServerCache() {
1559
2172
  try {
1560
- if (!(0, node_fs_1.existsSync)(MCP_CACHE_PATH))
2173
+ const fp = mcpCachePath();
2174
+ if (!(0, node_fs_1.existsSync)(fp))
1561
2175
  return [];
1562
- return JSON.parse((0, node_fs_1.readFileSync)(MCP_CACHE_PATH, "utf-8"));
2176
+ return JSON.parse((0, node_fs_1.readFileSync)(fp, "utf-8"));
1563
2177
  }
1564
2178
  catch {
1565
2179
  return [];
@@ -1567,43 +2181,12 @@ function loadMcpServerCache() {
1567
2181
  }
1568
2182
  function saveMcpServerCache(servers) {
1569
2183
  try {
1570
- const dir = node_path_1.default.dirname(MCP_CACHE_PATH);
2184
+ const fp = mcpCachePath();
2185
+ const dir = node_path_1.default.dirname(fp);
1571
2186
  (0, node_fs_1.mkdirSync)(dir, { recursive: true });
1572
- (0, node_fs_1.writeFileSync)(MCP_CACHE_PATH, JSON.stringify(servers));
2187
+ (0, node_fs_1.writeFileSync)(fp, JSON.stringify(servers));
1573
2188
  }
1574
2189
  catch {
1575
2190
  // best-effort
1576
2191
  }
1577
2192
  }
1578
- // Walk messages newest-first, stop at the most recent /clear boundary, and
1579
- // pull todos from the last TodoWrite call. Pure function so the history-view
1580
- // branch can use it without an in-memory session.
1581
- function extractTodosFromHistory(messages) {
1582
- for (let i = messages.length - 1; i >= 0; i--) {
1583
- const msg = messages[i];
1584
- if (msg.role === "system" && msg.content === "__compacted__")
1585
- return [];
1586
- if (msg.role !== "assistant")
1587
- continue;
1588
- for (let j = msg.toolUses.length - 1; j >= 0; j--) {
1589
- if (msg.toolUses[j].name !== "TodoWrite")
1590
- continue;
1591
- try {
1592
- const input = JSON.parse(msg.toolUses[j].input);
1593
- if (!Array.isArray(input.todos))
1594
- return [];
1595
- return input.todos
1596
- .filter((t) => t.content && t.status)
1597
- .map((t) => ({
1598
- content: t.content,
1599
- status: t.status,
1600
- activeForm: t.activeForm || undefined,
1601
- }));
1602
- }
1603
- catch {
1604
- return [];
1605
- }
1606
- }
1607
- }
1608
- return [];
1609
- }