@alexjbarnes/cockpit 0.1.1 → 0.3.0

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 (707) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +28 -3
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +147 -3
  5. package/.next/react-loadable-manifest.json +19 -3
  6. package/.next/required-server-files.js +3 -0
  7. package/.next/required-server-files.json +3 -0
  8. package/.next/routes-manifest.json +162 -0
  9. package/.next/server/app/(app)/agents/[name]/page.js +3 -3
  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 +3 -3
  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 -0
  40. package/.next/server/app/(app)/inbox/[id]/page.js.nft.json +1 -0
  41. package/.next/server/app/(app)/inbox/[id]/page_client-reference-manifest.js +1 -0
  42. package/.next/server/app/(app)/inbox/page.js +2 -0
  43. package/.next/server/app/(app)/inbox/page.js.nft.json +1 -0
  44. package/.next/server/app/(app)/inbox/page_client-reference-manifest.js +1 -0
  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 +6 -6
  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 -0
  82. package/.next/server/app/(app)/settings/notifications/page.js.nft.json +1 -0
  83. package/.next/server/app/(app)/settings/notifications/page_client-reference-manifest.js +1 -0
  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 +5 -0
  169. package/.next/server/app/api/inbox/[id]/route.js.nft.json +1 -0
  170. package/.next/server/app/api/inbox/[id]/route_client-reference-manifest.js +1 -0
  171. package/.next/server/app/api/inbox/route.js +5 -0
  172. package/.next/server/app/api/inbox/route.js.nft.json +1 -0
  173. package/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -0
  174. package/.next/server/app/api/jobs/[id]/route.js +1 -1
  175. package/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -1
  176. package/.next/server/app/api/jobs/[id]/runs/[runId]/route.js +1 -1
  177. package/.next/server/app/api/jobs/[id]/runs/[runId]/transcript/route.js +1 -1
  178. package/.next/server/app/api/jobs/[id]/runs/route.js +1 -1
  179. package/.next/server/app/api/jobs/[id]/trigger/route.js +1 -1
  180. package/.next/server/app/api/jobs/[id]/trigger/route.js.nft.json +1 -1
  181. package/.next/server/app/api/jobs/mcp-discover/route.js +1 -1
  182. package/.next/server/app/api/jobs/mcp-discover/route.js.nft.json +1 -1
  183. package/.next/server/app/api/jobs/route.js +1 -1
  184. package/.next/server/app/api/jobs/route.js.nft.json +1 -1
  185. package/.next/server/app/api/jobs/status/route.js +1 -1
  186. package/.next/server/app/api/mcp-servers/[name]/route.js +1 -1
  187. package/.next/server/app/api/mcp-servers/[name]/test/route.js +1 -1
  188. package/.next/server/app/api/mcp-servers/route.js +1 -1
  189. package/.next/server/app/api/notifications/route.js +1 -0
  190. package/.next/server/app/api/notifications/route.js.nft.json +1 -0
  191. package/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
  192. package/.next/server/app/api/notifications/test/route.js +5 -0
  193. package/.next/server/app/api/notifications/test/route.js.nft.json +1 -0
  194. package/.next/server/app/api/notifications/test/route_client-reference-manifest.js +1 -0
  195. package/.next/server/app/api/providers/[id]/route.js +1 -0
  196. package/.next/server/app/api/providers/[id]/route.js.nft.json +1 -0
  197. package/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -0
  198. package/.next/server/app/api/providers/route.js +1 -0
  199. package/.next/server/app/api/providers/route.js.nft.json +1 -0
  200. package/.next/server/app/api/providers/route_client-reference-manifest.js +1 -0
  201. package/.next/server/app/api/reviews/pinned/route.js +1 -0
  202. package/.next/server/app/api/reviews/pinned/route.js.nft.json +1 -0
  203. package/.next/server/app/api/reviews/pinned/route_client-reference-manifest.js +1 -0
  204. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  205. package/.next/server/app/api/sessions/[id]/mcp/route.js +1 -1
  206. package/.next/server/app/api/sessions/[id]/mcp/route.js.nft.json +1 -1
  207. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  208. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  209. package/.next/server/app/api/sessions/[id]/search/route.js +1 -1
  210. package/.next/server/app/api/sessions/[id]/tabs/route.js +1 -0
  211. package/.next/server/app/api/sessions/[id]/tabs/route.js.nft.json +1 -0
  212. package/.next/server/app/api/sessions/[id]/tabs/route_client-reference-manifest.js +1 -0
  213. package/.next/server/app/api/sessions/bulk-delete/route.js +1 -0
  214. package/.next/server/app/api/sessions/bulk-delete/route.js.nft.json +1 -0
  215. package/.next/server/app/api/sessions/bulk-delete/route_client-reference-manifest.js +1 -0
  216. package/.next/server/app/api/sessions/by-ids/route.js +1 -0
  217. package/.next/server/app/api/sessions/by-ids/route.js.nft.json +1 -0
  218. package/.next/server/app/api/sessions/by-ids/route_client-reference-manifest.js +1 -0
  219. package/.next/server/app/api/sessions/group/route.js +1 -0
  220. package/.next/server/app/api/sessions/group/route.js.nft.json +1 -0
  221. package/.next/server/app/api/sessions/group/route_client-reference-manifest.js +1 -0
  222. package/.next/server/app/api/sessions/pinned/route.js +1 -1
  223. package/.next/server/app/api/sessions/route.js +1 -1
  224. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  225. package/.next/server/app/api/sessions/search/route.js +1 -0
  226. package/.next/server/app/api/sessions/search/route.js.nft.json +1 -0
  227. package/.next/server/app/api/sessions/search/route_client-reference-manifest.js +1 -0
  228. package/.next/server/app/api/sessions/thinking/route.js +1 -0
  229. package/.next/server/app/api/sessions/thinking/route.js.nft.json +1 -0
  230. package/.next/server/app/api/sessions/thinking/route_client-reference-manifest.js +1 -0
  231. package/.next/server/app/api/skills/[name]/route.js +1 -1
  232. package/.next/server/app/api/skills/route.js +1 -1
  233. package/.next/server/app/api/terminal/[id]/route.js +1 -0
  234. package/.next/server/app/api/terminal/[id]/route.js.nft.json +1 -0
  235. package/.next/server/app/api/terminal/[id]/route_client-reference-manifest.js +1 -0
  236. package/.next/server/app/api/terminal/route.js +1 -0
  237. package/.next/server/app/api/terminal/route.js.nft.json +1 -0
  238. package/.next/server/app/api/terminal/route_client-reference-manifest.js +1 -0
  239. package/.next/server/app/api/usage/route.js +1 -1
  240. package/.next/server/app/api/version/changelog/route.js +1 -0
  241. package/.next/server/app/api/version/changelog/route.js.nft.json +1 -0
  242. package/.next/server/app/api/version/changelog/route_client-reference-manifest.js +1 -0
  243. package/.next/server/app/api/version/cockpit/changelog/route.js +1 -0
  244. package/.next/server/app/api/version/cockpit/changelog/route.js.nft.json +1 -0
  245. package/.next/server/app/api/version/cockpit/changelog/route_client-reference-manifest.js +1 -0
  246. package/.next/server/app/api/version/cockpit/route.js +1 -1
  247. package/.next/server/app/api/version/route.js +2 -2
  248. package/.next/server/app/changes.html +1 -1
  249. package/.next/server/app/changes.rsc +4 -4
  250. package/.next/server/app/changes.segments/!KGFwcCk/changes/__PAGE__.segment.rsc +2 -2
  251. package/.next/server/app/changes.segments/!KGFwcCk/changes.segment.rsc +1 -1
  252. package/.next/server/app/changes.segments/!KGFwcCk.segment.rsc +2 -2
  253. package/.next/server/app/changes.segments/_full.segment.rsc +4 -4
  254. package/.next/server/app/changes.segments/_head.segment.rsc +1 -1
  255. package/.next/server/app/changes.segments/_index.segment.rsc +2 -2
  256. package/.next/server/app/changes.segments/_tree.segment.rsc +2 -2
  257. package/.next/server/app/claude-md/edit.html +1 -1
  258. package/.next/server/app/claude-md/edit.rsc +4 -4
  259. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit/__PAGE__.segment.rsc +2 -2
  260. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit.segment.rsc +1 -1
  261. package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
  262. package/.next/server/app/claude-md/edit.segments/!KGFwcCk.segment.rsc +2 -2
  263. package/.next/server/app/claude-md/edit.segments/_full.segment.rsc +4 -4
  264. package/.next/server/app/claude-md/edit.segments/_head.segment.rsc +1 -1
  265. package/.next/server/app/claude-md/edit.segments/_index.segment.rsc +2 -2
  266. package/.next/server/app/claude-md/edit.segments/_tree.segment.rsc +2 -2
  267. package/.next/server/app/claude-md.html +1 -1
  268. package/.next/server/app/claude-md.rsc +4 -4
  269. package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md/__PAGE__.segment.rsc +2 -2
  270. package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
  271. package/.next/server/app/claude-md.segments/!KGFwcCk.segment.rsc +2 -2
  272. package/.next/server/app/claude-md.segments/_full.segment.rsc +4 -4
  273. package/.next/server/app/claude-md.segments/_head.segment.rsc +1 -1
  274. package/.next/server/app/claude-md.segments/_index.segment.rsc +2 -2
  275. package/.next/server/app/claude-md.segments/_tree.segment.rsc +2 -2
  276. package/.next/server/app/commands.html +1 -1
  277. package/.next/server/app/commands.rsc +4 -4
  278. package/.next/server/app/commands.segments/!KGFwcCk/commands/__PAGE__.segment.rsc +2 -2
  279. package/.next/server/app/commands.segments/!KGFwcCk/commands.segment.rsc +1 -1
  280. package/.next/server/app/commands.segments/!KGFwcCk.segment.rsc +2 -2
  281. package/.next/server/app/commands.segments/_full.segment.rsc +4 -4
  282. package/.next/server/app/commands.segments/_head.segment.rsc +1 -1
  283. package/.next/server/app/commands.segments/_index.segment.rsc +2 -2
  284. package/.next/server/app/commands.segments/_tree.segment.rsc +2 -2
  285. package/.next/server/app/files.html +1 -1
  286. package/.next/server/app/files.rsc +4 -4
  287. package/.next/server/app/files.segments/!KGFwcCk/files/__PAGE__.segment.rsc +2 -2
  288. package/.next/server/app/files.segments/!KGFwcCk/files.segment.rsc +1 -1
  289. package/.next/server/app/files.segments/!KGFwcCk.segment.rsc +2 -2
  290. package/.next/server/app/files.segments/_full.segment.rsc +4 -4
  291. package/.next/server/app/files.segments/_head.segment.rsc +1 -1
  292. package/.next/server/app/files.segments/_index.segment.rsc +2 -2
  293. package/.next/server/app/files.segments/_tree.segment.rsc +2 -2
  294. package/.next/server/app/hooks.html +1 -1
  295. package/.next/server/app/hooks.rsc +4 -4
  296. package/.next/server/app/hooks.segments/!KGFwcCk/hooks/__PAGE__.segment.rsc +2 -2
  297. package/.next/server/app/hooks.segments/!KGFwcCk/hooks.segment.rsc +1 -1
  298. package/.next/server/app/hooks.segments/!KGFwcCk.segment.rsc +2 -2
  299. package/.next/server/app/hooks.segments/_full.segment.rsc +4 -4
  300. package/.next/server/app/hooks.segments/_head.segment.rsc +1 -1
  301. package/.next/server/app/hooks.segments/_index.segment.rsc +2 -2
  302. package/.next/server/app/hooks.segments/_tree.segment.rsc +2 -2
  303. package/.next/server/app/inbox.html +1 -0
  304. package/.next/server/app/inbox.meta +16 -0
  305. package/.next/server/app/inbox.rsc +23 -0
  306. package/.next/server/app/inbox.segments/!KGFwcCk/inbox/__PAGE__.segment.rsc +9 -0
  307. package/.next/server/app/inbox.segments/!KGFwcCk/inbox.segment.rsc +5 -0
  308. package/.next/server/app/inbox.segments/!KGFwcCk.segment.rsc +7 -0
  309. package/.next/server/app/inbox.segments/_full.segment.rsc +23 -0
  310. package/.next/server/app/inbox.segments/_head.segment.rsc +6 -0
  311. package/.next/server/app/inbox.segments/_index.segment.rsc +5 -0
  312. package/.next/server/app/inbox.segments/_tree.segment.rsc +2 -0
  313. package/.next/server/app/index.html +1 -1
  314. package/.next/server/app/index.rsc +4 -4
  315. package/.next/server/app/index.segments/!KGFwcCk/__PAGE__.segment.rsc +2 -2
  316. package/.next/server/app/index.segments/!KGFwcCk.segment.rsc +2 -2
  317. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  318. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  319. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  320. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  321. package/.next/server/app/jobs.html +1 -1
  322. package/.next/server/app/jobs.rsc +4 -4
  323. package/.next/server/app/jobs.segments/!KGFwcCk/jobs/__PAGE__.segment.rsc +2 -2
  324. package/.next/server/app/jobs.segments/!KGFwcCk/jobs.segment.rsc +1 -1
  325. package/.next/server/app/jobs.segments/!KGFwcCk.segment.rsc +2 -2
  326. package/.next/server/app/jobs.segments/_full.segment.rsc +4 -4
  327. package/.next/server/app/jobs.segments/_head.segment.rsc +1 -1
  328. package/.next/server/app/jobs.segments/_index.segment.rsc +2 -2
  329. package/.next/server/app/jobs.segments/_tree.segment.rsc +2 -2
  330. package/.next/server/app/login/page.js +2 -2
  331. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  332. package/.next/server/app/login.html +1 -1
  333. package/.next/server/app/login.rsc +2 -2
  334. package/.next/server/app/login.segments/_full.segment.rsc +2 -2
  335. package/.next/server/app/login.segments/_head.segment.rsc +1 -1
  336. package/.next/server/app/login.segments/_index.segment.rsc +2 -2
  337. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  338. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  339. package/.next/server/app/login.segments/login.segment.rsc +1 -1
  340. package/.next/server/app/mcp-servers.html +1 -1
  341. package/.next/server/app/mcp-servers.rsc +4 -4
  342. package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers/__PAGE__.segment.rsc +2 -2
  343. package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers.segment.rsc +1 -1
  344. package/.next/server/app/mcp-servers.segments/!KGFwcCk.segment.rsc +2 -2
  345. package/.next/server/app/mcp-servers.segments/_full.segment.rsc +4 -4
  346. package/.next/server/app/mcp-servers.segments/_head.segment.rsc +1 -1
  347. package/.next/server/app/mcp-servers.segments/_index.segment.rsc +2 -2
  348. package/.next/server/app/mcp-servers.segments/_tree.segment.rsc +2 -2
  349. package/.next/server/app/reviews.html +1 -1
  350. package/.next/server/app/reviews.rsc +4 -4
  351. package/.next/server/app/reviews.segments/!KGFwcCk/reviews/__PAGE__.segment.rsc +2 -2
  352. package/.next/server/app/reviews.segments/!KGFwcCk/reviews.segment.rsc +1 -1
  353. package/.next/server/app/reviews.segments/!KGFwcCk.segment.rsc +2 -2
  354. package/.next/server/app/reviews.segments/_full.segment.rsc +4 -4
  355. package/.next/server/app/reviews.segments/_head.segment.rsc +1 -1
  356. package/.next/server/app/reviews.segments/_index.segment.rsc +2 -2
  357. package/.next/server/app/reviews.segments/_tree.segment.rsc +2 -2
  358. package/.next/server/app/settings/appearance.html +1 -0
  359. package/.next/server/app/settings/appearance.meta +17 -0
  360. package/.next/server/app/settings/appearance.rsc +23 -0
  361. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance/__PAGE__.segment.rsc +9 -0
  362. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance.segment.rsc +5 -0
  363. package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings.segment.rsc +5 -0
  364. package/.next/server/app/settings/appearance.segments/!KGFwcCk.segment.rsc +7 -0
  365. package/.next/server/app/settings/appearance.segments/_full.segment.rsc +23 -0
  366. package/.next/server/app/settings/appearance.segments/_head.segment.rsc +6 -0
  367. package/.next/server/app/settings/appearance.segments/_index.segment.rsc +5 -0
  368. package/.next/server/app/settings/appearance.segments/_tree.segment.rsc +2 -0
  369. package/.next/server/app/settings/notifications.html +1 -0
  370. package/.next/server/app/settings/notifications.meta +17 -0
  371. package/.next/server/app/settings/notifications.rsc +23 -0
  372. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications/__PAGE__.segment.rsc +9 -0
  373. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications.segment.rsc +5 -0
  374. package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings.segment.rsc +5 -0
  375. package/.next/server/app/settings/notifications.segments/!KGFwcCk.segment.rsc +7 -0
  376. package/.next/server/app/settings/notifications.segments/_full.segment.rsc +23 -0
  377. package/.next/server/app/settings/notifications.segments/_head.segment.rsc +6 -0
  378. package/.next/server/app/settings/notifications.segments/_index.segment.rsc +5 -0
  379. package/.next/server/app/settings/notifications.segments/_tree.segment.rsc +2 -0
  380. package/.next/server/app/settings/providers/new.html +1 -0
  381. package/.next/server/app/settings/providers/new.meta +18 -0
  382. package/.next/server/app/settings/providers/new.rsc +23 -0
  383. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new/__PAGE__.segment.rsc +9 -0
  384. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new.segment.rsc +5 -0
  385. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
  386. package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings.segment.rsc +5 -0
  387. package/.next/server/app/settings/providers/new.segments/!KGFwcCk.segment.rsc +7 -0
  388. package/.next/server/app/settings/providers/new.segments/_full.segment.rsc +23 -0
  389. package/.next/server/app/settings/providers/new.segments/_head.segment.rsc +6 -0
  390. package/.next/server/app/settings/providers/new.segments/_index.segment.rsc +5 -0
  391. package/.next/server/app/settings/providers/new.segments/_tree.segment.rsc +2 -0
  392. package/.next/server/app/settings/providers.html +1 -0
  393. package/.next/server/app/settings/providers.meta +17 -0
  394. package/.next/server/app/settings/providers.rsc +23 -0
  395. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers/__PAGE__.segment.rsc +9 -0
  396. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
  397. package/.next/server/app/settings/providers.segments/!KGFwcCk/settings.segment.rsc +5 -0
  398. package/.next/server/app/settings/providers.segments/!KGFwcCk.segment.rsc +7 -0
  399. package/.next/server/app/settings/providers.segments/_full.segment.rsc +23 -0
  400. package/.next/server/app/settings/providers.segments/_head.segment.rsc +6 -0
  401. package/.next/server/app/settings/providers.segments/_index.segment.rsc +5 -0
  402. package/.next/server/app/settings/providers.segments/_tree.segment.rsc +2 -0
  403. package/.next/server/app/settings/session.html +1 -0
  404. package/.next/server/app/settings/session.meta +17 -0
  405. package/.next/server/app/settings/session.rsc +23 -0
  406. package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session/__PAGE__.segment.rsc +9 -0
  407. package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session.segment.rsc +5 -0
  408. package/.next/server/app/settings/session.segments/!KGFwcCk/settings.segment.rsc +5 -0
  409. package/.next/server/app/settings/session.segments/!KGFwcCk.segment.rsc +7 -0
  410. package/.next/server/app/settings/session.segments/_full.segment.rsc +23 -0
  411. package/.next/server/app/settings/session.segments/_head.segment.rsc +6 -0
  412. package/.next/server/app/settings/session.segments/_index.segment.rsc +5 -0
  413. package/.next/server/app/settings/session.segments/_tree.segment.rsc +2 -0
  414. package/.next/server/app/settings.html +1 -1
  415. package/.next/server/app/settings.rsc +4 -4
  416. package/.next/server/app/settings.segments/!KGFwcCk/settings/__PAGE__.segment.rsc +2 -2
  417. package/.next/server/app/settings.segments/!KGFwcCk/settings.segment.rsc +1 -1
  418. package/.next/server/app/settings.segments/!KGFwcCk.segment.rsc +2 -2
  419. package/.next/server/app/settings.segments/_full.segment.rsc +4 -4
  420. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  421. package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  422. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  423. package/.next/server/app/skills.html +1 -1
  424. package/.next/server/app/skills.rsc +4 -4
  425. package/.next/server/app/skills.segments/!KGFwcCk/skills/__PAGE__.segment.rsc +2 -2
  426. package/.next/server/app/skills.segments/!KGFwcCk/skills.segment.rsc +1 -1
  427. package/.next/server/app/skills.segments/!KGFwcCk.segment.rsc +2 -2
  428. package/.next/server/app/skills.segments/_full.segment.rsc +4 -4
  429. package/.next/server/app/skills.segments/_head.segment.rsc +1 -1
  430. package/.next/server/app/skills.segments/_index.segment.rsc +2 -2
  431. package/.next/server/app/skills.segments/_tree.segment.rsc +2 -2
  432. package/.next/server/app-paths-manifest.json +28 -3
  433. package/.next/server/chunks/1002.js +18 -0
  434. package/.next/server/chunks/1011.js +1 -0
  435. package/.next/server/chunks/1979.js +2 -2
  436. package/.next/server/chunks/{9012.js → 3006.js} +3 -3
  437. package/.next/server/chunks/3108.js +1 -0
  438. package/.next/server/chunks/3434.js +1 -0
  439. package/.next/server/chunks/{6142.js → 4342.js} +1 -1
  440. package/.next/server/chunks/4352.js +1 -0
  441. package/.next/server/chunks/4445.js +1 -1
  442. package/.next/server/chunks/5965.js +1 -1
  443. package/.next/server/chunks/7782.js +6 -0
  444. package/.next/server/chunks/8148.js +1 -0
  445. package/.next/server/chunks/9599.js +11 -0
  446. package/.next/server/middleware-build-manifest.js +1 -1
  447. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  448. package/.next/server/pages/404.html +1 -1
  449. package/.next/server/pages/500.html +1 -1
  450. package/.next/server/server-reference-manifest.json +1 -1
  451. package/.next/static/chunks/{35922.5bdf78a760129504.js → 13541.056c34ca7fde6869.js} +1 -1
  452. package/.next/static/chunks/26126-97874904b42befb8.js +1 -0
  453. package/.next/static/chunks/{22086-756d490e3320ad15.js → 31010-6e87f77b97544424.js} +1 -1
  454. package/.next/static/chunks/3765-d323c6675307a63e.js +20 -0
  455. package/.next/static/chunks/41487-d802643f4a8fad3c.js +199 -0
  456. package/.next/static/chunks/48273-bbd15bac6733dfc4.js +6 -0
  457. package/.next/static/chunks/{80392.bca860d8b5972706.js → 58011.3de5770e8b0d8759.js} +1 -1
  458. package/.next/static/chunks/63606.a387b0261d6523ab.js +1 -0
  459. package/.next/static/chunks/6935-f436a624267529fb.js +1 -0
  460. package/.next/static/chunks/{69427.755a0a4013596f7a.js → 69427.a0b463c808aa54c8.js} +1 -1
  461. package/.next/static/chunks/86939-dfc6f8eb395caa89.js +1 -0
  462. package/.next/static/chunks/app/(app)/agents/[name]/page-8bdd0359043537d4.js +8 -0
  463. package/.next/static/chunks/app/(app)/agents/page-6fcfd7ab6781814e.js +1 -0
  464. package/.next/static/chunks/app/(app)/changes/page-4549a5bd72d77e3e.js +1 -0
  465. package/.next/static/chunks/app/(app)/claude-md/edit/page-08e6e120e71979f4.js +1 -0
  466. package/.next/static/chunks/app/(app)/claude-md/page-cd9e2176a12ba241.js +1 -0
  467. package/.next/static/chunks/app/(app)/commands/[name]/page-7cdfdef29ded0aa0.js +6 -0
  468. package/.next/static/chunks/app/(app)/commands/page-f126b608b04747ac.js +1 -0
  469. package/.next/static/chunks/app/(app)/files/page-f526eb95821e000e.js +1 -0
  470. package/.next/static/chunks/app/(app)/hooks/[event]/page-28038323fd29adfa.js +6 -0
  471. package/.next/static/chunks/app/(app)/hooks/page-f1f39284e53c0344.js +1 -0
  472. package/.next/static/chunks/app/(app)/inbox/[id]/page-bc1ff3a0db0114a4.js +1 -0
  473. package/.next/static/chunks/app/(app)/inbox/page-82e03870103ce9bd.js +1 -0
  474. package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-7fb788f772ff2129.js +1 -0
  475. package/.next/static/chunks/app/(app)/jobs/[id]/page-a5856b9ae967ff59.js +1 -0
  476. package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-b7c513402db11db6.js +1 -0
  477. package/.next/static/chunks/app/(app)/jobs/page-e9bbd6c116b9699f.js +1 -0
  478. package/.next/static/chunks/app/(app)/layout-ce9e1be301c60fe5.js +1 -0
  479. package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-d6d805a27ec0b0c0.js +1 -0
  480. package/.next/static/chunks/app/(app)/mcp-servers/page-4b7276d43451cd43.js +1 -0
  481. package/.next/static/chunks/app/(app)/page-027a5382da30ddb9.js +1 -0
  482. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-9ab2955c455bb5fa.js +13 -0
  483. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/page-c5fd013309ab3eba.js +1 -0
  484. package/.next/static/chunks/app/(app)/reviews/page-47530d93bb9d4a76.js +1 -0
  485. package/.next/static/chunks/app/(app)/sessions/[id]/page-94f891e1b54fd05f.js +1 -0
  486. package/.next/static/chunks/app/(app)/settings/appearance/page-95902da748ac5f1e.js +1 -0
  487. package/.next/static/chunks/app/(app)/settings/notifications/page-229f1db6beb1d19c.js +1 -0
  488. package/.next/static/chunks/app/(app)/settings/page-8ed16a66fdde10cd.js +1 -0
  489. package/.next/static/chunks/app/(app)/settings/providers/[id]/page-13654263246617b3.js +1 -0
  490. package/.next/static/chunks/app/(app)/settings/providers/new/page-e1798e321ccbc6df.js +1 -0
  491. package/.next/static/chunks/app/(app)/settings/providers/page-0bb4c1db2ee35b3d.js +1 -0
  492. package/.next/static/chunks/app/(app)/settings/session/page-ab216a8fa37a0f76.js +1 -0
  493. package/.next/static/chunks/app/(app)/skills/[name]/page-8ab85d5090967ee4.js +6 -0
  494. package/.next/static/chunks/app/(app)/skills/page-c52773eacb27c04e.js +1 -0
  495. package/.next/static/chunks/app/_global-error/page-fc747760bd4c8a4b.js +1 -0
  496. package/.next/static/chunks/app/api/agents/[name]/route-fc747760bd4c8a4b.js +1 -0
  497. package/.next/static/chunks/app/api/agents/route-fc747760bd4c8a4b.js +1 -0
  498. package/.next/static/chunks/app/api/auth/check/route-fc747760bd4c8a4b.js +1 -0
  499. package/.next/static/chunks/app/api/auth/login/route-fc747760bd4c8a4b.js +1 -0
  500. package/.next/static/chunks/app/api/auth/setup/route-fc747760bd4c8a4b.js +1 -0
  501. package/.next/static/chunks/app/api/auth/ws-token/route-fc747760bd4c8a4b.js +1 -0
  502. package/.next/static/chunks/app/api/btw/route-fc747760bd4c8a4b.js +1 -0
  503. package/.next/static/chunks/app/api/claude-md/route-fc747760bd4c8a4b.js +1 -0
  504. package/.next/static/chunks/app/api/commands/[name]/route-fc747760bd4c8a4b.js +1 -0
  505. package/.next/static/chunks/app/api/commands/route-fc747760bd4c8a4b.js +1 -0
  506. package/.next/static/chunks/app/api/defaults/route-fc747760bd4c8a4b.js +1 -0
  507. package/.next/static/chunks/app/api/filesystem/browse/route-fc747760bd4c8a4b.js +1 -0
  508. package/.next/static/chunks/app/api/filesystem/files/route-fc747760bd4c8a4b.js +1 -0
  509. package/.next/static/chunks/app/api/filesystem/mkdir/route-fc747760bd4c8a4b.js +1 -0
  510. package/.next/static/chunks/app/api/filesystem/read/route-fc747760bd4c8a4b.js +1 -0
  511. package/.next/static/chunks/app/api/git/clone/route-fc747760bd4c8a4b.js +1 -0
  512. package/.next/static/chunks/app/api/git/commit/route-fc747760bd4c8a4b.js +1 -0
  513. package/.next/static/chunks/app/api/git/diff/route-fc747760bd4c8a4b.js +1 -0
  514. package/.next/static/chunks/app/api/git/discard/route-fc747760bd4c8a4b.js +1 -0
  515. package/.next/static/chunks/app/api/git/generate-message/route-fc747760bd4c8a4b.js +1 -0
  516. package/.next/static/chunks/app/api/git/push/route-fc747760bd4c8a4b.js +1 -0
  517. package/.next/static/chunks/app/api/git/status/route-fc747760bd4c8a4b.js +1 -0
  518. package/.next/static/chunks/app/api/github/file-content/route-fc747760bd4c8a4b.js +1 -0
  519. package/.next/static/chunks/app/api/github/orgs/route-fc747760bd4c8a4b.js +1 -0
  520. package/.next/static/chunks/app/api/github/prs/checks/route-fc747760bd4c8a4b.js +1 -0
  521. package/.next/static/chunks/app/api/github/prs/diff/route-fc747760bd4c8a4b.js +1 -0
  522. package/.next/static/chunks/app/api/github/prs/review/route-fc747760bd4c8a4b.js +1 -0
  523. package/.next/static/chunks/app/api/github/prs/route-fc747760bd4c8a4b.js +1 -0
  524. package/.next/static/chunks/app/api/github/prs/view/route-fc747760bd4c8a4b.js +1 -0
  525. package/.next/static/chunks/app/api/github/repos/route-fc747760bd4c8a4b.js +1 -0
  526. package/.next/static/chunks/app/api/github/review-session/route-fc747760bd4c8a4b.js +1 -0
  527. package/.next/static/chunks/app/api/health/route-fc747760bd4c8a4b.js +1 -0
  528. package/.next/static/chunks/app/api/hooks/route-fc747760bd4c8a4b.js +1 -0
  529. package/.next/static/chunks/app/api/inbox/[id]/route-fc747760bd4c8a4b.js +1 -0
  530. package/.next/static/chunks/app/api/inbox/route-fc747760bd4c8a4b.js +1 -0
  531. package/.next/static/chunks/app/api/jobs/[id]/route-fc747760bd4c8a4b.js +1 -0
  532. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-fc747760bd4c8a4b.js +1 -0
  533. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-fc747760bd4c8a4b.js +1 -0
  534. package/.next/static/chunks/app/api/jobs/[id]/runs/route-fc747760bd4c8a4b.js +1 -0
  535. package/.next/static/chunks/app/api/jobs/[id]/trigger/route-fc747760bd4c8a4b.js +1 -0
  536. package/.next/static/chunks/app/api/jobs/mcp-discover/route-fc747760bd4c8a4b.js +1 -0
  537. package/.next/static/chunks/app/api/jobs/route-fc747760bd4c8a4b.js +1 -0
  538. package/.next/static/chunks/app/api/jobs/status/route-fc747760bd4c8a4b.js +1 -0
  539. package/.next/static/chunks/app/api/mcp-servers/[name]/route-fc747760bd4c8a4b.js +1 -0
  540. package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-fc747760bd4c8a4b.js +1 -0
  541. package/.next/static/chunks/app/api/mcp-servers/route-fc747760bd4c8a4b.js +1 -0
  542. package/.next/static/chunks/app/api/notifications/route-fc747760bd4c8a4b.js +1 -0
  543. package/.next/static/chunks/app/api/notifications/test/route-fc747760bd4c8a4b.js +1 -0
  544. package/.next/static/chunks/app/api/providers/[id]/route-fc747760bd4c8a4b.js +1 -0
  545. package/.next/static/chunks/app/api/providers/route-fc747760bd4c8a4b.js +1 -0
  546. package/.next/static/chunks/app/api/reviews/pinned/route-fc747760bd4c8a4b.js +1 -0
  547. package/.next/static/chunks/app/api/sessions/[id]/context/route-fc747760bd4c8a4b.js +1 -0
  548. package/.next/static/chunks/app/api/sessions/[id]/mcp/route-fc747760bd4c8a4b.js +1 -0
  549. package/.next/static/chunks/app/api/sessions/[id]/route-fc747760bd4c8a4b.js +1 -0
  550. package/.next/static/chunks/app/api/sessions/[id]/search/route-fc747760bd4c8a4b.js +1 -0
  551. package/.next/static/chunks/app/api/sessions/[id]/tabs/route-fc747760bd4c8a4b.js +1 -0
  552. package/.next/static/chunks/app/api/sessions/bulk-delete/route-fc747760bd4c8a4b.js +1 -0
  553. package/.next/static/chunks/app/api/sessions/by-ids/route-fc747760bd4c8a4b.js +1 -0
  554. package/.next/static/chunks/app/api/sessions/group/route-fc747760bd4c8a4b.js +1 -0
  555. package/.next/static/chunks/app/api/sessions/pinned/route-fc747760bd4c8a4b.js +1 -0
  556. package/.next/static/chunks/app/api/sessions/route-fc747760bd4c8a4b.js +1 -0
  557. package/.next/static/chunks/app/api/sessions/search/route-fc747760bd4c8a4b.js +1 -0
  558. package/.next/static/chunks/app/api/sessions/thinking/route-fc747760bd4c8a4b.js +1 -0
  559. package/.next/static/chunks/app/api/skills/[name]/route-fc747760bd4c8a4b.js +1 -0
  560. package/.next/static/chunks/app/api/skills/route-fc747760bd4c8a4b.js +1 -0
  561. package/.next/static/chunks/app/api/terminal/[id]/route-fc747760bd4c8a4b.js +1 -0
  562. package/.next/static/chunks/app/api/terminal/route-fc747760bd4c8a4b.js +1 -0
  563. package/.next/static/chunks/app/api/usage/route-fc747760bd4c8a4b.js +1 -0
  564. package/.next/static/chunks/app/api/version/changelog/route-fc747760bd4c8a4b.js +1 -0
  565. package/.next/static/chunks/app/api/version/cockpit/changelog/route-fc747760bd4c8a4b.js +1 -0
  566. package/.next/static/chunks/app/api/version/cockpit/route-fc747760bd4c8a4b.js +1 -0
  567. package/.next/static/chunks/app/api/version/route-fc747760bd4c8a4b.js +1 -0
  568. package/.next/static/chunks/e868780c.f24b6da08e62c7b2.js +18 -0
  569. package/.next/static/chunks/next/dist/client/components/builtin/app-error-fc747760bd4c8a4b.js +1 -0
  570. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-fc747760bd4c8a4b.js +1 -0
  571. package/.next/static/chunks/next/dist/client/components/builtin/not-found-fc747760bd4c8a4b.js +1 -0
  572. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-fc747760bd4c8a4b.js +1 -0
  573. package/.next/static/chunks/webpack-e31bb45fa59caed8.js +1 -0
  574. package/.next/static/css/3f8af4ae6f812d5c.css +1 -0
  575. package/.next/static/zr8XZzqb74eHitdlkpo-C/_buildManifest.js +1 -0
  576. package/README.md +14 -4
  577. package/bin/cockpit-hook-bridge.mjs +101 -0
  578. package/dist/server.js +49 -2
  579. package/dist/src/lib/models.js +48 -7
  580. package/dist/src/server/auth.js +32 -10
  581. package/dist/src/server/claude-settings.js +153 -0
  582. package/dist/src/server/cli-init-fetch.js +86 -0
  583. package/dist/src/server/cron-utils.js +16 -5
  584. package/dist/src/server/debug-logger.js +2 -2
  585. package/dist/src/server/defaults.js +18 -7
  586. package/dist/src/server/fs-watcher.js +50 -0
  587. package/dist/src/server/hook-bridge-path.js +34 -0
  588. package/dist/src/server/hook-event-translator.js +211 -0
  589. package/dist/src/server/hook-router.js +150 -0
  590. package/dist/src/server/inbox.js +136 -0
  591. package/dist/src/server/job-lock.js +103 -0
  592. package/dist/src/server/job-scheduler.js +170 -43
  593. package/dist/src/server/job-storage.js +32 -20
  594. package/dist/src/server/notification-settings.js +43 -0
  595. package/dist/src/server/notifications.js +125 -0
  596. package/dist/src/server/paths.js +23 -0
  597. package/dist/src/server/plans.js +8 -5
  598. package/dist/src/server/providers.js +128 -0
  599. package/dist/src/server/pty-runtime.js +324 -0
  600. package/dist/src/server/pty-session.js +178 -0
  601. package/dist/src/server/session-manager.js +838 -152
  602. package/dist/src/server/session-prefs.js +33 -8
  603. package/dist/src/server/singleton.js +18 -0
  604. package/dist/src/server/stream-processor.js +61 -48
  605. package/dist/src/server/terminal-manager.js +153 -0
  606. package/dist/src/server/todo-watcher.js +178 -0
  607. package/dist/src/server/transcript-watcher.js +91 -0
  608. package/dist/src/server/transcript.js +444 -13
  609. package/dist/src/server/ws-handler.js +251 -74
  610. package/next.config.ts +1 -0
  611. package/package.json +10 -3
  612. package/public/fonts/symbols-nerd-font-mono.woff2 +0 -0
  613. package/.next/server/chunks/1941.js +0 -9
  614. package/.next/server/chunks/2444.js +0 -6
  615. package/.next/server/chunks/8346.js +0 -1
  616. package/.next/static/V2EfPtTUC96VYyF12K0om/_buildManifest.js +0 -1
  617. package/.next/static/chunks/30120-1535e9064b17ce74.js +0 -20
  618. package/.next/static/chunks/66997-652baf5596173fea.js +0 -199
  619. package/.next/static/chunks/93273-c5cb6dcedef67c81.js +0 -6
  620. package/.next/static/chunks/app/(app)/agents/[name]/page-44c5691c80f17d38.js +0 -8
  621. package/.next/static/chunks/app/(app)/agents/page-4ce7a715bc0145dc.js +0 -1
  622. package/.next/static/chunks/app/(app)/changes/page-84cf4cd3ca347d98.js +0 -1
  623. package/.next/static/chunks/app/(app)/claude-md/edit/page-fb7117171d0f94d2.js +0 -1
  624. package/.next/static/chunks/app/(app)/claude-md/page-9503f1415e660911.js +0 -1
  625. package/.next/static/chunks/app/(app)/commands/[name]/page-6ef571e73b105248.js +0 -6
  626. package/.next/static/chunks/app/(app)/commands/page-e8a506da73d1c280.js +0 -1
  627. package/.next/static/chunks/app/(app)/files/page-67a95d351a685d79.js +0 -1
  628. package/.next/static/chunks/app/(app)/hooks/[event]/page-03f85595561b068a.js +0 -6
  629. package/.next/static/chunks/app/(app)/hooks/page-5578c83ad353e307.js +0 -1
  630. package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-51d784c59737778c.js +0 -1
  631. package/.next/static/chunks/app/(app)/jobs/[id]/page-7d00e7a01c70a261.js +0 -1
  632. package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-665191da233fde19.js +0 -1
  633. package/.next/static/chunks/app/(app)/jobs/page-8b4ee1166a53d5e1.js +0 -1
  634. package/.next/static/chunks/app/(app)/layout-8dad55d6ce637a01.js +0 -1
  635. package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-c30f0d78daf7719e.js +0 -1
  636. package/.next/static/chunks/app/(app)/mcp-servers/page-737b87d338afdb49.js +0 -1
  637. package/.next/static/chunks/app/(app)/page-40052655d2a9a84f.js +0 -1
  638. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-1d9179bf5a4de7a4.js +0 -13
  639. package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/page-d8a9ee39e7cc056a.js +0 -1
  640. package/.next/static/chunks/app/(app)/reviews/page-098e6e6fe3123e02.js +0 -1
  641. package/.next/static/chunks/app/(app)/sessions/[id]/page-a74f7fe8322678ba.js +0 -1
  642. package/.next/static/chunks/app/(app)/settings/page-1fa46b8ac8e22927.js +0 -1
  643. package/.next/static/chunks/app/(app)/skills/[name]/page-e6572062a6ad90df.js +0 -6
  644. package/.next/static/chunks/app/(app)/skills/page-8fca8814aa818ae6.js +0 -1
  645. package/.next/static/chunks/app/_global-error/page-b277aba73f9e0212.js +0 -1
  646. package/.next/static/chunks/app/api/agents/[name]/route-b277aba73f9e0212.js +0 -1
  647. package/.next/static/chunks/app/api/agents/route-b277aba73f9e0212.js +0 -1
  648. package/.next/static/chunks/app/api/auth/check/route-b277aba73f9e0212.js +0 -1
  649. package/.next/static/chunks/app/api/auth/login/route-b277aba73f9e0212.js +0 -1
  650. package/.next/static/chunks/app/api/auth/setup/route-b277aba73f9e0212.js +0 -1
  651. package/.next/static/chunks/app/api/auth/ws-token/route-b277aba73f9e0212.js +0 -1
  652. package/.next/static/chunks/app/api/btw/route-b277aba73f9e0212.js +0 -1
  653. package/.next/static/chunks/app/api/claude-md/route-b277aba73f9e0212.js +0 -1
  654. package/.next/static/chunks/app/api/commands/[name]/route-b277aba73f9e0212.js +0 -1
  655. package/.next/static/chunks/app/api/commands/route-b277aba73f9e0212.js +0 -1
  656. package/.next/static/chunks/app/api/defaults/route-b277aba73f9e0212.js +0 -1
  657. package/.next/static/chunks/app/api/filesystem/browse/route-b277aba73f9e0212.js +0 -1
  658. package/.next/static/chunks/app/api/filesystem/files/route-b277aba73f9e0212.js +0 -1
  659. package/.next/static/chunks/app/api/filesystem/mkdir/route-b277aba73f9e0212.js +0 -1
  660. package/.next/static/chunks/app/api/filesystem/read/route-b277aba73f9e0212.js +0 -1
  661. package/.next/static/chunks/app/api/git/clone/route-b277aba73f9e0212.js +0 -1
  662. package/.next/static/chunks/app/api/git/commit/route-b277aba73f9e0212.js +0 -1
  663. package/.next/static/chunks/app/api/git/diff/route-b277aba73f9e0212.js +0 -1
  664. package/.next/static/chunks/app/api/git/discard/route-b277aba73f9e0212.js +0 -1
  665. package/.next/static/chunks/app/api/git/generate-message/route-b277aba73f9e0212.js +0 -1
  666. package/.next/static/chunks/app/api/git/push/route-b277aba73f9e0212.js +0 -1
  667. package/.next/static/chunks/app/api/git/status/route-b277aba73f9e0212.js +0 -1
  668. package/.next/static/chunks/app/api/github/file-content/route-b277aba73f9e0212.js +0 -1
  669. package/.next/static/chunks/app/api/github/orgs/route-b277aba73f9e0212.js +0 -1
  670. package/.next/static/chunks/app/api/github/prs/checks/route-b277aba73f9e0212.js +0 -1
  671. package/.next/static/chunks/app/api/github/prs/diff/route-b277aba73f9e0212.js +0 -1
  672. package/.next/static/chunks/app/api/github/prs/review/route-b277aba73f9e0212.js +0 -1
  673. package/.next/static/chunks/app/api/github/prs/route-b277aba73f9e0212.js +0 -1
  674. package/.next/static/chunks/app/api/github/prs/view/route-b277aba73f9e0212.js +0 -1
  675. package/.next/static/chunks/app/api/github/repos/route-b277aba73f9e0212.js +0 -1
  676. package/.next/static/chunks/app/api/github/review-session/route-b277aba73f9e0212.js +0 -1
  677. package/.next/static/chunks/app/api/health/route-b277aba73f9e0212.js +0 -1
  678. package/.next/static/chunks/app/api/hooks/route-b277aba73f9e0212.js +0 -1
  679. package/.next/static/chunks/app/api/jobs/[id]/route-b277aba73f9e0212.js +0 -1
  680. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-b277aba73f9e0212.js +0 -1
  681. package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-b277aba73f9e0212.js +0 -1
  682. package/.next/static/chunks/app/api/jobs/[id]/runs/route-b277aba73f9e0212.js +0 -1
  683. package/.next/static/chunks/app/api/jobs/[id]/trigger/route-b277aba73f9e0212.js +0 -1
  684. package/.next/static/chunks/app/api/jobs/mcp-discover/route-b277aba73f9e0212.js +0 -1
  685. package/.next/static/chunks/app/api/jobs/route-b277aba73f9e0212.js +0 -1
  686. package/.next/static/chunks/app/api/jobs/status/route-b277aba73f9e0212.js +0 -1
  687. package/.next/static/chunks/app/api/mcp-servers/[name]/route-b277aba73f9e0212.js +0 -1
  688. package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-b277aba73f9e0212.js +0 -1
  689. package/.next/static/chunks/app/api/mcp-servers/route-b277aba73f9e0212.js +0 -1
  690. package/.next/static/chunks/app/api/sessions/[id]/context/route-b277aba73f9e0212.js +0 -1
  691. package/.next/static/chunks/app/api/sessions/[id]/mcp/route-b277aba73f9e0212.js +0 -1
  692. package/.next/static/chunks/app/api/sessions/[id]/route-b277aba73f9e0212.js +0 -1
  693. package/.next/static/chunks/app/api/sessions/[id]/search/route-b277aba73f9e0212.js +0 -1
  694. package/.next/static/chunks/app/api/sessions/pinned/route-b277aba73f9e0212.js +0 -1
  695. package/.next/static/chunks/app/api/sessions/route-b277aba73f9e0212.js +0 -1
  696. package/.next/static/chunks/app/api/skills/[name]/route-b277aba73f9e0212.js +0 -1
  697. package/.next/static/chunks/app/api/skills/route-b277aba73f9e0212.js +0 -1
  698. package/.next/static/chunks/app/api/usage/route-b277aba73f9e0212.js +0 -1
  699. package/.next/static/chunks/app/api/version/cockpit/route-b277aba73f9e0212.js +0 -1
  700. package/.next/static/chunks/app/api/version/route-b277aba73f9e0212.js +0 -1
  701. package/.next/static/chunks/next/dist/client/components/builtin/app-error-b277aba73f9e0212.js +0 -1
  702. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-b277aba73f9e0212.js +0 -1
  703. package/.next/static/chunks/next/dist/client/components/builtin/not-found-b277aba73f9e0212.js +0 -1
  704. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-b277aba73f9e0212.js +0 -1
  705. package/.next/static/chunks/webpack-2a5835e108df6f34.js +0 -1
  706. package/.next/static/css/1e1239c76b265910.css +0 -1
  707. /package/.next/static/{V2EfPtTUC96VYyF12K0om → zr8XZzqb74eHitdlkpo-C}/_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,10 @@ 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,
