parasor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (633) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/THIRD-PARTY-NOTICES.md +138 -0
  4. package/bin/parasor.mjs +3 -0
  5. package/node_modules/@parasor/shared/dist/client.d.ts +8 -0
  6. package/node_modules/@parasor/shared/dist/client.d.ts.map +1 -0
  7. package/node_modules/@parasor/shared/dist/client.js +2 -0
  8. package/node_modules/@parasor/shared/dist/client.js.map +1 -0
  9. package/node_modules/@parasor/shared/dist/drops.d.ts +24 -0
  10. package/node_modules/@parasor/shared/dist/drops.d.ts.map +1 -0
  11. package/node_modules/@parasor/shared/dist/drops.js +2 -0
  12. package/node_modules/@parasor/shared/dist/drops.js.map +1 -0
  13. package/node_modules/@parasor/shared/dist/file-uploads.d.ts +56 -0
  14. package/node_modules/@parasor/shared/dist/file-uploads.d.ts.map +1 -0
  15. package/node_modules/@parasor/shared/dist/file-uploads.js +13 -0
  16. package/node_modules/@parasor/shared/dist/file-uploads.js.map +1 -0
  17. package/node_modules/@parasor/shared/dist/ide-commands.d.ts +8 -0
  18. package/node_modules/@parasor/shared/dist/ide-commands.d.ts.map +1 -0
  19. package/node_modules/@parasor/shared/dist/ide-commands.js +59 -0
  20. package/node_modules/@parasor/shared/dist/ide-commands.js.map +1 -0
  21. package/node_modules/@parasor/shared/dist/pane-commands.d.ts +7 -0
  22. package/node_modules/@parasor/shared/dist/pane-commands.d.ts.map +1 -0
  23. package/node_modules/@parasor/shared/dist/pane-commands.js +47 -0
  24. package/node_modules/@parasor/shared/dist/pane-commands.js.map +1 -0
  25. package/node_modules/@parasor/shared/dist/pane-model.d.ts +63 -0
  26. package/node_modules/@parasor/shared/dist/pane-model.d.ts.map +1 -0
  27. package/node_modules/@parasor/shared/dist/pane-model.js +89 -0
  28. package/node_modules/@parasor/shared/dist/pane-model.js.map +1 -0
  29. package/node_modules/@parasor/shared/dist/panes.d.ts +33 -0
  30. package/node_modules/@parasor/shared/dist/panes.d.ts.map +1 -0
  31. package/node_modules/@parasor/shared/dist/panes.js +2 -0
  32. package/node_modules/@parasor/shared/dist/panes.js.map +1 -0
  33. package/node_modules/@parasor/shared/dist/runtime.d.ts +180 -0
  34. package/node_modules/@parasor/shared/dist/runtime.d.ts.map +1 -0
  35. package/node_modules/@parasor/shared/dist/runtime.js +2 -0
  36. package/node_modules/@parasor/shared/dist/runtime.js.map +1 -0
  37. package/node_modules/@parasor/shared/dist/state.d.ts +192 -0
  38. package/node_modules/@parasor/shared/dist/state.d.ts.map +1 -0
  39. package/node_modules/@parasor/shared/dist/state.js +10 -0
  40. package/node_modules/@parasor/shared/dist/state.js.map +1 -0
  41. package/node_modules/@parasor/shared/dist/terminal.d.ts +191 -0
  42. package/node_modules/@parasor/shared/dist/terminal.d.ts.map +1 -0
  43. package/node_modules/@parasor/shared/dist/terminal.js +174 -0
  44. package/node_modules/@parasor/shared/dist/terminal.js.map +1 -0
  45. package/node_modules/@parasor/shared/dist/types.d.ts +13 -0
  46. package/node_modules/@parasor/shared/dist/types.d.ts.map +1 -0
  47. package/node_modules/@parasor/shared/dist/types.js +13 -0
  48. package/node_modules/@parasor/shared/dist/types.js.map +1 -0
  49. package/node_modules/@parasor/shared/dist/worktree-local-files.d.ts +14 -0
  50. package/node_modules/@parasor/shared/dist/worktree-local-files.d.ts.map +1 -0
  51. package/node_modules/@parasor/shared/dist/worktree-local-files.js +41 -0
  52. package/node_modules/@parasor/shared/dist/worktree-local-files.js.map +1 -0
  53. package/node_modules/@parasor/shared/dist/ws-events.d.ts +152 -0
  54. package/node_modules/@parasor/shared/dist/ws-events.d.ts.map +1 -0
  55. package/node_modules/@parasor/shared/dist/ws-events.js +2 -0
  56. package/node_modules/@parasor/shared/dist/ws-events.js.map +1 -0
  57. package/node_modules/@parasor/shared/package.json +13 -0
  58. package/package.json +61 -0
  59. package/server/agent-detector/agent-state-store.d.ts +23 -0
  60. package/server/agent-detector/agent-state-store.d.ts.map +1 -0
  61. package/server/agent-detector/agent-state-store.js +110 -0
  62. package/server/agent-detector/agent-state-store.js.map +1 -0
  63. package/server/agent-detector/detector.d.ts +80 -0
  64. package/server/agent-detector/detector.d.ts.map +1 -0
  65. package/server/agent-detector/detector.js +219 -0
  66. package/server/agent-detector/detector.js.map +1 -0
  67. package/server/agent-detector/event-map.d.ts +25 -0
  68. package/server/agent-detector/event-map.d.ts.map +1 -0
  69. package/server/agent-detector/event-map.js +136 -0
  70. package/server/agent-detector/event-map.js.map +1 -0
  71. package/server/agent-detector/manual-agent-tracker.d.ts +19 -0
  72. package/server/agent-detector/manual-agent-tracker.d.ts.map +1 -0
  73. package/server/agent-detector/manual-agent-tracker.js +123 -0
  74. package/server/agent-detector/manual-agent-tracker.js.map +1 -0
  75. package/server/agent-detector/output-eligibility.d.ts +3 -0
  76. package/server/agent-detector/output-eligibility.d.ts.map +1 -0
  77. package/server/agent-detector/output-eligibility.js +39 -0
  78. package/server/agent-detector/output-eligibility.js.map +1 -0
  79. package/server/application/files/errors.d.ts +28 -0
  80. package/server/application/files/errors.d.ts.map +1 -0
  81. package/server/application/files/errors.js +55 -0
  82. package/server/application/files/errors.js.map +1 -0
  83. package/server/application/files/local-filesystem.d.ts +36 -0
  84. package/server/application/files/local-filesystem.d.ts.map +1 -0
  85. package/server/application/files/local-filesystem.js +171 -0
  86. package/server/application/files/local-filesystem.js.map +1 -0
  87. package/server/application/files/project-file-queries.d.ts +16 -0
  88. package/server/application/files/project-file-queries.d.ts.map +1 -0
  89. package/server/application/files/project-file-queries.js +126 -0
  90. package/server/application/files/project-file-queries.js.map +1 -0
  91. package/server/application/integrations/errors.d.ts +16 -0
  92. package/server/application/integrations/errors.d.ts.map +1 -0
  93. package/server/application/integrations/errors.js +31 -0
  94. package/server/application/integrations/errors.js.map +1 -0
  95. package/server/application/integrations/hook-notify.d.ts +32 -0
  96. package/server/application/integrations/hook-notify.d.ts.map +1 -0
  97. package/server/application/integrations/hook-notify.js +118 -0
  98. package/server/application/integrations/hook-notify.js.map +1 -0
  99. package/server/application/integrations/open-url.d.ts +11 -0
  100. package/server/application/integrations/open-url.d.ts.map +1 -0
  101. package/server/application/integrations/open-url.js +23 -0
  102. package/server/application/integrations/open-url.js.map +1 -0
  103. package/server/application/ports.d.ts +11 -0
  104. package/server/application/ports.d.ts.map +1 -0
  105. package/server/application/ports.js +2 -0
  106. package/server/application/ports.js.map +1 -0
  107. package/server/application/workspace/errors.d.ts +21 -0
  108. package/server/application/workspace/errors.d.ts.map +1 -0
  109. package/server/application/workspace/errors.js +21 -0
  110. package/server/application/workspace/errors.js.map +1 -0
  111. package/server/application/workspace/pane-commands.d.ts +47 -0
  112. package/server/application/workspace/pane-commands.d.ts.map +1 -0
  113. package/server/application/workspace/pane-commands.js +193 -0
  114. package/server/application/workspace/pane-commands.js.map +1 -0
  115. package/server/application/workspace/project-commands.d.ts +34 -0
  116. package/server/application/workspace/project-commands.d.ts.map +1 -0
  117. package/server/application/workspace/project-commands.js +81 -0
  118. package/server/application/workspace/project-commands.js.map +1 -0
  119. package/server/application/workspace/project-queries.d.ts +21 -0
  120. package/server/application/workspace/project-queries.d.ts.map +1 -0
  121. package/server/application/workspace/project-queries.js +216 -0
  122. package/server/application/workspace/project-queries.js.map +1 -0
  123. package/server/application/workspace/session-commands.d.ts +24 -0
  124. package/server/application/workspace/session-commands.d.ts.map +1 -0
  125. package/server/application/workspace/session-commands.js +123 -0
  126. package/server/application/workspace/session-commands.js.map +1 -0
  127. package/server/application/workspace/session-queries.d.ts +14 -0
  128. package/server/application/workspace/session-queries.d.ts.map +1 -0
  129. package/server/application/workspace/session-queries.js +47 -0
  130. package/server/application/workspace/session-queries.js.map +1 -0
  131. package/server/application/workspace/worktree-commands.d.ts +98 -0
  132. package/server/application/workspace/worktree-commands.d.ts.map +1 -0
  133. package/server/application/workspace/worktree-commands.js +323 -0
  134. package/server/application/workspace/worktree-commands.js.map +1 -0
  135. package/server/application/workspace/worktree-local-files.d.ts +11 -0
  136. package/server/application/workspace/worktree-local-files.d.ts.map +1 -0
  137. package/server/application/workspace/worktree-local-files.js +223 -0
  138. package/server/application/workspace/worktree-local-files.js.map +1 -0
  139. package/server/application/workspace/worktree-reconcile.d.ts +21 -0
  140. package/server/application/workspace/worktree-reconcile.d.ts.map +1 -0
  141. package/server/application/workspace/worktree-reconcile.js +49 -0
  142. package/server/application/workspace/worktree-reconcile.js.map +1 -0
  143. package/server/auth/origin.d.ts +17 -0
  144. package/server/auth/origin.d.ts.map +1 -0
  145. package/server/auth/origin.js +93 -0
  146. package/server/auth/origin.js.map +1 -0
  147. package/server/auth/pairing-token.d.ts +28 -0
  148. package/server/auth/pairing-token.d.ts.map +1 -0
  149. package/server/auth/pairing-token.js +46 -0
  150. package/server/auth/pairing-token.js.map +1 -0
  151. package/server/auth/token-exchange.d.ts +11 -0
  152. package/server/auth/token-exchange.d.ts.map +1 -0
  153. package/server/auth/token-exchange.js +27 -0
  154. package/server/auth/token-exchange.js.map +1 -0
  155. package/server/auth/token.d.ts +18 -0
  156. package/server/auth/token.d.ts.map +1 -0
  157. package/server/auth/token.js +115 -0
  158. package/server/auth/token.js.map +1 -0
  159. package/server/bootstrap/create-app-server.d.ts +49 -0
  160. package/server/bootstrap/create-app-server.d.ts.map +1 -0
  161. package/server/bootstrap/create-app-server.js +154 -0
  162. package/server/bootstrap/create-app-server.js.map +1 -0
  163. package/server/bootstrap/project-runtime.d.ts +29 -0
  164. package/server/bootstrap/project-runtime.d.ts.map +1 -0
  165. package/server/bootstrap/project-runtime.js +253 -0
  166. package/server/bootstrap/project-runtime.js.map +1 -0
  167. package/server/bootstrap/pty-env.d.ts +3 -0
  168. package/server/bootstrap/pty-env.d.ts.map +1 -0
  169. package/server/bootstrap/pty-env.js +15 -0
  170. package/server/bootstrap/pty-env.js.map +1 -0
  171. package/server/bootstrap/reconcile-state.d.ts +16 -0
  172. package/server/bootstrap/reconcile-state.d.ts.map +1 -0
  173. package/server/bootstrap/reconcile-state.js +73 -0
  174. package/server/bootstrap/reconcile-state.js.map +1 -0
  175. package/server/bootstrap/runtime-loops.d.ts +51 -0
  176. package/server/bootstrap/runtime-loops.d.ts.map +1 -0
  177. package/server/bootstrap/runtime-loops.js +189 -0
  178. package/server/bootstrap/runtime-loops.js.map +1 -0
  179. package/server/bootstrap/runtime-port.d.ts +4 -0
  180. package/server/bootstrap/runtime-port.d.ts.map +1 -0
  181. package/server/bootstrap/runtime-port.js +52 -0
  182. package/server/bootstrap/runtime-port.js.map +1 -0
  183. package/server/bootstrap/safety-gate.d.ts +22 -0
  184. package/server/bootstrap/safety-gate.d.ts.map +1 -0
  185. package/server/bootstrap/safety-gate.js +43 -0
  186. package/server/bootstrap/safety-gate.js.map +1 -0
  187. package/server/bootstrap/shutdown-marker.d.ts +35 -0
  188. package/server/bootstrap/shutdown-marker.d.ts.map +1 -0
  189. package/server/bootstrap/shutdown-marker.js +100 -0
  190. package/server/bootstrap/shutdown-marker.js.map +1 -0
  191. package/server/bootstrap/shutdown-runtime.d.ts +62 -0
  192. package/server/bootstrap/shutdown-runtime.d.ts.map +1 -0
  193. package/server/bootstrap/shutdown-runtime.js +66 -0
  194. package/server/bootstrap/shutdown-runtime.js.map +1 -0
  195. package/server/bootstrap/startup-banner.d.ts +34 -0
  196. package/server/bootstrap/startup-banner.d.ts.map +1 -0
  197. package/server/bootstrap/startup-banner.js +114 -0
  198. package/server/bootstrap/startup-banner.js.map +1 -0
  199. package/server/bootstrap/wire-runtime.d.ts +42 -0
  200. package/server/bootstrap/wire-runtime.d.ts.map +1 -0
  201. package/server/bootstrap/wire-runtime.js +205 -0
  202. package/server/bootstrap/wire-runtime.js.map +1 -0
  203. package/server/cli/help.d.ts +3 -0
  204. package/server/cli/help.d.ts.map +1 -0
  205. package/server/cli/help.js +39 -0
  206. package/server/cli/help.js.map +1 -0
  207. package/server/cli/hook-client.d.ts +12 -0
  208. package/server/cli/hook-client.d.ts.map +1 -0
  209. package/server/cli/hook-client.js +81 -0
  210. package/server/cli/hook-client.js.map +1 -0
  211. package/server/cli/hook.d.ts +3 -0
  212. package/server/cli/hook.d.ts.map +1 -0
  213. package/server/cli/hook.js +152 -0
  214. package/server/cli/hook.js.map +1 -0
  215. package/server/cli/main.d.ts +2 -0
  216. package/server/cli/main.d.ts.map +1 -0
  217. package/server/cli/main.js +133 -0
  218. package/server/cli/main.js.map +1 -0
  219. package/server/cli/notify.d.ts +19 -0
  220. package/server/cli/notify.d.ts.map +1 -0
  221. package/server/cli/notify.js +77 -0
  222. package/server/cli/notify.js.map +1 -0
  223. package/server/cli/open.d.ts +2 -0
  224. package/server/cli/open.d.ts.map +1 -0
  225. package/server/cli/open.js +47 -0
  226. package/server/cli/open.js.map +1 -0
  227. package/server/cli/probe-daemon-version.d.ts +46 -0
  228. package/server/cli/probe-daemon-version.d.ts.map +1 -0
  229. package/server/cli/probe-daemon-version.js +167 -0
  230. package/server/cli/probe-daemon-version.js.map +1 -0
  231. package/server/cli/pty-host.d.ts +36 -0
  232. package/server/cli/pty-host.d.ts.map +1 -0
  233. package/server/cli/pty-host.js +390 -0
  234. package/server/cli/pty-host.js.map +1 -0
  235. package/server/cli/qr.d.ts +2 -0
  236. package/server/cli/qr.d.ts.map +1 -0
  237. package/server/cli/qr.js +70 -0
  238. package/server/cli/qr.js.map +1 -0
  239. package/server/cli/restart-confirm.d.ts +33 -0
  240. package/server/cli/restart-confirm.d.ts.map +1 -0
  241. package/server/cli/restart-confirm.js +107 -0
  242. package/server/cli/restart-confirm.js.map +1 -0
  243. package/server/cli/restart.d.ts +17 -0
  244. package/server/cli/restart.d.ts.map +1 -0
  245. package/server/cli/restart.js +145 -0
  246. package/server/cli/restart.js.map +1 -0
  247. package/server/cli/service-darwin.d.ts +70 -0
  248. package/server/cli/service-darwin.d.ts.map +1 -0
  249. package/server/cli/service-darwin.js +562 -0
  250. package/server/cli/service-darwin.js.map +1 -0
  251. package/server/cli/service-linux.d.ts +81 -0
  252. package/server/cli/service-linux.d.ts.map +1 -0
  253. package/server/cli/service-linux.js +412 -0
  254. package/server/cli/service-linux.js.map +1 -0
  255. package/server/cli/service.d.ts +33 -0
  256. package/server/cli/service.d.ts.map +1 -0
  257. package/server/cli/service.js +133 -0
  258. package/server/cli/service.js.map +1 -0
  259. package/server/cli/shim-installer.d.ts +35 -0
  260. package/server/cli/shim-installer.d.ts.map +1 -0
  261. package/server/cli/shim-installer.js +662 -0
  262. package/server/cli/shim-installer.js.map +1 -0
  263. package/server/cli/shim-open.d.ts +2 -0
  264. package/server/cli/shim-open.d.ts.map +1 -0
  265. package/server/cli/shim-open.js +128 -0
  266. package/server/cli/shim-open.js.map +1 -0
  267. package/server/cli/shutdown-deps.d.ts +41 -0
  268. package/server/cli/shutdown-deps.d.ts.map +1 -0
  269. package/server/cli/shutdown-deps.js +158 -0
  270. package/server/cli/shutdown-deps.js.map +1 -0
  271. package/server/cli/stop.d.ts +11 -0
  272. package/server/cli/stop.d.ts.map +1 -0
  273. package/server/cli/stop.js +123 -0
  274. package/server/cli/stop.js.map +1 -0
  275. package/server/cli/unknown-command.d.ts +8 -0
  276. package/server/cli/unknown-command.d.ts.map +1 -0
  277. package/server/cli/unknown-command.js +14 -0
  278. package/server/cli/unknown-command.js.map +1 -0
  279. package/server/debug/agent-status-recorder.d.ts +57 -0
  280. package/server/debug/agent-status-recorder.d.ts.map +1 -0
  281. package/server/debug/agent-status-recorder.js +209 -0
  282. package/server/debug/agent-status-recorder.js.map +1 -0
  283. package/server/debug/terminal-trace-recorder.d.ts +41 -0
  284. package/server/debug/terminal-trace-recorder.d.ts.map +1 -0
  285. package/server/debug/terminal-trace-recorder.js +112 -0
  286. package/server/debug/terminal-trace-recorder.js.map +1 -0
  287. package/server/fonts/catalog.d.ts +35 -0
  288. package/server/fonts/catalog.d.ts.map +1 -0
  289. package/server/fonts/catalog.js +76 -0
  290. package/server/fonts/catalog.js.map +1 -0
  291. package/server/fonts/installer.d.ts +45 -0
  292. package/server/fonts/installer.d.ts.map +1 -0
  293. package/server/fonts/installer.js +201 -0
  294. package/server/fonts/installer.js.map +1 -0
  295. package/server/fonts/routes.d.ts +4 -0
  296. package/server/fonts/routes.d.ts.map +1 -0
  297. package/server/fonts/routes.js +91 -0
  298. package/server/fonts/routes.js.map +1 -0
  299. package/server/fs/drops.d.ts +50 -0
  300. package/server/fs/drops.d.ts.map +1 -0
  301. package/server/fs/drops.js +137 -0
  302. package/server/fs/drops.js.map +1 -0
  303. package/server/fs/file-uploads.d.ts +57 -0
  304. package/server/fs/file-uploads.d.ts.map +1 -0
  305. package/server/fs/file-uploads.js +214 -0
  306. package/server/fs/file-uploads.js.map +1 -0
  307. package/server/fs/file-watcher.d.ts +22 -0
  308. package/server/fs/file-watcher.d.ts.map +1 -0
  309. package/server/fs/file-watcher.js +105 -0
  310. package/server/fs/file-watcher.js.map +1 -0
  311. package/server/fs/git-watcher.d.ts +76 -0
  312. package/server/fs/git-watcher.d.ts.map +1 -0
  313. package/server/fs/git-watcher.js +356 -0
  314. package/server/fs/git-watcher.js.map +1 -0
  315. package/server/fs/media.d.ts +35 -0
  316. package/server/fs/media.d.ts.map +1 -0
  317. package/server/fs/media.js +271 -0
  318. package/server/fs/media.js.map +1 -0
  319. package/server/fs/service.d.ts +97 -0
  320. package/server/fs/service.d.ts.map +1 -0
  321. package/server/fs/service.js +306 -0
  322. package/server/fs/service.js.map +1 -0
  323. package/server/fs/upload-staging.d.ts +76 -0
  324. package/server/fs/upload-staging.d.ts.map +1 -0
  325. package/server/fs/upload-staging.js +283 -0
  326. package/server/fs/upload-staging.js.map +1 -0
  327. package/server/fs/watcher-lifecycle.d.ts +24 -0
  328. package/server/fs/watcher-lifecycle.d.ts.map +1 -0
  329. package/server/fs/watcher-lifecycle.js +105 -0
  330. package/server/fs/watcher-lifecycle.js.map +1 -0
  331. package/server/index.d.ts +17 -0
  332. package/server/index.d.ts.map +1 -0
  333. package/server/index.js +510 -0
  334. package/server/index.js.map +1 -0
  335. package/server/ipc/socket-server.d.ts +28 -0
  336. package/server/ipc/socket-server.d.ts.map +1 -0
  337. package/server/ipc/socket-server.js +206 -0
  338. package/server/ipc/socket-server.js.map +1 -0
  339. package/server/lib/git-exec.d.ts +38 -0
  340. package/server/lib/git-exec.d.ts.map +1 -0
  341. package/server/lib/git-exec.js +96 -0
  342. package/server/lib/git-exec.js.map +1 -0
  343. package/server/lib/open-in-ide.d.ts +22 -0
  344. package/server/lib/open-in-ide.d.ts.map +1 -0
  345. package/server/lib/open-in-ide.js +90 -0
  346. package/server/lib/open-in-ide.js.map +1 -0
  347. package/server/lib/open-in-os.d.ts +20 -0
  348. package/server/lib/open-in-os.d.ts.map +1 -0
  349. package/server/lib/open-in-os.js +51 -0
  350. package/server/lib/open-in-os.js.map +1 -0
  351. package/server/lib/path.d.ts +2 -0
  352. package/server/lib/path.d.ts.map +1 -0
  353. package/server/lib/path.js +10 -0
  354. package/server/lib/path.js.map +1 -0
  355. package/server/lib/promise-mutex.d.ts +7 -0
  356. package/server/lib/promise-mutex.d.ts.map +1 -0
  357. package/server/lib/promise-mutex.js +26 -0
  358. package/server/lib/promise-mutex.js.map +1 -0
  359. package/server/lib/sd-notify.d.ts +8 -0
  360. package/server/lib/sd-notify.d.ts.map +1 -0
  361. package/server/lib/sd-notify.js +27 -0
  362. package/server/lib/sd-notify.js.map +1 -0
  363. package/server/net/local-machine.d.ts +7 -0
  364. package/server/net/local-machine.d.ts.map +1 -0
  365. package/server/net/local-machine.js +79 -0
  366. package/server/net/local-machine.js.map +1 -0
  367. package/server/net/reachable-host.d.ts +12 -0
  368. package/server/net/reachable-host.d.ts.map +1 -0
  369. package/server/net/reachable-host.js +25 -0
  370. package/server/net/reachable-host.js.map +1 -0
  371. package/server/network/endpoints.d.ts +14 -0
  372. package/server/network/endpoints.d.ts.map +1 -0
  373. package/server/network/endpoints.js +104 -0
  374. package/server/network/endpoints.js.map +1 -0
  375. package/server/network/qr.d.ts +16 -0
  376. package/server/network/qr.d.ts.map +1 -0
  377. package/server/network/qr.js +89 -0
  378. package/server/network/qr.js.map +1 -0
  379. package/server/port-forwarder/forwarder.d.ts +47 -0
  380. package/server/port-forwarder/forwarder.d.ts.map +1 -0
  381. package/server/port-forwarder/forwarder.js +159 -0
  382. package/server/port-forwarder/forwarder.js.map +1 -0
  383. package/server/port-scanner/scanner.d.ts +24 -0
  384. package/server/port-scanner/scanner.d.ts.map +1 -0
  385. package/server/port-scanner/scanner.js +193 -0
  386. package/server/port-scanner/scanner.js.map +1 -0
  387. package/server/pty/connection-lifecycle.d.ts +50 -0
  388. package/server/pty/connection-lifecycle.d.ts.map +1 -0
  389. package/server/pty/connection-lifecycle.js +113 -0
  390. package/server/pty/connection-lifecycle.js.map +1 -0
  391. package/server/pty/daemon-connect.d.ts +52 -0
  392. package/server/pty/daemon-connect.d.ts.map +1 -0
  393. package/server/pty/daemon-connect.js +62 -0
  394. package/server/pty/daemon-connect.js.map +1 -0
  395. package/server/pty/handshake-timeout-race.d.ts +22 -0
  396. package/server/pty/handshake-timeout-race.d.ts.map +1 -0
  397. package/server/pty/handshake-timeout-race.js +23 -0
  398. package/server/pty/handshake-timeout-race.js.map +1 -0
  399. package/server/pty/headless-replay-snapshot.d.ts +28 -0
  400. package/server/pty/headless-replay-snapshot.d.ts.map +1 -0
  401. package/server/pty/headless-replay-snapshot.js +285 -0
  402. package/server/pty/headless-replay-snapshot.js.map +1 -0
  403. package/server/pty/headless-terminal-state-cache.d.ts +31 -0
  404. package/server/pty/headless-terminal-state-cache.d.ts.map +1 -0
  405. package/server/pty/headless-terminal-state-cache.js +119 -0
  406. package/server/pty/headless-terminal-state-cache.js.map +1 -0
  407. package/server/pty/hello-ack-validator.d.ts +15 -0
  408. package/server/pty/hello-ack-validator.d.ts.map +1 -0
  409. package/server/pty/hello-ack-validator.js +30 -0
  410. package/server/pty/hello-ack-validator.js.map +1 -0
  411. package/server/pty/host-daemon/bootstrap.d.ts +100 -0
  412. package/server/pty/host-daemon/bootstrap.d.ts.map +1 -0
  413. package/server/pty/host-daemon/bootstrap.js +611 -0
  414. package/server/pty/host-daemon/bootstrap.js.map +1 -0
  415. package/server/pty/host-daemon/daemon.d.ts +111 -0
  416. package/server/pty/host-daemon/daemon.d.ts.map +1 -0
  417. package/server/pty/host-daemon/daemon.js +648 -0
  418. package/server/pty/host-daemon/daemon.js.map +1 -0
  419. package/server/pty/host-daemon/entry.d.ts +3 -0
  420. package/server/pty/host-daemon/entry.d.ts.map +1 -0
  421. package/server/pty/host-daemon/entry.js +72 -0
  422. package/server/pty/host-daemon/entry.js.map +1 -0
  423. package/server/pty/host-daemon/lockfile.d.ts +12 -0
  424. package/server/pty/host-daemon/lockfile.d.ts.map +1 -0
  425. package/server/pty/host-daemon/lockfile.js +120 -0
  426. package/server/pty/host-daemon/lockfile.js.map +1 -0
  427. package/server/pty/host-daemon/mode-marker.d.ts +77 -0
  428. package/server/pty/host-daemon/mode-marker.d.ts.map +1 -0
  429. package/server/pty/host-daemon/mode-marker.js +228 -0
  430. package/server/pty/host-daemon/mode-marker.js.map +1 -0
  431. package/server/pty/host-daemon/orphan-cleanup.d.ts +42 -0
  432. package/server/pty/host-daemon/orphan-cleanup.d.ts.map +1 -0
  433. package/server/pty/host-daemon/orphan-cleanup.js +84 -0
  434. package/server/pty/host-daemon/orphan-cleanup.js.map +1 -0
  435. package/server/pty/host-daemon/paths.d.ts +10 -0
  436. package/server/pty/host-daemon/paths.d.ts.map +1 -0
  437. package/server/pty/host-daemon/paths.js +56 -0
  438. package/server/pty/host-daemon/paths.js.map +1 -0
  439. package/server/pty/host-daemon/server-connection.d.ts +44 -0
  440. package/server/pty/host-daemon/server-connection.d.ts.map +1 -0
  441. package/server/pty/host-daemon/server-connection.js +100 -0
  442. package/server/pty/host-daemon/server-connection.js.map +1 -0
  443. package/server/pty/host-daemon/service-detection.d.ts +24 -0
  444. package/server/pty/host-daemon/service-detection.d.ts.map +1 -0
  445. package/server/pty/host-daemon/service-detection.js +16 -0
  446. package/server/pty/host-daemon/service-detection.js.map +1 -0
  447. package/server/pty/host-daemon/socket-ready.d.ts +22 -0
  448. package/server/pty/host-daemon/socket-ready.d.ts.map +1 -0
  449. package/server/pty/host-daemon/socket-ready.js +33 -0
  450. package/server/pty/host-daemon/socket-ready.js.map +1 -0
  451. package/server/pty/host-daemon/spawn-daemon.d.ts +45 -0
  452. package/server/pty/host-daemon/spawn-daemon.d.ts.map +1 -0
  453. package/server/pty/host-daemon/spawn-daemon.js +155 -0
  454. package/server/pty/host-daemon/spawn-daemon.js.map +1 -0
  455. package/server/pty/host-daemon/terminate-daemon.d.ts +16 -0
  456. package/server/pty/host-daemon/terminate-daemon.d.ts.map +1 -0
  457. package/server/pty/host-daemon/terminate-daemon.js +128 -0
  458. package/server/pty/host-daemon/terminate-daemon.js.map +1 -0
  459. package/server/pty/host-protocol/frames.d.ts +110 -0
  460. package/server/pty/host-protocol/frames.d.ts.map +1 -0
  461. package/server/pty/host-protocol/frames.js +255 -0
  462. package/server/pty/host-protocol/frames.js.map +1 -0
  463. package/server/pty/host-protocol/messages.d.ts +140 -0
  464. package/server/pty/host-protocol/messages.d.ts.map +1 -0
  465. package/server/pty/host-protocol/messages.js +117 -0
  466. package/server/pty/host-protocol/messages.js.map +1 -0
  467. package/server/pty/host.d.ts +273 -0
  468. package/server/pty/host.d.ts.map +1 -0
  469. package/server/pty/host.js +184 -0
  470. package/server/pty/host.js.map +1 -0
  471. package/server/pty/in-process-host.d.ts +224 -0
  472. package/server/pty/in-process-host.d.ts.map +1 -0
  473. package/server/pty/in-process-host.js +1183 -0
  474. package/server/pty/in-process-host.js.map +1 -0
  475. package/server/pty/osc7-lifecycle.d.ts +8 -0
  476. package/server/pty/osc7-lifecycle.d.ts.map +1 -0
  477. package/server/pty/osc7-lifecycle.js +22 -0
  478. package/server/pty/osc7-lifecycle.js.map +1 -0
  479. package/server/pty/osc7-parser.d.ts +23 -0
  480. package/server/pty/osc7-parser.d.ts.map +1 -0
  481. package/server/pty/osc7-parser.js +91 -0
  482. package/server/pty/osc7-parser.js.map +1 -0
  483. package/server/pty/remote-host.d.ts +188 -0
  484. package/server/pty/remote-host.d.ts.map +1 -0
  485. package/server/pty/remote-host.js +810 -0
  486. package/server/pty/remote-host.js.map +1 -0
  487. package/server/pty/request-correlator.d.ts +59 -0
  488. package/server/pty/request-correlator.d.ts.map +1 -0
  489. package/server/pty/request-correlator.js +75 -0
  490. package/server/pty/request-correlator.js.map +1 -0
  491. package/server/pty/scrollback-log.d.ts +130 -0
  492. package/server/pty/scrollback-log.d.ts.map +1 -0
  493. package/server/pty/scrollback-log.js +344 -0
  494. package/server/pty/scrollback-log.js.map +1 -0
  495. package/server/pty/scrollback-sanitize.d.ts +2 -0
  496. package/server/pty/scrollback-sanitize.d.ts.map +1 -0
  497. package/server/pty/scrollback-sanitize.js +54 -0
  498. package/server/pty/scrollback-sanitize.js.map +1 -0
  499. package/server/pty/session-mirror.d.ts +67 -0
  500. package/server/pty/session-mirror.d.ts.map +1 -0
  501. package/server/pty/session-mirror.js +112 -0
  502. package/server/pty/session-mirror.js.map +1 -0
  503. package/server/pty/session-policy.d.ts +85 -0
  504. package/server/pty/session-policy.d.ts.map +1 -0
  505. package/server/pty/session-policy.js +186 -0
  506. package/server/pty/session-policy.js.map +1 -0
  507. package/server/pty/version-mismatch-recovery.d.ts +71 -0
  508. package/server/pty/version-mismatch-recovery.d.ts.map +1 -0
  509. package/server/pty/version-mismatch-recovery.js +63 -0
  510. package/server/pty/version-mismatch-recovery.js.map +1 -0
  511. package/server/routes/debug-agent-status.d.ts +5 -0
  512. package/server/routes/debug-agent-status.d.ts.map +1 -0
  513. package/server/routes/debug-agent-status.js +22 -0
  514. package/server/routes/debug-agent-status.js.map +1 -0
  515. package/server/routes/debug-diagnostics.d.ts +8 -0
  516. package/server/routes/debug-diagnostics.d.ts.map +1 -0
  517. package/server/routes/debug-diagnostics.js +34 -0
  518. package/server/routes/debug-diagnostics.js.map +1 -0
  519. package/server/routes/debug-terminal-trace.d.ts +16 -0
  520. package/server/routes/debug-terminal-trace.d.ts.map +1 -0
  521. package/server/routes/debug-terminal-trace.js +545 -0
  522. package/server/routes/debug-terminal-trace.js.map +1 -0
  523. package/server/routes/drops.d.ts +13 -0
  524. package/server/routes/drops.d.ts.map +1 -0
  525. package/server/routes/drops.js +126 -0
  526. package/server/routes/drops.js.map +1 -0
  527. package/server/routes/file-uploads.d.ts +9 -0
  528. package/server/routes/file-uploads.d.ts.map +1 -0
  529. package/server/routes/file-uploads.js +119 -0
  530. package/server/routes/file-uploads.js.map +1 -0
  531. package/server/routes/files.d.ts +9 -0
  532. package/server/routes/files.d.ts.map +1 -0
  533. package/server/routes/files.js +441 -0
  534. package/server/routes/files.js.map +1 -0
  535. package/server/routes/filesystem.d.ts +6 -0
  536. package/server/routes/filesystem.d.ts.map +1 -0
  537. package/server/routes/filesystem.js +76 -0
  538. package/server/routes/filesystem.js.map +1 -0
  539. package/server/routes/git.d.ts +38 -0
  540. package/server/routes/git.d.ts.map +1 -0
  541. package/server/routes/git.js +585 -0
  542. package/server/routes/git.js.map +1 -0
  543. package/server/routes/healthz.d.ts +8 -0
  544. package/server/routes/healthz.d.ts.map +1 -0
  545. package/server/routes/healthz.js +24 -0
  546. package/server/routes/healthz.js.map +1 -0
  547. package/server/routes/hook.d.ts +14 -0
  548. package/server/routes/hook.d.ts.map +1 -0
  549. package/server/routes/hook.js +86 -0
  550. package/server/routes/hook.js.map +1 -0
  551. package/server/routes/ide-commands.d.ts +9 -0
  552. package/server/routes/ide-commands.d.ts.map +1 -0
  553. package/server/routes/ide-commands.js +23 -0
  554. package/server/routes/ide-commands.js.map +1 -0
  555. package/server/routes/lib/resolve-worktree.d.ts +30 -0
  556. package/server/routes/lib/resolve-worktree.d.ts.map +1 -0
  557. package/server/routes/lib/resolve-worktree.js +35 -0
  558. package/server/routes/lib/resolve-worktree.js.map +1 -0
  559. package/server/routes/open.d.ts +4 -0
  560. package/server/routes/open.d.ts.map +1 -0
  561. package/server/routes/open.js +21 -0
  562. package/server/routes/open.js.map +1 -0
  563. package/server/routes/pane-commands.d.ts +9 -0
  564. package/server/routes/pane-commands.d.ts.map +1 -0
  565. package/server/routes/pane-commands.js +23 -0
  566. package/server/routes/pane-commands.js.map +1 -0
  567. package/server/routes/projects.d.ts +15 -0
  568. package/server/routes/projects.d.ts.map +1 -0
  569. package/server/routes/projects.js +363 -0
  570. package/server/routes/projects.js.map +1 -0
  571. package/server/routes/server-notices.d.ts +4 -0
  572. package/server/routes/server-notices.d.ts.map +1 -0
  573. package/server/routes/server-notices.js +29 -0
  574. package/server/routes/server-notices.js.map +1 -0
  575. package/server/routes/service-config.d.ts +11 -0
  576. package/server/routes/service-config.d.ts.map +1 -0
  577. package/server/routes/service-config.js +64 -0
  578. package/server/routes/service-config.js.map +1 -0
  579. package/server/routes/sessions.d.ts +7 -0
  580. package/server/routes/sessions.d.ts.map +1 -0
  581. package/server/routes/sessions.js +218 -0
  582. package/server/routes/sessions.js.map +1 -0
  583. package/server/service/caffeinate.d.ts +33 -0
  584. package/server/service/caffeinate.d.ts.map +1 -0
  585. package/server/service/caffeinate.js +72 -0
  586. package/server/service/caffeinate.js.map +1 -0
  587. package/server/state/app-state.d.ts +167 -0
  588. package/server/state/app-state.d.ts.map +1 -0
  589. package/server/state/app-state.js +335 -0
  590. package/server/state/app-state.js.map +1 -0
  591. package/server/state/project-manager.d.ts +30 -0
  592. package/server/state/project-manager.d.ts.map +1 -0
  593. package/server/state/project-manager.js +128 -0
  594. package/server/state/project-manager.js.map +1 -0
  595. package/server/state/server-notices.d.ts +12 -0
  596. package/server/state/server-notices.d.ts.map +1 -0
  597. package/server/state/server-notices.js +32 -0
  598. package/server/state/server-notices.js.map +1 -0
  599. package/server/state/worktree-cache.d.ts +25 -0
  600. package/server/state/worktree-cache.d.ts.map +1 -0
  601. package/server/state/worktree-cache.js +53 -0
  602. package/server/state/worktree-cache.js.map +1 -0
  603. package/server/ws/events.d.ts +45 -0
  604. package/server/ws/events.d.ts.map +1 -0
  605. package/server/ws/events.js +134 -0
  606. package/server/ws/events.js.map +1 -0
  607. package/server/ws/keepalive.d.ts +27 -0
  608. package/server/ws/keepalive.d.ts.map +1 -0
  609. package/server/ws/keepalive.js +63 -0
  610. package/server/ws/keepalive.js.map +1 -0
  611. package/server/ws/terminal-attach.d.ts +13 -0
  612. package/server/ws/terminal-attach.d.ts.map +1 -0
  613. package/server/ws/terminal-attach.js +233 -0
  614. package/server/ws/terminal-attach.js.map +1 -0
  615. package/server/ws/terminal-flow.d.ts +17 -0
  616. package/server/ws/terminal-flow.d.ts.map +1 -0
  617. package/server/ws/terminal-flow.js +64 -0
  618. package/server/ws/terminal-flow.js.map +1 -0
  619. package/server/ws/terminal.d.ts +69 -0
  620. package/server/ws/terminal.d.ts.map +1 -0
  621. package/server/ws/terminal.js +311 -0
  622. package/server/ws/terminal.js.map +1 -0
  623. package/web/assets/EditorPane-CzzT3iYY.js +123 -0
  624. package/web/assets/SymbolsNerdFontMono-Regular-CwEZqMeU.woff2 +0 -0
  625. package/web/assets/TerminalPane-CjbYzePr.js +68 -0
  626. package/web/assets/TerminalPane-DkTCHfhq.css +1 -0
  627. package/web/assets/file-icons-JBi09j0r.js +6 -0
  628. package/web/assets/index-CTTkRpnn.css +2 -0
  629. package/web/assets/index-CmhewzMp.js +34 -0
  630. package/web/assets/session-resume-7f-tB-ZU.js +2 -0
  631. package/web/assets/terminal-trace-PuuFRybC.js +2803 -0
  632. package/web/assets/useVirtualKeyboard-DgJb9u9d.js +1 -0
  633. package/web/index.html +52 -0
