gitspace 0.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/.claude/settings.local.json +21 -0
  2. package/.gitspace/bundle.json +50 -0
  3. package/.gitspace/select/01-status.sh +40 -0
  4. package/.gitspace/setup/01-install-deps.sh +12 -0
  5. package/.gitspace/setup/02-typecheck.sh +16 -0
  6. package/AGENTS.md +439 -0
  7. package/CLAUDE.md +1 -0
  8. package/LICENSE +25 -0
  9. package/README.md +607 -0
  10. package/bin/gssh +62 -0
  11. package/bun.lock +647 -0
  12. package/docs/CONNECTION.md +623 -0
  13. package/docs/GATEWAY-WORKER.md +319 -0
  14. package/docs/GETTING-STARTED.md +448 -0
  15. package/docs/GITSPACE-PLATFORM.md +1819 -0
  16. package/docs/INFRASTRUCTURE.md +1347 -0
  17. package/docs/PROTOCOL.md +619 -0
  18. package/docs/QUICKSTART.md +174 -0
  19. package/docs/RELAY.md +327 -0
  20. package/docs/REMOTE-DESIGN.md +549 -0
  21. package/docs/ROADMAP.md +564 -0
  22. package/docs/SITE_DOCS_FIGMA_MAKE.md +1167 -0
  23. package/docs/STACK-DESIGN.md +588 -0
  24. package/docs/UNIFIED_ARCHITECTURE.md +292 -0
  25. package/experiments/pty-benchmark.ts +148 -0
  26. package/experiments/pty-latency.ts +100 -0
  27. package/experiments/router/client.ts +199 -0
  28. package/experiments/router/protocol.ts +74 -0
  29. package/experiments/router/router.ts +217 -0
  30. package/experiments/router/session.ts +180 -0
  31. package/experiments/router/test.ts +133 -0
  32. package/experiments/socket-bandwidth.ts +77 -0
  33. package/homebrew/gitspace.rb +45 -0
  34. package/landing-page/ATTRIBUTIONS.md +3 -0
  35. package/landing-page/README.md +11 -0
  36. package/landing-page/bun.lock +801 -0
  37. package/landing-page/guidelines/Guidelines.md +61 -0
  38. package/landing-page/index.html +37 -0
  39. package/landing-page/package.json +90 -0
  40. package/landing-page/postcss.config.mjs +15 -0
  41. package/landing-page/public/_redirects +1 -0
  42. package/landing-page/public/favicon.png +0 -0
  43. package/landing-page/src/app/App.tsx +53 -0
  44. package/landing-page/src/app/components/figma/ImageWithFallback.tsx +27 -0
  45. package/landing-page/src/app/components/ui/accordion.tsx +66 -0
  46. package/landing-page/src/app/components/ui/alert-dialog.tsx +157 -0
  47. package/landing-page/src/app/components/ui/alert.tsx +66 -0
  48. package/landing-page/src/app/components/ui/aspect-ratio.tsx +11 -0
  49. package/landing-page/src/app/components/ui/avatar.tsx +53 -0
  50. package/landing-page/src/app/components/ui/badge.tsx +46 -0
  51. package/landing-page/src/app/components/ui/breadcrumb.tsx +109 -0
  52. package/landing-page/src/app/components/ui/button.tsx +57 -0
  53. package/landing-page/src/app/components/ui/calendar.tsx +75 -0
  54. package/landing-page/src/app/components/ui/card.tsx +92 -0
  55. package/landing-page/src/app/components/ui/carousel.tsx +241 -0
  56. package/landing-page/src/app/components/ui/chart.tsx +353 -0
  57. package/landing-page/src/app/components/ui/checkbox.tsx +32 -0
  58. package/landing-page/src/app/components/ui/collapsible.tsx +33 -0
  59. package/landing-page/src/app/components/ui/command.tsx +177 -0
  60. package/landing-page/src/app/components/ui/context-menu.tsx +252 -0
  61. package/landing-page/src/app/components/ui/dialog.tsx +135 -0
  62. package/landing-page/src/app/components/ui/drawer.tsx +132 -0
  63. package/landing-page/src/app/components/ui/dropdown-menu.tsx +257 -0
  64. package/landing-page/src/app/components/ui/form.tsx +168 -0
  65. package/landing-page/src/app/components/ui/hover-card.tsx +44 -0
  66. package/landing-page/src/app/components/ui/input-otp.tsx +77 -0
  67. package/landing-page/src/app/components/ui/input.tsx +21 -0
  68. package/landing-page/src/app/components/ui/label.tsx +24 -0
  69. package/landing-page/src/app/components/ui/menubar.tsx +276 -0
  70. package/landing-page/src/app/components/ui/navigation-menu.tsx +168 -0
  71. package/landing-page/src/app/components/ui/pagination.tsx +127 -0
  72. package/landing-page/src/app/components/ui/popover.tsx +48 -0
  73. package/landing-page/src/app/components/ui/progress.tsx +31 -0
  74. package/landing-page/src/app/components/ui/radio-group.tsx +45 -0
  75. package/landing-page/src/app/components/ui/resizable.tsx +56 -0
  76. package/landing-page/src/app/components/ui/scroll-area.tsx +58 -0
  77. package/landing-page/src/app/components/ui/select.tsx +189 -0
  78. package/landing-page/src/app/components/ui/separator.tsx +28 -0
  79. package/landing-page/src/app/components/ui/sheet.tsx +139 -0
  80. package/landing-page/src/app/components/ui/sidebar.tsx +726 -0
  81. package/landing-page/src/app/components/ui/skeleton.tsx +13 -0
  82. package/landing-page/src/app/components/ui/slider.tsx +63 -0
  83. package/landing-page/src/app/components/ui/sonner.tsx +25 -0
  84. package/landing-page/src/app/components/ui/switch.tsx +31 -0
  85. package/landing-page/src/app/components/ui/table.tsx +116 -0
  86. package/landing-page/src/app/components/ui/tabs.tsx +66 -0
  87. package/landing-page/src/app/components/ui/textarea.tsx +18 -0
  88. package/landing-page/src/app/components/ui/toggle-group.tsx +73 -0
  89. package/landing-page/src/app/components/ui/toggle.tsx +47 -0
  90. package/landing-page/src/app/components/ui/tooltip.tsx +61 -0
  91. package/landing-page/src/app/components/ui/use-mobile.ts +21 -0
  92. package/landing-page/src/app/components/ui/utils.ts +6 -0
  93. package/landing-page/src/components/docs/DocsContent.tsx +718 -0
  94. package/landing-page/src/components/docs/DocsSidebar.tsx +84 -0
  95. package/landing-page/src/components/landing/CTA.tsx +59 -0
  96. package/landing-page/src/components/landing/Comparison.tsx +84 -0
  97. package/landing-page/src/components/landing/FaultyTerminal.tsx +424 -0
  98. package/landing-page/src/components/landing/Features.tsx +201 -0
  99. package/landing-page/src/components/landing/Hero.tsx +142 -0
  100. package/landing-page/src/components/landing/Pricing.tsx +140 -0
  101. package/landing-page/src/components/landing/Roadmap.tsx +86 -0
  102. package/landing-page/src/components/landing/Security.tsx +81 -0
  103. package/landing-page/src/components/landing/TerminalWindow.tsx +27 -0
  104. package/landing-page/src/components/landing/UseCases.tsx +55 -0
  105. package/landing-page/src/components/landing/Workflow.tsx +101 -0
  106. package/landing-page/src/components/layout/DashboardNavbar.tsx +37 -0
  107. package/landing-page/src/components/layout/Footer.tsx +55 -0
  108. package/landing-page/src/components/layout/LandingNavbar.tsx +82 -0
  109. package/landing-page/src/components/ui/badge.tsx +39 -0
  110. package/landing-page/src/components/ui/breadcrumb.tsx +115 -0
  111. package/landing-page/src/components/ui/button.tsx +57 -0
  112. package/landing-page/src/components/ui/card.tsx +79 -0
  113. package/landing-page/src/components/ui/mock-terminal.tsx +68 -0
  114. package/landing-page/src/components/ui/separator.tsx +28 -0
  115. package/landing-page/src/lib/utils.ts +6 -0
  116. package/landing-page/src/main.tsx +10 -0
  117. package/landing-page/src/pages/Dashboard.tsx +133 -0
  118. package/landing-page/src/pages/DocsPage.tsx +79 -0
  119. package/landing-page/src/pages/LandingPage.tsx +31 -0
  120. package/landing-page/src/pages/TerminalView.tsx +106 -0
  121. package/landing-page/src/styles/fonts.css +0 -0
  122. package/landing-page/src/styles/index.css +3 -0
  123. package/landing-page/src/styles/tailwind.css +4 -0
  124. package/landing-page/src/styles/theme.css +181 -0
  125. package/landing-page/vite.config.ts +19 -0
  126. package/npm/darwin-arm64/bin/gssh +0 -0
  127. package/npm/darwin-arm64/package.json +20 -0
  128. package/package.json +74 -0
  129. package/scripts/build.ts +284 -0
  130. package/scripts/release.ts +140 -0
  131. package/src/__tests__/test-utils.ts +298 -0
  132. package/src/commands/__tests__/serve-messages.test.ts +190 -0
  133. package/src/commands/access.ts +298 -0
  134. package/src/commands/add.ts +452 -0
  135. package/src/commands/auth.ts +364 -0
  136. package/src/commands/connect.ts +287 -0
  137. package/src/commands/directory.ts +16 -0
  138. package/src/commands/host.ts +396 -0
  139. package/src/commands/identity.ts +184 -0
  140. package/src/commands/list.ts +200 -0
  141. package/src/commands/relay.ts +315 -0
  142. package/src/commands/remove.ts +241 -0
  143. package/src/commands/serve.ts +1493 -0
  144. package/src/commands/share.ts +456 -0
  145. package/src/commands/status.ts +125 -0
  146. package/src/commands/switch.ts +353 -0
  147. package/src/commands/tmux.ts +317 -0
  148. package/src/core/__tests__/access.test.ts +240 -0
  149. package/src/core/access.ts +277 -0
  150. package/src/core/bundle.ts +342 -0
  151. package/src/core/config.ts +510 -0
  152. package/src/core/git.ts +317 -0
  153. package/src/core/github.ts +151 -0
  154. package/src/core/identity.ts +631 -0
  155. package/src/core/linear.ts +225 -0
  156. package/src/core/shell.ts +161 -0
  157. package/src/core/trusted-relays.ts +315 -0
  158. package/src/index.ts +821 -0
  159. package/src/lib/remote-session/index.ts +7 -0
  160. package/src/lib/remote-session/protocol.ts +267 -0
  161. package/src/lib/remote-session/session-handler.ts +581 -0
  162. package/src/lib/remote-session/workspace-scanner.ts +167 -0
  163. package/src/lib/tmux-lite/README.md +81 -0
  164. package/src/lib/tmux-lite/cli.ts +796 -0
  165. package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +349 -0
  166. package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +291 -0
  167. package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +142 -0
  168. package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +339 -0
  169. package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +477 -0
  170. package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +499 -0
  171. package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +371 -0
  172. package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +573 -0
  173. package/src/lib/tmux-lite/crypto/access-control.test.ts +512 -0
  174. package/src/lib/tmux-lite/crypto/access-control.ts +320 -0
  175. package/src/lib/tmux-lite/crypto/frames.test.ts +262 -0
  176. package/src/lib/tmux-lite/crypto/frames.ts +141 -0
  177. package/src/lib/tmux-lite/crypto/handshake.ts +894 -0
  178. package/src/lib/tmux-lite/crypto/identity.test.ts +220 -0
  179. package/src/lib/tmux-lite/crypto/identity.ts +286 -0
  180. package/src/lib/tmux-lite/crypto/index.ts +51 -0
  181. package/src/lib/tmux-lite/crypto/invites.test.ts +381 -0
  182. package/src/lib/tmux-lite/crypto/invites.ts +215 -0
  183. package/src/lib/tmux-lite/crypto/keyexchange.ts +435 -0
  184. package/src/lib/tmux-lite/crypto/keys.test.ts +58 -0
  185. package/src/lib/tmux-lite/crypto/keys.ts +47 -0
  186. package/src/lib/tmux-lite/crypto/secretbox.test.ts +169 -0
  187. package/src/lib/tmux-lite/crypto/secretbox.ts +124 -0
  188. package/src/lib/tmux-lite/handshake-handler.ts +451 -0
  189. package/src/lib/tmux-lite/protocol.test.ts +307 -0
  190. package/src/lib/tmux-lite/protocol.ts +266 -0
  191. package/src/lib/tmux-lite/relay-client.ts +506 -0
  192. package/src/lib/tmux-lite/server.ts +1250 -0
  193. package/src/lib/tmux-lite/shell-integration.sh +37 -0
  194. package/src/lib/tmux-lite/terminal-queries.test.ts +54 -0
  195. package/src/lib/tmux-lite/terminal-queries.ts +49 -0
  196. package/src/relay/__tests__/e2e-flow.test.ts +1284 -0
  197. package/src/relay/__tests__/helpers/auth.ts +354 -0
  198. package/src/relay/__tests__/helpers/ports.ts +51 -0
  199. package/src/relay/__tests__/protocol-validation.test.ts +265 -0
  200. package/src/relay/authorization.ts +303 -0
  201. package/src/relay/embedded-assets.generated.d.ts +15 -0
  202. package/src/relay/identity.ts +352 -0
  203. package/src/relay/index.ts +57 -0
  204. package/src/relay/pipes.test.ts +427 -0
  205. package/src/relay/pipes.ts +195 -0
  206. package/src/relay/protocol.ts +804 -0
  207. package/src/relay/registries.test.ts +437 -0
  208. package/src/relay/registries.ts +593 -0
  209. package/src/relay/server.test.ts +1323 -0
  210. package/src/relay/server.ts +1092 -0
  211. package/src/relay/signing.ts +238 -0
  212. package/src/relay/types.ts +69 -0
  213. package/src/serve/client-session-manager.ts +622 -0
  214. package/src/serve/daemon.ts +497 -0
  215. package/src/serve/pty-session.ts +236 -0
  216. package/src/serve/types.ts +169 -0
  217. package/src/shared/components/Flow.tsx +453 -0
  218. package/src/shared/components/Flow.tui.tsx +343 -0
  219. package/src/shared/components/Flow.web.tsx +442 -0
  220. package/src/shared/components/Inbox.tsx +446 -0
  221. package/src/shared/components/Inbox.tui.tsx +262 -0
  222. package/src/shared/components/Inbox.web.tsx +329 -0
  223. package/src/shared/components/MachineList.tsx +187 -0
  224. package/src/shared/components/MachineList.tui.tsx +161 -0
  225. package/src/shared/components/MachineList.web.tsx +210 -0
  226. package/src/shared/components/ProjectList.tsx +176 -0
  227. package/src/shared/components/ProjectList.tui.tsx +109 -0
  228. package/src/shared/components/ProjectList.web.tsx +143 -0
  229. package/src/shared/components/SpacesBrowser.tsx +332 -0
  230. package/src/shared/components/SpacesBrowser.tui.tsx +163 -0
  231. package/src/shared/components/SpacesBrowser.web.tsx +221 -0
  232. package/src/shared/components/index.ts +103 -0
  233. package/src/shared/hooks/index.ts +16 -0
  234. package/src/shared/hooks/useNavigation.ts +226 -0
  235. package/src/shared/index.ts +122 -0
  236. package/src/shared/providers/LocalMachineProvider.ts +425 -0
  237. package/src/shared/providers/MachineProvider.ts +165 -0
  238. package/src/shared/providers/RemoteMachineProvider.ts +444 -0
  239. package/src/shared/providers/index.ts +26 -0
  240. package/src/shared/types.ts +145 -0
  241. package/src/tui/adapters.ts +120 -0
  242. package/src/tui/app.tsx +1816 -0
  243. package/src/tui/components/Terminal.tsx +580 -0
  244. package/src/tui/hooks/index.ts +35 -0
  245. package/src/tui/hooks/useAppState.ts +314 -0
  246. package/src/tui/hooks/useDaemonStatus.ts +174 -0
  247. package/src/tui/hooks/useInboxTUI.ts +113 -0
  248. package/src/tui/hooks/useRemoteMachines.ts +209 -0
  249. package/src/tui/index.ts +24 -0
  250. package/src/tui/state.ts +299 -0
  251. package/src/tui/terminal-bracketed-paste.test.ts +45 -0
  252. package/src/tui/terminal-bracketed-paste.ts +47 -0
  253. package/src/types/bundle.ts +112 -0
  254. package/src/types/config.ts +89 -0
  255. package/src/types/errors.ts +206 -0
  256. package/src/types/identity.ts +284 -0
  257. package/src/types/workspace-fuzzy.ts +49 -0
  258. package/src/types/workspace.ts +151 -0
  259. package/src/utils/bun-socket-writer.ts +80 -0
  260. package/src/utils/deps.ts +127 -0
  261. package/src/utils/fuzzy-match.ts +125 -0
  262. package/src/utils/logger.ts +127 -0
  263. package/src/utils/markdown.ts +254 -0
  264. package/src/utils/onboarding.ts +229 -0
  265. package/src/utils/prompts.ts +114 -0
  266. package/src/utils/run-commands.ts +112 -0
  267. package/src/utils/run-scripts.ts +142 -0
  268. package/src/utils/sanitize.ts +98 -0
  269. package/src/utils/secrets.ts +122 -0
  270. package/src/utils/shell-escape.ts +40 -0
  271. package/src/utils/utf8.ts +79 -0
  272. package/src/utils/workspace-state.ts +47 -0
  273. package/src/web/README.md +73 -0
  274. package/src/web/bun.lock +575 -0
  275. package/src/web/eslint.config.js +23 -0
  276. package/src/web/index.html +16 -0
  277. package/src/web/package.json +37 -0
  278. package/src/web/public/vite.svg +1 -0
  279. package/src/web/src/App.tsx +604 -0
  280. package/src/web/src/assets/react.svg +1 -0
  281. package/src/web/src/components/Terminal.tsx +207 -0
  282. package/src/web/src/hooks/useRelayConnection.ts +224 -0
  283. package/src/web/src/hooks/useTerminal.ts +699 -0
  284. package/src/web/src/index.css +55 -0
  285. package/src/web/src/lib/crypto/__tests__/web-terminal.test.ts +1158 -0
  286. package/src/web/src/lib/crypto/frames.ts +205 -0
  287. package/src/web/src/lib/crypto/handshake.ts +396 -0
  288. package/src/web/src/lib/crypto/identity.ts +128 -0
  289. package/src/web/src/lib/crypto/keyexchange.ts +246 -0
  290. package/src/web/src/lib/crypto/relay-signing.ts +53 -0
  291. package/src/web/src/lib/invite.ts +58 -0
  292. package/src/web/src/lib/storage/identity-store.ts +94 -0
  293. package/src/web/src/main.tsx +10 -0
  294. package/src/web/src/types/identity.ts +45 -0
  295. package/src/web/tsconfig.app.json +28 -0
  296. package/src/web/tsconfig.json +7 -0
  297. package/src/web/tsconfig.node.json +26 -0
  298. package/src/web/vite.config.ts +31 -0
  299. package/todo-security.md +92 -0
  300. package/tsconfig.json +23 -0
  301. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite +0 -0
  302. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-shm +0 -0
  303. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-wal +0 -0
  304. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite +0 -0
  305. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-shm +0 -0
  306. package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-wal +0 -0
  307. package/worker/bun.lock +237 -0
  308. package/worker/package.json +22 -0
  309. package/worker/schema.sql +96 -0
  310. package/worker/src/handlers/auth.ts +451 -0
  311. package/worker/src/handlers/subdomains.ts +376 -0
  312. package/worker/src/handlers/user.ts +98 -0
  313. package/worker/src/index.ts +70 -0
  314. package/worker/src/middleware/auth.ts +152 -0
  315. package/worker/src/services/cloudflare.ts +609 -0
  316. package/worker/src/types.ts +96 -0
  317. package/worker/tsconfig.json +15 -0
  318. package/worker/wrangler.toml +26 -0
