@jlongo78/agent-spaces 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/.next/standalone/.claude/settings.local.json +16 -0
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +19 -19
  6. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  20. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  24. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  26. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  28. package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  30. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  31. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  32. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  33. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  34. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  35. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  36. package/.next/standalone/.next/server/app/admin/analytics.rsc +5 -5
  37. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
  38. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +5 -5
  42. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  43. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +3 -3
  44. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  45. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  46. package/.next/standalone/.next/server/app/admin/users.rsc +5 -5
  47. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  49. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  50. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  51. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +5 -5
  52. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  53. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +3 -3
  54. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/analytics.html +1 -1
  56. package/.next/standalone/.next/server/app/analytics.rsc +5 -5
  57. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +5 -5
  61. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  62. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +3 -3
  63. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  64. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/chat/route.js +1 -1
  67. package/.next/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/network/handshake/route.js +1 -1
  72. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/network/projects/route.js +2 -1
  74. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/network/search/route.js +2 -1
  76. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js +2 -1
  78. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js +2 -1
  80. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/network/sessions/route.js +2 -1
  82. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js +2 -1
  84. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +2 -1
  86. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/search/route.js +1 -1
  91. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/sessions/route.js +1 -1
  96. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/tier/route.js +1 -1
  100. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/api/workspaces/route.js +1 -1
  108. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/app/login.html +1 -1
  111. package/.next/standalone/.next/server/app/login.rsc +4 -4
  112. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +4 -4
  113. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  114. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +3 -3
  115. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  116. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  117. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  118. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  121. package/.next/standalone/.next/server/app/m/projects.rsc +5 -5
  122. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +5 -5
  123. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  124. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +3 -3
  125. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  126. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +2 -2
  127. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  128. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +2 -2
  129. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  130. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  131. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  132. package/.next/standalone/.next/server/app/m/sessions.rsc +5 -5
  133. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +5 -5
  134. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  135. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +3 -3
  136. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  137. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +2 -2
  138. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  139. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +2 -2
  140. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  141. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  142. package/.next/standalone/.next/server/app/m/settings.rsc +5 -5
  143. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +5 -5
  144. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  145. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +3 -3
  146. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  147. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +2 -2
  148. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  149. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +2 -2
  150. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  152. package/.next/standalone/.next/server/app/m/terminal.rsc +5 -5
  153. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +5 -5
  154. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  155. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +3 -3
  156. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  157. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  158. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  159. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +2 -2
  160. package/.next/standalone/.next/server/app/m.html +1 -1
  161. package/.next/standalone/.next/server/app/m.rsc +5 -5
  162. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +5 -5
  163. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  164. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +3 -3
  165. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  166. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +2 -2
  167. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +2 -2
  168. package/.next/standalone/.next/server/app/network.html +1 -1
  169. package/.next/standalone/.next/server/app/network.rsc +5 -5
  170. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +2 -2
  171. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  172. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  173. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +5 -5
  174. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  175. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +3 -3
  176. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  177. package/.next/standalone/.next/server/app/projects.html +1 -1
  178. package/.next/standalone/.next/server/app/projects.rsc +5 -5
  179. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +2 -2
  180. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  181. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  182. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +5 -5
  183. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  184. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +3 -3
  185. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  186. package/.next/standalone/.next/server/app/sessions.html +1 -1
  187. package/.next/standalone/.next/server/app/sessions.rsc +5 -5
  188. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +2 -2
  189. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  190. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  191. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +5 -5
  192. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  193. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +3 -3
  194. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  195. package/.next/standalone/.next/server/app/settings.html +1 -1
  196. package/.next/standalone/.next/server/app/settings.rsc +5 -5
  197. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +2 -2
  198. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  199. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  200. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +5 -5
  201. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  202. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +3 -3
  203. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  204. package/.next/standalone/.next/server/app/terminal.html +1 -1
  205. package/.next/standalone/.next/server/app/terminal.rsc +5 -5
  206. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  207. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  208. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  209. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +5 -5
  210. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  211. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +3 -3
  212. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  213. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  214. package/.next/standalone/.next/server/app/workspaces.rsc +5 -5
  215. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +2 -2
  216. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  217. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +2 -2
  218. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +5 -5
  219. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  220. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +3 -3
  221. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  222. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d038fdf._.js +106 -0
  223. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0e4c2d35._.js → [root-of-the-server]__12673e47._.js} +2 -2
  224. package/.next/standalone/.next/server/chunks/[root-of-the-server]__130dee4b._.js +2 -2
  225. package/.next/standalone/.next/server/chunks/[root-of-the-server]__142c2f41._.js +2 -2
  226. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2861e096._.js +1 -1
  227. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2d3d8d52._.js +2 -2
  228. package/.next/standalone/.next/server/chunks/[root-of-the-server]__45205e47._.js +98 -0
  229. package/.next/standalone/.next/server/chunks/[root-of-the-server]__46b7da42._.js +98 -0
  230. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__8765f2fc._.js → [root-of-the-server]__4cf845f6._.js} +3 -3
  231. package/.next/standalone/.next/server/chunks/[root-of-the-server]__57b966d5._.js +2 -2
  232. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5a0020ba._.js +3 -3
  233. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5bd0f118._.js +2 -2
  234. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5bf8f2c0._.js +98 -0
  235. package/.next/standalone/.next/server/chunks/[root-of-the-server]__69eb20b1._.js +98 -0
  236. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74c48d65._.js +2 -2
  237. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7d6610c4._.js +2 -2
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__84f3af14._.js +2 -2
  239. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a38f7af1._.js +98 -0
  240. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a6eb742d._.js +3 -3
  241. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4c83e91._.js +3 -3
  242. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b7c8a7dd._.js +98 -0
  243. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__cae0486f._.js → [root-of-the-server]__c1d7faa6._.js} +4 -4
  244. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c546cf71._.js +1 -1
  245. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__a2ee9884._.js → [root-of-the-server]__c977bf2f._.js} +2 -2
  246. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2f9be33._.js +98 -0
  247. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d5615808._.js +2 -2
  248. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d877df12._.js +1 -1
  249. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9d6e526._.js +98 -0
  250. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f66ceeb8._.js +2 -2
  251. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f893957c._.js +3 -3
  252. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fcd26315._.js +2 -2
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fd505913._.js +2 -2
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__feff7b91._.js +3 -3
  255. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  256. package/.next/standalone/.next/server/chunks/ssr/_1f12caba._.js +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/_43e7e611._.js +1 -1
  258. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_network_page_tsx_27f035db._.js +1 -1
  259. package/.next/standalone/.next/server/chunks/ssr/src_lib_telemetry_ts_d7f80cd0._.js +1 -1
  260. package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
  261. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  262. package/.next/standalone/.next/server/pages/404.html +1 -1
  263. package/.next/standalone/.next/server/pages/500.html +2 -2
  264. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  265. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  266. package/.next/standalone/.next/static/chunks/{10c6424526b53431.js → 483bf086feba6531.js} +1 -1
  267. package/.next/standalone/.next/static/chunks/{f8d7a4a58f712ecd.js → 56ddb2d75f5beb1a.js} +1 -1
  268. package/.next/standalone/.next/static/chunks/7c4cfb3160fa8dd4.js +5 -0
  269. package/.next/standalone/.next/static/chunks/{3434c5b2c9958276.js → ae3a695e671c8d31.js} +1 -1
  270. package/.next/standalone/.next/static/chunks/e972ec0d23b19896.js +5 -0
  271. package/.next/standalone/.next/static/chunks/ff5fac1bd7b518dd.css +3 -0
  272. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  273. package/.next/standalone/node_modules/@img/{sharp-linux-x64 → sharp-win32-x64}/package.json +39 -46
  274. package/.next/standalone/package.json +89 -89
  275. package/.next/standalone/server.js +1 -1
  276. package/.next/standalone/tsconfig.json +34 -34
  277. package/LICENSE +661 -661
  278. package/README.md +131 -131
  279. package/bin/fix-standalone-externals.js +79 -79
  280. package/bin/lib/auto-setup.js +110 -101
  281. package/bin/mdns-service.js +171 -171
  282. package/bin/postinstall.js +35 -35
  283. package/bin/setup-admin.js +195 -189
  284. package/bin/spaces-dev.js +208 -208
  285. package/bin/spaces-install.js +572 -483
  286. package/bin/spaces-service.js +881 -0
  287. package/bin/spaces-setup.js +253 -247
  288. package/bin/spaces.js +500 -466
  289. package/bin/terminal-server.js +1252 -1117
  290. package/package.json +89 -89
  291. package/.next/standalone/.next/server/chunks/[root-of-the-server]__18a58c5f._.js +0 -3
  292. package/.next/standalone/.next/server/chunks/[root-of-the-server]__41e589ee._.js +0 -3
  293. package/.next/standalone/.next/server/chunks/[root-of-the-server]__464db440._.js +0 -3
  294. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4ad64489._.js +0 -3
  295. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64f5810e._.js +0 -98
  296. package/.next/standalone/.next/server/chunks/[root-of-the-server]__95b7f18e._.js +0 -3
  297. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a6ce192e._.js +0 -3
  298. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e2b78951._.js +0 -3
  299. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f84e3cf3._.js +0 -98
  300. package/.next/standalone/.next/static/chunks/302ce212c690bec4.js +0 -5
  301. package/.next/standalone/.next/static/chunks/67c7bf5024309fca.css +0 -3
  302. package/.next/standalone/.next/static/chunks/cb442c50eecb758d.js +0 -5
  303. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +0 -46
  304. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  305. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +0 -1
  306. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  307. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +0 -42
  308. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  309. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  310. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  311. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  312. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  313. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  314. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  315. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  316. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  317. /package/.next/standalone/.next/static/{nbYSIjUtkSwSvTgyR5p00 → 5J530rtIR_FsG4E9MLLpB}/_buildManifest.js +0 -0
  318. /package/.next/standalone/.next/static/{nbYSIjUtkSwSvTgyR5p00 → 5J530rtIR_FsG4E9MLLpB}/_clientMiddlewareManifest.json +0 -0
  319. /package/.next/standalone/.next/static/{nbYSIjUtkSwSvTgyR5p00 → 5J530rtIR_FsG4E9MLLpB}/_ssgManifest.js +0 -0
  320. /package/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-win32-x64}/versions.json +0 -0
