gitspace 0.2.0-rc.2 → 0.2.0-rc.21

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 (316) hide show
  1. package/README.md +68 -38
  2. package/package.json +36 -25
  3. package/.claude/settings.local.json +0 -21
  4. package/.gitspace/bundle.json +0 -50
  5. package/.gitspace/select/01-status.sh +0 -40
  6. package/.gitspace/setup/01-install-deps.sh +0 -12
  7. package/.gitspace/setup/02-typecheck.sh +0 -16
  8. package/AGENTS.md +0 -439
  9. package/CLAUDE.md +0 -1
  10. package/bun.lock +0 -647
  11. package/docs/CONNECTION.md +0 -623
  12. package/docs/GATEWAY-WORKER.md +0 -319
  13. package/docs/GETTING-STARTED.md +0 -448
  14. package/docs/GITSPACE-PLATFORM.md +0 -1819
  15. package/docs/INFRASTRUCTURE.md +0 -1347
  16. package/docs/PROTOCOL.md +0 -619
  17. package/docs/QUICKSTART.md +0 -174
  18. package/docs/RELAY.md +0 -327
  19. package/docs/REMOTE-DESIGN.md +0 -549
  20. package/docs/ROADMAP.md +0 -564
  21. package/docs/SITE_DOCS_FIGMA_MAKE.md +0 -1167
  22. package/docs/STACK-DESIGN.md +0 -588
  23. package/docs/UNIFIED_ARCHITECTURE.md +0 -292
  24. package/experiments/pty-benchmark.ts +0 -148
  25. package/experiments/pty-latency.ts +0 -100
  26. package/experiments/router/client.ts +0 -199
  27. package/experiments/router/protocol.ts +0 -74
  28. package/experiments/router/router.ts +0 -217
  29. package/experiments/router/session.ts +0 -180
  30. package/experiments/router/test.ts +0 -133
  31. package/experiments/socket-bandwidth.ts +0 -77
  32. package/homebrew/gitspace.rb +0 -45
  33. package/landing-page/ATTRIBUTIONS.md +0 -3
  34. package/landing-page/README.md +0 -11
  35. package/landing-page/bun.lock +0 -801
  36. package/landing-page/guidelines/Guidelines.md +0 -61
  37. package/landing-page/index.html +0 -37
  38. package/landing-page/package.json +0 -90
  39. package/landing-page/postcss.config.mjs +0 -15
  40. package/landing-page/public/_redirects +0 -1
  41. package/landing-page/public/favicon.png +0 -0
  42. package/landing-page/src/app/App.tsx +0 -53
  43. package/landing-page/src/app/components/figma/ImageWithFallback.tsx +0 -27
  44. package/landing-page/src/app/components/ui/accordion.tsx +0 -66
  45. package/landing-page/src/app/components/ui/alert-dialog.tsx +0 -157
  46. package/landing-page/src/app/components/ui/alert.tsx +0 -66
  47. package/landing-page/src/app/components/ui/aspect-ratio.tsx +0 -11
  48. package/landing-page/src/app/components/ui/avatar.tsx +0 -53
  49. package/landing-page/src/app/components/ui/badge.tsx +0 -46
  50. package/landing-page/src/app/components/ui/breadcrumb.tsx +0 -109
  51. package/landing-page/src/app/components/ui/button.tsx +0 -57
  52. package/landing-page/src/app/components/ui/calendar.tsx +0 -75
  53. package/landing-page/src/app/components/ui/card.tsx +0 -92
  54. package/landing-page/src/app/components/ui/carousel.tsx +0 -241
  55. package/landing-page/src/app/components/ui/chart.tsx +0 -353
  56. package/landing-page/src/app/components/ui/checkbox.tsx +0 -32
  57. package/landing-page/src/app/components/ui/collapsible.tsx +0 -33
  58. package/landing-page/src/app/components/ui/command.tsx +0 -177
  59. package/landing-page/src/app/components/ui/context-menu.tsx +0 -252
  60. package/landing-page/src/app/components/ui/dialog.tsx +0 -135
  61. package/landing-page/src/app/components/ui/drawer.tsx +0 -132
  62. package/landing-page/src/app/components/ui/dropdown-menu.tsx +0 -257
  63. package/landing-page/src/app/components/ui/form.tsx +0 -168
  64. package/landing-page/src/app/components/ui/hover-card.tsx +0 -44
  65. package/landing-page/src/app/components/ui/input-otp.tsx +0 -77
  66. package/landing-page/src/app/components/ui/input.tsx +0 -21
  67. package/landing-page/src/app/components/ui/label.tsx +0 -24
  68. package/landing-page/src/app/components/ui/menubar.tsx +0 -276
  69. package/landing-page/src/app/components/ui/navigation-menu.tsx +0 -168
  70. package/landing-page/src/app/components/ui/pagination.tsx +0 -127
  71. package/landing-page/src/app/components/ui/popover.tsx +0 -48
  72. package/landing-page/src/app/components/ui/progress.tsx +0 -31
  73. package/landing-page/src/app/components/ui/radio-group.tsx +0 -45
  74. package/landing-page/src/app/components/ui/resizable.tsx +0 -56
  75. package/landing-page/src/app/components/ui/scroll-area.tsx +0 -58
  76. package/landing-page/src/app/components/ui/select.tsx +0 -189
  77. package/landing-page/src/app/components/ui/separator.tsx +0 -28
  78. package/landing-page/src/app/components/ui/sheet.tsx +0 -139
  79. package/landing-page/src/app/components/ui/sidebar.tsx +0 -726
  80. package/landing-page/src/app/components/ui/skeleton.tsx +0 -13
  81. package/landing-page/src/app/components/ui/slider.tsx +0 -63
  82. package/landing-page/src/app/components/ui/sonner.tsx +0 -25
  83. package/landing-page/src/app/components/ui/switch.tsx +0 -31
  84. package/landing-page/src/app/components/ui/table.tsx +0 -116
  85. package/landing-page/src/app/components/ui/tabs.tsx +0 -66
  86. package/landing-page/src/app/components/ui/textarea.tsx +0 -18
  87. package/landing-page/src/app/components/ui/toggle-group.tsx +0 -73
  88. package/landing-page/src/app/components/ui/toggle.tsx +0 -47
  89. package/landing-page/src/app/components/ui/tooltip.tsx +0 -61
  90. package/landing-page/src/app/components/ui/use-mobile.ts +0 -21
  91. package/landing-page/src/app/components/ui/utils.ts +0 -6
  92. package/landing-page/src/components/docs/DocsContent.tsx +0 -718
  93. package/landing-page/src/components/docs/DocsSidebar.tsx +0 -84
  94. package/landing-page/src/components/landing/CTA.tsx +0 -59
  95. package/landing-page/src/components/landing/Comparison.tsx +0 -84
  96. package/landing-page/src/components/landing/FaultyTerminal.tsx +0 -424
  97. package/landing-page/src/components/landing/Features.tsx +0 -201
  98. package/landing-page/src/components/landing/Hero.tsx +0 -142
  99. package/landing-page/src/components/landing/Pricing.tsx +0 -140
  100. package/landing-page/src/components/landing/Roadmap.tsx +0 -86
  101. package/landing-page/src/components/landing/Security.tsx +0 -81
  102. package/landing-page/src/components/landing/TerminalWindow.tsx +0 -27
  103. package/landing-page/src/components/landing/UseCases.tsx +0 -55
  104. package/landing-page/src/components/landing/Workflow.tsx +0 -101
  105. package/landing-page/src/components/layout/DashboardNavbar.tsx +0 -37
  106. package/landing-page/src/components/layout/Footer.tsx +0 -55
  107. package/landing-page/src/components/layout/LandingNavbar.tsx +0 -82
  108. package/landing-page/src/components/ui/badge.tsx +0 -39
  109. package/landing-page/src/components/ui/breadcrumb.tsx +0 -115
  110. package/landing-page/src/components/ui/button.tsx +0 -57
  111. package/landing-page/src/components/ui/card.tsx +0 -79
  112. package/landing-page/src/components/ui/mock-terminal.tsx +0 -68
  113. package/landing-page/src/components/ui/separator.tsx +0 -28
  114. package/landing-page/src/lib/utils.ts +0 -6
  115. package/landing-page/src/main.tsx +0 -10
  116. package/landing-page/src/pages/Dashboard.tsx +0 -133
  117. package/landing-page/src/pages/DocsPage.tsx +0 -79
  118. package/landing-page/src/pages/LandingPage.tsx +0 -31
  119. package/landing-page/src/pages/TerminalView.tsx +0 -106
  120. package/landing-page/src/styles/fonts.css +0 -0
  121. package/landing-page/src/styles/index.css +0 -3
  122. package/landing-page/src/styles/tailwind.css +0 -4
  123. package/landing-page/src/styles/theme.css +0 -181
  124. package/landing-page/vite.config.ts +0 -19
  125. package/npm/darwin-arm64/bin/gssh +0 -0
  126. package/npm/darwin-arm64/package.json +0 -20
  127. package/scripts/build.ts +0 -298
  128. package/scripts/release.ts +0 -140
  129. package/src/__tests__/test-utils.ts +0 -298
  130. package/src/commands/__tests__/serve-messages.test.ts +0 -190
  131. package/src/commands/access.ts +0 -298
  132. package/src/commands/add.ts +0 -452
  133. package/src/commands/auth.ts +0 -364
  134. package/src/commands/connect.ts +0 -287
  135. package/src/commands/directory.ts +0 -16
  136. package/src/commands/host.ts +0 -396
  137. package/src/commands/identity.ts +0 -184
  138. package/src/commands/list.ts +0 -200
  139. package/src/commands/relay.ts +0 -315
  140. package/src/commands/remove.ts +0 -241
  141. package/src/commands/serve.ts +0 -1493
  142. package/src/commands/share.ts +0 -456
  143. package/src/commands/status.ts +0 -125
  144. package/src/commands/switch.ts +0 -353
  145. package/src/commands/tmux.ts +0 -317
  146. package/src/core/__tests__/access.test.ts +0 -240
  147. package/src/core/access.ts +0 -277
  148. package/src/core/bundle.ts +0 -342
  149. package/src/core/config.ts +0 -510
  150. package/src/core/git.ts +0 -317
  151. package/src/core/github.ts +0 -151
  152. package/src/core/identity.ts +0 -631
  153. package/src/core/linear.ts +0 -225
  154. package/src/core/shell.ts +0 -161
  155. package/src/core/trusted-relays.ts +0 -315
  156. package/src/index.ts +0 -810
  157. package/src/lib/remote-session/index.ts +0 -7
  158. package/src/lib/remote-session/protocol.ts +0 -267
  159. package/src/lib/remote-session/session-handler.ts +0 -581
  160. package/src/lib/remote-session/workspace-scanner.ts +0 -167
  161. package/src/lib/tmux-lite/README.md +0 -81
  162. package/src/lib/tmux-lite/cli.ts +0 -796
  163. package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +0 -349
  164. package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +0 -291
  165. package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +0 -142
  166. package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +0 -339
  167. package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +0 -477
  168. package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +0 -499
  169. package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +0 -371
  170. package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +0 -573
  171. package/src/lib/tmux-lite/crypto/access-control.test.ts +0 -512
  172. package/src/lib/tmux-lite/crypto/access-control.ts +0 -320
  173. package/src/lib/tmux-lite/crypto/frames.test.ts +0 -262
  174. package/src/lib/tmux-lite/crypto/frames.ts +0 -141
  175. package/src/lib/tmux-lite/crypto/handshake.ts +0 -894
  176. package/src/lib/tmux-lite/crypto/identity.test.ts +0 -220
  177. package/src/lib/tmux-lite/crypto/identity.ts +0 -286
  178. package/src/lib/tmux-lite/crypto/index.ts +0 -51
  179. package/src/lib/tmux-lite/crypto/invites.test.ts +0 -381
  180. package/src/lib/tmux-lite/crypto/invites.ts +0 -215
  181. package/src/lib/tmux-lite/crypto/keyexchange.ts +0 -435
  182. package/src/lib/tmux-lite/crypto/keys.test.ts +0 -58
  183. package/src/lib/tmux-lite/crypto/keys.ts +0 -47
  184. package/src/lib/tmux-lite/crypto/secretbox.test.ts +0 -169
  185. package/src/lib/tmux-lite/crypto/secretbox.ts +0 -124
  186. package/src/lib/tmux-lite/handshake-handler.ts +0 -451
  187. package/src/lib/tmux-lite/protocol.test.ts +0 -307
  188. package/src/lib/tmux-lite/protocol.ts +0 -266
  189. package/src/lib/tmux-lite/relay-client.ts +0 -506
  190. package/src/lib/tmux-lite/server.ts +0 -1250
  191. package/src/lib/tmux-lite/shell-integration.sh +0 -37
  192. package/src/lib/tmux-lite/terminal-queries.test.ts +0 -54
  193. package/src/lib/tmux-lite/terminal-queries.ts +0 -49
  194. package/src/relay/__tests__/e2e-flow.test.ts +0 -1284
  195. package/src/relay/__tests__/helpers/auth.ts +0 -354
  196. package/src/relay/__tests__/helpers/ports.ts +0 -51
  197. package/src/relay/__tests__/protocol-validation.test.ts +0 -265
  198. package/src/relay/authorization.ts +0 -303
  199. package/src/relay/embedded-assets.generated.d.ts +0 -15
  200. package/src/relay/identity.ts +0 -352
  201. package/src/relay/index.ts +0 -57
  202. package/src/relay/pipes.test.ts +0 -427
  203. package/src/relay/pipes.ts +0 -195
  204. package/src/relay/protocol.ts +0 -804
  205. package/src/relay/registries.test.ts +0 -437
  206. package/src/relay/registries.ts +0 -593
  207. package/src/relay/server.test.ts +0 -1323
  208. package/src/relay/server.ts +0 -1092
  209. package/src/relay/signing.ts +0 -238
  210. package/src/relay/types.ts +0 -69
  211. package/src/serve/client-session-manager.ts +0 -622
  212. package/src/serve/daemon.ts +0 -497
  213. package/src/serve/pty-session.ts +0 -236
  214. package/src/serve/types.ts +0 -169
  215. package/src/shared/components/Flow.tsx +0 -453
  216. package/src/shared/components/Flow.tui.tsx +0 -343
  217. package/src/shared/components/Flow.web.tsx +0 -442
  218. package/src/shared/components/Inbox.tsx +0 -446
  219. package/src/shared/components/Inbox.tui.tsx +0 -262
  220. package/src/shared/components/Inbox.web.tsx +0 -329
  221. package/src/shared/components/MachineList.tsx +0 -187
  222. package/src/shared/components/MachineList.tui.tsx +0 -161
  223. package/src/shared/components/MachineList.web.tsx +0 -210
  224. package/src/shared/components/ProjectList.tsx +0 -176
  225. package/src/shared/components/ProjectList.tui.tsx +0 -109
  226. package/src/shared/components/ProjectList.web.tsx +0 -143
  227. package/src/shared/components/SpacesBrowser.tsx +0 -332
  228. package/src/shared/components/SpacesBrowser.tui.tsx +0 -163
  229. package/src/shared/components/SpacesBrowser.web.tsx +0 -221
  230. package/src/shared/components/index.ts +0 -103
  231. package/src/shared/hooks/index.ts +0 -16
  232. package/src/shared/hooks/useNavigation.ts +0 -226
  233. package/src/shared/index.ts +0 -122
  234. package/src/shared/providers/LocalMachineProvider.ts +0 -425
  235. package/src/shared/providers/MachineProvider.ts +0 -165
  236. package/src/shared/providers/RemoteMachineProvider.ts +0 -444
  237. package/src/shared/providers/index.ts +0 -26
  238. package/src/shared/types.ts +0 -145
  239. package/src/tui/adapters.ts +0 -120
  240. package/src/tui/app.tsx +0 -1816
  241. package/src/tui/components/Terminal.tsx +0 -580
  242. package/src/tui/hooks/index.ts +0 -35
  243. package/src/tui/hooks/useAppState.ts +0 -314
  244. package/src/tui/hooks/useDaemonStatus.ts +0 -174
  245. package/src/tui/hooks/useInboxTUI.ts +0 -113
  246. package/src/tui/hooks/useRemoteMachines.ts +0 -209
  247. package/src/tui/index.ts +0 -24
  248. package/src/tui/state.ts +0 -299
  249. package/src/tui/terminal-bracketed-paste.test.ts +0 -45
  250. package/src/tui/terminal-bracketed-paste.ts +0 -47
  251. package/src/types/bundle.ts +0 -112
  252. package/src/types/config.ts +0 -89
  253. package/src/types/errors.ts +0 -206
  254. package/src/types/identity.ts +0 -284
  255. package/src/types/workspace-fuzzy.ts +0 -49
  256. package/src/types/workspace.ts +0 -151
  257. package/src/utils/bun-socket-writer.ts +0 -80
  258. package/src/utils/deps.ts +0 -127
  259. package/src/utils/fuzzy-match.ts +0 -125
  260. package/src/utils/logger.ts +0 -127
  261. package/src/utils/markdown.ts +0 -254
  262. package/src/utils/onboarding.ts +0 -229
  263. package/src/utils/prompts.ts +0 -114
  264. package/src/utils/run-commands.ts +0 -112
  265. package/src/utils/run-scripts.ts +0 -142
  266. package/src/utils/sanitize.ts +0 -98
  267. package/src/utils/secrets.ts +0 -122
  268. package/src/utils/shell-escape.ts +0 -40
  269. package/src/utils/utf8.ts +0 -79
  270. package/src/utils/workspace-state.ts +0 -47
  271. package/src/web/README.md +0 -73
  272. package/src/web/bun.lock +0 -575
  273. package/src/web/eslint.config.js +0 -23
  274. package/src/web/index.html +0 -16
  275. package/src/web/package.json +0 -37
  276. package/src/web/public/vite.svg +0 -1
  277. package/src/web/src/App.tsx +0 -604
  278. package/src/web/src/assets/react.svg +0 -1
  279. package/src/web/src/components/Terminal.tsx +0 -207
  280. package/src/web/src/hooks/useRelayConnection.ts +0 -224
  281. package/src/web/src/hooks/useTerminal.ts +0 -699
  282. package/src/web/src/index.css +0 -55
  283. package/src/web/src/lib/crypto/__tests__/web-terminal.test.ts +0 -1158
  284. package/src/web/src/lib/crypto/frames.ts +0 -205
  285. package/src/web/src/lib/crypto/handshake.ts +0 -396
  286. package/src/web/src/lib/crypto/identity.ts +0 -128
  287. package/src/web/src/lib/crypto/keyexchange.ts +0 -246
  288. package/src/web/src/lib/crypto/relay-signing.ts +0 -53
  289. package/src/web/src/lib/invite.ts +0 -58
  290. package/src/web/src/lib/storage/identity-store.ts +0 -94
  291. package/src/web/src/main.tsx +0 -10
  292. package/src/web/src/types/identity.ts +0 -45
  293. package/src/web/tsconfig.app.json +0 -28
  294. package/src/web/tsconfig.json +0 -7
  295. package/src/web/tsconfig.node.json +0 -26
  296. package/src/web/vite.config.ts +0 -31
  297. package/todo-security.md +0 -92
  298. package/tsconfig.json +0 -23
  299. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite +0 -0
  300. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-shm +0 -0
  301. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-wal +0 -0
  302. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite +0 -0
  303. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-shm +0 -0
  304. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-wal +0 -0
  305. package/worker/bun.lock +0 -237
  306. package/worker/package.json +0 -22
  307. package/worker/schema.sql +0 -96
  308. package/worker/src/handlers/auth.ts +0 -451
  309. package/worker/src/handlers/subdomains.ts +0 -376
  310. package/worker/src/handlers/user.ts +0 -98
  311. package/worker/src/index.ts +0 -70
  312. package/worker/src/middleware/auth.ts +0 -152
  313. package/worker/src/services/cloudflare.ts +0 -609
  314. package/worker/src/types.ts +0 -96
  315. package/worker/tsconfig.json +0 -15
  316. package/worker/wrangler.toml +0 -26
