purplemux 0.2.3 → 0.2.5

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 (474) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +84 -79
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/routes-manifest.json +47 -7
  6. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-qfa-x._.js +3 -0
  7. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00nrs0h._.js +3 -0
  8. package/.next/standalone/.next/server/chunks/[root-of-the-server]__014kwh_._.js +3 -0
  9. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02v.lnb._.js +3 -0
  10. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03x8rds._.js +3 -0
  11. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04cr_m8._.js +1 -1
  12. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06j59n1._.js +3 -0
  13. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07gfnob._.js +1 -1
  14. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07xijrd._.js +1 -1
  15. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08tdlcm._.js +1 -1
  16. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09_6_.~._.js +3 -0
  17. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09gkm_6._.js +1 -1
  18. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_uldiw._.js +15 -0
  19. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0a4t.z5._.js +52 -0
  20. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ar~lbk._.js +3 -0
  21. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bo-su1._.js +1 -1
  22. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c-bb5d._.js +1 -1
  23. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0dvelfj._.js +52 -0
  24. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e.7isl._.js +5 -0
  25. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gcec.8._.js +3 -0
  26. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0i1m1v9._.js +3 -0
  27. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ihlt6s._.js +1 -1
  28. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kd7wei._.js +3 -0
  29. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0mky_tj._.js +35 -2
  30. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oiiu_o._.js +3 -0
  31. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oqgn2h._.js +3 -0
  32. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qvunc5._.js +1 -1
  33. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0r77-u1._.js +52 -0
  34. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rhb4gk._.js +3 -0
  35. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vi8p6v._.js +1 -1
  36. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w0wz~a._.js +3 -0
  37. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w3m-oz._.js +1 -1
  38. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zh8xur._.js +3 -0
  39. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~iu3jq._.js +3 -0
  40. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11xw16l._.js +3 -0
  41. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12nr~pb._.js +1 -1
  42. package/.next/standalone/.next/server/chunks/{_0v81st0._.js → _0.pa6m1._.js} +1 -1
  43. package/.next/standalone/.next/server/chunks/_05ib7yu._.js +3 -0
  44. package/.next/standalone/.next/server/chunks/{_0ll-5~7._.js → _09y8.gr._.js} +1 -1
  45. package/.next/standalone/.next/server/chunks/{_0.5a4bu._.js → _0mwq11h._.js} +1 -1
  46. package/.next/standalone/.next/server/chunks/_0y4b49w._.js +3 -0
  47. package/.next/standalone/.next/server/chunks/_0zcb2f0._.js +3 -0
  48. package/.next/standalone/.next/server/chunks/{node_modules_ws_124xx2_._.js → _106a~ya._.js} +2 -2
  49. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_pages-api_00-t8sq.js +1 -1
  50. package/.next/standalone/.next/server/chunks/src_lib_00fhuqb._.js +3 -0
  51. package/.next/standalone/.next/server/chunks/src_lib_0dvlmi4._.js +15 -0
  52. package/.next/standalone/.next/server/chunks/src_lib_0ojl2hg._.js +52 -0
  53. package/.next/standalone/.next/server/chunks/src_lib_layout-store_ts_0fanx7c._.js +1 -1
  54. package/.next/standalone/.next/server/chunks/src_lib_status-manager_ts_003hlhy._.js +1 -13
  55. package/.next/standalone/.next/server/chunks/src_lib_workspace-store_ts_0vqt073._.js +1 -40
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ap_bxo._.js +3 -0
  57. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t9ru13._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/ssr/_0-9ezhb._.js +3 -0
  59. package/.next/standalone/.next/server/chunks/ssr/{_101yu0w._.js → _0-kyl7i._.js} +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/_003~2_g._.js +3 -0
  61. package/.next/standalone/.next/server/chunks/ssr/_00zsk6a._.js +3 -0
  62. package/.next/standalone/.next/server/chunks/ssr/_017c8be._.js +3 -0
  63. package/.next/standalone/.next/server/chunks/ssr/_01eupc5._.js +3 -0
  64. package/.next/standalone/.next/server/chunks/ssr/_05bq96_._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/ssr/{_0c1yivm._.js → _070zc_o._.js} +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/_07jud1p._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/ssr/_0_sz4y0._.js +3 -0
  68. package/.next/standalone/.next/server/chunks/ssr/_0_uqm-4._.js +3 -0
  69. package/.next/standalone/.next/server/chunks/ssr/{_0ftinmo._.js → _0ed.wmt._.js} +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/_0egedv6._.js +3 -0
  71. package/.next/standalone/.next/server/chunks/ssr/{_0-ug5tr._.js → _0fota2a._.js} +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/_0h4kenr._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/_0ihbr8k._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_0lpqhot._.js +3 -0
  75. package/.next/standalone/.next/server/chunks/ssr/_0mltzed._.js +3 -0
  76. package/.next/standalone/.next/server/chunks/ssr/_0nbe6mv._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/ssr/_0pg-q18._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_0pp3e5j._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/_0ttiybw._.js +18 -0
  80. package/.next/standalone/.next/server/chunks/ssr/_0w.1ts8._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/_0w6jc9p._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/_0xp3-y6._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/ssr/_0y7o.rg._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/ssr/_0ytb_c0._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/ssr/{_0ozy~xe._.js → _0~hz1fq._.js} +2 -2
  86. package/.next/standalone/.next/server/chunks/ssr/_1289s74._.js +3 -0
  87. package/.next/standalone/.next/server/chunks/ssr/{_02jzd5g._.js → _13gee5r._.js} +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/messages_de_terminal_json_[json]_cjs_05jirtw._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/messages_de_webBrowser_json_[json]_cjs_0wfz-ul._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/messages_en_terminal_json_[json]_cjs_0~ls3g-._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/messages_en_webBrowser_json_[json]_cjs_0oirdko._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/messages_es_terminal_json_[json]_cjs_04g2b1_._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/messages_es_webBrowser_json_[json]_cjs_0w_no_c._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/messages_fr_terminal_json_[json]_cjs_0uhakya._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/messages_fr_webBrowser_json_[json]_cjs_00tbjsf._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/messages_ja_terminal_json_[json]_cjs_0776z4f._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/messages_ja_webBrowser_json_[json]_cjs_0tp7~.s._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/messages_ko_terminal_json_[json]_cjs_06611.3._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/messages_ko_webBrowser_json_[json]_cjs_0ibtysu._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/messages_pt-BR_terminal_json_[json]_cjs_034yyg9._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/messages_pt-BR_webBrowser_json_[json]_cjs_0eu9fbw._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/messages_ru_terminal_json_[json]_cjs_0emk8~n._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/messages_ru_webBrowser_json_[json]_cjs_113-x8n._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/messages_tr_terminal_json_[json]_cjs_0xpix8g._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/messages_tr_webBrowser_json_[json]_cjs_12ziott._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/messages_zh-CN_terminal_json_[json]_cjs_12vwl8a._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/messages_zh-CN_webBrowser_json_[json]_cjs_0e5lp-q._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/messages_zh-TW_terminal_json_[json]_cjs_0spg5z5._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/messages_zh-TW_webBrowser_json_[json]_cjs_0u_cpuv._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/ssr/node_modules_@base-ui_030gj7p._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/node_modules_@base-ui_04tdvwp._.js +3 -0
  112. package/.next/standalone/.next/server/chunks/ssr/node_modules_@base-ui_0bdox2f._.js +3 -0
  113. package/.next/standalone/.next/server/chunks/ssr/{src_components_12mrirb._.js → src_components_0_nzv1r._.js} +1 -1
  114. package/.next/standalone/.next/server/chunks/ssr/{src_components_0_aiven._.js → src_components_0bqqfju._.js} +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/{src_components_0geizrr._.js → src_components_0rqxlj-._.js} +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/{src_components_11_1i~k._.js → src_components_0s~.n3e._.js} +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/src_components_features_mobile_mobile-terminal-page_tsx_02chzch._.js +1 -1
  118. package/.next/standalone/.next/server/chunks/ssr/src_components_features_workspace_terminal-page_tsx_0wuq-jl._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/src_lib_message-namespaces_ts_0wjpvu5._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/ssr/src_lib_workspace-store_ts_00x-rec._.js +10 -0
  121. package/.next/standalone/.next/server/middleware-build-manifest.js +84 -79
  122. package/.next/standalone/.next/server/pages/_app/build-manifest.json +4 -4
  123. package/.next/standalone/.next/server/pages/_app/client-build-manifest.json +1 -1
  124. package/.next/standalone/.next/server/pages/_app.js +2 -2
  125. package/.next/standalone/.next/server/pages/_app.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/pages/api/auth/login.js +2 -2
  127. package/.next/standalone/.next/server/pages/api/auth/login.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/pages/api/auth/preflight.js +2 -2
  129. package/.next/standalone/.next/server/pages/api/auth/preflight.js.nft.json +1 -1
  130. package/.next/standalone/.next/server/pages/api/auth/setup.js +2 -2
  131. package/.next/standalone/.next/server/pages/api/auth/setup.js.nft.json +1 -1
  132. package/.next/standalone/.next/server/pages/api/check-claude.js +5 -1
  133. package/.next/standalone/.next/server/pages/api/check-claude.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/console/pages-manifest.json +3 -0
  135. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/console.js +8 -0
  136. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/console.js.map +5 -0
  137. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/console.js.nft.json +1 -0
  138. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/eval/pages-manifest.json +3 -0
  139. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/eval.js +8 -0
  140. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/eval.js.map +5 -0
  141. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/eval.js.nft.json +1 -0
  142. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/network/pages-manifest.json +3 -0
  143. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/network.js +8 -0
  144. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/network.js.map +5 -0
  145. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/network.js.nft.json +1 -0
  146. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/screenshot/pages-manifest.json +3 -0
  147. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/screenshot.js +8 -0
  148. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/screenshot.js.map +5 -0
  149. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/screenshot.js.nft.json +1 -0
  150. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/url/pages-manifest.json +3 -0
  151. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/url.js +8 -0
  152. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/url.js.map +5 -0
  153. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/browser/url.js.nft.json +1 -0
  154. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/result.js +3 -3
  155. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/result.js.nft.json +1 -1
  156. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/send.js +3 -3
  157. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/send.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/status.js +3 -3
  159. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId]/status.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId].js +3 -3
  161. package/.next/standalone/.next/server/pages/api/cli/tabs/[tabId].js.nft.json +1 -1
  162. package/.next/standalone/.next/server/pages/api/cli/tabs.js +3 -3
  163. package/.next/standalone/.next/server/pages/api/cli/tabs.js.nft.json +1 -1
  164. package/.next/standalone/.next/server/pages/api/cli/workspaces.js +2 -2
  165. package/.next/standalone/.next/server/pages/api/cli/workspaces.js.nft.json +1 -1
  166. package/.next/standalone/.next/server/pages/api/config.js +2 -2
  167. package/.next/standalone/.next/server/pages/api/config.js.nft.json +1 -1
  168. package/.next/standalone/.next/server/pages/api/layout/diff.js +1 -1
  169. package/.next/standalone/.next/server/pages/api/layout/diff.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/[tabId]/move.js +2 -2
  171. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/[tabId]/move.js.nft.json +1 -1
  172. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/[tabId].js +5 -5
  173. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/[tabId].js.nft.json +1 -1
  174. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/order.js +2 -2
  175. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs/order.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs.js +5 -5
  177. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId]/tabs.js.nft.json +1 -1
  178. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId].js +2 -2
  179. package/.next/standalone/.next/server/pages/api/layout/pane/[paneId].js.nft.json +1 -1
  180. package/.next/standalone/.next/server/pages/api/layout/pane.js +2 -2
  181. package/.next/standalone/.next/server/pages/api/layout/pane.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/pages/api/layout.js +2 -2
  183. package/.next/standalone/.next/server/pages/api/layout.js.nft.json +1 -1
  184. package/.next/standalone/.next/server/pages/api/message-history.js +2 -2
  185. package/.next/standalone/.next/server/pages/api/message-history.js.nft.json +1 -1
  186. package/.next/standalone/.next/server/pages/api/preflight/runtime.js.nft.json +1 -1
  187. package/.next/standalone/.next/server/pages/api/stats/daily-report/cache.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/pages/api/stats/daily-report/generate.js.nft.json +1 -1
  189. package/.next/standalone/.next/server/pages/api/stats/daily-report/list.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/pages/api/stats/projects.js.nft.json +1 -1
  191. package/.next/standalone/.next/server/pages/api/stats/sessions.js.nft.json +1 -1
  192. package/.next/standalone/.next/server/pages/api/stats/uptime.js.nft.json +1 -1
  193. package/.next/standalone/.next/server/pages/api/status/hook.js +6 -6
  194. package/.next/standalone/.next/server/pages/api/status/hook.js.nft.json +1 -1
  195. package/.next/standalone/.next/server/pages/api/status/statusline.js +6 -6
  196. package/.next/standalone/.next/server/pages/api/status/statusline.js.nft.json +1 -1
  197. package/.next/standalone/.next/server/pages/api/timeline/sessions.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/pages/api/tmux/permission-options.js +3 -2
  199. package/.next/standalone/.next/server/pages/api/tmux/permission-options.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/pages/api/tmux/plan-options.js +3 -2
  201. package/.next/standalone/.next/server/pages/api/tmux/plan-options.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/pages/api/tmux/recover-unknown.js +5 -5
  203. package/.next/standalone/.next/server/pages/api/tmux/recover-unknown.js.nft.json +1 -1
  204. package/.next/standalone/.next/server/pages/api/tmux/reset.js +5 -5
  205. package/.next/standalone/.next/server/pages/api/tmux/reset.js.nft.json +1 -1
  206. package/.next/standalone/.next/server/pages/api/workspace/[workspaceId].js +2 -2
  207. package/.next/standalone/.next/server/pages/api/workspace/[workspaceId].js.nft.json +1 -1
  208. package/.next/standalone/.next/server/pages/api/workspace/active.js +2 -2
  209. package/.next/standalone/.next/server/pages/api/workspace/active.js.nft.json +1 -1
  210. package/.next/standalone/.next/server/pages/api/workspace/group/[groupId].js +2 -2
  211. package/.next/standalone/.next/server/pages/api/workspace/group/[groupId].js.nft.json +1 -1
  212. package/.next/standalone/.next/server/pages/api/workspace/group/reorder.js +2 -2
  213. package/.next/standalone/.next/server/pages/api/workspace/group/reorder.js.nft.json +1 -1
  214. package/.next/standalone/.next/server/pages/api/workspace/group.js +2 -2
  215. package/.next/standalone/.next/server/pages/api/workspace/group.js.nft.json +1 -1
  216. package/.next/standalone/.next/server/pages/api/workspace/reorder.js +2 -2
  217. package/.next/standalone/.next/server/pages/api/workspace/reorder.js.nft.json +1 -1
  218. package/.next/standalone/.next/server/pages/api/workspace/validate.js +2 -2
  219. package/.next/standalone/.next/server/pages/api/workspace/validate.js.nft.json +1 -1
  220. package/.next/standalone/.next/server/pages/api/workspace.js +5 -5
  221. package/.next/standalone/.next/server/pages/api/workspace.js.nft.json +1 -1
  222. package/.next/standalone/.next/server/pages/de/404.html +1 -1
  223. package/.next/standalone/.next/server/pages/de/500.html +1 -1
  224. package/.next/standalone/.next/server/pages/en/404.html +1 -1
  225. package/.next/standalone/.next/server/pages/en/500.html +1 -1
  226. package/.next/standalone/.next/server/pages/es/404.html +1 -1
  227. package/.next/standalone/.next/server/pages/es/500.html +1 -1
  228. package/.next/standalone/.next/server/pages/fr/404.html +1 -1
  229. package/.next/standalone/.next/server/pages/fr/500.html +1 -1
  230. package/.next/standalone/.next/server/pages/index/build-manifest.json +16 -15
  231. package/.next/standalone/.next/server/pages/index/client-build-manifest.json +1 -1
  232. package/.next/standalone/.next/server/pages/index/react-loadable-manifest.json +9 -9
  233. package/.next/standalone/.next/server/pages/index.js +13 -12
  234. package/.next/standalone/.next/server/pages/index.js.nft.json +1 -1
  235. package/.next/standalone/.next/server/pages/ja/404.html +1 -1
  236. package/.next/standalone/.next/server/pages/ja/500.html +1 -1
  237. package/.next/standalone/.next/server/pages/ko/404.html +1 -1
  238. package/.next/standalone/.next/server/pages/ko/500.html +1 -1
  239. package/.next/standalone/.next/server/pages/login/build-manifest.json +9 -8
  240. package/.next/standalone/.next/server/pages/login/client-build-manifest.json +1 -1
  241. package/.next/standalone/.next/server/pages/login.js +8 -7
  242. package/.next/standalone/.next/server/pages/login.js.nft.json +1 -1
  243. package/.next/standalone/.next/server/pages/pt-BR/404.html +1 -1
  244. package/.next/standalone/.next/server/pages/pt-BR/500.html +1 -1
  245. package/.next/standalone/.next/server/pages/reports/build-manifest.json +14 -13
  246. package/.next/standalone/.next/server/pages/reports/client-build-manifest.json +1 -1
  247. package/.next/standalone/.next/server/pages/reports/react-loadable-manifest.json +1 -1
  248. package/.next/standalone/.next/server/pages/reports.js +15 -14
  249. package/.next/standalone/.next/server/pages/reports.js.nft.json +1 -1
  250. package/.next/standalone/.next/server/pages/reset.js.nft.json +1 -1
  251. package/.next/standalone/.next/server/pages/ru/404.html +1 -1
  252. package/.next/standalone/.next/server/pages/ru/500.html +1 -1
  253. package/.next/standalone/.next/server/pages/stats/build-manifest.json +15 -14
  254. package/.next/standalone/.next/server/pages/stats/client-build-manifest.json +1 -1
  255. package/.next/standalone/.next/server/pages/stats/react-loadable-manifest.json +1 -1
  256. package/.next/standalone/.next/server/pages/stats.js +13 -12
  257. package/.next/standalone/.next/server/pages/stats.js.nft.json +1 -1
  258. package/.next/standalone/.next/server/pages/tools-required/build-manifest.json +6 -6
  259. package/.next/standalone/.next/server/pages/tools-required/client-build-manifest.json +1 -1
  260. package/.next/standalone/.next/server/pages/tools-required.js +4 -3
  261. package/.next/standalone/.next/server/pages/tools-required.js.nft.json +1 -1
  262. package/.next/standalone/.next/server/pages/tr/404.html +1 -1
  263. package/.next/standalone/.next/server/pages/tr/500.html +1 -1
  264. package/.next/standalone/.next/server/pages/webview/build-manifest.json +17 -16
  265. package/.next/standalone/.next/server/pages/webview/client-build-manifest.json +1 -1
  266. package/.next/standalone/.next/server/pages/webview/react-loadable-manifest.json +1 -1
  267. package/.next/standalone/.next/server/pages/webview.js +13 -12
  268. package/.next/standalone/.next/server/pages/webview.js.nft.json +1 -1
  269. package/.next/standalone/.next/server/pages/zh-CN/404.html +1 -1
  270. package/.next/standalone/.next/server/pages/zh-CN/500.html +1 -1
  271. package/.next/standalone/.next/server/pages/zh-TW/404.html +1 -1
  272. package/.next/standalone/.next/server/pages/zh-TW/500.html +1 -1
  273. package/.next/standalone/.next/server/pages-manifest.json +5 -0
  274. package/.next/standalone/.next/static/chunks/{11tnyk0iystp1.js → 0--r5y9cw3.0z.js} +1 -1
  275. package/.next/standalone/.next/static/chunks/{0w1ldes9u.mhe.js → 0-8v00lvs9_s0.js} +1 -1
  276. package/.next/standalone/.next/static/chunks/{0oy5nvsojxb2i.js → 0-rskn1p_p.qb.js} +1 -1
  277. package/.next/standalone/.next/static/chunks/{0h7n~i8gk~-a2.js → 0.4j~sc70rsrv.js} +1 -1
  278. package/.next/standalone/.next/static/chunks/{0g0xm7shj062y.js → 001_h.~thz3j3.js} +1 -1
  279. package/.next/standalone/.next/static/chunks/{0ynitrrzdxcnh.js → 00gxls80r--_0.js} +9 -8
  280. package/.next/standalone/.next/static/chunks/{121i8u8byuotx.js → 01rmp.m_ls7z_.js} +1 -1
  281. package/.next/standalone/.next/static/chunks/{0312riii_sl_1.js → 02o84r01jsc.z.js} +1 -1
  282. package/.next/standalone/.next/static/chunks/039-4cgt.dvjg.js +1 -0
  283. package/.next/standalone/.next/static/chunks/03t01d94eyxh2.js +1 -0
  284. package/.next/standalone/.next/static/chunks/04hn532e1vcts.js +1 -0
  285. package/.next/standalone/.next/static/chunks/05o56eq7.f3q2.js +1 -0
  286. package/.next/standalone/.next/static/chunks/{0x.dxrfqc.ix9.js → 0628quqp4ggh9.js} +1 -1
  287. package/.next/standalone/.next/static/chunks/06ak74s111wx-.js +1 -0
  288. package/.next/standalone/.next/static/chunks/07yop4v9xcwb9.js +1 -0
  289. package/.next/standalone/.next/static/chunks/08d6vee5l~1wn.js +1 -0
  290. package/.next/standalone/.next/static/chunks/09o2m0ingey8v.js +1 -0
  291. package/.next/standalone/.next/static/chunks/{0d5b6a8r1tk95.js → 09s7ub8rgh~u-.js} +1 -1
  292. package/.next/standalone/.next/static/chunks/{02su2lz3i24nj.js → 09zxrli-btome.js} +1 -1
  293. package/.next/standalone/.next/static/chunks/0_7~rgbkmfo_p.js +1 -0
  294. package/.next/standalone/.next/static/chunks/0a1xt.enr50l5.js +1 -0
  295. package/.next/standalone/.next/static/chunks/{0-p.9vdmq-_co.js → 0am7rh7xdv5lw.js} +4 -4
  296. package/.next/standalone/.next/static/chunks/{13u3mwvwu3kc..js → 0apqp49tgoz~z.js} +1 -1
  297. package/.next/standalone/.next/static/chunks/{0_67ozmvnvz16.js → 0bx27stclo8g5.js} +1 -1
  298. package/.next/standalone/.next/static/chunks/0ddh4qmi2awdq.js +1 -0
  299. package/.next/standalone/.next/static/chunks/0dwxj97xm70gv.js +1 -0
  300. package/.next/standalone/.next/static/chunks/0f3q6qhpk.i_r.js +1 -0
  301. package/.next/standalone/.next/static/chunks/{07.5h~7~q9~1e.js → 0f_7vuqno92ye.js} +1 -1
  302. package/.next/standalone/.next/static/chunks/0fsldybjx443~.js +1 -0
  303. package/.next/standalone/.next/static/chunks/0gfhd.gsbt9qg.js +1 -0
  304. package/.next/standalone/.next/static/chunks/0hv4~cszgs3im.js +1 -0
  305. package/.next/standalone/.next/static/chunks/0ic.mcu6-9din.js +1 -0
  306. package/.next/standalone/.next/static/chunks/0k4b.~5c4nvtm.js +1 -0
  307. package/.next/standalone/.next/static/chunks/0kqxfunh4731g.js +1 -0
  308. package/.next/standalone/.next/static/chunks/{0fn24h74ta78c.js → 0k~crb4s4z7gy.js} +1 -1
  309. package/.next/standalone/.next/static/chunks/0lrjdru2bjp.x.js +1 -0
  310. package/.next/standalone/.next/static/chunks/0lujhtd04orw5.js +1 -0
  311. package/.next/standalone/.next/static/chunks/0mwkajcworx_-.js +1 -0
  312. package/.next/standalone/.next/static/chunks/0nqofghl.17w_.js +1 -0
  313. package/.next/standalone/.next/static/chunks/0o1lsz827g-q_.js +1 -0
  314. package/.next/standalone/.next/static/chunks/0qqsez8ir1.fs.js +1 -0
  315. package/.next/standalone/.next/static/chunks/{0_htal_j04mkg.js → 0r3lm4_qr3y.a.js} +1 -1
  316. package/.next/standalone/.next/static/chunks/{06vxx-4w.uvj0.js → 0rahh2v7~f4tj.js} +17 -16
  317. package/.next/standalone/.next/static/chunks/{0pxbg4s8a4y54.js → 0rb41e1r1urhx.js} +1 -1
  318. package/.next/standalone/.next/static/chunks/0uii4rziiew3_.js +1 -0
  319. package/.next/standalone/.next/static/chunks/0vtkq~yk_1~gv.js +1 -0
  320. package/.next/standalone/.next/static/chunks/0vx2hhzc46h_7.js +1 -0
  321. package/.next/standalone/.next/static/chunks/0x_.wshvak6zp.js +1 -0
  322. package/.next/standalone/.next/static/chunks/0xa1.t1vj1mw0.js +1 -0
  323. package/.next/standalone/.next/static/chunks/0xpr6vw-p8oxk.js +1 -0
  324. package/.next/standalone/.next/static/chunks/{0uzs3jw4-93ly.js → 0zih6-g65txpb.js} +1 -1
  325. package/.next/standalone/.next/static/chunks/0zn1jt__-t51p.js +1 -0
  326. package/.next/standalone/.next/static/chunks/0zrhxc96zwjuv.js +1 -0
  327. package/.next/standalone/.next/static/chunks/0z~yy1lqrvp_a.js +1 -0
  328. package/.next/standalone/.next/static/chunks/0~cgr_3dpx0vl.js +1 -0
  329. package/.next/standalone/.next/static/chunks/{0te1jnz5.rt.r.js → 0~g0t2q6o3r-7.js} +6 -6
  330. package/.next/standalone/.next/static/chunks/0~vfb0ylk_9au.js +16 -0
  331. package/.next/standalone/.next/static/chunks/109f1pvy3e_vd.js +1 -0
  332. package/.next/standalone/.next/static/chunks/10em078j6cul4.js +1 -0
  333. package/.next/standalone/.next/static/chunks/{0a9t5laucshuf.js → 10todxw2604hk.js} +1 -1
  334. package/.next/standalone/.next/static/chunks/{05zne4hn1v65k.js → 10uz6x-h~dv0..js} +14 -13
  335. package/.next/standalone/.next/static/chunks/{0~nexgc77r_hk.js → 13q-ol3bkz8ft.js} +16 -15
  336. package/.next/standalone/.next/static/chunks/14if5vtky.3sn.js +1 -0
  337. package/.next/standalone/.next/static/chunks/{017n78o_7xb4_.js → 15hd85wggjanq.js} +1 -1
  338. package/.next/standalone/.next/static/chunks/15i_n03eg5uyp.js +1 -0
  339. package/.next/standalone/.next/static/chunks/15sblmrroyskk.js +1 -0
  340. package/.next/standalone/.next/static/chunks/1756nfyulu.9h.css +1 -0
  341. package/.next/standalone/.next/static/chunks/{0j.sfmmqj2xel.js → 17rh_.7tkk2m0.js} +15 -14
  342. package/.next/standalone/.next/static/chunks/turbopack-02..gqxjw9fev.js +1 -0
  343. package/.next/standalone/.next/static/chunks/turbopack-05luogg2yney~.js +1 -0
  344. package/.next/standalone/.next/static/chunks/turbopack-092b2t67-z3ds.js +1 -0
  345. package/.next/standalone/.next/static/chunks/turbopack-0eue2xixdnbd..js +1 -0
  346. package/.next/standalone/.next/static/chunks/{turbopack-15bv~a4hbvh29.js → turbopack-0i6l53-j6t6zg.js} +1 -1
  347. package/.next/standalone/.next/static/chunks/{turbopack-0d-xk62f1t05v.js → turbopack-0ser1ty-sh2jk.js} +1 -1
  348. package/.next/standalone/.next/static/chunks/{turbopack-0zcblahe.hdqd.js → turbopack-0zouy.~ram.7g.js} +1 -1
  349. package/.next/standalone/.next/static/{X7BRO7ORR4bKFt1LXzGU8 → onsm_2jNZvyggHqM9yibn}/_buildManifest.js +11 -6
  350. package/.next/standalone/messages/de/terminal.json +4 -0
  351. package/.next/standalone/messages/de/webBrowser.json +5 -1
  352. package/.next/standalone/messages/en/terminal.json +4 -0
  353. package/.next/standalone/messages/en/webBrowser.json +5 -1
  354. package/.next/standalone/messages/es/terminal.json +4 -0
  355. package/.next/standalone/messages/es/webBrowser.json +5 -1
  356. package/.next/standalone/messages/fr/terminal.json +4 -0
  357. package/.next/standalone/messages/fr/webBrowser.json +5 -1
  358. package/.next/standalone/messages/ja/terminal.json +4 -0
  359. package/.next/standalone/messages/ja/webBrowser.json +5 -1
  360. package/.next/standalone/messages/ko/terminal.json +4 -0
  361. package/.next/standalone/messages/ko/webBrowser.json +5 -1
  362. package/.next/standalone/messages/pt-BR/terminal.json +4 -0
  363. package/.next/standalone/messages/pt-BR/webBrowser.json +5 -1
  364. package/.next/standalone/messages/ru/terminal.json +4 -0
  365. package/.next/standalone/messages/ru/webBrowser.json +5 -1
  366. package/.next/standalone/messages/tr/terminal.json +4 -0
  367. package/.next/standalone/messages/tr/webBrowser.json +5 -1
  368. package/.next/standalone/messages/zh-CN/terminal.json +4 -0
  369. package/.next/standalone/messages/zh-CN/webBrowser.json +5 -1
  370. package/.next/standalone/messages/zh-TW/terminal.json +4 -0
  371. package/.next/standalone/messages/zh-TW/webBrowser.json +5 -1
  372. package/.next/standalone/package.json +5 -2
  373. package/.next/standalone/server.js +1 -1
  374. package/.next/standalone/src/config/tmux.conf +17 -7
  375. package/.next/standalone/src/lib/providers/claude/index.ts +44 -0
  376. package/.next/standalone/src/pages/api/layout/pane/[paneId]/tabs/index.ts +13 -6
  377. package/README.de.md +5 -4
  378. package/README.es.md +5 -4
  379. package/README.fr.md +5 -4
  380. package/README.ja.md +5 -4
  381. package/README.ko.md +5 -4
  382. package/README.md +5 -4
  383. package/README.pt-BR.md +5 -4
  384. package/README.ru.md +5 -4
  385. package/README.tr.md +5 -4
  386. package/README.zh-CN.md +5 -4
  387. package/README.zh-TW.md +5 -4
  388. package/bin/cli.js +95 -0
  389. package/dist/server.js +974 -852
  390. package/package.json +5 -2
  391. package/src/config/tmux.conf +17 -7
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01.~37j._.js +0 -3
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__016s4a9._.js +0 -3
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02.9a5j._.js +0 -3
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03l15.f._.js +0 -3
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ij_ys._.js +0 -42
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06h3gzy._.js +0 -3
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_fu3k.._.js +0 -3
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_imm_0._.js +0 -3
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0abp0lo._.js +0 -3
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0auutl5._.js +0 -5
  402. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d-inw8._.js +0 -3
  403. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g8mjyh._.js +0 -3
  404. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lk7ru8._.js +0 -3
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l~_wd0._.js +0 -3
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ovn6yp._.js +0 -3
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0un_g-o._.js +0 -3
  408. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12ksl6n._.js +0 -42
  409. package/.next/standalone/.next/server/chunks/_03-duro._.js +0 -3
  410. package/.next/standalone/.next/server/chunks/_07097f~._.js +0 -3
  411. package/.next/standalone/.next/server/chunks/_0z7d6.z._.js +0 -3
  412. package/.next/standalone/.next/server/chunks/src_lib_0p.xsqi._.js +0 -3
  413. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da5cj~._.js +0 -3
  414. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12b2-y_._.js +0 -3
  415. package/.next/standalone/.next/server/chunks/ssr/_016o9_-._.js +0 -3
  416. package/.next/standalone/.next/server/chunks/ssr/_04iqb-o._.js +0 -3
  417. package/.next/standalone/.next/server/chunks/ssr/_04q3_kj._.js +0 -3
  418. package/.next/standalone/.next/server/chunks/ssr/_0a_u5qm._.js +0 -3
  419. package/.next/standalone/.next/server/chunks/ssr/_0d58w1~._.js +0 -3
  420. package/.next/standalone/.next/server/chunks/ssr/_0nib_x8._.js +0 -3
  421. package/.next/standalone/.next/server/chunks/ssr/_0nuztht._.js +0 -18
  422. package/.next/standalone/.next/server/chunks/ssr/_0oca87b._.js +0 -3
  423. package/.next/standalone/.next/server/chunks/ssr/_0ovjjn5._.js +0 -3
  424. package/.next/standalone/.next/server/chunks/ssr/_0pk4~_0._.js +0 -3
  425. package/.next/standalone/.next/server/chunks/ssr/_0qt-m3l._.js +0 -3
  426. package/.next/standalone/.next/server/chunks/ssr/_0sm8slq._.js +0 -3
  427. package/.next/standalone/.next/server/chunks/ssr/_10s2f96._.js +0 -3
  428. package/.next/standalone/.next/server/chunks/ssr/_13c-b~p._.js +0 -3
  429. package/.next/standalone/.next/server/chunks/ssr/_13lrp9_._.js +0 -3
  430. package/.next/standalone/.next/static/chunks/0-7en.d6a3jki.js +0 -1
  431. package/.next/standalone/.next/static/chunks/0-pm5wxsyxs3e.js +0 -1
  432. package/.next/standalone/.next/static/chunks/01ul8lmr04ls3.js +0 -1
  433. package/.next/standalone/.next/static/chunks/05b7zy0n0vhms.js +0 -1
  434. package/.next/standalone/.next/static/chunks/05kshd9vdrl4o.js +0 -1
  435. package/.next/standalone/.next/static/chunks/05w~qu2zpvh2f.js +0 -1
  436. package/.next/standalone/.next/static/chunks/08f708~_7uy_i.js +0 -1
  437. package/.next/standalone/.next/static/chunks/0af.3khnmptnl.js +0 -1
  438. package/.next/standalone/.next/static/chunks/0cvx059r5hgj1.js +0 -1
  439. package/.next/standalone/.next/static/chunks/0dp178b-0_ltl.js +0 -1
  440. package/.next/standalone/.next/static/chunks/0ebjicjua7yl-.js +0 -1
  441. package/.next/standalone/.next/static/chunks/0gn-f6_m696k0.js +0 -1
  442. package/.next/standalone/.next/static/chunks/0kaufevqdhsld.js +0 -1
  443. package/.next/standalone/.next/static/chunks/0n2k1al4sr_qq.css +0 -1
  444. package/.next/standalone/.next/static/chunks/0n4fv8.loh_0x.js +0 -1
  445. package/.next/standalone/.next/static/chunks/0nn618je7_7ec.js +0 -16
  446. package/.next/standalone/.next/static/chunks/0pv9~yath4mjh.js +0 -1
  447. package/.next/standalone/.next/static/chunks/0q0yh17_ncipj.js +0 -1
  448. package/.next/standalone/.next/static/chunks/0qkrdmhiv-0d3.js +0 -1
  449. package/.next/standalone/.next/static/chunks/0r9z55-r31en8.js +0 -1
  450. package/.next/standalone/.next/static/chunks/0ra09kjja5rf..js +0 -1
  451. package/.next/standalone/.next/static/chunks/0sc7tkg1gojr..js +0 -1
  452. package/.next/standalone/.next/static/chunks/0u.snf3d~5nvq.js +0 -1
  453. package/.next/standalone/.next/static/chunks/0u9yrtrs1bktp.js +0 -1
  454. package/.next/standalone/.next/static/chunks/0v.l~.~v98c2c.js +0 -1
  455. package/.next/standalone/.next/static/chunks/0wu~4k-l8otuy.js +0 -1
  456. package/.next/standalone/.next/static/chunks/0wvu-lowt9uem.js +0 -1
  457. package/.next/standalone/.next/static/chunks/0x7cvsf..ezd..js +0 -1
  458. package/.next/standalone/.next/static/chunks/0yb~gw6ukzdmo.js +0 -1
  459. package/.next/standalone/.next/static/chunks/0yg3hj1g~k1ip.js +0 -1
  460. package/.next/standalone/.next/static/chunks/0z_~g~mb.kjs1.js +0 -1
  461. package/.next/standalone/.next/static/chunks/0~c6h8j7ut2ca.js +0 -1
  462. package/.next/standalone/.next/static/chunks/0~lnp45fxxtgz.js +0 -1
  463. package/.next/standalone/.next/static/chunks/0~ts_4hi7.u_0.js +0 -1
  464. package/.next/standalone/.next/static/chunks/13_l03e3sab-g.js +0 -1
  465. package/.next/standalone/.next/static/chunks/156~ejmpjxu8e.js +0 -1
  466. package/.next/standalone/.next/static/chunks/15m4y6otktj8z.js +0 -1
  467. package/.next/standalone/.next/static/chunks/16bag6z7n~ffw.js +0 -1
  468. package/.next/standalone/.next/static/chunks/17ebdp-_o5o30.js +0 -1
  469. package/.next/standalone/.next/static/chunks/turbopack-0nn9kx.dkgwqs.js +0 -1
  470. package/.next/standalone/.next/static/chunks/turbopack-0rb3q18bhb2hu.js +0 -1
  471. package/.next/standalone/.next/static/chunks/turbopack-0~wmco6ifn20m.js +0 -1
  472. package/.next/standalone/.next/static/chunks/turbopack-1469mxaruw82d.js +0 -1
  473. /package/.next/standalone/.next/static/{X7BRO7ORR4bKFt1LXzGU8 → onsm_2jNZvyggHqM9yibn}/_clientMiddlewareManifest.js +0 -0
  474. /package/.next/standalone/.next/static/{X7BRO7ORR4bKFt1LXzGU8 → onsm_2jNZvyggHqM9yibn}/_ssgManifest.js +0 -0