@@ -0,0 +1,810 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { ConnectionLifecycle } from "./connection-lifecycle.js";
3
+ import { raceHandshakeWithTimeout } from "./handshake-timeout-race.js";
4
+ import { HeadlessTerminalStateCache } from "./headless-terminal-state-cache.js";
5
+ import { validateHelloAck } from "./hello-ack-validator.js";
6
+ import { decodeGenerationStreamPayload, decodeStreamPayload, encodeFrame, encodeGenerationStreamPayload, FrameError, FrameParser, FrameType, } from "./host-protocol/frames.js";
7
+ import { decodeJsonPayload, encodeJsonPayload, PROTOCOL_VERSION, } from "./host-protocol/messages.js";
8
+ import { RequestCorrelator } from "./request-correlator.js";
9
+ import { stripQueryEscapes } from "./scrollback-sanitize.js";
10
+ import { SessionMirror } from "./session-mirror.js";
11
+ const DEFAULT_DAEMON_LEGACY_REPLAY_MAX_BYTES = 256 * 1024;
12
+ const DEFAULT_HEADLESS_REPLAY_SCROLLBACK_LINES = 10_000;
13
+ const DEFAULT_HEADLESS_REPLAY_MAX_BYTES = DEFAULT_DAEMON_LEGACY_REPLAY_MAX_BYTES;
14
+ const DEFAULT_HEADLESS_STATE_MAX_SESSIONS = 8;
15
+ const DEFAULT_HEADLESS_STATE_TTL_MS = 10 * 60_000;
16
+ function readPositiveIntegerEnv(name) {
17
+ const raw = process.env[name];
18
+ if (!raw)
19
+ return null;
20
+ const value = Number(raw);
21
+ if (!Number.isSafeInteger(value) || value <= 0)
22
+ return null;
23
+ return value;
24
+ }
25
+ function readBooleanEnv(name) {
26
+ const raw = process.env[name];
27
+ if (raw === undefined)
28
+ return null;
29
+ const value = raw.trim().toLowerCase();
30
+ if (value === "1" || value === "true" || value === "yes" || value === "on")
31
+ return true;
32
+ if (value === "0" || value === "false" || value === "no" || value === "off")
33
+ return false;
34
+ return null;
35
+ }
36
+ function readHeadlessReplayEnabled() {
37
+ return (readBooleanEnv("PARASOR_HEADLESS_REPLAY") ??
38
+ readBooleanEnv("PARASOR_EXPERIMENT_HEADLESS_REPLAY") ??
39
+ true);
40
+ }
41
+ function utf8Tail(text, maxBytes) {
42
+ const buf = Buffer.from(text, "utf8");
43
+ if (buf.length <= maxBytes)
44
+ return text;
45
+ const slice = buf.subarray(buf.length - maxBytes);
46
+ let start = 0;
47
+ while (start < slice.length && start < 3 && (slice[start] & 0xc0) === 0x80) {
48
+ start++;
49
+ }
50
+ return slice.subarray(start).toString("utf8");
51
+ }
52
+ export class RemotePtyHostError extends Error {
53
+ code;
54
+ constructor(code, message) {
55
+ super(message);
56
+ this.code = code;
57
+ this.name = "RemotePtyHostError";
58
+ }
59
+ }
60
+ const ACK_FRAME_TYPES = new Set([
61
+ FrameType.CREATE_ACK,
62
+ FrameType.RESTART_ACK,
63
+ FrameType.DISPOSE_ACK,
64
+ FrameType.DISPOSE_ALL_ACK,
65
+ FrameType.SHUTDOWN_ALL_ACK,
66
+ FrameType.INIT_CLIENT_ACK,
67
+ FrameType.PERSIST_PROJECT_DOMAINS_ACK,
68
+ ]);
69
+ export class RemotePtyHost {
70
+ socket;
71
+ parser = new FrameParser();
72
+ requestTimeoutMs;
73
+ scrollbackLog;
74
+ daemonLegacyReplayMaxBytes;
75
+ headlessReplayEnabled;
76
+ headlessReplayScrollbackLines;
77
+ headlessReplayMaxBytes;
78
+ headlessStateCache;
79
+ /**
80
+ * owns the `connecting ->
81
+ * snapshot-pending -> ready / dropped` transitions, the connectionId +
82
+ * generation stamped at HELLO_ACK time, and the deferred handshake
83
+ * Promise. Socket-agnostic by construction; this host drives transitions
84
+ * and reads the stamped headers when emitting frames.
85
+ * See {@link ConnectionLifecycle}.
86
+ */
87
+ lifecycle = new ConnectionLifecycle();
88
+ /**
89
+ * Request/response correlation: monotonic requestId, the pending-id Map,
90
+ * per-request timeout scheduling, and ACK/NACK/drop dispatch. Socket-
91
+ * agnostic by construction; state-machine guards and wire encoding live
92
+ * on this host. See {@link RequestCorrelator}.
93
+ */
94
+ correlator;
95
+ /**
96
+ * Local view-state of daemon-owned sessions plus the PTY generation gate per-session
97
+ * generation latch. Pure, socket-free reconciliation lives in
98
+ * {@link SessionMirror}; this shell only feeds it decoded frames.
99
+ */
100
+ mirror = new SessionMirror();
101
+ attached = new Map();
102
+ /** Attach fencing -- server-local monotonic counter for attach-token mintage. */
103
+ nextAttachToken = 1;
104
+ /**
105
+ * Session IDs we have ever appended scrollback for. Tracked separately
106
+ * from `mirror` so disposeAll() can purge files even if the daemon's
107
+ * SESSION_LIST snapshot lagged behind a DATA broadcast at shutdown
108
+ * time. Cleared on `dispose(id)` / `disposeAll()`.
109
+ */
110
+ scrollbackOwnedIds = new Set();
111
+ ptyEnv = {};
112
+ dataListeners = [];
113
+ inputListeners = [];
114
+ onSessionExit = null;
115
+ /**
116
+ * Build + handshake in one step. Use this from production code; tests
117
+ * may want to drive HELLO_ACK manually and can poke `_internal` instead.
118
+ */
119
+ static async connect(deps) {
120
+ const host = new RemotePtyHost(deps);
121
+ /*
122
+ * a daemon that accept()s the socket but
123
+ * never sends HELLO_ACK / SESSION_LIST would hang server boot
124
+ * indefinitely. Race the handshake against a deadline; on timeout
125
+ * destroy the socket (which fires the `error` listener attached in
126
+ * the constructor -> handleDrop -> rejectHandshake), then surface a
127
+ * typed `handshake-timeout` error to the caller.
128
+ */
129
+ await raceHandshakeWithTimeout({
130
+ awaiter: host.lifecycle.awaitReady,
131
+ timeoutMs: deps.handshakeTimeoutMs ?? 10_000,
132
+ onTimeout: () => deps.socket.destroy(),
133
+ buildTimeoutError: (timeoutMs) => new RemotePtyHostError("handshake-timeout", `parasor-pty-host handshake did not complete within ${timeoutMs}ms`),
134
+ });
135
+ return host;
136
+ }
137
+ constructor(deps) {
138
+ this.socket = deps.socket;
139
+ this.requestTimeoutMs = deps.requestTimeoutMs ?? 30_000;
140
+ this.scrollbackLog = deps.scrollbackLog ?? null;
141
+ const configuredDaemonLegacyReplayMaxBytes = deps.daemonLegacyReplayMaxBytes;
142
+ this.daemonLegacyReplayMaxBytes =
143
+ (typeof configuredDaemonLegacyReplayMaxBytes === "number" &&
144
+ Number.isSafeInteger(configuredDaemonLegacyReplayMaxBytes) &&
145
+ configuredDaemonLegacyReplayMaxBytes > 0
146
+ ? configuredDaemonLegacyReplayMaxBytes
147
+ : null) ??
148
+ readPositiveIntegerEnv("PARASOR_DAEMON_LEGACY_REPLAY_MAX_BYTES") ??
149
+ DEFAULT_DAEMON_LEGACY_REPLAY_MAX_BYTES;
150
+ this.headlessReplayEnabled = readHeadlessReplayEnabled();
151
+ this.headlessReplayScrollbackLines =
152
+ readPositiveIntegerEnv("PARASOR_HEADLESS_REPLAY_SCROLLBACK_LINES") ??
153
+ DEFAULT_HEADLESS_REPLAY_SCROLLBACK_LINES;
154
+ this.headlessReplayMaxBytes =
155
+ readPositiveIntegerEnv("PARASOR_HEADLESS_REPLAY_MAX_BYTES") ??
156
+ DEFAULT_HEADLESS_REPLAY_MAX_BYTES;
157
+ this.headlessStateCache = this.headlessReplayEnabled
158
+ ? new HeadlessTerminalStateCache({
159
+ cols: 80,
160
+ rows: 24,
161
+ scrollbackLines: this.headlessReplayScrollbackLines,
162
+ maxBytes: this.headlessReplayMaxBytes,
163
+ maxSessions: readPositiveIntegerEnv("PARASOR_HEADLESS_STATE_MAX_SESSIONS") ??
164
+ DEFAULT_HEADLESS_STATE_MAX_SESSIONS,
165
+ ttlMs: readPositiveIntegerEnv("PARASOR_HEADLESS_STATE_TTL_MS") ??
166
+ DEFAULT_HEADLESS_STATE_TTL_MS,
167
+ })
168
+ : null;
169
+ this.correlator = new RequestCorrelator({
170
+ timeoutMs: this.requestTimeoutMs,
171
+ buildTimeoutError: (requestId, timeoutMs) => new RemotePtyHostError("ipc-timeout", `request ${requestId} timed out after ${timeoutMs}ms`),
172
+ send: (type, requestId, payload) => this.send(type, requestId, payload),
173
+ });
174
+ this.socket.on("data", (chunk) => this.handleChunk(chunk));
175
+ this.socket.on("close", () => this.handleDrop("connection closed"));
176
+ this.socket.on("error", () => this.handleDrop("socket error"));
177
+ this.sendHello(deps.serverPid ?? process.pid);
178
+ }
179
+ // --- handshake ---
180
+ sendHello(serverPid) {
181
+ const payload = {
182
+ protocolVersion: PROTOCOL_VERSION,
183
+ serverPid,
184
+ };
185
+ this.socket.write(encodeFrame({
186
+ type: FrameType.HELLO,
187
+ connectionId: 0,
188
+ generation: 0n,
189
+ requestId: 1,
190
+ payload: encodeJsonPayload(payload),
191
+ }));
192
+ }
193
+ // --- frame ingestion ---
194
+ handleChunk(chunk) {
195
+ let frames;
196
+ try {
197
+ frames = this.parser.push(chunk);
198
+ }
199
+ catch (err) {
200
+ this.handleDrop(err instanceof FrameError ? `parser: ${err.message}` : "parser failure");
201
+ return;
202
+ }
203
+ for (const frame of frames) {
204
+ if (this.lifecycle.isDropped)
205
+ return;
206
+ this.dispatch(frame);
207
+ }
208
+ }
209
+ dispatch(frame) {
210
+ if (frame.type === FrameType.HELLO_ACK) {
211
+ this.onHelloAck(frame);
212
+ return;
213
+ }
214
+ if (frame.type === FrameType.NACK) {
215
+ this.onNack(frame);
216
+ return;
217
+ }
218
+ /*
219
+ * Permit SESSION_LIST during snapshot-pending -- that frame *completes*
220
+ * the handshake. Everything else (ACKs, SESSION_UPDATE/EXIT, DATA,
221
+ * SESSION_INPUT) requires `ready`: requests are gated behind
222
+ * handshakePromise so no ACK should arrive early, and broadcasts
223
+ * before the initial snapshot would land in an empty mirror.
224
+ */
225
+ if (this.lifecycle.current === "snapshot-pending") {
226
+ if (frame.type === FrameType.SESSION_LIST) {
227
+ this.applySessionList(frame);
228
+ }
229
+ return;
230
+ }
231
+ if (!this.lifecycle.isReady)
232
+ return;
233
+ if (ACK_FRAME_TYPES.has(frame.type)) {
234
+ // Stale acks (peer slow / fenced) return false from the correlator
235
+ // and are silently dropped -- same behavior as the prior inline lookup.
236
+ this.correlator.ack(frame);
237
+ return;
238
+ }
239
+ switch (frame.type) {
240
+ case FrameType.SESSION_UPDATE:
241
+ this.applySessionUpdate(frame);
242
+ return;
243
+ case FrameType.SESSION_LIST:
244
+ this.applySessionList(frame);
245
+ return;
246
+ case FrameType.SESSION_EXIT:
247
+ this.applySessionExit(frame);
248
+ return;
249
+ case FrameType.DATA:
250
+ this.applyData(frame);
251
+ return;
252
+ case FrameType.SESSION_INPUT:
253
+ this.applySessionInput(frame);
254
+ return;
255
+ default:
256
+ // Unknown daemon->server frame type. Log-equivalent is no-op
257
+ // since we don't have a console channel here; the daemon would
258
+ // never send something we don't know during normal operation.
259
+ return;
260
+ }
261
+ }
262
+ onHelloAck(frame) {
263
+ if (this.lifecycle.current !== "connecting")
264
+ return;
265
+ const result = validateHelloAck(frame.payload, PROTOCOL_VERSION);
266
+ if (!result.ok) {
267
+ this.lifecycle.drop(new RemotePtyHostError(result.code, result.message));
268
+ return;
269
+ }
270
+ /*
271
+ * Design contract: handshake "ready" is HELLO_ACK + first SESSION_LIST applied.
272
+ * applyHelloAck transitions to snapshot-pending; the resolve fires from
273
+ * applySessionList -> lifecycle.markReady once the initial snapshot lands.
274
+ */
275
+ this.lifecycle.applyHelloAck(result.connectionId, result.generation);
276
+ }
277
+ onNack(frame) {
278
+ let body;
279
+ try {
280
+ body = decodeJsonPayload(frame.payload);
281
+ }
282
+ catch {
283
+ this.handleDrop("undecodable NACK");
284
+ return;
285
+ }
286
+ if (frame.requestId !== 0) {
287
+ // requestId=0 is handled below as a connection-level NACK; otherwise
288
+ // delegate to the correlator. Stale ids (peer slow / fenced) are a
289
+ // no-op -- same behavior as the prior inline lookup.
290
+ this.correlator.nack(frame.requestId, new RemotePtyHostError(body.code, body.message));
291
+ return;
292
+ }
293
+ /*
294
+ * requestId=0 NACK is a connection-level fault: handshake-required,
295
+ * version-mismatch, evicted, daemon-shutting-down, or a malformed
296
+ * frame the daemon refused. Either way, the wire is dead -- drop and
297
+ * let the supervisor rebuild.
298
+ */
299
+ if (this.lifecycle.isAwaitingHandshake) {
300
+ // Reject the awaiter with the daemon's specific NACK code BEFORE
301
+ // handleDrop runs -- Promise rejection is idempotent so the subsequent
302
+ // drop()'s "connection-dropped" reject is a no-op, preserving the
303
+ // daemon-specific error on the connect() awaiter side.
304
+ this.lifecycle.rejectHandshakeOnly(new RemotePtyHostError(body.code, body.message));
305
+ }
306
+ this.handleDrop(`daemon NACK: ${body.code} ${body.message}`);
307
+ }
308
+ // --- broadcast handlers (mirror reconciliation + listener fan-out) ---
309
+ applySessionUpdate(frame) {
310
+ const body = decodeJsonPayload(frame.payload);
311
+ this.mirror.upsert(body.session);
312
+ }
313
+ applySessionList(frame) {
314
+ const body = decodeJsonPayload(frame.payload);
315
+ this.mirror.applyList(body.sessions);
316
+ // Idempotent: markReady returns false on any state other than
317
+ // snapshot-pending, so later SESSION_LIST broadcasts just update the
318
+ // mirror without re-resolving the handshake.
319
+ this.lifecycle.markReady();
320
+ }
321
+ applySessionExit(frame) {
322
+ const body = decodeJsonPayload(frame.payload);
323
+ this.mirror.applyExit(body.sessionId, body.endReason);
324
+ this.onSessionExit?.(body.sessionId, body.sessionGeneration, body.endReason);
325
+ }
326
+ applyData(frame) {
327
+ /*
328
+ * PTY generation gate: DATA frames now carry a `[idLen][sessionId][gen:u32 BE][data]`
329
+ * payload (PROTOCOL_VERSION 2.0.0). The generation is recorded into
330
+ * `latestGeneration` so the binary `attachClient` adapter can read
331
+ * the live value when wrapping `sink.onChunk`, and is forwarded to
332
+ * `dataListeners` (the WS handler stamps it into OUTPUT frames so
333
+ * the client echoes it back on INPUT). String per-client listeners
334
+ * stay generation-agnostic -- those are the legacy non-binary attach
335
+ * path that does not feed back into the input gate.
336
+ */
337
+ const decoded = decodeGenerationStreamPayload(frame.payload);
338
+ const data = decoded.data.toString("utf8");
339
+ /*
340
+ * PTY generation gate: advance the monotonic generation latch and learn whether this
341
+ * chunk is stale. The daemon's in-process host can flush an old-generation
342
+ * batch AFTER auto-resume bumps the generation (the setImmediate that
343
+ * captured generationAtSpawn fires post-respawn); those late chunks arrive
344
+ * tagged with the old gen. The mirror only moves the latch forward, so the
345
+ * next INPUT frame echoes the current gen rather than the stale one.
346
+ */
347
+ const { stale: isStale } = this.mirror.recordDataGeneration(decoded.sessionId, decoded.generation);
348
+ /*
349
+ * PTY generation gate: stale-gen DATA must not reach attached clients
350
+ * or scrollback in daemon mode. The in-process side already gates
351
+ * its `attachedClients` broadcast on `generationStillCurrent` so
352
+ * old-PTY bytes never hit a client xterm; the daemon symmetric path
353
+ * is here. If we forwarded a stale chunk, the per-client wrapper in
354
+ * `attachClient()` would read the latch value and re-tag those bytes
355
+ * with the NEW gen -- defeating the whole PTY generation gate fence. Worse: scrollback
356
+ * would record stale bytes AFTER fresh ones, corrupting the on-disk
357
+ * replay order. Drop the fanout / scrollback when stale; keep
358
+ * `dataListeners` so debug / recording observers still see every byte
359
+ * tagged with its true emit-time generation (they self-decide on staleness).
360
+ */
361
+ if (!isStale) {
362
+ void this.headlessStateCache
363
+ ?.writeExisting(decoded.sessionId, data)
364
+ .catch((err) => {
365
+ console.warn(`[terminal] headless state update failed for session=${decoded.sessionId.slice(0, 8)}: ${err.message}`);
366
+ this.headlessStateCache?.delete(decoded.sessionId);
367
+ });
368
+ const clients = this.attached.get(decoded.sessionId);
369
+ if (clients) {
370
+ for (const client of clients.values()) {
371
+ try {
372
+ client.listener(data);
373
+ }
374
+ catch {
375
+ // listener faults are not fatal; isolate so one bad client
376
+ // doesn't break broadcast for siblings.
377
+ }
378
+ }
379
+ }
380
+ }
381
+ for (const listener of this.dataListeners) {
382
+ try {
383
+ listener(decoded.sessionId, data, decoded.generation);
384
+ }
385
+ catch {
386
+ /* same isolation */
387
+ }
388
+ }
389
+ /*
390
+ * Persist every fresh DATA chunk to the per-session disk log so a
391
+ * re-mounting xterm (tab switch, dev-server reload while the daemon
392
+ * survives) can rehydrate via `replay:"full"`. The daemon owns PTY
393
+ * lifetime in this mode; without our own append the server has no
394
+ * way to feed scrollback back to a fresh client. Buffered+throttled
395
+ * inside ScrollbackLog so the broadcast hot path stays cheap.
396
+ * Stale-gen chunks are intentionally skipped so a
397
+ * subsequent `replay:"full"` does not surface old-PTY bytes after
398
+ * the new spawn's prompt.
399
+ */
400
+ if (this.scrollbackLog && !isStale) {
401
+ this.scrollbackLog.append(decoded.sessionId, data);
402
+ this.scrollbackOwnedIds.add(decoded.sessionId);
403
+ }
404
+ }
405
+ applySessionInput(frame) {
406
+ const decoded = decodeStreamPayload(frame.payload);
407
+ const data = decoded.data.toString("utf8");
408
+ for (const listener of this.inputListeners) {
409
+ try {
410
+ listener(decoded.sessionId, data);
411
+ }
412
+ catch {
413
+ /* ignore */
414
+ }
415
+ }
416
+ }
417
+ // --- send helpers ---
418
+ send(type, requestId, payload) {
419
+ if (this.lifecycle.isDropped)
420
+ return;
421
+ try {
422
+ this.socket.write(encodeFrame({
423
+ type,
424
+ connectionId: this.lifecycle.connectionId,
425
+ generation: this.lifecycle.generation,
426
+ requestId,
427
+ payload,
428
+ }));
429
+ }
430
+ catch {
431
+ this.handleDrop("write failure");
432
+ }
433
+ }
434
+ fireAndForget(type, payload) {
435
+ if (!this.lifecycle.isReady)
436
+ return;
437
+ this.send(type, 0, payload);
438
+ }
439
+ async request(type, payload) {
440
+ if (this.lifecycle.isDropped) {
441
+ throw new RemotePtyHostError("connection-dropped", "RemotePtyHost socket is dropped");
442
+ }
443
+ if (this.lifecycle.isAwaitingHandshake) {
444
+ // Defer until handshake completes (HELLO_ACK + first SESSION_LIST);
445
+ // if it rejects, propagate.
446
+ await this.lifecycle.awaitReady;
447
+ }
448
+ return this.correlator.request(type, payload);
449
+ }
450
+ handleDrop(reason) {
451
+ const err = new RemotePtyHostError("connection-dropped", reason);
452
+ // lifecycle.drop transitions to 'dropped' and rejects the handshake
453
+ // promise if it was still awaiting (Promise reject is idempotent, so a
454
+ // prior rejectHandshakeOnly with a daemon-specific code wins). Returns
455
+ // false when state was already 'dropped' -- gate correlator.rejectAll on
456
+ // the actual transition so a re-entry from the close/error listener
457
+ // pair doesn't fire a second bulk reject.
458
+ if (this.lifecycle.drop(err)) {
459
+ this.correlator.rejectAll(err);
460
+ }
461
+ }
462
+ // --- PtyHost interface (async) ---
463
+ async create(input) {
464
+ const payload = {
465
+ projectId: input.projectId,
466
+ command: input.command,
467
+ cwd: input.cwd,
468
+ title: input.title,
469
+ bootstrapInput: input.bootstrapInput,
470
+ };
471
+ const ack = await this.request(FrameType.CREATE_REQ, encodeJsonPayload(payload));
472
+ const body = decodeJsonPayload(ack.payload);
473
+ this.mirror.upsert(body.session);
474
+ return body.session;
475
+ }
476
+ async restart(id) {
477
+ const payload = { sessionId: id };
478
+ const ack = await this.request(FrameType.RESTART_REQ, encodeJsonPayload(payload));
479
+ const body = decodeJsonPayload(ack.payload);
480
+ /*
481
+ * PTY generation gate: restart bumps the generation server-side. `upsert` seeds the
482
+ * latch so the WS client's first INPUT after restart is sent under the
483
+ * new generation; otherwise it races the first DATA chunk under the old
484
+ * gen, trips the daemon-side input gate, and drops the keystroke.
485
+ */
486
+ this.mirror.upsert(body.session);
487
+ return body.session;
488
+ }
489
+ async dispose(id) {
490
+ const payload = { sessionId: id };
491
+ await this.request(FrameType.DISPOSE_REQ, encodeJsonPayload(payload));
492
+ this.mirror.remove(id);
493
+ this.attached.delete(id);
494
+ this.headlessStateCache?.delete(id);
495
+ if (this.scrollbackLog) {
496
+ this.scrollbackLog.remove(id);
497
+ this.scrollbackOwnedIds.delete(id);
498
+ }
499
+ }
500
+ async disposeAll() {
501
+ await this.request(FrameType.DISPOSE_ALL_REQ, encodeJsonPayload({}));
502
+ this.mirror.clear();
503
+ this.attached.clear();
504
+ this.headlessStateCache?.clear();
505
+ if (this.scrollbackLog) {
506
+ for (const id of this.scrollbackOwnedIds)
507
+ this.scrollbackLog.remove(id);
508
+ this.scrollbackOwnedIds.clear();
509
+ }
510
+ }
511
+ /**
512
+ * By protocol, `shutdownAll` is detach-only: the
513
+ * daemon ACKs and then evicts our connection. We swallow the
514
+ * subsequent `connection-dropped` to make caller code shape-identical
515
+ * to `InProcessPtyHost.shutdownAll()` (which never throws).
516
+ *
517
+ * The `reason` parameter is accepted to satisfy the `PtyHost`
518
+ * interface (in-process uses it to stamp `endReason` on every session
519
+ * record); on the remote path it has no effect -- the daemon owns the
520
+ * sessions and will stamp its own `daemon-graceful`/`daemon-crash` on
521
+ * its next own SIGTERM.
522
+ */
523
+ async shutdownAll(_reason) {
524
+ if (!this.lifecycle.isReady)
525
+ return;
526
+ try {
527
+ await this.request(FrameType.SHUTDOWN_ALL_REQ, encodeJsonPayload({}));
528
+ }
529
+ catch (err) {
530
+ if (err instanceof RemotePtyHostError &&
531
+ err.code === "connection-dropped")
532
+ return;
533
+ throw err;
534
+ }
535
+ }
536
+ /**
537
+ * state persistence delegate / daemon state ownership -- implements `AppStatePersistenceDelegate.persist`. Ships
538
+ * the server-owned project-domain snapshot to the daemon, which is the
539
+ * sole writer of `state.json`. Resolves on PERSIST_PROJECT_DOMAINS_ACK,
540
+ * rejects on NACK / connection drop / IPC timeout. AppStateStore routes
541
+ * those rejections through `onPersistError` so a transient IPC fault
542
+ * does not silently lose project / projectStates / serviceConfig /
543
+ * paneCommands / ideCommands
544
+ * mutations.
545
+ *
546
+ * `sessions` and `sessionRecords` are deliberately not forwarded -- the
547
+ * daemon owns those domains and would overwrite its own snapshot if we
548
+ * did. Only the server-owned slices ride along.
549
+ */
550
+ async persist(state) {
551
+ const payload = {
552
+ projects: state.projects,
553
+ projectStates: state.projectStates,
554
+ serviceConfig: state.serviceConfig,
555
+ paneCommands: state.paneCommands,
556
+ ideCommands: state.ideCommands,
557
+ };
558
+ await this.request(FrameType.PERSIST_PROJECT_DOMAINS_REQ, encodeJsonPayload(payload));
559
+ }
560
+ async initClient(id, clientId, cols, rows, listener) {
561
+ const attachToken = this.nextAttachToken++;
562
+ const payload = {
563
+ sessionId: id,
564
+ clientId,
565
+ cols,
566
+ rows,
567
+ attachToken,
568
+ };
569
+ const ack = await this.request(FrameType.INIT_CLIENT_REQ, encodeJsonPayload(payload));
570
+ const body = decodeJsonPayload(ack.payload);
571
+ if (!body.accepted)
572
+ return { ok: false };
573
+ let bySession = this.attached.get(id);
574
+ if (!bySession) {
575
+ bySession = new Map();
576
+ this.attached.set(id, bySession);
577
+ }
578
+ bySession.set(clientId, { listener, attachToken });
579
+ return { ok: true, attachToken };
580
+ }
581
+ /**
582
+ * : daemon-mode chunked replay is out of scope for the
583
+ * initial implementation -- the daemon's STREAM_DATA frame does not yet
584
+ * carry the (gen, seq) header needed for the chunk ring to be
585
+ * authoritative end-to-end. We therefore negotiate
586
+ * `binary=false / chunkedReplay=false` so the client knows scrollback
587
+ * cursor semantics are legacy.
588
+ *
589
+ * Live OUTPUT is forwarded through the binary `sink.onChunk` path
590
+ * with a synthetic per-attach seq counter; the generation now comes
591
+ * from `latestGeneration` (PTY generation gate) so the WS layer stamps each OUTPUT
592
+ * with the producing PTY's true generation, the client echoes that
593
+ * back on INPUT, and the daemon-side gate can drop stale input that
594
+ * targets a no-longer-current generation. The client-side
595
+ * `serverState.lastDeliveredSeq=null` we return causes the client to
596
+ * drop any persisted cursor on init-ack -- so the synthetic seq cannot
597
+ * collide with a stale ring entry on reconnect.
598
+ *
599
+ * Scrollback rehydration: when a `ScrollbackLog` is supplied, the disk
600
+ * tail is shipped as `replay:"full"`. This fixes the "blank terminal
601
+ * on tab switch" regression -- without it, a re-mount sees nothing
602
+ * until fresh PTY output arrives, even though the daemon still owns
603
+ * the live session.
604
+ */
605
+ async attachClient(id, clientId, cols, rows, _capabilities, sink) {
606
+ let syntheticSeq = 0n;
607
+ const result = await this.initClient(id, clientId, cols, rows, (data) => {
608
+ const gen = this.mirror.generationOf(id);
609
+ sink.onChunk(gen, syntheticSeq++, Buffer.from(data, "utf8"));
610
+ });
611
+ if (!result.ok)
612
+ return { ok: false };
613
+ const seedGen = this.mirror.generationOf(id);
614
+ const tail = this.scrollbackLog?.readTail(id) ?? "";
615
+ if (tail.length > 0) {
616
+ let fullReplay;
617
+ let replayDiagnostics;
618
+ const rawBytes = Buffer.byteLength(tail, "utf8");
619
+ if (this.headlessReplayEnabled && this.headlessStateCache) {
620
+ try {
621
+ const headlessSnapshot = (await this.headlessStateCache.snapshot(id, { cols, rows })) ??
622
+ (await this.headlessStateCache.rebuild(id, tail, { cols, rows }));
623
+ if (!headlessSnapshot) {
624
+ throw new Error("empty headless replay snapshot");
625
+ }
626
+ const snapshot = headlessSnapshot.snapshot;
627
+ fullReplay = headlessSnapshot.snapshot.text;
628
+ replayDiagnostics = {
629
+ source: headlessSnapshot.source,
630
+ rawBytes: snapshot.rawBytes,
631
+ replayBytes: snapshot.snapshotBytes,
632
+ headlessDurationMs: snapshot.durationMs,
633
+ headlessBufferLines: snapshot.bufferLines,
634
+ headlessEmittedLines: snapshot.emittedLines,
635
+ scrollbackLines: this.headlessReplayScrollbackLines,
636
+ maxBytes: this.headlessReplayMaxBytes,
637
+ };
638
+ }
639
+ catch (err) {
640
+ console.warn(`[terminal] headless replay snapshot failed for session=${id.slice(0, 8)}: ${err.message}`);
641
+ fullReplay = stripQueryEscapes(utf8Tail(tail, this.daemonLegacyReplayMaxBytes));
642
+ replayDiagnostics = {
643
+ source: "headless-fallback",
644
+ rawBytes,
645
+ replayBytes: Buffer.byteLength(fullReplay, "utf8"),
646
+ scrollbackLines: this.headlessReplayScrollbackLines,
647
+ maxBytes: this.headlessReplayMaxBytes,
648
+ };
649
+ }
650
+ }
651
+ else {
652
+ fullReplay = stripQueryEscapes(utf8Tail(tail, this.daemonLegacyReplayMaxBytes));
653
+ replayDiagnostics = {
654
+ source: "raw-tail",
655
+ rawBytes,
656
+ replayBytes: Buffer.byteLength(fullReplay, "utf8"),
657
+ maxBytes: this.daemonLegacyReplayMaxBytes,
658
+ };
659
+ }
660
+ return {
661
+ ok: true,
662
+ attachToken: result.attachToken,
663
+ capabilities: { binary: false, chunkedReplay: false },
664
+ serverState: {
665
+ generation: seedGen,
666
+ lastDeliveredSeq: null,
667
+ oldestSeq: null,
668
+ },
669
+ replay: "full",
670
+ fullReplay,
671
+ replayDiagnostics,
672
+ };
673
+ }
674
+ return {
675
+ ok: true,
676
+ attachToken: result.attachToken,
677
+ capabilities: { binary: false, chunkedReplay: false },
678
+ serverState: {
679
+ generation: seedGen,
680
+ lastDeliveredSeq: null,
681
+ oldestSeq: null,
682
+ },
683
+ replay: "none",
684
+ };
685
+ }
686
+ // --- PtyHost interface (sync mutators, fire-and-forget) ---
687
+ setPtyEnv(env) {
688
+ this.ptyEnv = { ...this.ptyEnv, ...env };
689
+ const payload = { env };
690
+ this.fireAndForget(FrameType.SET_PTY_ENV, encodeJsonPayload(payload));
691
+ }
692
+ setTitle(id, title, titleManual = false) {
693
+ const session = this.mirror.get(id);
694
+ if (!session)
695
+ return false;
696
+ const next = titleManual
697
+ ? { ...session, title, titleManual: true }
698
+ : (() => {
699
+ const { titleManual: _drop, ...rest } = session;
700
+ return { ...rest, title };
701
+ })();
702
+ this.mirror.replace(next);
703
+ const payload = { sessionId: id, title, titleManual };
704
+ this.fireAndForget(FrameType.SET_TITLE, encodeJsonPayload(payload));
705
+ return true;
706
+ }
707
+ setPinned(id, pinned) {
708
+ const session = this.mirror.get(id);
709
+ if (!session)
710
+ return false;
711
+ /*
712
+ * Match InProcessPtyHost's optimistic shape: drop the `pinned`
713
+ * key entirely when it goes false, set it to `true` when true.
714
+ * This keeps the Liskov contract intact -- callers reading the
715
+ * mirror sync after setPinned() see the same shape regardless of
716
+ * implementation.
717
+ */
718
+ if (pinned) {
719
+ this.mirror.replace({ ...session, pinned: true });
720
+ }
721
+ else {
722
+ const { pinned: _drop, ...rest } = session;
723
+ this.mirror.replace(rest);
724
+ }
725
+ const payload = { sessionId: id, pinned };
726
+ this.fireAndForget(FrameType.SET_PINNED, encodeJsonPayload(payload));
727
+ return true;
728
+ }
729
+ write(id, data, generation) {
730
+ /*
731
+ * PTY generation gate: forward the client-supplied generation across the IPC so the
732
+ * daemon-side InProcessPtyHost can apply the same drop-stale-input
733
+ * gate that in-process mode uses. `0` is a sentinel meaning "no
734
+ * gating" (legacy callers / non-WS writes); the daemon treats `0`
735
+ * the same way an `undefined` generation arg would be treated.
736
+ */
737
+ this.fireAndForget(FrameType.WRITE, encodeGenerationStreamPayload(id, Buffer.from(data, "utf8"), generation ?? 0));
738
+ }
739
+ resize(id, cols, rows) {
740
+ const payload = { sessionId: id, cols, rows };
741
+ this.fireAndForget(FrameType.RESIZE, encodeJsonPayload(payload));
742
+ }
743
+ refresh(id) {
744
+ const payload = { sessionId: id };
745
+ this.fireAndForget(FrameType.REFRESH, encodeJsonPayload(payload));
746
+ }
747
+ pauseOutput(id, clientId) {
748
+ const payload = { sessionId: id, clientId };
749
+ this.fireAndForget(FrameType.PAUSE_OUTPUT, encodeJsonPayload(payload));
750
+ }
751
+ resumeOutput(id, clientId) {
752
+ const payload = { sessionId: id, clientId };
753
+ this.fireAndForget(FrameType.RESUME_OUTPUT, encodeJsonPayload(payload));
754
+ }
755
+ detachClient(id, clientId, expectedToken) {
756
+ const bySession = this.attached.get(id);
757
+ if (expectedToken !== undefined) {
758
+ const entry = bySession?.get(clientId);
759
+ if (!entry || entry.attachToken !== expectedToken)
760
+ return;
761
+ }
762
+ if (bySession) {
763
+ bySession.delete(clientId);
764
+ if (bySession.size === 0)
765
+ this.attached.delete(id);
766
+ }
767
+ const payload = {
768
+ sessionId: id,
769
+ clientId,
770
+ ...(expectedToken !== undefined && { attachToken: expectedToken }),
771
+ };
772
+ this.fireAndForget(FrameType.DETACH_CLIENT, encodeJsonPayload(payload));
773
+ }
774
+ // --- PtyHost interface (sync read accessors, mirror-served) ---
775
+ list() {
776
+ return this.mirror.list();
777
+ }
778
+ get(id) {
779
+ return this.mirror.get(id);
780
+ }
781
+ listByProject(projectId) {
782
+ return this.mirror.listByProject(projectId);
783
+ }
784
+ /*
785
+ * Scrollback is served from the server-side disk log populated by
786
+ * `applyData`. Foreground-process state still lives in the daemon's
787
+ * AppStateStore and is reachable only via SESSION_UPDATE -- the
788
+ * accessor stays null per the mismatch column.
789
+ */
790
+ getScrollback(id) {
791
+ if (!this.scrollbackLog)
792
+ return null;
793
+ const tail = this.scrollbackLog.readTail(id);
794
+ return tail.length > 0 ? tail : null;
795
+ }
796
+ getForegroundProcess(_id) {
797
+ return null;
798
+ }
799
+ loadPersistedSession(_session, _wasGracefulShutdown) {
800
+ // No-op on remote: the daemon owns persistence and SESSION_LIST is the
801
+ // server mirror's source of truth.
802
+ }
803
+ onSessionInput(listener) {
804
+ this.inputListeners.push(listener);
805
+ }
806
+ onSessionData(listener) {
807
+ this.dataListeners.push(listener);
808
+ }
809
+ }
810
+ //# sourceMappingURL=remote-host.js.map