81
+ pendingRequestCount: 0,
57
82
  };
58
83
  this.sessions.set(id, {
59
84
  info,
@@ -70,27 +95,42 @@ class SessionManager {
70
95
  thinkingLevel: defaults.thinkingLevel,
71
96
  streamState: null,
72
97
  contextUsage: null,
73
- contextWindowSize: 200_000,
98
+ contextWindowSize: (0, models_1.contextSizeToWindow)(info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE),
74
99
  todoItems: [],
75
100
  pendingRequests: new Map(),
76
101
  controlCallbacks: new Map(),
77
102
  streamingSnapshot: null,
78
103
  queuedMessages: [],
79
104
  queuePaused: false,
105
+ modelSlots,
80
106
  transcriptBuffer: [],
81
107
  transcriptByteOffset: 0,
82
108
  transcriptTotalSize: 0,
83
109
  bufferCliSessionId: id,
84
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 },
85
117
  });
118
+ (0, session_prefs_1.setSessionPrefs)(id, { runtime: rt });
86
119
  return info;
87
120
  }
88
121
  ensureSession(id, cwd) {
89
122
  let session = this.sessions.get(id);
90
123
  if (!session) {
91
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}`);
92
129
  const defaults = (0, defaults_1.getDefaults)();
93
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;
94
134
  session = {
95
135
  info: {
96
136
  id,
@@ -99,23 +139,28 @@ class SessionManager {
99
139
  createdAt: now,
100
140
  lastActiveAt: now,
101
141
  status: "idle",
102
- model: prefs?.model || defaults.model || undefined,
142
+ model: modelSlots.main,
143
+ contextSize: restoredContextSize,
144
+ runtime: restoredRuntime,
145
+ pendingRequestCount: 0,
103
146
  },
104
147
  process: null,
105
148
  stdin: null,
106
149
  emitter: new node_events_1.EventEmitter(),
107
150
  hasSpawnedBefore: true,
108
- cliSessionId: prefs?.cliSessionId || id,
109
- previousCliSessionIds: prefs?.previousCliSessionIds || [],
151
+ cliSessionId: cliId,
152
+ previousCliSessionIds: prevIds,
110
153
  bypassAllPermissions: prefs?.bypassAllPermissions ?? defaults.bypassAllPermissions,
111
154
  planMode: prefs?.planMode ?? false,
112
155
  pendingPlanReminder: prefs?.planMode ?? false,
113
156
  needsRespawnForPermissions: false,
114
157
  compacting: false,
115
- 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,
116
161
  streamState: null,
117
162
  contextUsage: null,
118
- contextWindowSize: 200_000,
163
+ contextWindowSize: (0, models_1.contextSizeToWindow)(restoredContextSize),
119
164
  todoItems: [],
120
165
  pendingRequests: new Map(),
121
166
  controlCallbacks: new Map(),
@@ -123,11 +168,18 @@ class SessionManager {
123
168
  streamingSnapshot: null,
124
169
  queuedMessages: [],
125
170
  queuePaused: false,
171
+ modelSlots,
126
172
  transcriptBuffer: [],
127
173
  transcriptByteOffset: 0,
128
174
  transcriptTotalSize: 0,
129
- bufferCliSessionId: prefs?.cliSessionId || id,
175
+ bufferCliSessionId: cliId,
130
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 },
131
183
  };
132
184
  this.sessions.set(id, session);
133
185
  }
@@ -146,30 +198,31 @@ class SessionManager {
146
198
  this.ensureSession(id, cwd);
147
199
  session = this.sessions.get(id);
148
200
  }
149
- const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, session.info.cwd, { tailLines: 150 });
201
+ const stitching = (0, defaults_1.getDefaults)().messageStitching;
202
+ const willStitch = stitching && session.previousCliSessionIds.length > 0;
203
+ // Load full current session when stitching to avoid losing middle messages.
204
+ // Without stitching, tail-read is fine because byteOffset stays pointing at
205
+ // the current session's file for backward pagination.
206
+ const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, session.info.cwd, willStitch ? undefined : { tailLines: 150 });
150
207
  let { messages, byteOffset, totalSize, lastUsage } = result;
151
208
  session.bufferCliSessionId = session.cliSessionId;
152
- // Stitch previous session messages across /clear boundaries so the full
153
- // conversation is visible on refresh instead of only post-clear messages.
154
- if (session.previousCliSessionIds.length > 0) {
155
- const currentMessages = messages;
209
+ if (willStitch) {
156
210
  for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
157
211
  const prevId = session.previousCliSessionIds[i];
158
212
  const prevResult = await (0, transcript_1.loadTranscript)(prevId, session.info.cwd, { tailLines: 150 });
159
213
  if (prevResult.messages.length > 0) {
160
214
  const marker = {
161
- id: "clear-boundary-" + Date.now(),
215
+ id: `clear-boundary-${i}`,
162
216
  role: "system",
163
217
  content: "__context_reset__",
164
218
  toolUses: [],
165
219
  blocks: [],
166
220
  timestamp: Date.now(),
167
221
  };
168
- messages = [...prevResult.messages, marker, ...currentMessages];
222
+ messages = [...prevResult.messages, marker, ...messages];
169
223
  byteOffset = prevResult.byteOffset;
170
224
  lastUsage = lastUsage || prevResult.lastUsage;
171
225
  session.bufferCliSessionId = prevId;
172
- break;
173
226
  }
174
227
  }
175
228
  }
@@ -178,11 +231,11 @@ class SessionManager {
178
231
  session.transcriptByteOffset = byteOffset;
179
232
  session.transcriptTotalSize = totalSize;
180
233
  // Fresh pagination copy so getMoreHistory doesn't consume the canonical list
181
- session.paginationPrevIds = [...session.previousCliSessionIds];
234
+ session.paginationPrevIds = stitching ? [...session.previousCliSessionIds] : [];
182
235
  // Send last 50 to client, keep rest in buffer
183
236
  const PAGE = 50;
184
237
  const clientMessages = messages.length > PAGE ? messages.slice(-PAGE) : messages;
185
- const hasMore = messages.length > PAGE || byteOffset > 0 || session.previousCliSessionIds.length > 0;
238
+ const hasMore = messages.length > PAGE || byteOffset > 0 || (stitching && session.previousCliSessionIds.length > 0);
186
239
  const defaultName = node_path_1.default.basename(session.info.cwd) || session.info.cwd;
187
240
  if (session.info.name === defaultName && messages.length > 0) {
188
241
  const firstUser = messages.find((m) => m.role === "user" && m.content && !m.content.startsWith("[") && !m.content.startsWith("<"));
@@ -190,35 +243,46 @@ class SessionManager {
190
243
  session.info.name = firstUser.content.slice(0, 120);
191
244
  }
192
245
  }
193
- 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 };
194
260
  }
195
261
  async getSessionByCwd(id, cwd) {
196
262
  this.ensureSession(id, cwd);
197
263
  const session = this.sessions.get(id);
198
- const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd, { tailLines: 150 });
264
+ const stitching = (0, defaults_1.getDefaults)().messageStitching;
265
+ const willStitch = stitching && session.previousCliSessionIds.length > 0;
266
+ const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd, willStitch ? undefined : { tailLines: 150 });
199
267
  let { messages, byteOffset, totalSize, lastUsage } = result;
200
268
  session.bufferCliSessionId = session.cliSessionId;
201
- // Stitch previous session messages across /clear boundaries so the full
202
- // conversation is visible on refresh instead of only post-clear messages.
203
- if (session.previousCliSessionIds.length > 0) {
204
- const currentMessages = messages;
269
+ if (willStitch) {
205
270
  for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
206
271
  const prevId = session.previousCliSessionIds[i];
207
272
  const prevResult = await (0, transcript_1.loadTranscript)(prevId, cwd, { tailLines: 150 });
208
273
  if (prevResult.messages.length > 0) {
209
274
  const marker = {
210
- id: "clear-boundary-" + Date.now(),
275
+ id: `clear-boundary-${i}`,
211
276
  role: "system",
212
277
  content: "__context_reset__",
213
278
  toolUses: [],
214
279
  blocks: [],
215
280
  timestamp: Date.now(),
216
281
  };
217
- messages = [...prevResult.messages, marker, ...currentMessages];
282
+ messages = [...prevResult.messages, marker, ...messages];
218
283
  byteOffset = prevResult.byteOffset;
219
284
  lastUsage = lastUsage || prevResult.lastUsage;
220
285
  session.bufferCliSessionId = prevId;
221
- break;
222
286
  }
223
287
  }
224
288
  }
@@ -227,11 +291,11 @@ class SessionManager {
227
291
  session.transcriptByteOffset = byteOffset;
228
292
  session.transcriptTotalSize = totalSize;
229
293
  // Fresh pagination copy so getMoreHistory doesn't consume the canonical list
230
- session.paginationPrevIds = [...session.previousCliSessionIds];
294
+ session.paginationPrevIds = stitching ? [...session.previousCliSessionIds] : [];
231
295
  // Send last 50 to client, keep rest in buffer
232
296
  const PAGE = 50;
233
297
  const clientMessages = messages.length > PAGE ? messages.slice(-PAGE) : messages;
234
- const hasMore = messages.length > PAGE || byteOffset > 0 || session.previousCliSessionIds.length > 0;
298
+ const hasMore = messages.length > PAGE || byteOffset > 0 || (stitching && session.previousCliSessionIds.length > 0);
235
299
  // Derive title from first user message if name is still the default
236
300
  const defaultName = node_path_1.default.basename(cwd) || cwd;
237
301
  if (session.info.name === defaultName && messages.length > 0) {
@@ -240,31 +304,43 @@ class SessionManager {
240
304
  session.info.name = firstUser.content.slice(0, 120);
241
305
  }
242
306
  }
243
- 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 };
244
321
  }
245
322
  async getCliSessionView(cliId, cwd) {
246
323
  if (!(0, transcript_1.transcriptExists)(cliId, cwd))
247
324
  return null;
248
325
  const chain = (0, session_prefs_1.findChainForCliSession)(cliId);
249
326
  const prevIds = chain ? chain.truncatedPrevIds : [];
250
- const result = await (0, transcript_1.loadTranscript)(cliId, cwd, { tailLines: 150 });
327
+ const willStitch = (0, defaults_1.getDefaults)().messageStitching && prevIds.length > 0;
328
+ const result = await (0, transcript_1.loadTranscript)(cliId, cwd, willStitch ? undefined : { tailLines: 150 });
251
329
  let { messages, lastUsage } = result;
252
- if (prevIds.length > 0) {
253
- const currentMessages = messages;
330
+ if (willStitch) {
254
331
  for (let i = prevIds.length - 1; i >= 0; i--) {
255
332
  const prevResult = await (0, transcript_1.loadTranscript)(prevIds[i], cwd, { tailLines: 150 });
256
333
  if (prevResult.messages.length > 0) {
257
334
  const marker = {
258
- id: "clear-boundary-" + Date.now(),
335
+ id: `clear-boundary-${i}`,
259
336
  role: "system",
260
337
  content: "__context_reset__",
261
338
  toolUses: [],
262
339
  blocks: [],
263
340
  timestamp: Date.now(),
264
341
  };
265
- messages = [...prevResult.messages, marker, ...currentMessages];
342
+ messages = [...prevResult.messages, marker, ...messages];
266
343
  lastUsage = lastUsage || prevResult.lastUsage;
267
- break;
268
344
  }
269
345
  }
270
346
  }
@@ -277,11 +353,27 @@ class SessionManager {
277
353
  name = firstUser.content.slice(0, 120);
278
354
  }
279
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;
280
371
  return {
281
372
  info: { id: cliId, name, cwd, createdAt: Date.now(), lastActiveAt: Date.now(), status: "idle" },
282
373
  messages: clientMessages,
283
374
  hasMore: messages.length > PAGE,
284
- lastUsage,
375
+ lastUsage: normalized,
376
+ promptHistory: allPrompts,
285
377
  };
286
378
  }
287
379
  async getMoreHistory(sessionId, beforeMessageId) {
@@ -356,9 +448,21 @@ class SessionManager {
356
448
  isCompacting(id) {
357
449
  return this.sessions.get(id)?.compacting ?? false;
358
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
+ }
359
463
  listActiveSessions() {
360
464
  return Array.from(this.sessions.values())
361
- .filter((s) => s.process !== null)
465
+ .filter((s) => s.process !== null || !!s.ptyRuntime?.isAlive)
362
466
  .map((s) => s.info);
363
467
  }
364
468
  listKnownSessions() {
@@ -380,13 +484,18 @@ class SessionManager {
380
484
  }
381
485
  isProcessAlive(id) {
382
486
  const session = this.sessions.get(id);
383
- return !!session?.process;
487
+ return !!session?.process || !!session?.ptyRuntime?.isAlive;
488
+ }
489
+ hasRunningProcess(id) {
490
+ const session = this.sessions.get(id);
491
+ return !!session?.process || !!session?.ptyRuntime?.isAlive;
384
492
  }
385
493
  fixStaleStatus(id) {
386
494
  const session = this.sessions.get(id);
387
- if (session && session.info.status === "running" && !session.process) {
495
+ if (session && session.info.status === "running" && !session.process && !session.ptyRuntime?.isAlive) {
388
496
  session.info.status = "idle";
389
497
  session.pendingRequests.clear();
498
+ this.notifyPendingChanged(session, id);
390
499
  }
391
500
  }
392
501
  restartSession(sessionId) {
@@ -398,7 +507,11 @@ class SessionManager {
398
507
  return false;
399
508
  }
400
509
  this.killProcess(session);
510
+ if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
511
+ session.hasSpawnedBefore = false;
512
+ }
401
513
  session.pendingRequests.clear();
514
+ this.notifyPendingChanged(session, sessionId);
402
515
  session.streamingSnapshot = null;
403
516
  session.info.status = "idle";
404
517
  session.emitter.emit("status", sessionId, "idle");
@@ -413,6 +526,20 @@ class SessionManager {
413
526
  if (session.process) {
414
527
  this.endProcess(session, "session_destroyed");
415
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);
416
543
  session.emitter.removeAllListeners();
417
544
  this.sessions.delete(id);
418
545
  return true;
@@ -429,14 +556,26 @@ class SessionManager {
429
556
  }
430
557
  onStatus(id, listener) {
431
558
  const session = this.sessions.get(id);
432
- if (!session)
559
+ if (!session) {
560
+ smLog(id, "onStatus: session not in memory, returning null");
433
561
  return null;
562
+ }
434
563
  const handler = (_sessionId, status) => {
435
564
  listener(status);
436
565
  };
437
566
  session.emitter.on("status", handler);
438
567
  return () => session.emitter.off("status", handler);
439
568
  }
569
+ onPending(id, listener) {
570
+ const session = this.sessions.get(id);
571
+ if (!session)
572
+ return null;
573
+ const handler = (_sessionId, count) => {
574
+ listener(count);
575
+ };
576
+ session.emitter.on("pending", handler);
577
+ return () => session.emitter.off("pending", handler);
578
+ }
440
579
  onError(id, listener) {
441
580
  const session = this.sessions.get(id);
442
581
  if (!session)
@@ -447,19 +586,55 @@ class SessionManager {
447
586
  session.emitter.on("error", handler);
448
587
  return () => session.emitter.off("error", handler);
449
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
+ }
450
597
  interrupt(id) {
451
598
  const session = this.sessions.get(id);
452
- if (!session?.process) {
453
- (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 });
454
601
  return false;
455
602
  }
456
603
  // Pause the queue atomically with the interrupt so
457
604
  // flushQueuedMessage (called on message_done) becomes a no-op.
458
- // This prevents a race where message_done fires before a
459
- // separate pause_queue WS message can arrive.
460
605
  if (session.queuedMessages.length > 0) {
461
606
  session.queuePaused = true;
462
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
+ }
463
638
  // Send a control_request interrupt via stdin instead of SIGINT.
464
639
  // SIGINT kills the process, forcing a full respawn + transcript reload
465
640
  // on the next message. The control_request interrupt aborts the current
@@ -473,23 +648,34 @@ class SessionManager {
473
648
  };
474
649
  (0, debug_logger_1.logDiag)(id, "interrupt:stdin", { requestId: request.request_id });
475
650
  session.stdin.write(JSON.stringify(request) + "\n");
651
+ session.pendingRequests.clear();
652
+ this.notifyPendingChanged(session, id);
476
653
  return true;
477
654
  }
478
655
  // Fallback: if stdin is gone, kill the process group
479
656
  (0, debug_logger_1.logDiag)(id, "interrupt:kill-fallback");
480
657
  this.killProcessGroup(session.process);
658
+ session.pendingRequests.clear();
659
+ this.notifyPendingChanged(session, id);
481
660
  return true;
482
661
  }
483
662
  addPendingRequest(sessionId, request) {
484
663
  const session = this.sessions.get(sessionId);
485
664
  if (session) {
486
665
  session.pendingRequests.set(request.requestId, request);
666
+ this.notifyPendingChanged(session, sessionId);
487
667
  }
488
668
  }
489
669
  removePendingRequest(sessionId, requestId) {
490
670
  const session = this.sessions.get(sessionId);
491
671
  if (session) {
672
+ const had = session.pendingRequests.has(requestId);
673
+ const wasQuestion = session.pendingRequests.get(requestId)?.type === "question";
492
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
+ }
678
+ this.notifyPendingChanged(session, sessionId);
493
679
  }
494
680
  }
495
681
  getPendingRequests(sessionId) {
@@ -498,11 +684,26 @@ class SessionManager {
498
684
  return [];
499
685
  return Array.from(session.pendingRequests.values());
500
686
  }
687
+ getPendingRequest(sessionId, requestId) {
688
+ return this.sessions.get(sessionId)?.pendingRequests.get(requestId);
689
+ }
501
690
  respondToPermission(sessionId, requestId, allowed, toolInput, permissionSuggestions, denyReason) {
502
691
  const session = this.sessions.get(sessionId);
503
- 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)
504
704
  return false;
505
705
  session.pendingRequests.delete(requestId);
706
+ this.notifyPendingChanged(session, sessionId);
506
707
  const response = {
507
708
  type: "control_response",
508
709
  response: {
@@ -511,7 +712,7 @@ class SessionManager {
511
712
  response: allowed
512
713
  ? {
513
714
  behavior: "allow",
514
- ...(toolInput ? { updatedInput: toolInput } : {}),
715
+ updatedInput: toolInput ?? {},
515
716
  ...(permissionSuggestions?.length ? { updatedPermissions: permissionSuggestions } : {}),
516
717
  }
517
718
  : { behavior: "deny", message: denyReason ?? "User denied" },
@@ -540,6 +741,7 @@ class SessionManager {
540
741
  // Don't change CLI mode while in plan mode; bypass will restore on plan exit
541
742
  if (!session.planMode) {
542
743
  this.sendPermissionMode(session, sessionId, "bypassPermissions");
744
+ this.scheduleRespawnForPermissions(session);
543
745
  }
544
746
  this.emitSystem(session, sessionId, "__bypass_state::on");
545
747
  }
@@ -551,9 +753,36 @@ class SessionManager {
551
753
  (0, session_prefs_1.setSessionPrefs)(sessionId, { bypassAllPermissions: false });
552
754
  if (!session.planMode) {
553
755
  this.sendPermissionMode(session, sessionId, "default");
756
+ this.scheduleRespawnForPermissions(session);
554
757
  }
555
758
  this.emitSystem(session, sessionId, "__bypass_state::off");
556
759
  }
760
+ // Runtime set_permission_mode is unreliable when the CLI was spawned without
761
+ // the target mode. Respawning the process picks up --permission-mode from
762
+ // session state, guaranteeing the next message runs in the right mode.
763
+ // If a message is in flight, defer until message_done so we don't orphan it.
764
+ scheduleRespawnForPermissions(session) {
765
+ if (!session.process && !session.ptyRuntime?.isAlive)
766
+ return;
767
+ if (session.info.status === "idle") {
768
+ this.killProcess(session);
769
+ session.hasSpawnedBefore = (0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd);
770
+ }
771
+ else {
772
+ session.needsRespawnForPermissions = true;
773
+ }
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
+ }
557
786
  isBypassActive(sessionId) {
558
787
  const session = this.sessions.get(sessionId);
559
788
  return session?.bypassAllPermissions ?? false;
@@ -567,13 +796,14 @@ class SessionManager {
567
796
  (0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: true });
568
797
  // Kill process so it restarts without --allow-dangerously-skip-permissions,
569
798
  // which lets the CLI natively enforce plan mode tool restrictions.
570
- if (session.process) {
799
+ if (session.process || session.ptyRuntime?.isAlive) {
571
800
  this.killProcess(session);
572
801
  session.info.status = "idle";
573
802
  session.emitter.emit("status", sessionId, "idle");
574
803
  }
575
804
  // Clear orphaned pending requests from the killed process
576
805
  session.pendingRequests.clear();
806
+ this.notifyPendingChanged(session, sessionId);
577
807
  this.emitSystem(session, sessionId, "__plan_state::on");
578
808
  }
579
809
  clearPlanMode(sessionId) {
@@ -584,13 +814,14 @@ class SessionManager {
584
814
  (0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: false });
585
815
  // Kill process so it restarts with --allow-dangerously-skip-permissions,
586
816
  // restoring bypass capability for build mode.
587
- if (session.process) {
817
+ if (session.process || session.ptyRuntime?.isAlive) {
588
818
  this.killProcess(session);
589
819
  session.info.status = "idle";
590
820
  session.emitter.emit("status", sessionId, "idle");
591
821
  }
592
822
  // Clear orphaned pending requests from the killed process
593
823
  session.pendingRequests.clear();
824
+ this.notifyPendingChanged(session, sessionId);
594
825
  this.emitSystem(session, sessionId, "__plan_state::off");
595
826
  // Re-sync bypass state with the client so the UI reflects it correctly
596
827
  // after the plan-mode process is torn down.
@@ -602,19 +833,41 @@ class SessionManager {
602
833
  const session = this.sessions.get(sessionId);
603
834
  return session?.planMode ?? false;
604
835
  }
605
- setModel(sessionId, model) {
836
+ setModel(sessionId, model, contextSize) {
606
837
  const session = this.sessions.get(sessionId);
607
- 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)
840
+ return;
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})`);
608
854
  return;
