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/review.ts
DELETED
|
@@ -1,787 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Review command — open or interact with the diff review system
|
|
3
|
-
*
|
|
4
|
-
* Primary entry point: `gssh review`
|
|
5
|
-
* Opens the browser-based review UI at http://localhost:<port>?view=review&workspace=<current>
|
|
6
|
-
*
|
|
7
|
-
* Sub-commands:
|
|
8
|
-
* gssh review notes [--workspace <name>] [--project <name>]
|
|
9
|
-
* Print saved review threads as structured JSON (LLM-friendly).
|
|
10
|
-
*
|
|
11
|
-
* gssh review import [--pr <number>] [--workspace <name>] [--project <name>]
|
|
12
|
-
* Import GitHub PR review comments as local threads.
|
|
13
|
-
*
|
|
14
|
-
* gssh review push [--pr <number>] [--workspace <name>] [--project <name>]
|
|
15
|
-
* Push local review decisions to GitHub as a formal PR review.
|
|
16
|
-
*
|
|
17
|
-
* gssh review hunks <file>
|
|
18
|
-
* List hunks in a changed file with stable index and header.
|
|
19
|
-
*
|
|
20
|
-
* gssh review add-hunk <file> --index <n> [--approve|--reject|--pending] [--body <text>]
|
|
21
|
-
* Add or update a hunk-level review decision/comment.
|
|
22
|
-
*
|
|
23
|
-
* gssh review add-file <file> --body <text>
|
|
24
|
-
* Add a file-level review thread.
|
|
25
|
-
*
|
|
26
|
-
* gssh review add-line <file> --start <n> [--end <n>] [--side LEFT|RIGHT] --body <text>
|
|
27
|
-
* Add a line-range review thread.
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
import open from 'open';
|
|
31
|
-
import { readProjectConfig, readGlobalConfig, getGitspaceDir } from '../core/config.js';
|
|
32
|
-
import { executeLocalReviewOperation } from '../core/review-executor.js';
|
|
33
|
-
import { logger } from '../utils/logger.js';
|
|
34
|
-
import { normalizeHunkHeader } from '../utils/hunk-header.js';
|
|
35
|
-
import { detectWorkspaceContextFromCwd } from '../utils/workspace-id.js';
|
|
36
|
-
import type { HunkDecision, ReviewChangedFile, ReviewThread } from '../types/review.js';
|
|
37
|
-
|
|
38
|
-
// Match the port used by `gssh serve` local relay (overridable via RELAY_PORT env)
|
|
39
|
-
const DEFAULT_PORT = parseInt(process.env.RELAY_PORT ?? '4480', 10);
|
|
40
|
-
|
|
41
|
-
// ============================================================================
|
|
42
|
-
// Helpers
|
|
43
|
-
// ============================================================================
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Resolve the current workspace name from the global config / cwd.
|
|
47
|
-
* Returns null if no workspace context is available.
|
|
48
|
-
*/
|
|
49
|
-
function detectWorkspaceFromCwd(): { projectName: string; workspaceName: string } | null {
|
|
50
|
-
return detectWorkspaceContextFromCwd(process.cwd(), getGitspaceDir());
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function resolveCurrentWorkspace(options: {
|
|
54
|
-
workspace?: string;
|
|
55
|
-
project?: string;
|
|
56
|
-
}): { projectName: string; workspaceName: string } | null {
|
|
57
|
-
const envProject = process.env.GSSH_SPACE_PROJECT;
|
|
58
|
-
const envWorkspace = process.env.GSSH_SPACE_WORKSPACE;
|
|
59
|
-
const cwdContext = detectWorkspaceFromCwd();
|
|
60
|
-
const globalConfig = readGlobalConfig();
|
|
61
|
-
const projectName =
|
|
62
|
-
options.project ??
|
|
63
|
-
envProject ??
|
|
64
|
-
cwdContext?.projectName ??
|
|
65
|
-
globalConfig.currentProject ??
|
|
66
|
-
null;
|
|
67
|
-
|
|
68
|
-
if (!projectName) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (options.workspace) {
|
|
73
|
-
return { projectName, workspaceName: options.workspace };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (envWorkspace && (!envProject || envProject === projectName)) {
|
|
77
|
-
return { projectName, workspaceName: envWorkspace };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (cwdContext && cwdContext.projectName === projectName) {
|
|
81
|
-
return { projectName, workspaceName: cwdContext.workspaceName };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Try to derive workspace name from the global state marker
|
|
85
|
-
// (reads from <project>/.config.json currentWorkspace if set)
|
|
86
|
-
try {
|
|
87
|
-
const projectConfig = readProjectConfig(projectName);
|
|
88
|
-
const workspaceValue = (projectConfig as { currentWorkspace?: unknown }).currentWorkspace;
|
|
89
|
-
const workspaceName = typeof workspaceValue === 'string' ? workspaceValue : undefined;
|
|
90
|
-
if (workspaceName) {
|
|
91
|
-
return { projectName, workspaceName };
|
|
92
|
-
}
|
|
93
|
-
} catch {
|
|
94
|
-
// ignore
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface SpaceContextOptions {
|
|
101
|
-
workspace?: string;
|
|
102
|
-
project?: string;
|
|
103
|
-
json?: boolean;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export async function showSpaceContext(options: SpaceContextOptions = {}): Promise<void> {
|
|
107
|
-
const context = resolveCurrentWorkspace(options);
|
|
108
|
-
const payload = {
|
|
109
|
-
mode: process.env.GSSH_SESSION_MODE ?? null,
|
|
110
|
-
tmuxSessionId: process.env.TMUX_LITE ?? null,
|
|
111
|
-
context,
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
if (options.json) {
|
|
115
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!context) {
|
|
120
|
-
logger.log('No workspace context resolved.');
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
logger.log(`Project: ${context.projectName}`);
|
|
125
|
-
logger.log(`Workspace: ${context.workspaceName}`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function parseHunksFromDiff(diff: string): Array<{
|
|
129
|
-
index: number;
|
|
130
|
-
header: string;
|
|
131
|
-
context: string | null;
|
|
132
|
-
targetRef: string;
|
|
133
|
-
}> {
|
|
134
|
-
const lines = diff.split('\n');
|
|
135
|
-
const hunks: Array<{
|
|
136
|
-
index: number;
|
|
137
|
-
header: string;
|
|
138
|
-
context: string | null;
|
|
139
|
-
targetRef: string;
|
|
140
|
-
}> = [];
|
|
141
|
-
|
|
142
|
-
let index = 1;
|
|
143
|
-
for (const line of lines) {
|
|
144
|
-
if (!line.startsWith('@@')) continue;
|
|
145
|
-
const header = normalizeHunkHeader(line);
|
|
146
|
-
const contextMatch = header.match(/^@@[^@]*@@(?:\s+(.*))?$/);
|
|
147
|
-
const context = contextMatch && contextMatch[1] ? contextMatch[1] : null;
|
|
148
|
-
hunks.push({
|
|
149
|
-
index,
|
|
150
|
-
header,
|
|
151
|
-
context,
|
|
152
|
-
targetRef: `hunk:${index}`,
|
|
153
|
-
});
|
|
154
|
-
index++;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return hunks;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function formatThreadTarget(
|
|
161
|
-
target: ReviewThread['target']
|
|
162
|
-
): { targetRef: string; targetSummary: string } {
|
|
163
|
-
switch (target.kind) {
|
|
164
|
-
case 'hunk':
|
|
165
|
-
return {
|
|
166
|
-
targetRef: `hunk:${target.file}:${target.hunkHeader}`,
|
|
167
|
-
targetSummary: `hunk in ${target.file} (${target.hunkHeader})`,
|
|
168
|
-
};
|
|
169
|
-
case 'line':
|
|
170
|
-
return {
|
|
171
|
-
targetRef: `line:${target.file}:${target.side}:${target.startLine}-${target.endLine}`,
|
|
172
|
-
targetSummary: `lines ${target.startLine}-${target.endLine} (${target.side}) in ${target.file}`,
|
|
173
|
-
};
|
|
174
|
-
case 'file':
|
|
175
|
-
return {
|
|
176
|
-
targetRef: `file:${target.file}`,
|
|
177
|
-
targetSummary: `file ${target.file}`,
|
|
178
|
-
};
|
|
179
|
-
case 'workspace':
|
|
180
|
-
return {
|
|
181
|
-
targetRef: 'workspace',
|
|
182
|
-
targetSummary: 'workspace',
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function parseDecisionFlags(options: {
|
|
188
|
-
approve?: boolean;
|
|
189
|
-
reject?: boolean;
|
|
190
|
-
pending?: boolean;
|
|
191
|
-
}): HunkDecision | undefined {
|
|
192
|
-
const selected = [
|
|
193
|
-
options.approve ? 'approved' : null,
|
|
194
|
-
options.reject ? 'rejected' : null,
|
|
195
|
-
options.pending ? 'pending' : null,
|
|
196
|
-
].filter((value): value is HunkDecision => value !== null);
|
|
197
|
-
|
|
198
|
-
if (selected.length > 1) {
|
|
199
|
-
throw new Error('Choose only one decision flag: --approve, --reject, or --pending.');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return selected[0];
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function defaultDecisionBody(decision?: HunkDecision): string {
|
|
206
|
-
if (decision === 'approved') return 'Approved hunk via CLI.';
|
|
207
|
-
if (decision === 'rejected') return 'Rejected hunk via CLI.';
|
|
208
|
-
if (decision === 'pending') return 'Marked hunk as pending via CLI.';
|
|
209
|
-
return '';
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async function getChangedFilesForContext(ctx: {
|
|
213
|
-
projectName: string;
|
|
214
|
-
workspaceName: string;
|
|
215
|
-
}): Promise<ReviewChangedFile[]> {
|
|
216
|
-
const result = await executeLocalReviewOperation({
|
|
217
|
-
op: 'get_changed_files',
|
|
218
|
-
projectName: ctx.projectName,
|
|
219
|
-
workspaceName: ctx.workspaceName,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
if (result.op !== 'changed_files') {
|
|
223
|
-
throw new Error(`Unexpected response from get_changed_files: ${result.op}`);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return result.files;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function resolveChangedFile(
|
|
230
|
-
changedFiles: ReviewChangedFile[],
|
|
231
|
-
inputFile: string
|
|
232
|
-
): ReviewChangedFile {
|
|
233
|
-
const exact = changedFiles.find(
|
|
234
|
-
(file) => file.filePath === inputFile || file.prevFilePath === inputFile
|
|
235
|
-
);
|
|
236
|
-
if (exact) return exact;
|
|
237
|
-
|
|
238
|
-
const suffixMatches = changedFiles.filter(
|
|
239
|
-
(file) =>
|
|
240
|
-
file.filePath.endsWith(`/${inputFile}`) ||
|
|
241
|
-
(file.prevFilePath ? file.prevFilePath.endsWith(`/${inputFile}`) : false)
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
if (suffixMatches.length === 1) {
|
|
245
|
-
return suffixMatches[0];
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (suffixMatches.length > 1) {
|
|
249
|
-
const choices = suffixMatches.slice(0, 8).map((file) => `- ${file.filePath}`).join('\n');
|
|
250
|
-
throw new Error(
|
|
251
|
-
`File path is ambiguous: ${inputFile}\nMatches:\n${choices}\nPlease provide a full path.`
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const sample = changedFiles.slice(0, 12).map((file) => `- ${file.filePath}`).join('\n');
|
|
256
|
-
throw new Error(
|
|
257
|
-
`File is not changed in this workspace: ${inputFile}\nChanged files:\n${sample}`
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Open a URL in the default browser.
|
|
263
|
-
*/
|
|
264
|
-
async function openBrowser(url: string): Promise<void> {
|
|
265
|
-
try {
|
|
266
|
-
await open(url, { wait: false });
|
|
267
|
-
} catch (error) {
|
|
268
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
269
|
-
logger.warning(`Could not open browser automatically: ${message}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// ============================================================================
|
|
274
|
-
// Main review command (opens browser)
|
|
275
|
-
// ============================================================================
|
|
276
|
-
|
|
277
|
-
export interface ReviewOptions {
|
|
278
|
-
workspace?: string;
|
|
279
|
-
project?: string;
|
|
280
|
-
port?: number;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export async function openReview(options: ReviewOptions = {}): Promise<void> {
|
|
284
|
-
const port = options.port ?? DEFAULT_PORT;
|
|
285
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
286
|
-
|
|
287
|
-
let url = `http://localhost:${port}?view=review`;
|
|
288
|
-
if (ctx) {
|
|
289
|
-
url += `&workspace=${encodeURIComponent(ctx.workspaceName)}&project=${encodeURIComponent(ctx.projectName)}`;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
logger.log(`Opening review UI: ${url}`);
|
|
293
|
-
logger.log('(Requires `gssh serve start` to be running)');
|
|
294
|
-
await openBrowser(url);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// ============================================================================
|
|
298
|
-
// gssh review notes
|
|
299
|
-
// ============================================================================
|
|
300
|
-
|
|
301
|
-
export interface ReviewNotesOptions {
|
|
302
|
-
workspace?: string;
|
|
303
|
-
project?: string;
|
|
304
|
-
format?: 'json' | 'text';
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export async function showReviewNotes(options: ReviewNotesOptions = {}): Promise<void> {
|
|
308
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
309
|
-
if (!ctx) {
|
|
310
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
311
|
-
process.exit(1);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const result = await executeLocalReviewOperation({
|
|
315
|
-
op: 'get_threads',
|
|
316
|
-
projectName: ctx.projectName,
|
|
317
|
-
workspaceName: ctx.workspaceName,
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
if (result.op !== 'threads') {
|
|
321
|
-
logger.error('Unexpected response from review operation');
|
|
322
|
-
process.exit(1);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const { threads } = result;
|
|
326
|
-
|
|
327
|
-
const formatted = threads.map((thread) => {
|
|
328
|
-
const { targetRef, targetSummary } = formatThreadTarget(thread.target);
|
|
329
|
-
return {
|
|
330
|
-
...thread,
|
|
331
|
-
targetRef,
|
|
332
|
-
targetSummary,
|
|
333
|
-
targetKind: thread.target.kind,
|
|
334
|
-
...(thread.target.kind === 'hunk' ? { hunkHeader: thread.target.hunkHeader } : {}),
|
|
335
|
-
};
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
if (options.format === 'text') {
|
|
339
|
-
if (threads.length === 0) {
|
|
340
|
-
logger.log('No review threads found.');
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
for (const thread of formatted) {
|
|
344
|
-
const decision = thread.decision ? ` [${thread.decision.toUpperCase()}]` : '';
|
|
345
|
-
const resolved = thread.resolved ? ' (resolved)' : '';
|
|
346
|
-
logger.log(`\n--- Thread: ${thread.id}${decision}${resolved} ---`);
|
|
347
|
-
logger.log(`Target: ${thread.targetSummary}`);
|
|
348
|
-
logger.log(`Target Ref: ${thread.targetRef}`);
|
|
349
|
-
if (thread.targetKind === 'hunk' && thread.hunkHeader) {
|
|
350
|
-
logger.log(`Hunk Header: ${thread.hunkHeader}`);
|
|
351
|
-
}
|
|
352
|
-
for (const comment of thread.comments) {
|
|
353
|
-
logger.log(` [${comment.author} @ ${comment.createdAt}]: ${comment.body}`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Default: JSON output for LLM consumption
|
|
360
|
-
console.log(JSON.stringify({ threads: formatted }, null, 2));
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// ============================================================================
|
|
364
|
-
// gssh review hunks
|
|
365
|
-
// ============================================================================
|
|
366
|
-
|
|
367
|
-
export interface ReviewHunksOptions {
|
|
368
|
-
workspace?: string;
|
|
369
|
-
project?: string;
|
|
370
|
-
format?: 'json' | 'text';
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
export async function listReviewHunks(file: string, options: ReviewHunksOptions = {}): Promise<void> {
|
|
374
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
375
|
-
if (!ctx) {
|
|
376
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
377
|
-
process.exit(1);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const changed = await getChangedFilesForContext(ctx);
|
|
381
|
-
const resolvedFile = resolveChangedFile(changed, file);
|
|
382
|
-
|
|
383
|
-
const result = await executeLocalReviewOperation({
|
|
384
|
-
op: 'get_file_diff',
|
|
385
|
-
projectName: ctx.projectName,
|
|
386
|
-
workspaceName: ctx.workspaceName,
|
|
387
|
-
filePath: resolvedFile.filePath,
|
|
388
|
-
prevFilePath: resolvedFile.prevFilePath,
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
if (result.op !== 'file_diff') {
|
|
392
|
-
logger.error('Unexpected response from get_file_diff operation');
|
|
393
|
-
process.exit(1);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const hunks = parseHunksFromDiff(result.diff).map((hunk) => ({
|
|
397
|
-
...hunk,
|
|
398
|
-
file: resolvedFile.filePath,
|
|
399
|
-
targetRef: `hunk:${resolvedFile.filePath}:${hunk.index}`,
|
|
400
|
-
}));
|
|
401
|
-
|
|
402
|
-
if (options.format === 'text') {
|
|
403
|
-
if (hunks.length === 0) {
|
|
404
|
-
logger.log(`No hunks found in ${resolvedFile.filePath}.`);
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
logger.log(`Hunks in ${resolvedFile.filePath}:`);
|
|
408
|
-
for (const hunk of hunks) {
|
|
409
|
-
logger.log(` [${hunk.index}] ${hunk.header}`);
|
|
410
|
-
}
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
console.log(
|
|
415
|
-
JSON.stringify(
|
|
416
|
-
{
|
|
417
|
-
file: resolvedFile.filePath,
|
|
418
|
-
prevFilePath: resolvedFile.prevFilePath,
|
|
419
|
-
hunks,
|
|
420
|
-
},
|
|
421
|
-
null,
|
|
422
|
-
2
|
|
423
|
-
)
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// ============================================================================
|
|
428
|
-
// gssh review add-hunk
|
|
429
|
-
// ============================================================================
|
|
430
|
-
|
|
431
|
-
export interface ReviewAddHunkOptions {
|
|
432
|
-
workspace?: string;
|
|
433
|
-
project?: string;
|
|
434
|
-
index: number;
|
|
435
|
-
body?: string;
|
|
436
|
-
approve?: boolean;
|
|
437
|
-
reject?: boolean;
|
|
438
|
-
pending?: boolean;
|
|
439
|
-
json?: boolean;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
export async function addHunkReview(file: string, options: ReviewAddHunkOptions): Promise<void> {
|
|
443
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
444
|
-
if (!ctx) {
|
|
445
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
446
|
-
process.exit(1);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (!Number.isFinite(options.index) || options.index < 1) {
|
|
450
|
-
logger.error('--index must be a positive integer (1-based).');
|
|
451
|
-
process.exit(1);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const decision = parseDecisionFlags(options);
|
|
455
|
-
const body = options.body?.trim() ?? '';
|
|
456
|
-
if (!decision && !body) {
|
|
457
|
-
logger.error('Provide at least one of: --approve/--reject/--pending or --body <text>.');
|
|
458
|
-
process.exit(1);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const changed = await getChangedFilesForContext(ctx);
|
|
462
|
-
const resolvedFile = resolveChangedFile(changed, file);
|
|
463
|
-
|
|
464
|
-
const diffResult = await executeLocalReviewOperation({
|
|
465
|
-
op: 'get_file_diff',
|
|
466
|
-
projectName: ctx.projectName,
|
|
467
|
-
workspaceName: ctx.workspaceName,
|
|
468
|
-
filePath: resolvedFile.filePath,
|
|
469
|
-
prevFilePath: resolvedFile.prevFilePath,
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
if (diffResult.op !== 'file_diff') {
|
|
473
|
-
logger.error('Unexpected response from get_file_diff operation');
|
|
474
|
-
process.exit(1);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const hunks = parseHunksFromDiff(diffResult.diff);
|
|
478
|
-
const chosen = hunks.find((hunk) => hunk.index === options.index);
|
|
479
|
-
if (!chosen) {
|
|
480
|
-
logger.error(`Hunk index ${options.index} not found in ${resolvedFile.filePath}.`);
|
|
481
|
-
process.exit(1);
|
|
482
|
-
}
|
|
483
|
-
const chosenHeader = normalizeHunkHeader(chosen.header);
|
|
484
|
-
|
|
485
|
-
const threadsResult = await executeLocalReviewOperation({
|
|
486
|
-
op: 'get_threads',
|
|
487
|
-
projectName: ctx.projectName,
|
|
488
|
-
workspaceName: ctx.workspaceName,
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
if (threadsResult.op !== 'threads') {
|
|
492
|
-
logger.error('Unexpected response from get_threads operation');
|
|
493
|
-
process.exit(1);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const existing = threadsResult.threads.find(
|
|
497
|
-
(thread) =>
|
|
498
|
-
thread.target.kind === 'hunk' &&
|
|
499
|
-
thread.target.file === resolvedFile.filePath &&
|
|
500
|
-
normalizeHunkHeader(thread.target.hunkHeader) === chosenHeader
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
let createdOrUpdatedThreadId = existing?.id;
|
|
504
|
-
|
|
505
|
-
if (existing && decision) {
|
|
506
|
-
await executeLocalReviewOperation({
|
|
507
|
-
op: 'update_thread',
|
|
508
|
-
projectName: ctx.projectName,
|
|
509
|
-
workspaceName: ctx.workspaceName,
|
|
510
|
-
threadId: existing.id,
|
|
511
|
-
decision,
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (existing && body) {
|
|
516
|
-
await executeLocalReviewOperation({
|
|
517
|
-
op: 'add_reply',
|
|
518
|
-
projectName: ctx.projectName,
|
|
519
|
-
workspaceName: ctx.workspaceName,
|
|
520
|
-
threadId: existing.id,
|
|
521
|
-
body,
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (!existing) {
|
|
526
|
-
const createResult = await executeLocalReviewOperation({
|
|
527
|
-
op: 'create_thread',
|
|
528
|
-
projectName: ctx.projectName,
|
|
529
|
-
workspaceName: ctx.workspaceName,
|
|
530
|
-
target: {
|
|
531
|
-
kind: 'hunk',
|
|
532
|
-
file: resolvedFile.filePath,
|
|
533
|
-
hunkHeader: chosenHeader,
|
|
534
|
-
},
|
|
535
|
-
body: body || defaultDecisionBody(decision),
|
|
536
|
-
decision,
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
if (createResult.op !== 'thread_created') {
|
|
540
|
-
logger.error('Unexpected response from create_thread operation');
|
|
541
|
-
process.exit(1);
|
|
542
|
-
}
|
|
543
|
-
createdOrUpdatedThreadId = createResult.thread.id;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (options.json) {
|
|
547
|
-
console.log(
|
|
548
|
-
JSON.stringify(
|
|
549
|
-
{
|
|
550
|
-
ok: true,
|
|
551
|
-
file: resolvedFile.filePath,
|
|
552
|
-
hunkIndex: chosen.index,
|
|
553
|
-
hunkHeader: chosenHeader,
|
|
554
|
-
targetRef: `hunk:${resolvedFile.filePath}:${chosen.index}`,
|
|
555
|
-
decision: decision ?? null,
|
|
556
|
-
threadId: createdOrUpdatedThreadId ?? null,
|
|
557
|
-
reusedThread: Boolean(existing),
|
|
558
|
-
bodyAdded: body.length > 0,
|
|
559
|
-
},
|
|
560
|
-
null,
|
|
561
|
-
2
|
|
562
|
-
)
|
|
563
|
-
);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
logger.success(
|
|
568
|
-
`${existing ? 'Updated' : 'Added'} hunk review on ${resolvedFile.filePath} [${chosen.index}] (${chosenHeader})`
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
// ============================================================================
|
|
573
|
-
// gssh review add-file
|
|
574
|
-
// ============================================================================
|
|
575
|
-
|
|
576
|
-
export interface ReviewAddFileOptions {
|
|
577
|
-
workspace?: string;
|
|
578
|
-
project?: string;
|
|
579
|
-
body: string;
|
|
580
|
-
json?: boolean;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
export async function addFileReview(file: string, options: ReviewAddFileOptions): Promise<void> {
|
|
584
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
585
|
-
if (!ctx) {
|
|
586
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
587
|
-
process.exit(1);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
const body = options.body?.trim();
|
|
591
|
-
if (!body) {
|
|
592
|
-
logger.error('--body is required for add-file.');
|
|
593
|
-
process.exit(1);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const changed = await getChangedFilesForContext(ctx);
|
|
597
|
-
const resolvedFile = resolveChangedFile(changed, file);
|
|
598
|
-
|
|
599
|
-
const result = await executeLocalReviewOperation({
|
|
600
|
-
op: 'create_thread',
|
|
601
|
-
projectName: ctx.projectName,
|
|
602
|
-
workspaceName: ctx.workspaceName,
|
|
603
|
-
target: { kind: 'file', file: resolvedFile.filePath },
|
|
604
|
-
body,
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
if (result.op !== 'thread_created') {
|
|
608
|
-
logger.error('Unexpected response from create_thread operation');
|
|
609
|
-
process.exit(1);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
if (options.json) {
|
|
613
|
-
console.log(
|
|
614
|
-
JSON.stringify(
|
|
615
|
-
{
|
|
616
|
-
ok: true,
|
|
617
|
-
threadId: result.thread.id,
|
|
618
|
-
targetRef: `file:${resolvedFile.filePath}`,
|
|
619
|
-
file: resolvedFile.filePath,
|
|
620
|
-
},
|
|
621
|
-
null,
|
|
622
|
-
2
|
|
623
|
-
)
|
|
624
|
-
);
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
logger.success(`Added file review thread for ${resolvedFile.filePath}.`);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// ============================================================================
|
|
632
|
-
// gssh review add-line
|
|
633
|
-
// ============================================================================
|
|
634
|
-
|
|
635
|
-
export interface ReviewAddLineOptions {
|
|
636
|
-
workspace?: string;
|
|
637
|
-
project?: string;
|
|
638
|
-
start: number;
|
|
639
|
-
end?: number;
|
|
640
|
-
side?: 'LEFT' | 'RIGHT' | string;
|
|
641
|
-
body: string;
|
|
642
|
-
json?: boolean;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
export async function addLineReview(file: string, options: ReviewAddLineOptions): Promise<void> {
|
|
646
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
647
|
-
if (!ctx) {
|
|
648
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
649
|
-
process.exit(1);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
if (!Number.isFinite(options.start) || options.start < 1) {
|
|
653
|
-
logger.error('--start must be a positive integer.');
|
|
654
|
-
process.exit(1);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
const normalizedEnd = options.end && Number.isFinite(options.end)
|
|
658
|
-
? Math.max(options.start, options.end)
|
|
659
|
-
: options.start;
|
|
660
|
-
|
|
661
|
-
const normalizedSide = String(options.side ?? 'RIGHT').toUpperCase();
|
|
662
|
-
if (normalizedSide !== 'LEFT' && normalizedSide !== 'RIGHT') {
|
|
663
|
-
logger.error('--side must be LEFT or RIGHT.');
|
|
664
|
-
process.exit(1);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
const body = options.body?.trim();
|
|
668
|
-
if (!body) {
|
|
669
|
-
logger.error('--body is required for add-line.');
|
|
670
|
-
process.exit(1);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
const changed = await getChangedFilesForContext(ctx);
|
|
674
|
-
const resolvedFile = resolveChangedFile(changed, file);
|
|
675
|
-
|
|
676
|
-
const result = await executeLocalReviewOperation({
|
|
677
|
-
op: 'create_thread',
|
|
678
|
-
projectName: ctx.projectName,
|
|
679
|
-
workspaceName: ctx.workspaceName,
|
|
680
|
-
target: {
|
|
681
|
-
kind: 'line',
|
|
682
|
-
file: resolvedFile.filePath,
|
|
683
|
-
startLine: options.start,
|
|
684
|
-
endLine: normalizedEnd,
|
|
685
|
-
side: normalizedSide,
|
|
686
|
-
},
|
|
687
|
-
body,
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
if (result.op !== 'thread_created') {
|
|
691
|
-
logger.error('Unexpected response from create_thread operation');
|
|
692
|
-
process.exit(1);
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
const targetRef = `line:${resolvedFile.filePath}:${normalizedSide}:${options.start}-${normalizedEnd}`;
|
|
696
|
-
|
|
697
|
-
if (options.json) {
|
|
698
|
-
console.log(
|
|
699
|
-
JSON.stringify(
|
|
700
|
-
{
|
|
701
|
-
ok: true,
|
|
702
|
-
threadId: result.thread.id,
|
|
703
|
-
targetRef,
|
|
704
|
-
file: resolvedFile.filePath,
|
|
705
|
-
side: normalizedSide,
|
|
706
|
-
start: options.start,
|
|
707
|
-
end: normalizedEnd,
|
|
708
|
-
},
|
|
709
|
-
null,
|
|
710
|
-
2
|
|
711
|
-
)
|
|
712
|
-
);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
logger.success(
|
|
717
|
-
`Added line review thread for ${resolvedFile.filePath}:${options.start}-${normalizedEnd} (${normalizedSide}).`
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// ============================================================================
|
|
722
|
-
// gssh review import
|
|
723
|
-
// ============================================================================
|
|
724
|
-
|
|
725
|
-
export interface ReviewImportOptions {
|
|
726
|
-
workspace?: string;
|
|
727
|
-
project?: string;
|
|
728
|
-
pr?: number;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
export async function importReview(options: ReviewImportOptions = {}): Promise<void> {
|
|
732
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
733
|
-
if (!ctx) {
|
|
734
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
735
|
-
process.exit(1);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
logger.log(`Importing GitHub PR review for ${ctx.projectName}:${ctx.workspaceName}...`);
|
|
739
|
-
|
|
740
|
-
const result = await executeLocalReviewOperation({
|
|
741
|
-
op: 'import_github',
|
|
742
|
-
projectName: ctx.projectName,
|
|
743
|
-
workspaceName: ctx.workspaceName,
|
|
744
|
-
prNumber: options.pr,
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
if (result.op !== 'github_imported') {
|
|
748
|
-
logger.error('Unexpected response from import operation');
|
|
749
|
-
process.exit(1);
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
logger.success(`Imported ${result.imported} new thread(s) from GitHub (${result.threads.length} total).`);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// ============================================================================
|
|
756
|
-
// gssh review push
|
|
757
|
-
// ============================================================================
|
|
758
|
-
|
|
759
|
-
export interface ReviewPushOptions {
|
|
760
|
-
workspace?: string;
|
|
761
|
-
project?: string;
|
|
762
|
-
pr?: number;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
export async function pushReview(options: ReviewPushOptions = {}): Promise<void> {
|
|
766
|
-
const ctx = resolveCurrentWorkspace(options);
|
|
767
|
-
if (!ctx) {
|
|
768
|
-
logger.error('Could not determine current project/workspace. Use --project and --workspace flags.');
|
|
769
|
-
process.exit(1);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
logger.log(`Pushing review for ${ctx.projectName}:${ctx.workspaceName} to GitHub...`);
|
|
773
|
-
|
|
774
|
-
const result = await executeLocalReviewOperation({
|
|
775
|
-
op: 'push_github',
|
|
776
|
-
projectName: ctx.projectName,
|
|
777
|
-
workspaceName: ctx.workspaceName,
|
|
778
|
-
prNumber: options.pr,
|
|
779
|
-
});
|
|
780
|
-
|
|
781
|
-
if (result.op !== 'github_pushed') {
|
|
782
|
-
logger.error('Unexpected response from push operation');
|
|
783
|
-
process.exit(1);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
logger.success(`Review submitted to GitHub: ${result.url}`);
|
|
787
|
-
}
|