claude-mux 0.26.2 → 0.26.4

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 (157) hide show
  1. package/dist/server/ws-handlers.d.ts.map +1 -1
  2. package/dist/server/ws-handlers.js +37 -6
  3. package/dist/server/ws-handlers.js.map +1 -1
  4. package/dist/tmux/pane.d.ts +13 -3
  5. package/dist/tmux/pane.d.ts.map +1 -1
  6. package/dist/tmux/pane.js +113 -36
  7. package/dist/tmux/pane.js.map +1 -1
  8. package/dist/transcript/context-peek.d.ts +18 -0
  9. package/dist/transcript/context-peek.d.ts.map +1 -1
  10. package/dist/transcript/context-peek.js +59 -12
  11. package/dist/transcript/context-peek.js.map +1 -1
  12. package/dist/types/ws-messages.d.ts +6 -0
  13. package/dist/types/ws-messages.d.ts.map +1 -1
  14. package/dist/types/ws-messages.js +2 -0
  15. package/dist/types/ws-messages.js.map +1 -1
  16. package/dist/utils/version.d.ts +1 -1
  17. package/dist/utils/version.js +1 -1
  18. package/dist/web/client/_app/immutable/assets/0.CiLJk_Xe.css +1 -0
  19. package/{web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.XJ3XhAQU.css → dist/web/client/_app/immutable/assets/3.DIECCPxi.css} +1 -1
  20. package/dist/web/client/_app/immutable/chunks/Bjgls5C2.js +2 -0
  21. package/{web/.svelte-kit/output/client/_app/immutable/chunks/Cotx9uI_.js → dist/web/client/_app/immutable/chunks/C8V5fK-3.js} +1 -1
  22. package/dist/web/client/_app/immutable/chunks/DnC9WjQh.js +57 -0
  23. package/dist/web/client/_app/immutable/chunks/MhGpinwS.js +1 -0
  24. package/dist/web/client/_app/immutable/chunks/cJslalWy.js +1 -0
  25. package/dist/web/client/_app/immutable/entry/{app.DXHW0aPL.js → app.tijMyuHe.js} +2 -2
  26. package/dist/web/client/_app/immutable/entry/start.BjUUmuae.js +1 -0
  27. package/dist/web/client/_app/immutable/nodes/{0.DAnv2asW.js → 0.Dh-WcEW1.js} +1 -1
  28. package/dist/web/client/_app/immutable/nodes/{1.CU8f4oNB.js → 1.haoM4e9N.js} +1 -1
  29. package/dist/web/client/_app/immutable/nodes/{2.BYpvCgtu.js → 2.DtC9KdX8.js} +1 -1
  30. package/dist/web/client/_app/immutable/nodes/3.FZTTKJCk.js +168 -0
  31. package/dist/web/client/_app/version.json +1 -1
  32. package/dist/web/server/chunks/{0-C-AAPmon.js → 0-Cw5iP0WY.js} +9 -9
  33. package/dist/web/server/chunks/{0-C-AAPmon.js.map → 0-Cw5iP0WY.js.map} +1 -1
  34. package/dist/web/server/chunks/{1-T_dogl8W.js → 1-CR_g4jt5.js} +3 -3
  35. package/dist/web/server/chunks/{1-T_dogl8W.js.map → 1-CR_g4jt5.js.map} +1 -1
  36. package/dist/web/server/chunks/{2-FlchE_4u.js → 2-Cy0TJi3N.js} +7 -7
  37. package/dist/web/server/chunks/{2-FlchE_4u.js.map → 2-Cy0TJi3N.js.map} +1 -1
  38. package/dist/web/server/chunks/{3-U2bTntXU.js → 3-D9Ui86YT.js} +7 -7
  39. package/dist/web/server/chunks/{3-U2bTntXU.js.map → 3-D9Ui86YT.js.map} +1 -1
  40. package/dist/web/server/chunks/{_layout.svelte-Ddn9Wu-V.js → _layout.svelte-DZ2sqwz3.js} +4 -4
  41. package/dist/web/server/chunks/{_layout.svelte-Ddn9Wu-V.js.map → _layout.svelte-DZ2sqwz3.js.map} +1 -1
  42. package/dist/web/server/chunks/{_page.svelte-_F3qltju.js → _page.svelte--yq9E8Jb.js} +2 -2
  43. package/dist/web/server/chunks/{_page.svelte-_F3qltju.js.map → _page.svelte--yq9E8Jb.js.map} +1 -1
  44. package/dist/web/server/chunks/{_server.ts-CNU4yPZZ.js → _server.ts-BCCIAioG.js} +4 -2
  45. package/dist/web/server/chunks/_server.ts-BCCIAioG.js.map +1 -0
  46. package/dist/web/server/chunks/{_server.ts-CtsPyICr.js → _server.ts-BMZtxwLP.js} +2 -2
  47. package/dist/web/server/chunks/{_server.ts-CtsPyICr.js.map → _server.ts-BMZtxwLP.js.map} +1 -1
  48. package/dist/web/server/chunks/{_server.ts-BBrtrcEt.js → _server.ts-CONr9rjv.js} +2 -2
  49. package/dist/web/server/chunks/{_server.ts-BBrtrcEt.js.map → _server.ts-CONr9rjv.js.map} +1 -1
  50. package/dist/web/server/chunks/{_server.ts-fnuGtMqr.js → _server.ts-CSKVHlMn.js} +3 -3
  51. package/dist/web/server/chunks/{_server.ts-fnuGtMqr.js.map → _server.ts-CSKVHlMn.js.map} +1 -1
  52. package/dist/web/server/chunks/{_server.ts-Df32fD_Q.js → _server.ts-D1PwUVXn.js} +2 -2
  53. package/dist/web/server/chunks/{_server.ts-Df32fD_Q.js.map → _server.ts-D1PwUVXn.js.map} +1 -1
  54. package/dist/web/server/chunks/{_server.ts-C00ejke7.js → _server.ts-D4xa8gs1.js} +2 -2
  55. package/dist/web/server/chunks/{_server.ts-C00ejke7.js.map → _server.ts-D4xa8gs1.js.map} +1 -1
  56. package/dist/web/server/chunks/{_server.ts-C6MJsvPN.js → _server.ts-DxjUBscT.js} +3 -3
  57. package/dist/web/server/chunks/{_server.ts-C6MJsvPN.js.map → _server.ts-DxjUBscT.js.map} +1 -1
  58. package/dist/web/server/chunks/{button-C1GVS_oY.js → button-BxVvCjdl.js} +24 -4
  59. package/dist/web/server/chunks/{button-C1GVS_oY.js.map → button-BxVvCjdl.js.map} +1 -1
  60. package/dist/web/server/chunks/{hooks.server-DG_lyHkY.js → hooks.server-B8dJh24b.js} +3 -3
  61. package/dist/web/server/chunks/{hooks.server-DG_lyHkY.js.map → hooks.server-B8dJh24b.js.map} +1 -1
  62. package/dist/web/server/chunks/{ws-handlers-BQ2RtlNl.js → ws-handlers-fSFiSfwn.js} +150 -43
  63. package/dist/web/server/chunks/ws-handlers-fSFiSfwn.js.map +1 -0
  64. package/dist/web/server/chunks/{ws-managers-DLQiiQnX.js → ws-managers-Cv1gfcBO.js} +2 -2
  65. package/dist/web/server/chunks/{ws-managers-DLQiiQnX.js.map → ws-managers-Cv1gfcBO.js.map} +1 -1
  66. package/dist/web/server/index.js +2 -2
  67. package/dist/web/server/index.js.map +1 -1
  68. package/dist/web/server/manifest.js +17 -17
  69. package/dist/web/server/manifest.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/server/ws-handlers.ts +35 -6
  72. package/src/tmux/pane.ts +124 -33
  73. package/src/transcript/context-peek.ts +71 -13
  74. package/src/types/ws-messages.ts +2 -0
  75. package/src/utils/version.ts +1 -1
  76. package/tests/tmux/activity-line.test.ts +47 -0
  77. package/tests/tmux/prompt-options.test.ts +49 -4
  78. package/tests/transcript/title-peek.test.ts +54 -0
  79. package/web/.svelte-kit/adapter-bun/.vite/manifest.json +4 -8
  80. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_layout.6tlxP3iE.css +1 -0
  81. package/{dist/web/client/_app/immutable/assets/3.XJ3XhAQU.css → web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.DIECCPxi.css} +1 -1
  82. package/web/.svelte-kit/adapter-bun/chunks/button.js +24 -1
  83. package/web/.svelte-kit/adapter-bun/chunks/internal2.js +1 -1
  84. package/web/.svelte-kit/adapter-bun/chunks/ws-handlers.js +137 -40
  85. package/web/.svelte-kit/adapter-bun/chunks/ws-managers.js +1 -1
  86. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/projects/new-session/_server.ts.js +3 -1
  87. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_server.ts.js +1 -1
  88. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/settings/_server.ts.js +1 -1
  89. package/web/.svelte-kit/adapter-bun/entries/pages/_layout.svelte.js +2 -2
  90. package/web/.svelte-kit/adapter-bun/entries/pages/session/_target_/_page.svelte.js +2 -1
  91. package/web/.svelte-kit/adapter-bun/manifest-full.js +1 -1
  92. package/web/.svelte-kit/adapter-bun/manifest.js +1 -1
  93. package/web/.svelte-kit/adapter-bun/nodes/0.js +2 -2
  94. package/web/.svelte-kit/adapter-bun/nodes/1.js +1 -1
  95. package/web/.svelte-kit/adapter-bun/nodes/2.js +1 -1
  96. package/web/.svelte-kit/adapter-bun/nodes/3.js +2 -2
  97. package/web/.svelte-kit/generated/server/internal.js +1 -1
  98. package/web/.svelte-kit/output/client/.vite/manifest.json +59 -59
  99. package/web/.svelte-kit/output/client/_app/immutable/assets/0.CiLJk_Xe.css +1 -0
  100. package/web/.svelte-kit/output/client/_app/immutable/assets/{3.XJ3XhAQU.css → 3.DIECCPxi.css} +1 -1
  101. package/web/.svelte-kit/output/client/_app/immutable/chunks/Bjgls5C2.js +2 -0
  102. package/{dist/web/client/_app/immutable/chunks/Cotx9uI_.js → web/.svelte-kit/output/client/_app/immutable/chunks/C8V5fK-3.js} +1 -1
  103. package/web/.svelte-kit/output/client/_app/immutable/chunks/DnC9WjQh.js +57 -0
  104. package/web/.svelte-kit/output/client/_app/immutable/chunks/MhGpinwS.js +1 -0
  105. package/web/.svelte-kit/output/client/_app/immutable/chunks/cJslalWy.js +1 -0
  106. package/web/.svelte-kit/output/client/_app/immutable/entry/{app.DXHW0aPL.js → app.tijMyuHe.js} +2 -2
  107. package/web/.svelte-kit/output/client/_app/immutable/entry/start.BjUUmuae.js +1 -0
  108. package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.DAnv2asW.js → 0.Dh-WcEW1.js} +1 -1
  109. package/web/.svelte-kit/output/client/_app/immutable/nodes/{1.CU8f4oNB.js → 1.haoM4e9N.js} +1 -1
  110. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.BYpvCgtu.js → 2.DtC9KdX8.js} +1 -1
  111. package/web/.svelte-kit/output/client/_app/immutable/nodes/3.FZTTKJCk.js +168 -0
  112. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  113. package/web/.svelte-kit/output/server/.vite/manifest.json +4 -8
  114. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.6tlxP3iE.css +1 -0
  115. package/web/.svelte-kit/output/server/_app/immutable/assets/{_page.XJ3XhAQU.css → _page.DIECCPxi.css} +1 -1
  116. package/web/.svelte-kit/output/server/chunks/button.js +24 -1
  117. package/web/.svelte-kit/output/server/chunks/internal2.js +1 -1
  118. package/web/.svelte-kit/output/server/chunks/ws-handlers.js +137 -40
  119. package/web/.svelte-kit/output/server/chunks/ws-managers.js +1 -1
  120. package/web/.svelte-kit/output/server/entries/endpoints/api/projects/new-session/_server.ts.js +3 -1
  121. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_server.ts.js +1 -1
  122. package/web/.svelte-kit/output/server/entries/endpoints/api/settings/_server.ts.js +1 -1
  123. package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +2 -2
  124. package/web/.svelte-kit/output/server/entries/pages/session/_target_/_page.svelte.js +2 -1
  125. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  126. package/web/.svelte-kit/output/server/manifest.js +1 -1
  127. package/web/.svelte-kit/output/server/nodes/0.js +2 -2
  128. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  129. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  130. package/web/.svelte-kit/output/server/nodes/3.js +2 -2
  131. package/web/src/lib/actions/longPress.ts +52 -6
  132. package/web/src/lib/components/AllSessionsPanel.svelte +12 -3
  133. package/web/src/lib/stores/websocket-base.svelte.ts +24 -1
  134. package/web/src/routes/api/projects/new-session/+server.ts +3 -0
  135. package/web/src/routes/session/[target]/+page.svelte +60 -12
  136. package/dist/web/client/_app/immutable/assets/0.DwaaTdPO.css +0 -1
  137. package/dist/web/client/_app/immutable/chunks/1pIWnoD_.js +0 -1
  138. package/dist/web/client/_app/immutable/chunks/DfoR1zCV.js +0 -1
  139. package/dist/web/client/_app/immutable/chunks/DmEI2TOa.js +0 -57
  140. package/dist/web/client/_app/immutable/chunks/DtVU-s3j.js +0 -2
  141. package/dist/web/client/_app/immutable/entry/start.CchjowOg.js +0 -1
  142. package/dist/web/client/_app/immutable/nodes/3.DuMzeRg3.js +0 -168
  143. package/dist/web/server/chunks/_server.ts-CNU4yPZZ.js.map +0 -1
  144. package/dist/web/server/chunks/geometry-CUMMOI9q.js +0 -46
  145. package/dist/web/server/chunks/geometry-CUMMOI9q.js.map +0 -1
  146. package/dist/web/server/chunks/ws-handlers-BQ2RtlNl.js.map +0 -1
  147. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_layout.Bpy37C6o.css +0 -1
  148. package/web/.svelte-kit/adapter-bun/chunks/geometry.js +0 -32
  149. package/web/.svelte-kit/output/client/_app/immutable/assets/0.DwaaTdPO.css +0 -1
  150. package/web/.svelte-kit/output/client/_app/immutable/chunks/1pIWnoD_.js +0 -1
  151. package/web/.svelte-kit/output/client/_app/immutable/chunks/DfoR1zCV.js +0 -1
  152. package/web/.svelte-kit/output/client/_app/immutable/chunks/DmEI2TOa.js +0 -57
  153. package/web/.svelte-kit/output/client/_app/immutable/chunks/DtVU-s3j.js +0 -2
  154. package/web/.svelte-kit/output/client/_app/immutable/entry/start.CchjowOg.js +0 -1
  155. package/web/.svelte-kit/output/client/_app/immutable/nodes/3.DuMzeRg3.js +0 -168
  156. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.Bpy37C6o.css +0 -1
  157. package/web/.svelte-kit/output/server/chunks/geometry.js +0 -32