@@ -0,0 +1,881 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const { execFileSync, spawnSync } = require('child_process');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const fs = require('fs');
9
+ const readline = require('readline');
10
+
11
+ let SPACES_DIR = path.join(os.homedir(), '.spaces');
12
+ let CONFIG_PATH = path.join(SPACES_DIR, 'server.json');
13
+ let LOGS_DIR = path.join(SPACES_DIR, 'logs');
14
+ const SERVICE_NAME = 'spaces';
15
+ const LABEL = 'com.agentspaces.spaces';
16
+ const TASK_NAME = 'Spaces';
17
+
18
+ // Override SPACES_DIR to point to a different user's home
19
+ function setTargetHome(homedir) {
20
+ SPACES_DIR = path.join(homedir, '.spaces');
21
+ CONFIG_PATH = path.join(SPACES_DIR, 'server.json');
22
+ LOGS_DIR = path.join(SPACES_DIR, 'logs');
23
+ }
24
+
25
+ // ─── Helpers ──────────────────────────────────────────────────
26
+ function log(msg) { console.log(` ${msg}`); }
27
+ function logOk(msg) { console.log(` ✓ ${msg}`); }
28
+ function logErr(msg) { console.error(` ✗ ${msg}`); }
29
+
30
+ function resolveConfig() {
31
+ let config = {};
32
+ if (fs.existsSync(CONFIG_PATH)) {
33
+ try { config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')); } catch {}
34
+ }
35
+ return {
36
+ port: config.port || 3457,
37
+ tier: config.tier || 'community',
38
+ basePath: config.basePath || '',
39
+ allowedOrigins: config.allowedOrigins || '',
40
+ };
41
+ }
42
+
43
+ function resolveSpacesPath() {
44
+ return path.join(__dirname, 'spaces.js');
45
+ }
46
+
47
+ function resolveProjectDir() {
48
+ return path.join(__dirname, '..');
49
+ }
50
+
51
+ function resolveNodePath() {
52
+ return process.execPath;
53
+ }
54
+
55
+ function promptLevel() {
56
+ return new Promise((resolve) => {
57
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
58
+ console.log('');
59
+ log('Install as:');
60
+ log(' 1. System service (starts on boot, all users)');
61
+ log(' 2. User service (starts on login, current user only)');
62
+ console.log('');
63
+ rl.question(' Choice [2]: ', (answer) => {
64
+ rl.close();
65
+ const choice = answer.trim() || '2';
66
+ resolve(choice === '1' ? 'system' : 'user');
67
+ });
68
+ });
69
+ }
70
+
71
+ function ensureLogsDir() {
72
+ fs.mkdirSync(LOGS_DIR, { recursive: true });
73
+ }
74
+
75
+ // Detect Windows user profiles that have .claude/ (Claude Code data)
76
+ function findClaudeUsers() {
77
+ if (process.platform !== 'win32') return [];
78
+ const usersDir = path.dirname(os.homedir());
79
+ const skip = new Set(['Public', 'Default', 'Default User', 'All Users']);
80
+ try {
81
+ return fs.readdirSync(usersDir)
82
+ .filter(name => !skip.has(name) && !name.startsWith('.'))
83
+ .filter(name => {
84
+ const claudeDir = path.join(usersDir, name, '.claude');
85
+ return fs.existsSync(claudeDir);
86
+ })
87
+ .map(name => ({ name, homedir: path.join(usersDir, name) }));
88
+ } catch { return []; }
89
+ }
90
+
91
+ // Prompt for which user's home directory to target (system service only).
92
+ // Looks for users with .claude/ (Claude Code data) since that's what gets synced.
93
+ function promptTargetUser() {
94
+ return new Promise((resolve) => {
95
+ const currentHome = os.homedir();
96
+ const users = findClaudeUsers();
97
+
98
+ // No Claude users found — fall back to current user
99
+ if (users.length === 0) {
100
+ resolve(currentHome);
101
+ return;
102
+ }
103
+ // Single Claude user — auto-select
104
+ if (users.length === 1) {
105
+ log(`Using home directory: ${users[0].homedir}`);
106
+ resolve(users[0].homedir);
107
+ return;
108
+ }
109
+
110
+ // Multiple Claude users — ask which one
111
+ console.log('');
112
+ log('Multiple users have Claude Code data:');
113
+ users.forEach((u, i) => log(` ${i + 1}. ${u.name} (${u.homedir})`));
114
+ console.log('');
115
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
116
+ rl.question(` Run as user [1]: `, (answer) => {
117
+ rl.close();
118
+ const idx = parseInt(answer.trim() || '1', 10) - 1;
119
+ const chosen = users[idx] || users[0];
120
+ resolve(chosen.homedir);
121
+ });
122
+ });
123
+ }
124
+
125
+
126
+ // --- SSH key provisioning (for multi-user system service) ---
127
+ function checkOpenSSHServer() {
128
+ if (process.platform !== 'win32') return true;
129
+ try {
130
+ const result = spawnSync('powershell', ['-NoProfile', '-Command',
131
+ 'Get-Service sshd -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Status'
132
+ ], { encoding: 'utf-8', timeout: 10000 });
133
+ const status = (result.stdout || '').trim();
134
+ return status === 'Running' || status === 'Stopped';
135
+ } catch { return false; }
136
+ }
137
+
138
+ function ensureOpenSSHServer() {
139
+ if (process.platform !== 'win32') return;
140
+ if (checkOpenSSHServer()) {
141
+ try {
142
+ spawnSync('powershell', ['-NoProfile', '-Command',
143
+ 'Start-Service sshd; Set-Service -Name sshd -StartupType Automatic'
144
+ ], { stdio: 'pipe', timeout: 15000 });
145
+ logOk('OpenSSH Server started and set to automatic');
146
+ } catch {
147
+ log('Warning: could not start OpenSSH Server');
148
+ }
149
+ return;
150
+ }
151
+ log('Installing OpenSSH Server (required for multi-user terminals)...');
152
+ try {
153
+ const result = spawnSync('powershell', ['-NoProfile', '-Command',
154
+ 'Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0'
155
+ ], { encoding: 'utf-8', stdio: 'pipe', timeout: 120000 });
156
+ if (result.status === 0) {
157
+ logOk('OpenSSH Server installed');
158
+ spawnSync('powershell', ['-NoProfile', '-Command',
159
+ 'Start-Service sshd; Set-Service -Name sshd -StartupType Automatic'
160
+ ], { stdio: 'pipe', timeout: 15000 });
161
+ logOk('OpenSSH Server started');
162
+ } else {
163
+ logErr('Failed to install OpenSSH Server: ' + (result.stderr || '').trim());
164
+ log('Multi-user terminals will not work. Install manually:');
165
+ log(' Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0');
166
+ }
167
+ } catch (e) {
168
+ logErr('Failed to install OpenSSH Server: ' + e.message);
169
+ }
170
+ }
171
+
172
+ function ensureServiceKey() {
173
+ const keyPath = path.join(SPACES_DIR, 'service_key');
174
+ if (fs.existsSync(keyPath)) return keyPath;
175
+ log('Generating SSH service key...');
176
+ fs.mkdirSync(SPACES_DIR, { recursive: true });
177
+ const result = spawnSync('ssh-keygen', [
178
+ '-t', 'ed25519',
179
+ '-f', keyPath,
180
+ '-N', '',
181
+ '-C', 'spaces-service-key',
182
+ ], { stdio: 'pipe', timeout: 10000 });
183
+ if (result.status !== 0) {
184
+ logErr('Failed to generate SSH key');
185
+ return null;
186
+ }
187
+
188
+ // On Windows, restrict private key permissions so OpenSSH accepts it.
189
+ // OpenSSH requires: no inherited ACLs, only the file owner + SYSTEM may have access.
190
+ if (process.platform === 'win32') {
191
+ try {
192
+ const currentUser = os.userInfo().username;
193
+ // Remove inheritance and all default ACLs, then grant only owner + SYSTEM
194
+ spawnSync('icacls', [keyPath, '/inheritance:r',
195
+ '/remove', 'BUILTIN\\Administrators',
196
+ '/remove', 'BUILTIN\\Users',
197
+ '/remove', 'Everyone',
198
+ '/grant:r', currentUser + ':(F)',
199
+ '/grant', 'NT AUTHORITY\\SYSTEM:(F)'], { stdio: 'pipe', timeout: 5000 });
200
+ } catch {}
201
+ }
202
+
203
+ logOk('SSH service key generated');
204
+ return keyPath;
205
+ }
206
+
207
+ function authorizeServiceKey(keyPath, targetUser) {
208
+ const pubKey = fs.readFileSync(keyPath + '.pub', 'utf-8').trim();
209
+
210
+ if (process.platform === 'win32') {
211
+ // Windows OpenSSH ignores ~/.ssh/authorized_keys for admin users.
212
+ // Must use C:\ProgramData\ssh\administrators_authorized_keys instead.
213
+ const adminAuthKeys = path.join(process.env.ProgramData || 'C:\\ProgramData', 'ssh', 'administrators_authorized_keys');
214
+ const userAuthKeys = path.join(path.dirname(os.homedir()), targetUser, '.ssh', 'authorized_keys');
215
+
216
+ // Check if user is an administrator (exact match, not substring)
217
+ let isAdmin = false;
218
+ try {
219
+ const result = spawnSync('net', ['localgroup', 'Administrators'], { encoding: 'utf-8', timeout: 5000 });
220
+ const lines = (result.stdout || '').split(/\r?\n/);
221
+ const sep = lines.findIndex(l => l.trim().startsWith('---'));
222
+ if (sep >= 0) {
223
+ const members = lines.slice(sep + 1).map(l => l.trim()).filter(Boolean);
224
+ isAdmin = members.some(m => m.toLowerCase() === targetUser.toLowerCase());
225
+ }
226
+ } catch {}
227
+
228
+ const authKeysPath = isAdmin ? adminAuthKeys : userAuthKeys;
229
+ const authDir = path.dirname(authKeysPath);
230
+ if (!fs.existsSync(authDir)) fs.mkdirSync(authDir, { recursive: true });
231
+
232
+ // Check if key already authorized
233
+ if (fs.existsSync(authKeysPath)) {
234
+ const existing = fs.readFileSync(authKeysPath, 'utf-8');
235
+ if (existing.includes(pubKey)) return;
236
+ }
237
+ fs.appendFileSync(authKeysPath, pubKey + String.fromCharCode(10));
238
+
239
+ // Fix permissions for administrators_authorized_keys
240
+ if (isAdmin) {
241
+ try {
242
+ spawnSync('icacls', [authKeysPath, '/inheritance:r', '/grant', 'SYSTEM:(R)', '/grant', 'Administrators:(R)'], { stdio: 'pipe', timeout: 5000 });
243
+ } catch {}
244
+ }
245
+ } else {
246
+ // Linux/macOS: use ~/.ssh/authorized_keys
247
+ let userHome;
248
+ try {
249
+ // Use getent to resolve the actual home directory (works with LDAP, NIS, etc.)
250
+ const result = spawnSync('getent', ['passwd', targetUser], { encoding: 'utf-8', timeout: 5000 });
251
+ const fields = (result.stdout || '').split(':');
252
+ userHome = fields[5] || (process.platform === 'darwin' ? `/Users/${targetUser}` : `/home/${targetUser}`);
253
+ } catch {
254
+ userHome = process.platform === 'darwin' ? `/Users/${targetUser}` : `/home/${targetUser}`;
255
+ }
256
+ const sshDir = path.join(userHome, '.ssh');
257
+ const authKeysPath = path.join(sshDir, 'authorized_keys');
258
+ if (!fs.existsSync(sshDir)) fs.mkdirSync(sshDir, { recursive: true, mode: 0o700 });
259
+ if (fs.existsSync(authKeysPath)) {
260
+ const existing = fs.readFileSync(authKeysPath, 'utf-8');
261
+ if (existing.includes(pubKey)) return;
262
+ }
263
+ fs.appendFileSync(authKeysPath, pubKey + String.fromCharCode(10));
264
+ }
265
+ logOk('SSH key authorized for ' + targetUser);
266
+ }
267
+
268
+ const LEVEL_PATH = path.join(SPACES_DIR, 'service-level');
269
+
270
+ function saveLevel(level) {
271
+ fs.mkdirSync(SPACES_DIR, { recursive: true });
272
+ fs.writeFileSync(LEVEL_PATH, level);
273
+ }
274
+
275
+ function loadLevel() {
276
+ try { return fs.readFileSync(LEVEL_PATH, 'utf-8').trim(); } catch { return null; }
277
+ }
278
+
279
+ // ─── Platform detection ───────────────────────────────────────
280
+ function getPlatform() {
281
+ switch (process.platform) {
282
+ case 'linux': return 'linux';
283
+ case 'darwin': return 'darwin';
284
+ case 'win32': return 'win32';
285
+ default:
286
+ logErr(`Unsupported platform: ${process.platform}`);
287
+ process.exit(1);
288
+ }
289
+ }
290
+
291
+ // ─── Linux (systemd) ─────────────────────────────────────────
292
+ function linuxServicePath(level) {
293
+ if (level === 'system') {
294
+ return `/etc/systemd/system/${SERVICE_NAME}.service`;
295
+ }
296
+ const userDir = path.join(os.homedir(), '.config', 'systemd', 'user');
297
+ fs.mkdirSync(userDir, { recursive: true });
298
+ return path.join(userDir, `${SERVICE_NAME}.service`);
299
+ }
300
+
301
+ function linuxUnitFile(level) {
302
+ const config = resolveConfig();
303
+ const nodePath = resolveNodePath();
304
+ const spacesPath = resolveSpacesPath();
305
+ const projectDir = resolveProjectDir();
306
+
307
+ let envLines = [
308
+ `Environment=SPACES_SERVICE=1`,
309
+ `Environment=SPACES_PORT=${config.port}`,
310
+ ];
311
+ // Don't hardcode SPACES_TIER — let spaces.js auto-detect from installed packages
312
+ if (config.tier && config.tier !== 'community') {
313
+ envLines.push(`Environment=SPACES_TIER=${config.tier}`);
314
+ }
315
+ if (config.basePath) {
316
+ envLines.push(`Environment=SPACES_BASE_PATH=${config.basePath}`);
317
+ }
318
+ if (config.allowedOrigins) {
319
+ envLines.push(`Environment=SPACES_ALLOWED_ORIGINS=${config.allowedOrigins}`);
320
+ }
321
+
322
+ let serviceSection = [
323
+ 'Type=simple',
324
+ `ExecStart=${nodePath} ${spacesPath}`,
325
+ `WorkingDirectory=${projectDir}`,
326
+ ...envLines,
327
+ 'Restart=on-failure',
328
+ 'RestartSec=5',
329
+ ];
330
+
331
+ if (level === 'system') {
332
+ const username = os.userInfo().username;
333
+ serviceSection.push(`User=${username}`);
334
+ serviceSection.push(`Group=${username}`);
335
+ }
336
+
337
+ const wantedBy = level === 'system' ? 'multi-user.target' : 'default.target';
338
+
339
+ return [
340
+ '[Unit]',
341
+ 'Description=Spaces - Agent Workspace Manager',
342
+ 'After=network.target',
343
+ '',
344
+ '[Service]',
345
+ ...serviceSection,
346
+ '',
347
+ '[Install]',
348
+ `WantedBy=${wantedBy}`,
349
+ '',
350
+ ].join('\n');
351
+ }
352
+
353
+ function linuxSystemctl(level, ...args) {
354
+ if (level === 'system') {
355
+ execFileSync('sudo', ['systemctl', ...args], { stdio: 'inherit' });
356
+ } else {
357
+ // User-level systemctl needs XDG_RUNTIME_DIR to connect to the user bus
358
+ const env = { ...process.env };
359
+ if (!env.XDG_RUNTIME_DIR) {
360
+ env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
361
+ }
362
+ execFileSync('systemctl', ['--user', ...args], { stdio: 'inherit', env });
363
+ }
364
+ }
365
+
366
+ async function linuxInstall() {
367
+ const level = await promptLevel();
368
+ const unitContent = linuxUnitFile(level);
369
+ const servicePath = linuxServicePath(level);
370
+
371
+ log(`Writing unit file to ${servicePath}`);
372
+ if (level === 'system') {
373
+ const result = spawnSync('sudo', ['tee', servicePath], {
374
+ input: unitContent,
375
+ stdio: ['pipe', 'pipe', 'inherit'],
376
+ });
377
+ if (result.status !== 0) {
378
+ logErr('Failed to write unit file');
379
+ process.exit(1);
380
+ }
381
+ } else {
382
+ fs.writeFileSync(servicePath, unitContent);
383
+ }
384
+ logOk('Unit file written');
385
+
386
+ saveLevel(level);
387
+
388
+ linuxSystemctl(level, 'daemon-reload');
389
+ logOk('Reloaded systemd daemon');
390
+
391
+ linuxSystemctl(level, 'enable', `${SERVICE_NAME}.service`);
392
+ logOk('Service enabled');
393
+
394
+ linuxSystemctl(level, 'start', `${SERVICE_NAME}.service`);
395
+ logOk('Service started');
396
+
397
+ if (level === 'user') {
398
+ try {
399
+ const env = { ...process.env };
400
+ if (!env.XDG_RUNTIME_DIR) env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
401
+ execFileSync('loginctl', ['enable-linger', os.userInfo().username], { stdio: 'inherit', env });
402
+ logOk('Enabled login lingering for user service');
403
+ } catch {
404
+ log('Warning: could not enable-linger (user service may not start on boot)');
405
+ }
406
+ }
407
+
408
+ logOk(`Spaces installed as ${level} service`);
409
+ }
410
+
411
+ async function linuxUninstall() {
412
+ const level = loadLevel() || 'user';
413
+ const servicePath = linuxServicePath(level);
414
+
415
+ try {
416
+ linuxSystemctl(level, 'stop', `${SERVICE_NAME}.service`);
417
+ logOk('Service stopped');
418
+ } catch {
419
+ log('Service was not running');
420
+ }
421
+
422
+ try {
423
+ linuxSystemctl(level, 'disable', `${SERVICE_NAME}.service`);
424
+ logOk('Service disabled');
425
+ } catch {
426
+ log('Service was not enabled');
427
+ }
428
+
429
+ try {
430
+ if (level === 'system') {
431
+ execFileSync('sudo', ['rm', '-f', servicePath], { stdio: 'inherit' });
432
+ } else {
433
+ fs.unlinkSync(servicePath);
434
+ }
435
+ logOk('Unit file removed');
436
+ } catch {
437
+ log('Unit file was already removed');
438
+ }
439
+
440
+ try {
441
+ linuxSystemctl(level, 'daemon-reload');
442
+ logOk('Reloaded systemd daemon');
443
+ } catch {
444
+ log('Warning: daemon-reload failed');
445
+ }
446
+
447
+ try {
448
+ fs.unlinkSync(LEVEL_PATH);
449
+ } catch {}
450
+
451
+ logOk('Spaces service uninstalled');
452
+ }
453
+
454
+ async function linuxStart() {
455
+ const level = loadLevel() || 'user';
456
+ linuxSystemctl(level, 'start', `${SERVICE_NAME}.service`);
457
+ logOk('Service started');
458
+ }
459
+
460
+ async function linuxStop() {
461
+ const level = loadLevel() || 'user';
462
+ linuxSystemctl(level, 'stop', `${SERVICE_NAME}.service`);
463
+ logOk('Service stopped');
464
+ }
465
+
466
+ async function linuxStatus() {
467
+ const level = loadLevel() || 'user';
468
+ try {
469
+ linuxSystemctl(level, 'status', `${SERVICE_NAME}.service`);
470
+ } catch {
471
+ // systemctl status returns non-zero for stopped/failed services
472
+ }
473
+ }
474
+
475
+ async function linuxLogs() {
476
+ const level = loadLevel() || 'user';
477
+ if (level === 'user') {
478
+ const env = { ...process.env };
479
+ if (!env.XDG_RUNTIME_DIR) env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
480
+ spawnSync('journalctl', ['--user', '-u', SERVICE_NAME, '-f', '--no-pager'], { stdio: 'inherit', env });
481
+ } else {
482
+ spawnSync('sudo', ['journalctl', '-u', SERVICE_NAME, '-f', '--no-pager'], { stdio: 'inherit' });
483
+ }
484
+ }
485
+
486
+ // ─── macOS (launchd) ─────────────────────────────────────────
487
+ function darwinPlistPath(level) {
488
+ if (level === 'system') {
489
+ return `/Library/LaunchDaemons/${LABEL}.plist`;
490
+ }
491
+ return path.join(os.homedir(), 'Library', 'LaunchAgents', `${LABEL}.plist`);
492
+ }
493
+
494
+ function darwinPlistContent(level) {
495
+ ensureLogsDir();
496
+ const config = resolveConfig();
497
+ const nodePath = resolveNodePath();
498
+ const spacesPath = resolveSpacesPath();
499
+ const projectDir = resolveProjectDir();
500
+ const outLog = path.join(LOGS_DIR, 'spaces.out.log');
501
+ const errLog = path.join(LOGS_DIR, 'spaces.err.log');
502
+
503
+ let envEntries = [
504
+ ` <key>SPACES_SERVICE</key>`,
505
+ ` <string>1</string>`,
506
+ ` <key>SPACES_PORT</key>`,
507
+ ` <string>${config.port}</string>`,
508
+ ];
509
+ // Don't hardcode SPACES_TIER — let spaces.js auto-detect from installed packages
510
+ if (config.tier && config.tier !== 'community') {
511
+ envEntries.push(` <key>SPACES_TIER</key>`);
512
+ envEntries.push(` <string>${config.tier}</string>`);
513
+ }
514
+ if (config.basePath) {
515
+ envEntries.push(` <key>SPACES_BASE_PATH</key>`);
516
+ envEntries.push(` <string>${config.basePath}</string>`);
517
+ }
518
+ if (config.allowedOrigins) {
519
+ envEntries.push(` <key>SPACES_ALLOWED_ORIGINS</key>`);
520
+ envEntries.push(` <string>${config.allowedOrigins}</string>`);
521
+ }
522
+
523
+ let extraKeys = '';
524
+ if (level === 'system') {
525
+ extraKeys = ` <key>UserName</key>\n <string>${os.userInfo().username}</string>\n`;
526
+ }
527
+
528
+ return [
529
+ '<?xml version="1.0" encoding="UTF-8"?>',
530
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
531
+ '<plist version="1.0">',
532
+ '<dict>',
533
+ ` <key>Label</key>`,
534
+ ` <string>${LABEL}</string>`,
535
+ ` <key>ProgramArguments</key>`,
536
+ ` <array>`,
537
+ ` <string>${nodePath}</string>`,
538
+ ` <string>${spacesPath}</string>`,
539
+ ` </array>`,
540
+ ` <key>WorkingDirectory</key>`,
541
+ ` <string>${projectDir}</string>`,
542
+ ` <key>EnvironmentVariables</key>`,
543
+ ` <dict>`,
544
+ ...envEntries,
545
+ ` </dict>`,
546
+ ` <key>RunAtLoad</key>`,
547
+ ` <true/>`,
548
+ ` <key>KeepAlive</key>`,
549
+ ` <true/>`,
550
+ ` <key>StandardOutPath</key>`,
551
+ ` <string>${outLog}</string>`,
552
+ ` <key>StandardErrorPath</key>`,
553
+ ` <string>${errLog}</string>`,
554
+ extraKeys ? extraKeys.trimEnd() : null,
555
+ '</dict>',
556
+ '</plist>',
557
+ '',
558
+ ].filter((line) => line !== null).join('\n');
559
+ }
560
+
561
+ async function darwinInstall() {
562
+ const level = await promptLevel();
563
+ const plistPath = darwinPlistPath(level);
564
+ const plistContent = darwinPlistContent(level);
565
+
566
+ // Unload existing (ignore errors)
567
+ try {
568
+ execFileSync('launchctl', ['unload', '-w', plistPath], { stdio: 'pipe' });
569
+ } catch {}
570
+
571
+ log(`Writing plist to ${plistPath}`);
572
+ if (level === 'system') {
573
+ const result = spawnSync('sudo', ['tee', plistPath], {
574
+ input: plistContent,
575
+ stdio: ['pipe', 'pipe', 'inherit'],
576
+ });
577
+ if (result.status !== 0) {
578
+ logErr('Failed to write plist file');
579
+ process.exit(1);
580
+ }
581
+ execFileSync('sudo', ['chown', 'root:wheel', plistPath], { stdio: 'inherit' });
582
+ execFileSync('sudo', ['chmod', '644', plistPath], { stdio: 'inherit' });
583
+ } else {
584
+ const agentsDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
585
+ fs.mkdirSync(agentsDir, { recursive: true });
586
+ fs.writeFileSync(plistPath, plistContent);
587
+ }
588
+ logOk('Plist file written');
589
+
590
+ saveLevel(level);
591
+
592
+ if (level === 'system') {
593
+ execFileSync('sudo', ['launchctl', 'load', '-w', plistPath], { stdio: 'inherit' });
594
+ } else {
595
+ execFileSync('launchctl', ['load', '-w', plistPath], { stdio: 'inherit' });
596
+ }
597
+ logOk('Service loaded');
598
+
599
+ logOk(`Spaces installed as ${level} service`);
600
+ }
601
+
602
+ async function darwinUninstall() {
603
+ const level = loadLevel() || 'user';
604
+ const plistPath = darwinPlistPath(level);
605
+
606
+ try {
607
+ if (level === 'system') {
608
+ execFileSync('sudo', ['launchctl', 'unload', '-w', plistPath], { stdio: 'inherit' });
609
+ } else {
610
+ execFileSync('launchctl', ['unload', '-w', plistPath], { stdio: 'inherit' });
611
+ }
612
+ logOk('Service unloaded');
613
+ } catch {
614
+ log('Service was not loaded');
615
+ }
616
+
617
+ try {
618
+ if (level === 'system') {
619
+ execFileSync('sudo', ['rm', '-f', plistPath], { stdio: 'inherit' });
620
+ } else {
621
+ fs.unlinkSync(plistPath);
622
+ }
623
+ logOk('Plist file removed');
624
+ } catch {
625
+ log('Plist file was already removed');
626
+ }
627
+
628
+ try {
629
+ fs.unlinkSync(LEVEL_PATH);
630
+ } catch {}
631
+
632
+ logOk('Spaces service uninstalled');
633
+ }
634
+
635
+ async function darwinStart() {
636
+ const level = loadLevel() || 'user';
637
+ const plistPath = darwinPlistPath(level);
638
+ if (level === 'system') {
639
+ execFileSync('sudo', ['launchctl', 'load', '-w', plistPath], { stdio: 'inherit' });
640
+ } else {
641
+ execFileSync('launchctl', ['load', '-w', plistPath], { stdio: 'inherit' });
642
+ }
643
+ logOk('Service started');
644
+ }
645
+
646
+ async function darwinStop() {
647
+ const level = loadLevel() || 'user';
648
+ const plistPath = darwinPlistPath(level);
649
+ if (level === 'system') {
650
+ execFileSync('sudo', ['launchctl', 'unload', '-w', plistPath], { stdio: 'inherit' });
651
+ } else {
652
+ execFileSync('launchctl', ['unload', '-w', plistPath], { stdio: 'inherit' });
653
+ }
654
+ logOk('Service stopped');
655
+ }
656
+
657
+ async function darwinStatus() {
658
+ try {
659
+ const result = execFileSync('launchctl', ['list'], { encoding: 'utf-8' });
660
+ const lines = result.split('\n').filter((line) => line.includes(LABEL));
661
+ if (lines.length > 0) {
662
+ log('Spaces service status:');
663
+ lines.forEach((line) => log(line));
664
+ } else {
665
+ log('Spaces service is not loaded');
666
+ }
667
+ } catch {
668
+ log('Spaces service is not loaded');
669
+ }
670
+ }
671
+
672
+ async function darwinLogs() {
673
+ ensureLogsDir();
674
+ const outLogPath = path.join(LOGS_DIR, 'spaces.out.log');
675
+ if (!fs.existsSync(outLogPath)) {
676
+ logErr(`Log file not found: ${outLogPath}`);
677
+ log('Service may not have started yet');
678
+ process.exit(1);
679
+ }
680
+ spawnSync('tail', ['-f', outLogPath], { stdio: 'inherit' });
681
+ }
682
+
683
+ // ─── Windows (Task Scheduler) ────────────────────────────────
684
+ function win32WrapperScript(level) {
685
+ ensureLogsDir();
686
+ const config = resolveConfig();
687
+ const nodePath = resolveNodePath();
688
+ const spacesPath = resolveSpacesPath();
689
+ const outLog = path.join(LOGS_DIR, 'spaces.out.log');
690
+ const wrapperPath = path.join(SPACES_DIR, 'spaces-service.cmd');
691
+
692
+ const lines = [
693
+ '@echo off',
694
+ ];
695
+ // When running as SYSTEM, override USERPROFILE so os.homedir() resolves
696
+ // to the target user's home directory (where .spaces/ config lives).
697
+ if (level === 'system') {
698
+ const homedir = path.dirname(SPACES_DIR); // use resolved target, not os.homedir()
699
+ const drive = path.parse(homedir).root.slice(0, -1);
700
+ const rest = homedir.slice(drive.length);
701
+ lines.push(`set USERPROFILE=${homedir}`);
702
+ lines.push(`set HOMEDRIVE=${drive}`);
703
+ lines.push(`set HOMEPATH=${rest}`);
704
+ }
705
+ lines.push('set SPACES_SERVICE=1');
706
+ lines.push(`set SPACES_PORT=${config.port}`);
707
+ // Don't hardcode SPACES_TIER — let spaces.js auto-detect from installed packages
708
+ if (config.tier && config.tier !== 'community') {
709
+ lines.push(`set SPACES_TIER=${config.tier}`);
710
+ }
711
+ if (config.basePath) {
712
+ lines.push(`set SPACES_BASE_PATH=${config.basePath}`);
713
+ }
714
+ if (config.allowedOrigins) {
715
+ lines.push(`set SPACES_ALLOWED_ORIGINS=${config.allowedOrigins}`);
716
+ }
717
+ lines.push(`"${nodePath}" "${spacesPath}" >> "${outLog}" 2>&1`);
718
+ lines.push('');
719
+
720
+ fs.writeFileSync(wrapperPath, lines.join('\r\n'));
721
+ return wrapperPath;
722
+ }
723
+
724
+ async function win32Install() {
725
+ const level = await promptLevel();
726
+
727
+ // For system service, determine the target user's home directory
728
+ // (may differ from the admin account running the installer)
729
+ if (level === 'system' && process.platform === 'win32') {
730
+ const targetHome = await promptTargetUser();
731
+ setTargetHome(targetHome);
732
+ }
733
+
734
+ const wrapperPath = win32WrapperScript(level);
735
+
736
+ log(`Wrapper script written to ${wrapperPath}`);
737
+
738
+ // Delete existing task (ignore errors)
739
+ try {
740
+ execFileSync('schtasks', ['/Delete', '/TN', TASK_NAME, '/F'], { stdio: 'pipe' });
741
+ } catch {}
742
+
743
+ if (level === 'system') {
744
+ execFileSync('schtasks', ['/Create', '/TN', TASK_NAME, '/TR', `"${wrapperPath}"`, '/SC', 'ONSTART', '/RU', 'SYSTEM', '/F'], { stdio: 'inherit' });
745
+ } else {
746
+ execFileSync('schtasks', ['/Create', '/TN', TASK_NAME, '/TR', `"${wrapperPath}"`, '/SC', 'ONLOGON', '/RL', 'HIGHEST', '/F'], { stdio: 'inherit' });
747
+ }
748
+ logOk('Scheduled task created');
749
+
750
+ saveLevel(level);
751
+
752
+ // Set up SSH for multi-user support (system service only)
753
+ // Only ensure OpenSSH is available — key generation is handled at runtime
754
+ // by ensureServiceKeyAtRuntime() in terminal-server.js, which runs as SYSTEM
755
+ // so the key is owned by SYSTEM and OpenSSH accepts it.
756
+ if (level === 'system') {
757
+ ensureOpenSSHServer();
758
+ log('SSH service key will be generated on first run (as SYSTEM)');
759
+ }
760
+
761
+ execFileSync('schtasks', ['/Run', '/TN', TASK_NAME], { stdio: 'inherit' });
762
+ logOk('Task started');
763
+
764
+ logOk(`Spaces installed as ${level} service`);
765
+ }
766
+
767
+ async function win32Uninstall() {
768
+ try {
769
+ execFileSync('schtasks', ['/End', '/TN', TASK_NAME], { stdio: 'pipe' });
770
+ logOk('Task ended');
771
+ } catch {
772
+ log('Task was not running');
773
+ }
774
+
775
+ try {
776
+ execFileSync('schtasks', ['/Delete', '/TN', TASK_NAME, '/F'], { stdio: 'pipe' });
777
+ logOk('Scheduled task removed');
778
+ } catch {
779
+ log('Scheduled task was already removed');
780
+ }
781
+
782
+ try {
783
+ const wrapperPath = path.join(SPACES_DIR, 'spaces-service.cmd');
784
+ fs.unlinkSync(wrapperPath);
785
+ logOk('Wrapper script removed');
786
+ } catch {
787
+ log('Wrapper script was already removed');
788
+ }
789
+
790
+ try {
791
+ fs.unlinkSync(LEVEL_PATH);
792
+ } catch {}
793
+
794
+ logOk('Spaces service uninstalled');
795
+ }
796
+
797
+ async function win32Start() {
798
+ execFileSync('schtasks', ['/Run', '/TN', TASK_NAME], { stdio: 'inherit' });
799
+ logOk('Task started');
800
+ }
801
+
802
+ async function win32Stop() {
803
+ try {
804
+ execFileSync('schtasks', ['/End', '/TN', TASK_NAME], { stdio: 'pipe' });
805
+ } catch {}
806
+
807
+ // Kill the actual node processes on our ports (verify it's node before killing)
808
+ const config = resolveConfig();
809
+ const ports = [config.port || 3457, 3400];
810
+ let killed = 0;
811
+ for (const port of ports) {
812
+ try {
813
+ const output = execFileSync('netstat', ['-ano'], { encoding: 'utf-8' });
814
+ for (const line of output.split(String.fromCharCode(10))) {
815
+ if (line.includes(':' + port + ' ') && line.includes('LISTENING')) {
816
+ const parts = line.trim().split(/\s+/);
817
+ const pid = parseInt(parts[parts.length - 1], 10);
818
+ if (pid > 0) {
819
+ // Verify the process is node.exe before killing to avoid terminating unrelated processes
820
+ try {
821
+ const taskInfo = execFileSync('tasklist', ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'], { encoding: 'utf-8' });
822
+ if (!taskInfo.toLowerCase().includes('node.exe')) continue;
823
+ process.kill(pid, 'SIGTERM'); killed++;
824
+ } catch {}
825
+ }
826
+ }
827
+ }
828
+ } catch {}
829
+ }
830
+
831
+ if (killed > 0) {
832
+ logOk('Stopped ' + killed + ' process(es)');
833
+ } else {
834
+ logOk('Task stopped');
835
+ }
836
+ }
837
+
838
+ async function win32Status() {
839
+ try {
840
+ execFileSync('schtasks', ['/Query', '/TN', TASK_NAME, '/V', '/FO', 'LIST'], { stdio: 'inherit' });
841
+ } catch {
842
+ log('Spaces service is not installed');
843
+ }
844
+ }
845
+
846
+ async function win32Logs() {
847
+ ensureLogsDir();
848
+ const outLogPath = path.join(LOGS_DIR, 'spaces.out.log');
849
+ if (!fs.existsSync(outLogPath)) {
850
+ logErr(`Log file not found: ${outLogPath}`);
851
+ log('Service may not have started yet');
852
+ process.exit(1);
853
+ }
854
+ spawnSync('powershell', ['-Command', `Get-Content "${outLogPath}" -Wait -Tail 50`], { stdio: 'inherit' });
855
+ }
856
+
857
+ // ─── Dispatch table ──────────────────────────────────────────
858
+ const platforms = {
859
+ linux: { install: linuxInstall, uninstall: linuxUninstall, start: linuxStart, stop: linuxStop, status: linuxStatus, logs: linuxLogs },
860
+ darwin: { install: darwinInstall, uninstall: darwinUninstall, start: darwinStart, stop: darwinStop, status: darwinStatus, logs: darwinLogs },
861
+ win32: { install: win32Install, uninstall: win32Uninstall, start: win32Start, stop: win32Stop, status: win32Status, logs: win32Logs },
862
+ };
863
+
864
+ // ─── CLI ──────────────────────────────────────────────────────
865
+ async function main() {
866
+ const action = process.argv[2];
867
+ const platform = getPlatform();
868
+ const dispatch = platforms[platform];
869
+
870
+ if (!action || !dispatch[action]) {
871
+ log('Usage: spaces service <install|uninstall|start|stop|status|logs>');
872
+ process.exit(action ? 1 : 0);
873
+ }
874
+
875
+ await dispatch[action]();
876
+ }
877
+
878
+ main().catch((err) => {
879
+ logErr(err.message);
880
+ process.exit(1);
881
+ });