@@ -1,510 +0,0 @@
1
- /**
2
- * Configuration management for global and project configs
3
- */
4
-
5
- import {
6
- existsSync,
7
- mkdirSync,
8
- readFileSync,
9
- writeFileSync,
10
- readdirSync,
11
- statSync,
12
- chmodSync,
13
- } from 'fs'
14
- import { join, dirname } from 'path'
15
- import { homedir } from 'os'
16
- import type { GlobalConfig, ProjectConfig } from '../types/config.js'
17
- import {
18
- DEFAULT_GLOBAL_CONFIG,
19
- createDefaultProjectConfig,
20
- } from '../types/config.js'
21
- import { SpacesError } from '../types/errors.js'
22
-
23
- /**
24
- * Get the global gitspace directory path
25
- */
26
- export function getGitspaceDir(): string {
27
- return join(homedir(), 'gitspace')
28
- }
29
-
30
- /**
31
- * @deprecated Use getGitspaceDir() instead
32
- */
33
- export function getSpacesDir(): string {
34
- return getGitspaceDir()
35
- }
36
-
37
- /**
38
- * Get the global config file path
39
- */
40
- export function getGlobalConfigPath(): string {
41
- return join(getSpacesDir(), '.config.json')
42
- }
43
-
44
- /**
45
- * Get a project directory path
46
- */
47
- export function getProjectDir(projectName: string): string {
48
- return join(getSpacesDir(), projectName)
49
- }
50
-
51
- /**
52
- * Get a project config file path
53
- */
54
- export function getProjectConfigPath(projectName: string): string {
55
- return join(getProjectDir(projectName), '.config.json')
56
- }
57
-
58
- /**
59
- * Get the base repository directory for a project
60
- */
61
- export function getProjectBaseDir(projectName: string): string {
62
- return join(getProjectDir(projectName), 'base')
63
- }
64
-
65
- /**
66
- * Get the workspaces directory for a project
67
- */
68
- export function getProjectWorkspacesDir(projectName: string): string {
69
- return join(getProjectDir(projectName), 'workspaces')
70
- }
71
-
72
- /**
73
- * Get the scripts directory for a project
74
- */
75
- export function getProjectScriptsDir(projectName: string): string {
76
- return join(getProjectDir(projectName), 'scripts')
77
- }
78
-
79
- /**
80
- * Get a specific scripts phase directory (pre, setup, select)
81
- */
82
- export function getScriptsPhaseDir(
83
- projectName: string,
84
- phase: 'pre' | 'setup' | 'select' | 'remove'
85
- ): string {
86
- return join(getProjectScriptsDir(projectName), phase)
87
- }
88
-
89
- /**
90
- * Initialize global config with defaults
91
- */
92
- function initializeGlobalConfig(): GlobalConfig {
93
- return {
94
- ...DEFAULT_GLOBAL_CONFIG,
95
- projectsDir: getSpacesDir(),
96
- }
97
- }
98
-
99
- /**
100
- * Read global configuration
101
- */
102
- export function readGlobalConfig(): GlobalConfig {
103
- const configPath = getGlobalConfigPath()
104
-
105
- if (!existsSync(configPath)) {
106
- // Return default config if file doesn't exist
107
- return initializeGlobalConfig()
108
- }
109
-
110
- try {
111
- const content = readFileSync(configPath, 'utf-8')
112
- const config = JSON.parse(content) as GlobalConfig
113
-
114
- // Merge with defaults to ensure all fields exist
115
- return {
116
- ...initializeGlobalConfig(),
117
- ...config,
118
- }
119
- } catch (error) {
120
- throw new SpacesError(
121
- `Failed to read global config: ${
122
- error instanceof Error ? error.message : 'Unknown error'
123
- }`,
124
- 'SYSTEM_ERROR',
125
- 2
126
- )
127
- }
128
- }
129
-
130
- /**
131
- * Write global configuration
132
- */
133
- export function writeGlobalConfig(config: GlobalConfig): void {
134
- const configPath = getGlobalConfigPath()
135
- const spacesDir = dirname(configPath)
136
-
137
- // Ensure spaces directory exists
138
- if (!existsSync(spacesDir)) {
139
- mkdirSync(spacesDir, { recursive: true })
140
- }
141
-
142
- try {
143
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8')
144
- chmodSync(configPath, 0o600)
145
- } catch (error) {
146
- throw new SpacesError(
147
- `Failed to write global config: ${
148
- error instanceof Error ? error.message : 'Unknown error'
149
- }`,
150
- 'SYSTEM_ERROR',
151
- 2
152
- )
153
- }
154
- }
155
-
156
- /**
157
- * Update global configuration
158
- */
159
- export function updateGlobalConfig(
160
- updates: Partial<GlobalConfig>
161
- ): GlobalConfig {
162
- const config = readGlobalConfig()
163
- const updated = { ...config, ...updates }
164
- writeGlobalConfig(updated)
165
- return updated
166
- }
167
-
168
- /**
169
- * Read project configuration
170
- */
171
- export function readProjectConfig(projectName: string): ProjectConfig {
172
- const configPath = getProjectConfigPath(projectName)
173
-
174
- if (!existsSync(configPath)) {
175
- throw new SpacesError(`Project "${projectName}" not found`, 'USER_ERROR', 1)
176
- }
177
-
178
- try {
179
- const content = readFileSync(configPath, 'utf-8')
180
- return JSON.parse(content) as ProjectConfig
181
- } catch (error) {
182
- throw new SpacesError(
183
- `Failed to read project config for "${projectName}": ${
184
- error instanceof Error ? error.message : 'Unknown error'
185
- }`,
186
- 'SYSTEM_ERROR',
187
- 2
188
- )
189
- }
190
- }
191
-
192
- /**
193
- * Write project configuration
194
- */
195
- export function writeProjectConfig(
196
- projectName: string,
197
- config: ProjectConfig
198
- ): void {
199
- const configPath = getProjectConfigPath(projectName)
200
- const projectDir = dirname(configPath)
201
-
202
- // Ensure project directory exists
203
- if (!existsSync(projectDir)) {
204
- mkdirSync(projectDir, { recursive: true })
205
- }
206
-
207
- try {
208
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8')
209
- chmodSync(configPath, 0o600)
210
- } catch (error) {
211
- throw new SpacesError(
212
- `Failed to write project config for "${projectName}": ${
213
- error instanceof Error ? error.message : 'Unknown error'
214
- }`,
215
- 'SYSTEM_ERROR',
216
- 2
217
- )
218
- }
219
- }
220
-
221
- /**
222
- * Update project configuration
223
- */
224
- export function updateProjectConfig(
225
- projectName: string,
226
- updates: Partial<ProjectConfig>
227
- ): ProjectConfig {
228
- const config = readProjectConfig(projectName)
229
- const updated = { ...config, ...updates }
230
- writeProjectConfig(projectName, updated)
231
- return updated
232
- }
233
-
234
- /**
235
- * Get current project name from env var or global config
236
- * Resolution order:
237
- * 1. SPACES_CURRENT_PROJECT environment variable
238
- * 2. currentProject field in global config
239
- * 3. null if neither is set
240
- */
241
- export function getCurrentProject(): string | null {
242
- // Check environment variable first
243
- const envProject = process.env.SPACES_CURRENT_PROJECT
244
- if (envProject) {
245
- return envProject
246
- }
247
-
248
- // Fall back to global config
249
- const globalConfig = readGlobalConfig()
250
- return globalConfig.currentProject
251
- }
252
-
253
- /**
254
- * Set current project in global config
255
- */
256
- export function setCurrentProject(projectName: string): void {
257
- updateGlobalConfig({ currentProject: projectName })
258
- }
259
-
260
- /**
261
- * Check if the global config exists (first-time setup check)
262
- */
263
- export function isFirstTimeSetup(): boolean {
264
- return !existsSync(getGlobalConfigPath())
265
- }
266
-
267
- /**
268
- * Initialize spaces directory and config for first-time setup
269
- */
270
- export function initializeSpaces(): void {
271
- const spacesDir = getSpacesDir()
272
-
273
- // Create spaces directory if it doesn't exist
274
- if (!existsSync(spacesDir)) {
275
- mkdirSync(spacesDir, { recursive: true })
276
- }
277
-
278
- // Create global config if it doesn't exist
279
- if (!existsSync(getGlobalConfigPath())) {
280
- writeGlobalConfig(initializeGlobalConfig())
281
- }
282
- }
283
-
284
- /**
285
- * Get all project names
286
- */
287
- export function getAllProjectNames(): string[] {
288
- const spacesDir = getSpacesDir()
289
-
290
- if (!existsSync(spacesDir)) {
291
- return []
292
- }
293
-
294
- try {
295
- const entries = readdirSync(spacesDir) as string[]
296
-
297
- // Filter to only directories that have a .config.json file
298
- return entries.filter((entry: string) => {
299
- const projectDir = join(spacesDir, entry)
300
- const configPath = join(projectDir, '.config.json')
301
- return (
302
- statSync(projectDir).isDirectory() &&
303
- existsSync(configPath) &&
304
- entry !== 'app' // Exclude the app directory
305
- )
306
- })
307
- } catch (error) {
308
- throw new SpacesError(
309
- `Failed to list projects: ${
310
- error instanceof Error ? error.message : 'Unknown error'
311
- }`,
312
- 'SYSTEM_ERROR',
313
- 2
314
- )
315
- }
316
- }
317
-
318
- /**
319
- * Check if a project exists
320
- */
321
- export function projectExists(projectName: string): boolean {
322
- const configPath = getProjectConfigPath(projectName)
323
- return existsSync(configPath)
324
- }
325
-
326
- /**
327
- * Create a new project configuration
328
- */
329
- export function createProject(
330
- projectName: string,
331
- repository: string,
332
- baseBranch: string,
333
- linearApiKey?: string,
334
- linearTeamKey?: string
335
- ): ProjectConfig {
336
- const config = createDefaultProjectConfig(
337
- projectName,
338
- repository,
339
- baseBranch,
340
- linearApiKey,
341
- linearTeamKey
342
- )
343
-
344
- // Create project directories
345
- const projectDir = getProjectDir(projectName)
346
- const baseDir = getProjectBaseDir(projectName)
347
- const workspacesDir = getProjectWorkspacesDir(projectName)
348
-
349
- mkdirSync(projectDir, { recursive: true })
350
- mkdirSync(baseDir, { recursive: true })
351
- mkdirSync(workspacesDir, { recursive: true })
352
-
353
- // Create scripts directories
354
- mkdirSync(getScriptsPhaseDir(projectName, 'pre'), { recursive: true })
355
- mkdirSync(getScriptsPhaseDir(projectName, 'setup'), { recursive: true })
356
- mkdirSync(getScriptsPhaseDir(projectName, 'select'), { recursive: true })
357
- mkdirSync(getScriptsPhaseDir(projectName, 'remove'), { recursive: true })
358
-
359
- // Create example template scripts in each phase directory
360
- const preExampleScript = `#!/bin/bash
361
- # Pre-phase script - runs BEFORE workspace shell opens
362
- #
363
- # Current working directory: ~/gitspace/<project>/workspaces/<workspace>/
364
- # (Scripts run from the workspace directory, so you can use relative paths)
365
- #
366
- # This script runs in your terminal immediately after the worktree is created.
367
- # Perfect for preparation tasks like:
368
- # - Copying environment files (cp .env.example .env)
369
- # - Creating directories (mkdir -p tmp/uploads)
370
- # - Any setup that other scripts might need
371
- #
372
- # Arguments:
373
- # $1 - Workspace name (e.g., "my-feature")
374
- # $2 - Repository name (e.g., "myorg/my-app")
375
- #
376
- # To use this script:
377
- # 1. Rename it (e.g., 01-copy-env.sh)
378
- # 2. Add your commands
379
- # 3. Make it executable: chmod +x scripts/pre/01-copy-env.sh
380
-
381
- WORKSPACE_NAME=$1
382
- REPOSITORY=$2
383
-
384
- echo "Running Spaces pre-install on: $WORKSPACE_NAME from $REPOSITORY"
385
- `
386
-
387
- const setupExampleScript = `#!/bin/bash
388
- # Setup-phase script - runs ONCE when workspace is first created
389
- #
390
- # Current working directory: ~/gitspace/<project>/workspaces/<workspace>/
391
- # (Scripts run from the workspace directory, so you can use relative paths)
392
- #
393
- # This script runs the first time a workspace is created.
394
- # Perfect for one-time setup tasks like:
395
- # - Installing dependencies (npm install, bundle install)
396
- # - Initial builds (npm run build)
397
- # - Database setup
398
- # - Any expensive setup that should only run once
399
- #
400
- # After all setup scripts run, GitSpace creates a gitspace.lock marker file
401
- # to prevent them from running again.
402
- #
403
- # Arguments:
404
- # $1 - Workspace name (e.g., "my-feature")
405
- # $2 - Repository name (e.g., "myorg/my-app")
406
- #
407
- # To use this script:
408
- # 1. Rename it (e.g., 01-install.sh)
409
- # 2. Add your commands
410
- # 3. Make it executable: chmod +x scripts/setup/01-install.sh
411
-
412
- WORKSPACE_NAME=$1
413
- REPOSITORY=$2
414
-
415
- echo "Setting up Spaces workspace on: $WORKSPACE_NAME from $REPOSITORY"
416
- `
417
-
418
- const selectExampleScript = `#!/bin/bash
419
- # Select-phase script - runs EVERY TIME you switch to a workspace
420
- #
421
- # Current working directory: ~/gitspace/<project>/workspaces/<workspace>/
422
- # (Scripts run from the workspace directory, so you can use relative paths)
423
- #
424
- # This script runs every time you switch to an existing workspace
425
- # (where setup already completed).
426
- # Perfect for quick status updates like:
427
- # - Fetching latest changes (git fetch --all)
428
- # - Checking workspace state (git status)
429
- # - Environment checks
430
- # - Quick status updates
431
- #
432
- # Arguments:
433
- # $1 - Workspace name (e.g., "my-feature")
434
- # $2 - Repository name (e.g., "myorg/my-app")
435
- #
436
- # To use this script:
437
- # 1. Rename it (e.g., 01-fetch.sh)
438
- # 2. Add your commands
439
- # 3. Make it executable: chmod +x scripts/select/01-fetch.sh
440
-
441
- WORKSPACE_NAME=$1
442
- REPOSITORY=$2
443
-
444
- echo "Running Spaces script on: $WORKSPACE_NAME from $REPOSITORY"
445
- `
446
-
447
- const removeExampleScript = `#!/bin/bash
448
- # Remove-phase script - runs when workspace is REMOVED
449
- #
450
- # Current working directory: ~/gitspace/<project>/workspaces/<workspace>/
451
- # (Scripts run from the workspace directory, so you can use relative paths)
452
- #
453
- # This script runs in your terminal when you remove a workspace,
454
- # BEFORE the worktree is deleted. Perfect for cleanup tasks like:
455
- # - Tearing down test databases
456
- # - Removing cloud resources (S3 buckets, EC2 instances)
457
- # - Cleaning up external services
458
- # - Removing temporary Docker containers/volumes
459
- # - Cleaning up API keys or tokens
460
- #
461
- # Arguments:
462
- # $1 - Workspace name (e.g., "my-feature")
463
- # $2 - Repository name (e.g., "myorg/my-app")
464
- #
465
- # To use this script:
466
- # 1. Rename it (e.g., 01-cleanup-db.sh)
467
- # 2. Add your commands
468
- # 3. Make it executable: chmod +x scripts/remove/01-cleanup-db.sh
469
-
470
- WORKSPACE_NAME=$1
471
- REPOSITORY=$2
472
-
473
- echo "Running Spaces cleanup on: $WORKSPACE_NAME from $REPOSITORY"
474
- `
475
-
476
- // Write and make executable
477
- const preExamplePath = join(
478
- getScriptsPhaseDir(projectName, 'pre'),
479
- '00-example.sh'
480
- )
481
- const setupExamplePath = join(
482
- getScriptsPhaseDir(projectName, 'setup'),
483
- '00-example.sh'
484
- )
485
- const selectExamplePath = join(
486
- getScriptsPhaseDir(projectName, 'select'),
487
- '00-example.sh'
488
- )
489
- const removeExamplePath = join(
490
- getScriptsPhaseDir(projectName, 'remove'),
491
- '00-example.sh'
492
- )
493
-
494
- writeFileSync(preExamplePath, preExampleScript, 'utf-8')
495
- chmodSync(preExamplePath, 0o755)
496
-
497
- writeFileSync(setupExamplePath, setupExampleScript, 'utf-8')
498
- chmodSync(setupExamplePath, 0o755)
499
-
500
- writeFileSync(selectExamplePath, selectExampleScript, 'utf-8')
501
- chmodSync(selectExamplePath, 0o755)
502
-
503
- writeFileSync(removeExamplePath, removeExampleScript, 'utf-8')
504
- chmodSync(removeExamplePath, 0o755)
505
-
506
- // Write project config
507
- writeProjectConfig(projectName, config)
508
-
509
- return config
510
- }