@@ -1,6 +1,6 @@
1
1
  import "./exports-piA4c_uA.js";
2
- import { c as parseWsPath, s as handleWsMessage, u as resizePane } from "./ws-handlers-BQ2RtlNl.js";
3
- import { i as transcriptWsManager, n as sessionsWsManager, r as terminalWsManager } from "./ws-managers-DLQiiQnX.js";
2
+ import { c as parseWsPath, s as handleWsMessage, u as resizePane } from "./ws-handlers-fSFiSfwn.js";
3
+ import { i as transcriptWsManager, n as sessionsWsManager, r as terminalWsManager } from "./ws-managers-Cv1gfcBO.js";
4
4
  //#region .svelte-kit/adapter-bun/entries/hooks.server.js
5
5
  const wsDataMap = /* @__PURE__ */ new WeakMap();
6
6
  const CORS_ORIGIN = /^https?:\/\/(?:[a-z0-9-]+\.)*[a-z0-9-]+\.ts\.net(?::\d+)?$|^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d+)?$/i;
@@ -98,4 +98,4 @@ const websocket = {
98
98
  //#endregion
99
99
  export { handle, websocket };
100
100
 
101
- //# sourceMappingURL=hooks.server-DG_lyHkY.js.map
101
+ //# sourceMappingURL=hooks.server-B8dJh24b.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.server-DG_lyHkY.js","names":[],"sources":["../../../../web/.svelte-kit/adapter-bun/entries/hooks.server.js"],"sourcesContent":["import \"@sveltejs/kit\";\nimport { p as parseWsPath, h as handleWsMessage, r as resizePane } from \"../chunks/ws-handlers.js\";\nimport { s as sessionsWsManager, t as terminalWsManager, a as transcriptWsManager } from \"../chunks/ws-managers.js\";\nconst wsDataMap = /* @__PURE__ */ new WeakMap();\nconst CORS_ORIGIN = /^https?:\\/\\/(?:[a-z0-9-]+\\.)*[a-z0-9-]+\\.ts\\.net(?::\\d+)?$|^https?:\\/\\/(?:localhost|127\\.0\\.0\\.1)(?::\\d+)?$/i;\nfunction corsHeaders(origin) {\n return {\n \"Access-Control-Allow-Origin\": origin,\n \"Access-Control-Allow-Methods\": \"GET, POST, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"600\",\n Vary: \"Origin\"\n };\n}\nconst handle = async ({ event, resolve }) => {\n const origin = event.request.headers.get(\"origin\");\n const crossSite = !!origin && origin !== event.url.origin && CORS_ORIGIN.test(origin);\n if (crossSite && event.request.method === \"OPTIONS\" && event.url.pathname.startsWith(\"/api/\")) {\n return new Response(null, { status: 204, headers: corsHeaders(origin) });\n }\n const connectionHeader = event.request.headers.get(\"connection\");\n const upgradeHeader = event.request.headers.get(\"upgrade\");\n if (connectionHeader?.toLowerCase().includes(\"upgrade\") && upgradeHeader?.toLowerCase() === \"websocket\") {\n const url = new URL(event.request.url);\n const parsed = parseWsPath(url.pathname);\n if (parsed) {\n await event.platform.server.upgrade(event.platform.request, {\n data: parsed\n });\n return new Response(null, { status: 101 });\n }\n }\n const response = await resolve(event);\n if (crossSite && event.url.pathname.startsWith(\"/api/\")) {\n for (const [name, value] of Object.entries(corsHeaders(origin))) response.headers.set(name, value);\n }\n return response;\n};\nconst websocket = {\n /**\n * Transcript snapshots are hundreds of kilobytes of JSON, and the phone\n * reading them is usually on the far side of a tailnet. The payloads are\n * highly repetitive, so deflate takes them down by roughly an order of\n * magnitude; the terminal's small frames pay a negligible amount of CPU.\n */\n perMessageDeflate: true,\n open(ws) {\n const data = ws.data;\n if (!data) return;\n const client = {\n send: (msg) => ws.send(msg),\n isOpen: () => ws.readyState === WebSocket.OPEN,\n close: () => ws.close(),\n getBufferedAmount: () => ws.bufferedAmount\n };\n wsDataMap.set(ws, { ...data, client });\n let accepted = false;\n if (data.type === \"sessions\") {\n accepted = sessionsWsManager.addClient(client);\n } else if (data.type === \"terminal\" && data.target) {\n accepted = terminalWsManager.addClient(client, data.target);\n } else if (data.type === \"transcript\" && data.target) {\n accepted = transcriptWsManager.addClient(client, data.target);\n }\n if (!accepted) {\n ws.close(1013, \"Max clients reached\");\n }\n },\n message(ws, message) {\n const msgStr = message.toString();\n const data = wsDataMap.get(ws);\n const target = data?.target;\n let handlers;\n if (target && data?.type === \"terminal\") {\n handlers = {\n resize: (cols, rows) => resizePane(target, cols, rows),\n historyRequest: (before, count) => terminalWsManager.requestHistory(data.client, target, before, count)\n };\n } else if (target && data?.type === \"transcript\") {\n handlers = {\n historyRequest: (before, count) => transcriptWsManager.requestHistory(data.client, target, before, count)\n };\n }\n const response = handleWsMessage(msgStr, handlers);\n if (response === \"pong\") {\n ws.send(\"pong\");\n }\n },\n close(ws) {\n const data = wsDataMap.get(ws);\n if (!data) return;\n if (data.type === \"sessions\") {\n sessionsWsManager.removeClient(data.client);\n } else if (data.type === \"terminal\") {\n terminalWsManager.removeClient(data.client, data.target);\n } else if (data.type === \"transcript\") {\n transcriptWsManager.removeClient(data.client, data.target);\n }\n wsDataMap.delete(ws);\n },\n error(ws, error) {\n const data = wsDataMap.get(ws);\n console.log(`[ws:${data?.type ?? \"unknown\"}] WebSocket error`, {\n code: error.code,\n message: error.message\n });\n if (data) {\n if (data.type === \"sessions\") {\n sessionsWsManager.removeClient(data.client);\n } else if (data.type === \"terminal\") {\n terminalWsManager.removeClient(data.client, data.target);\n } else if (data.type === \"transcript\") {\n transcriptWsManager.removeClient(data.client, data.target);\n }\n wsDataMap.delete(ws);\n }\n }\n};\nexport {\n handle,\n websocket\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"hooks.server-B8dJh24b.js","names":[],"sources":["../../../../web/.svelte-kit/adapter-bun/entries/hooks.server.js"],"sourcesContent":["import \"@sveltejs/kit\";\nimport { p as parseWsPath, h as handleWsMessage, r as resizePane } from \"../chunks/ws-handlers.js\";\nimport { s as sessionsWsManager, t as terminalWsManager, a as transcriptWsManager } from \"../chunks/ws-managers.js\";\nconst wsDataMap = /* @__PURE__ */ new WeakMap();\nconst CORS_ORIGIN = /^https?:\\/\\/(?:[a-z0-9-]+\\.)*[a-z0-9-]+\\.ts\\.net(?::\\d+)?$|^https?:\\/\\/(?:localhost|127\\.0\\.0\\.1)(?::\\d+)?$/i;\nfunction corsHeaders(origin) {\n return {\n \"Access-Control-Allow-Origin\": origin,\n \"Access-Control-Allow-Methods\": \"GET, POST, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"600\",\n Vary: \"Origin\"\n };\n}\nconst handle = async ({ event, resolve }) => {\n const origin = event.request.headers.get(\"origin\");\n const crossSite = !!origin && origin !== event.url.origin && CORS_ORIGIN.test(origin);\n if (crossSite && event.request.method === \"OPTIONS\" && event.url.pathname.startsWith(\"/api/\")) {\n return new Response(null, { status: 204, headers: corsHeaders(origin) });\n }\n const connectionHeader = event.request.headers.get(\"connection\");\n const upgradeHeader = event.request.headers.get(\"upgrade\");\n if (connectionHeader?.toLowerCase().includes(\"upgrade\") && upgradeHeader?.toLowerCase() === \"websocket\") {\n const url = new URL(event.request.url);\n const parsed = parseWsPath(url.pathname);\n if (parsed) {\n await event.platform.server.upgrade(event.platform.request, {\n data: parsed\n });\n return new Response(null, { status: 101 });\n }\n }\n const response = await resolve(event);\n if (crossSite && event.url.pathname.startsWith(\"/api/\")) {\n for (const [name, value] of Object.entries(corsHeaders(origin))) response.headers.set(name, value);\n }\n return response;\n};\nconst websocket = {\n /**\n * Transcript snapshots are hundreds of kilobytes of JSON, and the phone\n * reading them is usually on the far side of a tailnet. The payloads are\n * highly repetitive, so deflate takes them down by roughly an order of\n * magnitude; the terminal's small frames pay a negligible amount of CPU.\n */\n perMessageDeflate: true,\n open(ws) {\n const data = ws.data;\n if (!data) return;\n const client = {\n send: (msg) => ws.send(msg),\n isOpen: () => ws.readyState === WebSocket.OPEN,\n close: () => ws.close(),\n getBufferedAmount: () => ws.bufferedAmount\n };\n wsDataMap.set(ws, { ...data, client });\n let accepted = false;\n if (data.type === \"sessions\") {\n accepted = sessionsWsManager.addClient(client);\n } else if (data.type === \"terminal\" && data.target) {\n accepted = terminalWsManager.addClient(client, data.target);\n } else if (data.type === \"transcript\" && data.target) {\n accepted = transcriptWsManager.addClient(client, data.target);\n }\n if (!accepted) {\n ws.close(1013, \"Max clients reached\");\n }\n },\n message(ws, message) {\n const msgStr = message.toString();\n const data = wsDataMap.get(ws);\n const target = data?.target;\n let handlers;\n if (target && data?.type === \"terminal\") {\n handlers = {\n resize: (cols, rows) => resizePane(target, cols, rows),\n historyRequest: (before, count) => terminalWsManager.requestHistory(data.client, target, before, count)\n };\n } else if (target && data?.type === \"transcript\") {\n handlers = {\n historyRequest: (before, count) => transcriptWsManager.requestHistory(data.client, target, before, count)\n };\n }\n const response = handleWsMessage(msgStr, handlers);\n if (response === \"pong\") {\n ws.send(\"pong\");\n }\n },\n close(ws) {\n const data = wsDataMap.get(ws);\n if (!data) return;\n if (data.type === \"sessions\") {\n sessionsWsManager.removeClient(data.client);\n } else if (data.type === \"terminal\") {\n terminalWsManager.removeClient(data.client, data.target);\n } else if (data.type === \"transcript\") {\n transcriptWsManager.removeClient(data.client, data.target);\n }\n wsDataMap.delete(ws);\n },\n error(ws, error) {\n const data = wsDataMap.get(ws);\n console.log(`[ws:${data?.type ?? \"unknown\"}] WebSocket error`, {\n code: error.code,\n message: error.message\n });\n if (data) {\n if (data.type === \"sessions\") {\n sessionsWsManager.removeClient(data.client);\n } else if (data.type === \"terminal\") {\n terminalWsManager.removeClient(data.client, data.target);\n } else if (data.type === \"transcript\") {\n transcriptWsManager.removeClient(data.client, data.target);\n }\n wsDataMap.delete(ws);\n }\n }\n};\nexport {\n handle,\n websocket\n};\n"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
- import { c as readLinks, d as updateSession, i as getSession, o as getSessionsDir, r as getAllSessions, t as cleanupStaleSessions } from "./sessions-json-BVFqIpMt.js";
1
+ import { c as readLinks, d as updateSession, i as getSession, o as getSessionsDir, r as getAllSessions, t as cleanupStaleSessions, u as sanitizeDisplayName } from "./sessions-json-BVFqIpMt.js";
2
2
  import { n as readNumber, r as readString, t as asRecord } from "./json-4v86y-Ft.js";
3
3
  import { r as SESSIONS_DIR } from "./paths-6nWNmeI4.js";
4
4
  import { t as isDictated } from "./dictation-marks-CgHF_2Qw.js";
5
- import { n as wantsWidening, r as widenDetachedWindow } from "./geometry-CUMMOI9q.js";
6
5
  import { i as getQueueSummary, n as enqueue } from "./message-queue-D4vYsMyd.js";
7
6
  import { homedir } from "os";
8
7
  import { closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, statSync, writeFileSync } from "fs";
@@ -782,7 +781,7 @@ var JsonlTailer = class {
782
781
  }
783
782
  }
