gitspace 0.2.0-rc.20 → 0.2.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -6
- package/.claude/settings.local.json +0 -10
- package/.gitspace/bundle.json +0 -50
- package/.gitspace/events.json +0 -11
- package/.gitspace/processes.json +0 -23
- package/.gitspace/scripts/select/01-status.sh +0 -39
- package/.gitspace/scripts/setup/01-install-deps.sh +0 -12
- package/.gitspace/scripts/setup/02-typecheck.sh +0 -16
- package/AGENTS.md +0 -469
- package/CLAUDE.md +0 -1
- package/bun.lock +0 -794
- package/docs/CONNECTION.md +0 -623
- package/docs/GATEWAY-WORKER.md +0 -319
- package/docs/GETTING-STARTED.md +0 -448
- package/docs/GITSPACE-PLATFORM.md +0 -1819
- package/docs/INFRASTRUCTURE.md +0 -1347
- package/docs/PROTOCOL.md +0 -619
- package/docs/QUICKSTART.md +0 -183
- package/docs/RELAY.md +0 -327
- package/docs/REMOTE-DESIGN.md +0 -554
- package/docs/ROADMAP.md +0 -564
- package/docs/SITE_DOCS_FIGMA_MAKE.md +0 -1176
- package/docs/STACK-DESIGN.md +0 -588
- package/docs/UNIFIED_ARCHITECTURE.md +0 -138
- package/experiments/pty-benchmark.ts +0 -148
- package/experiments/pty-latency.ts +0 -100
- package/experiments/router/client.ts +0 -199
- package/experiments/router/protocol.ts +0 -74
- package/experiments/router/router.ts +0 -217
- package/experiments/router/session.ts +0 -180
- package/experiments/router/test.ts +0 -133
- package/experiments/socket-bandwidth.ts +0 -77
- package/homebrew/gitspace.rb +0 -45
- package/landing-page/ATTRIBUTIONS.md +0 -3
- package/landing-page/README.md +0 -11
- package/landing-page/bun.lock +0 -801
- package/landing-page/guidelines/Guidelines.md +0 -61
- package/landing-page/index.html +0 -37
- package/landing-page/package.json +0 -90
- package/landing-page/postcss.config.mjs +0 -15
- package/landing-page/public/_redirects +0 -1
- package/landing-page/public/favicon.png +0 -0
- package/landing-page/src/app/App.tsx +0 -53
- package/landing-page/src/app/components/figma/ImageWithFallback.tsx +0 -27
- package/landing-page/src/app/components/ui/accordion.tsx +0 -66
- package/landing-page/src/app/components/ui/alert-dialog.tsx +0 -157
- package/landing-page/src/app/components/ui/alert.tsx +0 -66
- package/landing-page/src/app/components/ui/aspect-ratio.tsx +0 -11
- package/landing-page/src/app/components/ui/avatar.tsx +0 -53
- package/landing-page/src/app/components/ui/badge.tsx +0 -46
- package/landing-page/src/app/components/ui/breadcrumb.tsx +0 -109
- package/landing-page/src/app/components/ui/button.tsx +0 -57
- package/landing-page/src/app/components/ui/calendar.tsx +0 -75
- package/landing-page/src/app/components/ui/card.tsx +0 -92
- package/landing-page/src/app/components/ui/carousel.tsx +0 -241
- package/landing-page/src/app/components/ui/chart.tsx +0 -353
- package/landing-page/src/app/components/ui/checkbox.tsx +0 -32
- package/landing-page/src/app/components/ui/collapsible.tsx +0 -33
- package/landing-page/src/app/components/ui/command.tsx +0 -177
- package/landing-page/src/app/components/ui/context-menu.tsx +0 -252
- package/landing-page/src/app/components/ui/dialog.tsx +0 -135
- package/landing-page/src/app/components/ui/drawer.tsx +0 -132
- package/landing-page/src/app/components/ui/dropdown-menu.tsx +0 -257
- package/landing-page/src/app/components/ui/form.tsx +0 -168
- package/landing-page/src/app/components/ui/hover-card.tsx +0 -44
- package/landing-page/src/app/components/ui/input-otp.tsx +0 -77
- package/landing-page/src/app/components/ui/input.tsx +0 -21
- package/landing-page/src/app/components/ui/label.tsx +0 -24
- package/landing-page/src/app/components/ui/menubar.tsx +0 -276
- package/landing-page/src/app/components/ui/navigation-menu.tsx +0 -168
- package/landing-page/src/app/components/ui/pagination.tsx +0 -127
- package/landing-page/src/app/components/ui/popover.tsx +0 -48
- package/landing-page/src/app/components/ui/progress.tsx +0 -31
- package/landing-page/src/app/components/ui/radio-group.tsx +0 -45
- package/landing-page/src/app/components/ui/resizable.tsx +0 -56
- package/landing-page/src/app/components/ui/scroll-area.tsx +0 -58
- package/landing-page/src/app/components/ui/select.tsx +0 -189
- package/landing-page/src/app/components/ui/separator.tsx +0 -28
- package/landing-page/src/app/components/ui/sheet.tsx +0 -139
- package/landing-page/src/app/components/ui/sidebar.tsx +0 -726
- package/landing-page/src/app/components/ui/skeleton.tsx +0 -13
- package/landing-page/src/app/components/ui/slider.tsx +0 -63
- package/landing-page/src/app/components/ui/sonner.tsx +0 -25
- package/landing-page/src/app/components/ui/switch.tsx +0 -31
- package/landing-page/src/app/components/ui/table.tsx +0 -116
- package/landing-page/src/app/components/ui/tabs.tsx +0 -66
- package/landing-page/src/app/components/ui/textarea.tsx +0 -18
- package/landing-page/src/app/components/ui/toggle-group.tsx +0 -73
- package/landing-page/src/app/components/ui/toggle.tsx +0 -47
- package/landing-page/src/app/components/ui/tooltip.tsx +0 -61
- package/landing-page/src/app/components/ui/use-mobile.ts +0 -21
- package/landing-page/src/app/components/ui/utils.ts +0 -6
- package/landing-page/src/components/docs/DocsContent.tsx +0 -801
- package/landing-page/src/components/docs/DocsSidebar.tsx +0 -90
- package/landing-page/src/components/landing/CTA.tsx +0 -59
- package/landing-page/src/components/landing/Comparison.tsx +0 -84
- package/landing-page/src/components/landing/FaultyTerminal.tsx +0 -424
- package/landing-page/src/components/landing/Features.tsx +0 -201
- package/landing-page/src/components/landing/Hero.tsx +0 -142
- package/landing-page/src/components/landing/Pricing.tsx +0 -140
- package/landing-page/src/components/landing/Roadmap.tsx +0 -86
- package/landing-page/src/components/landing/Security.tsx +0 -81
- package/landing-page/src/components/landing/TerminalWindow.tsx +0 -27
- package/landing-page/src/components/landing/UseCases.tsx +0 -55
- package/landing-page/src/components/landing/Workflow.tsx +0 -101
- package/landing-page/src/components/layout/DashboardNavbar.tsx +0 -37
- package/landing-page/src/components/layout/Footer.tsx +0 -55
- package/landing-page/src/components/layout/LandingNavbar.tsx +0 -82
- package/landing-page/src/components/ui/badge.tsx +0 -39
- package/landing-page/src/components/ui/breadcrumb.tsx +0 -115
- package/landing-page/src/components/ui/button.tsx +0 -57
- package/landing-page/src/components/ui/card.tsx +0 -79
- package/landing-page/src/components/ui/mock-terminal.tsx +0 -68
- package/landing-page/src/components/ui/separator.tsx +0 -28
- package/landing-page/src/lib/utils.ts +0 -6
- package/landing-page/src/main.tsx +0 -10
- package/landing-page/src/pages/Dashboard.tsx +0 -133
- package/landing-page/src/pages/DocsPage.tsx +0 -79
- package/landing-page/src/pages/LandingPage.tsx +0 -31
- package/landing-page/src/pages/TerminalView.tsx +0 -106
- package/landing-page/src/styles/fonts.css +0 -0
- package/landing-page/src/styles/index.css +0 -3
- package/landing-page/src/styles/tailwind.css +0 -4
- package/landing-page/src/styles/theme.css +0 -181
- package/landing-page/vite.config.ts +0 -19
- package/scripts/GHOSTTY_TAB_BUG.md +0 -106
- package/scripts/build.ts +0 -298
- package/scripts/migrate-secrets.ts +0 -77
- package/scripts/release.ts +0 -140
- package/scripts/sample-events.ts +0 -263
- package/scripts/test-tabs-minimal.ts +0 -68
- package/scripts/test-tabs-workaround.ts +0 -95
- package/scripts/test-tabs.ts +0 -171
- package/src/__tests__/test-utils.ts +0 -298
- package/src/app/input/__tests__/sessionCommands.test.ts +0 -40
- package/src/app/input/sessionCommands.ts +0 -94
- package/src/app/session/__tests__/useAttachController.test.ts +0 -229
- package/src/app/session/createSessionBackend.bun.ts +0 -76
- package/src/app/session/createSessionBackend.web.ts +0 -104
- package/src/app/session/types.ts +0 -16
- package/src/app/session/useAttachController.ts +0 -220
- package/src/app/session/useProcessActions.ts +0 -201
- package/src/app/session/useSessionClient.ts +0 -35
- package/src/app/session/useWorkspaceDeleteFlow.ts +0 -170
- package/src/app.tui.tsx +0 -2929
- package/src/app.web.tsx +0 -1454
- package/src/commands/__tests__/connect-key.test.ts +0 -10
- package/src/commands/__tests__/events.test.ts +0 -201
- package/src/commands/__tests__/notifications.test.ts +0 -349
- package/src/commands/__tests__/process.test.ts +0 -251
- package/src/commands/__tests__/serve-messages.test.ts +0 -190
- package/src/commands/__tests__/serve-process-hosting.test.ts +0 -63
- package/src/commands/access.ts +0 -298
- package/src/commands/add.ts +0 -455
- package/src/commands/auth.ts +0 -369
- package/src/commands/bundle.ts +0 -232
- package/src/commands/config.ts +0 -242
- package/src/commands/connect-key.ts +0 -1
- package/src/commands/connect.ts +0 -576
- package/src/commands/directory.ts +0 -16
- package/src/commands/events.ts +0 -157
- package/src/commands/host.ts +0 -566
- package/src/commands/identity.ts +0 -184
- package/src/commands/linear.ts +0 -717
- package/src/commands/list.ts +0 -181
- package/src/commands/migrate.ts +0 -52
- package/src/commands/notifications.ts +0 -351
- package/src/commands/process.ts +0 -104
- package/src/commands/relay.ts +0 -315
- package/src/commands/remove.ts +0 -279
- package/src/commands/review.ts +0 -787
- package/src/commands/serve.ts +0 -1946
- package/src/commands/share.ts +0 -451
- package/src/commands/status.ts +0 -125
- package/src/commands/switch.ts +0 -361
- package/src/commands/tmux.ts +0 -317
- package/src/components/DPad.web.tsx +0 -343
- package/src/components/DiffViewer.web.tsx +0 -1192
- package/src/components/Events.tsx +0 -137
- package/src/components/Events.tui.tsx +0 -129
- package/src/components/Events.web.tsx +0 -386
- package/src/components/FloatingControls.web.tsx +0 -112
- package/src/components/FloatingJogWheel.web.tsx +0 -240
- package/src/components/Flow.tsx +0 -458
- package/src/components/Flow.tui.tsx +0 -343
- package/src/components/Flow.web.tsx +0 -442
- package/src/components/Inbox.tsx +0 -448
- package/src/components/Inbox.tui.tsx +0 -262
- package/src/components/Inbox.web.tsx +0 -329
- package/src/components/MachineList.tsx +0 -187
- package/src/components/MachineList.tui.tsx +0 -161
- package/src/components/MachineList.web.tsx +0 -210
- package/src/components/NumPad.web.tsx +0 -270
- package/src/components/ProjectList.tsx +0 -175
- package/src/components/ProjectList.tui.tsx +0 -109
- package/src/components/ProjectList.web.tsx +0 -143
- package/src/components/ProjectOnboardingStep.ts +0 -23
- package/src/components/ProjectOnboardingStep.tui.tsx +0 -88
- package/src/components/ProjectOnboardingStep.web.tsx +0 -59
- package/src/components/RemoteMachineScreen.tui.tsx +0 -690
- package/src/components/ScriptTerminal.tui.tsx +0 -160
- package/src/components/ScriptTerminal.web.tsx +0 -89
- package/src/components/SessionTerminal.tui.tsx +0 -406
- package/src/components/SessionTerminal.web.tsx +0 -467
- package/src/components/SpacesBrowser.tsx +0 -540
- package/src/components/SpacesBrowser.tui.tsx +0 -258
- package/src/components/SpacesBrowser.web.tsx +0 -332
- package/src/components/TerminalControls.web.tsx +0 -464
- package/src/components/ThreadPanel.web.tsx +0 -798
- package/src/components/__tests__/SpacesBrowser.test.ts +0 -541
- package/src/components/__tests__/SpacesBrowser.tui.test.tsx +0 -249
- package/src/components/__tests__/script-terminal-buffer.tui.test.ts +0 -72
- package/src/components/index.ts +0 -105
- package/src/components/review-decision-colors.ts +0 -11
- package/src/components/script-terminal-buffer.tui.ts +0 -37
- package/src/components/session-terminal-page-navigation.ts +0 -48
- package/src/components/terminal-bracketed-paste.tui.test.ts +0 -43
- package/src/components/terminal-bracketed-paste.tui.ts +0 -46
- package/src/core/__tests__/access.test.ts +0 -240
- package/src/core/__tests__/bundle-refresh.test.ts +0 -567
- package/src/core/__tests__/bundle.test.ts +0 -209
- package/src/core/__tests__/github-review.test.ts +0 -781
- package/src/core/__tests__/project-lifecycle.test.ts +0 -137
- package/src/core/__tests__/workspace-lifecycle.test.ts +0 -159
- package/src/core/__tests__/workspace.test.ts +0 -149
- package/src/core/access.ts +0 -277
- package/src/core/bundle-refresh.ts +0 -1064
- package/src/core/bundle.ts +0 -326
- package/src/core/config.ts +0 -405
- package/src/core/git.ts +0 -768
- package/src/core/github-review.ts +0 -761
- package/src/core/github.ts +0 -151
- package/src/core/identity.ts +0 -631
- package/src/core/linear.ts +0 -403
- package/src/core/preferences-service.ts +0 -17
- package/src/core/project-catalog.ts +0 -52
- package/src/core/project-lifecycle.ts +0 -163
- package/src/core/review-executor.ts +0 -316
- package/src/core/review.ts +0 -407
- package/src/core/secret-runtime.ts +0 -167
- package/src/core/shell.ts +0 -117
- package/src/core/trusted-relays.ts +0 -315
- package/src/core/workspace-lifecycle.ts +0 -216
- package/src/core/workspace.ts +0 -363
- package/src/hooks/__tests__/useLocalSession.tui.test.ts +0 -557
- package/src/hooks/index.ts +0 -8
- package/src/hooks/index.tui.ts +0 -32
- package/src/hooks/useDaemonStatus.tui.ts +0 -174
- package/src/hooks/useLocalSession.tui.ts +0 -395
- package/src/hooks/useRelayConnection.web.ts +0 -54
- package/src/hooks/useRemoteMachines.tui.ts +0 -166
- package/src/hooks/useRemoteTerminal.tui.ts +0 -22
- package/src/hooks/useReview.web.ts +0 -248
- package/src/hooks/useTerminal.web.ts +0 -36
- package/src/hooks/useUserActivity.ts +0 -61
- package/src/hooks/useVisualViewport.web.ts +0 -104
- package/src/index.ts +0 -1376
- package/src/lib/events/__tests__/collector-filter.test.ts +0 -105
- package/src/lib/events/__tests__/store-query.test.ts +0 -103
- package/src/lib/events/collector.ts +0 -494
- package/src/lib/events/filters.ts +0 -26
- package/src/lib/events/index.ts +0 -11
- package/src/lib/events/indexer.ts +0 -14
- package/src/lib/events/paths.ts +0 -69
- package/src/lib/events/reader.ts +0 -212
- package/src/lib/events/store.ts +0 -141
- package/src/lib/invite.web.ts +0 -58
- package/src/lib/preferences-service.web.ts +0 -41
- package/src/lib/processes/__tests__/config.test.ts +0 -83
- package/src/lib/processes/__tests__/names.test.ts +0 -125
- package/src/lib/processes/__tests__/schema.test.ts +0 -208
- package/src/lib/processes/__tests__/watchdog.test.ts +0 -210
- package/src/lib/processes/autostart.ts +0 -16
- package/src/lib/processes/config.ts +0 -187
- package/src/lib/processes/control.ts +0 -53
- package/src/lib/processes/editor.ts +0 -32
- package/src/lib/processes/events-config.ts +0 -37
- package/src/lib/processes/index.ts +0 -14
- package/src/lib/processes/instances.ts +0 -20
- package/src/lib/processes/manager.ts +0 -131
- package/src/lib/processes/names.ts +0 -71
- package/src/lib/processes/registry.ts +0 -26
- package/src/lib/processes/runner.ts +0 -211
- package/src/lib/processes/scheduler.ts +0 -17
- package/src/lib/processes/schema.ts +0 -74
- package/src/lib/processes/session-list.ts +0 -15
- package/src/lib/processes/state.ts +0 -82
- package/src/lib/processes/watchdog.test.ts +0 -79
- package/src/lib/processes/watchdog.ts +0 -106
- package/src/lib/remote-session/__tests__/protocol.test.ts +0 -291
- package/src/lib/remote-session/index.ts +0 -7
- package/src/lib/remote-session/protocol.ts +0 -443
- package/src/lib/remote-session/session-handler.ts +0 -1298
- package/src/lib/remote-session/workspace-scanner.ts +0 -161
- package/src/lib/sonner.web.ts +0 -1
- package/src/lib/storage/identity-store.web.ts +0 -94
- package/src/lib/tmux-lite/README.md +0 -81
- package/src/lib/tmux-lite/cli.ts +0 -855
- package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +0 -349
- package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +0 -291
- package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +0 -142
- package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +0 -339
- package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +0 -477
- package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +0 -499
- package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +0 -371
- package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +0 -573
- package/src/lib/tmux-lite/crypto/access-control.test.ts +0 -512
- package/src/lib/tmux-lite/crypto/access-control.ts +0 -320
- package/src/lib/tmux-lite/crypto/frames.test.ts +0 -262
- package/src/lib/tmux-lite/crypto/frames.ts +0 -141
- package/src/lib/tmux-lite/crypto/handshake.ts +0 -894
- package/src/lib/tmux-lite/crypto/identity.test.ts +0 -220
- package/src/lib/tmux-lite/crypto/identity.ts +0 -286
- package/src/lib/tmux-lite/crypto/index.ts +0 -51
- package/src/lib/tmux-lite/crypto/invites.test.ts +0 -381
- package/src/lib/tmux-lite/crypto/invites.ts +0 -215
- package/src/lib/tmux-lite/crypto/keyexchange.ts +0 -435
- package/src/lib/tmux-lite/crypto/keys.test.ts +0 -58
- package/src/lib/tmux-lite/crypto/keys.ts +0 -47
- package/src/lib/tmux-lite/crypto/secretbox.test.ts +0 -169
- package/src/lib/tmux-lite/crypto/secretbox.ts +0 -124
- package/src/lib/tmux-lite/handshake-handler.ts +0 -451
- package/src/lib/tmux-lite/process-run.integration.test.ts +0 -266
- package/src/lib/tmux-lite/protocol.test.ts +0 -307
- package/src/lib/tmux-lite/protocol.ts +0 -291
- package/src/lib/tmux-lite/relay-client.ts +0 -506
- package/src/lib/tmux-lite/server-lifecycle.test.ts +0 -212
- package/src/lib/tmux-lite/server.ts +0 -1412
- package/src/lib/tmux-lite/shell-integration.sh +0 -37
- package/src/lib/tmux-lite/terminal-queries.test.ts +0 -54
- package/src/lib/tmux-lite/terminal-queries.ts +0 -49
- package/src/notifications/__tests__/useNotifications.test.ts +0 -739
- package/src/notifications/index.ts +0 -32
- package/src/notifications/policy.test.ts +0 -424
- package/src/notifications/policy.ts +0 -139
- package/src/notifications/types.ts +0 -82
- package/src/notifications/useNotifications.ts +0 -350
- package/src/pages/ReviewPage.web.tsx +0 -511
- package/src/preferences/index.ts +0 -1
- package/src/preferences/types.ts +0 -9
- package/src/relay/__tests__/e2e-flow.test.ts +0 -1284
- package/src/relay/__tests__/helpers/auth.ts +0 -354
- package/src/relay/__tests__/helpers/ports.ts +0 -51
- package/src/relay/__tests__/protocol-validation.test.ts +0 -265
- package/src/relay/authorization.ts +0 -303
- package/src/relay/embedded-assets.generated.d.ts +0 -15
- package/src/relay/identity.ts +0 -352
- package/src/relay/index.ts +0 -57
- package/src/relay/pipes.test.ts +0 -427
- package/src/relay/pipes.ts +0 -195
- package/src/relay/protocol.ts +0 -804
- package/src/relay/registries.test.ts +0 -437
- package/src/relay/registries.ts +0 -593
- package/src/relay/server.test.ts +0 -1323
- package/src/relay/server.ts +0 -1128
- package/src/relay/signing.ts +0 -238
- package/src/relay/types.ts +0 -69
- package/src/relay-client/__tests__/machine-directory-client.test.ts +0 -152
- package/src/relay-client/__tests__/useMachineDirectory.test.ts +0 -172
- package/src/relay-client/adapters/browser.ts +0 -27
- package/src/relay-client/adapters/node.ts +0 -29
- package/src/relay-client/index.ts +0 -33
- package/src/relay-client/machine-directory-client.ts +0 -244
- package/src/relay-client/useMachineDirectory.ts +0 -175
- package/src/serve/client-session-manager.ts +0 -635
- package/src/serve/daemon.ts +0 -497
- package/src/serve/pty-session.ts +0 -236
- package/src/serve/types.ts +0 -174
- package/src/session/__tests__/backend-manager.test.ts +0 -101
- package/src/session/__tests__/local-session-backend.test.ts +0 -1129
- package/src/session/__tests__/reducer.test.ts +0 -80
- package/src/session/__tests__/remote-session-backend.test.ts +0 -995
- package/src/session/__tests__/session-name.test.ts +0 -35
- package/src/session/__tests__/useBundleRefreshAttachFlow.test.ts +0 -431
- package/src/session/__tests__/useRemoteSessionClient.test.ts +0 -424
- package/src/session/__tests__/workspace-shell-hooks.integration.test.ts +0 -268
- package/src/session/__tests__/workspace-shell-hooks.test.ts +0 -24
- package/src/session/adapters/browser-remote.ts +0 -101
- package/src/session/adapters/node-remote.ts +0 -135
- package/src/session/backend-key.ts +0 -5
- package/src/session/backend-manager.ts +0 -80
- package/src/session/backend.ts +0 -93
- package/src/session/backends/local-session-backend.ts +0 -1119
- package/src/session/backends/remote-session-backend.ts +0 -1378
- package/src/session/crypto/__tests__/web-terminal.test.ts +0 -1158
- package/src/session/crypto/frames.web.ts +0 -205
- package/src/session/crypto/handshake.web.ts +0 -396
- package/src/session/crypto/identity.web.ts +0 -133
- package/src/session/crypto/keyexchange.web.ts +0 -246
- package/src/session/crypto/relay-signing.web.ts +0 -53
- package/src/session/events.ts +0 -38
- package/src/session/index.ts +0 -116
- package/src/session/reducer.ts +0 -274
- package/src/session/selectors.ts +0 -28
- package/src/session/session-name.ts +0 -50
- package/src/session/types.ts +0 -101
- package/src/session/useBundleRefreshAttachFlow.ts +0 -608
- package/src/session/useRemoteSessionClient.ts +0 -424
- package/src/session/useSessionEngine.ts +0 -432
- package/src/session/workspace-shell-hooks.ts +0 -35
- package/src/tui/__tests__/input-text.test.ts +0 -24
- package/src/tui/__tests__/local-terminal-sync.test.ts +0 -82
- package/src/tui/__tests__/session-terminal-page-navigation.test.ts +0 -94
- package/src/tui/app.tsx +0 -2
- package/src/tui/index.ts +0 -18
- package/src/tui/input-text.ts +0 -38
- package/src/tui/local-terminal-sync.ts +0 -41
- package/src/types/bundle-refresh.ts +0 -42
- package/src/types/bundle.ts +0 -130
- package/src/types/config.ts +0 -287
- package/src/types/errors.ts +0 -292
- package/src/types/events.ts +0 -91
- package/src/types/identity.ts +0 -284
- package/src/types/processes.ts +0 -45
- package/src/types/review.ts +0 -349
- package/src/types/script-phase.ts +0 -3
- package/src/types/workspace-fuzzy.ts +0 -49
- package/src/types/workspace.ts +0 -151
- package/src/utils/__tests__/onboarding.test.ts +0 -358
- package/src/utils/__tests__/run-scripts.test.ts +0 -535
- package/src/utils/__tests__/run-workspace-scripts.test.ts +0 -406
- package/src/utils/__tests__/workspace-setup.integration.test.ts +0 -633
- package/src/utils/__tests__/workspace-state.test.ts +0 -78
- package/src/utils/bun-socket-writer.ts +0 -80
- package/src/utils/clipboard.ts +0 -53
- package/src/utils/deps.test.ts +0 -31
- package/src/utils/deps.ts +0 -145
- package/src/utils/device.web.ts +0 -163
- package/src/utils/fuzzy-match.ts +0 -125
- package/src/utils/hostnames.ts +0 -43
- package/src/utils/hunk-header.ts +0 -17
- package/src/utils/id.ts +0 -9
- package/src/utils/logger.ts +0 -127
- package/src/utils/markdown.ts +0 -254
- package/src/utils/normalize-env-key.ts +0 -13
- package/src/utils/onboarding.ts +0 -279
- package/src/utils/prompts.ts +0 -176
- package/src/utils/run-commands.ts +0 -112
- package/src/utils/run-scripts.ts +0 -337
- package/src/utils/run-workspace-scripts.ts +0 -355
- package/src/utils/sanitize.test.ts +0 -149
- package/src/utils/sanitize.ts +0 -162
- package/src/utils/secrets.ts +0 -836
- package/src/utils/shell-escape.ts +0 -40
- package/src/utils/utf8.ts +0 -79
- package/src/utils/workspace-id.ts +0 -55
- package/src/utils/workspace-state.ts +0 -427
- package/src/version.generated.d.ts +0 -2
- package/todo-security.md +0 -92
- package/tsconfig.json +0 -29
- package/web/README.md +0 -73
- package/web/bun.lock +0 -675
- package/web/eslint.config.js +0 -23
- package/web/index.css +0 -249
- package/web/index.html +0 -16
- package/web/main.tsx +0 -10
- package/web/package.json +0 -39
- package/web/public/vite.svg +0 -1
- package/web/tsconfig.app.json +0 -35
- package/web/tsconfig.json +0 -7
- package/web/tsconfig.node.json +0 -26
- package/web/vite.config.ts +0 -39
- package/worker/bun.lock +0 -237
- package/worker/package.json +0 -22
- package/worker/schema.sql +0 -96
- package/worker/src/handlers/auth.ts +0 -451
- package/worker/src/handlers/subdomains.ts +0 -376
- package/worker/src/handlers/user.ts +0 -98
- package/worker/src/index.ts +0 -70
- package/worker/src/middleware/auth.ts +0 -152
- package/worker/src/services/cloudflare.ts +0 -609
- package/worker/src/types.ts +0 -96
- package/worker/tsconfig.json +0 -15
- package/worker/wrangler.toml +0 -26
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type { Socket } from "bun";
|
|
2
|
-
|
|
3
|
-
type WritableData = Buffer | Uint8Array | ArrayBuffer;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Bun sockets are unbuffered. `socket.write()` can write fewer bytes than provided
|
|
7
|
-
* under backpressure. For framed protocols, partial writes will desync the reader.
|
|
8
|
-
*
|
|
9
|
-
* This helper buffers pending bytes and flushes them when the socket drains.
|
|
10
|
-
*/
|
|
11
|
-
export function createBufferedSocketWriter(socket: Socket<any>) {
|
|
12
|
-
const queue: Buffer[] = [];
|
|
13
|
-
let headOffset = 0;
|
|
14
|
-
|
|
15
|
-
const flush = () => {
|
|
16
|
-
while (queue.length > 0) {
|
|
17
|
-
const head = queue[0]!;
|
|
18
|
-
const remaining = head.length - headOffset;
|
|
19
|
-
|
|
20
|
-
if (remaining <= 0) {
|
|
21
|
-
queue.shift();
|
|
22
|
-
headOffset = 0;
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const written = socket.write(head, headOffset, remaining);
|
|
27
|
-
|
|
28
|
-
// -1: closed/shutting down. 0: backpressure.
|
|
29
|
-
if (written <= 0) return;
|
|
30
|
-
|
|
31
|
-
headOffset += written;
|
|
32
|
-
if (headOffset >= head.length) {
|
|
33
|
-
queue.shift();
|
|
34
|
-
headOffset = 0;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const write = (data: WritableData) => {
|
|
40
|
-
// Copy into a stable Buffer (avoids subarray lifetime issues and ensures queue owns bytes)
|
|
41
|
-
const buf = Buffer.from(data as any);
|
|
42
|
-
|
|
43
|
-
// Fast-path if nothing queued.
|
|
44
|
-
if (queue.length === 0) {
|
|
45
|
-
const written = socket.write(buf);
|
|
46
|
-
|
|
47
|
-
if (written <= 0) {
|
|
48
|
-
queue.push(buf);
|
|
49
|
-
headOffset = 0;
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (written >= buf.length) return;
|
|
54
|
-
|
|
55
|
-
queue.push(buf);
|
|
56
|
-
headOffset = written;
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
queue.push(buf);
|
|
61
|
-
flush();
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const clear = () => {
|
|
65
|
-
queue.length = 0;
|
|
66
|
-
headOffset = 0;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const pendingBytes = () => {
|
|
70
|
-
let total = 0;
|
|
71
|
-
for (let i = 0; i < queue.length; i++) total += queue[i]!.length;
|
|
72
|
-
return Math.max(0, total - headOffset);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
return { write, flush, clear, pendingBytes };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
package/src/utils/clipboard.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clipboard utilities for cross-platform clipboard operations.
|
|
3
|
-
*
|
|
4
|
-
* Uses a multi-layered approach:
|
|
5
|
-
* 1. OSC52 escape sequence - works over SSH, in tmux, remote terminals
|
|
6
|
-
* 2. clipboardy - handles platform-specific clipboard (pbcopy, xclip, etc.)
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import clipboard from 'clipboardy';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Copy text to clipboard using OSC52 + system clipboard fallback.
|
|
13
|
-
*
|
|
14
|
-
* OSC52 is written first because it works in remote/SSH sessions where
|
|
15
|
-
* the system clipboard wouldn't be accessible.
|
|
16
|
-
*
|
|
17
|
-
* @param text - The text to copy to clipboard
|
|
18
|
-
*/
|
|
19
|
-
export async function copyToClipboard(text: string): Promise<void> {
|
|
20
|
-
// 1. OSC52 escape sequence - works over SSH/remote sessions
|
|
21
|
-
// Format: ESC ] 52 ; c ; <base64-encoded-text> BEL
|
|
22
|
-
const base64 = Buffer.from(text).toString('base64');
|
|
23
|
-
const osc52 = `\x1b]52;c;${base64}\x07`;
|
|
24
|
-
|
|
25
|
-
// Wrap for tmux compatibility - tmux requires DCS wrapper
|
|
26
|
-
const finalOsc52 = process.env['TMUX']
|
|
27
|
-
? `\x1bPtmux;\x1b${osc52}\x1b\\`
|
|
28
|
-
: osc52;
|
|
29
|
-
|
|
30
|
-
process.stdout.write(finalOsc52);
|
|
31
|
-
|
|
32
|
-
// 2. Also use clipboardy for local system clipboard
|
|
33
|
-
// This handles pbcopy (macOS), xclip/xsel (Linux), clip.exe (Windows)
|
|
34
|
-
try {
|
|
35
|
-
await clipboard.write(text);
|
|
36
|
-
} catch {
|
|
37
|
-
// OSC52 should have worked for terminal-based copying
|
|
38
|
-
// Silently ignore clipboardy failures (e.g., headless environment)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Read text from clipboard.
|
|
44
|
-
*
|
|
45
|
-
* @returns The clipboard text, or undefined if unavailable
|
|
46
|
-
*/
|
|
47
|
-
export async function readFromClipboard(): Promise<string | undefined> {
|
|
48
|
-
try {
|
|
49
|
-
return await clipboard.read();
|
|
50
|
-
} catch {
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
}
|
package/src/utils/deps.test.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from 'bun:test';
|
|
2
|
-
import { checkCommandExists } from './deps.js';
|
|
3
|
-
|
|
4
|
-
describe('checkCommandExists', () => {
|
|
5
|
-
test('returns true for commands that exist', async () => {
|
|
6
|
-
// These should exist on any system running this test
|
|
7
|
-
expect(await checkCommandExists('ls')).toBe(true);
|
|
8
|
-
expect(await checkCommandExists('which')).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test('returns false for commands that do not exist', async () => {
|
|
12
|
-
expect(await checkCommandExists('nonexistent-command-xyz-123')).toBe(false);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test('returns false for invalid command names (injection prevention)', async () => {
|
|
16
|
-
expect(await checkCommandExists('ls; echo hacked')).toBe(false);
|
|
17
|
-
expect(await checkCommandExists('ls && rm -rf /')).toBe(false);
|
|
18
|
-
expect(await checkCommandExists('$(whoami)')).toBe(false);
|
|
19
|
-
expect(await checkCommandExists('ls | cat')).toBe(false);
|
|
20
|
-
expect(await checkCommandExists('')).toBe(false);
|
|
21
|
-
expect(await checkCommandExists('cmd with spaces')).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('allows valid command name characters', async () => {
|
|
25
|
-
// These are valid command name formats (alphanumeric, dash, underscore)
|
|
26
|
-
// They may not exist, but should pass validation
|
|
27
|
-
expect(await checkCommandExists('my-command')).toBe(false); // valid format, doesn't exist
|
|
28
|
-
expect(await checkCommandExists('my_command')).toBe(false); // valid format, doesn't exist
|
|
29
|
-
expect(await checkCommandExists('command123')).toBe(false); // valid format, doesn't exist
|
|
30
|
-
});
|
|
31
|
-
});
|
package/src/utils/deps.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dependency checking utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { exec, execFile } from 'child_process';
|
|
6
|
-
import { promisify } from 'util';
|
|
7
|
-
import type { Dependency } from '../types/workspace.js';
|
|
8
|
-
import { DependencyError, GitHubAuthError } from '../types/errors.js';
|
|
9
|
-
import { logger } from './logger.js';
|
|
10
|
-
|
|
11
|
-
const execAsync = promisify(exec);
|
|
12
|
-
const execFileAsync = promisify(execFile);
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Required system dependencies
|
|
16
|
-
*/
|
|
17
|
-
export const REQUIRED_DEPS: Dependency[] = [
|
|
18
|
-
{
|
|
19
|
-
name: 'GitHub CLI',
|
|
20
|
-
command: 'gh',
|
|
21
|
-
checkArgs: ['--version'],
|
|
22
|
-
installUrl: 'https://cli.github.com/',
|
|
23
|
-
authCheck: async () => {
|
|
24
|
-
try {
|
|
25
|
-
await execAsync('gh auth status');
|
|
26
|
-
return true;
|
|
27
|
-
} catch {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'Git',
|
|
34
|
-
command: 'git',
|
|
35
|
-
checkArgs: ['--version'],
|
|
36
|
-
installUrl: 'https://git-scm.com/',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'jq',
|
|
40
|
-
command: 'jq',
|
|
41
|
-
checkArgs: ['--version'],
|
|
42
|
-
installUrl: 'https://stedolan.github.io/jq/',
|
|
43
|
-
},
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Check if a command exists by running it with args
|
|
48
|
-
*/
|
|
49
|
-
async function commandExists(command: string, checkArgs: string[]): Promise<boolean> {
|
|
50
|
-
try {
|
|
51
|
-
await execAsync(`${command} ${checkArgs.join(' ')}`);
|
|
52
|
-
return true;
|
|
53
|
-
} catch {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Check if a command exists in PATH using `which`
|
|
60
|
-
* Validates command name to prevent injection
|
|
61
|
-
*/
|
|
62
|
-
export async function checkCommandExists(command: string): Promise<boolean> {
|
|
63
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(command)) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
await execFileAsync('which', [command]);
|
|
69
|
-
return true;
|
|
70
|
-
} catch {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Check all required dependencies
|
|
77
|
-
*/
|
|
78
|
-
export async function checkDependencies(deps: Dependency[] = REQUIRED_DEPS): Promise<{
|
|
79
|
-
missing: Dependency[];
|
|
80
|
-
allPresent: boolean;
|
|
81
|
-
}> {
|
|
82
|
-
const missing: Dependency[] = [];
|
|
83
|
-
|
|
84
|
-
for (const dep of deps) {
|
|
85
|
-
const exists = await commandExists(dep.command, dep.checkArgs);
|
|
86
|
-
if (!exists) {
|
|
87
|
-
missing.push(dep);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
missing,
|
|
93
|
-
allPresent: missing.length === 0,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Check GitHub CLI authentication
|
|
99
|
-
*/
|
|
100
|
-
export async function checkGitHubAuth(): Promise<void> {
|
|
101
|
-
const ghDep = REQUIRED_DEPS.find((d) => d.command === 'gh');
|
|
102
|
-
if (!ghDep?.authCheck) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const isAuthenticated = await ghDep.authCheck();
|
|
107
|
-
if (!isAuthenticated) {
|
|
108
|
-
throw new GitHubAuthError();
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Display missing dependencies and exit
|
|
114
|
-
*/
|
|
115
|
-
export function displayMissingDependencies(missing: Dependency[]): never {
|
|
116
|
-
logger.error('Missing required dependencies:\n');
|
|
117
|
-
|
|
118
|
-
for (const dep of missing) {
|
|
119
|
-
logger.log(` ${dep.name} (${dep.command})`);
|
|
120
|
-
logger.dim(` Install: ${dep.installUrl}\n`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
throw new DependencyError(
|
|
124
|
-
'Please install the missing dependencies and try again.'
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Check dependencies and throw if any are missing
|
|
130
|
-
*/
|
|
131
|
-
export async function ensureDependencies(deps?: Dependency[]): Promise<void> {
|
|
132
|
-
const { missing, allPresent } = await checkDependencies(deps);
|
|
133
|
-
|
|
134
|
-
if (!allPresent) {
|
|
135
|
-
displayMissingDependencies(missing);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Check specific dependencies (subset of all required)
|
|
141
|
-
*/
|
|
142
|
-
export async function checkSpecificDeps(commands: string[]): Promise<void> {
|
|
143
|
-
const depsToCheck = REQUIRED_DEPS.filter((d) => commands.includes(d.command));
|
|
144
|
-
await ensureDependencies(depsToCheck);
|
|
145
|
-
}
|
package/src/utils/device.web.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Device detection utilities for mobile-specific behavior.
|
|
3
|
-
* Comprehensive detection for iOS, Safari, PWA, and touch devices.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Detect iOS devices (iPhone, iPad, iPod).
|
|
8
|
-
* Includes detection for iPadOS 13+ which reports as MacIntel but has touch.
|
|
9
|
-
*/
|
|
10
|
-
export function isIOSDevice(): boolean {
|
|
11
|
-
if (typeof navigator === 'undefined') return false;
|
|
12
|
-
|
|
13
|
-
const ua = navigator.userAgent;
|
|
14
|
-
const iOS = /iPad|iPhone|iPod/.test(ua);
|
|
15
|
-
|
|
16
|
-
// iPadOS 13+ reports as MacIntel but has touch support
|
|
17
|
-
const iPadOS =
|
|
18
|
-
navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;
|
|
19
|
-
|
|
20
|
-
return iOS || iPadOS;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Detect if running as an installed PWA on iOS (standalone mode).
|
|
25
|
-
*/
|
|
26
|
-
export function isIOSPWA(): boolean {
|
|
27
|
-
if (!isIOSDevice()) return false;
|
|
28
|
-
return (navigator as { standalone?: boolean }).standalone === true;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Detect Safari browser (but not Chrome which includes "Safari" in UA).
|
|
33
|
-
*/
|
|
34
|
-
export function isSafari(): boolean {
|
|
35
|
-
if (typeof navigator === 'undefined') return false;
|
|
36
|
-
|
|
37
|
-
const ua = navigator.userAgent;
|
|
38
|
-
return (
|
|
39
|
-
/Safari/.test(ua) && !/Chrome/.test(ua) && !/Chromium/.test(ua)
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Detect Android devices.
|
|
45
|
-
*/
|
|
46
|
-
export function isAndroidDevice(): boolean {
|
|
47
|
-
if (typeof navigator === 'undefined') return false;
|
|
48
|
-
return /Android/.test(navigator.userAgent);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Detect any mobile device (iOS or Android).
|
|
53
|
-
*/
|
|
54
|
-
export function isMobileDevice(): boolean {
|
|
55
|
-
return isIOSDevice() || isAndroidDevice();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Detect touch-capable device.
|
|
60
|
-
* More reliable than checking for mobile OS since laptops can have touch.
|
|
61
|
-
*/
|
|
62
|
-
export function isTouchDevice(): boolean {
|
|
63
|
-
if (typeof window === 'undefined') return false;
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
'ontouchstart' in window ||
|
|
67
|
-
navigator.maxTouchPoints > 0 ||
|
|
68
|
-
// @ts-expect-error - msMaxTouchPoints is IE-specific
|
|
69
|
-
navigator.msMaxTouchPoints > 0
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Detect if device has a coarse pointer (finger/stylus vs mouse).
|
|
75
|
-
* Uses CSS media query for reliable detection.
|
|
76
|
-
*/
|
|
77
|
-
export function hasCoarsePointer(): boolean {
|
|
78
|
-
if (typeof window === 'undefined' || !window.matchMedia) return false;
|
|
79
|
-
return window.matchMedia('(pointer: coarse)').matches;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Detect if device cannot hover (touch-only, no mouse).
|
|
84
|
-
*/
|
|
85
|
-
export function cannotHover(): boolean {
|
|
86
|
-
if (typeof window === 'undefined' || !window.matchMedia) return false;
|
|
87
|
-
return window.matchMedia('(hover: none)').matches;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Detect mobile layout based on viewport width.
|
|
92
|
-
* Uses the same breakpoint as Tailwind's sm: (640px) or custom.
|
|
93
|
-
*/
|
|
94
|
-
export function isMobileLayout(breakpoint = 768): boolean {
|
|
95
|
-
if (typeof window === 'undefined' || !window.matchMedia) return false;
|
|
96
|
-
return window.matchMedia(`(max-width: ${breakpoint - 1}px)`).matches;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get platform-specific modifier key name.
|
|
101
|
-
* Returns 'Cmd' on Mac/iOS, 'Ctrl' on others.
|
|
102
|
-
*/
|
|
103
|
-
export function getPlatformModifier(): 'Cmd' | 'Ctrl' {
|
|
104
|
-
if (typeof navigator === 'undefined') return 'Ctrl';
|
|
105
|
-
|
|
106
|
-
const isMac =
|
|
107
|
-
navigator.platform?.startsWith('Mac') ||
|
|
108
|
-
isIOSDevice();
|
|
109
|
-
|
|
110
|
-
return isMac ? 'Cmd' : 'Ctrl';
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Trigger haptic feedback if supported.
|
|
115
|
-
* @param duration - Vibration duration in milliseconds (default: 10)
|
|
116
|
-
*/
|
|
117
|
-
export function triggerHaptic(duration = 10): void {
|
|
118
|
-
if (typeof navigator === 'undefined') return;
|
|
119
|
-
|
|
120
|
-
if ('vibrate' in navigator) {
|
|
121
|
-
try {
|
|
122
|
-
navigator.vibrate(duration);
|
|
123
|
-
} catch (err) {
|
|
124
|
-
// Log in development for debugging
|
|
125
|
-
if (import.meta.env.DEV) {
|
|
126
|
-
console.debug('Haptic feedback not available:', err);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Apply device-specific CSS classes to document element.
|
|
134
|
-
* Call once on app initialization.
|
|
135
|
-
*/
|
|
136
|
-
export function applyDeviceClasses(): void {
|
|
137
|
-
if (typeof document === 'undefined') return;
|
|
138
|
-
|
|
139
|
-
const root = document.documentElement;
|
|
140
|
-
|
|
141
|
-
if (isIOSDevice()) {
|
|
142
|
-
root.classList.add('ios-device');
|
|
143
|
-
if (isIOSPWA()) {
|
|
144
|
-
root.classList.add('ios-pwa');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (isSafari()) {
|
|
149
|
-
root.classList.add('safari');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (isAndroidDevice()) {
|
|
153
|
-
root.classList.add('android-device');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (isTouchDevice()) {
|
|
157
|
-
root.classList.add('touch-device');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (hasCoarsePointer()) {
|
|
161
|
-
root.classList.add('coarse-pointer');
|
|
162
|
-
}
|
|
163
|
-
}
|
package/src/utils/fuzzy-match.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fuzzy matching algorithm
|
|
3
|
-
* Matches query against candidates and returns scored results
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { FuzzyMatch, WorkspaceCandidate } from '../types/workspace-fuzzy.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Perform fuzzy matching on workspace candidates
|
|
10
|
-
*
|
|
11
|
-
* Algorithm:
|
|
12
|
-
* 1. For each candidate, calculate match score
|
|
13
|
-
* 2. Filter out scores below threshold (30)
|
|
14
|
-
* 3. Sort by score descending
|
|
15
|
-
*
|
|
16
|
-
* @param query Search string
|
|
17
|
-
* @param candidates List of workspace candidates
|
|
18
|
-
* @returns Sorted array of matches with scores
|
|
19
|
-
*/
|
|
20
|
-
export function fuzzyMatch(
|
|
21
|
-
query: string,
|
|
22
|
-
candidates: WorkspaceCandidate[]
|
|
23
|
-
): FuzzyMatch[] {
|
|
24
|
-
const matches: FuzzyMatch[] = [];
|
|
25
|
-
|
|
26
|
-
for (const candidate of candidates) {
|
|
27
|
-
const result = calculateMatchScore(query, candidate.name);
|
|
28
|
-
|
|
29
|
-
if (result.score >= 30) { // Minimum threshold
|
|
30
|
-
matches.push({
|
|
31
|
-
item: candidate,
|
|
32
|
-
score: result.score,
|
|
33
|
-
matchedIndices: result.matchedIndices,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Sort by score descending
|
|
39
|
-
matches.sort((a, b) => b.score - a.score);
|
|
40
|
-
|
|
41
|
-
return matches;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Calculate fuzzy match score between query and candidate
|
|
46
|
-
*
|
|
47
|
-
* Scoring rules:
|
|
48
|
-
* - All query characters must exist in order: otherwise score = 0
|
|
49
|
-
* - Consecutive character matches: +10 points per consecutive char
|
|
50
|
-
* - Word boundary matches: +5 points (e.g., "fb" matches "feature-branch")
|
|
51
|
-
* - Exact case match: +2 points per char
|
|
52
|
-
* - Start of string match: +15 points
|
|
53
|
-
* - Character proximity: -1 point per gap
|
|
54
|
-
* - Base score: 50 points if all chars match
|
|
55
|
-
*
|
|
56
|
-
* @param query Search string
|
|
57
|
-
* @param candidate String to match against
|
|
58
|
-
* @returns Object with score and matched character indices
|
|
59
|
-
*/
|
|
60
|
-
function calculateMatchScore(
|
|
61
|
-
query: string,
|
|
62
|
-
candidate: string
|
|
63
|
-
): { score: number; matchedIndices: number[] } {
|
|
64
|
-
if (!query || !candidate) {
|
|
65
|
-
return { score: 0, matchedIndices: [] };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const queryLower = query.toLowerCase();
|
|
69
|
-
const candidateLower = candidate.toLowerCase();
|
|
70
|
-
|
|
71
|
-
// Find all query characters in candidate
|
|
72
|
-
const matchedIndices: number[] = [];
|
|
73
|
-
let candidateIndex = 0;
|
|
74
|
-
|
|
75
|
-
for (let i = 0; i < queryLower.length; i++) {
|
|
76
|
-
const queryChar = queryLower[i];
|
|
77
|
-
const foundIndex = candidateLower.indexOf(queryChar, candidateIndex);
|
|
78
|
-
|
|
79
|
-
if (foundIndex === -1) {
|
|
80
|
-
// Character not found - no match
|
|
81
|
-
return { score: 0, matchedIndices: [] };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
matchedIndices.push(foundIndex);
|
|
85
|
-
candidateIndex = foundIndex + 1;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// All characters matched - start with base score
|
|
89
|
-
let score = 50;
|
|
90
|
-
|
|
91
|
-
// Bonus: Start of string match
|
|
92
|
-
if (matchedIndices[0] === 0) {
|
|
93
|
-
score += 15;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Calculate bonuses for consecutive matches, word boundaries, and case
|
|
97
|
-
for (let i = 0; i < matchedIndices.length; i++) {
|
|
98
|
-
const index = matchedIndices[i];
|
|
99
|
-
const queryChar = query[i];
|
|
100
|
-
const candidateChar = candidate[index];
|
|
101
|
-
|
|
102
|
-
// Consecutive match bonus
|
|
103
|
-
if (i > 0 && matchedIndices[i] === matchedIndices[i - 1] + 1) {
|
|
104
|
-
score += 10;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Word boundary bonus (after -, _, /, or at start)
|
|
108
|
-
if (index === 0 || ['-', '_', '/'].includes(candidate[index - 1])) {
|
|
109
|
-
score += 5;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Exact case match bonus
|
|
113
|
-
if (queryChar === candidateChar) {
|
|
114
|
-
score += 2;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Proximity penalty (gap between matched characters)
|
|
118
|
-
if (i > 0) {
|
|
119
|
-
const gap = matchedIndices[i] - matchedIndices[i - 1] - 1;
|
|
120
|
-
score -= gap; // -1 point per character gap
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return { score, matchedIndices };
|
|
125
|
-
}
|
package/src/utils/hostnames.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const MAX_LABEL_LENGTH = 63;
|
|
2
|
-
const MAX_HOSTNAME_LENGTH = 253;
|
|
3
|
-
|
|
4
|
-
function clampLabel(value: string, maxLength: number): string {
|
|
5
|
-
if (value.length <= maxLength) return value;
|
|
6
|
-
const trimmed = value.slice(0, maxLength).replace(/-+$/g, '');
|
|
7
|
-
return trimmed.length > 0 ? trimmed : 'x';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function normalizeHostLabel(value: string): string {
|
|
11
|
-
const normalized = value
|
|
12
|
-
.toLowerCase()
|
|
13
|
-
.replace(/[^a-z0-9-]/g, '-')
|
|
14
|
-
.replace(/-+/g, '-')
|
|
15
|
-
.replace(/^-|-$/g, '');
|
|
16
|
-
if (!normalized) return 'x';
|
|
17
|
-
return clampLabel(normalized, MAX_LABEL_LENGTH);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function buildProcessHostname(
|
|
21
|
-
serveDomain: string,
|
|
22
|
-
workspaceId: string,
|
|
23
|
-
processName: string,
|
|
24
|
-
instance: number,
|
|
25
|
-
portLabel: string
|
|
26
|
-
): string {
|
|
27
|
-
const workspaceSegment = normalizeHostLabel(workspaceId);
|
|
28
|
-
const processSegment = normalizeHostLabel(processName);
|
|
29
|
-
const portSegment = normalizeHostLabel(portLabel);
|
|
30
|
-
|
|
31
|
-
const base = `${portSegment}.${processSegment}-${instance}`;
|
|
32
|
-
const suffix = `.${serveDomain}`;
|
|
33
|
-
let hostname = `${base}.${workspaceSegment}${suffix}`;
|
|
34
|
-
|
|
35
|
-
if (hostname.length <= MAX_HOSTNAME_LENGTH) {
|
|
36
|
-
return hostname;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const availableWorkspace = MAX_HOSTNAME_LENGTH - base.length - suffix.length - 1;
|
|
40
|
-
const trimmedWorkspace = clampLabel(workspaceSegment, Math.max(1, availableWorkspace));
|
|
41
|
-
hostname = `${base}.${trimmedWorkspace}${suffix}`;
|
|
42
|
-
return hostname;
|
|
43
|
-
}
|
package/src/utils/hunk-header.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function normalizeHunkHeader(header: string): string {
|
|
2
|
-
const trimmed = header.trim();
|
|
3
|
-
if (!trimmed) {
|
|
4
|
-
return '@@ @@';
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const match = trimmed.match(/^@@\s*(.*?)\s*@@(?:\s*(.*))?$/);
|
|
8
|
-
if (!match) {
|
|
9
|
-
return trimmed.replace(/\s+/g, ' ');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const specs = (match[1] ?? '').trim().replace(/\s+/g, ' ');
|
|
13
|
-
const context = (match[2] ?? '').trim().replace(/\s+/g, ' ');
|
|
14
|
-
|
|
15
|
-
const headerCore = specs ? `@@ ${specs} @@` : '@@ @@';
|
|
16
|
-
return context ? `${headerCore} ${context}` : headerCore;
|
|
17
|
-
}
|
package/src/utils/id.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate a reasonably unique identifier.
|
|
3
|
-
*/
|
|
4
|
-
export function generateId(): string {
|
|
5
|
-
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
6
|
-
return crypto.randomUUID();
|
|
7
|
-
}
|
|
8
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
9
|
-
}
|