package/dist/server.js CHANGED
@@ -3847,7 +3847,7 @@ var init_platform = __esm({
3847
3847
  });
3848
3848
 
3849
3849
  // src/lib/tmux.ts
3850
- var import_child_process, import_promises, import_util, import_path2, log, execFile, TMUX_SOCKET, TMUX_CONFIG_PATH, CMD_TIMEOUT, listSessions, createSession, sleep, killSession, hasSession, cleanDeadSessions, scanSessions, readShellCwd, getSessionCwd, getSessionPanePid, applyConfig, defaultSessionName, workspaceSessionName, getPaneCurrentCommand, getAllPanesInfo, SAFE_SHELLS, checkTerminalProcess, getPaneTitle, exitCopyMode, sendKeys, capturePaneContent, capturePaneContentWithHistory, getChildPidsOf, getDescendantPids, getListeningPortsLinux, getListeningPorts;
3850
+ var import_child_process, import_promises, import_util, import_path2, log, execFile, TMUX_SOCKET, TMUX_CONFIG_PATH, CMD_TIMEOUT, listSessions, createSession, sleep, killSession, resolveExistingDir, hasSession, cleanDeadSessions, scanSessions, readShellCwd, getSessionCwd, getSessionPanePid, applyConfig, defaultSessionName, workspaceSessionName, getPaneCurrentCommand, getAllPanesInfo, SAFE_SHELLS, checkTerminalProcess, getPaneTitle, exitCopyMode, sendKeys, capturePaneContent, capturePaneContentWithHistory, getChildPidsOf, getDescendantPids, getListeningPortsLinux, getListeningPorts;
3851
3851
  var init_tmux = __esm({
3852
3852
  "src/lib/tmux.ts"() {
3853
3853
  "use strict";
@@ -3957,6 +3957,21 @@ var init_tmux = __esm({
3957
3957
  }
3958
3958
  log.warn(`tmux session still alive after kill: ${name}`);
3959
3959
  };
3960
+ resolveExistingDir = async (preferred) => {
3961
+ const fallback = PRISTINE_ENV.HOME || "/";
3962
+ if (!preferred) return fallback;
3963
+ let candidate = preferred;
3964
+ while (true) {
3965
+ try {
3966
+ const stat = await import_promises.default.stat(candidate);
3967
+ if (stat.isDirectory()) return candidate;
3968
+ } catch {
3969
+ }
3970
+ const parent = import_path2.default.dirname(candidate);
3971
+ if (parent === candidate) return fallback;
3972
+ candidate = parent;
3973
+ }
3974
+ };
3960
3975
  hasSession = async (name) => {
3961
3976
  try {
3962
3977
  await execFile(
@@ -4219,13 +4234,13 @@ var init_tmux = __esm({
4219
4234
  });
4220
4235
 
4221
4236
  // src/lib/sync-server.ts
4222
- var log3, g2, clients, handleSyncConnection, BACKPRESSURE_LIMIT, broadcastSync, gracefulSyncShutdown;
4237
+ var log2, g2, clients, handleSyncConnection, BACKPRESSURE_LIMIT, broadcastSync, gracefulSyncShutdown;
4223
4238
  var init_sync_server = __esm({
4224
4239
  "src/lib/sync-server.ts"() {
4225
4240
  "use strict";
4226
4241
  init_wrapper();
4227
4242
  init_logger();
4228
- log3 = createLogger("sync");
4243
+ log2 = createLogger("sync");
4229
4244
  g2 = globalThis;
4230
4245
  if (!g2.__ptSyncClients) g2.__ptSyncClients = /* @__PURE__ */ new Set();
4231
4246
  clients = g2.__ptSyncClients;
@@ -4233,7 +4248,7 @@ var init_sync_server = __esm({
4233
4248
  clients.add(ws);
4234
4249
  ws.on("close", () => clients.delete(ws));
4235
4250
  ws.on("error", (err) => {
4236
- log3.error(`websocket error: ${err.message}`);
4251
+ log2.error(`websocket error: ${err.message}`);
4237
4252
  clients.delete(ws);
4238
4253
  });
4239
4254
  };
@@ -4271,35 +4286,35 @@ var init_layout_tree = __esm({
4271
4286
  });
4272
4287
 
4273
4288
  // src/lib/layout-store.ts
4274
- var import_promises5, import_path7, import_os6, log7, BASE_DIR2, g4, setLayoutReconciler, withLock2, generatePaneId, generateTabId, resolveLayoutDir, resolveLayoutFile, createDefaultTab, createDefaultPaneNode, readLayoutFile, extractWsIdFromPath, writeLayoutFile, crossCheckLayout, createDefaultLayout, parseSessionName, updateTabClaudeSessionId, updateTabClaudeSummary, updateTabLastUserMessage, updateTabCliStatus;
4289
+ var import_promises2, import_path3, import_os2, log3, BASE_DIR, g3, setLayoutReconciler, withLock, generatePaneId, generateTabId, resolveLayoutDir, resolveLayoutFile, createDefaultTab, createDefaultPaneNode, readLayoutFile, extractWsIdFromPath, writeLayoutFile, crossCheckLayout, createDefaultLayout, reconcileTabCwd, parseSessionName, mutateTab, updateTabAgentSessionId, updateTabAgentSummary, updateTabClaudeSummary, updateTabLastUserMessage, updateTabCliStatus;
4275
4290
  var init_layout_store = __esm({
4276
4291
  "src/lib/layout-store.ts"() {
4277
4292
  "use strict";
4278
- import_promises5 = __toESM(require("fs/promises"));
4279
- import_path7 = __toESM(require("path"));
4280
- import_os6 = __toESM(require("os"));
4293
+ import_promises2 = __toESM(require("fs/promises"));
4294
+ import_path3 = __toESM(require("path"));
4295
+ import_os2 = __toESM(require("os"));
4281
4296
  init_nanoid();
4282
4297
  init_tmux();
4283
4298
  init_sync_server();
4284
4299
  init_logger();
4285
4300
  init_layout_tree();
4286
4301
  init_layout_tree();
4287
- log7 = createLogger("layout");
4288
- BASE_DIR2 = import_path7.default.join(import_os6.default.homedir(), ".purplemux");
4289
- g4 = globalThis;
4290
- if (!g4.__ptLayoutLock) g4.__ptLayoutLock = Promise.resolve();
4291
- if (!g4.__ptLayoutContentCache) g4.__ptLayoutContentCache = /* @__PURE__ */ new Map();
4292
- if (g4.__ptLayoutReconciler === void 0) g4.__ptLayoutReconciler = null;
4302
+ log3 = createLogger("layout");
4303
+ BASE_DIR = import_path3.default.join(import_os2.default.homedir(), ".purplemux");
4304
+ g3 = globalThis;
4305
+ if (!g3.__ptLayoutLock) g3.__ptLayoutLock = Promise.resolve();
4306
+ if (!g3.__ptLayoutContentCache) g3.__ptLayoutContentCache = /* @__PURE__ */ new Map();
4307
+ if (g3.__ptLayoutReconciler === void 0) g3.__ptLayoutReconciler = null;
4293
4308
  setLayoutReconciler = (reconciler) => {
4294
- g4.__ptLayoutReconciler = reconciler;
4309
+ g3.__ptLayoutReconciler = reconciler;
4295
4310
  };
4296
- withLock2 = async (fn) => {
4311
+ withLock = async (fn) => {
4297
4312
  let release;
4298
4313
  const next2 = new Promise((r) => {
4299
4314
  release = r;
4300
4315
  });
4301
- const prev = g4.__ptLayoutLock;
4302
- g4.__ptLayoutLock = next2;
4316
+ const prev = g3.__ptLayoutLock;
4317
+ g3.__ptLayoutLock = next2;
4303
4318
  await prev;
4304
4319
  try {
4305
4320
  return await fn();
@@ -4309,8 +4324,8 @@ var init_layout_store = __esm({
4309
4324
  };
4310
4325
  generatePaneId = () => `pane-${nanoid(6)}`;
4311
4326
  generateTabId = () => `tab-${nanoid(6)}`;
4312
- resolveLayoutDir = (wsId) => import_path7.default.join(BASE_DIR2, "workspaces", wsId);
4313
- resolveLayoutFile = (wsId) => import_path7.default.join(resolveLayoutDir(wsId), "layout.json");
4327
+ resolveLayoutDir = (wsId) => import_path3.default.join(BASE_DIR, "workspaces", wsId);
4328
+ resolveLayoutFile = (wsId) => import_path3.default.join(resolveLayoutDir(wsId), "layout.json");
4314
4329
  createDefaultTab = (wsId, paneId, order = 0, cwd) => {
4315
4330
  const tabId = generateTabId();
4316
4331
  const tab = {
@@ -4333,16 +4348,16 @@ var init_layout_store = __esm({
4333
4348
  readLayoutFile = async (filePath) => {
4334
4349
  let raw;
4335
4350
  try {
4336
- raw = await import_promises5.default.readFile(filePath, "utf-8");
4351
+ raw = await import_promises2.default.readFile(filePath, "utf-8");
4337
4352
  } catch {
4338
4353
  return null;
4339
4354
  }
4340
4355
  try {
4341
4356
  return JSON.parse(raw);
4342
4357
  } catch {
4343
- log7.warn(`${filePath} parse failed`);
4358
+ log3.warn(`${filePath} parse failed`);
4344
4359
  try {
4345
- await import_promises5.default.copyFile(filePath, filePath.replace(/\.json$/, ".json.bak"));
4360
+ await import_promises2.default.copyFile(filePath, filePath.replace(/\.json$/, ".json.bak"));
4346
4361
  } catch {
4347
4362
  }
4348
4363
  return null;
@@ -4354,22 +4369,22 @@ var init_layout_store = __esm({
4354
4369
  };
4355
4370
  writeLayoutFile = async (data, filePath) => {
4356
4371
  const contentKey = JSON.stringify({ root: data.root, activePaneId: data.activePaneId });
4357
- const cache2 = g4.__ptLayoutContentCache;
4372
+ const cache2 = g3.__ptLayoutContentCache;
4358
4373
  if (cache2.get(filePath) === contentKey) return;
4359
- await import_promises5.default.mkdir(import_path7.default.dirname(filePath), { recursive: true });
4374
+ await import_promises2.default.mkdir(import_path3.default.dirname(filePath), { recursive: true });
4360
4375
  const tmpFile = filePath + ".tmp";
4361
4376
  try {
4362
- await import_promises5.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
4363
- await import_promises5.default.rename(tmpFile, filePath);
4377
+ await import_promises2.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
4378
+ await import_promises2.default.rename(tmpFile, filePath);
4364
4379
  } catch (err) {
4365
- await import_promises5.default.unlink(tmpFile).catch(() => {
4380
+ await import_promises2.default.unlink(tmpFile).catch(() => {
4366
4381
  });
4367
4382
  throw err;
4368
4383
  }
4369
4384
  cache2.set(filePath, contentKey);
4370
4385
  const wsId = extractWsIdFromPath(filePath);
4371
4386
  if (wsId) {
4372
- const reconciler = g4.__ptLayoutReconciler;
4387
+ const reconciler = g3.__ptLayoutReconciler;
4373
4388
  if (reconciler) {
4374
4389
  const validTabIds = collectAllTabs(data.root).map((t) => t.id);
4375
4390
  reconciler.reconcileWorkspaceTabs(wsId, validTabIds);
@@ -4388,7 +4403,7 @@ var init_layout_store = __esm({
4388
4403
  layoutSessions.add(tab.sessionName);
4389
4404
  if (!tmuxSet.has(tab.sessionName) && tab.panelType === "claude-code") {
4390
4405
  const cwd = tab.cwd || defaultCwd;
4391
- log7.debug(`crossCheck: Claude tab session recreated: ${tab.sessionName} (cwd: ${cwd})`);
4406
+ log3.debug(`crossCheck: Claude tab session recreated: ${tab.sessionName} (cwd: ${cwd})`);
4392
4407
  await createSession(tab.sessionName, 80, 24, cwd);
4393
4408
  changed = true;
4394
4409
  }
@@ -4433,75 +4448,69 @@ var init_layout_store = __esm({
4433
4448
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4434
4449
  };
4435
4450
  };
4451
+ reconcileTabCwd = async (sessionName) => withLock(async () => {
4452
+ const parsed = parseSessionName(sessionName);
4453
+ if (!parsed) return;
4454
+ const filePath = resolveLayoutFile(parsed.wsId);
4455
+ const layout = await readLayoutFile(filePath);
4456
+ if (!layout) return;
4457
+ const pane = collectPanes(layout.root).find((p) => p.id === parsed.paneId);
4458
+ if (!pane) return;
4459
+ const tab = pane.tabs.find((t) => t.id === parsed.tabId);
4460
+ if (!tab || !tab.cwd) return;
4461
+ const effectiveCwd = await resolveExistingDir(tab.cwd);
4462
+ if (effectiveCwd === tab.cwd) return;
4463
+ log3.warn(`tab cwd missing, clearing: ${sessionName} (was ${tab.cwd})`);
4464
+ tab.cwd = effectiveCwd;
4465
+ delete tab.lastCommand;
4466
+ layout.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4467
+ await writeLayoutFile(layout, filePath);
4468
+ });
4436
4469
  parseSessionName = (sessionName) => {
4437
4470
  const match = sessionName.match(/^pt-(ws-.*?)-(pane-.*?)-(tab-.+)$/);
4438
4471
  if (!match) return null;
4439
4472
  return { wsId: match[1], paneId: match[2], tabId: match[3] };
4440
4473
  };
4441
- updateTabClaudeSessionId = async (sessionName, claudeSessionId) => {
4442
- const parsed = parseSessionName(sessionName);
4443
- if (!parsed) return;
4444
- await withLock2(async () => {
4445
- const filePath = resolveLayoutFile(parsed.wsId);
4446
- const layout = await readLayoutFile(filePath);
4447
- if (!layout) return;
4448
- const allTabs = collectAllTabs(layout.root);
4449
- const tab = allTabs.find((t) => t.sessionName === sessionName);
4450
- if (!tab) return;
4451
- tab.claudeSessionId = claudeSessionId;
4452
- layout.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4453
- await writeLayoutFile(layout, filePath);
4454
- });
4455
- };
4456
- updateTabClaudeSummary = async (sessionName, claudeSummary) => {
4457
- const parsed = parseSessionName(sessionName);
4458
- if (!parsed) return;
4459
- await withLock2(async () => {
4460
- const filePath = resolveLayoutFile(parsed.wsId);
4461
- const layout = await readLayoutFile(filePath);
4462
- if (!layout) return;
4463
- const allTabs = collectAllTabs(layout.root);
4464
- const tab = allTabs.find((t) => t.sessionName === sessionName);
4465
- if (!tab) return;
4466
- if (tab.claudeSummary === claudeSummary) return;
4467
- tab.claudeSummary = claudeSummary;
4468
- layout.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4469
- await writeLayoutFile(layout, filePath);
4470
- });
4471
- };
4472
- updateTabLastUserMessage = async (sessionName, lastUserMessage) => {
4473
- const parsed = parseSessionName(sessionName);
4474
- if (!parsed) return;
4475
- await withLock2(async () => {
4476
- const filePath = resolveLayoutFile(parsed.wsId);
4477
- const layout = await readLayoutFile(filePath);
4478
- if (!layout) return;
4479
- const allTabs = collectAllTabs(layout.root);
4480
- const tab = allTabs.find((t) => t.sessionName === sessionName);
4481
- if (!tab) return;
4482
- if (tab.lastUserMessage === lastUserMessage) return;
4483
- tab.lastUserMessage = lastUserMessage;
4484
- layout.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4485
- await writeLayoutFile(layout, filePath);
4486
- });
4487
- };
4488
- updateTabCliStatus = async (sessionName, cliState, dismissedAt) => {
4474
+ mutateTab = async (sessionName, mutator) => {
4489
4475
  const parsed = parseSessionName(sessionName);
4490
4476
  if (!parsed) return;
4491
- await withLock2(async () => {
4477
+ await withLock(async () => {
4492
4478
  const filePath = resolveLayoutFile(parsed.wsId);
4493
4479
  const layout = await readLayoutFile(filePath);
4494
4480
  if (!layout) return;
4495
- const allTabs = collectAllTabs(layout.root);
4496
- const tab = allTabs.find((t) => t.sessionName === sessionName);
4481
+ const tab = collectAllTabs(layout.root).find((t) => t.sessionName === sessionName);
4497
4482
  if (!tab) return;
4498
- if (tab.cliState === cliState && tab.dismissedAt === dismissedAt) return;
4499
- tab.cliState = cliState;
4500
- tab.dismissedAt = dismissedAt;
4483
+ if (!mutator(tab)) return;
4501
4484
  layout.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4502
4485
  await writeLayoutFile(layout, filePath);
4503
4486
  });
4504
4487
  };
4488
+ updateTabAgentSessionId = (sessionName, provider, sessionId) => mutateTab(sessionName, (tab) => {
4489
+ if (provider.readSessionId(tab) === sessionId) return false;
4490
+ provider.writeSessionId(tab, sessionId);
4491
+ return true;
4492
+ });
4493
+ updateTabAgentSummary = (sessionName, provider, summary) => mutateTab(sessionName, (tab) => {
4494
+ if (provider.readSummary(tab) === summary) return false;
4495
+ provider.writeSummary(tab, summary);
4496
+ return true;
4497
+ });
4498
+ updateTabClaudeSummary = (sessionName, claudeSummary) => mutateTab(sessionName, (tab) => {
4499
+ if (tab.claudeSummary === claudeSummary) return false;
4500
+ tab.claudeSummary = claudeSummary;
4501
+ return true;
4502
+ });
4503
+ updateTabLastUserMessage = (sessionName, lastUserMessage) => mutateTab(sessionName, (tab) => {
4504
+ if (tab.lastUserMessage === lastUserMessage) return false;
4505
+ tab.lastUserMessage = lastUserMessage;
4506
+ return true;
4507
+ });
4508
+ updateTabCliStatus = (sessionName, cliState, dismissedAt) => mutateTab(sessionName, (tab) => {
4509
+ if (tab.cliState === cliState && tab.dismissedAt === dismissedAt) return false;
4510
+ tab.cliState = cliState;
4511
+ tab.dismissedAt = dismissedAt;
4512
+ return true;
4513
+ });
4505
4514
  }
4506
4515
  });
4507
4516
 
@@ -4556,6 +4565,16 @@ purplemux api-guide
4556
4565
  (long-running builds, different project context, parallel exploration).
4557
4566
  - Poll \`status\` and read \`result\` to verify delegated work.
4558
4567
  - Prefer small, scoped tabs over cramming everything into one session.
4568
+
4569
+ ### Tab type notes
4570
+
4571
+ - **\`web-browser\` tabs**: Electron webviews, not tmux. The \`alive\` field in
4572
+ \`tab list\` / \`tab status\` is always \`false\` for these \u2014 that is the normal
4573
+ value, not a sign the tab is dead. Do not gate actions on \`alive\`. Use the
4574
+ browser-specific HTTP endpoints (\`/browser/url\`, \`/browser/screenshot\`, \u2026;
4575
+ see \`purplemux api-guide\`) directly.
4576
+ - **\`terminal\` / \`claude-code\` tabs**: run inside tmux, so \`alive\` is a valid
4577
+ liveness signal.
4559
4578
  `;
4560
4579
  };
4561
4580
  writeClaudePromptFile = async (ws) => {
@@ -4583,7 +4602,7 @@ var init_workspace_order = __esm({
4583
4602
  "src/lib/workspace-order.ts"() {
4584
4603
  "use strict";
4585
4604
  getVisuallyOrderedWorkspaces = (workspaces, groups) => {
4586
- const validGroupIds = new Set(groups.map((g10) => g10.id));
4605
+ const validGroupIds = new Set(groups.map((g11) => g11.id));
4587
4606
  const byGroup = /* @__PURE__ */ new Map();
4588
4607
  const ungrouped = [];
4589
4608
  for (const ws of workspaces) {
@@ -4597,8 +4616,8 @@ var init_workspace_order = __esm({
4597
4616
  }
4598
4617
  }
4599
4618
  const ordered = [];
4600
- for (const g10 of groups) {
4601
- const list = byGroup.get(g10.id);
4619
+ for (const g11 of groups) {
4620
+ const list = byGroup.get(g11.id);
4602
4621
  if (list) ordered.push(...list);
4603
4622
  }
4604
4623
  ordered.push(...ungrouped);
@@ -4662,10 +4681,10 @@ var init_workspace_store = __esm({
4662
4681
  delete legacy.order;
4663
4682
  }
4664
4683
  if (!Array.isArray(data.groups)) data.groups = [];
4665
- for (const g10 of data.groups) {
4666
- delete g10.order;
4684
+ for (const g11 of data.groups) {
4685
+ delete g11.order;
4667
4686
  }
4668
- const validGroupIds = new Set(data.groups.map((g10) => g10.id));
4687
+ const validGroupIds = new Set(data.groups.map((g11) => g11.id));
4669
4688
  for (const ws of data.workspaces) {
4670
4689
  if (ws.groupId && !validGroupIds.has(ws.groupId)) {
4671
4690
  ws.groupId = null;
@@ -6942,11 +6961,11 @@ var require_bn = __commonJS({
6942
6961
  var B = new BN(0);
6943
6962
  var C = new BN(0);
6944
6963
  var D = new BN(1);
6945
- var g10 = 0;
6964
+ var g11 = 0;
6946
6965
  while (x.isEven() && y.isEven()) {
6947
6966
  x.iushrn(1);
6948
6967
  y.iushrn(1);
6949
- ++g10;
6968
+ ++g11;
6950
6969
  }
6951
6970
  var yp = y.clone();
6952
6971
  var xp = x.clone();
@@ -6988,7 +7007,7 @@ var require_bn = __commonJS({
6988
7007
  return {
6989
7008
  a: C,
6990
7009
  b: D,
6991
- gcd: y.iushln(g10)
7010
+ gcd: y.iushln(g11)
6992
7011
  };
6993
7012
  };
6994
7013
  BN.prototype._invmp = function _invmp(p) {
@@ -13478,8 +13497,9 @@ var encodeStdout = (data) => {
13478
13497
  };
13479
13498
 
13480
13499
  // src/lib/terminal-server.ts
13500
+ init_layout_store();
13481
13501
  init_logger();
13482
- var log2 = createLogger("terminal");
13502
+ var log4 = createLogger("terminal");
13483
13503
  var MSG_STDIN2 = 0;
13484
13504
  var MSG_RESIZE2 = 2;
13485
13505
  var MSG_HEARTBEAT = 3;
@@ -13622,7 +13642,7 @@ var handleConnection = async (ws, request, sessionId) => {
13622
13642
  if (clientId) {
13623
13643
  connections.forEach((conn2) => {
13624
13644
  if (conn2.clientId === clientId && !conn2.cleaned) {
13625
- log2.debug(`replacing existing connection for clientId: ${clientId}`);
13645
+ log4.debug(`replacing existing connection for clientId: ${clientId}`);
13626
13646
  conn2.detaching = true;
13627
13647
  cleanup(conn2);
13628
13648
  }
@@ -13633,7 +13653,7 @@ var handleConnection = async (ws, request, sessionId) => {
13633
13653
  let evicted = 0;
13634
13654
  for (const [oldWs, oldConn] of connections) {
13635
13655
  if (evicted >= toEvict) break;
13636
- log2.debug(`evicting stale connection for session: ${oldConn.sessionName}`);
13656
+ log4.debug(`evicting stale connection for session: ${oldConn.sessionName}`);
13637
13657
  oldConn.detaching = true;
13638
13658
  cleanup(oldConn);
13639
13659
  if (oldWs.readyState === import_websocket.default.OPEN || oldWs.readyState === import_websocket.default.CONNECTING) {
@@ -13643,7 +13663,7 @@ var handleConnection = async (ws, request, sessionId) => {
13643
13663
  }
13644
13664
  }
13645
13665
  if (connections.size >= MAX_CONNECTIONS) {
13646
- log2.warn(`connection rejected: max connections (${MAX_CONNECTIONS}) reached`);
13666
+ log4.warn(`connection rejected: max connections (${MAX_CONNECTIONS}) reached`);
13647
13667
  ws.close(1013, "Max connections exceeded");
13648
13668
  return;
13649
13669
  }
@@ -13712,9 +13732,9 @@ var handleConnection = async (ws, request, sessionId) => {
13712
13732
  break;
13713
13733
  }
13714
13734
  case MSG_KILL_SESSION: {
13715
- log2.debug(`kill session requested: ${sessionName}`);
13735
+ log4.debug(`kill session requested: ${sessionName}`);
13716
13736
  killSession(sessionName).catch((err) => {
13717
- log2.error(`kill session failed: ${err instanceof Error ? err.message : err}`);
13737
+ log4.error(`kill session failed: ${err instanceof Error ? err.message : err}`);
13718
13738
  });
13719
13739
  break;
13720
13740
  }
@@ -13727,7 +13747,7 @@ var handleConnection = async (ws, request, sessionId) => {
13727
13747
  cleanup(conn);
13728
13748
  });
13729
13749
  ws.on("error", (err) => {
13730
- log2.error(`websocket error: ${err.message}`);
13750
+ log4.error(`websocket error: ${err.message}`);
13731
13751
  if (!conn) return;
13732
13752
  conn.detaching = true;
13733
13753
  cleanup(conn);
@@ -13736,7 +13756,10 @@ var handleConnection = async (ws, request, sessionId) => {
13736
13756
  sessionName = sessionId;
13737
13757
  const exists = await hasSession(sessionId);
13738
13758
  if (!exists) {
13739
- log2.warn(`session not found: ${sessionName}`);
13759
+ log4.warn(`session not found: ${sessionName}`);
13760
+ await reconcileTabCwd(sessionName).catch((err) => {
13761
+ log4.warn(`reconcile cwd failed: ${err instanceof Error ? err.message : err}`);
13762
+ });
13740
13763
  ws.close(1011, "Session not found");
13741
13764
  return;
13742
13765
  }
@@ -13746,7 +13769,7 @@ var handleConnection = async (ws, request, sessionId) => {
13746
13769
  try {
13747
13770
  ptyProcess = attachToSession(sessionName, currentCols, currentRows);
13748
13771
  } catch (err) {
13749
- log2.error(`tmux attach failed: ${err instanceof Error ? err.message : err}`);
13772
+ log4.error(`tmux attach failed: ${err instanceof Error ? err.message : err}`);
13750
13773
  ws.close(1011, "Session attach failed");
13751
13774
  return;
13752
13775
  }
@@ -13759,7 +13782,7 @@ var handleConnection = async (ws, request, sessionId) => {
13759
13782
  if (ws.readyState !== import_websocket.default.OPEN) return;
13760
13783
  ptyProcess = attachToSession(sessionName, currentCols, currentRows);
13761
13784
  } catch (err) {
13762
- log2.error(`tmux session creation failed: ${err instanceof Error ? err.message : err}`);
13785
+ log4.error(`tmux session creation failed: ${err instanceof Error ? err.message : err}`);
13763
13786
  ws.close(1011, "Session create failed");
13764
13787
  return;
13765
13788
  }
@@ -13819,7 +13842,7 @@ var handleConnection = async (ws, request, sessionId) => {
13819
13842
  if (newEnd <= conn.throttleUntil) return;
13820
13843
  conn.throttleUntil = newEnd;
13821
13844
  if (!wasActive) {
13822
- log2.debug(`[throttle] window started ${THROTTLE_WINDOW_MS}ms reason=${reason} session=${sessionName} pid=${ptyPid}`);
13845
+ log4.debug(`[throttle] window started ${THROTTLE_WINDOW_MS}ms reason=${reason} session=${sessionName} pid=${ptyPid}`);
13823
13846
  }
13824
13847
  if (conn.throttleInterval) return;
13825
13848
  conn.throttleInterval = setInterval(() => {
@@ -13827,7 +13850,7 @@ var handleConnection = async (ws, request, sessionId) => {
13827
13850
  if (Date.now() < conn.throttleUntil) return;
13828
13851
  clearInterval(conn.throttleInterval);
13829
13852
  conn.throttleInterval = null;
13830
- log2.debug(`[throttle] window ended session=${sessionName} pid=${ptyPid}`);
13853
+ log4.debug(`[throttle] window ended session=${sessionName} pid=${ptyPid}`);
13831
13854
  }, THROTTLE_FLUSH_INTERVAL_MS);
13832
13855
  };
13833
13856
  startThrottleWindow("initial");
@@ -13846,7 +13869,7 @@ var handleConnection = async (ws, request, sessionId) => {
13846
13869
  conn.disposables.push(
13847
13870
  ptyProcess.onExit(({ exitCode, signal }) => {
13848
13871
  if (conn.cleaned) return;
13849
- log2.debug(
13872
+ log4.debug(
13850
13873
  `pty exited (pid: ${ptyProcess.pid}, code: ${exitCode}, signal: ${signal}, detaching: ${conn.detaching})`
13851
13874
  );
13852
13875
  cleanup(conn, !conn.detaching);
@@ -13857,27 +13880,27 @@ var handleConnection = async (ws, request, sessionId) => {
13857
13880
  // src/lib/install-server.ts
13858
13881
  init_wrapper();
13859
13882
  var pty2 = __toESM(require("node-pty"));
13860
- var import_os3 = __toESM(require("os"));
13883
+ var import_os4 = __toESM(require("os"));
13861
13884
 
13862
13885
  // src/lib/config-store.ts
13863
- var import_promises2 = __toESM(require("fs/promises"));
13864
- var import_path3 = __toESM(require("path"));
13865
- var import_os2 = __toESM(require("os"));
13886
+ var import_promises3 = __toESM(require("fs/promises"));
13887
+ var import_path4 = __toESM(require("path"));
13888
+ var import_os3 = __toESM(require("os"));
13866
13889
  var import_crypto = __toESM(require("crypto"));
13867
13890
  init_sync_server();
13868
13891
  init_logger();
13869
- var log4 = createLogger("config");
13870
- var BASE_DIR = import_path3.default.join(import_os2.default.homedir(), ".purplemux");
13871
- var CONFIG_FILE = import_path3.default.join(BASE_DIR, "config.json");
13872
- var g3 = globalThis;
13873
- if (!g3.__ptConfigLock) g3.__ptConfigLock = Promise.resolve();
13874
- var withLock = async (fn) => {
13892
+ var log5 = createLogger("config");
13893
+ var BASE_DIR2 = import_path4.default.join(import_os3.default.homedir(), ".purplemux");
13894
+ var CONFIG_FILE = import_path4.default.join(BASE_DIR2, "config.json");
13895
+ var g4 = globalThis;
13896
+ if (!g4.__ptConfigLock) g4.__ptConfigLock = Promise.resolve();
13897
+ var withLock2 = async (fn) => {
13875
13898
  let release;
13876
13899
  const next2 = new Promise((r) => {
13877
13900
  release = r;
13878
13901
  });
13879
- const prev = g3.__ptConfigLock;
13880
- g3.__ptConfigLock = next2;
13902
+ const prev = g4.__ptConfigLock;
13903
+ g4.__ptConfigLock = next2;
13881
13904
  await prev;
13882
13905
  try {
13883
13906
  return await fn();
@@ -13890,7 +13913,7 @@ var emptyConfig = () => ({
13890
13913
  });
13891
13914
  var readConfig = async () => {
13892
13915
  try {
13893
- const raw = await import_promises2.default.readFile(CONFIG_FILE, "utf-8");
13916
+ const raw = await import_promises3.default.readFile(CONFIG_FILE, "utf-8");
13894
13917
  return JSON.parse(raw);
13895
13918
  } catch {
13896
13919
  return null;
@@ -13899,18 +13922,18 @@ var readConfig = async () => {
13899
13922
  var writeConfig = async (data) => {
13900
13923
  const { updatedAt: _, ...rest } = data;
13901
13924
  const contentKey = JSON.stringify(rest);
13902
- if (g3.__ptConfigContentCache === contentKey) return;
13925
+ if (g4.__ptConfigContentCache === contentKey) return;
13903
13926
  data.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
13904
13927
  const tmpFile = CONFIG_FILE + ".tmp";
13905
13928
  try {
13906
- await import_promises2.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
13907
- await import_promises2.default.rename(tmpFile, CONFIG_FILE);
13929
+ await import_promises3.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
13930
+ await import_promises3.default.rename(tmpFile, CONFIG_FILE);
13908
13931
  } catch (err) {
13909
- await import_promises2.default.unlink(tmpFile).catch(() => {
13932
+ await import_promises3.default.unlink(tmpFile).catch(() => {
13910
13933
  });
13911
13934
  throw err;
13912
13935
  }
13913
- g3.__ptConfigContentCache = contentKey;
13936
+ g4.__ptConfigContentCache = contentKey;
13914
13937
  broadcastSync({ type: "config" });
13915
13938
  };
13916
13939
  var SCRYPT_KEYLEN = 64;
@@ -13932,7 +13955,7 @@ var getConfig = async () => {
13932
13955
  const data = await readConfig();
13933
13956
  return data ?? emptyConfig();
13934
13957
  };
13935
- var updateConfig = async (updates) => withLock(async () => {
13958
+ var updateConfig = async (updates) => withLock2(async () => {
13936
13959
  const data = await readConfig() ?? emptyConfig();
13937
13960
  Object.assign(data, updates);
13938
13961
  await writeConfig(data);
@@ -13942,14 +13965,14 @@ var needsSetup = async () => {
13942
13965
  return !isHashedPassword(data?.authPassword);
13943
13966
  };
13944
13967
  var initConfigStore = async () => {
13945
- await import_promises2.default.mkdir(BASE_DIR, { recursive: true });
13968
+ await import_promises3.default.mkdir(BASE_DIR2, { recursive: true });
13946
13969
  const existing = await readConfig();
13947
13970
  if (existing) {
13948
- log4.debug("config.json loaded");
13971
+ log5.debug("config.json loaded");
13949
13972
  return;
13950
13973
  }
13951
13974
  await writeConfig(emptyConfig());
13952
- log4.info("Initial config.json created (onboarding required)");
13975
+ log5.info("Initial config.json created (onboarding required)");
13953
13976
  };
13954
13977
  var getDangerouslySkipPermissions = async () => {
13955
13978
  const data = await readConfig();
@@ -13961,7 +13984,7 @@ var generateSecret = () => import_crypto.default.randomBytes(32).toString("hex")
13961
13984
  init_shell_env();
13962
13985
  init_pristine_env();
13963
13986
  init_logger();
13964
- var log5 = createLogger("install");
13987
+ var log6 = createLogger("install");
13965
13988
  var RUNTIME_INSTALL_COMMANDS = /* @__PURE__ */ new Set([
13966
13989
  "tmux-install",
13967
13990
  "tmux-upgrade",
@@ -14028,7 +14051,7 @@ var handleInstallConnection = async (ws, request) => {
14028
14051
  if (activeConn) {
14029
14052
  cleanup2();
14030
14053
  }
14031
- const shell = import_os3.default.userInfo().shell || PRISTINE_ENV.SHELL || (process.platform === "darwin" ? "/bin/zsh" : "/bin/bash");
14054
+ const shell = import_os4.default.userInfo().shell || PRISTINE_ENV.SHELL || (process.platform === "darwin" ? "/bin/zsh" : "/bin/bash");
14032
14055
  const cols = parseInt(url2.searchParams.get("cols") || "", 10) || 80;
14033
14056
  const rows = parseInt(url2.searchParams.get("rows") || "", 10) || 24;
14034
14057
  let ptyProcess;
@@ -14044,12 +14067,12 @@ var handleInstallConnection = async (ws, request) => {
14044
14067
  }
14045
14068
  });
14046
14069
  } catch (err) {
14047
- log5.error(`pty spawn failed: ${err instanceof Error ? err.message : err}`);
14070
+ log6.error(`pty spawn failed: ${err instanceof Error ? err.message : err}`);
14048
14071
  ws.close(1011, "PTY spawn failed");
14049
14072
  return;
14050
14073
  }
14051
14074
  activeConn = { ws, pty: ptyProcess };
14052
- log5.info(`install session started: ${command} (pid: ${ptyProcess.pid})`);
14075
+ log6.info(`install session started: ${command} (pid: ${ptyProcess.pid})`);
14053
14076
  const disposables = [];
14054
14077
  disposables.push(
14055
14078
  ptyProcess.onData((data) => {
@@ -14059,7 +14082,7 @@ var handleInstallConnection = async (ws, request) => {
14059
14082
  );
14060
14083
  disposables.push(
14061
14084
  ptyProcess.onExit(() => {
14062
- log5.info(`install pty exited: ${command}`);
14085
+ log6.info(`install pty exited: ${command}`);
14063
14086
  disposeAll(disposables);
14064
14087
  if (ws.readyState === import_websocket.default.OPEN) {
14065
14088
  ws.close(1e3, "Process exited");
@@ -14118,335 +14141,8 @@ init_wrapper();
14118
14141
  var import_fs5 = require("fs");
14119
14142
  var import_fs6 = require("fs");
14120
14143
 
14121
- // src/lib/session-detection.ts
14122
- var import_promises3 = __toESM(require("fs/promises"));
14123
- var import_fs = require("fs");
14124
- var import_path5 = __toESM(require("path"));
14125
- var import_os5 = __toESM(require("os"));
14126
- var import_child_process3 = require("child_process");
14127
- var import_util3 = require("util");
14128
-
14129
- // src/lib/preflight.ts
14130
- var import_child_process2 = require("child_process");
14131
- var import_os4 = __toESM(require("os"));
14132
- var import_path4 = __toESM(require("path"));
14133
- var import_util2 = require("util");
14134
- init_shell_env();
14135
- init_pristine_env();
14136
- var execFile2 = (0, import_util2.promisify)(import_child_process2.execFile);
14137
- var CMD_TIMEOUT2 = 5e3;
14138
- var shellPathCache = null;
14139
- var shellPathPromise = null;
14140
- var defaultShell2 = () => import_os4.default.userInfo().shell || defaultShell();
14141
- var resolveShellPathAsync = async () => {
14142
- const shell = defaultShell2();
14143
- try {
14144
- const { stdout } = await execFile2(shell, ["-ilc", 'echo -n "$PATH"'], {
14145
- timeout: CMD_TIMEOUT2,
14146
- env: {
14147
- ...buildShellEnv(),
14148
- SHELL: shell,
14149
- DISABLE_AUTO_UPDATE: "true",
14150
- ZSH_TMUX_AUTOSTARTED: "true"
14151
- }
14152
- });
14153
- return stdout.toString().trim();
14154
- } catch {
14155
- return PRISTINE_ENV.PATH || "";
14156
- }
14157
- };
14158
- var initShellPath = async () => {
14159
- shellPathCache = await resolveShellPathAsync();
14160
- };
14161
- var getShellPath = async () => {
14162
- if (shellPathCache) return shellPathCache;
14163
- if (!shellPathPromise) {
14164
- shellPathPromise = resolveShellPathAsync().then((result) => {
14165
- shellPathCache = result;
14166
- shellPathPromise = null;
14167
- return result;
14168
- });
14169
- }
14170
- return shellPathPromise;
14171
- };
14172
- var CLAUDE_KNOWN_DIRS = [import_path4.default.join(import_os4.default.homedir(), ".local", "bin")];
14173
-
14174
- // src/lib/session-detection.ts
14175
- init_platform();
14176
- var execFile3 = (0, import_util3.promisify)(import_child_process3.execFile);
14177
- var CLAUDE_DIR = import_path5.default.join(import_os5.default.homedir(), ".claude");
14178
- var SESSIONS_DIR = import_path5.default.join(CLAUDE_DIR, "sessions");
14179
- var PROJECTS_DIR = import_path5.default.join(CLAUDE_DIR, "projects");
14180
- var CLAUDE_KNOWN_PATHS = [import_path5.default.join(import_os5.default.homedir(), ".local", "bin", "claude")];
14181
- var PID_POLL_INTERVAL = 1e4;
14182
- var SESSION_DIR_DEBOUNCE = 200;
14183
- var INSTALL_CHECK_INTERVAL = 6e4;
14184
- var MAX_SANITIZED_LENGTH = 200;
14185
- var toClaudeProjectName = (dirPath) => {
14186
- const sanitized = dirPath.replace(/[^a-zA-Z0-9]/g, "-");
14187
- if (sanitized.length <= MAX_SANITIZED_LENGTH) {
14188
- return sanitized;
14189
- }
14190
- const hash2 = simpleHash(dirPath);
14191
- return `${sanitized.slice(0, MAX_SANITIZED_LENGTH)}-${hash2}`;
14192
- };
14193
- var simpleHash = (str) => {
14194
- let hash2 = 0;
14195
- for (let i = 0; i < str.length; i++) {
14196
- hash2 = (hash2 << 5) - hash2 + str.charCodeAt(i) | 0;
14197
- }
14198
- return Math.abs(hash2).toString(36);
14199
- };
14200
- var isProcessRunning = (pid) => new Promise((resolve) => {
14201
- (0, import_child_process3.execFile)("ps", ["-p", String(pid)], (err) => {
14202
- resolve(!err);
14203
- });
14204
- });
14205
- var getChildPids = async (parentPid) => {
14206
- try {
14207
- const { stdout } = await execFile3("pgrep", ["-P", String(parentPid)]);
14208
- return stdout.trim().split("\n").map((s) => parseInt(s, 10)).filter((n) => !Number.isNaN(n));
14209
- } catch {
14210
- return [];
14211
- }
14212
- };
14213
- var getProcessCwd = async (pid) => {
14214
- if (isLinux) {
14215
- try {
14216
- return await import_promises3.default.readlink(`/proc/${pid}/cwd`);
14217
- } catch {
14218
- return null;
14219
- }
14220
- }
14221
- try {
14222
- const { stdout } = await execFile3("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"]);
14223
- const line = stdout.split("\n").find((l) => l.startsWith("n/"));
14224
- return line ? line.slice(1) : null;
14225
- } catch {
14226
- return null;
14227
- }
14228
- };
14229
- var getClaudeSessionFromArgs = async (childPids) => {
14230
- for (const pid of childPids) {
14231
- try {
14232
- const { stdout } = await execFile3("ps", ["-p", String(pid), "-o", "args="]);
14233
- const args = stdout.trim();
14234
- const match = args.match(/claude\s+--resume\s+([0-9a-f-]{36})/);
14235
- if (match) {
14236
- const cwd = await getProcessCwd(pid);
14237
- return { pid, sessionId: match[1], cwd };
14238
- }
14239
- } catch {
14240
- continue;
14241
- }
14242
- }
14243
- return null;
14244
- };
14245
- var readPidFile = async (filePath) => {
14246
- try {
14247
- const raw = await import_promises3.default.readFile(filePath, "utf-8");
14248
- const data = JSON.parse(raw);
14249
- if (!data.pid || !data.sessionId) return null;
14250
- return data;
14251
- } catch {
14252
- return null;
14253
- }
14254
- };
14255
- var findJsonlPath = async (projectDir, sessionId) => {
14256
- const jsonlPath = import_path5.default.join(projectDir, `${sessionId}.jsonl`);
14257
- try {
14258
- await import_promises3.default.access(jsonlPath);
14259
- return jsonlPath;
14260
- } catch {
14261
- return null;
14262
- }
14263
- };
14264
- var isClaudeInstalled = async () => {
14265
- try {
14266
- await execFile3("claude", ["--version"], { timeout: 5e3, env: { ...process.env, PATH: await getShellPath() } });
14267
- return true;
14268
- } catch {
14269
- for (const p of CLAUDE_KNOWN_PATHS) {
14270
- try {
14271
- await import_promises3.default.access(p);
14272
- return true;
14273
- } catch {
14274
- }
14275
- }
14276
- return false;
14277
- }
14278
- };
14279
- var isClaudeRunning = async (panePid, preloadedChildPids) => {
14280
- const childPids = preloadedChildPids ?? await getChildPids(panePid);
14281
- for (const pid of childPids) {
14282
- try {
14283
- const { stdout } = await execFile3("ps", ["-p", String(pid), "-o", "args="]);
14284
- if (stdout.trim().includes("claude")) return true;
14285
- } catch {
14286
- continue;
14287
- }
14288
- }
14289
- return false;
14290
- };
14291
- var detectActiveSession = async (panePid, preloadedChildPids) => {
14292
- try {
14293
- await import_promises3.default.access(CLAUDE_DIR);
14294
- } catch {
14295
- const installed = await isClaudeInstalled();
14296
- const status = installed ? "not-initialized" : "not-installed";
14297
- return { status, sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
14298
- }
14299
- const directChildPids = preloadedChildPids ?? await getChildPids(panePid);
14300
- if (directChildPids.length === 0) {
14301
- return { status: "not-running", sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
14302
- }
14303
- const grandchildPids = (await Promise.all(directChildPids.map(getChildPids))).flat();
14304
- const allPids = [...directChildPids, ...grandchildPids];
14305
- const childPidSet = new Set(allPids);
14306
- try {
14307
- const pidFiles = await import_promises3.default.readdir(SESSIONS_DIR);
14308
- const jsonFiles = pidFiles.filter((f) => f.endsWith(".json"));
14309
- for (const file2 of jsonFiles) {
14310
- const data = await readPidFile(import_path5.default.join(SESSIONS_DIR, file2));
14311
- if (!data) continue;
14312
- if (!childPidSet.has(data.pid)) continue;
14313
- let processArgs = "";
14314
- try {
14315
- const { stdout } = await execFile3("ps", ["-p", String(data.pid), "-o", "args="]);
14316
- processArgs = stdout.trim();
14317
- } catch {
14318
- try {
14319
- await import_promises3.default.unlink(import_path5.default.join(SESSIONS_DIR, file2));
14320
- } catch {
14321
- }
14322
- continue;
14323
- }
14324
- if (!processArgs.includes("claude")) {
14325
- try {
14326
- await import_promises3.default.unlink(import_path5.default.join(SESSIONS_DIR, file2));
14327
- } catch {
14328
- }
14329
- continue;
14330
- }
14331
- const projectName = toClaudeProjectName(data.cwd);
14332
- const projectDir = import_path5.default.join(PROJECTS_DIR, projectName);
14333
- let jsonlPath = await findJsonlPath(projectDir, data.sessionId);
14334
- let effectiveSessionId = data.sessionId;
14335
- if (!jsonlPath) {
14336
- const resumeMatch = processArgs.match(/--resume\s+([0-9a-f-]{36})/);
14337
- if (resumeMatch) {
14338
- const resumeSessionId = resumeMatch[1];
14339
- const resumeJsonlPath = await findJsonlPath(projectDir, resumeSessionId);
14340
- if (resumeJsonlPath) {
14341
- jsonlPath = resumeJsonlPath;
14342
- effectiveSessionId = resumeSessionId;
14343
- }
14344
- }
14345
- }
14346
- return {
14347
- status: "running",
14348
- sessionId: effectiveSessionId,
14349
- jsonlPath,
14350
- pid: data.pid,
14351
- startedAt: data.startedAt,
14352
- cwd: data.cwd
14353
- };
14354
- }
14355
- } catch {
14356
- }
14357
- const fromArgs = await getClaudeSessionFromArgs(allPids);
14358
- if (fromArgs) {
14359
- const cwd = fromArgs.cwd;
14360
- if (cwd) {
14361
- const projectName = toClaudeProjectName(cwd);
14362
- const projectDir = import_path5.default.join(PROJECTS_DIR, projectName);
14363
- const jsonlPath = await findJsonlPath(projectDir, fromArgs.sessionId);
14364
- return {
14365
- status: "running",
14366
- sessionId: fromArgs.sessionId,
14367
- jsonlPath,
14368
- pid: fromArgs.pid,
14369
- startedAt: null,
14370
- cwd
14371
- };
14372
- }
14373
- }
14374
- return { status: "not-running", sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
14375
- };
14376
- var watchSessionsDir = (panePid, onChange, options) => {
14377
- let watcher = null;
14378
- let pidPollTimer = null;
14379
- let debounceTimer = null;
14380
- let installCheckTimer = null;
14381
- let currentPid = null;
14382
- let stopped = false;
14383
- const pollPid = async () => {
14384
- if (stopped || !currentPid) return;
14385
- const running = await isProcessRunning(currentPid);
14386
- if (!running && !stopped) {
14387
- currentPid = null;
14388
- const info = await detectActiveSession(panePid);
14389
- onChange(info);
14390
- }
14391
- };
14392
- const handleSessionDirChange = () => {
14393
- if (stopped) return;
14394
- if (debounceTimer) clearTimeout(debounceTimer);
14395
- debounceTimer = setTimeout(async () => {
14396
- if (stopped) return;
14397
- const info = await detectActiveSession(panePid);
14398
- if (info.pid) currentPid = info.pid;
14399
- onChange(info);
14400
- }, SESSION_DIR_DEBOUNCE);
14401
- };
14402
- const tryWatch = () => {
14403
- if (stopped) return;
14404
- try {
14405
- watcher = (0, import_fs.watch)(SESSIONS_DIR, handleSessionDirChange);
14406
- watcher.on("error", () => {
14407
- });
14408
- if (installCheckTimer) {
14409
- clearInterval(installCheckTimer);
14410
- installCheckTimer = null;
14411
- }
14412
- } catch {
14413
- if (!installCheckTimer) {
14414
- installCheckTimer = setInterval(async () => {
14415
- if (stopped) return;
14416
- try {
14417
- await import_promises3.default.access(SESSIONS_DIR);
14418
- tryWatch();
14419
- const info = await detectActiveSession(panePid);
14420
- if (info.pid) currentPid = info.pid;
14421
- onChange(info);
14422
- } catch {
14423
- }
14424
- }, INSTALL_CHECK_INTERVAL);
14425
- }
14426
- }
14427
- };
14428
- tryWatch();
14429
- pidPollTimer = setInterval(pollPid, PID_POLL_INTERVAL);
14430
- if (!options?.skipInitial) {
14431
- detectActiveSession(panePid).then((info) => {
14432
- if (stopped) return;
14433
- if (info.pid) currentPid = info.pid;
14434
- onChange(info);
14435
- });
14436
- }
14437
- return {
14438
- stop: () => {
14439
- stopped = true;
14440
- if (watcher) watcher.close();
14441
- if (pidPollTimer) clearInterval(pidPollTimer);
14442
- if (debounceTimer) clearTimeout(debounceTimer);
14443
- if (installCheckTimer) clearInterval(installCheckTimer);
14444
- }
14445
- };
14446
- };
14447
-
14448
- // src/lib/session-parser.ts
14449
- var import_promises4 = __toESM(require("fs/promises"));
14144
+ // src/lib/session-parser.ts
14145
+ var import_promises4 = __toESM(require("fs/promises"));
14450
14146
 
14451
14147
  // node_modules/zod/v4/classic/external.js
14452
14148
  var external_exports = {};
@@ -29318,125 +29014,655 @@ var import_readline = require("readline");
29318
29014
  init_tmux();
29319
29015
 
29320
29016
  // src/lib/session-list.ts
29017
+ var import_path7 = __toESM(require("path"));
29018
+
29019
+ // src/lib/session-detection.ts
29020
+ var import_promises5 = __toESM(require("fs/promises"));
29021
+ var import_fs = require("fs");
29321
29022
  var import_path6 = __toESM(require("path"));
29322
- init_tmux();
29323
- init_logger();
29023
+ var import_os6 = __toESM(require("os"));
29024
+ var import_child_process3 = require("child_process");
29025
+ var import_util5 = require("util");
29324
29026
 
29325
- // src/lib/session-meta-cache.ts
29326
- var CACHE_TTL = 3e4;
29327
- var createMetaCache = () => {
29328
- const store = /* @__PURE__ */ new Map();
29329
- const get = (sessionId) => {
29330
- const entry = store.get(sessionId);
29331
- if (!entry) return void 0;
29332
- if (Date.now() - entry.cachedAt > CACHE_TTL) {
29333
- store.delete(sessionId);
29334
- return void 0;
29335
- }
29336
- return entry.meta;
29337
- };
29338
- const set2 = (sessionId, meta3, mtime) => {
29339
- store.set(sessionId, { meta: meta3, mtime, cachedAt: Date.now() });
29340
- };
29341
- const isStale = (sessionId, currentMtime) => {
29342
- const entry = store.get(sessionId);
29343
- if (!entry) return true;
29344
- if (Date.now() - entry.cachedAt > CACHE_TTL) {
29345
- store.delete(sessionId);
29346
- return true;
29347
- }
29348
- return entry.mtime !== currentMtime;
29349
- };
29350
- const clear = () => {
29351
- store.clear();
29352
- };
29353
- return { get, set: set2, isStale, clear };
29027
+ // src/lib/preflight.ts
29028
+ var import_child_process2 = require("child_process");
29029
+ var import_os5 = __toESM(require("os"));
29030
+ var import_path5 = __toESM(require("path"));
29031
+ var import_util4 = require("util");
29032
+ init_shell_env();
29033
+ init_pristine_env();
29034
+ var execFile2 = (0, import_util4.promisify)(import_child_process2.execFile);
29035
+ var CMD_TIMEOUT2 = 5e3;
29036
+ var shellPathCache = null;
29037
+ var shellPathPromise = null;
29038
+ var defaultShell2 = () => import_os5.default.userInfo().shell || defaultShell();
29039
+ var resolveShellPathAsync = async () => {
29040
+ const shell = defaultShell2();
29041
+ try {
29042
+ const { stdout } = await execFile2(shell, ["-ilc", 'echo -n "$PATH"'], {
29043
+ timeout: CMD_TIMEOUT2,
29044
+ env: {
29045
+ ...buildShellEnv(),
29046
+ SHELL: shell,
29047
+ DISABLE_AUTO_UPDATE: "true",
29048
+ ZSH_TMUX_AUTOSTARTED: "true"
29049
+ }
29050
+ });
29051
+ return stdout.toString().trim();
29052
+ } catch {
29053
+ return PRISTINE_ENV.PATH || "";
29054
+ }
29354
29055
  };
29355
-
29356
- // src/lib/session-list.ts
29357
- var log6 = createLogger("session-list");
29358
- var PROJECTS_DIR2 = import_path6.default.join(
29359
- process.env.HOME || process.env.USERPROFILE || "/",
29360
- ".claude",
29361
- "projects"
29362
- );
29363
- var metaCache = createMetaCache();
29364
- var cwdToProjectPath = (cwd) => {
29365
- const projectName = toClaudeProjectName(cwd);
29366
- return import_path6.default.join(PROJECTS_DIR2, projectName);
29056
+ var initShellPath = async () => {
29057
+ shellPathCache = await resolveShellPathAsync();
29367
29058
  };
29059
+ var getShellPath = async () => {
29060
+ if (shellPathCache) return shellPathCache;
29061
+ if (!shellPathPromise) {
29062
+ shellPathPromise = resolveShellPathAsync().then((result) => {
29063
+ shellPathCache = result;
29064
+ shellPathPromise = null;
29065
+ return result;
29066
+ });
29067
+ }
29068
+ return shellPathPromise;
29069
+ };
29070
+ var CLAUDE_KNOWN_DIRS = [import_path5.default.join(import_os5.default.homedir(), ".local", "bin")];
29368
29071
 
29369
- // src/lib/timeline-server.ts
29370
- init_layout_store();
29371
-
29372
- // src/lib/status-manager.ts
29373
- init_wrapper();
29374
- init_workspace_store();
29375
- init_layout_store();
29376
- init_tmux();
29377
- init_tab_title();
29378
-
29379
- // src/lib/rate-limits-watcher.ts
29380
- var import_fs2 = __toESM(require("fs"));
29381
- var import_promises8 = __toESM(require("fs/promises"));
29382
- var import_path11 = __toESM(require("path"));
29383
- init_logger();
29384
-
29385
- // src/lib/statusline-script.ts
29386
- var import_path10 = __toESM(require("path"));
29387
- var import_os8 = __toESM(require("os"));
29388
- var BASE_DIR4 = import_path10.default.join(import_os8.default.homedir(), ".purplemux");
29389
- var STATUSLINE_SCRIPT_PATH = import_path10.default.join(BASE_DIR4, "statusline.sh");
29390
- var RATE_LIMITS_FILE = import_path10.default.join(BASE_DIR4, "rate-limits.json");
29391
- var STATUSLINE_SCRIPT_CONTENT = `#!/bin/sh
29392
- PORT_FILE="$HOME/.purplemux/port"
29393
- TOKEN_FILE="$HOME/.purplemux/cli-token"
29394
- [ -f "$PORT_FILE" ] || exit 0
29395
- [ -f "$TOKEN_FILE" ] || exit 0
29396
- PORT=$(cat "$PORT_FILE")
29397
- TOKEN=$(cat "$TOKEN_FILE")
29398
- curl -sf --max-time 2 -X POST \\
29399
- -H 'Content-Type: application/json' \\
29400
- -H "x-pmux-token: \${TOKEN}" \\
29401
- --data-binary @- \\
29402
- "http://localhost:\${PORT}/api/status/statusline" 2>/dev/null || exit 0
29403
- `;
29404
-
29405
- // src/lib/rate-limits-watcher.ts
29406
- var log10 = createLogger("rate-limits");
29407
- var DEBOUNCE_MS = 500;
29408
- var WATCH_DIR = import_path11.default.dirname(RATE_LIMITS_FILE);
29409
- var WATCH_FILENAME = import_path11.default.basename(RATE_LIMITS_FILE);
29410
- var createRateLimitsWatcher = (onChange) => {
29411
- let watcher = null;
29412
- let debounceTimer = null;
29413
- let lastTs = 0;
29414
- const readAndNotify = async () => {
29415
- try {
29416
- const raw = await import_promises8.default.readFile(RATE_LIMITS_FILE, "utf-8");
29417
- const data = JSON.parse(raw);
29418
- if (data.ts && data.ts !== lastTs) {
29419
- lastTs = data.ts;
29420
- onChange(data);
29421
- }
29422
- } catch {
29423
- }
29424
- };
29425
- const start2 = () => {
29426
- readAndNotify();
29427
- try {
29428
- watcher = import_fs2.default.watch(WATCH_DIR, (_eventType, filename) => {
29429
- if (filename !== WATCH_FILENAME) return;
29430
- if (debounceTimer) clearTimeout(debounceTimer);
29431
- debounceTimer = setTimeout(readAndNotify, DEBOUNCE_MS);
29432
- });
29433
- watcher.on("error", () => {
29434
- log10.debug(`${WATCH_DIR} watch error, retrying...`);
29435
- stop();
29436
- setTimeout(start2, 5e3);
29437
- });
29438
- } catch {
29439
- log10.debug(`${WATCH_DIR} not available yet, retrying...`);
29072
+ // src/lib/session-detection.ts
29073
+ init_platform();
29074
+ var execFile3 = (0, import_util5.promisify)(import_child_process3.execFile);
29075
+ var CLAUDE_DIR = import_path6.default.join(import_os6.default.homedir(), ".claude");
29076
+ var SESSIONS_DIR = import_path6.default.join(CLAUDE_DIR, "sessions");
29077
+ var PROJECTS_DIR = import_path6.default.join(CLAUDE_DIR, "projects");
29078
+ var CLAUDE_KNOWN_PATHS = [import_path6.default.join(import_os6.default.homedir(), ".local", "bin", "claude")];
29079
+ var PID_POLL_INTERVAL = 1e4;
29080
+ var SESSION_DIR_DEBOUNCE = 200;
29081
+ var INSTALL_CHECK_INTERVAL = 6e4;
29082
+ var MAX_SANITIZED_LENGTH = 200;
29083
+ var toClaudeProjectName = (dirPath) => {
29084
+ const sanitized = dirPath.replace(/[^a-zA-Z0-9]/g, "-");
29085
+ if (sanitized.length <= MAX_SANITIZED_LENGTH) {
29086
+ return sanitized;
29087
+ }
29088
+ const hash2 = simpleHash(dirPath);
29089
+ return `${sanitized.slice(0, MAX_SANITIZED_LENGTH)}-${hash2}`;
29090
+ };
29091
+ var simpleHash = (str) => {
29092
+ let hash2 = 0;
29093
+ for (let i = 0; i < str.length; i++) {
29094
+ hash2 = (hash2 << 5) - hash2 + str.charCodeAt(i) | 0;
29095
+ }
29096
+ return Math.abs(hash2).toString(36);
29097
+ };
29098
+ var isProcessRunning = (pid) => new Promise((resolve) => {
29099
+ (0, import_child_process3.execFile)("ps", ["-p", String(pid)], (err) => {
29100
+ resolve(!err);
29101
+ });
29102
+ });
29103
+ var getChildPids = async (parentPid) => {
29104
+ try {
29105
+ const { stdout } = await execFile3("pgrep", ["-P", String(parentPid)]);
29106
+ return stdout.trim().split("\n").map((s) => parseInt(s, 10)).filter((n) => !Number.isNaN(n));
29107
+ } catch {
29108
+ return [];
29109
+ }
29110
+ };
29111
+ var getProcessCwd = async (pid) => {
29112
+ if (isLinux) {
29113
+ try {
29114
+ return await import_promises5.default.readlink(`/proc/${pid}/cwd`);
29115
+ } catch {
29116
+ return null;
29117
+ }
29118
+ }
29119
+ try {
29120
+ const { stdout } = await execFile3("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"]);
29121
+ const line = stdout.split("\n").find((l) => l.startsWith("n/"));
29122
+ return line ? line.slice(1) : null;
29123
+ } catch {
29124
+ return null;
29125
+ }
29126
+ };
29127
+ var getClaudeSessionFromArgs = async (childPids) => {
29128
+ for (const pid of childPids) {
29129
+ try {
29130
+ const { stdout } = await execFile3("ps", ["-p", String(pid), "-o", "args="]);
29131
+ const args = stdout.trim();
29132
+ const match = args.match(/claude\s+--resume\s+([0-9a-f-]{36})/);
29133
+ if (match) {
29134
+ const cwd = await getProcessCwd(pid);
29135
+ return { pid, sessionId: match[1], cwd };
29136
+ }
29137
+ } catch {
29138
+ continue;
29139
+ }
29140
+ }
29141
+ return null;
29142
+ };
29143
+ var readPidFile = async (filePath) => {
29144
+ try {
29145
+ const raw = await import_promises5.default.readFile(filePath, "utf-8");
29146
+ const data = JSON.parse(raw);
29147
+ if (!data.pid || !data.sessionId) return null;
29148
+ return data;
29149
+ } catch {
29150
+ return null;
29151
+ }
29152
+ };
29153
+ var findJsonlPath = async (projectDir, sessionId) => {
29154
+ const jsonlPath = import_path6.default.join(projectDir, `${sessionId}.jsonl`);
29155
+ try {
29156
+ await import_promises5.default.access(jsonlPath);
29157
+ return jsonlPath;
29158
+ } catch {
29159
+ return null;
29160
+ }
29161
+ };
29162
+ var isClaudeInstalled = async () => {
29163
+ try {
29164
+ await execFile3("claude", ["--version"], { timeout: 5e3, env: { ...process.env, PATH: await getShellPath() } });
29165
+ return true;
29166
+ } catch {
29167
+ for (const p of CLAUDE_KNOWN_PATHS) {
29168
+ try {
29169
+ await import_promises5.default.access(p);
29170
+ return true;
29171
+ } catch {
29172
+ }
29173
+ }
29174
+ return false;
29175
+ }
29176
+ };
29177
+ var isClaudeRunning = async (panePid, preloadedChildPids) => {
29178
+ const childPids = preloadedChildPids ?? await getChildPids(panePid);
29179
+ for (const pid of childPids) {
29180
+ try {
29181
+ const { stdout } = await execFile3("ps", ["-p", String(pid), "-o", "args="]);
29182
+ if (stdout.trim().includes("claude")) return true;
29183
+ } catch {
29184
+ continue;
29185
+ }
29186
+ }
29187
+ return false;
29188
+ };
29189
+ var detectActiveSession = async (panePid, preloadedChildPids) => {
29190
+ try {
29191
+ await import_promises5.default.access(CLAUDE_DIR);
29192
+ } catch {
29193
+ const installed = await isClaudeInstalled();
29194
+ const status = installed ? "not-initialized" : "not-installed";
29195
+ return { status, sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
29196
+ }
29197
+ const directChildPids = preloadedChildPids ?? await getChildPids(panePid);
29198
+ if (directChildPids.length === 0) {
29199
+ return { status: "not-running", sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
29200
+ }
29201
+ const grandchildPids = (await Promise.all(directChildPids.map(getChildPids))).flat();
29202
+ const allPids = [...directChildPids, ...grandchildPids];
29203
+ const childPidSet = new Set(allPids);
29204
+ try {
29205
+ const pidFiles = await import_promises5.default.readdir(SESSIONS_DIR);
29206
+ const jsonFiles = pidFiles.filter((f) => f.endsWith(".json"));
29207
+ for (const file2 of jsonFiles) {
29208
+ const data = await readPidFile(import_path6.default.join(SESSIONS_DIR, file2));
29209
+ if (!data) continue;
29210
+ if (!childPidSet.has(data.pid)) continue;
29211
+ let processArgs = "";
29212
+ try {
29213
+ const { stdout } = await execFile3("ps", ["-p", String(data.pid), "-o", "args="]);
29214
+ processArgs = stdout.trim();
29215
+ } catch {
29216
+ try {
29217
+ await import_promises5.default.unlink(import_path6.default.join(SESSIONS_DIR, file2));
29218
+ } catch {
29219
+ }
29220
+ continue;
29221
+ }
29222
+ if (!processArgs.includes("claude")) {
29223
+ try {
29224
+ await import_promises5.default.unlink(import_path6.default.join(SESSIONS_DIR, file2));
29225
+ } catch {
29226
+ }
29227
+ continue;
29228
+ }
29229
+ const projectName = toClaudeProjectName(data.cwd);
29230
+ const projectDir = import_path6.default.join(PROJECTS_DIR, projectName);
29231
+ let jsonlPath = await findJsonlPath(projectDir, data.sessionId);
29232
+ let effectiveSessionId = data.sessionId;
29233
+ if (!jsonlPath) {
29234
+ const resumeMatch = processArgs.match(/--resume\s+([0-9a-f-]{36})/);
29235
+ if (resumeMatch) {
29236
+ const resumeSessionId = resumeMatch[1];
29237
+ const resumeJsonlPath = await findJsonlPath(projectDir, resumeSessionId);
29238
+ if (resumeJsonlPath) {
29239
+ jsonlPath = resumeJsonlPath;
29240
+ effectiveSessionId = resumeSessionId;
29241
+ }
29242
+ }
29243
+ }
29244
+ return {
29245
+ status: "running",
29246
+ sessionId: effectiveSessionId,
29247
+ jsonlPath,
29248
+ pid: data.pid,
29249
+ startedAt: data.startedAt,
29250
+ cwd: data.cwd
29251
+ };
29252
+ }
29253
+ } catch {
29254
+ }
29255
+ const fromArgs = await getClaudeSessionFromArgs(allPids);
29256
+ if (fromArgs) {
29257
+ const cwd = fromArgs.cwd;
29258
+ if (cwd) {
29259
+ const projectName = toClaudeProjectName(cwd);
29260
+ const projectDir = import_path6.default.join(PROJECTS_DIR, projectName);
29261
+ const jsonlPath = await findJsonlPath(projectDir, fromArgs.sessionId);
29262
+ return {
29263
+ status: "running",
29264
+ sessionId: fromArgs.sessionId,
29265
+ jsonlPath,
29266
+ pid: fromArgs.pid,
29267
+ startedAt: null,
29268
+ cwd
29269
+ };
29270
+ }
29271
+ }
29272
+ return { status: "not-running", sessionId: null, jsonlPath: null, pid: null, startedAt: null, cwd: null };
29273
+ };
29274
+ var watchSessionsDir = (panePid, onChange, options) => {
29275
+ let watcher = null;
29276
+ let pidPollTimer = null;
29277
+ let debounceTimer = null;
29278
+ let installCheckTimer = null;
29279
+ let currentPid = null;
29280
+ let stopped = false;
29281
+ const pollPid = async () => {
29282
+ if (stopped || !currentPid) return;
29283
+ const running = await isProcessRunning(currentPid);
29284
+ if (!running && !stopped) {
29285
+ currentPid = null;
29286
+ const info = await detectActiveSession(panePid);
29287
+ onChange(info);
29288
+ }
29289
+ };
29290
+ const handleSessionDirChange = () => {
29291
+ if (stopped) return;
29292
+ if (debounceTimer) clearTimeout(debounceTimer);
29293
+ debounceTimer = setTimeout(async () => {
29294
+ if (stopped) return;
29295
+ const info = await detectActiveSession(panePid);
29296
+ if (info.pid) currentPid = info.pid;
29297
+ onChange(info);
29298
+ }, SESSION_DIR_DEBOUNCE);
29299
+ };
29300
+ const tryWatch = () => {
29301
+ if (stopped) return;
29302
+ try {
29303
+ watcher = (0, import_fs.watch)(SESSIONS_DIR, handleSessionDirChange);
29304
+ watcher.on("error", () => {
29305
+ });
29306
+ if (installCheckTimer) {
29307
+ clearInterval(installCheckTimer);
29308
+ installCheckTimer = null;
29309
+ }
29310
+ } catch {
29311
+ if (!installCheckTimer) {
29312
+ installCheckTimer = setInterval(async () => {
29313
+ if (stopped) return;
29314
+ try {
29315
+ await import_promises5.default.access(SESSIONS_DIR);
29316
+ tryWatch();
29317
+ const info = await detectActiveSession(panePid);
29318
+ if (info.pid) currentPid = info.pid;
29319
+ onChange(info);
29320
+ } catch {
29321
+ }
29322
+ }, INSTALL_CHECK_INTERVAL);
29323
+ }
29324
+ }
29325
+ };
29326
+ tryWatch();
29327
+ pidPollTimer = setInterval(pollPid, PID_POLL_INTERVAL);
29328
+ if (!options?.skipInitial) {
29329
+ detectActiveSession(panePid).then((info) => {
29330
+ if (stopped) return;
29331
+ if (info.pid) currentPid = info.pid;
29332
+ onChange(info);
29333
+ });
29334
+ }
29335
+ return {
29336
+ stop: () => {
29337
+ stopped = true;
29338
+ if (watcher) watcher.close();
29339
+ if (pidPollTimer) clearInterval(pidPollTimer);
29340
+ if (debounceTimer) clearTimeout(debounceTimer);
29341
+ if (installCheckTimer) clearInterval(installCheckTimer);
29342
+ }
29343
+ };
29344
+ };
29345
+
29346
+ // src/lib/session-list.ts
29347
+ init_tmux();
29348
+ init_logger();
29349
+
29350
+ // src/lib/session-meta-cache.ts
29351
+ var CACHE_TTL = 3e4;
29352
+ var createMetaCache = () => {
29353
+ const store = /* @__PURE__ */ new Map();
29354
+ const get = (sessionId) => {
29355
+ const entry = store.get(sessionId);
29356
+ if (!entry) return void 0;
29357
+ if (Date.now() - entry.cachedAt > CACHE_TTL) {
29358
+ store.delete(sessionId);
29359
+ return void 0;
29360
+ }
29361
+ return entry.meta;
29362
+ };
29363
+ const set2 = (sessionId, meta3, mtime) => {
29364
+ store.set(sessionId, { meta: meta3, mtime, cachedAt: Date.now() });
29365
+ };
29366
+ const isStale = (sessionId, currentMtime) => {
29367
+ const entry = store.get(sessionId);
29368
+ if (!entry) return true;
29369
+ if (Date.now() - entry.cachedAt > CACHE_TTL) {
29370
+ store.delete(sessionId);
29371
+ return true;
29372
+ }
29373
+ return entry.mtime !== currentMtime;
29374
+ };
29375
+ const clear = () => {
29376
+ store.clear();
29377
+ };
29378
+ return { get, set: set2, isStale, clear };
29379
+ };
29380
+
29381
+ // src/lib/session-list.ts
29382
+ var log7 = createLogger("session-list");
29383
+ var PROJECTS_DIR2 = import_path7.default.join(
29384
+ process.env.HOME || process.env.USERPROFILE || "/",
29385
+ ".claude",
29386
+ "projects"
29387
+ );
29388
+ var metaCache = createMetaCache();
29389
+ var cwdToProjectPath = (cwd) => {
29390
+ const projectName = toClaudeProjectName(cwd);
29391
+ return import_path7.default.join(PROJECTS_DIR2, projectName);
29392
+ };
29393
+
29394
+ // src/lib/timeline-server.ts
29395
+ init_layout_store();
29396
+
29397
+ // src/lib/status-manager.ts
29398
+ init_wrapper();
29399
+ init_workspace_store();
29400
+ init_layout_store();
29401
+ init_tmux();
29402
+
29403
+ // src/lib/hook-settings.ts
29404
+ var import_promises8 = __toESM(require("fs/promises"));
29405
+ var import_path11 = __toESM(require("path"));
29406
+ var import_os9 = __toESM(require("os"));
29407
+ init_logger();
29408
+
29409
+ // src/lib/statusline-script.ts
29410
+ var import_path10 = __toESM(require("path"));
29411
+ var import_os8 = __toESM(require("os"));
29412
+ var BASE_DIR4 = import_path10.default.join(import_os8.default.homedir(), ".purplemux");
29413
+ var STATUSLINE_SCRIPT_PATH = import_path10.default.join(BASE_DIR4, "statusline.sh");
29414
+ var RATE_LIMITS_FILE = import_path10.default.join(BASE_DIR4, "rate-limits.json");
29415
+ var STATUSLINE_SCRIPT_CONTENT = `#!/bin/sh
29416
+ PORT_FILE="$HOME/.purplemux/port"
29417
+ TOKEN_FILE="$HOME/.purplemux/cli-token"
29418
+ [ -f "$PORT_FILE" ] || exit 0
29419
+ [ -f "$TOKEN_FILE" ] || exit 0
29420
+ PORT=$(cat "$PORT_FILE")
29421
+ TOKEN=$(cat "$TOKEN_FILE")
29422
+ curl -sf --max-time 2 -X POST \\
29423
+ -H 'Content-Type: application/json' \\
29424
+ -H "x-pmux-token: \${TOKEN}" \\
29425
+ --data-binary @- \\
29426
+ "http://localhost:\${PORT}/api/status/statusline" 2>/dev/null || exit 0
29427
+ `;
29428
+
29429
+ // src/lib/hook-settings.ts
29430
+ var log10 = createLogger("hooks");
29431
+ var BASE_DIR5 = import_path11.default.join(import_os9.default.homedir(), ".purplemux");
29432
+ var HOOKS_FILE = import_path11.default.join(BASE_DIR5, "hooks.json");
29433
+ var PORT_FILE = import_path11.default.join(BASE_DIR5, "port");
29434
+ var HOOK_SCRIPT = import_path11.default.join(BASE_DIR5, "status-hook.sh");
29435
+ var HOOK_SETTINGS_PATH = HOOKS_FILE;
29436
+ var HOOK_SCRIPT_CONTENT = `#!/bin/sh
29437
+ EVENT="\${1:-poll}"
29438
+ PORT_FILE="$HOME/.purplemux/port"
29439
+ TOKEN_FILE="$HOME/.purplemux/cli-token"
29440
+ [ -f "$PORT_FILE" ] || exit 0
29441
+ [ -f "$TOKEN_FILE" ] || exit 0
29442
+ PORT=$(cat "$PORT_FILE")
29443
+ TOKEN=$(cat "$TOKEN_FILE")
29444
+ SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null) || SESSION=""
29445
+
29446
+ NOTIFICATION_TYPE=""
29447
+ if [ "$EVENT" = "notification" ]; then
29448
+ NOTIFICATION_TYPE=$(sed -n 's/.*"notification_type"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
29449
+ fi
29450
+
29451
+ PAYLOAD="{\\"event\\":\\"\${EVENT}\\",\\"session\\":\\"\${SESSION}\\""
29452
+ if [ -n "$NOTIFICATION_TYPE" ]; then
29453
+ PAYLOAD="\${PAYLOAD},\\"notificationType\\":\\"\${NOTIFICATION_TYPE}\\""
29454
+ fi
29455
+ PAYLOAD="\${PAYLOAD}}"
29456
+
29457
+ curl -s -X POST -o /dev/null -H 'Content-Type: application/json' -H "x-pmux-token: \${TOKEN}" -d "$PAYLOAD" "http://localhost:\${PORT}/api/status/hook" 2>/dev/null
29458
+ exit 0
29459
+ `;
29460
+ var hookEntry = (event, timeout = 3) => [
29461
+ {
29462
+ matcher: "",
29463
+ hooks: [
29464
+ {
29465
+ type: "command",
29466
+ command: `sh "${HOOK_SCRIPT}" ${event}`,
29467
+ timeout
29468
+ }
29469
+ ]
29470
+ }
29471
+ ];
29472
+ var buildHookSettings = () => ({
29473
+ hooks: {
29474
+ SessionStart: hookEntry("session-start"),
29475
+ UserPromptSubmit: hookEntry("prompt-submit"),
29476
+ Notification: hookEntry("notification"),
29477
+ Stop: hookEntry("stop"),
29478
+ StopFailure: hookEntry("stop"),
29479
+ PreCompact: hookEntry("pre-compact"),
29480
+ PostCompact: hookEntry("post-compact")
29481
+ },
29482
+ statusLine: {
29483
+ type: "command",
29484
+ command: `sh "${STATUSLINE_SCRIPT_PATH}"`
29485
+ }
29486
+ });
29487
+ var ensureHookSettings = async (port) => {
29488
+ await import_promises8.default.mkdir(BASE_DIR5, { recursive: true });
29489
+ await import_promises8.default.writeFile(PORT_FILE, String(port), { mode: 384 });
29490
+ try {
29491
+ const existing = await import_promises8.default.readFile(HOOK_SCRIPT, "utf-8");
29492
+ if (existing !== HOOK_SCRIPT_CONTENT) {
29493
+ await import_promises8.default.writeFile(HOOK_SCRIPT, HOOK_SCRIPT_CONTENT, { mode: 493 });
29494
+ }
29495
+ } catch {
29496
+ await import_promises8.default.writeFile(HOOK_SCRIPT, HOOK_SCRIPT_CONTENT, { mode: 493 });
29497
+ }
29498
+ try {
29499
+ const existing = await import_promises8.default.readFile(STATUSLINE_SCRIPT_PATH, "utf-8");
29500
+ if (existing !== STATUSLINE_SCRIPT_CONTENT) {
29501
+ await import_promises8.default.writeFile(STATUSLINE_SCRIPT_PATH, STATUSLINE_SCRIPT_CONTENT, { mode: 493 });
29502
+ }
29503
+ } catch {
29504
+ await import_promises8.default.writeFile(STATUSLINE_SCRIPT_PATH, STATUSLINE_SCRIPT_CONTENT, { mode: 493 });
29505
+ }
29506
+ const settings = buildHookSettings();
29507
+ const content = JSON.stringify(settings, null, 2) + "\n";
29508
+ try {
29509
+ const existing = await import_promises8.default.readFile(HOOKS_FILE, "utf-8");
29510
+ if (existing === content) return;
29511
+ } catch {
29512
+ }
29513
+ await import_promises8.default.writeFile(HOOKS_FILE, content, { mode: 384 });
29514
+ log10.debug(`${HOOKS_FILE} created`);
29515
+ };
29516
+ var removePortFile = async () => {
29517
+ try {
29518
+ await import_promises8.default.unlink(PORT_FILE);
29519
+ } catch {
29520
+ }
29521
+ };
29522
+
29523
+ // src/lib/claude-command.ts
29524
+ init_claude_prompt();
29525
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
29526
+ var isValidSessionId = (id) => typeof id === "string" && UUID_RE.test(id);
29527
+ var buildClaudeFlags = async (workspaceId) => {
29528
+ const skipPerms = await getDangerouslySkipPermissions();
29529
+ const parts = [`--settings ${HOOK_SETTINGS_PATH}`];
29530
+ if (workspaceId) {
29531
+ parts.push(`--append-system-prompt-file ${getClaudePromptPath(workspaceId)}`);
29532
+ }
29533
+ if (skipPerms) parts.push("--dangerously-skip-permissions");
29534
+ return parts.join(" ");
29535
+ };
29536
+ var buildResumeCommand = async (sessionId, workspaceId) => {
29537
+ if (!isValidSessionId(sessionId)) {
29538
+ throw new Error(`Invalid session ID format: ${sessionId}`);
29539
+ }
29540
+ const flags = await buildClaudeFlags(workspaceId);
29541
+ return `claude --resume ${sessionId} ${flags}`;
29542
+ };
29543
+
29544
+ // src/lib/providers/claude/index.ts
29545
+ var claudeProvider = {
29546
+ id: "claude",
29547
+ displayName: "Claude Code",
29548
+ panelType: "claude-code",
29549
+ matchesProcess: (commandName) => commandName === "claude" || commandName === "node",
29550
+ isValidSessionId,
29551
+ detectActiveSession: (panePid, childPids) => detectActiveSession(panePid, childPids),
29552
+ isAgentRunning: (panePid, childPids) => isClaudeRunning(panePid, childPids),
29553
+ watchSessions: (panePid, onChange, options) => watchSessionsDir(panePid, onChange, options),
29554
+ buildResumeCommand: (sessionId, { workspaceId }) => buildResumeCommand(sessionId, workspaceId),
29555
+ buildLaunchCommand: async ({ workspaceId }) => {
29556
+ const flags = await buildClaudeFlags(workspaceId);
29557
+ return `claude ${flags}`;
29558
+ },
29559
+ readSessionId: (tab) => tab.claudeSessionId ?? null,
29560
+ writeSessionId: (tab, sessionId) => {
29561
+ tab.claudeSessionId = sessionId ?? null;
29562
+ },
29563
+ readJsonlPath: (tab) => tab.claudeJsonlPath ?? null,
29564
+ writeJsonlPath: (tab, jsonlPath) => {
29565
+ tab.claudeJsonlPath = jsonlPath ?? null;
29566
+ },
29567
+ readSummary: (tab) => tab.claudeSummary ?? null,
29568
+ writeSummary: (tab, summary) => {
29569
+ tab.claudeSummary = summary ?? null;
29570
+ }
29571
+ };
29572
+
29573
+ // src/lib/providers/registry.ts
29574
+ var g6 = globalThis;
29575
+ if (!g6.__ptAgentProviders) g6.__ptAgentProviders = /* @__PURE__ */ new Map();
29576
+ var providers = g6.__ptAgentProviders;
29577
+ var registerProvider = (provider) => {
29578
+ providers.set(provider.id, provider);
29579
+ };
29580
+ var getProviderByPanelType = (panelType) => {
29581
+ if (!panelType) return null;
29582
+ for (const provider of providers.values()) {
29583
+ if (provider.panelType === panelType) return provider;
29584
+ }
29585
+ return null;
29586
+ };
29587
+ var getProviderByProcessName = (commandName) => {
29588
+ for (const provider of providers.values()) {
29589
+ if (provider.matchesProcess(commandName)) return provider;
29590
+ }
29591
+ return null;
29592
+ };
29593
+ var listProviders = () => Array.from(providers.values());
29594
+
29595
+ // src/lib/providers/index.ts
29596
+ registerProvider(claudeProvider);
29597
+ var NOT_RUNNING = {
29598
+ status: "not-running",
29599
+ sessionId: null,
29600
+ jsonlPath: null,
29601
+ pid: null,
29602
+ startedAt: null,
29603
+ cwd: null
29604
+ };
29605
+ var NOT_INSTALLED = {
29606
+ status: "not-installed",
29607
+ sessionId: null,
29608
+ jsonlPath: null,
29609
+ pid: null,
29610
+ startedAt: null,
29611
+ cwd: null
29612
+ };
29613
+ var detectAnyActiveSession = async (panePid, childPids) => {
29614
+ const providers2 = listProviders();
29615
+ let allNotInstalled = providers2.length > 0;
29616
+ for (const provider of providers2) {
29617
+ const info = await provider.detectActiveSession(panePid, childPids);
29618
+ if (info.status === "running") return { provider, info };
29619
+ if (info.status !== "not-installed") allNotInstalled = false;
29620
+ }
29621
+ return { provider: null, info: allNotInstalled ? NOT_INSTALLED : NOT_RUNNING };
29622
+ };
29623
+
29624
+ // src/lib/status-manager.ts
29625
+ init_tab_title();
29626
+
29627
+ // src/lib/rate-limits-watcher.ts
29628
+ var import_fs2 = __toESM(require("fs"));
29629
+ var import_promises9 = __toESM(require("fs/promises"));
29630
+ var import_path12 = __toESM(require("path"));
29631
+ init_logger();
29632
+ var log11 = createLogger("rate-limits");
29633
+ var DEBOUNCE_MS = 500;
29634
+ var WATCH_DIR = import_path12.default.dirname(RATE_LIMITS_FILE);
29635
+ var WATCH_FILENAME = import_path12.default.basename(RATE_LIMITS_FILE);
29636
+ var createRateLimitsWatcher = (onChange) => {
29637
+ let watcher = null;
29638
+ let debounceTimer = null;
29639
+ let lastTs = 0;
29640
+ const readAndNotify = async () => {
29641
+ try {
29642
+ const raw = await import_promises9.default.readFile(RATE_LIMITS_FILE, "utf-8");
29643
+ const data = JSON.parse(raw);
29644
+ if (data.ts && data.ts !== lastTs) {
29645
+ lastTs = data.ts;
29646
+ onChange(data);
29647
+ }
29648
+ } catch {
29649
+ }
29650
+ };
29651
+ const start2 = () => {
29652
+ readAndNotify();
29653
+ try {
29654
+ watcher = import_fs2.default.watch(WATCH_DIR, (_eventType, filename) => {
29655
+ if (filename !== WATCH_FILENAME) return;
29656
+ if (debounceTimer) clearTimeout(debounceTimer);
29657
+ debounceTimer = setTimeout(readAndNotify, DEBOUNCE_MS);
29658
+ });
29659
+ watcher.on("error", () => {
29660
+ log11.debug(`${WATCH_DIR} watch error, retrying...`);
29661
+ stop();
29662
+ setTimeout(start2, 5e3);
29663
+ });
29664
+ } catch {
29665
+ log11.debug(`${WATCH_DIR} not available yet, retrying...`);
29440
29666
  setTimeout(start2, 5e3);
29441
29667
  }
29442
29668
  };
@@ -29618,23 +29844,23 @@ var parsePermissionOptions = (paneContent) => {
29618
29844
  };
29619
29845
 
29620
29846
  // src/lib/session-history.ts
29621
- var import_promises9 = __toESM(require("fs/promises"));
29622
- var import_path12 = __toESM(require("path"));
29623
- var import_os9 = __toESM(require("os"));
29847
+ var import_promises10 = __toESM(require("fs/promises"));
29848
+ var import_path13 = __toESM(require("path"));
29849
+ var import_os10 = __toESM(require("os"));
29624
29850
  init_logger();
29625
- var log11 = createLogger("session-history");
29851
+ var log12 = createLogger("session-history");
29626
29852
  var MAX_ENTRIES = 200;
29627
- var BASE_DIR5 = import_path12.default.join(import_os9.default.homedir(), ".purplemux");
29628
- var SESSION_HISTORY_FILE = import_path12.default.join(BASE_DIR5, "session-history.json");
29629
- var g6 = globalThis;
29630
- if (!g6.__purplemuxSessionHistoryLock) g6.__purplemuxSessionHistoryLock = Promise.resolve();
29853
+ var BASE_DIR6 = import_path13.default.join(import_os10.default.homedir(), ".purplemux");
29854
+ var SESSION_HISTORY_FILE = import_path13.default.join(BASE_DIR6, "session-history.json");
29855
+ var g7 = globalThis;
29856
+ if (!g7.__purplemuxSessionHistoryLock) g7.__purplemuxSessionHistoryLock = Promise.resolve();
29631
29857
  var withLock3 = async (fn) => {
29632
29858
  let release;
29633
29859
  const next2 = new Promise((r) => {
29634
29860
  release = r;
29635
29861
  });
29636
- const prev = g6.__purplemuxSessionHistoryLock;
29637
- g6.__purplemuxSessionHistoryLock = next2;
29862
+ const prev = g7.__purplemuxSessionHistoryLock;
29863
+ g7.__purplemuxSessionHistoryLock = next2;
29638
29864
  await prev;
29639
29865
  try {
29640
29866
  return await fn();
@@ -29646,16 +29872,16 @@ var emptyData = () => ({ version: 1, entries: [] });
29646
29872
  var readSessionHistory = async () => {
29647
29873
  let raw;
29648
29874
  try {
29649
- raw = await import_promises9.default.readFile(SESSION_HISTORY_FILE, "utf-8");
29875
+ raw = await import_promises10.default.readFile(SESSION_HISTORY_FILE, "utf-8");
29650
29876
  } catch {
29651
29877
  return emptyData();
29652
29878
  }
29653
29879
  try {
29654
29880
  return JSON.parse(raw);
29655
29881
  } catch {
29656
- log11.warn("Failed to parse session-history.json, starting empty");
29882
+ log12.warn("Failed to parse session-history.json, starting empty");
29657
29883
  try {
29658
- await import_promises9.default.copyFile(SESSION_HISTORY_FILE, SESSION_HISTORY_FILE.replace(/\.json$/, ".json.bak"));
29884
+ await import_promises10.default.copyFile(SESSION_HISTORY_FILE, SESSION_HISTORY_FILE.replace(/\.json$/, ".json.bak"));
29659
29885
  } catch {
29660
29886
  }
29661
29887
  return emptyData();
@@ -29663,17 +29889,17 @@ var readSessionHistory = async () => {
29663
29889
  };
29664
29890
  var writeSessionHistory = async (data) => {
29665
29891
  const contentKey = JSON.stringify(data.entries);
29666
- if (g6.__purplemuxSessionHistoryContentCache === contentKey) return;
29892
+ if (g7.__purplemuxSessionHistoryContentCache === contentKey) return;
29667
29893
  const tmpFile = SESSION_HISTORY_FILE + ".tmp";
29668
29894
  try {
29669
- await import_promises9.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
29670
- await import_promises9.default.rename(tmpFile, SESSION_HISTORY_FILE);
29895
+ await import_promises10.default.writeFile(tmpFile, JSON.stringify(data, null, 2), { mode: 384 });
29896
+ await import_promises10.default.rename(tmpFile, SESSION_HISTORY_FILE);
29671
29897
  } catch (err) {
29672
- await import_promises9.default.unlink(tmpFile).catch(() => {
29898
+ await import_promises10.default.unlink(tmpFile).catch(() => {
29673
29899
  });
29674
29900
  throw err;
29675
29901
  }
29676
- g6.__purplemuxSessionHistoryContentCache = contentKey;
29902
+ g7.__purplemuxSessionHistoryContentCache = contentKey;
29677
29903
  };
29678
29904
  var addSessionHistoryEntry = async (entry) => {
29679
29905
  await withLock3(async () => {
@@ -29704,20 +29930,20 @@ var getSessionHistory = async () => {
29704
29930
  var import_web_push = __toESM(require_src2());
29705
29931
 
29706
29932
  // src/lib/push-subscriptions.ts
29707
- var import_promises10 = __toESM(require("fs/promises"));
29708
- var import_path13 = __toESM(require("path"));
29709
- var import_os10 = __toESM(require("os"));
29710
- var BASE_DIR6 = import_path13.default.join(import_os10.default.homedir(), ".purplemux");
29711
- var SUBS_FILE = import_path13.default.join(BASE_DIR6, "push-subscriptions.json");
29712
- var g7 = globalThis;
29713
- if (!g7.__ptPushLock) g7.__ptPushLock = Promise.resolve();
29933
+ var import_promises11 = __toESM(require("fs/promises"));
29934
+ var import_path14 = __toESM(require("path"));
29935
+ var import_os11 = __toESM(require("os"));
29936
+ var BASE_DIR7 = import_path14.default.join(import_os11.default.homedir(), ".purplemux");
29937
+ var SUBS_FILE = import_path14.default.join(BASE_DIR7, "push-subscriptions.json");
29938
+ var g8 = globalThis;
29939
+ if (!g8.__ptPushLock) g8.__ptPushLock = Promise.resolve();
29714
29940
  var withLock4 = async (fn) => {
29715
29941
  let release;
29716
29942
  const next2 = new Promise((r) => {
29717
29943
  release = r;
29718
29944
  });
29719
- const prev = g7.__ptPushLock;
29720
- g7.__ptPushLock = next2;
29945
+ const prev = g8.__ptPushLock;
29946
+ g8.__ptPushLock = next2;
29721
29947
  await prev;
29722
29948
  try {
29723
29949
  return await fn();
@@ -29727,20 +29953,20 @@ var withLock4 = async (fn) => {
29727
29953
  };
29728
29954
  var readSubs = async () => {
29729
29955
  try {
29730
- const raw = await import_promises10.default.readFile(SUBS_FILE, "utf-8");
29956
+ const raw = await import_promises11.default.readFile(SUBS_FILE, "utf-8");
29731
29957
  return JSON.parse(raw);
29732
29958
  } catch {
29733
29959
  return [];
29734
29960
  }
29735
29961
  };
29736
29962
  var writeSubs = async (subs) => {
29737
- await import_promises10.default.mkdir(BASE_DIR6, { recursive: true });
29963
+ await import_promises11.default.mkdir(BASE_DIR7, { recursive: true });
29738
29964
  const tmp = SUBS_FILE + ".tmp";
29739
29965
  try {
29740
- await import_promises10.default.writeFile(tmp, JSON.stringify(subs, null, 2), { mode: 384 });
29741
- await import_promises10.default.rename(tmp, SUBS_FILE);
29966
+ await import_promises11.default.writeFile(tmp, JSON.stringify(subs, null, 2), { mode: 384 });
29967
+ await import_promises11.default.rename(tmp, SUBS_FILE);
29742
29968
  } catch (err) {
29743
- await import_promises10.default.unlink(tmp).catch(() => {
29969
+ await import_promises11.default.unlink(tmp).catch(() => {
29744
29970
  });
29745
29971
  throw err;
29746
29972
  }
@@ -29773,50 +29999,50 @@ if (!gActive.__ptSessionPushTarget) gActive.__ptSessionPushTarget = /* @__PURE__
29773
29999
  var sessionPushTarget = gActive.__ptSessionPushTarget;
29774
30000
 
29775
30001
  // src/lib/vapid-keys.ts
29776
- var import_promises11 = __toESM(require("fs/promises"));
29777
- var import_path14 = __toESM(require("path"));
29778
- var import_os11 = __toESM(require("os"));
30002
+ var import_promises12 = __toESM(require("fs/promises"));
30003
+ var import_path15 = __toESM(require("path"));
30004
+ var import_os12 = __toESM(require("os"));
29779
30005
  var _webpush = __toESM(require_src2());
29780
30006
  init_logger();
29781
30007
  var webpush = _webpush.default ?? _webpush;
29782
- var log12 = createLogger("vapid");
29783
- var BASE_DIR7 = import_path14.default.join(import_os11.default.homedir(), ".purplemux");
29784
- var VAPID_FILE = import_path14.default.join(BASE_DIR7, "vapid-keys.json");
30008
+ var log13 = createLogger("vapid");
30009
+ var BASE_DIR8 = import_path15.default.join(import_os12.default.homedir(), ".purplemux");
30010
+ var VAPID_FILE = import_path15.default.join(BASE_DIR8, "vapid-keys.json");
29785
30011
  var cachedKeys = null;
29786
30012
  var getVAPIDKeys = async () => {
29787
30013
  if (cachedKeys) return cachedKeys;
29788
30014
  try {
29789
- const raw = await import_promises11.default.readFile(VAPID_FILE, "utf-8");
30015
+ const raw = await import_promises12.default.readFile(VAPID_FILE, "utf-8");
29790
30016
  cachedKeys = JSON.parse(raw);
29791
30017
  return cachedKeys;
29792
30018
  } catch {
29793
30019
  }
29794
30020
  const keys = webpush.generateVAPIDKeys();
29795
30021
  cachedKeys = { publicKey: keys.publicKey, privateKey: keys.privateKey };
29796
- await import_promises11.default.mkdir(BASE_DIR7, { recursive: true });
30022
+ await import_promises12.default.mkdir(BASE_DIR8, { recursive: true });
29797
30023
  const tmp = VAPID_FILE + ".tmp";
29798
30024
  try {
29799
- await import_promises11.default.writeFile(tmp, JSON.stringify(cachedKeys, null, 2), { mode: 384 });
29800
- await import_promises11.default.rename(tmp, VAPID_FILE);
30025
+ await import_promises12.default.writeFile(tmp, JSON.stringify(cachedKeys, null, 2), { mode: 384 });
30026
+ await import_promises12.default.rename(tmp, VAPID_FILE);
29801
30027
  } catch (err) {
29802
- await import_promises11.default.unlink(tmp).catch(() => {
30028
+ await import_promises12.default.unlink(tmp).catch(() => {
29803
30029
  });
29804
30030
  throw err;
29805
30031
  }
29806
- log12.info("VAPID keys generated");
30032
+ log13.info("VAPID keys generated");
29807
30033
  return cachedKeys;
29808
30034
  };
29809
30035
 
29810
30036
  // src/lib/status-manager.ts
29811
30037
  init_nanoid();
29812
- var import_promises12 = __toESM(require("fs/promises"));
30038
+ var import_promises13 = __toESM(require("fs/promises"));
29813
30039
  var import_fs3 = require("fs");
29814
- var import_path15 = __toESM(require("path"));
29815
- var log13 = createLogger("status");
30040
+ var import_path16 = __toESM(require("path"));
30041
+ var log14 = createLogger("status");
29816
30042
  var hookLog = createLogger("hooks");
29817
30043
  var sessionIdFromJsonlPath = (jsonlPath) => {
29818
30044
  if (!jsonlPath) return null;
29819
- return import_path15.default.basename(jsonlPath, ".jsonl");
30045
+ return import_path16.default.basename(jsonlPath, ".jsonl");
29820
30046
  };
29821
30047
  var INPUT_REQUESTING_NOTIFICATION_TYPES = /* @__PURE__ */ new Set(["permission_prompt", "worker_permission_prompt"]);
29822
30048
  var COMPACT_STALE_MS = 6e4;
@@ -29935,7 +30161,7 @@ var scanLines = (lines, elapsed) => {
29935
30161
  };
29936
30162
  var checkJsonlIdle = async (jsonlPath) => {
29937
30163
  try {
29938
- const stat = await import_promises12.default.stat(jsonlPath);
30164
+ const stat = await import_promises13.default.stat(jsonlPath);
29939
30165
  if (stat.size === 0) return { idle: true, stale: false, lastAssistantSnippet: null, currentAction: null, reset: false, lastEntryTs: null, staleMs: 0, interrupted: false };
29940
30166
  const cached3 = jsonlIdleCache.get(jsonlPath);
29941
30167
  if (cached3 && cached3.mtimeMs === stat.mtimeMs) {
@@ -29948,7 +30174,7 @@ var checkJsonlIdle = async (jsonlPath) => {
29948
30174
  }
29949
30175
  return { idle: false, stale: false, lastAssistantSnippet: cached3.lastAssistantSnippet, currentAction: cached3.currentAction, reset: cached3.reset, lastEntryTs: cached3.lastEntryTs, staleMs: cached3.staleMs, interrupted: cached3.interrupted };
29950
30176
  }
29951
- const handle = await import_promises12.default.open(jsonlPath, "r");
30177
+ const handle = await import_promises13.default.open(jsonlPath, "r");
29952
30178
  try {
29953
30179
  const elapsed = Date.now() - stat.mtimeMs;
29954
30180
  const readSize = Math.min(stat.size, JSONL_TAIL_SIZE);
@@ -29980,9 +30206,9 @@ var checkJsonlIdle = async (jsonlPath) => {
29980
30206
  var parseJsonlStats = async (jsonlPath) => {
29981
30207
  const empty = { toolUsage: {}, touchedFiles: [], lastAssistantText: null, lastUserText: null, firstUserTs: null, lastAssistantTs: null, turnDurationMs: null };
29982
30208
  try {
29983
- const stat = await import_promises12.default.stat(jsonlPath);
30209
+ const stat = await import_promises13.default.stat(jsonlPath);
29984
30210
  if (stat.size === 0) return empty;
29985
- const handle = await import_promises12.default.open(jsonlPath, "r");
30211
+ const handle = await import_promises13.default.open(jsonlPath, "r");
29986
30212
  try {
29987
30213
  const readSize = Math.min(stat.size, JSONL_EXTENDED_TAIL_SIZE);
29988
30214
  const buffer = Buffer.alloc(readSize);
@@ -30054,7 +30280,7 @@ var parseClaudePaneTitle = (paneTitle) => {
30054
30280
  const cleaned = paneTitle.replace(CLAUDE_TITLE_RE, "").trim();
30055
30281
  return cleaned || null;
30056
30282
  };
30057
- var g8 = globalThis;
30283
+ var g9 = globalThis;
30058
30284
  var StatusManager = class _StatusManager {
30059
30285
  constructor() {
30060
30286
  this.tabs = /* @__PURE__ */ new Map();
@@ -30091,10 +30317,11 @@ var StatusManager = class _StatusManager {
30091
30317
  const tabs = collectAllTabs(layout.root);
30092
30318
  for (const tab of tabs) {
30093
30319
  const paneInfo = panesInfo.get(tab.sessionName);
30094
- const detected = await this.readTabMetadata(paneInfo);
30320
+ const provider = getProviderByPanelType(tab.panelType);
30321
+ const detected = await this.readTabMetadata(paneInfo, provider);
30095
30322
  const persisted = tab.cliState ?? "idle";
30096
30323
  const cliState = persisted === "busy" ? "unknown" : persisted;
30097
- const { terminalStatus, listeningPorts } = tab.panelType === "claude-code" ? { terminalStatus: "idle", listeningPorts: [] } : await this.detectTerminalStatus(paneInfo);
30324
+ const { terminalStatus, listeningPorts } = provider ? { terminalStatus: "idle", listeningPorts: [] } : await this.detectTerminalStatus(paneInfo);
30098
30325
  const currentProcess = paneInfo?.command;
30099
30326
  const paneTitle = paneInfo ? `${paneInfo.command}|${paneInfo.path}` : void 0;
30100
30327
  const syntheticLastEvent = cliState === "needs-input" ? { name: "notification", at: Date.now(), seq: 0 } : null;
@@ -30124,7 +30351,7 @@ var StatusManager = class _StatusManager {
30124
30351
  this.startJsonlWatch(tab.id, detected.jsonlPath);
30125
30352
  }
30126
30353
  if (cliState === "unknown") {
30127
- this.resolveUnknown(tab.id).catch((err) => log13.warn("resolveUnknown failed: %s", err));
30354
+ this.resolveUnknown(tab.id).catch((err) => log14.warn("resolveUnknown failed: %s", err));
30128
30355
  }
30129
30356
  }
30130
30357
  }
@@ -30132,10 +30359,11 @@ var StatusManager = class _StatusManager {
30132
30359
  async resolveUnknown(tabId) {
30133
30360
  const entry = this.tabs.get(tabId);
30134
30361
  if (!entry || entry.cliState !== "unknown") return;
30362
+ const provider = getProviderByPanelType(entry.panelType);
30135
30363
  const paneInfo = (await getAllPanesInfo()).get(entry.tmuxSession);
30136
30364
  const childPids = paneInfo?.pid ? await getChildPids(paneInfo.pid) : [];
30137
- const claudeRunning = paneInfo?.pid ? await isClaudeRunning(paneInfo.pid, childPids) : false;
30138
- if (!claudeRunning) {
30365
+ const agentRunning = paneInfo?.pid && provider ? await provider.isAgentRunning(paneInfo.pid, childPids) : false;
30366
+ if (!agentRunning) {
30139
30367
  this.applyCliState(tabId, entry, "idle", { silent: true });
30140
30368
  this.persistToLayout(entry);
30141
30369
  this.broadcastUpdate(tabId, entry);
@@ -30151,13 +30379,13 @@ var StatusManager = class _StatusManager {
30151
30379
  }
30152
30380
  }
30153
30381
  }
30154
- async readTabMetadata(paneInfo) {
30382
+ async readTabMetadata(paneInfo, provider) {
30155
30383
  const empty = { lastAssistantSnippet: null, currentAction: null, jsonlPath: null };
30156
- if (!paneInfo || !paneInfo.pid) return empty;
30384
+ if (!paneInfo || !paneInfo.pid || !provider) return empty;
30157
30385
  const childPids = await getChildPids(paneInfo.pid);
30158
- const claudeRunning = await isClaudeRunning(paneInfo.pid, childPids);
30159
- if (!claudeRunning) return empty;
30160
- const session = await detectActiveSession(paneInfo.pid, childPids);
30386
+ const running = await provider.isAgentRunning(paneInfo.pid, childPids);
30387
+ if (!running) return empty;
30388
+ const session = await provider.detectActiveSession(paneInfo.pid, childPids);
30161
30389
  if (session.status !== "running" || !session.jsonlPath) {
30162
30390
  return { lastAssistantSnippet: null, currentAction: null, jsonlPath: session.jsonlPath ?? null };
30163
30391
  }
@@ -30185,7 +30413,7 @@ var StatusManager = class _StatusManager {
30185
30413
  this.currentInterval = this.getPollingInterval();
30186
30414
  this.pollingTimer = setInterval(() => {
30187
30415
  this.poll().catch((err) => {
30188
- log13.error({ err }, "Polling error");
30416
+ log14.error({ err }, "Polling error");
30189
30417
  });
30190
30418
  }, this.currentInterval);
30191
30419
  }
@@ -30210,13 +30438,14 @@ var StatusManager = class _StatusManager {
30210
30438
  knownTabIds.add(tab.id);
30211
30439
  const existing = this.tabs.get(tab.id);
30212
30440
  const paneInfo = panesInfo.get(tab.sessionName);
30213
- const { terminalStatus, listeningPorts } = tab.panelType === "claude-code" ? { terminalStatus: "idle", listeningPorts: [] } : await this.detectTerminalStatus(paneInfo);
30441
+ const provider = getProviderByPanelType(tab.panelType);
30442
+ const { terminalStatus, listeningPorts } = provider ? { terminalStatus: "idle", listeningPorts: [] } : await this.detectTerminalStatus(paneInfo);
30214
30443
  const currentProcess = paneInfo?.command;
30215
30444
  const newPaneTitle = paneInfo ? `${paneInfo.command}|${paneInfo.path}` : void 0;
30216
30445
  if (!existing) {
30217
30446
  const persisted = tab.cliState ?? "idle";
30218
30447
  const initialState = persisted === "busy" ? "unknown" : persisted;
30219
- const detected = await this.readTabMetadata(paneInfo);
30448
+ const detected = await this.readTabMetadata(paneInfo, provider);
30220
30449
  const syntheticLastEvent = initialState === "needs-input" ? { name: "notification", at: Date.now(), seq: 0 } : null;
30221
30450
  const entry = {
30222
30451
  cliState: initialState,
@@ -30241,14 +30470,14 @@ var StatusManager = class _StatusManager {
30241
30470
  this.persistToLayout(entry);
30242
30471
  this.broadcastUpdate(tab.id, entry);
30243
30472
  if (initialState === "unknown") {
30244
- this.resolveUnknown(tab.id).catch((err) => log13.warn("resolveUnknown failed: %s", err));
30473
+ this.resolveUnknown(tab.id).catch((err) => log14.warn("resolveUnknown failed: %s", err));
30245
30474
  }
30246
30475
  continue;
30247
30476
  }
30248
30477
  const processChanged = existing.currentProcess !== currentProcess;
30249
30478
  const messageChanged = existing.lastUserMessage !== tab.lastUserMessage;
30250
30479
  const panelTypeChanged = existing.panelType !== tab.panelType;
30251
- const refreshed = await this.readTabMetadata(paneInfo);
30480
+ const refreshed = await this.readTabMetadata(paneInfo, provider);
30252
30481
  existing.tabName = tab.name || (newPaneTitle ? formatTabTitle(newPaneTitle) : "");
30253
30482
  existing.currentProcess = currentProcess;
30254
30483
  existing.paneTitle = newPaneTitle;
@@ -30289,9 +30518,9 @@ var StatusManager = class _StatusManager {
30289
30518
  }
30290
30519
  if (existing.cliState === "busy" && existing.lastEvent && now - existing.lastEvent.at > BUSY_STUCK_MS) {
30291
30520
  const childPids = paneInfo?.pid ? await getChildPids(paneInfo.pid) : [];
30292
- const claudeRunning = paneInfo?.pid ? await isClaudeRunning(paneInfo.pid, childPids) : false;
30293
- if (!claudeRunning) {
30294
- log13.info({ tabId: tab.id }, "busy stuck \u2014 Claude process gone, forcing idle");
30521
+ const agentRunning = paneInfo?.pid && provider ? await provider.isAgentRunning(paneInfo.pid, childPids) : false;
30522
+ if (!agentRunning) {
30523
+ log14.info({ tabId: tab.id }, "busy stuck \u2014 agent process gone, forcing idle");
30295
30524
  this.applyCliState(tab.id, existing, "idle", { silent: true });
30296
30525
  this.persistToLayout(existing);
30297
30526
  this.broadcastUpdate(tab.id, existing);
@@ -30352,17 +30581,17 @@ var StatusManager = class _StatusManager {
30352
30581
  if (newState === "ready-for-review" && entry.jsonlPath) {
30353
30582
  const delay = (ms) => new Promise((r) => setTimeout(r, ms));
30354
30583
  delay(500).then(() => this.saveSessionHistory(tabId, entry, prevBusySince, false)).catch((err) => {
30355
- log13.warn("Failed to save session history: %s", err);
30584
+ log14.warn("Failed to save session history: %s", err);
30356
30585
  });
30357
30586
  }
30358
30587
  if (newState === "ready-for-review" && !opts.silent) {
30359
30588
  this.sendWebPush(tabId, entry, "review").catch((err) => {
30360
- log13.warn("Web push failed: %s", err);
30589
+ log14.warn("Web push failed: %s", err);
30361
30590
  });
30362
30591
  }
30363
30592
  if (newState === "needs-input" && !opts.silent) {
30364
30593
  this.sendWebPush(tabId, entry, "needs-input").catch((err) => {
30365
- log13.warn("Web push failed: %s", err);
30594
+ log14.warn("Web push failed: %s", err);
30366
30595
  });
30367
30596
  }
30368
30597
  const shouldWatch = (newState === "busy" || newState === "needs-input") && entry.jsonlPath;
@@ -30413,7 +30642,7 @@ var StatusManager = class _StatusManager {
30413
30642
  updateSessionHistoryDismissedAt(tabId, dismissedAt).then((updated) => {
30414
30643
  if (updated) this.broadcast({ type: "session-history:update", entry: updated });
30415
30644
  }).catch((err) => {
30416
- log13.warn("Failed to update session history dismissedAt: %s", err);
30645
+ log14.warn("Failed to update session history dismissedAt: %s", err);
30417
30646
  });
30418
30647
  }
30419
30648
  ackNotificationInput(tabId, seq) {
@@ -30431,7 +30660,7 @@ var StatusManager = class _StatusManager {
30431
30660
  if (!entry) return { recovered: false, reason: "no-entry" };
30432
30661
  if (entry.cliState !== "unknown") return { recovered: false, reason: "not-unknown" };
30433
30662
  const content = await capturePaneAtWidth(entry.tmuxSession, 120, 50).catch((err) => {
30434
- log13.warn("recoverUnknownIfPending capture failed: %s", err);
30663
+ log14.warn("recoverUnknownIfPending capture failed: %s", err);
30435
30664
  return null;
30436
30665
  });
30437
30666
  if (!content) return { recovered: false, reason: "capture-failed" };
@@ -30557,7 +30786,7 @@ var StatusManager = class _StatusManager {
30557
30786
  const entry = this.tabs.get(tabId);
30558
30787
  if (entry && (entry.cliState === "busy" || entry.cliState === "needs-input") && entry.lastUserMessage) {
30559
30788
  this.saveSessionHistory(tabId, entry, entry.busySince, true).catch((err) => {
30560
- log13.warn("Failed to save cancelled session history: %s", err);
30789
+ log14.warn("Failed to save cancelled session history: %s", err);
30561
30790
  });
30562
30791
  }
30563
30792
  this.stopJsonlWatch(tabId);
@@ -30662,7 +30891,7 @@ var StatusManager = class _StatusManager {
30662
30891
  if (cwd) {
30663
30892
  const candidate = `${cwdToProjectPath(cwd)}/${tab.claudeSessionId}.jsonl`;
30664
30893
  try {
30665
- await import_promises12.default.access(candidate);
30894
+ await import_promises13.default.access(candidate);
30666
30895
  jsonlPath = candidate;
30667
30896
  } catch {
30668
30897
  }
@@ -30677,8 +30906,8 @@ var StatusManager = class _StatusManager {
30677
30906
  if (!jsonlPath) {
30678
30907
  const panePid = await getSessionPanePid(tmuxSession);
30679
30908
  if (panePid) {
30680
- const session = await detectActiveSession(panePid);
30681
- jsonlPath = session.jsonlPath;
30909
+ const { info } = await detectAnyActiveSession(panePid);
30910
+ jsonlPath = info.jsonlPath;
30682
30911
  }
30683
30912
  }
30684
30913
  if (!jsonlPath) return;
@@ -30692,7 +30921,7 @@ var StatusManager = class _StatusManager {
30692
30921
  const existing = this.jsonlWatchers.get(tabId);
30693
30922
  if (existing?.jsonlPath === jsonlPath) return;
30694
30923
  if (existing) this.stopJsonlWatch(tabId);
30695
- log13.debug("startJsonlWatch tabId=%s path=%s", tabId, jsonlPath);
30924
+ log14.debug("startJsonlWatch tabId=%s path=%s", tabId, jsonlPath);
30696
30925
  try {
30697
30926
  const watcher = (0, import_fs3.watch)(jsonlPath, () => {
30698
30927
  const w = this.jsonlWatchers.get(tabId);
@@ -30713,7 +30942,7 @@ var StatusManager = class _StatusManager {
30713
30942
  stopJsonlWatch(tabId) {
30714
30943
  const w = this.jsonlWatchers.get(tabId);
30715
30944
  if (!w) return;
30716
- log13.debug("stopJsonlWatch tabId=%s", tabId);
30945
+ log14.debug("stopJsonlWatch tabId=%s", tabId);
30717
30946
  if (w.debounceTimer) clearTimeout(w.debounceTimer);
30718
30947
  try {
30719
30948
  w.watcher.close();
@@ -30809,140 +31038,21 @@ var StatusManager = class _StatusManager {
30809
31038
  if (status === 410 || status === 404) {
30810
31039
  await removeSubscription(sub.endpoint);
30811
31040
  }
30812
- log13.warn("Web push send error: %s", status);
31041
+ log14.warn("Web push send error: %s", status);
30813
31042
  }
30814
31043
  }
30815
31044
  }
30816
31045
  };
30817
31046
  var getStatusManager = () => {
30818
- if (!g8.__ptStatusManager) {
31047
+ if (!g9.__ptStatusManager) {
30819
31048
  const manager = new StatusManager();
30820
- g8.__ptStatusManager = manager;
31049
+ g9.__ptStatusManager = manager;
30821
31050
  setLayoutReconciler({
30822
31051
  reconcileWorkspaceTabs: (wsId, validTabIds) => manager.reconcileWorkspaceTabs(wsId, validTabIds),
30823
31052
  removeWorkspaceTabs: (wsId) => manager.removeWorkspaceTabs(wsId)
30824
31053
  });
30825
31054
  }
30826
- return g8.__ptStatusManager;
30827
- };
30828
-
30829
- // src/lib/hook-settings.ts
30830
- var import_promises13 = __toESM(require("fs/promises"));
30831
- var import_path16 = __toESM(require("path"));
30832
- var import_os12 = __toESM(require("os"));
30833
- init_logger();
30834
- var log14 = createLogger("hooks");
30835
- var BASE_DIR8 = import_path16.default.join(import_os12.default.homedir(), ".purplemux");
30836
- var HOOKS_FILE = import_path16.default.join(BASE_DIR8, "hooks.json");
30837
- var PORT_FILE = import_path16.default.join(BASE_DIR8, "port");
30838
- var HOOK_SCRIPT = import_path16.default.join(BASE_DIR8, "status-hook.sh");
30839
- var HOOK_SETTINGS_PATH = HOOKS_FILE;
30840
- var HOOK_SCRIPT_CONTENT = `#!/bin/sh
30841
- EVENT="\${1:-poll}"
30842
- PORT_FILE="$HOME/.purplemux/port"
30843
- TOKEN_FILE="$HOME/.purplemux/cli-token"
30844
- [ -f "$PORT_FILE" ] || exit 0
30845
- [ -f "$TOKEN_FILE" ] || exit 0
30846
- PORT=$(cat "$PORT_FILE")
30847
- TOKEN=$(cat "$TOKEN_FILE")
30848
- SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null) || SESSION=""
30849
-
30850
- NOTIFICATION_TYPE=""
30851
- if [ "$EVENT" = "notification" ]; then
30852
- NOTIFICATION_TYPE=$(sed -n 's/.*"notification_type"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
30853
- fi
30854
-
30855
- PAYLOAD="{\\"event\\":\\"\${EVENT}\\",\\"session\\":\\"\${SESSION}\\""
30856
- if [ -n "$NOTIFICATION_TYPE" ]; then
30857
- PAYLOAD="\${PAYLOAD},\\"notificationType\\":\\"\${NOTIFICATION_TYPE}\\""
30858
- fi
30859
- PAYLOAD="\${PAYLOAD}}"
30860
-
30861
- curl -s -X POST -o /dev/null -H 'Content-Type: application/json' -H "x-pmux-token: \${TOKEN}" -d "$PAYLOAD" "http://localhost:\${PORT}/api/status/hook" 2>/dev/null
30862
- exit 0
30863
- `;
30864
- var hookEntry = (event, timeout = 3) => [
30865
- {
30866
- matcher: "",
30867
- hooks: [
30868
- {
30869
- type: "command",
30870
- command: `sh "${HOOK_SCRIPT}" ${event}`,
30871
- timeout
30872
- }
30873
- ]
30874
- }
30875
- ];
30876
- var buildHookSettings = () => ({
30877
- hooks: {
30878
- SessionStart: hookEntry("session-start"),
30879
- UserPromptSubmit: hookEntry("prompt-submit"),
30880
- Notification: hookEntry("notification"),
30881
- Stop: hookEntry("stop"),
30882
- StopFailure: hookEntry("stop"),
30883
- PreCompact: hookEntry("pre-compact"),
30884
- PostCompact: hookEntry("post-compact")
30885
- },
30886
- statusLine: {
30887
- type: "command",
30888
- command: `sh "${STATUSLINE_SCRIPT_PATH}"`
30889
- }
30890
- });
30891
- var ensureHookSettings = async (port) => {
30892
- await import_promises13.default.mkdir(BASE_DIR8, { recursive: true });
30893
- await import_promises13.default.writeFile(PORT_FILE, String(port), { mode: 384 });
30894
- try {
30895
- const existing = await import_promises13.default.readFile(HOOK_SCRIPT, "utf-8");
30896
- if (existing !== HOOK_SCRIPT_CONTENT) {
30897
- await import_promises13.default.writeFile(HOOK_SCRIPT, HOOK_SCRIPT_CONTENT, { mode: 493 });
30898
- }
30899
- } catch {
30900
- await import_promises13.default.writeFile(HOOK_SCRIPT, HOOK_SCRIPT_CONTENT, { mode: 493 });
30901
- }
30902
- try {
30903
- const existing = await import_promises13.default.readFile(STATUSLINE_SCRIPT_PATH, "utf-8");
30904
- if (existing !== STATUSLINE_SCRIPT_CONTENT) {
30905
- await import_promises13.default.writeFile(STATUSLINE_SCRIPT_PATH, STATUSLINE_SCRIPT_CONTENT, { mode: 493 });
30906
- }
30907
- } catch {
30908
- await import_promises13.default.writeFile(STATUSLINE_SCRIPT_PATH, STATUSLINE_SCRIPT_CONTENT, { mode: 493 });
30909
- }
30910
- const settings = buildHookSettings();
30911
- const content = JSON.stringify(settings, null, 2) + "\n";
30912
- try {
30913
- const existing = await import_promises13.default.readFile(HOOKS_FILE, "utf-8");
30914
- if (existing === content) return;
30915
- } catch {
30916
- }
30917
- await import_promises13.default.writeFile(HOOKS_FILE, content, { mode: 384 });
30918
- log14.debug(`${HOOKS_FILE} created`);
30919
- };
30920
- var removePortFile = async () => {
30921
- try {
30922
- await import_promises13.default.unlink(PORT_FILE);
30923
- } catch {
30924
- }
30925
- };
30926
-
30927
- // src/lib/claude-command.ts
30928
- init_claude_prompt();
30929
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
30930
- var isValidSessionId = (id) => typeof id === "string" && UUID_RE.test(id);
30931
- var buildClaudeFlags = async (workspaceId) => {
30932
- const skipPerms = await getDangerouslySkipPermissions();
30933
- const parts = [`--settings ${HOOK_SETTINGS_PATH}`];
30934
- if (workspaceId) {
30935
- parts.push(`--append-system-prompt-file ${getClaudePromptPath(workspaceId)}`);
30936
- }
30937
- if (skipPerms) parts.push("--dangerously-skip-permissions");
30938
- return parts.join(" ");
30939
- };
30940
- var buildResumeCommand = async (sessionId, workspaceId) => {
30941
- if (!isValidSessionId(sessionId)) {
30942
- throw new Error(`Invalid session ID format: ${sessionId}`);
30943
- }
30944
- const flags = await buildClaudeFlags(workspaceId);
30945
- return `claude --resume ${sessionId} ${flags}`;
31055
+ return g9.__ptStatusManager;
30946
31056
  };
30947
31057
 
30948
31058
  // src/lib/session-stats.ts
@@ -31086,10 +31196,10 @@ var findLastUserMessage = (entries) => {
31086
31196
  }
31087
31197
  return null;
31088
31198
  };
31089
- var subscribeAndUpdateSummary = async (ws, jsonlPath, sessionId, sessionName) => {
31090
- const jsonlSummary = await subscribeToFile(ws, jsonlPath, sessionId, sessionName);
31199
+ var subscribeAndUpdateSummary = async (ws, jsonlPath, sessionId, sessionName, provider) => {
31200
+ const jsonlSummary = await subscribeToFile(ws, jsonlPath, sessionId, sessionName, provider);
31091
31201
  const summary = await resolveClaudeSummary(sessionName, jsonlSummary);
31092
- await updateTabClaudeSummary(sessionName, summary).catch(() => {
31202
+ await updateTabAgentSummary(sessionName, provider, summary).catch(() => {
31093
31203
  });
31094
31204
  };
31095
31205
  var broadcastToWatcher = (watcherKey, msg) => {
@@ -31159,19 +31269,17 @@ var processFileChange = async (fw) => {
31159
31269
  if (partialReads.length > 0) {
31160
31270
  await Promise.all(partialReads);
31161
31271
  }
31162
- if (fw.sessionName) {
31163
- const lastMsg = findLastUserMessage(newEntries);
31164
- if (lastMsg) {
31165
- await updateTabLastUserMessage(fw.sessionName, lastMsg).catch(() => {
31166
- });
31167
- getStatusManager().notifyLastUserMessage(fw.sessionName, lastMsg);
31168
- }
31272
+ const lastMsg = findLastUserMessage(newEntries);
31273
+ if (lastMsg) {
31274
+ await updateTabLastUserMessage(fw.sessionName, lastMsg).catch(() => {
31275
+ });
31276
+ getStatusManager().notifyLastUserMessage(fw.sessionName, lastMsg);
31169
31277
  }
31170
- if (!fw.summaryResolved && fw.sessionName && newEntries.some((e) => e.type === "assistant-message")) {
31278
+ if (!fw.summaryResolved && newEntries.some((e) => e.type === "assistant-message")) {
31171
31279
  fw.summaryResolved = true;
31172
31280
  const summary = await resolveClaudeSummary(fw.sessionName, void 0);
31173
31281
  if (summary) {
31174
- await updateTabClaudeSummary(fw.sessionName, summary).catch(() => {
31282
+ await updateTabAgentSummary(fw.sessionName, fw.provider, summary).catch(() => {
31175
31283
  });
31176
31284
  }
31177
31285
  }
@@ -31264,7 +31372,7 @@ var computeInitMeta = (entries, fileSize, createdAtOverride, customTitle) => {
31264
31372
  customTitle
31265
31373
  };
31266
31374
  };
31267
- var subscribeToFile = async (ws, jsonlPath, sessionId, sessionName) => {
31375
+ var subscribeToFile = async (ws, jsonlPath, sessionId, sessionName, provider) => {
31268
31376
  if (!(0, import_fs6.existsSync)(jsonlPath)) {
31269
31377
  sendJson(ws, { type: "timeline:init", entries: [], sessionId: sessionId ?? "", totalEntries: 0, startByteOffset: 0, hasMore: false, jsonlPath });
31270
31378
  return void 0;
@@ -31284,7 +31392,8 @@ var subscribeToFile = async (ws, jsonlPath, sessionId, sessionName) => {
31284
31392
  connections: /* @__PURE__ */ new Set(),
31285
31393
  debounceTimer: null,
31286
31394
  retryCount: 0,
31287
- sessionName: sessionName ?? null,
31395
+ sessionName,
31396
+ provider,
31288
31397
  summaryResolved: false,
31289
31398
  processing: false,
31290
31399
  pendingChange: false,
@@ -31293,9 +31402,6 @@ var subscribeToFile = async (ws, jsonlPath, sessionId, sessionName) => {
31293
31402
  fileWatchers.set(jsonlPath, fw);
31294
31403
  }
31295
31404
  fw.connections.add(ws);
31296
- if (sessionName && !fw.sessionName) {
31297
- fw.sessionName = sessionName;
31298
- }
31299
31405
  const result = await readTailEntries(jsonlPath, MAX_INIT_ENTRIES);
31300
31406
  if (result.errorCount > 0) {
31301
31407
  sendJson(ws, {
@@ -31362,7 +31468,7 @@ var cancelJsonlWatcher = (sessionName) => {
31362
31468
  pendingJsonlWatchers.delete(sessionName);
31363
31469
  }
31364
31470
  };
31365
- var watchForJsonlFile = (sessionName, sessionId, cwd) => {
31471
+ var watchForJsonlFile = (sessionName, sessionId, cwd, provider) => {
31366
31472
  cancelJsonlWatcher(sessionName);
31367
31473
  const projectDir = cwdToProjectPath(cwd);
31368
31474
  const jsonlFilename = `${sessionId}.jsonl`;
@@ -31385,7 +31491,7 @@ var watchForJsonlFile = (sessionName, sessionId, cwd) => {
31385
31491
  const onJsonlFound = async () => {
31386
31492
  stop();
31387
31493
  pendingJsonlWatchers.delete(sessionName);
31388
- await updateTabClaudeSessionId(sessionName, sessionId).catch(() => {
31494
+ await updateTabAgentSessionId(sessionName, provider, sessionId).catch(() => {
31389
31495
  });
31390
31496
  const wsConns = getSessionConnections(sessionName);
31391
31497
  for (const c of wsConns) {
@@ -31394,7 +31500,7 @@ var watchForJsonlFile = (sessionName, sessionId, cwd) => {
31394
31500
  unsubscribeFromFile(c.ws, c.currentJsonlPath);
31395
31501
  }
31396
31502
  c.currentJsonlPath = expectedJsonlPath;
31397
- await subscribeAndUpdateSummary(c.ws, expectedJsonlPath, sessionId, sessionName);
31503
+ await subscribeAndUpdateSummary(c.ws, expectedJsonlPath, sessionId, sessionName, provider);
31398
31504
  }
31399
31505
  }
31400
31506
  };
@@ -31489,9 +31595,9 @@ var handleResumeMessage = async (ws, conn, payload) => {
31489
31595
  return;
31490
31596
  }
31491
31597
  const parsed = parseSessionName(tmuxSession);
31492
- const resumeCmd = await buildResumeCommand(sessionId, parsed?.wsId);
31598
+ const resumeCmd = await conn.provider.buildResumeCommand(sessionId, { workspaceId: parsed?.wsId });
31493
31599
  await sendKeys(tmuxSession, resumeCmd);
31494
- await updateTabClaudeSessionId(conn.sessionName, sessionId).catch(() => {
31600
+ await updateTabAgentSessionId(conn.sessionName, conn.provider, sessionId).catch(() => {
31495
31601
  });
31496
31602
  const jsonlPath = await resolveJsonlPath(tmuxSession, sessionId);
31497
31603
  sendJson(ws, {
@@ -31504,12 +31610,12 @@ var handleResumeMessage = async (ws, conn, payload) => {
31504
31610
  unsubscribeFromFile(ws, conn.currentJsonlPath);
31505
31611
  }
31506
31612
  conn.currentJsonlPath = jsonlPath;
31507
- await subscribeAndUpdateSummary(ws, jsonlPath, sessionId, conn.sessionName);
31613
+ await subscribeAndUpdateSummary(ws, jsonlPath, sessionId, conn.sessionName, conn.provider);
31508
31614
  } else {
31509
31615
  sendEmptyInit(ws, sessionId);
31510
31616
  const cwd = await getSessionCwd(tmuxSession);
31511
31617
  if (cwd) {
31512
- watchForJsonlFile(conn.sessionName, sessionId, cwd);
31618
+ watchForJsonlFile(conn.sessionName, sessionId, cwd, conn.provider);
31513
31619
  }
31514
31620
  }
31515
31621
  } catch (err) {
@@ -31530,6 +31636,12 @@ var handleTimelineConnection = async (ws, request) => {
31530
31636
  ws.close(1008, "Missing session parameter");
31531
31637
  return;
31532
31638
  }
31639
+ const panelType = url2.searchParams.get("panelType") ?? "claude-code";
31640
+ const provider = getProviderByPanelType(panelType);
31641
+ if (!provider) {
31642
+ ws.close(1008, "Unknown panel type");
31643
+ return;
31644
+ }
31533
31645
  const panePid = await getSessionPanePid(sessionName);
31534
31646
  if (!panePid) {
31535
31647
  sendEmptyInit(ws);
@@ -31550,6 +31662,7 @@ var handleTimelineConnection = async (ws, request) => {
31550
31662
  ws,
31551
31663
  sessionName,
31552
31664
  panePid,
31665
+ provider,
31553
31666
  heartbeatTimer,
31554
31667
  lastHeartbeat,
31555
31668
  currentJsonlPath: null,
@@ -31572,14 +31685,14 @@ var handleTimelineConnection = async (ws, request) => {
31572
31685
  unsubscribeFromFile(ws, conn.currentJsonlPath);
31573
31686
  }
31574
31687
  conn.currentJsonlPath = msg.jsonlPath;
31575
- await subscribeToFile(ws, msg.jsonlPath, void 0, conn.sessionName);
31688
+ await subscribeToFile(ws, msg.jsonlPath, void 0, conn.sessionName, conn.provider);
31576
31689
  } else if (msg.type === "timeline:unsubscribe") {
31577
31690
  if (conn.currentJsonlPath) {
31578
31691
  unsubscribeFromFile(ws, conn.currentJsonlPath);
31579
31692
  conn.currentJsonlPath = null;
31580
31693
  }
31581
31694
  } else if (msg.type === "timeline:resume" && msg.sessionId && msg.tmuxSession) {
31582
- if (!isValidSessionId(msg.sessionId)) {
31695
+ if (!conn.provider.isValidSessionId(msg.sessionId)) {
31583
31696
  sendJson(ws, { type: "timeline:resume-error", message: "Invalid session ID format" });
31584
31697
  } else {
31585
31698
  await handleResumeMessage(ws, conn, {
@@ -31597,61 +31710,61 @@ var handleTimelineConnection = async (ws, request) => {
31597
31710
  log16.error(`websocket error: ${err.message}`);
31598
31711
  cleanup3(conn);
31599
31712
  });
31600
- const claudeSessionId = url2.searchParams.get("claudeSessionId");
31601
- const sessionInfo = await detectActiveSession(panePid);
31713
+ const hintSessionId = url2.searchParams.get("agentSessionId") ?? url2.searchParams.get("claudeSessionId");
31714
+ const sessionInfo = await provider.detectActiveSession(panePid);
31602
31715
  if (conn.cleaned) return;
31603
31716
  if (sessionInfo.status === "not-installed") {
31604
- sendJson(ws, { type: "timeline:error", code: "not-installed", message: "Claude CLI is not installed" });
31717
+ sendJson(ws, { type: "timeline:error", code: "not-installed", message: `${provider.displayName} is not installed` });
31605
31718
  sendEmptyInit(ws);
31606
31719
  return;
31607
31720
  }
31608
- if (claudeSessionId && sessionInfo.status === "not-running") {
31609
- await updateTabClaudeSessionId(conn.sessionName, null).catch(() => {
31721
+ if (hintSessionId && sessionInfo.status === "not-running") {
31722
+ await updateTabAgentSessionId(conn.sessionName, provider, null).catch(() => {
31610
31723
  });
31611
- await updateTabClaudeSummary(conn.sessionName, null).catch(() => {
31724
+ await updateTabAgentSummary(conn.sessionName, provider, null).catch(() => {
31612
31725
  });
31613
31726
  }
31614
- const isClaudeStarting = sessionInfo.status === "not-running" && !claudeSessionId && await isClaudeRunning(panePid);
31727
+ const isAgentStarting = sessionInfo.status === "not-running" && !hintSessionId && await provider.isAgentRunning(panePid);
31615
31728
  if (sessionInfo.status === "running" && sessionInfo.sessionId) {
31616
31729
  sendJson(ws, {
31617
31730
  type: "timeline:session-changed",
31618
31731
  newSessionId: sessionInfo.sessionId,
31619
31732
  reason: "session-waiting"
31620
31733
  });
31621
- } else if (isClaudeStarting) {
31734
+ } else if (isAgentStarting) {
31622
31735
  sendJson(ws, {
31623
31736
  type: "timeline:session-changed",
31624
31737
  newSessionId: "",
31625
31738
  reason: "session-waiting"
31626
31739
  });
31627
31740
  }
31628
- const effectiveSessionId = sessionInfo.sessionId ?? claudeSessionId;
31741
+ const effectiveSessionId = sessionInfo.sessionId ?? hintSessionId;
31629
31742
  if (sessionInfo.jsonlPath) {
31630
31743
  conn.currentJsonlPath = sessionInfo.jsonlPath;
31631
31744
  if (sessionInfo.sessionId) {
31632
- await updateTabClaudeSessionId(conn.sessionName, sessionInfo.sessionId).catch(() => {
31745
+ await updateTabAgentSessionId(conn.sessionName, provider, sessionInfo.sessionId).catch(() => {
31633
31746
  });
31634
31747
  }
31635
- await subscribeAndUpdateSummary(ws, sessionInfo.jsonlPath, sessionInfo.sessionId ?? void 0, conn.sessionName);
31748
+ await subscribeAndUpdateSummary(ws, sessionInfo.jsonlPath, sessionInfo.sessionId ?? void 0, conn.sessionName, provider);
31636
31749
  } else if (effectiveSessionId) {
31637
31750
  if (sessionInfo.sessionId) {
31638
- await updateTabClaudeSessionId(conn.sessionName, sessionInfo.sessionId).catch(() => {
31751
+ await updateTabAgentSessionId(conn.sessionName, provider, sessionInfo.sessionId).catch(() => {
31639
31752
  });
31640
31753
  }
31641
31754
  const jsonlPath = await resolveJsonlPath(sessionName, effectiveSessionId);
31642
31755
  if (jsonlPath) {
31643
31756
  conn.currentJsonlPath = jsonlPath;
31644
- await subscribeAndUpdateSummary(ws, jsonlPath, effectiveSessionId, conn.sessionName);
31757
+ await subscribeAndUpdateSummary(ws, jsonlPath, effectiveSessionId, conn.sessionName, provider);
31645
31758
  } else {
31646
31759
  sendEmptyInit(ws, effectiveSessionId);
31647
31760
  }
31648
- } else if (!isClaudeStarting) {
31761
+ } else if (!isAgentStarting) {
31649
31762
  sendEmptyInit(ws);
31650
31763
  }
31651
31764
  if (conn.cleaned) return;
31652
31765
  const wsKey = sessionName;
31653
31766
  if (!sessionWatchers.has(wsKey)) {
31654
- const sw = watchSessionsDir(panePid, async (newInfo) => {
31767
+ const sw = provider.watchSessions(panePid, async (newInfo) => {
31655
31768
  const wsConns = getSessionConnections(sessionName);
31656
31769
  for (const c of wsConns) {
31657
31770
  if (newInfo.jsonlPath && newInfo.jsonlPath !== c.currentJsonlPath) {
@@ -31661,7 +31774,7 @@ var handleTimelineConnection = async (ws, request) => {
31661
31774
  }
31662
31775
  c.currentJsonlPath = newInfo.jsonlPath;
31663
31776
  if (newInfo.sessionId) {
31664
- await updateTabClaudeSessionId(sessionName, newInfo.sessionId).catch(() => {
31777
+ await updateTabAgentSessionId(sessionName, provider, newInfo.sessionId).catch(() => {
31665
31778
  });
31666
31779
  }
31667
31780
  sendJson(c.ws, {
@@ -31669,16 +31782,16 @@ var handleTimelineConnection = async (ws, request) => {
31669
31782
  newSessionId: newInfo.sessionId ?? "",
31670
31783
  reason: "new-session-started"
31671
31784
  });
31672
- await subscribeAndUpdateSummary(c.ws, newInfo.jsonlPath, newInfo.sessionId ?? void 0, sessionName);
31785
+ await subscribeAndUpdateSummary(c.ws, newInfo.jsonlPath, newInfo.sessionId ?? void 0, sessionName, provider);
31673
31786
  } else if (!newInfo.jsonlPath && newInfo.status === "not-running") {
31674
31787
  cancelJsonlWatcher(sessionName);
31675
31788
  if (c.currentJsonlPath) {
31676
31789
  unsubscribeFromFile(c.ws, c.currentJsonlPath);
31677
31790
  c.currentJsonlPath = null;
31678
31791
  }
31679
- await updateTabClaudeSessionId(sessionName, null).catch(() => {
31792
+ await updateTabAgentSessionId(sessionName, provider, null).catch(() => {
31680
31793
  });
31681
- await updateTabClaudeSummary(sessionName, null).catch(() => {
31794
+ await updateTabAgentSummary(sessionName, provider, null).catch(() => {
31682
31795
  });
31683
31796
  sendJson(c.ws, {
31684
31797
  type: "timeline:session-changed",
@@ -31689,7 +31802,7 @@ var handleTimelineConnection = async (ws, request) => {
31689
31802
  }
31690
31803
  if (newInfo.status === "running" && !newInfo.jsonlPath) {
31691
31804
  if (newInfo.sessionId) {
31692
- await updateTabClaudeSessionId(sessionName, newInfo.sessionId).catch(() => {
31805
+ await updateTabAgentSessionId(sessionName, provider, newInfo.sessionId).catch(() => {
31693
31806
  });
31694
31807
  }
31695
31808
  for (const c of wsConns) {
@@ -31713,7 +31826,7 @@ var handleTimelineConnection = async (ws, request) => {
31713
31826
  const hasActiveSubscription = wsConns.some((c) => c.currentJsonlPath !== null);
31714
31827
  if (!hasActiveSubscription && wsConns.length > 0) {
31715
31828
  cancelJsonlWatcher(sessionName);
31716
- watchForJsonlFile(sessionName, newInfo.sessionId, newInfo.cwd);
31829
+ watchForJsonlFile(sessionName, newInfo.sessionId, newInfo.cwd, provider);
31717
31830
  }
31718
31831
  }
31719
31832
  }
@@ -31721,13 +31834,13 @@ var handleTimelineConnection = async (ws, request) => {
31721
31834
  sessionWatchers.set(wsKey, sw);
31722
31835
  }
31723
31836
  if (sessionInfo.status === "running" && !sessionInfo.jsonlPath && sessionInfo.sessionId && sessionInfo.cwd) {
31724
- watchForJsonlFile(sessionName, sessionInfo.sessionId, sessionInfo.cwd);
31837
+ watchForJsonlFile(sessionName, sessionInfo.sessionId, sessionInfo.cwd, provider);
31725
31838
  }
31726
- if (isClaudeStarting) {
31727
- const recheckInfo = await detectActiveSession(panePid);
31839
+ if (isAgentStarting) {
31840
+ const recheckInfo = await provider.detectActiveSession(panePid);
31728
31841
  if (conn.cleaned) return;
31729
31842
  if (recheckInfo.status === "running" && recheckInfo.sessionId && !conn.currentJsonlPath) {
31730
- await updateTabClaudeSessionId(sessionName, recheckInfo.sessionId).catch(() => {
31843
+ await updateTabAgentSessionId(sessionName, provider, recheckInfo.sessionId).catch(() => {
31731
31844
  });
31732
31845
  if (recheckInfo.jsonlPath) {
31733
31846
  conn.currentJsonlPath = recheckInfo.jsonlPath;
@@ -31736,7 +31849,7 @@ var handleTimelineConnection = async (ws, request) => {
31736
31849
  newSessionId: recheckInfo.sessionId,
31737
31850
  reason: "new-session-started"
31738
31851
  });
31739
- await subscribeAndUpdateSummary(ws, recheckInfo.jsonlPath, recheckInfo.sessionId, sessionName);
31852
+ await subscribeAndUpdateSummary(ws, recheckInfo.jsonlPath, recheckInfo.sessionId, sessionName, provider);
31740
31853
  } else if (recheckInfo.cwd) {
31741
31854
  sendJson(ws, {
31742
31855
  type: "timeline:session-changed",
@@ -31744,7 +31857,7 @@ var handleTimelineConnection = async (ws, request) => {
31744
31857
  reason: "session-waiting"
31745
31858
  });
31746
31859
  sendEmptyInit(ws, recheckInfo.sessionId, true);
31747
- watchForJsonlFile(sessionName, recheckInfo.sessionId, recheckInfo.cwd);
31860
+ watchForJsonlFile(sessionName, recheckInfo.sessionId, recheckInfo.cwd, provider);
31748
31861
  }
31749
31862
  } else {
31750
31863
  sendEmptyInit(ws, "", true);
@@ -31841,7 +31954,7 @@ var import_fs8 = __toESM(require("fs"));
31841
31954
  var import_path20 = __toESM(require("path"));
31842
31955
  var import_os15 = __toESM(require("os"));
31843
31956
  var TOKEN_FILE = import_path20.default.join(import_os15.default.homedir(), ".purplemux", "cli-token");
31844
- var g9 = globalThis;
31957
+ var g10 = globalThis;
31845
31958
  var readTokenFile = () => {
31846
31959
  try {
31847
31960
  const value = import_fs8.default.readFileSync(TOKEN_FILE, "utf-8").trim();
@@ -31858,14 +31971,14 @@ var writeTokenFile = (value) => {
31858
31971
  }
31859
31972
  };
31860
31973
  var getCliToken = () => {
31861
- if (g9.__ptCliToken) return g9.__ptCliToken;
31974
+ if (g10.__ptCliToken) return g10.__ptCliToken;
31862
31975
  const existing = readTokenFile();
31863
31976
  if (existing) {
31864
- g9.__ptCliToken = existing;
31977
+ g10.__ptCliToken = existing;
31865
31978
  return existing;
31866
31979
  }
31867
31980
  const fresh = (0, import_crypto2.randomBytes)(32).toString("hex");
31868
- g9.__ptCliToken = fresh;
31981
+ g10.__ptCliToken = fresh;
31869
31982
  writeTokenFile(fresh);
31870
31983
  return fresh;
31871
31984
  };
@@ -32011,14 +32124,17 @@ var findAutoResumeTargets = async () => {
32011
32124
  if (!layout) continue;
32012
32125
  const tabs = collectAllTabs(layout.root);
32013
32126
  for (const tab of tabs) {
32014
- if (tab.panelType === "claude-code" && tab.claudeSessionId) {
32015
- targets.push({
32016
- workspaceId: ws.id,
32017
- tabId: tab.id,
32018
- tmuxSession: tab.sessionName,
32019
- claudeSessionId: tab.claudeSessionId
32020
- });
32021
- }
32127
+ const provider = getProviderByPanelType(tab.panelType);
32128
+ if (!provider) continue;
32129
+ const sessionId = provider.readSessionId(tab);
32130
+ if (!sessionId) continue;
32131
+ targets.push({
32132
+ workspaceId: ws.id,
32133
+ tabId: tab.id,
32134
+ tmuxSession: tab.sessionName,
32135
+ sessionId,
32136
+ provider
32137
+ });
32022
32138
  }
32023
32139
  }
32024
32140
  return targets;
@@ -32032,15 +32148,18 @@ var sendResumeKeys = async (target) => {
32032
32148
  return false;
32033
32149
  }
32034
32150
  if (!SAFE_SHELLS2.has(command)) {
32035
- if (command === "claude" || command === "node") {
32036
- log19.debug(`Claude already running, skip: ${target.tmuxSession}`);
32151
+ const runningProvider = getProviderByProcessName(command);
32152
+ if (runningProvider && runningProvider.id === target.provider.id) {
32153
+ log19.debug(`${target.provider.displayName} already running, skip: ${target.tmuxSession}`);
32037
32154
  return true;
32038
32155
  }
32039
32156
  log19.debug(`Non-shell process running (${command}), skip: ${target.tmuxSession}`);
32040
32157
  return false;
32041
32158
  }
32042
- const resumeCmd = await buildResumeCommand(target.claudeSessionId, target.workspaceId);
32043
- log19.debug(`Sending resume: ${target.tmuxSession} \u2192 ${target.claudeSessionId}`);
32159
+ const resumeCmd = await target.provider.buildResumeCommand(target.sessionId, {
32160
+ workspaceId: target.workspaceId
32161
+ });
32162
+ log19.debug(`Sending resume: ${target.tmuxSession} \u2192 ${target.sessionId}`);
32044
32163
  await sendKeys(target.tmuxSession, resumeCmd);
32045
32164
  return true;
32046
32165
  } catch (err) {
@@ -32380,7 +32499,7 @@ init_logger();
32380
32499
  // package.json
32381
32500
  var package_default = {
32382
32501
  name: "purplemux",
32383
- version: "0.2.3",
32502
+ version: "0.2.5",
32384
32503
  description: "Manage multiple Claude Code sessions from your browser",
32385
32504
  license: "MIT",
32386
32505
  author: "subicura",
@@ -32417,6 +32536,8 @@ var package_default = {
32417
32536
  scripts: {
32418
32537
  dev: "tsx watch server.ts",
32419
32538
  build: "next build && node scripts/post-build.js && tsup",
32539
+ "build:landing": "eleventy",
32540
+ "dev:landing": "eleventy --serve",
32420
32541
  "build:server": "tsup",
32421
32542
  "build:electron:main": "tsup --config electron/tsup.config.ts",
32422
32543
  "build:electron": "next build && node scripts/post-build.js --electron && tsup && pnpm build:electron:main",
@@ -32485,6 +32606,7 @@ var package_default = {
32485
32606
  zustand: "^5.0.12"
32486
32607
  },
32487
32608
  devDependencies: {
32609
+ "@11ty/eleventy": "^3.1.5",
32488
32610
  "@electron/rebuild": "^4.0.3",
32489
32611
  "@tailwindcss/postcss": "^4",
32490
32612
  "@types/node": "^24.12.0",
@@ -32513,7 +32635,7 @@ var package_default = {
32513
32635
  hono: ">=4.12.14",
32514
32636
  "@hono/node-server": ">=1.19.13",
32515
32637
  lodash: ">=4.18.0",
32516
- "@xmldom/xmldom": "^0.8.12",
32638
+ "@xmldom/xmldom": "^0.8.13",
32517
32639
  "picomatch@>=2.0.0 <3.0.0": ">=2.3.2",
32518
32640
  "picomatch@>=4.0.0 <5.0.0": ">=4.0.4"
32519
32641
  }