784
783
  };
785
- const execFileAsync = promisify(execFile);
784
+ const execFileAsync$1 = promisify(execFile);
786
785
  function hardTimeout(p, ms, fallback) {
787
786
  return new Promise((resolve) => {
788
787
  const timer = setTimeout(() => resolve(fallback), ms);
@@ -797,7 +796,7 @@ function hardTimeout(p, ms, fallback) {
797
796
  }
798
797
  async function getAllPaneTitles() {
799
798
  const result = /* @__PURE__ */ new Map();
800
- const stdout = await hardTimeout(execFileAsync("tmux", [
799
+ const stdout = await hardTimeout(execFileAsync$1("tmux", [
801
800
  "list-panes",
802
801
  "-a",
803
802
  "-F",
@@ -821,7 +820,7 @@ async function getAllPaneTitles() {
821
820
  }
822
821
  async function sendKeyAsync(target, key) {
823
822
  try {
824
- await execFileAsync("tmux", [
823
+ await execFileAsync$1("tmux", [
825
824
  "send-keys",
826
825
  "-t",
827
826
  target,
@@ -833,7 +832,7 @@ async function sendKeyAsync(target, key) {
833
832
  }
834
833
  }
835
834
  async function capturePaneContentAsync(target, withColor = false) {
836
- return hardTimeout(execFileAsync("tmux", withColor ? [
835
+ return hardTimeout(execFileAsync$1("tmux", withColor ? [
837
836
  "capture-pane",
838
837
  "-p",
839
838
  "-e",
@@ -849,16 +848,20 @@ async function capturePaneContentAsync(target, withColor = false) {
849
848
  timeout: 1e3
850
849
  }).then((r) => r.stdout), 1500, null);
851
850
  }
852
- function isPaneShowingSpinner(content) {
853
- if (!content) return false;
854
- const bottomLines = content.split("\n").slice(-5).join("");
855
- return /[\u2800-\u28FF]/.test(bottomLines);
851
+ const ACTIVITY_LINE = /^\s*[⠀-⣿✻✢✳✶✽·]\s+(\S[^…]*…)/;
852
+ function readActivityLine(content) {
853
+ if (!content) return null;
854
+ for (const line of content.split("\n").slice(-12)) {
855
+ const m = ACTIVITY_LINE.exec(line);
856
+ if (m) return m[1].trim();
857
+ }
858
+ return null;
856
859
  }
857
860
  function isPaneShowingIdlePrompt(content) {
858
861
  if (!content) return false;
859
862
  const bottom = content.split("\n").slice(-12);
860
863
  const joined = bottom.join("\n");
861
- if (/[⠀-⣿]/.test(joined)) return false;
864
+ if (readActivityLine(content) !== null) return false;
862
865
  if (/esc to interrupt|esc to cancel|ctrl\+c to interrupt/i.test(joined)) return false;
863
866
  if (bottom.some((line) => /^\s*[^\w\s❯│>]\s+\S+…/.test(line))) return false;
864
867
  if (/Do you want|❯\s+\d+\./.test(joined)) return false;
@@ -1022,8 +1025,9 @@ function detectRemoteControlUrl(content) {
1022
1025
  return match ? match[0].replace(/[.,;:]+$/, "") : null;
1023
1026
  }
1024
1027
  const MAX_PROMPT_OPTIONS = 10;
1025
- const MAX_OPTION_CHARS = 120;
1028
+ const MAX_OPTION_CHARS = 4e3;
1026
1029
  const OPTION_RUN_WINDOW = 24;
1030
+ const QUESTION_LINES = 12;
1027
1031
  const OPTION_RUN_TAIL = 3;
1028
1032
  const OPTION_ROW = /^(❯|>)?\s*(\d+)[.)]\s+(\S.*)$/;
1029
1033
  const OPTION_RULE = /^[─━╌┄┈—–-]+$/;
@@ -1036,6 +1040,7 @@ const INLINE_HINT = /^(.*?\S)\s{2,}(\S.*)$/;
1036
1040
  const PREVIEW_COLUMN = /\s{2,}[┌┐└┘├┤─━│╭╮╰╯].*$/;
1037
1041
  const BOX_ROW = /^[┌┐└┘├┤─━│╭╮╰╯]/;
1038
1042
  const CHECKBOX = /^\[([ xX✔✓])\]\s*/;
1043
+ const TEXT_ROW = /^Type something\.?$/i;
1039
1044
  const HINT_INDENT_SPAN = 8;
1040
1045
  function bodyOf(line) {
1041
1046
  const body = (line ?? "").replace(/[\s│┃|╎┆┊]+$/, "").replace(/^\s*[│┃|╎┆┊]+/, "");
@@ -1048,6 +1053,18 @@ function bodyOf(line) {
1048
1053
  function clampOption(text) {
1049
1054
  return text.length > MAX_OPTION_CHARS ? text.slice(0, MAX_OPTION_CHARS) + "…" : text;
1050
1055
  }
1056
+ const WRAPPED_LINE_SHARE = .6;
1057
+ const MIN_WRAPPED_COLS = 60;
1058
+ function joinParagraph(lines) {
1059
+ const widest = Math.max(...lines.map((line) => line.length));
1060
+ let out = lines[0] ?? "";
1061
+ for (let i = 1; i < lines.length; i++) {
1062
+ const prev = lines[i - 1].length;
1063
+ const wrapped = prev >= MIN_WRAPPED_COLS && prev >= widest * WRAPPED_LINE_SHARE;
1064
+ out += (wrapped ? " " : "\n") + lines[i];
1065
+ }
1066
+ return out;
1067
+ }
1051
1068
  function readPromptOptions(content, mode = {}) {
1052
1069
  if (!content) return null;
1053
1070
  const raw = content.split("\n");
@@ -1118,19 +1135,28 @@ function readPromptOptions(content, mode = {}) {
1118
1135
  const last = k + 1 === rows.length;
1119
1136
  const stop = last ? declared ? lastContent : lastContent + 1 : rows[k + 1].i;
1120
1137
  const noting = last && declared;
1121
- let hint;
1138
+ const hintLines = [];
1139
+ let hintIndent = -1;
1140
+ let hintOpen = false;
1122
1141
  let ruled = false;
1123
1142
  for (let i = row.i + 1; i < stop; i++) {
1124
1143
  const { indent, text } = at(i);
1125
1144
  if (OPTION_RULE.test(text)) {
1145
+ hintOpen = false;
1126
1146
  if (!noting) break;
1127
1147
  ruled = true;
1128
1148
  continue;
1129
1149
  }
1130
- if (!text || BOX_ROW.test(text)) continue;
1150
+ if (!text || BOX_ROW.test(text)) {
1151
+ if (!text) hintOpen = false;
1152
+ continue;
1153
+ }
1131
1154
  const bare = text.replace(PREVIEW_COLUMN, "").trimEnd();
1132
1155
  if (!bare) continue;
1133
- if (!(!ruled && indent >= row.indent && indent <= row.indent + HINT_INDENT_SPAN) || hint !== void 0) {
1156
+ const under = !ruled && indent >= row.indent && indent <= row.indent + HINT_INDENT_SPAN;
1157
+ const continues = hintOpen && indent === hintIndent;
1158
+ if (!under || hintLines.length > 0 && !continues) {
1159
+ hintOpen = false;
1134
1160
  if (noting && !ruled) notes.push(clampOption(bare));
1135
1161
  continue;
1136
1162
  }
@@ -1138,8 +1164,11 @@ function readPromptOptions(content, mode = {}) {
1138
1164
  label = `${label} ${bare}`;
1139
1165
  continue;
1140
1166
  }
1141
- hint = clampOption(bare);
1167
+ hintLines.push(bare);
1168
+ hintIndent = indent;
1169
+ hintOpen = true;
1142
1170
  }
1171
+ let hint = hintLines.length > 0 ? clampOption(joinParagraph(hintLines)) : void 0;
1143
1172
  if (hint === void 0 && !preview) {
1144
1173
  const inline = label.match(INLINE_HINT);
1145
1174
  if (inline) {
@@ -1147,30 +1176,32 @@ function readPromptOptions(content, mode = {}) {
1147
1176
  hint = clampOption(inline[2]);
1148
1177
  }
1149
1178
  }
1150
- return {
1179
+ const option = {
1151
1180
  n: row.n,
1152
1181
  label: clampOption(label),
1153
1182
  hint,
1154
1183
  checked: box ? box[1] !== " " : void 0,
1155
1184
  selected: row.selected
1156
1185
  };
1186
+ if (TEXT_ROW.test(option.label)) option.text = true;
1187
+ return option;
1157
1188
  });
1158
- let question = null;
1159
- let top = null;
1160
- for (let i = rows[0].i - 1; i >= 0 && i >= rows[0].i - 4; i--) {
1189
+ const paragraph = [];
1190
+ for (let i = rows[0].i - 1; i >= 0 && i >= rows[0].i - QUESTION_LINES; i--) {
1161
1191
  const { text } = at(i);
1162
1192
  if (/^[─━╌┄┈╭╮╰╯]+$/.test(text) || TAB_STRIP.test(text)) break;
1163
1193
  if (!text) {
1164
- if (top !== null) break;
1194
+ if (paragraph.length > 0) break;
1165
1195
  continue;
1166
1196
  }
1167
- top = text;
1168
- if (text.endsWith("?")) {
1169
- question = clampOption(text);
1170
- break;
1171
- }
1197
+ paragraph.unshift(text);
1198
+ }
1199
+ let question = null;
1200
+ if (paragraph.length > 0) {
1201
+ const joined = joinParagraph(paragraph);
1202
+ const asking = joined.split("\n").pop();
1203
+ question = clampOption(asking.endsWith("?") ? asking : joined);
1172
1204
  }
1173
- if (question === null && top !== null) question = clampOption(top);
1174
1205
  const choice = {
1175
1206
  question,
1176
1207
  options
@@ -1186,6 +1217,45 @@ function readPromptOptions(content, mode = {}) {
1186
1217
  }
1187
1218
  return choice;
1188
1219
  }
1220
+ const execFileAsync = promisify(execFile);
1221
+ const STANDARD_PANE_WIDTH = 200;
1222
+ const STANDARD_PANE_HEIGHT = 50;
1223
+ const MIN_USEFUL_PANE_WIDTH = 160;
1224
+ function sizeArgsForNewSession() {
1225
+ return [
1226
+ "-x",
1227
+ String(STANDARD_PANE_WIDTH),
1228
+ "-y",
1229
+ String(STANDARD_PANE_HEIGHT)
1230
+ ];
1231
+ }
1232
+ function wantsWidening(pane) {
1233
+ return pane.attached === 0 && pane.width < MIN_USEFUL_PANE_WIDTH;
1234
+ }
1235
+ async function widenDetachedWindow(target) {
1236
+ try {
1237
+ await execFileAsync("tmux", [
1238
+ "resize-window",
1239
+ "-t",
1240
+ target,
1241
+ "-x",
1242
+ String(STANDARD_PANE_WIDTH),
1243
+ "-y",
1244
+ String(STANDARD_PANE_HEIGHT)
1245
+ ], { timeout: 1e3 });
1246
+ await execFileAsync("tmux", [
1247
+ "set-option",
1248
+ "-w",
1249
+ "-t",
1250
+ target,
1251
+ "window-size",
1252
+ "latest"
1253
+ ], { timeout: 1e3 });
1254
+ return true;
1255
+ } catch {
1256
+ return false;
1257
+ }
1258
+ }
1189
1259
  const TAIL_BYTES = 65536;
1190
1260
  const RESOLVE_RETRY_POLLS = 20;
1191
1261
  const paths = /* @__PURE__ */ new Map();
@@ -1203,9 +1273,9 @@ function transcriptPathFor(session) {
1203
1273
  });
1204
1274
  return path;
1205
1275
  }
1206
- function readLastUsage(path, size) {
1276
+ function readTailLines(path, size) {
1207
1277
  const length = Math.min(size, TAIL_BYTES);
1208
- if (length === 0) return null;
1278
+ if (length === 0) return [];
1209
1279
  const buffer = Buffer.alloc(length);
1210
1280
  const fd = openSync(path, "r");
1211
1281
  try {
@@ -1213,7 +1283,9 @@ function readLastUsage(path, size) {
1213
1283
  } finally {
1214
1284
  closeSync(fd);
1215
1285
  }
1216
- const lines = buffer.toString("utf-8").split("\n");
1286
+ return buffer.toString("utf-8").split("\n");
1287
+ }
1288
+ function lastUsage(lines) {
1217
1289
  for (let i = lines.length - 1; i >= 0; i--) {
1218
1290
  const line = lines[i];
1219
1291
  if (!line.includes("\"assistant\"")) continue;
@@ -1227,7 +1299,19 @@ function readLastUsage(path, size) {
1227
1299
  }
1228
1300
  return null;
1229
1301
  }
1230
- function peekContextUsage(session) {
1302
+ function lastCustomTitle(lines) {
1303
+ for (let i = lines.length - 1; i >= 0; i--) {
1304
+ const line = lines[i];
1305
+ if (!line.includes("\"custom-title\"")) continue;
1306
+ try {
1307
+ const record = asRecord(JSON.parse(line));
1308
+ if (record?.type !== "custom-title") continue;
1309
+ const title = record.customTitle;
1310
+ return typeof title === "string" ? title : "";
1311
+ } catch {}
1312
+ }
1313
+ }
1314
+ function fileMemoFor(session) {
1231
1315
  const path = transcriptPathFor(session);
1232
1316
  if (!path) return null;
1233
1317
  let stat;
@@ -1239,14 +1323,22 @@ function peekContextUsage(session) {
1239
1323
  return null;
1240
1324
  }
1241
1325
  const memo = files.get(path);
1242
- if (memo && memo.mtimeMs === stat.mtimeMs && memo.size === stat.size) return memo.usage;
1243
- const usage = readLastUsage(path, stat.size) ?? memo?.usage ?? null;
1244
- files.set(path, {
1326
+ if (memo && memo.mtimeMs === stat.mtimeMs && memo.size === stat.size) return memo;
1327
+ const lines = readTailLines(path, stat.size);
1328
+ const next = {
1245
1329
  mtimeMs: stat.mtimeMs,
1246
1330
  size: stat.size,
1247
- usage
1248
- });
1249
- return usage;
1331
+ usage: lastUsage(lines) ?? memo?.usage ?? null,
1332
+ title: lastCustomTitle(lines) ?? memo?.title
1333
+ };
1334
+ files.set(path, next);
1335
+ return next;
1336
+ }
1337
+ function peekTranscriptTitle(session) {
1338
+ return fileMemoFor(session)?.title;
1339
+ }
1340
+ function peekContextUsage(session) {
1341
+ return fileMemoFor(session)?.usage ?? null;
1250
1342
  }
1251
1343
  function peekContextPercent(session) {
1252
1344
  const usage = peekContextUsage(session);
@@ -1561,10 +1653,13 @@ async function captureAndSyncSessions() {
1561
1653
  });
1562
1654
  } else idleLookTicks.set(session.id, ticks);
1563
1655
  } else idleLookTicks.delete(session.id);
1564
- if (session.state === "idle" && isPaneShowingSpinner(content)) apply(session, {
1565
- state: "busy",
1566
- current_action: "Compacting..."
1567
- });
1656
+ if (session.state === "idle") {
1657
+ const activity = readActivityLine(content);
1658
+ if (activity) apply(session, {
1659
+ state: "busy",
1660
+ current_action: activity
1661
+ });
1662
+ }
1568
1663
  }));
1569
1664
  if (idleLookTicks.size > 0) {
1570
1665
  const live = new Set(sessions.map((s) => s.id));
@@ -1579,6 +1674,17 @@ async function captureAndSyncSessions() {
1579
1674
  const wideningNow = /* @__PURE__ */ new Set();
1580
1675
  const rcSeen = /* @__PURE__ */ new Set();
1581
1676
  let rcPrimed = false;
1677
+ const transcriptTitleSeen = /* @__PURE__ */ new Map();
1678
+ function syncTranscriptTitle(s) {
1679
+ if ((s.agent ?? "claude") !== "claude") return;
1680
+ const title = peekTranscriptTitle(s);
1681
+ if (title === void 0 || transcriptTitleSeen.get(s.id) === title) return;
1682
+ transcriptTitleSeen.set(s.id, title);
1683
+ const name = sanitizeDisplayName(title);
1684
+ if (name === (s.display_name ?? null)) return;
1685
+ updateSession(s.id, { display_name: name });
1686
+ s.display_name = name;
1687
+ }
1582
1688
  async function getEnrichedSessionsAsync() {
1583
1689
  const [{ captures, rawCaptures, sessions }, paneTitles] = await Promise.all([captureAndSyncSessions(), getAllPaneTitles()]);
1584
1690
  const links = readLinks();
@@ -1600,6 +1706,7 @@ async function getEnrichedSessionsAsync() {
1600
1706
  enqueue(s.tmux_target, "/rc", "control");
1601
1707
  }
1602
1708
  rcPrimed = true;
1709
+ for (const s of sessions) syncTranscriptTitle(s);
1603
1710
  for (const s of sessions) {
1604
1711
  if (!s.tmux_target) continue;
1605
1712
  const content = captures.get(s.tmux_target);
@@ -2538,6 +2645,6 @@ function parseWsPath(pathname) {
2538
2645
  return null;
2539
2646
  }
2540
2647
  //#endregion
2541
- export { getSavedProjects as a, parseWsPath as c, saveProject as d, updateSettings as f, getEnrichedSessionsAsync as i, removeProject as l, TerminalWsManager as n, getSettings as o, TranscriptWsManager as r, handleWsMessage as s, SessionsWsManager as t, resizePane as u };
2648
+ export { getSavedProjects as a, parseWsPath as c, saveProject as d, sizeArgsForNewSession as f, getEnrichedSessionsAsync as i, removeProject as l, TerminalWsManager as n, getSettings as o, updateSettings as p, TranscriptWsManager as r, handleWsMessage as s, SessionsWsManager as t, resizePane as u };
2542
2649
 
2543
- //# sourceMappingURL=ws-handlers-BQ2RtlNl.js.map
2650
+ //# sourceMappingURL=ws-handlers-fSFiSfwn.js.map