@jacques-ai/server 0.0.7-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/dist/config/config.d.ts +34 -0
  2. package/dist/config/config.d.ts.map +1 -0
  3. package/dist/config/config.js +32 -0
  4. package/dist/config/config.js.map +1 -0
  5. package/dist/connection/applescript.d.ts +46 -0
  6. package/dist/connection/applescript.d.ts.map +1 -0
  7. package/dist/connection/applescript.js +62 -0
  8. package/dist/connection/applescript.js.map +1 -0
  9. package/dist/connection/applescript.test.d.ts +5 -0
  10. package/dist/connection/applescript.test.d.ts.map +1 -0
  11. package/dist/connection/applescript.test.js +64 -0
  12. package/dist/connection/applescript.test.js.map +1 -0
  13. package/dist/connection/constants.d.ts +88 -0
  14. package/dist/connection/constants.d.ts.map +1 -0
  15. package/dist/connection/constants.js +110 -0
  16. package/dist/connection/constants.js.map +1 -0
  17. package/dist/connection/git-info.d.ts +30 -0
  18. package/dist/connection/git-info.d.ts.map +1 -0
  19. package/dist/connection/git-info.js +52 -0
  20. package/dist/connection/git-info.js.map +1 -0
  21. package/dist/connection/git-info.test.d.ts +5 -0
  22. package/dist/connection/git-info.test.d.ts.map +1 -0
  23. package/dist/connection/git-info.test.js +35 -0
  24. package/dist/connection/git-info.test.js.map +1 -0
  25. package/dist/connection/index.d.ts +19 -0
  26. package/dist/connection/index.d.ts.map +1 -0
  27. package/dist/connection/index.js +36 -0
  28. package/dist/connection/index.js.map +1 -0
  29. package/dist/connection/process-detection.d.ts +58 -0
  30. package/dist/connection/process-detection.d.ts.map +1 -0
  31. package/dist/connection/process-detection.js +239 -0
  32. package/dist/connection/process-detection.js.map +1 -0
  33. package/dist/connection/process-detection.test.d.ts +5 -0
  34. package/dist/connection/process-detection.test.d.ts.map +1 -0
  35. package/dist/connection/process-detection.test.js +43 -0
  36. package/dist/connection/process-detection.test.js.map +1 -0
  37. package/dist/connection/session-discovery.d.ts +55 -0
  38. package/dist/connection/session-discovery.d.ts.map +1 -0
  39. package/dist/connection/session-discovery.js +311 -0
  40. package/dist/connection/session-discovery.js.map +1 -0
  41. package/dist/connection/terminal-key.d.ts +126 -0
  42. package/dist/connection/terminal-key.d.ts.map +1 -0
  43. package/dist/connection/terminal-key.js +271 -0
  44. package/dist/connection/terminal-key.js.map +1 -0
  45. package/dist/connection/terminal-key.test.d.ts +5 -0
  46. package/dist/connection/terminal-key.test.d.ts.map +1 -0
  47. package/dist/connection/terminal-key.test.js +221 -0
  48. package/dist/connection/terminal-key.test.js.map +1 -0
  49. package/dist/connection/worktree.d.ts +114 -0
  50. package/dist/connection/worktree.d.ts.map +1 -0
  51. package/dist/connection/worktree.js +320 -0
  52. package/dist/connection/worktree.js.map +1 -0
  53. package/dist/connection/worktree.test.d.ts +5 -0
  54. package/dist/connection/worktree.test.d.ts.map +1 -0
  55. package/dist/connection/worktree.test.js +113 -0
  56. package/dist/connection/worktree.test.js.map +1 -0
  57. package/dist/focus-watcher.d.ts +51 -0
  58. package/dist/focus-watcher.d.ts.map +1 -0
  59. package/dist/focus-watcher.js +169 -0
  60. package/dist/focus-watcher.js.map +1 -0
  61. package/dist/handlers/event-handler.d.ts +93 -0
  62. package/dist/handlers/event-handler.d.ts.map +1 -0
  63. package/dist/handlers/event-handler.js +196 -0
  64. package/dist/handlers/event-handler.js.map +1 -0
  65. package/dist/handlers/event-handler.test.d.ts +5 -0
  66. package/dist/handlers/event-handler.test.d.ts.map +1 -0
  67. package/dist/handlers/event-handler.test.js +305 -0
  68. package/dist/handlers/event-handler.test.js.map +1 -0
  69. package/dist/handlers/session-handler.d.ts +23 -0
  70. package/dist/handlers/session-handler.d.ts.map +1 -0
  71. package/dist/handlers/session-handler.js +104 -0
  72. package/dist/handlers/session-handler.js.map +1 -0
  73. package/dist/handlers/session-handler.test.d.ts +5 -0
  74. package/dist/handlers/session-handler.test.d.ts.map +1 -0
  75. package/dist/handlers/session-handler.test.js +89 -0
  76. package/dist/handlers/session-handler.test.js.map +1 -0
  77. package/dist/handlers/settings-handler.d.ts +32 -0
  78. package/dist/handlers/settings-handler.d.ts.map +1 -0
  79. package/dist/handlers/settings-handler.js +127 -0
  80. package/dist/handlers/settings-handler.js.map +1 -0
  81. package/dist/handlers/settings-handler.test.d.ts +5 -0
  82. package/dist/handlers/settings-handler.test.d.ts.map +1 -0
  83. package/dist/handlers/settings-handler.test.js +105 -0
  84. package/dist/handlers/settings-handler.test.js.map +1 -0
  85. package/dist/handlers/window-handler.d.ts +30 -0
  86. package/dist/handlers/window-handler.d.ts.map +1 -0
  87. package/dist/handlers/window-handler.js +486 -0
  88. package/dist/handlers/window-handler.js.map +1 -0
  89. package/dist/handlers/window-handler.test.d.ts +8 -0
  90. package/dist/handlers/window-handler.test.d.ts.map +1 -0
  91. package/dist/handlers/window-handler.test.js +167 -0
  92. package/dist/handlers/window-handler.test.js.map +1 -0
  93. package/dist/handlers/worktree-handler.d.ts +28 -0
  94. package/dist/handlers/worktree-handler.d.ts.map +1 -0
  95. package/dist/handlers/worktree-handler.js +268 -0
  96. package/dist/handlers/worktree-handler.js.map +1 -0
  97. package/dist/handlers/worktree-handler.test.d.ts +8 -0
  98. package/dist/handlers/worktree-handler.test.d.ts.map +1 -0
  99. package/dist/handlers/worktree-handler.test.js +118 -0
  100. package/dist/handlers/worktree-handler.test.js.map +1 -0
  101. package/dist/handlers/ws-utils.d.ts +12 -0
  102. package/dist/handlers/ws-utils.d.ts.map +1 -0
  103. package/dist/handlers/ws-utils.js +16 -0
  104. package/dist/handlers/ws-utils.js.map +1 -0
  105. package/dist/http-api.d.ts +26 -0
  106. package/dist/http-api.d.ts.map +1 -0
  107. package/dist/http-api.js +148 -0
  108. package/dist/http-api.js.map +1 -0
  109. package/dist/logger.d.ts +42 -0
  110. package/dist/logger.d.ts.map +1 -0
  111. package/dist/logger.js +147 -0
  112. package/dist/logger.js.map +1 -0
  113. package/dist/logging/logger-factory.d.ts +51 -0
  114. package/dist/logging/logger-factory.d.ts.map +1 -0
  115. package/dist/logging/logger-factory.js +59 -0
  116. package/dist/logging/logger-factory.js.map +1 -0
  117. package/dist/mcp/search-tool.d.ts +65 -0
  118. package/dist/mcp/search-tool.d.ts.map +1 -0
  119. package/dist/mcp/search-tool.js +176 -0
  120. package/dist/mcp/search-tool.js.map +1 -0
  121. package/dist/mcp/server.d.ts +9 -0
  122. package/dist/mcp/server.d.ts.map +1 -0
  123. package/dist/mcp/server.js +152 -0
  124. package/dist/mcp/server.js.map +1 -0
  125. package/dist/process-scanner.d.ts +96 -0
  126. package/dist/process-scanner.d.ts.map +1 -0
  127. package/dist/process-scanner.js +194 -0
  128. package/dist/process-scanner.js.map +1 -0
  129. package/dist/routes/__tests__/archive-routes.test.d.ts +5 -0
  130. package/dist/routes/__tests__/archive-routes.test.d.ts.map +1 -0
  131. package/dist/routes/__tests__/archive-routes.test.js +158 -0
  132. package/dist/routes/__tests__/archive-routes.test.js.map +1 -0
  133. package/dist/routes/__tests__/config-routes.test.d.ts +5 -0
  134. package/dist/routes/__tests__/config-routes.test.d.ts.map +1 -0
  135. package/dist/routes/__tests__/config-routes.test.js +112 -0
  136. package/dist/routes/__tests__/config-routes.test.js.map +1 -0
  137. package/dist/routes/__tests__/http-utils.test.d.ts +5 -0
  138. package/dist/routes/__tests__/http-utils.test.d.ts.map +1 -0
  139. package/dist/routes/__tests__/http-utils.test.js +102 -0
  140. package/dist/routes/__tests__/http-utils.test.js.map +1 -0
  141. package/dist/routes/__tests__/notification-routes.test.d.ts +5 -0
  142. package/dist/routes/__tests__/notification-routes.test.d.ts.map +1 -0
  143. package/dist/routes/__tests__/notification-routes.test.js +91 -0
  144. package/dist/routes/__tests__/notification-routes.test.js.map +1 -0
  145. package/dist/routes/__tests__/project-routes.test.d.ts +5 -0
  146. package/dist/routes/__tests__/project-routes.test.d.ts.map +1 -0
  147. package/dist/routes/__tests__/project-routes.test.js +168 -0
  148. package/dist/routes/__tests__/project-routes.test.js.map +1 -0
  149. package/dist/routes/__tests__/session-routes.test.d.ts +5 -0
  150. package/dist/routes/__tests__/session-routes.test.d.ts.map +1 -0
  151. package/dist/routes/__tests__/session-routes.test.js +198 -0
  152. package/dist/routes/__tests__/session-routes.test.js.map +1 -0
  153. package/dist/routes/__tests__/source-routes.test.d.ts +5 -0
  154. package/dist/routes/__tests__/source-routes.test.d.ts.map +1 -0
  155. package/dist/routes/__tests__/source-routes.test.js +142 -0
  156. package/dist/routes/__tests__/source-routes.test.js.map +1 -0
  157. package/dist/routes/__tests__/sync-routes.test.d.ts +5 -0
  158. package/dist/routes/__tests__/sync-routes.test.d.ts.map +1 -0
  159. package/dist/routes/__tests__/sync-routes.test.js +77 -0
  160. package/dist/routes/__tests__/sync-routes.test.js.map +1 -0
  161. package/dist/routes/__tests__/test-helpers.d.ts +47 -0
  162. package/dist/routes/__tests__/test-helpers.d.ts.map +1 -0
  163. package/dist/routes/__tests__/test-helpers.js +97 -0
  164. package/dist/routes/__tests__/test-helpers.js.map +1 -0
  165. package/dist/routes/archive-routes.d.ts +15 -0
  166. package/dist/routes/archive-routes.d.ts.map +1 -0
  167. package/dist/routes/archive-routes.js +181 -0
  168. package/dist/routes/archive-routes.js.map +1 -0
  169. package/dist/routes/claude-routes.d.ts +9 -0
  170. package/dist/routes/claude-routes.d.ts.map +1 -0
  171. package/dist/routes/claude-routes.js +47 -0
  172. package/dist/routes/claude-routes.js.map +1 -0
  173. package/dist/routes/config-routes.d.ts +9 -0
  174. package/dist/routes/config-routes.d.ts.map +1 -0
  175. package/dist/routes/config-routes.js +56 -0
  176. package/dist/routes/config-routes.js.map +1 -0
  177. package/dist/routes/config-store.d.ts +41 -0
  178. package/dist/routes/config-store.d.ts.map +1 -0
  179. package/dist/routes/config-store.js +52 -0
  180. package/dist/routes/config-store.js.map +1 -0
  181. package/dist/routes/http-utils.d.ts +32 -0
  182. package/dist/routes/http-utils.d.ts.map +1 -0
  183. package/dist/routes/http-utils.js +123 -0
  184. package/dist/routes/http-utils.js.map +1 -0
  185. package/dist/routes/index.d.ts +19 -0
  186. package/dist/routes/index.d.ts.map +1 -0
  187. package/dist/routes/index.js +17 -0
  188. package/dist/routes/index.js.map +1 -0
  189. package/dist/routes/notification-routes.d.ts +10 -0
  190. package/dist/routes/notification-routes.d.ts.map +1 -0
  191. package/dist/routes/notification-routes.js +64 -0
  192. package/dist/routes/notification-routes.js.map +1 -0
  193. package/dist/routes/project-routes.d.ts +22 -0
  194. package/dist/routes/project-routes.d.ts.map +1 -0
  195. package/dist/routes/project-routes.js +415 -0
  196. package/dist/routes/project-routes.js.map +1 -0
  197. package/dist/routes/session-routes.d.ts +18 -0
  198. package/dist/routes/session-routes.d.ts.map +1 -0
  199. package/dist/routes/session-routes.js +609 -0
  200. package/dist/routes/session-routes.js.map +1 -0
  201. package/dist/routes/source-routes.d.ts +12 -0
  202. package/dist/routes/source-routes.d.ts.map +1 -0
  203. package/dist/routes/source-routes.js +119 -0
  204. package/dist/routes/source-routes.js.map +1 -0
  205. package/dist/routes/static-routes.d.ts +12 -0
  206. package/dist/routes/static-routes.d.ts.map +1 -0
  207. package/dist/routes/static-routes.js +52 -0
  208. package/dist/routes/static-routes.js.map +1 -0
  209. package/dist/routes/sync-routes.d.ts +9 -0
  210. package/dist/routes/sync-routes.d.ts.map +1 -0
  211. package/dist/routes/sync-routes.js +78 -0
  212. package/dist/routes/sync-routes.js.map +1 -0
  213. package/dist/routes/tile-routes.d.ts +10 -0
  214. package/dist/routes/tile-routes.d.ts.map +1 -0
  215. package/dist/routes/tile-routes.js +108 -0
  216. package/dist/routes/tile-routes.js.map +1 -0
  217. package/dist/routes/types.d.ts +17 -0
  218. package/dist/routes/types.d.ts.map +1 -0
  219. package/dist/routes/types.js +5 -0
  220. package/dist/routes/types.js.map +1 -0
  221. package/dist/routes/usage-routes.d.ts +8 -0
  222. package/dist/routes/usage-routes.d.ts.map +1 -0
  223. package/dist/routes/usage-routes.js +18 -0
  224. package/dist/routes/usage-routes.js.map +1 -0
  225. package/dist/server.d.ts +8 -0
  226. package/dist/server.d.ts.map +1 -0
  227. package/dist/server.js +173 -0
  228. package/dist/server.js.map +1 -0
  229. package/dist/services/branch-divergence-service.d.ts +48 -0
  230. package/dist/services/branch-divergence-service.d.ts.map +1 -0
  231. package/dist/services/branch-divergence-service.js +156 -0
  232. package/dist/services/branch-divergence-service.js.map +1 -0
  233. package/dist/services/broadcast-service.d.ts +68 -0
  234. package/dist/services/broadcast-service.d.ts.map +1 -0
  235. package/dist/services/broadcast-service.js +78 -0
  236. package/dist/services/broadcast-service.js.map +1 -0
  237. package/dist/services/broadcast-service.test.d.ts +5 -0
  238. package/dist/services/broadcast-service.test.d.ts.map +1 -0
  239. package/dist/services/broadcast-service.test.js +130 -0
  240. package/dist/services/broadcast-service.test.js.map +1 -0
  241. package/dist/services/chat-service.d.ts +72 -0
  242. package/dist/services/chat-service.d.ts.map +1 -0
  243. package/dist/services/chat-service.js +342 -0
  244. package/dist/services/chat-service.js.map +1 -0
  245. package/dist/services/chat-system-prompt.d.ts +14 -0
  246. package/dist/services/chat-system-prompt.d.ts.map +1 -0
  247. package/dist/services/chat-system-prompt.js +68 -0
  248. package/dist/services/chat-system-prompt.js.map +1 -0
  249. package/dist/services/notification-service.d.ts +115 -0
  250. package/dist/services/notification-service.d.ts.map +1 -0
  251. package/dist/services/notification-service.js +424 -0
  252. package/dist/services/notification-service.js.map +1 -0
  253. package/dist/services/notification-service.test.d.ts +5 -0
  254. package/dist/services/notification-service.test.d.ts.map +1 -0
  255. package/dist/services/notification-service.test.js +918 -0
  256. package/dist/services/notification-service.test.js.map +1 -0
  257. package/dist/session/cleanup-service.d.ts +51 -0
  258. package/dist/session/cleanup-service.d.ts.map +1 -0
  259. package/dist/session/cleanup-service.js +98 -0
  260. package/dist/session/cleanup-service.js.map +1 -0
  261. package/dist/session/cleanup-service.test.d.ts +5 -0
  262. package/dist/session/cleanup-service.test.d.ts.map +1 -0
  263. package/dist/session/cleanup-service.test.js +121 -0
  264. package/dist/session/cleanup-service.test.js.map +1 -0
  265. package/dist/session/process-monitor.d.ts +79 -0
  266. package/dist/session/process-monitor.d.ts.map +1 -0
  267. package/dist/session/process-monitor.js +270 -0
  268. package/dist/session/process-monitor.js.map +1 -0
  269. package/dist/session/process-monitor.test.d.ts +5 -0
  270. package/dist/session/process-monitor.test.d.ts.map +1 -0
  271. package/dist/session/process-monitor.test.js +367 -0
  272. package/dist/session/process-monitor.test.js.map +1 -0
  273. package/dist/session/session-factory.d.ts +29 -0
  274. package/dist/session/session-factory.d.ts.map +1 -0
  275. package/dist/session/session-factory.js +123 -0
  276. package/dist/session/session-factory.js.map +1 -0
  277. package/dist/session/session-factory.test.d.ts +5 -0
  278. package/dist/session/session-factory.test.d.ts.map +1 -0
  279. package/dist/session/session-factory.test.js +299 -0
  280. package/dist/session/session-factory.test.js.map +1 -0
  281. package/dist/session-registry.d.ts +168 -0
  282. package/dist/session-registry.d.ts.map +1 -0
  283. package/dist/session-registry.js +626 -0
  284. package/dist/session-registry.js.map +1 -0
  285. package/dist/session-registry.test.d.ts +5 -0
  286. package/dist/session-registry.test.d.ts.map +1 -0
  287. package/dist/session-registry.test.js +582 -0
  288. package/dist/session-registry.test.js.map +1 -0
  289. package/dist/start-server.d.ts +31 -0
  290. package/dist/start-server.d.ts.map +1 -0
  291. package/dist/start-server.js +408 -0
  292. package/dist/start-server.js.map +1 -0
  293. package/dist/terminal-activator.d.ts +29 -0
  294. package/dist/terminal-activator.d.ts.map +1 -0
  295. package/dist/terminal-activator.js +264 -0
  296. package/dist/terminal-activator.js.map +1 -0
  297. package/dist/terminal-activator.test.d.ts +9 -0
  298. package/dist/terminal-activator.test.d.ts.map +1 -0
  299. package/dist/terminal-activator.test.js +95 -0
  300. package/dist/terminal-activator.test.js.map +1 -0
  301. package/dist/terminal-launcher.d.ts +51 -0
  302. package/dist/terminal-launcher.d.ts.map +1 -0
  303. package/dist/terminal-launcher.js +298 -0
  304. package/dist/terminal-launcher.js.map +1 -0
  305. package/dist/terminal-launcher.test.d.ts +8 -0
  306. package/dist/terminal-launcher.test.d.ts.map +1 -0
  307. package/dist/terminal-launcher.test.js +222 -0
  308. package/dist/terminal-launcher.test.js.map +1 -0
  309. package/dist/types.d.ts +796 -0
  310. package/dist/types.d.ts.map +1 -0
  311. package/dist/types.js +15 -0
  312. package/dist/types.js.map +1 -0
  313. package/dist/unix-socket.d.ts +68 -0
  314. package/dist/unix-socket.d.ts.map +1 -0
  315. package/dist/unix-socket.js +180 -0
  316. package/dist/unix-socket.js.map +1 -0
  317. package/dist/usage-limits.d.ts +13 -0
  318. package/dist/usage-limits.d.ts.map +1 -0
  319. package/dist/usage-limits.js +112 -0
  320. package/dist/usage-limits.js.map +1 -0
  321. package/dist/watchers/handoff-watcher.d.ts +74 -0
  322. package/dist/watchers/handoff-watcher.d.ts.map +1 -0
  323. package/dist/watchers/handoff-watcher.js +124 -0
  324. package/dist/watchers/handoff-watcher.js.map +1 -0
  325. package/dist/watchers/handoff-watcher.test.d.ts +8 -0
  326. package/dist/watchers/handoff-watcher.test.d.ts.map +1 -0
  327. package/dist/watchers/handoff-watcher.test.js +142 -0
  328. package/dist/watchers/handoff-watcher.test.js.map +1 -0
  329. package/dist/websocket.d.ts +107 -0
  330. package/dist/websocket.d.ts.map +1 -0
  331. package/dist/websocket.js +268 -0
  332. package/dist/websocket.js.map +1 -0
  333. package/dist/window-manager/index.d.ts +28 -0
  334. package/dist/window-manager/index.d.ts.map +1 -0
  335. package/dist/window-manager/index.js +56 -0
  336. package/dist/window-manager/index.js.map +1 -0
  337. package/dist/window-manager/layouts.d.ts +42 -0
  338. package/dist/window-manager/layouts.d.ts.map +1 -0
  339. package/dist/window-manager/layouts.js +133 -0
  340. package/dist/window-manager/layouts.js.map +1 -0
  341. package/dist/window-manager/linux-manager.d.ts +45 -0
  342. package/dist/window-manager/linux-manager.d.ts.map +1 -0
  343. package/dist/window-manager/linux-manager.js +299 -0
  344. package/dist/window-manager/linux-manager.js.map +1 -0
  345. package/dist/window-manager/macos-manager.d.ts +103 -0
  346. package/dist/window-manager/macos-manager.d.ts.map +1 -0
  347. package/dist/window-manager/macos-manager.js +637 -0
  348. package/dist/window-manager/macos-manager.js.map +1 -0
  349. package/dist/window-manager/smart-layouts.d.ts +116 -0
  350. package/dist/window-manager/smart-layouts.d.ts.map +1 -0
  351. package/dist/window-manager/smart-layouts.js +188 -0
  352. package/dist/window-manager/smart-layouts.js.map +1 -0
  353. package/dist/window-manager/smart-layouts.test.d.ts +8 -0
  354. package/dist/window-manager/smart-layouts.test.d.ts.map +1 -0
  355. package/dist/window-manager/smart-layouts.test.js +311 -0
  356. package/dist/window-manager/smart-layouts.test.js.map +1 -0
  357. package/dist/window-manager/tile-state.d.ts +87 -0
  358. package/dist/window-manager/tile-state.d.ts.map +1 -0
  359. package/dist/window-manager/tile-state.js +136 -0
  360. package/dist/window-manager/tile-state.js.map +1 -0
  361. package/dist/window-manager/tile-state.test.d.ts +8 -0
  362. package/dist/window-manager/tile-state.test.d.ts.map +1 -0
  363. package/dist/window-manager/tile-state.test.js +179 -0
  364. package/dist/window-manager/tile-state.test.js.map +1 -0
  365. package/dist/window-manager/types.d.ts +104 -0
  366. package/dist/window-manager/types.d.ts.map +1 -0
  367. package/dist/window-manager/types.js +8 -0
  368. package/dist/window-manager/types.js.map +1 -0
  369. package/dist/window-manager/windows-manager.d.ts +44 -0
  370. package/dist/window-manager/windows-manager.d.ts.map +1 -0
  371. package/dist/window-manager/windows-manager.js +281 -0
  372. package/dist/window-manager/windows-manager.js.map +1 -0
  373. package/dist/window-manager/windows-manager.test.d.ts +8 -0
  374. package/dist/window-manager/windows-manager.test.d.ts.map +1 -0
  375. package/dist/window-manager/windows-manager.test.js +183 -0
  376. package/dist/window-manager/windows-manager.test.js.map +1 -0
  377. package/gui-dist/assets/index-BmYIHRYe.js +142 -0
  378. package/gui-dist/assets/index-D_N5RH8O.css +1 -0
  379. package/gui-dist/assets/vendor-icons-ByXNrcwf.js +336 -0
  380. package/gui-dist/assets/vendor-markdown-DWPYwU1x.js +22 -0
  381. package/gui-dist/assets/vendor-react-CpILBTDM.js +59 -0
  382. package/gui-dist/index.html +17 -0
  383. package/gui-dist/jacsub.png +0 -0
  384. package/package.json +67 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Smart Layout Engine
