gitspace 0.2.0-rc.20 → 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.
- package/package.json +11 -6
- package/.claude/settings.local.json +0 -10
- package/.gitspace/bundle.json +0 -50
- package/.gitspace/events.json +0 -11
- package/.gitspace/processes.json +0 -23
- package/.gitspace/scripts/select/01-status.sh +0 -39
- package/.gitspace/scripts/setup/01-install-deps.sh +0 -12
- package/.gitspace/scripts/setup/02-typecheck.sh +0 -16
- package/AGENTS.md +0 -469
- package/CLAUDE.md +0 -1
- package/bun.lock +0 -794
- package/docs/CONNECTION.md +0 -623
- package/docs/GATEWAY-WORKER.md +0 -319
- package/docs/GETTING-STARTED.md +0 -448
- package/docs/GITSPACE-PLATFORM.md +0 -1819
- package/docs/INFRASTRUCTURE.md +0 -1347
- package/docs/PROTOCOL.md +0 -619
- package/docs/QUICKSTART.md +0 -183
- package/docs/RELAY.md +0 -327
- package/docs/REMOTE-DESIGN.md +0 -554
- package/docs/ROADMAP.md +0 -564
- package/docs/SITE_DOCS_FIGMA_MAKE.md +0 -1176
- package/docs/STACK-DESIGN.md +0 -588
- package/docs/UNIFIED_ARCHITECTURE.md +0 -138
- package/experiments/pty-benchmark.ts +0 -148
- package/experiments/pty-latency.ts +0 -100
- package/experiments/router/client.ts +0 -199
- package/experiments/router/protocol.ts +0 -74
- package/experiments/router/router.ts +0 -217
- package/experiments/router/session.ts +0 -180
- package/experiments/router/test.ts +0 -133
- package/experiments/socket-bandwidth.ts +0 -77
- package/homebrew/gitspace.rb +0 -45
- package/landing-page/ATTRIBUTIONS.md +0 -3
- package/landing-page/README.md +0 -11
- package/landing-page/bun.lock +0 -801
- package/landing-page/guidelines/Guidelines.md +0 -61
- package/landing-page/index.html +0 -37
- package/landing-page/package.json +0 -90
- package/landing-page/postcss.config.mjs +0 -15
- package/landing-page/public/_redirects +0 -1
- package/landing-page/public/favicon.png +0 -0
- package/landing-page/src/app/App.tsx +0 -53
- package/landing-page/src/app/components/figma/ImageWithFallback.tsx +0 -27
- package/landing-page/src/app/components/ui/accordion.tsx +0 -66
- package/landing-page/src/app/components/ui/alert-dialog.tsx +0 -157
- package/landing-page/src/app/components/ui/alert.tsx +0 -66
- package/landing-page/src/app/components/ui/aspect-ratio.tsx +0 -11
- package/landing-page/src/app/components/ui/avatar.tsx +0 -53
- package/landing-page/src/app/components/ui/badge.tsx +0 -46
- package/landing-page/src/app/components/ui/breadcrumb.tsx +0 -109
- package/landing-page/src/app/components/ui/button.tsx +0 -57
- package/landing-page/src/app/components/ui/calendar.tsx +0 -75
- package/landing-page/src/app/components/ui/card.tsx +0 -92
- package/landing-page/src/app/components/ui/carousel.tsx +0 -241
- package/landing-page/src/app/components/ui/chart.tsx +0 -353
- package/landing-page/src/app/components/ui/checkbox.tsx +0 -32
- package/landing-page/src/app/components/ui/collapsible.tsx +0 -33
- package/landing-page/src/app/components/ui/command.tsx +0 -177
- package/landing-page/src/app/components/ui/context-menu.tsx +0 -252
- package/landing-page/src/app/components/ui/dialog.tsx +0 -135
- package/landing-page/src/app/components/ui/drawer.tsx +0 -132
- package/landing-page/src/app/components/ui/dropdown-menu.tsx +0 -257
- package/landing-page/src/app/components/ui/form.tsx +0 -168
- package/landing-page/src/app/components/ui/hover-card.tsx +0 -44
- package/landing-page/src/app/components/ui/input-otp.tsx +0 -77
- package/landing-page/src/app/components/ui/input.tsx +0 -21
- package/landing-page/src/app/components/ui/label.tsx +0 -24
- package/landing-page/src/app/components/ui/menubar.tsx +0 -276
- package/landing-page/src/app/components/ui/navigation-menu.tsx +0 -168
- package/landing-page/src/app/components/ui/pagination.tsx +0 -127
- package/landing-page/src/app/components/ui/popover.tsx +0 -48
- package/landing-page/src/app/components/ui/progress.tsx +0 -31
- package/landing-page/src/app/components/ui/radio-group.tsx +0 -45
- package/landing-page/src/app/components/ui/resizable.tsx +0 -56
- package/landing-page/src/app/components/ui/scroll-area.tsx +0 -58
- package/landing-page/src/app/components/ui/select.tsx +0 -189
- package/landing-page/src/app/components/ui/separator.tsx +0 -28
- package/landing-page/src/app/components/ui/sheet.tsx +0 -139
- package/landing-page/src/app/components/ui/sidebar.tsx +0 -726
- package/landing-page/src/app/components/ui/skeleton.tsx +0 -13
- package/landing-page/src/app/components/ui/slider.tsx +0 -63
- package/landing-page/src/app/components/ui/sonner.tsx +0 -25
- package/landing-page/src/app/components/ui/switch.tsx +0 -31
- package/landing-page/src/app/components/ui/table.tsx +0 -116
- package/landing-page/src/app/components/ui/tabs.tsx +0 -66
- package/landing-page/src/app/components/ui/textarea.tsx +0 -18
- package/landing-page/src/app/components/ui/toggle-group.tsx +0 -73
- package/landing-page/src/app/components/ui/toggle.tsx +0 -47
- package/landing-page/src/app/components/ui/tooltip.tsx +0 -61
- package/landing-page/src/app/components/ui/use-mobile.ts +0 -21
- package/landing-page/src/app/components/ui/utils.ts +0 -6
- package/landing-page/src/components/docs/DocsContent.tsx +0 -801
- package/landing-page/src/components/docs/DocsSidebar.tsx +0 -90
- package/landing-page/src/components/landing/CTA.tsx +0 -59
- package/landing-page/src/components/landing/Comparison.tsx +0 -84
- package/landing-page/src/components/landing/FaultyTerminal.tsx +0 -424
- package/landing-page/src/components/landing/Features.tsx +0 -201
- package/landing-page/src/components/landing/Hero.tsx +0 -142
- package/landing-page/src/components/landing/Pricing.tsx +0 -140
- package/landing-page/src/components/landing/Roadmap.tsx +0 -86
- package/landing-page/src/components/landing/Security.tsx +0 -81
- package/landing-page/src/components/landing/TerminalWindow.tsx +0 -27
- package/landing-page/src/components/landing/UseCases.tsx +0 -55
- package/landing-page/src/components/landing/Workflow.tsx +0 -101
- package/landing-page/src/components/layout/DashboardNavbar.tsx +0 -37
- package/landing-page/src/components/layout/Footer.tsx +0 -55
- package/landing-page/src/components/layout/LandingNavbar.tsx +0 -82
- package/landing-page/src/components/ui/badge.tsx +0 -39
- package/landing-page/src/components/ui/breadcrumb.tsx +0 -115
- package/landing-page/src/components/ui/button.tsx +0 -57
- package/landing-page/src/components/ui/card.tsx +0 -79
- package/landing-page/src/components/ui/mock-terminal.tsx +0 -68
- package/landing-page/src/components/ui/separator.tsx +0 -28
- package/landing-page/src/lib/utils.ts +0 -6
- package/landing-page/src/main.tsx +0 -10
- package/landing-page/src/pages/Dashboard.tsx +0 -133
- package/landing-page/src/pages/DocsPage.tsx +0 -79
- package/landing-page/src/pages/LandingPage.tsx +0 -31
- package/landing-page/src/pages/TerminalView.tsx +0 -106
- package/landing-page/src/styles/fonts.css +0 -0
- package/landing-page/src/styles/index.css +0 -3
- package/landing-page/src/styles/tailwind.css +0 -4
- package/landing-page/src/styles/theme.css +0 -181
- package/landing-page/vite.config.ts +0 -19
- package/scripts/GHOSTTY_TAB_BUG.md +0 -106
- package/scripts/build.ts +0 -298
- package/scripts/migrate-secrets.ts +0 -77
- package/scripts/release.ts +0 -140
- package/scripts/sample-events.ts +0 -263
- package/scripts/test-tabs-minimal.ts +0 -68
- package/scripts/test-tabs-workaround.ts +0 -95
- package/scripts/test-tabs.ts +0 -171
- package/src/__tests__/test-utils.ts +0 -298
- package/src/app/input/__tests__/sessionCommands.test.ts +0 -40
- package/src/app/input/sessionCommands.ts +0 -94
- package/src/app/session/__tests__/useAttachController.test.ts +0 -229
- package/src/app/session/createSessionBackend.bun.ts +0 -76
- package/src/app/session/createSessionBackend.web.ts +0 -104
- package/src/app/session/types.ts +0 -16
- package/src/app/session/useAttachController.ts +0 -220
- package/src/app/session/useProcessActions.ts +0 -201
- package/src/app/session/useSessionClient.ts +0 -35
- package/src/app/session/useWorkspaceDeleteFlow.ts +0 -170
- package/src/app.tui.tsx +0 -2929
- package/src/app.web.tsx +0 -1454
- package/src/commands/__tests__/connect-key.test.ts +0 -10
- package/src/commands/__tests__/events.test.ts +0 -201
- package/src/commands/__tests__/notifications.test.ts +0 -349
- package/src/commands/__tests__/process.test.ts +0 -251
- package/src/commands/__tests__/serve-messages.test.ts +0 -190
- package/src/commands/__tests__/serve-process-hosting.test.ts +0 -63
- package/src/commands/access.ts +0 -298
- package/src/commands/add.ts +0 -455
- package/src/commands/auth.ts +0 -369
- package/src/commands/bundle.ts +0 -232
- package/src/commands/config.ts +0 -242
- package/src/commands/connect-key.ts +0 -1
- package/src/commands/connect.ts +0 -576
- package/src/commands/directory.ts +0 -16
- package/src/commands/events.ts +0 -157
- package/src/commands/host.ts +0 -566
- package/src/commands/identity.ts +0 -184
- package/src/commands/linear.ts +0 -717
- package/src/commands/list.ts +0 -181
- package/src/commands/migrate.ts +0 -52
- package/src/commands/notifications.ts +0 -351
- package/src/commands/process.ts +0 -104
- package/src/commands/relay.ts +0 -315
- package/src/commands/remove.ts +0 -279
- package/src/commands/review.ts +0 -787
- package/src/commands/serve.ts +0 -1946
- package/src/commands/share.ts +0 -451
- package/src/commands/status.ts +0 -125
- package/src/commands/switch.ts +0 -361
- package/src/commands/tmux.ts +0 -317
- package/src/components/DPad.web.tsx +0 -343
- package/src/components/DiffViewer.web.tsx +0 -1192
- package/src/components/Events.tsx +0 -137
- package/src/components/Events.tui.tsx +0 -129
- package/src/components/Events.web.tsx +0 -386
- package/src/components/FloatingControls.web.tsx +0 -112
- package/src/components/FloatingJogWheel.web.tsx +0 -240
- package/src/components/Flow.tsx +0 -458
- package/src/components/Flow.tui.tsx +0 -343
- package/src/components/Flow.web.tsx +0 -442
- package/src/components/Inbox.tsx +0 -448
- package/src/components/Inbox.tui.tsx +0 -262
- package/src/components/Inbox.web.tsx +0 -329
- package/src/components/MachineList.tsx +0 -187
- package/src/components/MachineList.tui.tsx +0 -161
- package/src/components/MachineList.web.tsx +0 -210
- package/src/components/NumPad.web.tsx +0 -270
- package/src/components/ProjectList.tsx +0 -175
- package/src/components/ProjectList.tui.tsx +0 -109
- package/src/components/ProjectList.web.tsx +0 -143
- package/src/components/ProjectOnboardingStep.ts +0 -23
- package/src/components/ProjectOnboardingStep.tui.tsx +0 -88
- package/src/components/ProjectOnboardingStep.web.tsx +0 -59
- package/src/components/RemoteMachineScreen.tui.tsx +0 -690
- package/src/components/ScriptTerminal.tui.tsx +0 -160
- package/src/components/ScriptTerminal.web.tsx +0 -89
- package/src/components/SessionTerminal.tui.tsx +0 -406
- package/src/components/SessionTerminal.web.tsx +0 -467
- package/src/components/SpacesBrowser.tsx +0 -540
- package/src/components/SpacesBrowser.tui.tsx +0 -258
- package/src/components/SpacesBrowser.web.tsx +0 -332
- package/src/components/TerminalControls.web.tsx +0 -464
- package/src/components/ThreadPanel.web.tsx +0 -798
- package/src/components/__tests__/SpacesBrowser.test.ts +0 -541
- package/src/components/__tests__/SpacesBrowser.tui.test.tsx +0 -249
- package/src/components/__tests__/script-terminal-buffer.tui.test.ts +0 -72
- package/src/components/index.ts +0 -105
- package/src/components/review-decision-colors.ts +0 -11
- package/src/components/script-terminal-buffer.tui.ts +0 -37
- package/src/components/session-terminal-page-navigation.ts +0 -48
- package/src/components/terminal-bracketed-paste.tui.test.ts +0 -43
- package/src/components/terminal-bracketed-paste.tui.ts +0 -46
- package/src/core/__tests__/access.test.ts +0 -240
- package/src/core/__tests__/bundle-refresh.test.ts +0 -567
- package/src/core/__tests__/bundle.test.ts +0 -209
- package/src/core/__tests__/github-review.test.ts +0 -781
- package/src/core/__tests__/project-lifecycle.test.ts +0 -137
- package/src/core/__tests__/workspace-lifecycle.test.ts +0 -159
- package/src/core/__tests__/workspace.test.ts +0 -149
- package/src/core/access.ts +0 -277
- package/src/core/bundle-refresh.ts +0 -1064
- package/src/core/bundle.ts +0 -326
- package/src/core/config.ts +0 -405
- package/src/core/git.ts +0 -768
- package/src/core/github-review.ts +0 -761
- package/src/core/github.ts +0 -151
- package/src/core/identity.ts +0 -631
- package/src/core/linear.ts +0 -403
- package/src/core/preferences-service.ts +0 -17
- package/src/core/project-catalog.ts +0 -52
- package/src/core/project-lifecycle.ts +0 -163
- package/src/core/review-executor.ts +0 -316
- package/src/core/review.ts +0 -407
- package/src/core/secret-runtime.ts +0 -167
- package/src/core/shell.ts +0 -117
- package/src/core/trusted-relays.ts +0 -315
- package/src/core/workspace-lifecycle.ts +0 -216
- package/src/core/workspace.ts +0 -363
- package/src/hooks/__tests__/useLocalSession.tui.test.ts +0 -557
- package/src/hooks/index.ts +0 -8
- package/src/hooks/index.tui.ts +0 -32
- package/src/hooks/useDaemonStatus.tui.ts +0 -174
- package/src/hooks/useLocalSession.tui.ts +0 -395
- package/src/hooks/useRelayConnection.web.ts +0 -54
- package/src/hooks/useRemoteMachines.tui.ts +0 -166
- package/src/hooks/useRemoteTerminal.tui.ts +0 -22
- package/src/hooks/useReview.web.ts +0 -248
- package/src/hooks/useTerminal.web.ts +0 -36
- package/src/hooks/useUserActivity.ts +0 -61
- package/src/hooks/useVisualViewport.web.ts +0 -104
- package/src/index.ts +0 -1376
- package/src/lib/events/__tests__/collector-filter.test.ts +0 -105
- package/src/lib/events/__tests__/store-query.test.ts +0 -103
- package/src/lib/events/collector.ts +0 -494
- package/src/lib/events/filters.ts +0 -26
- package/src/lib/events/index.ts +0 -11
- package/src/lib/events/indexer.ts +0 -14
- package/src/lib/events/paths.ts +0 -69
- package/src/lib/events/reader.ts +0 -212
- package/src/lib/events/store.ts +0 -141
- package/src/lib/invite.web.ts +0 -58
- package/src/lib/preferences-service.web.ts +0 -41
- package/src/lib/processes/__tests__/config.test.ts +0 -83
- package/src/lib/processes/__tests__/names.test.ts +0 -125
- package/src/lib/processes/__tests__/schema.test.ts +0 -208
- package/src/lib/processes/__tests__/watchdog.test.ts +0 -210
- package/src/lib/processes/autostart.ts +0 -16
- package/src/lib/processes/config.ts +0 -187
- package/src/lib/processes/control.ts +0 -53
- package/src/lib/processes/editor.ts +0 -32
- package/src/lib/processes/events-config.ts +0 -37
- package/src/lib/processes/index.ts +0 -14
- package/src/lib/processes/instances.ts +0 -20
- package/src/lib/processes/manager.ts +0 -131
- package/src/lib/processes/names.ts +0 -71
- package/src/lib/processes/registry.ts +0 -26
- package/src/lib/processes/runner.ts +0 -211
- package/src/lib/processes/scheduler.ts +0 -17
- package/src/lib/processes/schema.ts +0 -74
- package/src/lib/processes/session-list.ts +0 -15
- package/src/lib/processes/state.ts +0 -82
- package/src/lib/processes/watchdog.test.ts +0 -79
- package/src/lib/processes/watchdog.ts +0 -106
- package/src/lib/remote-session/__tests__/protocol.test.ts +0 -291
- package/src/lib/remote-session/index.ts +0 -7
- package/src/lib/remote-session/protocol.ts +0 -443
- package/src/lib/remote-session/session-handler.ts +0 -1298
- package/src/lib/remote-session/workspace-scanner.ts +0 -161
- package/src/lib/sonner.web.ts +0 -1
- package/src/lib/storage/identity-store.web.ts +0 -94
- package/src/lib/tmux-lite/README.md +0 -81
- package/src/lib/tmux-lite/cli.ts +0 -855
- package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +0 -349
- package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +0 -291
- package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +0 -142
- package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +0 -339
- package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +0 -477
- package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +0 -499
- package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +0 -371
- package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +0 -573
- package/src/lib/tmux-lite/crypto/access-control.test.ts +0 -512
- package/src/lib/tmux-lite/crypto/access-control.ts +0 -320
- package/src/lib/tmux-lite/crypto/frames.test.ts +0 -262
- package/src/lib/tmux-lite/crypto/frames.ts +0 -141
- package/src/lib/tmux-lite/crypto/handshake.ts +0 -894
- package/src/lib/tmux-lite/crypto/identity.test.ts +0 -220
- package/src/lib/tmux-lite/crypto/identity.ts +0 -286
- package/src/lib/tmux-lite/crypto/index.ts +0 -51
- package/src/lib/tmux-lite/crypto/invites.test.ts +0 -381
- package/src/lib/tmux-lite/crypto/invites.ts +0 -215
- package/src/lib/tmux-lite/crypto/keyexchange.ts +0 -435
- package/src/lib/tmux-lite/crypto/keys.test.ts +0 -58
- package/src/lib/tmux-lite/crypto/keys.ts +0 -47
- package/src/lib/tmux-lite/crypto/secretbox.test.ts +0 -169
- package/src/lib/tmux-lite/crypto/secretbox.ts +0 -124
- package/src/lib/tmux-lite/handshake-handler.ts +0 -451
- package/src/lib/tmux-lite/process-run.integration.test.ts +0 -266
- package/src/lib/tmux-lite/protocol.test.ts +0 -307
- package/src/lib/tmux-lite/protocol.ts +0 -291
- package/src/lib/tmux-lite/relay-client.ts +0 -506
- package/src/lib/tmux-lite/server-lifecycle.test.ts +0 -212
- package/src/lib/tmux-lite/server.ts +0 -1412
- package/src/lib/tmux-lite/shell-integration.sh +0 -37
- package/src/lib/tmux-lite/terminal-queries.test.ts +0 -54
- package/src/lib/tmux-lite/terminal-queries.ts +0 -49
- package/src/notifications/__tests__/useNotifications.test.ts +0 -739
- package/src/notifications/index.ts +0 -32
- package/src/notifications/policy.test.ts +0 -424
- package/src/notifications/policy.ts +0 -139
- package/src/notifications/types.ts +0 -82
- package/src/notifications/useNotifications.ts +0 -350
- package/src/pages/ReviewPage.web.tsx +0 -511
- package/src/preferences/index.ts +0 -1
- package/src/preferences/types.ts +0 -9
- package/src/relay/__tests__/e2e-flow.test.ts +0 -1284
- package/src/relay/__tests__/helpers/auth.ts +0 -354
- package/src/relay/__tests__/helpers/ports.ts +0 -51
- package/src/relay/__tests__/protocol-validation.test.ts +0 -265
- package/src/relay/authorization.ts +0 -303
- package/src/relay/embedded-assets.generated.d.ts +0 -15
- package/src/relay/identity.ts +0 -352
- package/src/relay/index.ts +0 -57
- package/src/relay/pipes.test.ts +0 -427
- package/src/relay/pipes.ts +0 -195
- package/src/relay/protocol.ts +0 -804
- package/src/relay/registries.test.ts +0 -437
- package/src/relay/registries.ts +0 -593
- package/src/relay/server.test.ts +0 -1323
- package/src/relay/server.ts +0 -1128
- package/src/relay/signing.ts +0 -238
- package/src/relay/types.ts +0 -69
- package/src/relay-client/__tests__/machine-directory-client.test.ts +0 -152
- package/src/relay-client/__tests__/useMachineDirectory.test.ts +0 -172
- package/src/relay-client/adapters/browser.ts +0 -27
- package/src/relay-client/adapters/node.ts +0 -29
- package/src/relay-client/index.ts +0 -33
- package/src/relay-client/machine-directory-client.ts +0 -244
- package/src/relay-client/useMachineDirectory.ts +0 -175
- package/src/serve/client-session-manager.ts +0 -635
- package/src/serve/daemon.ts +0 -497
- package/src/serve/pty-session.ts +0 -236
- package/src/serve/types.ts +0 -174
- package/src/session/__tests__/backend-manager.test.ts +0 -101
- package/src/session/__tests__/local-session-backend.test.ts +0 -1129
- package/src/session/__tests__/reducer.test.ts +0 -80
- package/src/session/__tests__/remote-session-backend.test.ts +0 -995
- package/src/session/__tests__/session-name.test.ts +0 -35
- package/src/session/__tests__/useBundleRefreshAttachFlow.test.ts +0 -431
- package/src/session/__tests__/useRemoteSessionClient.test.ts +0 -424
- package/src/session/__tests__/workspace-shell-hooks.integration.test.ts +0 -268
- package/src/session/__tests__/workspace-shell-hooks.test.ts +0 -24
- package/src/session/adapters/browser-remote.ts +0 -101
- package/src/session/adapters/node-remote.ts +0 -135
- package/src/session/backend-key.ts +0 -5
- package/src/session/backend-manager.ts +0 -80
- package/src/session/backend.ts +0 -93
- package/src/session/backends/local-session-backend.ts +0 -1119
- package/src/session/backends/remote-session-backend.ts +0 -1378
- package/src/session/crypto/__tests__/web-terminal.test.ts +0 -1158
- package/src/session/crypto/frames.web.ts +0 -205
- package/src/session/crypto/handshake.web.ts +0 -396
- package/src/session/crypto/identity.web.ts +0 -133
- package/src/session/crypto/keyexchange.web.ts +0 -246
- package/src/session/crypto/relay-signing.web.ts +0 -53
- package/src/session/events.ts +0 -38
- package/src/session/index.ts +0 -116
- package/src/session/reducer.ts +0 -274
- package/src/session/selectors.ts +0 -28
- package/src/session/session-name.ts +0 -50
- package/src/session/types.ts +0 -101
- package/src/session/useBundleRefreshAttachFlow.ts +0 -608
- package/src/session/useRemoteSessionClient.ts +0 -424
- package/src/session/useSessionEngine.ts +0 -432
- package/src/session/workspace-shell-hooks.ts +0 -35
- package/src/tui/__tests__/input-text.test.ts +0 -24
- package/src/tui/__tests__/local-terminal-sync.test.ts +0 -82
- package/src/tui/__tests__/session-terminal-page-navigation.test.ts +0 -94
- package/src/tui/app.tsx +0 -2
- package/src/tui/index.ts +0 -18
- package/src/tui/input-text.ts +0 -38
- package/src/tui/local-terminal-sync.ts +0 -41
- package/src/types/bundle-refresh.ts +0 -42
- package/src/types/bundle.ts +0 -130
- package/src/types/config.ts +0 -287
- package/src/types/errors.ts +0 -292
- package/src/types/events.ts +0 -91
- package/src/types/identity.ts +0 -284
- package/src/types/processes.ts +0 -45
- package/src/types/review.ts +0 -349
- package/src/types/script-phase.ts +0 -3
- package/src/types/workspace-fuzzy.ts +0 -49
- package/src/types/workspace.ts +0 -151
- package/src/utils/__tests__/onboarding.test.ts +0 -358
- package/src/utils/__tests__/run-scripts.test.ts +0 -535
- package/src/utils/__tests__/run-workspace-scripts.test.ts +0 -406
- package/src/utils/__tests__/workspace-setup.integration.test.ts +0 -633
- package/src/utils/__tests__/workspace-state.test.ts +0 -78
- package/src/utils/bun-socket-writer.ts +0 -80
- package/src/utils/clipboard.ts +0 -53
- package/src/utils/deps.test.ts +0 -31
- package/src/utils/deps.ts +0 -145
- package/src/utils/device.web.ts +0 -163
- package/src/utils/fuzzy-match.ts +0 -125
- package/src/utils/hostnames.ts +0 -43
- package/src/utils/hunk-header.ts +0 -17
- package/src/utils/id.ts +0 -9
- package/src/utils/logger.ts +0 -127
- package/src/utils/markdown.ts +0 -254
- package/src/utils/normalize-env-key.ts +0 -13
- package/src/utils/onboarding.ts +0 -279
- package/src/utils/prompts.ts +0 -176
- package/src/utils/run-commands.ts +0 -112
- package/src/utils/run-scripts.ts +0 -337
- package/src/utils/run-workspace-scripts.ts +0 -355
- package/src/utils/sanitize.test.ts +0 -149
- package/src/utils/sanitize.ts +0 -162
- package/src/utils/secrets.ts +0 -836
- package/src/utils/shell-escape.ts +0 -40
- package/src/utils/utf8.ts +0 -79
- package/src/utils/workspace-id.ts +0 -55
- package/src/utils/workspace-state.ts +0 -427
- package/src/version.generated.d.ts +0 -2
- package/todo-security.md +0 -92
- package/tsconfig.json +0 -29
- package/web/README.md +0 -73
- package/web/bun.lock +0 -675
- package/web/eslint.config.js +0 -23
- package/web/index.css +0 -249
- package/web/index.html +0 -16
- package/web/main.tsx +0 -10
- package/web/package.json +0 -39
- package/web/public/vite.svg +0 -1
- package/web/tsconfig.app.json +0 -35
- package/web/tsconfig.json +0 -7
- package/web/tsconfig.node.json +0 -26
- package/web/vite.config.ts +0 -39
- package/worker/bun.lock +0 -237
- package/worker/package.json +0 -22
- package/worker/schema.sql +0 -96
- package/worker/src/handlers/auth.ts +0 -451
- package/worker/src/handlers/subdomains.ts +0 -376
- package/worker/src/handlers/user.ts +0 -98
- package/worker/src/index.ts +0 -70
- package/worker/src/middleware/auth.ts +0 -152
- package/worker/src/services/cloudflare.ts +0 -609
- package/worker/src/types.ts +0 -96
- package/worker/tsconfig.json +0 -15
- package/worker/wrangler.toml +0 -26
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# Unified Architecture
|
|
2
|
-
|
|
3
|
-
This document describes the canonical shared architecture for CLI/TUI/Web state and session handling.
|
|
4
|
-
|
|
5
|
-
## Status
|
|
6
|
-
|
|
7
|
-
Implementation is now centered on a shared session engine and backend adapters.
|
|
8
|
-
|
|
9
|
-
- Completed:
|
|
10
|
-
- Shared component logic/renderer split (`*.tsx`, `*.web.tsx`, `*.tui.tsx`)
|
|
11
|
-
- Shared workspace/project lifecycle orchestration (`core/workspace-lifecycle.ts`, `core/project-lifecycle.ts`)
|
|
12
|
-
- Shared relay machine-directory client (`src/relay-client/machine-directory-client.ts`)
|
|
13
|
-
- Shared relay machine-directory hook (`src/relay-client/useMachineDirectory.ts`) used by web+tui wrappers
|
|
14
|
-
- Shared session engine foundation (`src/session/*`)
|
|
15
|
-
- Shared remote/local backend adapters (`src/session/backends/*`)
|
|
16
|
-
- Shared remote session hook (`src/session/useRemoteSessionClient.ts`) used by web+tui wrappers
|
|
17
|
-
- Web remote terminal flow migrated to shared session backend
|
|
18
|
-
- TUI remote machine screen migrated to shared remote backend + remote terminal transport
|
|
19
|
-
- TUI local projects/workspaces/sessions/inbox state now sourced from shared local backend via `useLocalSession`
|
|
20
|
-
- TUI local terminal attach/detach/PTY lifecycle is now backend-driven via `LocalSessionBackend`
|
|
21
|
-
- TUI project/workspace panels now consume shared local backend state directly (legacy sync bridge removed)
|
|
22
|
-
- Legacy TUI-only state/adapter modules removed (`tui/state.ts`, `tui/adapters.ts`, `tui/hooks/useInboxTUI.ts`)
|
|
23
|
-
- Shared project catalog service (`core/project-catalog.ts`) used by CLI list + local backend + remote session handler
|
|
24
|
-
|
|
25
|
-
## Goals
|
|
26
|
-
|
|
27
|
-
1. Shared core behavior across platforms.
|
|
28
|
-
2. Platform differences isolated to renderer/input/transport adapters.
|
|
29
|
-
3. Remote and local machines represented through the same backend contract.
|
|
30
|
-
|
|
31
|
-
## Canonical Model
|
|
32
|
-
|
|
33
|
-
### 1) Session Engine (Shared)
|
|
34
|
-
|
|
35
|
-
`src/session/`
|
|
36
|
-
|
|
37
|
-
- `types.ts`: canonical backend/session state
|
|
38
|
-
- `events.ts`: normalized backend event contract
|
|
39
|
-
- `reducer.ts`: deterministic state transitions
|
|
40
|
-
- `backend-manager.ts`: backend registration + event routing
|
|
41
|
-
- `useSessionEngine.ts`: React hook API for platform UIs
|
|
42
|
-
- `useRemoteSessionClient.ts`: shared remote terminal/session orchestration hook used by platform wrappers
|
|
43
|
-
|
|
44
|
-
Key state shape:
|
|
45
|
-
|
|
46
|
-
- Backends keyed by descriptor (`local`, `remote:<relay>:<machine>`)
|
|
47
|
-
- Per-backend status, projects, workspaces, sessions, inbox, notification config, attach/script runtime state
|
|
48
|
-
- Active backend selection for UI focus
|
|
49
|
-
|
|
50
|
-
### 2) Backend Contract (Shared)
|
|
51
|
-
|
|
52
|
-
`src/session/backend.ts`
|
|
53
|
-
|
|
54
|
-
All local/remote machine operations are expressed through `SessionBackend`:
|
|
55
|
-
|
|
56
|
-
- connect/disconnect
|
|
57
|
-
- list projects/workspaces/sessions
|
|
58
|
-
- attach/detach/kill/delete
|
|
59
|
-
- inbox read/clear/fetch
|
|
60
|
-
- notification config get/update
|
|
61
|
-
- PTY write/resize (optional)
|
|
62
|
-
- event subscription
|
|
63
|
-
|
|
64
|
-
### 3) Backend Implementations
|
|
65
|
-
|
|
66
|
-
#### Remote backend
|
|
67
|
-
|
|
68
|
-
`src/session/backends/remote-session-backend.ts`
|
|
69
|
-
|
|
70
|
-
- Owns relay handshake lifecycle (X3DH adapters)
|
|
71
|
-
- Owns encrypted frame encode/decode adapters
|
|
72
|
-
- Speaks canonical remote-session protocol (`list_*`, `attach_session`, inbox/config/script-output, etc.)
|
|
73
|
-
- Emits normalized backend events
|
|
74
|
-
|
|
75
|
-
#### Local backend
|
|
76
|
-
|
|
77
|
-
`src/session/backends/local-session-backend.ts`
|
|
78
|
-
|
|
79
|
-
- Wraps local tmux/config/workspace lifecycle operations
|
|
80
|
-
- Maps local operations to the same backend event model as remote
|
|
81
|
-
|
|
82
|
-
## Platform Integration
|
|
83
|
-
|
|
84
|
-
### Web
|
|
85
|
-
|
|
86
|
-
- Relay directory: `src/hooks/useRelayConnection.web.ts`
|
|
87
|
-
- Terminal/session: `src/hooks/useTerminal.web.ts`
|
|
88
|
-
|
|
89
|
-
`useRelayConnection` and `useTerminal` are now thin adapters over shared relay/session hooks.
|
|
90
|
-
|
|
91
|
-
### TUI
|
|
92
|
-
|
|
93
|
-
- Relay directory: `src/hooks/useRemoteMachines.tui.ts`
|
|
94
|
-
- Remote terminal/session: `src/hooks/useRemoteTerminal.tui.ts`
|
|
95
|
-
- Remote attached renderer: `src/components/SessionTerminal.tui.tsx`
|
|
96
|
-
- Remote machine screen: `src/components/RemoteMachineScreen.tui.tsx`
|
|
97
|
-
|
|
98
|
-
Current TUI state split:
|
|
99
|
-
|
|
100
|
-
- Remote machine path uses shared remote backend.
|
|
101
|
-
- Local machine path uses shared local backend for projects/workspaces/sessions/inbox and terminal attach lifecycle.
|
|
102
|
-
- Project/workspace panel rendering reads backend state directly; local reducer now tracks only UI view/focus/loading/error state.
|
|
103
|
-
|
|
104
|
-
### CLI
|
|
105
|
-
|
|
106
|
-
- Project listing now shares project catalog logic through `src/core/project-catalog.ts`.
|
|
107
|
-
- Remote connect now uses shared remote backend adapters (`RemoteSessionBackend` + node adapters), matching TUI/Web session protocol flow.
|
|
108
|
-
|
|
109
|
-
## Data Flow
|
|
110
|
-
|
|
111
|
-
1. Platform creates backend(s) with descriptor + transport/crypto/handshake adapters.
|
|
112
|
-
2. Backend registers with `useSessionEngine`.
|
|
113
|
-
3. UI calls engine actions (`listWorkspaces`, `attachSession`, `requestInbox`, etc.).
|
|
114
|
-
4. Backend emits canonical events.
|
|
115
|
-
5. Engine reducer updates state.
|
|
116
|
-
6. Renderer consumes normalized state.
|
|
117
|
-
|
|
118
|
-
## Testing
|
|
119
|
-
|
|
120
|
-
Added/updated tests around the shared architecture:
|
|
121
|
-
|
|
122
|
-
- `src/session/__tests__/reducer.test.ts`
|
|
123
|
-
- `src/session/__tests__/backend-manager.test.ts`
|
|
124
|
-
- `src/session/__tests__/remote-session-backend.test.ts`
|
|
125
|
-
- `src/session/__tests__/local-session-backend.test.ts`
|
|
126
|
-
- `src/hooks/__tests__/useLocalSession.tui.test.ts`
|
|
127
|
-
- `src/tui/__tests__/local-terminal-sync.test.ts`
|
|
128
|
-
|
|
129
|
-
## Final Migration Target
|
|
130
|
-
|
|
131
|
-
When migration is complete:
|
|
132
|
-
|
|
133
|
-
- TUI and Web both run entirely on shared session engine state.
|
|
134
|
-
- Local and remote use the same backend contract.
|
|
135
|
-
- Platform-specific code is limited to:
|
|
136
|
-
- renderers (`*.web.tsx`, `*.tui.tsx`)
|
|
137
|
-
- UI input handling
|
|
138
|
-
- transport/crypto adapter wiring.
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PTY over Unix Socket Benchmark
|
|
3
|
-
* Tests latency and throughput of piping PTY data over Unix domain sockets
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { unlinkSync } from "fs";
|
|
7
|
-
|
|
8
|
-
const SOCKET_PATH = "/tmp/spaces-pty-bench.sock";
|
|
9
|
-
|
|
10
|
-
// Clean up any existing socket
|
|
11
|
-
try { unlinkSync(SOCKET_PATH); } catch {}
|
|
12
|
-
|
|
13
|
-
// ============== SERVER ==============
|
|
14
|
-
let serverTerminal: Bun.Terminal | null = null;
|
|
15
|
-
let serverProc: Bun.Subprocess | null = null;
|
|
16
|
-
|
|
17
|
-
const server = Bun.listen({
|
|
18
|
-
unix: SOCKET_PATH,
|
|
19
|
-
socket: {
|
|
20
|
-
open(socket) {
|
|
21
|
-
console.log("[server] Client connected");
|
|
22
|
-
},
|
|
23
|
-
data(socket, data) {
|
|
24
|
-
const msg = data.toString();
|
|
25
|
-
|
|
26
|
-
if (msg.startsWith("{")) {
|
|
27
|
-
const cmd = JSON.parse(msg);
|
|
28
|
-
|
|
29
|
-
if (cmd.type === "run") {
|
|
30
|
-
serverTerminal = new Bun.Terminal({
|
|
31
|
-
cols: 120,
|
|
32
|
-
rows: 40,
|
|
33
|
-
data(term, output) {
|
|
34
|
-
socket.write(output);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
serverProc = Bun.spawn(cmd.args, {
|
|
39
|
-
terminal: serverTerminal,
|
|
40
|
-
cwd: process.cwd(),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
serverProc.exited.then(code => {
|
|
44
|
-
socket.write(`\n__EXIT__${code}__`);
|
|
45
|
-
});
|
|
46
|
-
} else if (cmd.type === "resize") {
|
|
47
|
-
serverTerminal?.resize(cmd.cols, cmd.rows);
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
serverTerminal?.write(data);
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
close(socket) {
|
|
54
|
-
serverProc?.kill();
|
|
55
|
-
serverTerminal?.close();
|
|
56
|
-
},
|
|
57
|
-
error(socket, error) {
|
|
58
|
-
console.error("[server] Error:", error);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
console.log(`[server] Listening on ${SOCKET_PATH}`);
|
|
64
|
-
|
|
65
|
-
// ============== CLIENT ==============
|
|
66
|
-
await Bun.sleep(50);
|
|
67
|
-
|
|
68
|
-
let bytesReceived = 0;
|
|
69
|
-
let messagesReceived = 0;
|
|
70
|
-
let startTime = 0;
|
|
71
|
-
let firstByteTime = 0;
|
|
72
|
-
let testResolve: () => void;
|
|
73
|
-
|
|
74
|
-
const client = await Bun.connect({
|
|
75
|
-
unix: SOCKET_PATH,
|
|
76
|
-
socket: {
|
|
77
|
-
open(socket) {
|
|
78
|
-
console.log("[client] Connected via Unix socket\n");
|
|
79
|
-
},
|
|
80
|
-
data(socket, data) {
|
|
81
|
-
messagesReceived++;
|
|
82
|
-
bytesReceived += data.byteLength;
|
|
83
|
-
|
|
84
|
-
if (firstByteTime === 0) {
|
|
85
|
-
firstByteTime = performance.now();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const str = data.toString();
|
|
89
|
-
if (str.includes("__EXIT__")) {
|
|
90
|
-
const elapsed = performance.now() - startTime;
|
|
91
|
-
const throughput = (bytesReceived / 1024 / 1024) / (elapsed / 1000);
|
|
92
|
-
const latency = firstByteTime - startTime;
|
|
93
|
-
|
|
94
|
-
console.log(`\n--- Results ---`);
|
|
95
|
-
console.log(`Bytes: ${(bytesReceived / 1024).toFixed(2)} KB`);
|
|
96
|
-
console.log(`Chunks: ${messagesReceived}`);
|
|
97
|
-
console.log(`Time: ${elapsed.toFixed(2)} ms`);
|
|
98
|
-
console.log(`Throughput: ${throughput.toFixed(2)} MB/s`);
|
|
99
|
-
console.log(`First byte: ${latency.toFixed(3)} ms`);
|
|
100
|
-
testResolve?.();
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
error(socket, error) {
|
|
104
|
-
console.error("[client] Error:", error);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
async function runTest(name: string, args: string[], waitMs = 2000) {
|
|
110
|
-
console.log(`=== ${name} ===`);
|
|
111
|
-
bytesReceived = 0;
|
|
112
|
-
messagesReceived = 0;
|
|
113
|
-
firstByteTime = 0;
|
|
114
|
-
|
|
115
|
-
const done = new Promise<void>(r => { testResolve = r; });
|
|
116
|
-
startTime = performance.now();
|
|
117
|
-
client.write(JSON.stringify({ type: "run", args }));
|
|
118
|
-
|
|
119
|
-
await Promise.race([done, Bun.sleep(waitMs)]);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await runTest("Latency: echo", ["echo", "hello"], 500);
|
|
123
|
-
await runTest("Throughput: seq 50k", ["seq", "1", "50000"], 3000);
|
|
124
|
-
await runTest("Realistic: ls -laR", ["ls", "-laR", "/usr/bin"], 5000);
|
|
125
|
-
|
|
126
|
-
// Interactive test
|
|
127
|
-
console.log("\n=== Interactive: bash session ===");
|
|
128
|
-
bytesReceived = 0;
|
|
129
|
-
messagesReceived = 0;
|
|
130
|
-
firstByteTime = 0;
|
|
131
|
-
startTime = performance.now();
|
|
132
|
-
|
|
133
|
-
client.write(JSON.stringify({ type: "run", args: ["bash"] }));
|
|
134
|
-
await Bun.sleep(100);
|
|
135
|
-
|
|
136
|
-
for (const cmd of ["echo test", "ls", "pwd", "exit"]) {
|
|
137
|
-
await Bun.sleep(30);
|
|
138
|
-
client.write(cmd + "\n");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
await Bun.sleep(300);
|
|
142
|
-
console.log(`Interactive: ${(bytesReceived/1024).toFixed(2)} KB in ${(performance.now()-startTime).toFixed(0)} ms`);
|
|
143
|
-
|
|
144
|
-
server.stop();
|
|
145
|
-
client.end();
|
|
146
|
-
try { unlinkSync(SOCKET_PATH); } catch {}
|
|
147
|
-
console.log("\n✓ Done");
|
|
148
|
-
process.exit(0);
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure latency test - measure keystroke round-trip time
|
|
3
|
-
*/
|
|
4
|
-
import { unlinkSync } from "fs";
|
|
5
|
-
|
|
6
|
-
const SOCKET_PATH = "/tmp/spaces-latency.sock";
|
|
7
|
-
try { unlinkSync(SOCKET_PATH); } catch {}
|
|
8
|
-
|
|
9
|
-
let terminal: Bun.Terminal;
|
|
10
|
-
let clientSocket: any;
|
|
11
|
-
|
|
12
|
-
const server = Bun.listen({
|
|
13
|
-
unix: SOCKET_PATH,
|
|
14
|
-
socket: {
|
|
15
|
-
open(socket) {
|
|
16
|
-
clientSocket = socket;
|
|
17
|
-
terminal = new Bun.Terminal({
|
|
18
|
-
cols: 80,
|
|
19
|
-
rows: 24,
|
|
20
|
-
data(term, output) {
|
|
21
|
-
socket.write(output);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Spawn cat - echoes input immediately
|
|
26
|
-
Bun.spawn(["cat"], { terminal });
|
|
27
|
-
},
|
|
28
|
-
data(socket, data) {
|
|
29
|
-
terminal.write(data);
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
await Bun.sleep(50);
|
|
35
|
-
|
|
36
|
-
const latencies: number[] = [];
|
|
37
|
-
let pendingResolve: ((t: number) => void) | null = null;
|
|
38
|
-
let sendTime = 0;
|
|
39
|
-
|
|
40
|
-
const client = await Bun.connect({
|
|
41
|
-
unix: SOCKET_PATH,
|
|
42
|
-
socket: {
|
|
43
|
-
data(socket, data) {
|
|
44
|
-
if (pendingResolve) {
|
|
45
|
-
const latency = performance.now() - sendTime;
|
|
46
|
-
pendingResolve(latency);
|
|
47
|
-
pendingResolve = null;
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
async function measureRoundTrip(): Promise<number> {
|
|
54
|
-
return new Promise(resolve => {
|
|
55
|
-
pendingResolve = resolve;
|
|
56
|
-
sendTime = performance.now();
|
|
57
|
-
client.write("x");
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Warmup
|
|
62
|
-
for (let i = 0; i < 10; i++) {
|
|
63
|
-
await measureRoundTrip();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Measure
|
|
67
|
-
console.log("Measuring 1000 keystroke round-trips over Unix socket...\n");
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < 1000; i++) {
|
|
70
|
-
const lat = await measureRoundTrip();
|
|
71
|
-
latencies.push(lat);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
latencies.sort((a, b) => a - b);
|
|
75
|
-
|
|
76
|
-
const avg = latencies.reduce((a, b) => a + b) / latencies.length;
|
|
77
|
-
const p50 = latencies[Math.floor(latencies.length * 0.5)];
|
|
78
|
-
const p95 = latencies[Math.floor(latencies.length * 0.95)];
|
|
79
|
-
const p99 = latencies[Math.floor(latencies.length * 0.99)];
|
|
80
|
-
const min = latencies[0];
|
|
81
|
-
const max = latencies[latencies.length - 1];
|
|
82
|
-
|
|
83
|
-
console.log("=== Keystroke Round-Trip Latency ===");
|
|
84
|
-
console.log(`Min: ${min.toFixed(3)} ms`);
|
|
85
|
-
console.log(`Avg: ${avg.toFixed(3)} ms`);
|
|
86
|
-
console.log(`P50: ${p50.toFixed(3)} ms`);
|
|
87
|
-
console.log(`P95: ${p95.toFixed(3)} ms`);
|
|
88
|
-
console.log(`P99: ${p99.toFixed(3)} ms`);
|
|
89
|
-
console.log(`Max: ${max.toFixed(3)} ms`);
|
|
90
|
-
|
|
91
|
-
// Compare to typical human perception
|
|
92
|
-
console.log("\n=== Context ===");
|
|
93
|
-
console.log(`Human perception threshold: ~13ms`);
|
|
94
|
-
console.log(`60 FPS frame time: 16.67ms`);
|
|
95
|
-
console.log(`Typical SSH local: 1-5ms`);
|
|
96
|
-
console.log(`Typical SSH remote: 20-100ms`);
|
|
97
|
-
|
|
98
|
-
server.stop();
|
|
99
|
-
client.end();
|
|
100
|
-
try { unlinkSync(SOCKET_PATH); } catch {}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Client - connects to router, attaches to session
|
|
4
|
-
*
|
|
5
|
-
* Usage: bun client.ts [project] [workspace]
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { select } from "@inquirer/prompts";
|
|
9
|
-
import {
|
|
10
|
-
ROUTER_SOCKET,
|
|
11
|
-
type RouterCommand,
|
|
12
|
-
type RouterResponse,
|
|
13
|
-
type SessionInfo,
|
|
14
|
-
type AttachMode,
|
|
15
|
-
encodeControl,
|
|
16
|
-
isControl,
|
|
17
|
-
decodeControl,
|
|
18
|
-
type SessionEvent,
|
|
19
|
-
} from "./protocol";
|
|
20
|
-
|
|
21
|
-
const [project = "test", workspace = "default"] = process.argv.slice(2);
|
|
22
|
-
|
|
23
|
-
// Connect to router
|
|
24
|
-
async function routerCommand(cmd: RouterCommand): Promise<RouterResponse> {
|
|
25
|
-
return new Promise(async (resolve, reject) => {
|
|
26
|
-
const socket = await Bun.connect({
|
|
27
|
-
unix: ROUTER_SOCKET,
|
|
28
|
-
socket: {
|
|
29
|
-
data(socket, data) {
|
|
30
|
-
resolve(JSON.parse(data.toString()));
|
|
31
|
-
socket.end();
|
|
32
|
-
},
|
|
33
|
-
error(socket, error) {
|
|
34
|
-
reject(error);
|
|
35
|
-
},
|
|
36
|
-
connectError(socket, error) {
|
|
37
|
-
reject(new Error("Router not running. Start with: bun router.ts"));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
socket.write(JSON.stringify(cmd));
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Get or create session
|
|
47
|
-
console.log(`Connecting to ${project}/${workspace}...`);
|
|
48
|
-
|
|
49
|
-
let session: SessionInfo;
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
let response = await routerCommand({
|
|
53
|
-
type: "create",
|
|
54
|
-
project,
|
|
55
|
-
workspace,
|
|
56
|
-
cwd: process.cwd()
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Handle already-attached case
|
|
60
|
-
if (response.type === "already-attached") {
|
|
61
|
-
console.log(`\nSession "${project}/${workspace}" is already attached.\n`);
|
|
62
|
-
|
|
63
|
-
const choice = await select({
|
|
64
|
-
message: "What would you like to do?",
|
|
65
|
-
choices: [
|
|
66
|
-
{ value: "take-over", name: "Take over (disconnect other client)" },
|
|
67
|
-
{ value: "new", name: "Create new session for this workspace" },
|
|
68
|
-
{ value: "cancel", name: "Cancel" },
|
|
69
|
-
]
|
|
70
|
-
}) as AttachMode;
|
|
71
|
-
|
|
72
|
-
if (choice === "cancel") {
|
|
73
|
-
console.log("Cancelled.");
|
|
74
|
-
process.exit(0);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (choice === "take-over") {
|
|
78
|
-
// Attach with take-over mode
|
|
79
|
-
response = await routerCommand({
|
|
80
|
-
type: "attach",
|
|
81
|
-
sessionId: response.session.id,
|
|
82
|
-
mode: "take-over"
|
|
83
|
-
});
|
|
84
|
-
} else if (choice === "new") {
|
|
85
|
-
// Force create new session (kill old one first, then create)
|
|
86
|
-
await routerCommand({ type: "kill", sessionId: response.session.id });
|
|
87
|
-
response = await routerCommand({
|
|
88
|
-
type: "create",
|
|
89
|
-
project,
|
|
90
|
-
workspace,
|
|
91
|
-
cwd: process.cwd()
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (response.type === "error") {
|
|
97
|
-
console.error("Error:", response.message);
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (response.type !== "created") {
|
|
102
|
-
console.error("Unexpected response:", response);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
session = response.session;
|
|
107
|
-
} catch (e: any) {
|
|
108
|
-
console.error(e.message);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
console.log(`Attached to session ${session.id}`);
|
|
113
|
-
console.log("Press Ctrl+D to detach\n");
|
|
114
|
-
|
|
115
|
-
// Connect to session
|
|
116
|
-
const sessionSocket = await Bun.connect({
|
|
117
|
-
unix: session.socketPath,
|
|
118
|
-
socket: {
|
|
119
|
-
data(socket, data) {
|
|
120
|
-
const buf = Buffer.from(data);
|
|
121
|
-
|
|
122
|
-
if (isControl(buf)) {
|
|
123
|
-
const event = decodeControl(buf) as SessionEvent;
|
|
124
|
-
|
|
125
|
-
switch (event.type) {
|
|
126
|
-
case "attached":
|
|
127
|
-
// Replay scrollback
|
|
128
|
-
if (event.scrollback) {
|
|
129
|
-
const scrollback = Buffer.from(event.scrollback, "base64");
|
|
130
|
-
process.stdout.write(scrollback);
|
|
131
|
-
}
|
|
132
|
-
break;
|
|
133
|
-
|
|
134
|
-
case "exited":
|
|
135
|
-
process.stdin.setRawMode(false);
|
|
136
|
-
console.log(`\nSession exited with code ${event.code}`);
|
|
137
|
-
process.exit(event.code);
|
|
138
|
-
break;
|
|
139
|
-
|
|
140
|
-
case "kicked":
|
|
141
|
-
process.stdin.setRawMode(false);
|
|
142
|
-
console.log("\n\nAnother client took over this session.");
|
|
143
|
-
process.exit(0);
|
|
144
|
-
break;
|
|
145
|
-
|
|
146
|
-
case "pong":
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
// PTY output - write to terminal
|
|
151
|
-
process.stdout.write(buf);
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
close() {
|
|
156
|
-
process.stdin.setRawMode(false);
|
|
157
|
-
console.log("\nDisconnected from session");
|
|
158
|
-
process.exit(0);
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
error(socket, error) {
|
|
162
|
-
process.stdin.setRawMode(false);
|
|
163
|
-
console.error("\nSession error:", error.message);
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Send initial resize
|
|
170
|
-
sessionSocket.write(encodeControl({
|
|
171
|
-
type: "resize",
|
|
172
|
-
cols: process.stdout.columns || 80,
|
|
173
|
-
rows: process.stdout.rows || 24
|
|
174
|
-
}));
|
|
175
|
-
|
|
176
|
-
// Handle terminal resize
|
|
177
|
-
process.stdout.on("resize", () => {
|
|
178
|
-
sessionSocket.write(encodeControl({
|
|
179
|
-
type: "resize",
|
|
180
|
-
cols: process.stdout.columns,
|
|
181
|
-
rows: process.stdout.rows
|
|
182
|
-
}));
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Forward stdin to session
|
|
186
|
-
process.stdin.setRawMode(true);
|
|
187
|
-
process.stdin.resume();
|
|
188
|
-
|
|
189
|
-
for await (const chunk of process.stdin) {
|
|
190
|
-
// Check for Ctrl+D (detach)
|
|
191
|
-
if (chunk[0] === 4) {
|
|
192
|
-
sessionSocket.write(encodeControl({ type: "detach" }));
|
|
193
|
-
process.stdin.setRawMode(false);
|
|
194
|
-
console.log("\nDetached (session still running)");
|
|
195
|
-
process.exit(0);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
sessionSocket.write(chunk);
|
|
199
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared protocol between router, sessions, and clients
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export const ROUTER_SOCKET = "/tmp/spaces-router.sock";
|
|
6
|
-
export const SESSION_SOCKET_PREFIX = "/tmp/spaces-session-";
|
|
7
|
-
|
|
8
|
-
// Router commands (JSON over socket)
|
|
9
|
-
export type RouterCommand =
|
|
10
|
-
| { type: "list" }
|
|
11
|
-
| { type: "create"; project: string; workspace: string; cwd: string }
|
|
12
|
-
| { type: "attach"; sessionId: string; mode?: AttachMode }
|
|
13
|
-
| { type: "kill"; sessionId: string }
|
|
14
|
-
| { type: "kick"; sessionId: string }; // Disconnect current client
|
|
15
|
-
|
|
16
|
-
export type RouterResponse =
|
|
17
|
-
| { type: "sessions"; sessions: SessionInfo[] }
|
|
18
|
-
| { type: "created"; session: SessionInfo }
|
|
19
|
-
| { type: "already-attached"; session: SessionInfo } // Session exists but has a client
|
|
20
|
-
| { type: "error"; message: string }
|
|
21
|
-
| { type: "ok" };
|
|
22
|
-
|
|
23
|
-
export interface SessionInfo {
|
|
24
|
-
id: string;
|
|
25
|
-
project: string;
|
|
26
|
-
workspace: string;
|
|
27
|
-
socketPath: string;
|
|
28
|
-
pid: number;
|
|
29
|
-
attached: boolean; // true if a client is connected
|
|
30
|
-
createdAt: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// When attaching to an already-attached session
|
|
34
|
-
export type AttachMode =
|
|
35
|
-
| "take-over" // Disconnect existing client, you take over
|
|
36
|
-
| "new" // Create a new session for the same workspace
|
|
37
|
-
| "cancel"; // Abort
|
|
38
|
-
|
|
39
|
-
// Session protocol (binary + JSON control)
|
|
40
|
-
// Control messages start with 0x00, data is raw bytes
|
|
41
|
-
export const CONTROL_PREFIX = 0x00;
|
|
42
|
-
|
|
43
|
-
export type SessionControl =
|
|
44
|
-
| { type: "resize"; cols: number; rows: number }
|
|
45
|
-
| { type: "detach" }
|
|
46
|
-
| { type: "ping" };
|
|
47
|
-
|
|
48
|
-
export type SessionEvent =
|
|
49
|
-
| { type: "attached"; scrollback: string }
|
|
50
|
-
| { type: "exited"; code: number }
|
|
51
|
-
| { type: "kicked" } // Another client took over
|
|
52
|
-
| { type: "pong" };
|
|
53
|
-
|
|
54
|
-
// Helper to encode control message
|
|
55
|
-
export function encodeControl(msg: SessionControl | SessionEvent): Buffer {
|
|
56
|
-
const json = JSON.stringify(msg);
|
|
57
|
-
const buf = Buffer.alloc(1 + 4 + json.length);
|
|
58
|
-
buf[0] = CONTROL_PREFIX;
|
|
59
|
-
buf.writeUInt32BE(json.length, 1);
|
|
60
|
-
buf.write(json, 5);
|
|
61
|
-
return buf;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Helper to check if data is control message
|
|
65
|
-
export function isControl(data: Buffer): boolean {
|
|
66
|
-
return data[0] === CONTROL_PREFIX;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Helper to decode control message
|
|
70
|
-
export function decodeControl(data: Buffer): SessionControl | SessionEvent {
|
|
71
|
-
const len = data.readUInt32BE(1);
|
|
72
|
-
const json = data.subarray(5, 5 + len).toString();
|
|
73
|
-
return JSON.parse(json);
|
|
74
|
-
}
|