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
package/src/commands/connect.ts
DELETED
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connect command implementation
|
|
3
|
-
*
|
|
4
|
-
* Handles 'gssh connect <invite>' to connect to a remote machine
|
|
5
|
-
* via an invite token or URL, or lists available machines when no
|
|
6
|
-
* invite is provided.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { logger } from '../utils/logger.js';
|
|
10
|
-
import { promptPassword, promptConfirm, promptInput, selectOne } from '../utils/prompts.js';
|
|
11
|
-
import { loadKeypair, keypairExists } from '../core/identity.js';
|
|
12
|
-
import { parseInviteToken, isInviteExpired } from '../lib/tmux-lite/crypto/invites.js';
|
|
13
|
-
import WebSocket from 'ws';
|
|
14
|
-
import { createHash } from 'crypto';
|
|
15
|
-
import { buildRemoteBackendKey } from './connect-key.js';
|
|
16
|
-
import {
|
|
17
|
-
RemoteSessionBackend,
|
|
18
|
-
nodeRemoteSocketAdapter,
|
|
19
|
-
nodeRemoteCryptoAdapter,
|
|
20
|
-
nodeRemoteHandshakeAdapter,
|
|
21
|
-
createNodeRelaySigner,
|
|
22
|
-
type BackendEvent,
|
|
23
|
-
} from '../session/index.js';
|
|
24
|
-
import {
|
|
25
|
-
NoIdentityError,
|
|
26
|
-
SpacesError,
|
|
27
|
-
} from '../types/errors.js';
|
|
28
|
-
import type { InviteToken } from '../types/identity.js';
|
|
29
|
-
import type {
|
|
30
|
-
WorkspaceInfo,
|
|
31
|
-
} from '../lib/remote-session/protocol.js';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Connect to a remote machine via invite token
|
|
35
|
-
*
|
|
36
|
-
* @param inviteTokenOrUrl - Invite token (base64url) or URL containing token
|
|
37
|
-
* @param options - Command options
|
|
38
|
-
*/
|
|
39
|
-
export async function connectToRemote(
|
|
40
|
-
inviteTokenOrUrl?: string,
|
|
41
|
-
options: { relay?: string } = {}
|
|
42
|
-
): Promise<void> {
|
|
43
|
-
// Invite is required for connection
|
|
44
|
-
if (!inviteTokenOrUrl) {
|
|
45
|
-
throw new SpacesError(
|
|
46
|
-
'Invite token or URL required.\n\nUsage:\n gssh connect <invite-url>\n gssh connect <invite-token>\n\nGet an invite from the machine owner using:\n gssh share create',
|
|
47
|
-
'USER_ERROR',
|
|
48
|
-
1
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Step 1: Parse invite from URL or raw token
|
|
53
|
-
const token = extractAndValidateToken(inviteTokenOrUrl);
|
|
54
|
-
|
|
55
|
-
// Step 2: Display connection details and confirm
|
|
56
|
-
displayConnectionDetails(token);
|
|
57
|
-
|
|
58
|
-
const confirmed = await promptConfirm('Connect to this machine?', true);
|
|
59
|
-
if (!confirmed) {
|
|
60
|
-
logger.info('Cancelled');
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Step 3: Load local identity
|
|
65
|
-
if (!keypairExists()) {
|
|
66
|
-
throw new NoIdentityError();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const password = await promptPassword('Enter password to unlock identity:');
|
|
70
|
-
if (!password) {
|
|
71
|
-
logger.info('Cancelled');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const identity = await loadKeypair(password);
|
|
76
|
-
if (!identity) {
|
|
77
|
-
throw new SpacesError(
|
|
78
|
-
'Failed to unlock identity. Check your password.',
|
|
79
|
-
'USER_ERROR',
|
|
80
|
-
1
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Step 4: Connect to relay and establish remote session backend
|
|
85
|
-
const relayUrl = options.relay ?? token.relayUrl;
|
|
86
|
-
const rawInviteToken =
|
|
87
|
-
inviteTokenOrUrl.includes('#')
|
|
88
|
-
? extractTokenFromUrl(inviteTokenOrUrl) ?? inviteTokenOrUrl
|
|
89
|
-
: inviteTokenOrUrl;
|
|
90
|
-
const inviteId = createHash('sha256').update(rawInviteToken).digest('hex').substring(0, 16);
|
|
91
|
-
|
|
92
|
-
logger.info('Connecting to relay...');
|
|
93
|
-
|
|
94
|
-
const socketUrl = new URL(relayUrl);
|
|
95
|
-
socketUrl.searchParams.set('role', 'client');
|
|
96
|
-
|
|
97
|
-
const backendKey = buildRemoteBackendKey(relayUrl, token.machineId);
|
|
98
|
-
const backend = new RemoteSessionBackend({
|
|
99
|
-
descriptor: {
|
|
100
|
-
key: backendKey,
|
|
101
|
-
kind: 'remote',
|
|
102
|
-
label: token.machineId,
|
|
103
|
-
relayUrl,
|
|
104
|
-
machineId: token.machineId,
|
|
105
|
-
},
|
|
106
|
-
socket: new WebSocket(socketUrl.toString()),
|
|
107
|
-
socketAdapter: nodeRemoteSocketAdapter,
|
|
108
|
-
identity,
|
|
109
|
-
machineId: token.machineId,
|
|
110
|
-
inviteId,
|
|
111
|
-
inviteToken: rawInviteToken,
|
|
112
|
-
signer: (message, identity) => createNodeRelaySigner(identity)(message),
|
|
113
|
-
crypto: nodeRemoteCryptoAdapter,
|
|
114
|
-
handshake: nodeRemoteHandshakeAdapter,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
backend.setPtyOutputHandler((data) => {
|
|
118
|
-
process.stdout.write(Buffer.from(data));
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
let backendConnected = false;
|
|
122
|
-
const disconnectBackend = async () => {
|
|
123
|
-
if (!backendConnected) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
await backend.disconnect();
|
|
129
|
-
} catch (error) {
|
|
130
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
131
|
-
logger.error(`Failed to disconnect cleanly: ${detail}`);
|
|
132
|
-
} finally {
|
|
133
|
-
backendConnected = false;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
await backend.connect();
|
|
139
|
-
backendConnected = true;
|
|
140
|
-
} catch (error) {
|
|
141
|
-
if (error instanceof Error) {
|
|
142
|
-
throw new SpacesError(
|
|
143
|
-
`Connection failed: ${error.message}`,
|
|
144
|
-
'SYSTEM_ERROR',
|
|
145
|
-
2
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
logger.success('Connected!');
|
|
152
|
-
logger.log('');
|
|
153
|
-
logger.dim(`Access: ${token.accessType === 'full' ? 'Full access' : 'Session invite'}`);
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
const terminalSize = getTerminalSize();
|
|
157
|
-
let attachWait: {
|
|
158
|
-
promise: Promise<Extract<BackendEvent, { type: 'attached' }>>;
|
|
159
|
-
cancel: () => void;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
if (token.accessType === 'session-invite' && token.sessionId) {
|
|
163
|
-
logger.dim(`Session: ${token.sessionId}`);
|
|
164
|
-
attachWait = waitForBackendEvent(
|
|
165
|
-
backend,
|
|
166
|
-
(event): event is Extract<BackendEvent, { type: 'attached' }> => event.type === 'attached',
|
|
167
|
-
30000,
|
|
168
|
-
'attach confirmation'
|
|
169
|
-
);
|
|
170
|
-
try {
|
|
171
|
-
await backend.attachSession({
|
|
172
|
-
sessionId: token.sessionId,
|
|
173
|
-
cols: terminalSize.cols,
|
|
174
|
-
rows: terminalSize.rows,
|
|
175
|
-
});
|
|
176
|
-
} catch (error) {
|
|
177
|
-
attachWait.cancel();
|
|
178
|
-
throw error;
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
const workspace = await selectWorkspaceForFullAccess(backend);
|
|
182
|
-
if (!workspace) {
|
|
183
|
-
logger.info('Cancelled');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const sessionName = await promptInput('Session name (optional):');
|
|
188
|
-
if (sessionName === null) {
|
|
189
|
-
logger.info('Cancelled');
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
attachWait = waitForBackendEvent(
|
|
194
|
-
backend,
|
|
195
|
-
(event): event is Extract<BackendEvent, { type: 'attached' }> => event.type === 'attached',
|
|
196
|
-
30000,
|
|
197
|
-
'attach confirmation'
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
await backend.attachSession({
|
|
202
|
-
workspaceId: workspace.id,
|
|
203
|
-
sessionName: sessionName || undefined,
|
|
204
|
-
cols: terminalSize.cols,
|
|
205
|
-
rows: terminalSize.rows,
|
|
206
|
-
});
|
|
207
|
-
} catch (error) {
|
|
208
|
-
attachWait.cancel();
|
|
209
|
-
throw error;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const attached = await attachWait.promise;
|
|
214
|
-
logger.success(`Attached to ${attached.sessionName ?? attached.sessionId}`);
|
|
215
|
-
logger.log('');
|
|
216
|
-
logger.dim('Press Ctrl+D to disconnect');
|
|
217
|
-
logger.log('');
|
|
218
|
-
|
|
219
|
-
await startTerminalSession(backend);
|
|
220
|
-
backendConnected = false;
|
|
221
|
-
} finally {
|
|
222
|
-
await disconnectBackend();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Extract token from URL or validate raw token
|
|
228
|
-
*/
|
|
229
|
-
function extractAndValidateToken(input: string): InviteToken {
|
|
230
|
-
// Try to extract from URL
|
|
231
|
-
let rawToken = input;
|
|
232
|
-
|
|
233
|
-
if (input.includes('#')) {
|
|
234
|
-
const extracted = extractTokenFromUrl(input);
|
|
235
|
-
if (extracted) {
|
|
236
|
-
rawToken = extracted;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Parse and validate token
|
|
241
|
-
const token = parseInviteToken(rawToken);
|
|
242
|
-
if (!token) {
|
|
243
|
-
throw new SpacesError(
|
|
244
|
-
'Invalid invite token. Check that the token is complete and not corrupted.',
|
|
245
|
-
'USER_ERROR',
|
|
246
|
-
1
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (isInviteExpired(token)) {
|
|
251
|
-
throw new SpacesError(
|
|
252
|
-
'This invite has expired. Please request a new one.',
|
|
253
|
-
'USER_ERROR',
|
|
254
|
-
1
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return token;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Extract token from a URL like https://gitspace.sh/join#TOKEN
|
|
263
|
-
*/
|
|
264
|
-
function extractTokenFromUrl(url: string): string | null {
|
|
265
|
-
try {
|
|
266
|
-
const urlObj = new URL(url);
|
|
267
|
-
const hash = urlObj.hash;
|
|
268
|
-
if (hash && hash.length > 1) {
|
|
269
|
-
return hash.substring(1); // Remove leading #
|
|
270
|
-
}
|
|
271
|
-
return null;
|
|
272
|
-
} catch {
|
|
273
|
-
// Not a valid URL, might be raw token
|
|
274
|
-
if (url.includes('#')) {
|
|
275
|
-
return url.split('#')[1] || null;
|
|
276
|
-
}
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Display connection details from invite token
|
|
283
|
-
*/
|
|
284
|
-
function displayConnectionDetails(token: InviteToken): void {
|
|
285
|
-
const expiresAt = new Date(token.expiresAt);
|
|
286
|
-
const now = new Date();
|
|
287
|
-
const hoursRemaining = Math.round(
|
|
288
|
-
(expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60)
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
let expiryStr: string;
|
|
292
|
-
if (hoursRemaining < 1) {
|
|
293
|
-
const minutesRemaining = Math.round(
|
|
294
|
-
(expiresAt.getTime() - now.getTime()) / (1000 * 60)
|
|
295
|
-
);
|
|
296
|
-
expiryStr = `${minutesRemaining} minutes`;
|
|
297
|
-
} else if (hoursRemaining < 24) {
|
|
298
|
-
expiryStr = `${hoursRemaining} hours`;
|
|
299
|
-
} else {
|
|
300
|
-
const daysRemaining = Math.round(hoursRemaining / 24);
|
|
301
|
-
expiryStr = `${daysRemaining} days`;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
logger.log('');
|
|
305
|
-
logger.bold('Remote Connection Details:');
|
|
306
|
-
logger.log('');
|
|
307
|
-
logger.log(` Machine: ${token.machineId}`);
|
|
308
|
-
logger.log(` Access: ${token.accessType === 'full' ? 'Full access' : 'Session invite'}`);
|
|
309
|
-
if (token.sessionId) {
|
|
310
|
-
logger.log(` Session: ${token.sessionId}`);
|
|
311
|
-
}
|
|
312
|
-
logger.log(` Expires: ${expiryStr} (${expiresAt.toLocaleString()})`);
|
|
313
|
-
logger.log(` Relay: ${token.relayUrl}`);
|
|
314
|
-
if (token.singleUse) {
|
|
315
|
-
logger.dim(' (Single-use invite)');
|
|
316
|
-
}
|
|
317
|
-
logger.log('');
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Start interactive terminal session
|
|
322
|
-
*/
|
|
323
|
-
interface ConnectedTerminalBackend {
|
|
324
|
-
disconnect: () => Promise<void>;
|
|
325
|
-
writePtyData?: (data: Uint8Array) => Promise<void>;
|
|
326
|
-
resizePty?: (cols: number, rows: number) => Promise<void>;
|
|
327
|
-
onEvent: (handler: (event: BackendEvent) => void) => () => void;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
async function startTerminalSession(backend: ConnectedTerminalBackend): Promise<void> {
|
|
331
|
-
const handlers: Array<() => void> = [];
|
|
332
|
-
let cleanedUp = false;
|
|
333
|
-
|
|
334
|
-
const cleanup = () => {
|
|
335
|
-
if (cleanedUp) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
cleanedUp = true;
|
|
339
|
-
|
|
340
|
-
for (const handler of handlers) {
|
|
341
|
-
handler();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (process.stdin.isTTY) {
|
|
345
|
-
process.stdin.setRawMode(false);
|
|
346
|
-
}
|
|
347
|
-
process.stdin.pause();
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
await new Promise<void>((resolve) => {
|
|
351
|
-
let stopping = false;
|
|
352
|
-
const stop = async (message?: string) => {
|
|
353
|
-
if (stopping) {
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
stopping = true;
|
|
357
|
-
|
|
358
|
-
if (message) {
|
|
359
|
-
logger.info(message);
|
|
360
|
-
}
|
|
361
|
-
cleanup();
|
|
362
|
-
try {
|
|
363
|
-
await backend.disconnect();
|
|
364
|
-
} catch (error) {
|
|
365
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
366
|
-
logger.error(`Failed to disconnect cleanly: ${detail}`);
|
|
367
|
-
} finally {
|
|
368
|
-
resolve();
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const unsubEvents = backend.onEvent((event) => {
|
|
373
|
-
if (event.type === 'session_exited') {
|
|
374
|
-
void stop(`Session exited${typeof event.exitCode === 'number' ? ` (${event.exitCode})` : ''}`);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (event.type === 'detached') {
|
|
378
|
-
void stop('Detached');
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (event.type === 'status' && event.status === 'disconnected') {
|
|
382
|
-
void stop('Disconnected');
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (event.type === 'error') {
|
|
386
|
-
logger.error(`Connection error: ${event.message}`);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
handlers.push(unsubEvents);
|
|
390
|
-
|
|
391
|
-
// Set stdin to raw mode for character-by-character input
|
|
392
|
-
if (process.stdin.isTTY) {
|
|
393
|
-
process.stdin.setRawMode(true);
|
|
394
|
-
}
|
|
395
|
-
process.stdin.resume();
|
|
396
|
-
|
|
397
|
-
// Forward stdin to remote
|
|
398
|
-
const onData = (data: Buffer) => {
|
|
399
|
-
// Check for Ctrl+D (EOF)
|
|
400
|
-
if (data.length === 1 && data[0] === 0x04) {
|
|
401
|
-
logger.log('');
|
|
402
|
-
void stop('Disconnecting...');
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
backend.writePtyData?.(new Uint8Array(data))?.catch((error) => {
|
|
407
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
408
|
-
logger.error(`Failed to send PTY input: ${detail}`);
|
|
409
|
-
});
|
|
410
|
-
};
|
|
411
|
-
process.stdin.on('data', onData);
|
|
412
|
-
handlers.push(() => process.stdin.removeListener('data', onData));
|
|
413
|
-
|
|
414
|
-
// Handle terminal resize
|
|
415
|
-
if (process.stdout.isTTY) {
|
|
416
|
-
const onResize = () => {
|
|
417
|
-
const cols = process.stdout.columns;
|
|
418
|
-
const rows = process.stdout.rows;
|
|
419
|
-
backend.resizePty?.(cols, rows)?.catch((error) => {
|
|
420
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
421
|
-
logger.error(`Failed to send PTY resize: ${detail}`);
|
|
422
|
-
});
|
|
423
|
-
};
|
|
424
|
-
process.stdout.on('resize', onResize);
|
|
425
|
-
handlers.push(() => process.stdout.removeListener('resize', onResize));
|
|
426
|
-
|
|
427
|
-
// Send initial size
|
|
428
|
-
const cols = process.stdout.columns;
|
|
429
|
-
const rows = process.stdout.rows;
|
|
430
|
-
backend.resizePty?.(cols, rows)?.catch((error) => {
|
|
431
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
432
|
-
logger.error(`Failed to send initial PTY size: ${detail}`);
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Handle SIGINT (Ctrl+C)
|
|
437
|
-
const onSigInt = () => {
|
|
438
|
-
// Forward Ctrl+C to remote instead of terminating
|
|
439
|
-
backend.writePtyData?.(new Uint8Array([0x03]))?.catch((error) => {
|
|
440
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
441
|
-
logger.error(`Failed to send Ctrl+C to remote: ${detail}`);
|
|
442
|
-
});
|
|
443
|
-
};
|
|
444
|
-
process.on('SIGINT', onSigInt);
|
|
445
|
-
handlers.push(() => process.removeListener('SIGINT', onSigInt));
|
|
446
|
-
|
|
447
|
-
// Handle process termination
|
|
448
|
-
const onSigTerm = () => {
|
|
449
|
-
void stop('Disconnecting...');
|
|
450
|
-
};
|
|
451
|
-
process.on('SIGTERM', onSigTerm);
|
|
452
|
-
handlers.push(() => process.removeListener('SIGTERM', onSigTerm));
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function getTerminalSize(): { cols: number; rows: number } {
|
|
457
|
-
const cols = process.stdout.columns || 80;
|
|
458
|
-
const rows = process.stdout.rows || 24;
|
|
459
|
-
return { cols, rows };
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function waitForBackendEvent<TEvent extends BackendEvent>(
|
|
463
|
-
backend: { onEvent: (handler: (event: BackendEvent) => void) => () => void },
|
|
464
|
-
predicate: (event: BackendEvent) => event is TEvent,
|
|
465
|
-
timeoutMs: number,
|
|
466
|
-
label: string
|
|
467
|
-
): { promise: Promise<TEvent>; cancel: () => void } {
|
|
468
|
-
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
469
|
-
let unsubscribe: (() => void) | null = null;
|
|
470
|
-
let settled = false;
|
|
471
|
-
|
|
472
|
-
const cleanup = () => {
|
|
473
|
-
if (timeout) {
|
|
474
|
-
clearTimeout(timeout);
|
|
475
|
-
timeout = null;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
if (unsubscribe) {
|
|
479
|
-
unsubscribe();
|
|
480
|
-
unsubscribe = null;
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
const settle = (done: () => void) => {
|
|
485
|
-
if (settled) {
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
settled = true;
|
|
489
|
-
cleanup();
|
|
490
|
-
done();
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
const promise = new Promise<TEvent>((resolve, reject) => {
|
|
494
|
-
timeout = setTimeout(() => {
|
|
495
|
-
settle(() => {
|
|
496
|
-
reject(new SpacesError(`Timed out waiting for ${label}`, 'SYSTEM_ERROR', 2));
|
|
497
|
-
});
|
|
498
|
-
}, timeoutMs);
|
|
499
|
-
|
|
500
|
-
unsubscribe = backend.onEvent((event) => {
|
|
501
|
-
if (predicate(event)) {
|
|
502
|
-
settle(() => {
|
|
503
|
-
resolve(event);
|
|
504
|
-
});
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (event.type === 'command_error') {
|
|
509
|
-
settle(() => {
|
|
510
|
-
const message = event.code ? `[${event.code}] ${event.message}` : event.message;
|
|
511
|
-
reject(new SpacesError(message, 'SYSTEM_ERROR', 2));
|
|
512
|
-
});
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
if (event.type === 'error') {
|
|
517
|
-
settle(() => {
|
|
518
|
-
reject(new SpacesError(event.message, 'SYSTEM_ERROR', 2));
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
const cancel = () => {
|
|
525
|
-
if (settled) {
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
settled = true;
|
|
529
|
-
cleanup();
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
return { promise, cancel };
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
async function selectWorkspaceForFullAccess(
|
|
536
|
-
backend: {
|
|
537
|
-
listWorkspaces: () => Promise<void>;
|
|
538
|
-
onEvent: (handler: (event: BackendEvent) => void) => () => void;
|
|
539
|
-
}
|
|
540
|
-
): Promise<WorkspaceInfo | null> {
|
|
541
|
-
const workspacesWait = waitForBackendEvent(
|
|
542
|
-
backend,
|
|
543
|
-
(event): event is Extract<BackendEvent, { type: 'workspaces' }> => event.type === 'workspaces',
|
|
544
|
-
15000,
|
|
545
|
-
'workspace list'
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
try {
|
|
549
|
-
await backend.listWorkspaces();
|
|
550
|
-
} catch (error) {
|
|
551
|
-
workspacesWait.cancel();
|
|
552
|
-
throw error;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const response = await workspacesWait.promise;
|
|
556
|
-
const workspaces = response.workspaces;
|
|
557
|
-
|
|
558
|
-
if (workspaces.length === 0) {
|
|
559
|
-
throw new SpacesError('No workspaces available on remote machine', 'USER_ERROR', 1);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const selectedId = await selectOne(
|
|
563
|
-
workspaces.map((workspace) => ({
|
|
564
|
-
label: workspace.name,
|
|
565
|
-
value: workspace.id,
|
|
566
|
-
description: workspace.projectName,
|
|
567
|
-
})),
|
|
568
|
-
'Select workspace to open:'
|
|
569
|
-
);
|
|
570
|
-
|
|
571
|
-
if (!selectedId) {
|
|
572
|
-
return null;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
return workspaces.find((workspace) => workspace.id === selectedId) ?? null;
|
|
576
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { getCurrentProject, getProjectDir } from '../core/config'
|
|
2
|
-
import { SpacesError } from '../types/errors'
|
|
3
|
-
import { logger } from '../utils/logger'
|
|
4
|
-
|
|
5
|
-
export async function getProjectDirectory(options: {
|
|
6
|
-
json?: boolean
|
|
7
|
-
verbose?: boolean
|
|
8
|
-
}): Promise<void> {
|
|
9
|
-
const currentProject = getCurrentProject()
|
|
10
|
-
if (!currentProject) {
|
|
11
|
-
throw new SpacesError('No project found', 'USER_ERROR', 1)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const projectDirectory = getProjectDir(currentProject)
|
|
15
|
-
console.log(projectDirectory)
|
|
16
|
-
}
|