609
- // Detect 200K↔1M flip. The CLAUDE_CODE_DISABLE_1M_CONTEXT env var is
610
- // applied at spawn, so toggling the [1m] suffix mid-session needs a CLI
611
- // restart for the new context window to actually take effect.
612
- const has1m = (m) => !!m && /\[1m\]/i.test(m);
613
- const contextChanged = has1m(session.info.model) !== has1m(model);
855
+ }
614
856
  session.info.model = model;
615
- (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 });
616
860
  const nextEntry = (0, models_1.resolveModel)(model);
617
- 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
+ })();
618
871
  const levelChanged = coerced !== null && coerced !== session.thinkingLevel;
619
872
  if (levelChanged) {
620
873
  session.thinkingLevel = coerced;
@@ -622,13 +875,14 @@ class SessionManager {
622
875
  this.emitSystem(session, sessionId, `__thinking_level::${coerced}`);
623
876
  }
624
877
  if (session.stdin && !contextChanged) {
878
+ this.log(sessionId, `setModel: sending control_request set_model=${model}`);
625
879
  const request = {
626
880
  type: "control_request",
627
881
  request_id: `model-${Date.now()}`,
628
882
  request: { subtype: "set_model", model },
629
883
  };
630
884
  session.stdin.write(JSON.stringify(request) + "\n");
631
- if ((0, models_1.allowedEffortLevels)(nextEntry).length > 0) {
885
+ if (this.modelEffortLevels(model).length > 0) {
632
886
  const effortRequest = {
633
887
  type: "control_request",
634
888
  request_id: `effort-${Date.now()}`,
@@ -638,13 +892,44 @@ class SessionManager {
638
892
  }
639
893
  }
640
894
  else {
895
+ this.log(sessionId, `setModel: killing process (hasStdin=${!!session.stdin}, contextChanged=${contextChanged})`);
641
896
  this.killProcess(session);
897
+ if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
898
+ session.hasSpawnedBefore = false;
899
+ }
642
900
  session.queuedMessages.length = 0;
643
901
  session.queuePaused = false;
644
902
  session.info.status = "idle";
645
903
  session.emitter.emit("status", sessionId, "idle");
646
904
  }
647
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
+ }
648
933
  }
649
934
  getModel(sessionId) {
650
935
  return this.sessions.get(sessionId)?.info.model || "sonnet";
@@ -655,7 +940,7 @@ class SessionManager {
655
940
  return;
656
941
  session.thinkingLevel = level;
657
942
  (0, session_prefs_1.setSessionPrefs)(sessionId, { thinkingLevel: level });
658
- 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;
659
944
  if (session.stdin && supportsEffort) {
660
945
  const request = {
661
946
  type: "control_request",
@@ -857,45 +1142,33 @@ class SessionManager {
857
1142
  session.emitter.on("init", handler);
858
1143
  return () => session.emitter.off("init", handler);
859
1144
  }
860
- handleTodoWrite(session, sessionId, toolInput) {
861
- try {
862
- const input = JSON.parse(toolInput);
863
- const todos = input.todos;
864
- if (!Array.isArray(todos))
865
- return;
866
- session.todoItems = todos
867
- .filter((t) => t.content && t.status)
868
- .map((t) => ({
869
- content: t.content,
870
- status: t.status,
871
- activeForm: t.activeForm || undefined,
872
- }));
873
- session.emitter.emit("todos", sessionId, [...session.todoItems]);
874
- }
875
- catch {
876
- // invalid input, ignore
877
- }
878
- }
879
- rebuildTodosFromHistory(sessionId, messages) {
1145
+ loadTodosFromFiles(sessionId) {
880
1146
  const session = this.sessions.get(sessionId);
881
1147
  if (!session)
882
1148
  return;
883
- // If there's already a live todo state (set during the current process),
884
- // don't overwrite it from history.
885
1149
  if (session.todoItems.length > 0)
886
1150
  return;
887
- const todos = extractTodosFromHistory(messages);
1151
+ const watcher = new todo_watcher_1.TodoWatcher(session.cliSessionId, () => { });
1152
+ const todos = watcher.readOnce();
888
1153
  if (todos.length === 0)
889
1154
  return;
890
1155
  session.todoItems = todos;
891
1156
  session.emitter.emit("todos", sessionId, [...session.todoItems]);
892
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
+ }
893
1169
  extractUsage(session, sessionId, line) {
894
1170
  try {
895
1171
  const raw = JSON.parse(line.trim());
896
- if (raw.type === "result" && raw.modelUsage) {
897
- this.extractContextWindowSize(session, raw.modelUsage);
898
- }
899
1172
  if (raw.type !== "assistant" || !raw.message?.usage)
900
1173
  return;
901
1174
  // Skip synthetic responses (e.g. /context) that have all-zero usage
@@ -906,19 +1179,15 @@ class SessionManager {
906
1179
  const usage = { used, total: session.contextWindowSize };
907
1180
  session.contextUsage = usage;
908
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;
909
1186
  }
910
1187
  catch {
911
1188
  // not valid JSON, ignore
912
1189
  }
913
1190
  }
914
- extractContextWindowSize(session, modelUsage) {
915
- for (const model of Object.values(modelUsage)) {
916
- if (model.contextWindow && model.contextWindow > 0) {
917
- session.contextWindowSize = model.contextWindow;
918
- return;
919
- }
920
- }
921
- }
922
1191
  killProcessGroup(proc) {
923
1192
  if (!proc.pid)
924
1193
  return;
@@ -963,12 +1232,28 @@ class SessionManager {
963
1232
  session.process = null;
964
1233
  session.stdin = null;
965
1234
  }
1235
+ if (session.ptyRuntime) {
1236
+ const runtime = session.ptyRuntime;
1237
+ session.ptyRuntime = null;
1238
+ runtime.kill().catch(() => { });
1239
+ }
966
1240
  session.compacting = false;
967
1241
  }
968
1242
  emitSystem(session, sessionId, text) {
969
1243
  session.emitter.emit("system", sessionId, text);
970
1244
  }
1245
+ notifyPendingChanged(session, sessionId) {
1246
+ const count = session.pendingRequests.size;
1247
+ if (session.info.pendingRequestCount === count)
1248
+ return;
1249
+ session.info.pendingRequestCount = count;
1250
+ session.emitter.emit("pending", sessionId, count);
1251
+ }
971
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
+ }
972
1257
  for (const msg of result.intermediateMessages) {
973
1258
  session.emitter.emit("event", sessionId, { type: "message_done", message: msg });
974
1259
  if (msg.toolUses.some((t) => t.name === "Agent")) {
@@ -976,6 +1261,37 @@ class SessionManager {
976
1261
  }
977
1262
  }
978
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
+ }
979
1295
  const permModePrefix = "__permission_mode::";
980
1296
  if (sysMsg.startsWith(permModePrefix)) {
981
1297
  const mode = sysMsg.slice(permModePrefix.length);
@@ -998,9 +1314,14 @@ class SessionManager {
998
1314
  for (const errMsg of result.errors) {
999
1315
  session.emitter.emit("error", sessionId, errMsg);
1000
1316
  }
1001
- for (const todoInput of result.todoInputs) {
1002
- this.handleTodoWrite(session, sessionId, todoInput);
1003
- }
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();
1004
1325
  for (const pa of result.permissionActions) {
1005
1326
  if (pa.type === "auto_approve") {
1006
1327
  this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
@@ -1008,22 +1329,38 @@ class SessionManager {
1008
1329
  else if (pa.type === "auto_deny") {
1009
1330
  this.respondToPermission(sessionId, pa.requestId, false, undefined, undefined, pa.denyReason);
1010
1331
  }
1332
+ else if (session.bypassAllPermissions && !session.planMode && pa.toolName !== "AskUserQuestion") {
1333
+ this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
1334
+ bypassedRequestIds.add(pa.requestId);
1335
+ }
1011
1336
  else {
1012
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
+ }
1013
1342
  session.pendingRequests.set(pa.requestId, {
1014
- type: pa.toolName === "AskUserQuestion" ? "question" : "permission",
1343
+ type: reqType,
1015
1344
  requestId: pa.requestId,
1016
1345
  toolName: pa.toolName,
1017
1346
  toolInput: pa.toolInput || "",
1018
1347
  rawToolInput: pa.rawToolInput,
1348
+ permissionSuggestions: pa.permissionSuggestions,
1019
1349
  planFilePath: planPath,
1020
1350
  planContent: planPath ? (0, plans_1.readPlanFile)(planPath) : undefined,
1021
1351
  });
1352
+ this.notifyPendingChanged(session, sessionId);
1022
1353
  }
1023
1354
  }
1024
1355
  if (result.compactDone) {
1025
1356
  session.compacting = false;
1026
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);
1027
1364
  }
1028
1365
  if (result.emit.length > 0) {
1029
1366
  const listeners = session.emitter.listenerCount("event");
@@ -1032,6 +1369,9 @@ class SessionManager {
1032
1369
  }
1033
1370
  }
1034
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;
1035
1375
  session.emitter.emit("event", sessionId, event);
1036
1376
  }
1037
1377
  session.streamingSnapshot = result.snapshot;
@@ -1049,6 +1389,7 @@ class SessionManager {
1049
1389
  }
1050
1390
  if (result.statusChange === "idle") {
1051
1391
  session.info.status = "idle";
1392
+ console.log(`[sm] emit status idle for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
1052
1393
  session.emitter.emit("status", sessionId, "idle");
1053
1394
  this.flushQueuedMessage(session, sessionId);
1054
1395
  }
@@ -1115,6 +1456,7 @@ class SessionManager {
1115
1456
  this.emitSystem(session, sessionId, `__model_picker::${current}`);
1116
1457
  return true;
1117
1458
  }
1459
+ this.log(sessionId, `/model command: args="${args}", was=${session.info.model}`);
1118
1460
  this.killProcess(session);
1119
1461
  session.info.model = args;
1120
1462
  session.info.status = "idle";
@@ -1141,18 +1483,148 @@ class SessionManager {
1141
1483
  " /clear, /reset, /new - Clear conversation and start fresh",
1142
1484
  " /model [name] - Show or switch model",
1143
1485
  " /rename <name> - Rename this session",
1486
+ " /cost - Show session token usage",
1487
+ " /context - Show context window usage",
1488
+ " /status - Show session status",
1144
1489
  " /help - Show this help message",
1145
1490
  "",
1146
- "All other slash commands (/compact, /cost, /context, /commit,",
1147
- "/review, /analyze, etc.) are passed directly to Claude.",
1491
+ "Other commands (/compact, /commit, /review, etc.) are passed to Claude when possible.",
1148
1492
  ].join("\n");
1149
1493
  this.emitSystem(session, sessionId, helpText);
1150
1494
  return true;
1151
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
+ }
1152
1531
  }
1153
1532
  // All other slash commands pass through to Claude
1154
1533
  return false;
1155
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
+ }
1156
1628
  buildContent(session, text, images, documents) {
1157
1629
  const reminder = session.pendingPlanReminder ? this.planModeReminderText() : null;
1158
1630
  if (session.pendingPlanReminder)
@@ -1197,6 +1669,27 @@ Additional Cockpit rules beyond the CLI's defaults:
1197
1669
  smLog(id, `recovery succeeded: restored from ${cwd}`);
1198
1670
  return true;
1199
1671
  }
1672
+ estimateMessageTokens(text, images, documents) {
1673
+ let tokens = Math.ceil(text.length / 4);
1674
+ if (images)
1675
+ tokens += images.length * 2000;
1676
+ if (documents)
1677
+ tokens += documents.reduce((sum, d) => sum + Math.ceil(d.data.length / 5), 0);
1678
+ return tokens;
1679
+ }
1680
+ shouldPreCompact(session, text, images, documents) {
1681
+ if (!session.contextUsage)
1682
+ return false;
1683
+ if (session.compacting)
1684
+ return false;
1685
+ if (text.trim().toLowerCase().startsWith("/compact"))
1686
+ return false;
1687
+ if (text.trim().startsWith("/"))
1688
+ return false;
1689
+ const estimate = this.estimateMessageTokens(text, images, documents);
1690
+ const { used, total } = session.contextUsage;
1691
+ return used + estimate > total * 0.85;
1692
+ }
1200
1693
  sendMessage(sessionId, text, images, documents) {
1201
1694
  const session = this.sessions.get(sessionId);
1202
1695
  if (!session) {
@@ -1214,6 +1707,29 @@ Additional Cockpit rules beyond the CLI's defaults:
1214
1707
  this.emitSystem(session, sessionId, "__compact::start");
1215
1708
  }
1216
1709
  }
1710
+ // If the message would likely overflow the context window, compact first
1711
+ // and queue the message for delivery after compaction finishes.
1712
+ if (session.info.status !== "running" && this.shouldPreCompact(session, text, images, documents)) {
1713
+ this.log(sessionId, "pre-send compact: message would exceed 85% of context window");
1714
+ (0, debug_logger_1.logDiag)(sessionId, "compact:pre-send");
1715
+ session.queuedMessages.push({ id: `q-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text, images, documents });
1716
+ session.emitter.emit("queued", sessionId, session.queuedMessages.length);
1717
+ session.compacting = true;
1718
+ this.emitSystem(session, sessionId, "__compact::start");
1719
+ session.info.status = "running";
1720
+ session.emitter.emit("status", sessionId, "running");
1721
+ if (session.ptyRuntime?.isAlive) {
1722
+ session.ptyRuntime.sendText("/compact").catch(() => { });
1723
+ }
1724
+ else if (session.process && session.stdin) {
1725
+ const compactInput = { type: "user", message: { role: "user", content: "/compact" } };
1726
+ session.stdin.write(JSON.stringify(compactInput) + "\n");
1727
+ }
1728
+ else {
1729
+ this.spawnProcess(session, sessionId, "/compact");
1730
+ }
1731
+ return true;
1732
+ }
1217
1733
  const content = this.buildContent(session, text, images, documents);
1218
1734
  // If queue was paused (user interrupted then sent a new message),
1219
1735
  // discard the paused messages and reset the flag.
@@ -1228,9 +1744,27 @@ Additional Cockpit rules beyond the CLI's defaults:
1228
1744
  session.emitter.emit("queued", sessionId, session.queuedMessages.length);
1229
1745
  return true;
1230
1746
  }
1231
- (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
+ });
1232
1753
  session.info.status = "running";
1754
+ console.log(`[sm] emit status running for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
1233
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
+ }
1234
1768
  if (session.process && session.stdin) {
1235
1769
  if (session.streamState)
1236
1770
  session.streamState.thinkingStartedAt = Date.now();
@@ -1250,11 +1784,27 @@ Additional Cockpit rules beyond the CLI's defaults:
1250
1784
  }
1251
1785
  ensureProcess(sessionId) {
1252
1786
  const session = this.sessions.get(sessionId);
1253
- if (!session || session.process)
1787
+ if (!session || session.process || session.ptyRuntime?.isAlive)
1254
1788
  return;
1255
1789
  this.spawnProcess(session, sessionId);
1256
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
+ }
1257
1803
  spawnProcess(session, sessionId, text, images, documents) {
1804
+ if (session.runtime === "pty") {
1805
+ this.spawnPtyProcess(session, sessionId, text, images, documents);
1806
+ return;
1807
+ }
1258
1808
  this.log(sessionId, `spawning CLI process (resume=${session.hasSpawnedBefore}, model=${session.info.model || "sonnet"})`);
1259
1809
  const args = ["-p", "--verbose", "--output-format", "stream-json", "--input-format", "stream-json"];
1260
1810
  // In plan mode, omit --allow-dangerously-skip-permissions so the CLI
@@ -1277,25 +1827,35 @@ Additional Cockpit rules beyond the CLI's defaults:
1277
1827
  else {
1278
1828
  args.push("--session-id", session.cliSessionId);
1279
1829
  }
1280
- if (session.info.model) {
1281
- 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);
1282
1835
  }
1283
- if ((0, models_1.allowedEffortLevels)((0, models_1.resolveModel)(session.info.model)).length > 0) {
1836
+ if (this.modelEffortLevels(session.info.model).length > 0) {
1284
1837
  args.push("--effort", session.thinkingLevel);
1285
1838
  }
1286
1839
  const env = { ...process.env };
1287
1840
  delete env.CLAUDECODE;
1288
1841
  delete env.CLAUDE_CODE_ENTRYPOINT;
1289
- // Claude Code defaults to a model's full context window (1M for Opus 4.7,
1290
- // Sonnet 4.6) when no [1m] suffix is present, ignoring the suffix as the
1291
- // gate. CLAUDE_CODE_DISABLE_1M_CONTEXT is the only switch that forces 200K
1292
- // back regardless of model capability set it when the user picked 200K.
1293
- 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) {
1294
1850
  env.CLAUDE_CODE_DISABLE_1M_CONTEXT = "1";
1295
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
+ }
1296
1856
  (0, node_fs_1.mkdirSync)(session.info.cwd, { recursive: true });
1297
1857
  const isWin = process.platform === "win32";
1298
- const proc = (0, node_child_process_1.spawn)("claude", args, {
1858
+ const proc = (0, node_child_process_1.spawn)(getClaudeBin(), args, {
1299
1859
  cwd: session.info.cwd,
1300
1860
  env,
1301
1861
  stdio: ["pipe", "pipe", "pipe"],
@@ -1305,6 +1865,7 @@ Additional Cockpit rules beyond the CLI's defaults:
1305
1865
  session.stdin = proc.stdin;
1306
1866
  session.hasSpawnedBefore = true;
1307
1867
  this.log(sessionId, `CLI process spawned (pid=${proc.pid})`);
1868
+ this.startTodoWatcher(session, sessionId);
1308
1869
  // Send initialize control request before the first user message to get
1309
1870
  // model capabilities, account info, and command metadata from the CLI.
1310
1871
  const initRequest = {
@@ -1405,6 +1966,12 @@ Additional Cockpit rules beyond the CLI's defaults:
1405
1966
  (0, debug_logger_1.logDiag)(sessionId, "compact:done-on-close");
1406
1967
  session.compacting = false;
1407
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);
1408
1975
  }
1409
1976
  if (session.todoItems.length > 0 && session.todoItems.every((t) => t.status === "completed")) {
1410
1977
  session.todoItems = [];
@@ -1428,6 +1995,153 @@ Additional Cockpit rules beyond the CLI's defaults:
1428
1995
  this.flushQueuedMessage(session, sessionId);
1429
1996
  });
1430
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
+ }
1431
2145
  async loadAgentChildren(session, sessionId, messageId, cwd) {
1432
2146
  try {
1433
2147
  const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd);
@@ -1451,12 +2165,15 @@ Additional Cockpit rules beyond the CLI's defaults:
1451
2165
  }
1452
2166
  }
1453
2167
  exports.SessionManager = SessionManager;
1454
- 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
+ }
1455
2171
  function loadMcpServerCache() {
1456
2172
  try {
1457
- if (!(0, node_fs_1.existsSync)(MCP_CACHE_PATH))
2173
+ const fp = mcpCachePath();
2174
+ if (!(0, node_fs_1.existsSync)(fp))
1458
2175
  return [];
1459
- 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"));
1460
2177
  }
1461
2178
  catch {
1462
2179
  return [];
@@ -1464,43 +2181,12 @@ function loadMcpServerCache() {
1464
2181
  }
1465
2182
  function saveMcpServerCache(servers) {
1466
2183
  try {
1467
- const dir = node_path_1.default.dirname(MCP_CACHE_PATH);
2184
+ const fp = mcpCachePath();
2185
+ const dir = node_path_1.default.dirname(fp);
1468
2186
  (0, node_fs_1.mkdirSync)(dir, { recursive: true });
1469
- (0, node_fs_1.writeFileSync)(MCP_CACHE_PATH, JSON.stringify(servers));
2187
+ (0, node_fs_1.writeFileSync)(fp, JSON.stringify(servers));
1470
2188
  }
1471
2189
  catch {
1472
2190
  // best-effort
1473
2191
  }
1474
2192
  }
1475
- // Walk messages newest-first, stop at the most recent /clear boundary, and
1476
- // pull todos from the last TodoWrite call. Pure function so the history-view
1477
- // branch can use it without an in-memory session.
1478
- function extractTodosFromHistory(messages) {
1479
- for (let i = messages.length - 1; i >= 0; i--) {
1480
- const msg = messages[i];
1481
- if (msg.role === "system" && msg.content === "__compacted__")
1482
- return [];
1483
- if (msg.role !== "assistant")
1484
- continue;
1485
- for (let j = msg.toolUses.length - 1; j >= 0; j--) {
1486
- if (msg.toolUses[j].name !== "TodoWrite")
1487
- continue;
1488
- try {
1489
- const input = JSON.parse(msg.toolUses[j].input);
1490
- if (!Array.isArray(input.todos))
1491
- return [];
1492
- return input.todos
1493
- .filter((t) => t.content && t.status)
1494
- .map((t) => ({
1495
- content: t.content,
1496
- status: t.status,
1497
- activeForm: t.activeForm || undefined,
1498
- }));
1499
- }
1500
- catch {
1501
- return [];
1502
- }
1503
- }
1504
- }
1505
- return [];
1506
- }