3
+ *
4
+ * Calculates grid geometry for 1-8+ terminal windows, plans transitions
5
+ * when adding a window to an existing tiled layout, and finds free space
6
+ * for non-tiled placement.
7
+ *
8
+ * Grid progression (row-based, each row can have different column count):
9
+ *
10
+ * n=1: [A] 1 row, 1 col
11
+ * n=2: [A][B] 1 row, 2 cols
12
+ * n=3: [A][B][C] 1 row, 3 cols
13
+ * n=4: [A][B] / [C][D] 2×2 equal grid
14
+ * n=5: [A][B][C] / [D][E] 3 top, 2 bottom
15
+ * n=6: [A][B][C] / [D][E][F] 3×2 equal grid
16
+ * n=7: [A][B][C][D] / [E][F][G] 4 top, 3 bottom
17
+ * n=8: [A][B][C][D] / [E][F][G][H] 4×2 equal grid
18
+ *
19
+ * Slot ordering is column-major: iterate columns L→R, rows top→bottom
20
+ * within each column. This ensures stable index-based transitions.
21
+ */
22
+ import type { WindowGeometry } from './types.js';
23
+ /**
24
+ * Grid specification: number of columns in each row.
25
+ * Index 0 = top row, index 1 = bottom row (if present).
26
+ */
27
+ export interface GridSpec {
28
+ columnsPerRow: number[];
29
+ }
30
+ /**
31
+ * A slot in the grid with its position and geometry
32
+ */
33
+ export interface GridSlot {
34
+ column: number;
35
+ row: number;
36
+ geometry: WindowGeometry;
37
+ }
38
+ /**
39
+ * A reposition instruction for an existing window
40
+ */
41
+ export interface WindowReposition {
42
+ terminalKey: string;
43
+ sessionId: string;
44
+ newGeometry: WindowGeometry;
45
+ newColumn: number;
46
+ newRow: number;
47
+ }
48
+ /**
49
+ * Result of planning a smart tile transition
50
+ */
51
+ export interface SmartTileTransition {
52
+ /** Existing windows that need to be repositioned */
53
+ repositions: WindowReposition[];
54
+ /** Geometry for the new window */
55
+ newWindowGeometry: WindowGeometry;
56
+ /** The new window's grid position */
57
+ newColumn: number;
58
+ newRow: number;
59
+ /** Updated grid spec after the transition */
60
+ newGrid: GridSpec;
61
+ }
62
+ /**
63
+ * Get the grid specification for a given number of windows.
64
+ *
65
+ * Progression:
66
+ * 1: [1] — 1 fullscreen
67
+ * 2: [2] — 2 side-by-side
68
+ * 3: [3] — 3 side-by-side
69
+ * 4: [2,2] — 2×2 equal grid
70
+ * 5: [3,2] — 3 top, 2 bottom
71
+ * 6: [3,3] — 3×2 equal grid
72
+ * 7: [4,3] — 4 top, 3 bottom
73
+ * 8: [4,4] — 4×2 equal grid
74
+ * n≥4: [ceil(n/2), floor(n/2)]
75
+ */
76
+ export declare function getGridSpec(windowCount: number): GridSpec;
77
+ /**
78
+ * Calculate geometry for a single slot in the grid.
79
+ * Each row can have a different number of columns (and thus different widths).
80
+ */
81
+ export declare function calculateSlotGeometry(workArea: WindowGeometry, grid: GridSpec, row: number, column: number): WindowGeometry;
82
+ /**
83
+ * Calculate all slot geometries for n windows.
84
+ * Order: column-major (iterate columns L→R, rows top→bottom within each column).
85
+ */
86
+ export declare function calculateAllSlots(workArea: WindowGeometry, windowCount: number): GridSlot[];
87
+ /**
88
+ * Slot info from the current tile state (terminal + position).
89
+ */
90
+ export interface ExistingSlot {
91
+ terminalKey: string;
92
+ sessionId: string;
93
+ column: number;
94
+ row: number;
95
+ geometry: WindowGeometry;
96
+ }
97
+ /**
98
+ * Plan a smart tile transition: adding one window to the current layout.
99
+ *
100
+ * Uses index-based mapping: window at slot index i maps to new slot index i.
101
+ * Returns null if beyond 8 (caller should use free-space).
102
+ */
103
+ export declare function planSmartTileTransition(existingSlots: ExistingSlot[], workArea: WindowGeometry): SmartTileTransition | null;
104
+ /**
105
+ * Compute the overlap area between two rectangles.
106
+ */
107
+ export declare function computeOverlapArea(a: WindowGeometry, b: WindowGeometry): number;
108
+ /**
109
+ * Find the least-occupied position on the work area for a new terminal.
110
+ * Used when terminals are not in a recognized tiled layout, or when count > 8.
111
+ *
112
+ * Target size: 1/4 width, 1/2 height of work area.
113
+ * Scans an 8×4 grid of candidate positions and picks the one with least overlap.
114
+ */
115
+ export declare function findFreeSpace(workArea: WindowGeometry, existingWindows: WindowGeometry[]): WindowGeometry;
116
+ //# sourceMappingURL=smart-layouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-layouts.d.ts","sourceRoot":"","sources":["../../src/window-manager/smart-layouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,cAAc,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,kCAAkC;IAClC,iBAAiB,EAAE,cAAc,CAAC;IAClC,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAOzD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,cAAc,CAehB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,MAAM,GAClB,QAAQ,EAAE,CAsBZ;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,YAAY,EAAE,EAC7B,QAAQ,EAAE,cAAc,GACvB,mBAAmB,GAAG,IAAI,CA8C5B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAI/E;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EACxB,eAAe,EAAE,cAAc,EAAE,GAChC,cAAc,CA6ChB"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Smart Layout Engine
3
+ *
4
+ * Calculates grid geometry for 1-8+ terminal windows, plans transitions
5
+ * when adding a window to an existing tiled layout, and finds free space
6
+ * for non-tiled placement.
7
+ *
8
+ * Grid progression (row-based, each row can have different column count):
9
+ *
10
+ * n=1: [A] 1 row, 1 col
11
+ * n=2: [A][B] 1 row, 2 cols
12
+ * n=3: [A][B][C] 1 row, 3 cols
13
+ * n=4: [A][B] / [C][D] 2×2 equal grid
14
+ * n=5: [A][B][C] / [D][E] 3 top, 2 bottom
15
+ * n=6: [A][B][C] / [D][E][F] 3×2 equal grid
16
+ * n=7: [A][B][C][D] / [E][F][G] 4 top, 3 bottom
17
+ * n=8: [A][B][C][D] / [E][F][G][H] 4×2 equal grid
18
+ *
19
+ * Slot ordering is column-major: iterate columns L→R, rows top→bottom
20
+ * within each column. This ensures stable index-based transitions.
21
+ */
22
+ /**
23
+ * Get the grid specification for a given number of windows.
24
+ *
25
+ * Progression:
26
+ * 1: [1] — 1 fullscreen
27
+ * 2: [2] — 2 side-by-side
28
+ * 3: [3] — 3 side-by-side
29
+ * 4: [2,2] — 2×2 equal grid
30
+ * 5: [3,2] — 3 top, 2 bottom
31
+ * 6: [3,3] — 3×2 equal grid
32
+ * 7: [4,3] — 4 top, 3 bottom
33
+ * 8: [4,4] — 4×2 equal grid
34
+ * n≥4: [ceil(n/2), floor(n/2)]
35
+ */
36
+ export function getGridSpec(windowCount) {
37
+ if (windowCount <= 0)
38
+ return { columnsPerRow: [] };
39
+ if (windowCount === 1)
40
+ return { columnsPerRow: [1] };
41
+ if (windowCount === 2)
42
+ return { columnsPerRow: [2] };
43
+ if (windowCount === 3)
44
+ return { columnsPerRow: [3] };
45
+ // 4+: two rows, top row gets ceil, bottom gets floor
46
+ return { columnsPerRow: [Math.ceil(windowCount / 2), Math.floor(windowCount / 2)] };
47
+ }
48
+ /**
49
+ * Calculate geometry for a single slot in the grid.
50
+ * Each row can have a different number of columns (and thus different widths).
51
+ */
52
+ export function calculateSlotGeometry(workArea, grid, row, column) {
53
+ const numRows = grid.columnsPerRow.length;
54
+ const colsInRow = grid.columnsPerRow[row];
55
+ const rowHeight = Math.floor(workArea.height / numRows);
56
+ const colWidth = Math.floor(workArea.width / colsInRow);
57
+ const isLastRow = row === numRows - 1;
58
+ const isLastCol = column === colsInRow - 1;
59
+ return {
60
+ x: workArea.x + column * colWidth,
61
+ y: workArea.y + row * rowHeight,
62
+ width: isLastCol ? workArea.width - column * colWidth : colWidth,
63
+ height: isLastRow ? workArea.height - row * rowHeight : rowHeight,
64
+ };
65
+ }
66
+ /**
67
+ * Calculate all slot geometries for n windows.
68
+ * Order: column-major (iterate columns L→R, rows top→bottom within each column).
69
+ */
70
+ export function calculateAllSlots(workArea, windowCount) {
71
+ const grid = getGridSpec(windowCount);
72
+ if (grid.columnsPerRow.length === 0)
73
+ return [];
74
+ const slots = [];
75
+ const numRows = grid.columnsPerRow.length;
76
+ const maxCols = Math.max(...grid.columnsPerRow);
77
+ // Column-major: iterate columns, then rows within each column
78
+ for (let col = 0; col < maxCols; col++) {
79
+ for (let row = 0; row < numRows; row++) {
80
+ if (col < grid.columnsPerRow[row]) {
81
+ slots.push({
82
+ column: col,
83
+ row,
84
+ geometry: calculateSlotGeometry(workArea, grid, row, col),
85
+ });
86
+ }
87
+ }
88
+ }
89
+ return slots;
90
+ }
91
+ /**
92
+ * Plan a smart tile transition: adding one window to the current layout.
93
+ *
94
+ * Uses index-based mapping: window at slot index i maps to new slot index i.
95
+ * Returns null if beyond 8 (caller should use free-space).
96
+ */
97
+ export function planSmartTileTransition(existingSlots, workArea) {
98
+ const currentCount = existingSlots.length;
99
+ const newCount = currentCount + 1;
100
+ if (newCount > 8) {
101
+ return null; // Caller should use findFreeSpace
102
+ }
103
+ const newSlots = calculateAllSlots(workArea, newCount);
104
+ const newGrid = getGridSpec(newCount);
105
+ const repositions = [];
106
+ // Index-based mapping: existing slot at index i → new slot at index i
107
+ for (let i = 0; i < currentCount; i++) {
108
+ const existing = existingSlots[i];
109
+ const target = newSlots[i];
110
+ const geomChanged = (existing.geometry.x !== target.geometry.x ||
111
+ existing.geometry.y !== target.geometry.y ||
112
+ existing.geometry.width !== target.geometry.width ||
113
+ existing.geometry.height !== target.geometry.height);
114
+ if (geomChanged) {
115
+ repositions.push({
116
+ terminalKey: existing.terminalKey,
117
+ sessionId: existing.sessionId,
118
+ newGeometry: target.geometry,
119
+ newColumn: target.column,
120
+ newRow: target.row,
121
+ });
122
+ }
123
+ }
124
+ // The new window goes in the last slot
125
+ const newSlot = newSlots[currentCount];
126
+ return {
127
+ repositions,
128
+ newWindowGeometry: newSlot.geometry,
129
+ newColumn: newSlot.column,
130
+ newRow: newSlot.row,
131
+ newGrid,
132
+ };
133
+ }
134
+ /**
135
+ * Compute the overlap area between two rectangles.
136
+ */
137
+ export function computeOverlapArea(a, b) {
138
+ const overlapX = Math.max(0, Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x));
139
+ const overlapY = Math.max(0, Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y));
140
+ return overlapX * overlapY;
141
+ }
142
+ /**
143
+ * Find the least-occupied position on the work area for a new terminal.
144
+ * Used when terminals are not in a recognized tiled layout, or when count > 8.
145
+ *
146
+ * Target size: 1/4 width, 1/2 height of work area.
147
+ * Scans an 8×4 grid of candidate positions and picks the one with least overlap.
148
+ */
149
+ export function findFreeSpace(workArea, existingWindows) {
150
+ const targetW = Math.round(workArea.width / 4);
151
+ const targetH = Math.round(workArea.height / 2);
152
+ // If no existing windows, place at top-left
153
+ if (existingWindows.length === 0) {
154
+ return { x: workArea.x, y: workArea.y, width: targetW, height: targetH };
155
+ }
156
+ const GRID_COLS = 8;
157
+ const GRID_ROWS = 4;
158
+ const maxX = workArea.x + workArea.width - targetW;
159
+ const maxY = workArea.y + workArea.height - targetH;
160
+ // Avoid division by zero if work area is smaller than target
161
+ const stepX = GRID_COLS > 1 ? Math.max(1, Math.floor((maxX - workArea.x) / (GRID_COLS - 1))) : 0;
162
+ const stepY = GRID_ROWS > 1 ? Math.max(1, Math.floor((maxY - workArea.y) / (GRID_ROWS - 1))) : 0;
163
+ let bestX = workArea.x;
164
+ let bestY = workArea.y;
165
+ let bestOverlap = Infinity;
166
+ for (let gx = 0; gx < GRID_COLS; gx++) {
167
+ for (let gy = 0; gy < GRID_ROWS; gy++) {
168
+ const cx = Math.min(workArea.x + gx * stepX, maxX);
169
+ const cy = Math.min(workArea.y + gy * stepY, maxY);
170
+ const candidate = { x: cx, y: cy, width: targetW, height: targetH };
171
+ let overlapSum = 0;
172
+ for (const existing of existingWindows) {
173
+ overlapSum += computeOverlapArea(candidate, existing);
174
+ }
175
+ if (overlapSum < bestOverlap) {
176
+ bestOverlap = overlapSum;
177
+ bestX = cx;
178
+ bestY = cy;
179
+ if (overlapSum === 0)
180
+ break; // Can't do better than zero overlap
181
+ }
182
+ }
183
+ if (bestOverlap === 0)
184
+ break;
185
+ }
186
+ return { x: bestX, y: bestY, width: targetW, height: targetH };
187
+ }
188
+ //# sourceMappingURL=smart-layouts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-layouts.js","sourceRoot":"","sources":["../../src/window-manager/smart-layouts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Smart Layout Engine Tests
3
+ *
4
+ * Tests grid specifications, slot geometry calculations, transition planning,
5
+ * and free-space placement for the smart tiling system.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=smart-layouts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-layouts.test.d.ts","sourceRoot":"","sources":["../../src/window-manager/smart-layouts.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Smart Layout Engine Tests
3
+ *
4
+ * Tests grid specifications, slot geometry calculations, transition planning,
5
+ * and free-space placement for the smart tiling system.
6
+ */
7
+ import { describe, it, expect } from '@jest/globals';
8
+ import { getGridSpec, calculateSlotGeometry, calculateAllSlots, planSmartTileTransition, findFreeSpace, computeOverlapArea, } from './smart-layouts.js';
9
+ // Standard test work area (1920×1057 after dock/menubar on a 1080p display)
10
+ const WORK_AREA = { x: 0, y: 23, width: 1920, height: 1057 };
11
+ // ─── getGridSpec ─────────────────────────────────────────────
12
+ describe('getGridSpec', () => {
13
+ it('returns empty grid for 0 windows', () => {
14
+ expect(getGridSpec(0)).toEqual({ columnsPerRow: [] });
15
+ });
16
+ it('returns [1] for 1 window', () => {
17
+ expect(getGridSpec(1)).toEqual({ columnsPerRow: [1] });
18
+ });
19
+ it('returns [2] for 2 windows', () => {
20
+ expect(getGridSpec(2)).toEqual({ columnsPerRow: [2] });
21
+ });
22
+ it('returns [3] for 3 windows', () => {
23
+ expect(getGridSpec(3)).toEqual({ columnsPerRow: [3] });
24
+ });
25
+ it('returns [2,2] for 4 windows (2×2 grid)', () => {
26
+ expect(getGridSpec(4)).toEqual({ columnsPerRow: [2, 2] });
27
+ });
28
+ it('returns [3,2] for 5 windows (3 top, 2 bottom)', () => {
29
+ expect(getGridSpec(5)).toEqual({ columnsPerRow: [3, 2] });
30
+ });
31
+ it('returns [3,3] for 6 windows (3×2 grid)', () => {
32
+ expect(getGridSpec(6)).toEqual({ columnsPerRow: [3, 3] });
33
+ });
34
+ it('returns [4,3] for 7 windows', () => {
35
+ expect(getGridSpec(7)).toEqual({ columnsPerRow: [4, 3] });
36
+ });
37
+ it('returns [4,4] for 8 windows (4×2 grid)', () => {
38
+ expect(getGridSpec(8)).toEqual({ columnsPerRow: [4, 4] });
39
+ });
40
+ it('handles beyond 8 (9 = [5,4])', () => {
41
+ expect(getGridSpec(9)).toEqual({ columnsPerRow: [5, 4] });
42
+ });
43
+ it('handles 12 = [6,6]', () => {
44
+ expect(getGridSpec(12)).toEqual({ columnsPerRow: [6, 6] });
45
+ });
46
+ });
47
+ // ─── calculateSlotGeometry ───────────────────────────────────
48
+ describe('calculateSlotGeometry', () => {
49
+ it('returns full work area for 1×1 grid', () => {
50
+ const grid = getGridSpec(1);
51
+ const slot = calculateSlotGeometry(WORK_AREA, grid, 0, 0);
52
+ expect(slot).toEqual(WORK_AREA);
53
+ });
54
+ it('splits horizontally for 2 windows', () => {
55
+ const grid = getGridSpec(2);
56
+ const left = calculateSlotGeometry(WORK_AREA, grid, 0, 0);
57
+ const right = calculateSlotGeometry(WORK_AREA, grid, 0, 1);
58
+ expect(left.x).toBe(0);
59
+ expect(left.width).toBe(960);
60
+ expect(right.x).toBe(960);
61
+ expect(right.width).toBe(960);
62
+ expect(left.height).toBe(WORK_AREA.height);
63
+ expect(right.height).toBe(WORK_AREA.height);
64
+ });
65
+ it('last column gets remainder pixels', () => {
66
+ // 1920 / 3 = 640
67
+ const grid = getGridSpec(3);
68
+ const last = calculateSlotGeometry(WORK_AREA, grid, 0, 2);
69
+ expect(last.width).toBe(1920 - 640 * 2);
70
+ });
71
+ it('2×2 grid has equal-sized slots', () => {
72
+ const grid = getGridSpec(4); // [2, 2]
73
+ const topLeft = calculateSlotGeometry(WORK_AREA, grid, 0, 0);
74
+ const topRight = calculateSlotGeometry(WORK_AREA, grid, 0, 1);
75
+ const bottomLeft = calculateSlotGeometry(WORK_AREA, grid, 1, 0);
76
+ const bottomRight = calculateSlotGeometry(WORK_AREA, grid, 1, 1);
77
+ // All same width and height
78
+ expect(topLeft.width).toBe(960);
79
+ expect(topRight.width).toBe(960);
80
+ expect(bottomLeft.width).toBe(960);
81
+ expect(bottomRight.width).toBe(960);
82
+ expect(topLeft.height + bottomLeft.height).toBe(WORK_AREA.height);
83
+ });
84
+ it('5-window grid has different widths per row', () => {
85
+ const grid = getGridSpec(5); // [3, 2]
86
+ const topCol = calculateSlotGeometry(WORK_AREA, grid, 0, 0);
87
+ const bottomCol = calculateSlotGeometry(WORK_AREA, grid, 1, 0);
88
+ // Top row: 1/3 width, bottom row: 1/2 width
89
+ expect(topCol.width).toBe(640);
90
+ expect(bottomCol.width).toBe(960);
91
+ });
92
+ });
93
+ // ─── calculateAllSlots ──────────────────────────────────────
94
+ describe('calculateAllSlots', () => {
95
+ it('returns empty for 0 windows', () => {
96
+ expect(calculateAllSlots(WORK_AREA, 0)).toEqual([]);
97
+ });
98
+ it('returns 1 slot for 1 window', () => {
99
+ const slots = calculateAllSlots(WORK_AREA, 1);
100
+ expect(slots).toHaveLength(1);
101
+ expect(slots[0].column).toBe(0);
102
+ expect(slots[0].row).toBe(0);
103
+ });
104
+ it('returns column-major order for 4 windows (2×2)', () => {
105
+ const slots = calculateAllSlots(WORK_AREA, 4);
106
+ expect(slots).toHaveLength(4);
107
+ // Column-major: col 0 top, col 0 bottom, col 1 top, col 1 bottom
108
+ expect(slots[0]).toMatchObject({ column: 0, row: 0 });
109
+ expect(slots[1]).toMatchObject({ column: 0, row: 1 });
110
+ expect(slots[2]).toMatchObject({ column: 1, row: 0 });
111
+ expect(slots[3]).toMatchObject({ column: 1, row: 1 });
112
+ });
113
+ it('returns column-major order for 5 windows [3,2]', () => {
114
+ const slots = calculateAllSlots(WORK_AREA, 5);
115
+ expect(slots).toHaveLength(5);
116
+ // Col 0: (r0,c0), (r1,c0); Col 1: (r0,c1), (r1,c1); Col 2: (r0,c2)
117
+ expect(slots[0]).toMatchObject({ column: 0, row: 0 });
118
+ expect(slots[1]).toMatchObject({ column: 0, row: 1 });
119
+ expect(slots[2]).toMatchObject({ column: 1, row: 0 });
120
+ expect(slots[3]).toMatchObject({ column: 1, row: 1 });
121
+ expect(slots[4]).toMatchObject({ column: 2, row: 0 });
122
+ });
123
+ it('returns column-major order for 6 windows (3×2)', () => {
124
+ const slots = calculateAllSlots(WORK_AREA, 6);
125
+ expect(slots).toHaveLength(6);
126
+ expect(slots[0]).toMatchObject({ column: 0, row: 0 });
127
+ expect(slots[1]).toMatchObject({ column: 0, row: 1 });
128
+ expect(slots[2]).toMatchObject({ column: 1, row: 0 });
129
+ expect(slots[3]).toMatchObject({ column: 1, row: 1 });
130
+ expect(slots[4]).toMatchObject({ column: 2, row: 0 });
131
+ expect(slots[5]).toMatchObject({ column: 2, row: 1 });
132
+ });
133
+ it('returns column-major order for 7 windows [4,3]', () => {
134
+ const slots = calculateAllSlots(WORK_AREA, 7);
135
+ expect(slots).toHaveLength(7);
136
+ // Col 3 only has top row (bottom row has 3 cols)
137
+ expect(slots[0]).toMatchObject({ column: 0, row: 0 });
138
+ expect(slots[1]).toMatchObject({ column: 0, row: 1 });
139
+ expect(slots[2]).toMatchObject({ column: 1, row: 0 });
140
+ expect(slots[3]).toMatchObject({ column: 1, row: 1 });
141
+ expect(slots[4]).toMatchObject({ column: 2, row: 0 });
142
+ expect(slots[5]).toMatchObject({ column: 2, row: 1 });
143
+ expect(slots[6]).toMatchObject({ column: 3, row: 0 });
144
+ });
145
+ it('slots cover the entire work area without gaps for 6 windows', () => {
146
+ const slots = calculateAllSlots(WORK_AREA, 6);
147
+ const totalArea = slots.reduce((sum, s) => sum + s.geometry.width * s.geometry.height, 0);
148
+ const workAreaTotal = WORK_AREA.width * WORK_AREA.height;
149
+ // Allow small rounding difference (max 1 pixel per slot dimension)
150
+ expect(Math.abs(totalArea - workAreaTotal)).toBeLessThan(WORK_AREA.width + WORK_AREA.height);
151
+ });
152
+ it('no slots overlap for 8 windows', () => {
153
+ const slots = calculateAllSlots(WORK_AREA, 8);
154
+ for (let i = 0; i < slots.length; i++) {
155
+ for (let j = i + 1; j < slots.length; j++) {
156
+ const overlap = computeOverlapArea(slots[i].geometry, slots[j].geometry);
157
+ expect(overlap).toBe(0);
158
+ }
159
+ }
160
+ });
161
+ it('5-window grid has correct mixed widths', () => {
162
+ const slots = calculateAllSlots(WORK_AREA, 5);
163
+ // Top row slots: 1/3 width
164
+ expect(slots[0].geometry.width).toBe(640); // col 0, row 0
165
+ expect(slots[2].geometry.width).toBe(640); // col 1, row 0
166
+ expect(slots[4].geometry.width).toBe(640); // col 2, row 0
167
+ // Bottom row slots: 1/2 width
168
+ expect(slots[1].geometry.width).toBe(960); // col 0, row 1
169
+ expect(slots[3].geometry.width).toBe(960); // col 1, row 1
170
+ });
171
+ });
172
+ // ─── planSmartTileTransition ─────────────────────────────────
173
+ describe('planSmartTileTransition', () => {
174
+ function makeSlots(count) {
175
+ const slots = calculateAllSlots(WORK_AREA, count);
176
+ return slots.map((s, i) => ({
177
+ terminalKey: `ITERM:session-${i}`,
178
+ sessionId: `session-${i}`,
179
+ ...s,
180
+ }));
181
+ }
182
+ it('0→1: no repositions, full work area', () => {
183
+ const result = planSmartTileTransition([], WORK_AREA);
184
+ expect(result).not.toBeNull();
185
+ expect(result.repositions).toHaveLength(0);
186
+ expect(result.newWindowGeometry).toEqual(WORK_AREA);
187
+ });
188
+ it('1→2: 1 reposition (split to half)', () => {
189
+ const existing = makeSlots(1);
190
+ const result = planSmartTileTransition(existing, WORK_AREA);
191
+ expect(result).not.toBeNull();
192
+ expect(result.repositions).toHaveLength(1);
193
+ expect(result.repositions[0].newGeometry.width).toBe(960);
194
+ expect(result.newWindowGeometry.x).toBe(960);
195
+ });
196
+ it('2→3: 2 repositions (half → third)', () => {
197
+ const existing = makeSlots(2);
198
+ const result = planSmartTileTransition(existing, WORK_AREA);
199
+ expect(result).not.toBeNull();
200
+ expect(result.repositions).toHaveLength(2);
201
+ });
202
+ it('3→4: all 3 reposition (single row → 2×2 grid)', () => {
203
+ const existing = makeSlots(3);
204
+ const result = planSmartTileTransition(existing, WORK_AREA);
205
+ expect(result).not.toBeNull();
206
+ // All 3 existing windows change size/position
207
+ expect(result.repositions).toHaveLength(3);
208
+ // New window goes to last slot: (r1,c1) bottom-right
209
+ expect(result.newColumn).toBe(1);
210
+ expect(result.newRow).toBe(1);
211
+ });
212
+ it('4→5: 2 repositions (top row shrinks from 1/2 to 1/3 width)', () => {
213
+ const existing = makeSlots(4);
214
+ const result = planSmartTileTransition(existing, WORK_AREA);
215
+ expect(result).not.toBeNull();
216
+ // Top row windows shrink width (1/2→1/3), bottom row stays (1/2→1/2)
217
+ expect(result.repositions).toHaveLength(2);
218
+ // New window at top-right: (r0,c2)
219
+ expect(result.newColumn).toBe(2);
220
+ expect(result.newRow).toBe(0);
221
+ });
222
+ it('5→6: 2 repositions (bottom row shrinks from 1/2 to 1/3 width)', () => {
223
+ const existing = makeSlots(5);
224
+ const result = planSmartTileTransition(existing, WORK_AREA);
225
+ expect(result).not.toBeNull();
226
+ // Bottom row: 1/2→1/3 width (2 repos). Top row already half-height, no change.
227
+ expect(result.repositions).toHaveLength(2);
228
+ // New window: (r1,c2) bottom-right
229
+ expect(result.newColumn).toBe(2);
230
+ expect(result.newRow).toBe(1);
231
+ });
232
+ it('6→7: 3 repositions (top row shrinks from 1/3 to 1/4 width)', () => {
233
+ const existing = makeSlots(6);
234
+ const result = planSmartTileTransition(existing, WORK_AREA);
235
+ expect(result).not.toBeNull();
236
+ // Only top row windows change width (1/3→1/4), bottom row stays (1/3)
237
+ expect(result.repositions).toHaveLength(3);
238
+ // New window at top-right: (r0,c3)
239
+ expect(result.newColumn).toBe(3);
240
+ expect(result.newRow).toBe(0);
241
+ });
242
+ it('7→8: 3 repositions (bottom row shrinks from 1/3 to 1/4 width)', () => {
243
+ const existing = makeSlots(7);
244
+ const result = planSmartTileTransition(existing, WORK_AREA);
245
+ expect(result).not.toBeNull();
246
+ // Bottom row: 1/3→1/4 width (3 repos). Top row already half-height, no change.
247
+ expect(result.repositions).toHaveLength(3);
248
+ // New window: (r1,c3) bottom-right
249
+ expect(result.newColumn).toBe(3);
250
+ expect(result.newRow).toBe(1);
251
+ });
252
+ it('returns null for 8→9 (beyond limit)', () => {
253
+ const existing = makeSlots(8);
254
+ const result = planSmartTileTransition(existing, WORK_AREA);
255
+ expect(result).toBeNull();
256
+ });
257
+ it('new window geometry matches expected slot', () => {
258
+ const existing = makeSlots(3);
259
+ const result = planSmartTileTransition(existing, WORK_AREA);
260
+ const allSlotsFor4 = calculateAllSlots(WORK_AREA, 4);
261
+ // New window should be the last slot (index 3)
262
+ expect(result.newWindowGeometry).toEqual(allSlotsFor4[3].geometry);
263
+ });
264
+ });
265
+ // ─── computeOverlapArea ──────────────────────────────────────
266
+ describe('computeOverlapArea', () => {
267
+ it('returns 0 for non-overlapping rectangles', () => {
268
+ const a = { x: 0, y: 0, width: 100, height: 100 };
269
+ const b = { x: 200, y: 0, width: 100, height: 100 };
270
+ expect(computeOverlapArea(a, b)).toBe(0);
271
+ });
272
+ it('returns correct overlap for partially overlapping rectangles', () => {
273
+ const a = { x: 0, y: 0, width: 100, height: 100 };
274
+ const b = { x: 50, y: 50, width: 100, height: 100 };
275
+ // Overlap: 50×50 = 2500
276
+ expect(computeOverlapArea(a, b)).toBe(2500);
277
+ });
278
+ it('returns full area for identical rectangles', () => {
279
+ const a = { x: 10, y: 20, width: 100, height: 200 };
280
+ expect(computeOverlapArea(a, a)).toBe(20000);
281
+ });
282
+ });
283
+ // ─── findFreeSpace ──────────────────────────────────────────
284
+ describe('findFreeSpace', () => {
285
+ it('returns top-left for no existing windows', () => {
286
+ const result = findFreeSpace(WORK_AREA, []);
287
+ expect(result.x).toBe(WORK_AREA.x);
288
+ expect(result.y).toBe(WORK_AREA.y);
289
+ expect(result.width).toBe(Math.round(WORK_AREA.width / 4));
290
+ expect(result.height).toBe(Math.round(WORK_AREA.height / 2));
291
+ });
292
+ it('avoids a window in the top-left', () => {
293
+ const existing = [{ x: 0, y: 23, width: 960, height: 1057 }];
294
+ const result = findFreeSpace(WORK_AREA, existing);
295
+ // Should be placed somewhere on the right half
296
+ expect(result.x).toBeGreaterThan(0);
297
+ });
298
+ it('finds zero-overlap position when possible', () => {
299
+ // One small window in the center
300
+ const existing = [{ x: 800, y: 400, width: 320, height: 260 }];
301
+ const result = findFreeSpace(WORK_AREA, existing);
302
+ const overlap = computeOverlapArea(result, existing[0]);
303
+ expect(overlap).toBe(0);
304
+ });
305
+ it('returns correct target size', () => {
306
+ const result = findFreeSpace(WORK_AREA, []);
307
+ expect(result.width).toBe(480); // 1920/4
308
+ expect(result.height).toBe(529); // round(1057/2)
309
+ });
310
+ });
311
+ //# sourceMappingURL=smart-layouts.test.js.map