@@ -0,0 +1,588 @@
1
+ # Stacked PR Feature - Architecture Design
2
+
3
+ > **⚠️ FUTURE FEATURE DOCUMENT**
4
+ >
5
+ > This document describes a **planned feature** that is **not yet implemented**.
6
+ > The `gssh stack` command does not currently exist. This is a design document for future development.
7
+
8
+ ---
9
+
10
+ > AI-assisted splitting of work-in-progress commits into clean, logical PRs
11
+
12
+ ## Overview
13
+
14
+ The `gssh stack` command helps developers split messy WIP commits into clean, reviewable PRs using AI-assisted code analysis in a sandboxed environment.
15
+
16
+ ## Core Concept
17
+
18
+ ```
19
+ User's messy branch:
20
+ main ── wip1 ── wip2 ── debug ── wip3 ── fixup ── wip4 ── more...
21
+ └──────────── logical unit A ───────────┘ └── continued ──
22
+
23
+ After `gssh stack`:
24
+ main ── "Add auth" ── "Add tests" ──┬── (PR #1 created)
25
+
26
+ └── user's work rebased on top
27
+ ```
28
+
29
+ **Key insight**: Instead of building a fixed algorithm, we give the AI tools (AST analysis, git operations) in a sandbox and let it explore different ways to split the code.
30
+
31
+ ## Architecture
32
+
33
+ ### High-Level Components
34
+
35
+ ```
36
+ ┌─────────────────────────────────────────────────────────────────────┐
37
+ │ gssh stack command │
38
+ ├─────────────────────────────────────────────────────────────────────┤
39
+ │ │
40
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
41
+ │ │ Diff │ │ Sandbox │ │ Interactive UI │ │
42
+ │ │ Analyzer │───▶│ + AI │───▶│ (TUI/Prompts) │ │
43
+ │ │ │ │ Explorer │ │ │ │
44
+ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
45
+ │ │ │ │ │
46
+ │ ▼ ▼ ▼ │
47
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
48
+ │ │ AST │ │ Virtual │ │ Git Operations │ │
49
+ │ │ Bindings │ │ Filesystem │ │ (rebase, PR create) │ │
50
+ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
51
+ │ │
52
+ └─────────────────────────────────────────────────────────────────────┘
53
+ ```
54
+
55
+ ### Dependencies
56
+
57
+ ```json
58
+ {
59
+ "dependencies": {
60
+ "isomorphic-git": "^1.25.0", // Git ops in sandbox
61
+ "memfs": "^4.6.0", // Virtual filesystem
62
+ "@babel/parser": "^7.23.0", // AST parsing for JS/TS
63
+ "@babel/traverse": "^7.23.0", // AST traversal
64
+ "@babel/types": "^7.23.0", // AST type utilities
65
+ "isolated-vm": "^4.7.0", // V8 isolate sandbox
66
+ "ai-flow": "...", // AI abstraction (OpenAI responses API compatible)
67
+ "tensorzero": "..." // Multi-provider AI routing
68
+ }
69
+ }
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Component Design
75
+
76
+ ### 1. Diff Analyzer (`src/core/stack/diff-analyzer.ts`)
77
+
78
+ Parses git diff and extracts structured change information.
79
+
80
+ ```typescript
81
+ interface FileChange {
82
+ path: string;
83
+ status: 'added' | 'modified' | 'deleted' | 'renamed';
84
+ hunks: Hunk[];
85
+ oldContent?: string;
86
+ newContent?: string;
87
+ }
88
+
89
+ interface Hunk {
90
+ oldStart: number;
91
+ oldLines: number;
92
+ newStart: number;
93
+ newLines: number;
94
+ content: string;
95
+ addedLines: Line[];
96
+ removedLines: Line[];
97
+ }
98
+
99
+ // Functions
100
+ function parseDiff(diffText: string): FileChange[];
101
+ function getChangesInRange(repoPath: string, range: string): Promise<FileChange[]>;
102
+ function getFileAtRevision(repoPath: string, file: string, rev: string): Promise<string>;
103
+ ```
104
+
105
+ ### 2. AST Analysis Bindings (`src/core/stack/ast-bindings.ts`)
106
+
107
+ Provides TypeScript API for the AI sandbox to analyze code.
108
+
109
+ ```typescript
110
+ interface Symbol {
111
+ name: string;
112
+ kind: 'function' | 'class' | 'type' | 'variable' | 'import' | 'export';
113
+ file: string;
114
+ line: number;
115
+ exported: boolean;
116
+ }
117
+
118
+ interface Reference {
119
+ symbol: string;
120
+ file: string;
121
+ line: number;
122
+ }
123
+
124
+ interface ASTBindings {
125
+ // Parse code and return AST
126
+ parse(code: string, language: string): AST;
127
+
128
+ // Extract symbols defined in code
129
+ findDefinitions(code: string, language: string): Symbol[];
130
+
131
+ // Extract symbols referenced in code
132
+ findReferences(code: string, language: string): Reference[];
133
+
134
+ // Check if a set of changes is self-consistent
135
+ checkDependencies(changes: FileChange[]): {
136
+ valid: boolean;
137
+ missing: Symbol[]; // Referenced but not defined
138
+ circular: Symbol[][]; // Mutually dependent
139
+ };
140
+
141
+ // Get language from file extension
142
+ detectLanguage(filename: string): string;
143
+ }
144
+ ```
145
+
146
+ ### 3. Dependency Graph (`src/core/stack/dependency-graph.ts`)
147
+
148
+ Builds and analyzes the dependency graph of changes.
149
+
150
+ ```typescript
151
+ interface ChangeNode {
152
+ id: string;
153
+ files: string[];
154
+ hunks: Hunk[];
155
+ defines: Symbol[];
156
+ references: Symbol[];
157
+ }
158
+
159
+ interface DependencyGraph {
160
+ nodes: Map<string, ChangeNode>;
161
+ edges: Map<string, Set<string>>; // node -> depends on
162
+ }
163
+
164
+ // Functions
165
+ function buildGraph(changes: FileChange[], ast: ASTBindings): DependencyGraph;
166
+ function findStronglyConnectedComponents(graph: DependencyGraph): ChangeNode[][];
167
+ function topologicalSort(graph: DependencyGraph): ChangeNode[];
168
+ function suggestGroupings(graph: DependencyGraph): ProposedCommit[];
169
+ ```
170
+
171
+ **Dependency Analysis Flow:**
172
+
173
+ ```
174
+ Change A: Define `validateUser()` function
175
+ Change B: Use `validateUser()` in login.ts
176
+ Change C: Add `UserRole` type
177
+ Change D: Use `UserRole` in validateUser()
178
+
179
+ Dependency graph:
180
+ ─────────────────────────────────
181
+ C (UserRole)
182
+
183
+
184
+ A (validateUser) ◄── D (uses UserRole in A)
185
+
186
+
187
+ B (uses validateUser)
188
+ ─────────────────────────────────
189
+
190
+ Valid orderings: C → A+D → B
191
+ Invalid: B before A (undefined function)
192
+ ```
193
+
194
+ ### 4. Virtual Filesystem + Sandbox (`src/core/stack/sandbox.ts`)
195
+
196
+ Creates an isolated environment where AI can experiment with different commit arrangements.
197
+
198
+ ```typescript
199
+ interface SandboxFS {
200
+ // Read file (from base + overlay)
201
+ readFile(path: string): Promise<string>;
202
+
203
+ // Write to overlay (doesn't affect real FS)
204
+ writeFile(path: string, content: string): Promise<void>;
205
+
206
+ // Apply a patch to the virtual FS
207
+ applyPatch(patch: string): Promise<void>;
208
+
209
+ // Reset overlay, keep base
210
+ reset(): void;
211
+
212
+ // Snapshot current state
213
+ snapshot(): FSSnapshot;
214
+
215
+ // Restore from snapshot
216
+ restore(snapshot: FSSnapshot): void;
217
+ }
218
+
219
+ interface Sandbox {
220
+ fs: SandboxFS;
221
+ git: SandboxGit; // isomorphic-git bound to virtual FS
222
+ ast: ASTBindings;
223
+
224
+ // Execute AI-generated code in isolated environment
225
+ execute(code: string): Promise<any>;
226
+ }
227
+
228
+ // Implementation using memfs + isolated-vm
229
+ function createSandbox(repoPath: string, baseRef: string): Promise<Sandbox>;
230
+ ```
231
+
232
+ **Sandbox Architecture:**
233
+
234
+ ```
235
+ ┌─────────────────────────────────────────────────────────────────┐
236
+ │ Virtual FS Layer │
237
+ ├─────────────────────────────────────────────────────────────────┤
238
+ │ │
239
+ │ Base: Git tree at main (read-only) │
240
+ │ │ │
241
+ │ ├── Overlay: Proposed changes (copy-on-write) │
242
+ │ │ │
243
+ │ └── AI can: │
244
+ │ • Apply patch A, run tree-sitter, check deps │
245
+ │ • Apply patch A+B, run tsc, see if it compiles │
246
+ │ • Rollback, try different arrangement │
247
+ │ • Read any file as it would exist at that state │
248
+ │ │
249
+ └─────────────────────────────────────────────────────────────────┘
250
+ ```
251
+
252
+ ### 5. AI Integration (`src/core/stack/ai-explorer.ts`)
253
+
254
+ Orchestrates AI exploration of different commit arrangements.
255
+
256
+ ```typescript
257
+ interface ProposedCommit {
258
+ message: string;
259
+ files: string[];
260
+ hunks: Hunk[];
261
+ reasoning: string;
262
+ }
263
+
264
+ interface StackProposal {
265
+ commits: ProposedCommit[];
266
+ dependencyOrder: string[]; // Commit order
267
+ warnings: string[]; // Things user should review
268
+ conflicts: ConflictInfo[]; // Where user input needed
269
+ }
270
+
271
+ interface ConflictInfo {
272
+ type: 'circular' | 'interleaved' | 'ambiguous';
273
+ files: string[];
274
+ description: string;
275
+ options: string[];
276
+ }
277
+ ```
278
+
279
+ **AI Sandbox Bindings:**
280
+
281
+ ```typescript
282
+ import { AIFlow } from 'ai-flow'; // OpenAI responses API compatible
283
+
284
+ const AI_SYSTEM_PROMPT = `
285
+ You are analyzing code changes to split them into logical PRs.
286
+
287
+ You have access to these TypeScript APIs in your sandbox:
288
+ - git.getDiff(range): Get diff for commit range
289
+ - git.getFile(path, rev): Get file at revision
290
+ - ast.parse(code): Parse JS/TS to AST
291
+ - ast.findDefinitions(code): Find defined symbols
292
+ - ast.findReferences(code): Find referenced symbols
293
+ - ast.checkDeps(changes): Check if changes are self-consistent
294
+ - propose.group(files[], message): Propose a commit grouping
295
+ - propose.validate(groups[]): Validate proposed groupings
296
+
297
+ Write TypeScript code to explore the changes and propose logical groupings.
298
+ Return your final proposal via propose.finalize(groups[]).
299
+ `;
300
+ ```
301
+
302
+ ### 6. Interactive UI (`src/core/stack/ui.ts`)
303
+
304
+ TUI components for user interaction.
305
+
306
+ ```
307
+ ┌─────────────────────────────────────────────────────────────────┐
308
+ │ gssh stack - Analyzing changes... │
309
+ ├─────────────────────────────────────────────────────────────────┤
310
+ │ │
311
+ │ Found 47 changed lines across 8 files │
312
+ │ Base: main (3 commits behind) │
313
+ │ │
314
+ │ Proposed Stack: │
315
+ │ ─────────────── │
316
+ │ PR #1: "Add user authentication middleware" │
317
+ │ ├── src/middleware/auth.ts (+45 -12) │
318
+ │ ├── src/types/user.ts (+8 -0) │
319
+ │ └── src/routes/login.ts (+15 -3) │
320
+ │ │
321
+ │ PR #2: "Update button styles" │
322
+ │ └── src/styles/button.css (+5 -2) │
323
+ │ │
324
+ │ ⚠️ Needs Review: │
325
+ │ src/utils/helpers.ts has changes for both PRs │
326
+ │ │
327
+ │ [a] Accept [e] Edit [s] Split file [?] Help │
328
+ └─────────────────────────────────────────────────────────────────┘
329
+ ```
330
+
331
+ **Features:**
332
+ - Show proposed groupings with file lists
333
+ - Highlight conflicts/warnings
334
+ - Allow editing commit messages
335
+ - Allow reassigning files/hunks to different commits
336
+ - Preview resulting git history
337
+ - Confirm before executing
338
+
339
+ ### 7. Git Execution (`src/core/stack/git-executor.ts`)
340
+
341
+ Actually creates the branches and PRs.
342
+
343
+ ```typescript
344
+ interface StackExecutionPlan {
345
+ prBranches: string[]; // e.g., ["feature-auth", "feature-styles"]
346
+ continuationBranch: string; // Where remaining work goes
347
+ commits: Map<string, ProposedCommit[]>;
348
+ rebaseOnto: string;
349
+ }
350
+
351
+ async function executeStack(
352
+ workspacePath: string,
353
+ plan: StackExecutionPlan,
354
+ createPRs: boolean
355
+ ): Promise<{
356
+ createdBranches: string[];
357
+ prUrls?: string[];
358
+ continuationBranch: string;
359
+ }>;
360
+ ```
361
+
362
+ ### 8. Stack State Tracking (`src/core/stack/stack-state.ts`)
363
+
364
+ Persists stack relationships for future `gssh stack sync`.
365
+
366
+ ```typescript
367
+ // Stored in ~/gitspace/<project>/.stack-state.json
368
+ interface StackState {
369
+ stacks: Stack[];
370
+ }
371
+
372
+ interface Stack {
373
+ id: string; // UUID
374
+ createdAt: string;
375
+ baseBranch: string; // e.g., "main"
376
+ prs: StackedPR[]; // Ordered list (bottom to top)
377
+ continuationBranch?: string; // Branch with remaining work
378
+ }
379
+
380
+ interface StackedPR {
381
+ branch: string;
382
+ prNumber?: number;
383
+ prUrl?: string;
384
+ status: 'pending' | 'open' | 'merged' | 'closed';
385
+ baseBranch: string; // What this PR targets
386
+ headCommit: string; // For detecting updates
387
+ }
388
+ ```
389
+
390
+ ### 9. Stack Sync (`src/core/stack/sync.ts`) - Future
391
+
392
+ Handles rebasing when PRs are merged/updated.
393
+
394
+ ```typescript
395
+ // gssh stack sync
396
+ async function syncStack(
397
+ workspacePath: string,
398
+ stackId: string
399
+ ): Promise<{
400
+ rebased: string[]; // Branches that were rebased
401
+ conflicts: string[]; // Branches with conflicts
402
+ }>;
403
+
404
+ // Workflow:
405
+ // 1. Check status of each PR in stack (via gh api)
406
+ // 2. For merged PRs: rebase dependent branches onto new base
407
+ // 3. For updated PRs: detect force-push, rebase dependents
408
+ // 4. Report conflicts for manual resolution
409
+ ```
410
+
411
+ ---
412
+
413
+ ## File Structure
414
+
415
+ ```
416
+ src/
417
+ ├── commands/
418
+ │ └── stack.ts # Command entry point
419
+ ├── core/
420
+ │ └── stack/
421
+ │ ├── index.ts # Main orchestrator
422
+ │ ├── diff-analyzer.ts # Diff parsing
423
+ │ ├── ast-bindings.ts # AST analysis API (Babel-based)
424
+ │ ├── dependency-graph.ts # Graph analysis
425
+ │ ├── sandbox.ts # Virtual FS + isolate
426
+ │ ├── ai-explorer.ts # AI integration (ai-flow)
427
+ │ ├── git-executor.ts # Git operations
428
+ │ ├── stack-state.ts # Persist stack relationships
429
+ │ ├── sync.ts # Stack sync operations (future)
430
+ │ └── ui.ts # Interactive UI components
431
+ ├── types/
432
+ │ └── stack.ts # Type definitions
433
+ ```
434
+
435
+ **Integration Points:**
436
+ - `src/index.ts` - Register `stack` command with Commander.js
437
+ - `src/core/git.ts` - Reuse existing git utilities
438
+ - `src/utils/prompts.ts` - Reuse selectItem, promptInput, promptConfirm
439
+ - `src/core/config.ts` - Add getStackStateFile() path helper
440
+
441
+ ---
442
+
443
+ ## Command Interface
444
+
445
+ ```bash
446
+ # Basic usage - analyze current branch vs main
447
+ gssh stack
448
+
449
+ # Specify base branch
450
+ gssh stack --base develop
451
+
452
+ # Specify commit range
453
+ gssh stack --range HEAD~5..HEAD
454
+
455
+ # Non-interactive mode (for CI/scripts)
456
+ gssh stack --auto
457
+
458
+ # Just analyze, don't execute
459
+ gssh stack --dry-run
460
+
461
+ # Provide hints to AI
462
+ gssh stack --hint "The auth changes should be separate from the UI changes"
463
+
464
+ # Stack sync - rebase dependent branches when PRs merge/update
465
+ gssh stack sync
466
+
467
+ # List active stacks
468
+ gssh stack list
469
+
470
+ # Show stack status (PR states, rebase needed)
471
+ gssh stack status
472
+ ```
473
+
474
+ **Interactive Prompts:**
475
+ 1. After analysis: "Create PRs now, or just prepare branches?" → [Create PRs] [Branches only]
476
+ 2. Conflict resolution: "These files have interleaved changes" → [Split] [Keep together] [Show diff]
477
+ 3. Commit messages: "Edit commit messages?" → [Accept] [Edit]
478
+
479
+ ---
480
+
481
+ ## Implementation Phases
482
+
483
+ ### Phase 1: Foundation
484
+ **Files:** `package.json`, `src/types/stack.ts`, `src/core/stack/diff-analyzer.ts`
485
+
486
+ 1. Add dependencies: `@babel/parser`, `@babel/traverse`, `memfs`, `isomorphic-git`, `isolated-vm`
487
+ 2. Create type definitions
488
+ 3. Implement diff analyzer
489
+ 4. Add basic `gssh stack --dry-run` command
490
+
491
+ ### Phase 2: AST Analysis
492
+ **Files:** `src/core/stack/ast-bindings.ts`, `src/core/stack/dependency-graph.ts`
493
+
494
+ 1. Implement AST parsing with @babel/parser
495
+ 2. Build dependency graph
496
+ 3. Implement SCC detection and topological sort
497
+
498
+ ### Phase 3: Sandbox Environment
499
+ **Files:** `src/core/stack/sandbox.ts`
500
+
501
+ 1. Set up memfs virtual filesystem
502
+ 2. Integrate isomorphic-git
503
+ 3. Create isolated-vm sandbox with bindings
504
+
505
+ ### Phase 4: AI Integration
506
+ **Files:** `src/core/stack/ai-explorer.ts`
507
+
508
+ 1. Integrate ai-flow client
509
+ 2. Create system prompt with binding docs
510
+ 3. Implement exploration loop
511
+
512
+ ### Phase 5: Interactive UI
513
+ **Files:** `src/core/stack/ui.ts`, `src/commands/stack.ts`
514
+
515
+ 1. Analysis display
516
+ 2. Conflict resolution UI
517
+ 3. Commit message editing
518
+ 4. File/hunk reassignment
519
+
520
+ ### Phase 6: Git Execution
521
+ **Files:** `src/core/stack/git-executor.ts`, `src/core/stack/stack-state.ts`
522
+
523
+ 1. Branch creation and commit application
524
+ 2. PR creation via `gh` CLI
525
+ 3. Continuation branch rebasing
526
+ 4. State persistence
527
+
528
+ ### Phase 7: Stack Management (Future)
529
+ **Files:** `src/core/stack/sync.ts`
530
+
531
+ 1. `gssh stack list`
532
+ 2. `gssh stack status`
533
+ 3. `gssh stack sync`
534
+
535
+ ### Phase 8: Polish
536
+ 1. `--auto` mode
537
+ 2. Progress indicators
538
+ 3. Rollback on failure
539
+ 4. Documentation
540
+
541
+ ---
542
+
543
+ ## Technical Decisions
544
+
545
+ | Decision | Choice | Rationale |
546
+ |----------|--------|-----------|
547
+ | AST Parser | @babel/parser | Pure JS, no native deps, excellent JS/TS support |
548
+ | Sandbox | isolated-vm + memfs | True V8 isolate, fast startup, matches Cloudflare's approach |
549
+ | AI Provider | ai-flow + TensorZero | OpenAI responses API compatible, multi-provider support |
550
+ | PR Creation | User choice per run | Prompt each time for flexibility |
551
+
552
+ ---
553
+
554
+ ## Risk Mitigation
555
+
556
+ | Risk | Mitigation |
557
+ |------|------------|
558
+ | AI produces invalid groupings | Validate with AST before presenting to user |
559
+ | Complex merges fail | Always work on copies, never modify user's branch until confirmed |
560
+ | Large diffs overwhelm AI | Chunk analysis, summarize first |
561
+ | Circular dependencies | Detect and flag for user resolution |
562
+ | isolated-vm compatibility | Fall back to worker threads if needed |
563
+
564
+ ---
565
+
566
+ ## Success Criteria
567
+
568
+ 1. User can run `gssh stack` and see proposed commit groupings
569
+ 2. Each proposed commit is syntactically valid (passes AST validation)
570
+ 3. User can adjust groupings interactively
571
+ 4. User chooses: create PRs automatically OR just prepare branches
572
+ 5. Executing creates clean branches with logical commits
573
+ 6. User's remaining work is correctly rebased on top of stack
574
+ 7. Stack state is persisted for future `gssh stack sync`
575
+
576
+ ---
577
+
578
+ ## External Dependencies
579
+
580
+ 1. **ai-flow** - AI abstraction library (OpenAI responses API compatible)
581
+ 2. **TensorZero** - Multi-provider routing (optional)
582
+
583
+ ---
584
+
585
+ ## References
586
+
587
+ - [Cloudflare Code Mode](https://blog.cloudflare.com/code-mode/) - Inspiration for sandbox approach
588
+ - [Graphite](https://graphite.dev/) - Stacked PR workflow reference