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/core/linear.ts
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Linear API integration for issue management
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { LinearClient, LinearError, type Issue } from '@linear/sdk'
|
|
6
|
-
import { SpacesError } from '../types/errors.js'
|
|
7
|
-
import { logger } from '../utils/logger.js'
|
|
8
|
-
import type { LinearIssue } from '../types/workspace.js'
|
|
9
|
-
import type { LinearTeamInfo } from '../types/config.js'
|
|
10
|
-
import { readGlobalConfig, readProjectConfig, getCurrentProject } from './config.js'
|
|
11
|
-
import { getSecret } from '../utils/secrets.js'
|
|
12
|
-
|
|
13
|
-
/** Key used to store Linear API key in keychain (user-level) */
|
|
14
|
-
export const LINEAR_API_KEY_SECRET = 'linear-api-key'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Get the secret key name for a project-specific Linear API key
|
|
18
|
-
*/
|
|
19
|
-
export function getProjectLinearSecretKey(projectName: string): string {
|
|
20
|
-
return `linear-api-key-${projectName}`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Singleton Linear client instance
|
|
25
|
-
*/
|
|
26
|
-
let clientInstance: LinearClient | null = null
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get or create Linear client instance
|
|
30
|
-
*/
|
|
31
|
-
function getLinearClient(apiKey: string): LinearClient {
|
|
32
|
-
if (!clientInstance) {
|
|
33
|
-
clientInstance = new LinearClient({ apiKey })
|
|
34
|
-
}
|
|
35
|
-
return clientInstance
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Reset the Linear client (useful when API key changes)
|
|
40
|
-
*/
|
|
41
|
-
export function resetLinearClient(): void {
|
|
42
|
-
clientInstance = null
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Custom error class for Linear API errors
|
|
47
|
-
*/
|
|
48
|
-
export class LinearAPIError extends SpacesError {
|
|
49
|
-
constructor(message: string, originalError?: unknown) {
|
|
50
|
-
super(message, 'SERVICE_ERROR', 3)
|
|
51
|
-
this.name = 'LinearAPIError'
|
|
52
|
-
|
|
53
|
-
if (originalError) {
|
|
54
|
-
logger.debug(`Linear API error: ${originalError}`)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Retry a function with exponential backoff
|
|
61
|
-
*/
|
|
62
|
-
async function fetchWithRetry<T>(
|
|
63
|
-
fetchFn: () => Promise<T>,
|
|
64
|
-
maxRetries = 3
|
|
65
|
-
): Promise<T> {
|
|
66
|
-
let lastError: unknown
|
|
67
|
-
|
|
68
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
69
|
-
try {
|
|
70
|
-
return await fetchFn()
|
|
71
|
-
} catch (error: unknown) {
|
|
72
|
-
lastError = error
|
|
73
|
-
|
|
74
|
-
// Check if it's a retryable error (429 or 5xx)
|
|
75
|
-
let shouldRetry = false
|
|
76
|
-
let statusCode: number | undefined
|
|
77
|
-
|
|
78
|
-
if (error instanceof LinearError) {
|
|
79
|
-
// @ts-ignore - response may or may not have status
|
|
80
|
-
statusCode = error.response?.status
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (statusCode === 429 || (statusCode && statusCode >= 500)) {
|
|
84
|
-
shouldRetry = true
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (shouldRetry && attempt < maxRetries - 1) {
|
|
88
|
-
// Exponential backoff: 200ms, 400ms, 800ms
|
|
89
|
-
const delay = 200 * Math.pow(2, attempt)
|
|
90
|
-
await new Promise((resolve) => setTimeout(resolve, delay))
|
|
91
|
-
continue
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
throw error
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
throw lastError
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Fetch all pages from a paginated Linear SDK response
|
|
103
|
-
*/
|
|
104
|
-
async function fetchAllPages<T extends { id: string }>(initialPage: {
|
|
105
|
-
nodes: T[]
|
|
106
|
-
pageInfo: { hasNextPage: boolean }
|
|
107
|
-
fetchNext?: () => Promise<{ nodes: T[]; pageInfo: { hasNextPage: boolean } }>
|
|
108
|
-
}): Promise<T[]> {
|
|
109
|
-
const allItems: T[] = []
|
|
110
|
-
const seenIds = new Set<string>()
|
|
111
|
-
let currentPage = initialPage
|
|
112
|
-
|
|
113
|
-
while (true) {
|
|
114
|
-
// Add unique items
|
|
115
|
-
for (const item of currentPage.nodes) {
|
|
116
|
-
if (!seenIds.has(item.id)) {
|
|
117
|
-
seenIds.add(item.id)
|
|
118
|
-
allItems.push(item)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!currentPage.pageInfo.hasNextPage || !currentPage.fetchNext) {
|
|
123
|
-
break
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
currentPage = await currentPage.fetchNext()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return allItems
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Fetch unstarted issues from Linear
|
|
134
|
-
* @param apiKey Linear API key
|
|
135
|
-
* @param teamKey Optional team key to filter by (e.g., "ENG")
|
|
136
|
-
* @returns Array of unstarted issues
|
|
137
|
-
*/
|
|
138
|
-
export async function fetchUnstartedIssues(
|
|
139
|
-
apiKey: string,
|
|
140
|
-
teamKey?: string
|
|
141
|
-
): Promise<LinearIssue[]> {
|
|
142
|
-
try {
|
|
143
|
-
return await fetchWithRetry(async () => {
|
|
144
|
-
const client = getLinearClient(apiKey)
|
|
145
|
-
|
|
146
|
-
// Build filter for unstarted issues
|
|
147
|
-
const filter = {
|
|
148
|
-
state: { type: { eq: 'unstarted' } },
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
let linearIssues: Issue[]
|
|
152
|
-
|
|
153
|
-
if (teamKey) {
|
|
154
|
-
// Fetch team first
|
|
155
|
-
const teamsConnection = await client.teams({
|
|
156
|
-
filter: { key: { eq: teamKey } },
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
const team = teamsConnection.nodes[0]
|
|
160
|
-
|
|
161
|
-
if (!team) {
|
|
162
|
-
throw new LinearAPIError(`Team with key "${teamKey}" not found`)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Fetch issues for the team
|
|
166
|
-
const issuesConnection = await team.issues({ filter })
|
|
167
|
-
linearIssues = await fetchAllPages(issuesConnection)
|
|
168
|
-
} else {
|
|
169
|
-
// Fetch all unstarted issues
|
|
170
|
-
const issuesConnection = await client.issues({ filter })
|
|
171
|
-
linearIssues = await fetchAllPages(issuesConnection)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const convertedIssues: LinearIssue[] = []
|
|
175
|
-
for (let i = 0; i < linearIssues.length; i++) {
|
|
176
|
-
const issue = linearIssues[i]
|
|
177
|
-
|
|
178
|
-
// Create a lazy function for attachments (only fetched when called)
|
|
179
|
-
const attachments = async () => {
|
|
180
|
-
const attachmentsConnection = await issue.attachments()
|
|
181
|
-
const linearAttachments = await fetchAllPages(attachmentsConnection)
|
|
182
|
-
|
|
183
|
-
// Convert to our attachment format
|
|
184
|
-
return linearAttachments.map((att) => ({
|
|
185
|
-
id: att.id,
|
|
186
|
-
url: att.url,
|
|
187
|
-
title: att.title ?? null,
|
|
188
|
-
sourceType: att.sourceType ?? null,
|
|
189
|
-
createdAt: att.createdAt,
|
|
190
|
-
}))
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
convertedIssues.push({
|
|
194
|
-
id: issue.id,
|
|
195
|
-
identifier: issue.identifier,
|
|
196
|
-
title: issue.title,
|
|
197
|
-
description: issue.description ?? null,
|
|
198
|
-
state: issue.state,
|
|
199
|
-
url: issue.url,
|
|
200
|
-
assignee: issue.assignee,
|
|
201
|
-
createdAt: issue.createdAt,
|
|
202
|
-
updatedAt: issue.updatedAt,
|
|
203
|
-
attachments,
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return convertedIssues
|
|
208
|
-
})
|
|
209
|
-
} catch (error) {
|
|
210
|
-
if (error instanceof LinearAPIError) {
|
|
211
|
-
throw error
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (error instanceof LinearError) {
|
|
215
|
-
throw new LinearAPIError(`Linear API error: ${error.message}`, error)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
throw new LinearAPIError(
|
|
219
|
-
`Failed to fetch Linear issues: ${
|
|
220
|
-
error instanceof Error ? error.message : 'Unknown error'
|
|
221
|
-
}`,
|
|
222
|
-
error
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Validate a Linear API key by fetching the viewer (authenticated user)
|
|
229
|
-
*/
|
|
230
|
-
export async function validateLinearApiKey(apiKey: string): Promise<boolean> {
|
|
231
|
-
try {
|
|
232
|
-
logger.debug('Validating Linear API key...')
|
|
233
|
-
const testClient = new LinearClient({ apiKey })
|
|
234
|
-
await testClient.viewer
|
|
235
|
-
logger.debug('Linear API key validation successful')
|
|
236
|
-
return true
|
|
237
|
-
} catch (error) {
|
|
238
|
-
logger.debug(
|
|
239
|
-
`Linear API key validation failed: ${
|
|
240
|
-
error instanceof Error ? error.message : 'Unknown error'
|
|
241
|
-
}`
|
|
242
|
-
)
|
|
243
|
-
return false
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Fetch all teams accessible with the API key
|
|
249
|
-
*/
|
|
250
|
-
export async function fetchLinearTeams(apiKey: string): Promise<LinearTeamInfo[]> {
|
|
251
|
-
try {
|
|
252
|
-
return await fetchWithRetry(async () => {
|
|
253
|
-
const client = getLinearClient(apiKey)
|
|
254
|
-
const teamsConnection = await client.teams()
|
|
255
|
-
const teams = await fetchAllPages(teamsConnection)
|
|
256
|
-
|
|
257
|
-
return teams.map((team) => ({
|
|
258
|
-
id: team.id,
|
|
259
|
-
key: team.key,
|
|
260
|
-
name: team.name,
|
|
261
|
-
}))
|
|
262
|
-
})
|
|
263
|
-
} catch (error) {
|
|
264
|
-
if (error instanceof LinearAPIError) {
|
|
265
|
-
throw error
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (error instanceof LinearError) {
|
|
269
|
-
throw new LinearAPIError(`Linear API error: ${error.message}`, error)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
throw new LinearAPIError(
|
|
273
|
-
`Failed to fetch Linear teams: ${
|
|
274
|
-
error instanceof Error ? error.message : 'Unknown error'
|
|
275
|
-
}`,
|
|
276
|
-
error
|
|
277
|
-
)
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Resolved Linear configuration with API key and team info
|
|
283
|
-
*/
|
|
284
|
-
export interface ResolvedLinearConfig {
|
|
285
|
-
/** API key from keychain (null if not configured) */
|
|
286
|
-
apiKey: string | null
|
|
287
|
-
/** Team keys to use (from project or user default) */
|
|
288
|
-
teamKeys: string[]
|
|
289
|
-
/** Full team info from user config */
|
|
290
|
-
teams: LinearTeamInfo[]
|
|
291
|
-
/** Whether config came from project or user level */
|
|
292
|
-
scope: 'project' | 'user' | 'none'
|
|
293
|
-
/** Whether project has its own API key (vs inheriting from user) */
|
|
294
|
-
hasProjectApiKey: boolean
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Get Linear configuration with project -> user fallback
|
|
299
|
-
*
|
|
300
|
-
* Resolution order for API key:
|
|
301
|
-
* 1. Project-level API key (if set)
|
|
302
|
-
* 2. User-level API key
|
|
303
|
-
*
|
|
304
|
-
* Resolution order for teams:
|
|
305
|
-
* 1. Project-level linearTeams (if set)
|
|
306
|
-
* 2. User-level linearDefaultTeam (if set)
|
|
307
|
-
* 3. First team in user's linearTeams
|
|
308
|
-
*/
|
|
309
|
-
export async function getLinearConfig(projectName?: string): Promise<ResolvedLinearConfig> {
|
|
310
|
-
const project = projectName || getCurrentProject()
|
|
311
|
-
|
|
312
|
-
// Get user-level config
|
|
313
|
-
const globalConfig = readGlobalConfig()
|
|
314
|
-
const userTeams = globalConfig.linearTeams || []
|
|
315
|
-
const userDefaultTeam = globalConfig.linearDefaultTeam
|
|
316
|
-
|
|
317
|
-
// Check for project-level API key first
|
|
318
|
-
let apiKey: string | null = null
|
|
319
|
-
let hasProjectApiKey = false
|
|
320
|
-
|
|
321
|
-
if (project) {
|
|
322
|
-
const projectSecretKey = getProjectLinearSecretKey(project)
|
|
323
|
-
const projectApiKey = await getSecret(projectSecretKey)
|
|
324
|
-
if (projectApiKey) {
|
|
325
|
-
apiKey = projectApiKey
|
|
326
|
-
hasProjectApiKey = true
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Fall back to user-level API key
|
|
331
|
-
if (!apiKey) {
|
|
332
|
-
apiKey = await getSecret(LINEAR_API_KEY_SECRET)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// If no API key, return empty config
|
|
336
|
-
if (!apiKey) {
|
|
337
|
-
return {
|
|
338
|
-
apiKey: null,
|
|
339
|
-
teamKeys: [],
|
|
340
|
-
teams: userTeams,
|
|
341
|
-
scope: 'none',
|
|
342
|
-
hasProjectApiKey: false,
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Check for project-level override
|
|
347
|
-
if (project) {
|
|
348
|
-
try {
|
|
349
|
-
const projectConfig = readProjectConfig(project)
|
|
350
|
-
|
|
351
|
-
// Handle legacy config (deprecated linearApiKey/linearTeamKey)
|
|
352
|
-
if (projectConfig.linearApiKey || projectConfig.linearTeamKey) {
|
|
353
|
-
// Legacy config exists - use linearTeamKey if set
|
|
354
|
-
const legacyTeamKey = projectConfig.linearTeamKey
|
|
355
|
-
if (legacyTeamKey) {
|
|
356
|
-
return {
|
|
357
|
-
apiKey,
|
|
358
|
-
teamKeys: [legacyTeamKey],
|
|
359
|
-
teams: userTeams,
|
|
360
|
-
scope: 'project',
|
|
361
|
-
hasProjectApiKey,
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// New config - project-level team override
|
|
367
|
-
if (projectConfig.linearTeams && projectConfig.linearTeams.length > 0) {
|
|
368
|
-
return {
|
|
369
|
-
apiKey,
|
|
370
|
-
teamKeys: projectConfig.linearTeams,
|
|
371
|
-
teams: userTeams,
|
|
372
|
-
scope: 'project',
|
|
373
|
-
hasProjectApiKey,
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
} catch {
|
|
377
|
-
// Project doesn't exist, fall through to user config
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Fall back to user-level config
|
|
382
|
-
const teamKeys = userDefaultTeam
|
|
383
|
-
? [userDefaultTeam]
|
|
384
|
-
: userTeams.length > 0
|
|
385
|
-
? [userTeams[0].key]
|
|
386
|
-
: []
|
|
387
|
-
|
|
388
|
-
return {
|
|
389
|
-
apiKey,
|
|
390
|
-
teamKeys,
|
|
391
|
-
teams: userTeams,
|
|
392
|
-
scope: teamKeys.length > 0 ? 'user' : 'none',
|
|
393
|
-
hasProjectApiKey,
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Check if Linear is configured (has API key and at least one team)
|
|
399
|
-
*/
|
|
400
|
-
export async function isLinearConfigured(): Promise<boolean> {
|
|
401
|
-
const config = await getLinearConfig()
|
|
402
|
-
return config.apiKey !== null && config.teamKeys.length > 0
|
|
403
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getNotificationConfig,
|
|
3
|
-
updateNotificationConfig as updateNotificationConfigCore,
|
|
4
|
-
} from './config.js';
|
|
5
|
-
import type { PreferencesService } from '../preferences/index.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Preferences service backed by local gitspace config files.
|
|
9
|
-
*/
|
|
10
|
-
export const localPreferencesService: PreferencesService = {
|
|
11
|
-
async getNotificationConfig() {
|
|
12
|
-
return getNotificationConfig();
|
|
13
|
-
},
|
|
14
|
-
async updateNotificationConfig(config) {
|
|
15
|
-
return updateNotificationConfigCore(config);
|
|
16
|
-
},
|
|
17
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import {
|
|
4
|
-
getAllProjectNames,
|
|
5
|
-
getCurrentProject,
|
|
6
|
-
getProjectWorkspacesDir,
|
|
7
|
-
readProjectConfig,
|
|
8
|
-
} from './config.js';
|
|
9
|
-
|
|
10
|
-
export interface ProjectSummary {
|
|
11
|
-
name: string;
|
|
12
|
-
repository: string;
|
|
13
|
-
workspaceCount: number;
|
|
14
|
-
isCurrent: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* List projects with workspace counts and current-project marker.
|
|
19
|
-
*/
|
|
20
|
-
export function listProjectSummaries(): ProjectSummary[] {
|
|
21
|
-
const projectNames = getAllProjectNames();
|
|
22
|
-
const currentProject = getCurrentProject();
|
|
23
|
-
|
|
24
|
-
return projectNames.map((name) => {
|
|
25
|
-
const config = readProjectConfig(name);
|
|
26
|
-
const workspacesDir = getProjectWorkspacesDir(name);
|
|
27
|
-
let workspaceCount = 0;
|
|
28
|
-
|
|
29
|
-
if (existsSync(workspacesDir)) {
|
|
30
|
-
workspaceCount = readdirSync(workspacesDir)
|
|
31
|
-
.filter((entry) => {
|
|
32
|
-
const path = join(workspacesDir, entry);
|
|
33
|
-
if (!existsSync(path)) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
return readdirSync(path).length > 0;
|
|
38
|
-
} catch {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
.length;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
name,
|
|
47
|
-
repository: config.repository,
|
|
48
|
-
workspaceCount,
|
|
49
|
-
isCurrent: name === currentProject,
|
|
50
|
-
};
|
|
51
|
-
});
|
|
52
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared project lifecycle helpers for bundle state persistence.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
getProjectBaseDir,
|
|
7
|
-
readProjectConfig,
|
|
8
|
-
updateProjectConfig,
|
|
9
|
-
} from './config.js';
|
|
10
|
-
import {
|
|
11
|
-
getConfirmStepFingerprint,
|
|
12
|
-
hashBundle,
|
|
13
|
-
syncBundleWorkspaceState,
|
|
14
|
-
} from './bundle-refresh.js';
|
|
15
|
-
import { setProjectSecret } from '../utils/secrets.js';
|
|
16
|
-
import type { ConfirmStepResult, SpacesBundle } from '../types/bundle.js';
|
|
17
|
-
|
|
18
|
-
const BASE_SCOPE = '__base__';
|
|
19
|
-
|
|
20
|
-
interface ApplyProjectBundleStateOptions {
|
|
21
|
-
projectName: string;
|
|
22
|
-
bundle: SpacesBundle;
|
|
23
|
-
/** Non-secret onboarding values (input steps). */
|
|
24
|
-
inputValues?: Record<string, string>;
|
|
25
|
-
/** Secret onboarding values that should be written to keychain. */
|
|
26
|
-
secretValues?: Record<string, string>;
|
|
27
|
-
/** Secret keys already persisted outside this helper. */
|
|
28
|
-
secretKeys?: string[];
|
|
29
|
-
/** Confirm step results keyed by step id. */
|
|
30
|
-
confirmResults?: Record<string, ConfirmStepResult>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface ProjectLifecycleDeps {
|
|
34
|
-
getProjectBaseDir: typeof getProjectBaseDir;
|
|
35
|
-
readProjectConfig: typeof readProjectConfig;
|
|
36
|
-
updateProjectConfig: typeof updateProjectConfig;
|
|
37
|
-
syncBundleWorkspaceState: typeof syncBundleWorkspaceState;
|
|
38
|
-
hashBundle: typeof hashBundle;
|
|
39
|
-
getConfirmStepFingerprint: typeof getConfirmStepFingerprint;
|
|
40
|
-
setProjectSecret: typeof setProjectSecret;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const defaultDeps: ProjectLifecycleDeps = {
|
|
44
|
-
getProjectBaseDir,
|
|
45
|
-
readProjectConfig,
|
|
46
|
-
updateProjectConfig,
|
|
47
|
-
syncBundleWorkspaceState,
|
|
48
|
-
hashBundle,
|
|
49
|
-
getConfirmStepFingerprint,
|
|
50
|
-
setProjectSecret,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
function uniqueSorted(values: string[]): string[] {
|
|
54
|
-
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Persist bundle-derived project state in a shared, workspace-aware format.
|
|
59
|
-
*/
|
|
60
|
-
export async function applyProjectBundleState(
|
|
61
|
-
options: ApplyProjectBundleStateOptions,
|
|
62
|
-
deps: ProjectLifecycleDeps = defaultDeps
|
|
63
|
-
): Promise<void> {
|
|
64
|
-
const {
|
|
65
|
-
projectName,
|
|
66
|
-
bundle,
|
|
67
|
-
inputValues = {},
|
|
68
|
-
secretValues = {},
|
|
69
|
-
secretKeys = [],
|
|
70
|
-
confirmResults = {},
|
|
71
|
-
} = options;
|
|
72
|
-
|
|
73
|
-
// Seed/refresh base workspace scope metadata and required key unions.
|
|
74
|
-
const baseDir = deps.getProjectBaseDir(projectName);
|
|
75
|
-
const syncResult = deps.syncBundleWorkspaceState(projectName, baseDir);
|
|
76
|
-
|
|
77
|
-
if (!syncResult.hasBundle) {
|
|
78
|
-
const onboardingSteps = bundle.onboarding || [];
|
|
79
|
-
const requiredInputKeys = uniqueSorted(onboardingSteps
|
|
80
|
-
.filter((step) => step.type === 'input')
|
|
81
|
-
.map((step) => step.configKey));
|
|
82
|
-
const requiredSecretKeys = uniqueSorted(onboardingSteps
|
|
83
|
-
.filter((step) => step.type === 'secret')
|
|
84
|
-
.map((step) => step.configKey));
|
|
85
|
-
const confirmFingerprints = uniqueSorted(onboardingSteps
|
|
86
|
-
.filter((step) => step.type === 'confirm')
|
|
87
|
-
.map((step) => deps.getConfirmStepFingerprint(step)));
|
|
88
|
-
|
|
89
|
-
const seedConfig = deps.readProjectConfig(projectName);
|
|
90
|
-
const nextWorkspaceState = {
|
|
91
|
-
...(seedConfig.bundleWorkspaceState || {}),
|
|
92
|
-
[BASE_SCOPE]: {
|
|
93
|
-
scope: BASE_SCOPE,
|
|
94
|
-
bundleHash: deps.hashBundle(bundle),
|
|
95
|
-
requiredInputKeys,
|
|
96
|
-
requiredSecretKeys,
|
|
97
|
-
confirmFingerprints,
|
|
98
|
-
updatedAt: new Date().toISOString(),
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const mergedSecretKeys = uniqueSorted([
|
|
103
|
-
...(seedConfig.bundleSecretKeys || []),
|
|
104
|
-
...requiredSecretKeys,
|
|
105
|
-
]);
|
|
106
|
-
|
|
107
|
-
deps.updateProjectConfig(projectName, {
|
|
108
|
-
bundleWorkspaceState: nextWorkspaceState,
|
|
109
|
-
bundleSecretKeys: mergedSecretKeys.length > 0 ? mergedSecretKeys : undefined,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Persist new secret values to keychain.
|
|
114
|
-
for (const [key, value] of Object.entries(secretValues)) {
|
|
115
|
-
if (value) {
|
|
116
|
-
await deps.setProjectSecret(projectName, key, value);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const config = deps.readProjectConfig(projectName);
|
|
121
|
-
const mergedValues = {
|
|
122
|
-
...(config.bundleValues || {}),
|
|
123
|
-
...inputValues,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const mergedSecretKeys = uniqueSorted([
|
|
127
|
-
...(config.bundleSecretKeys || []),
|
|
128
|
-
...secretKeys,
|
|
129
|
-
...Object.keys(secretValues),
|
|
130
|
-
]);
|
|
131
|
-
|
|
132
|
-
const bundleHash = syncResult.bundleHash || deps.hashBundle(bundle);
|
|
133
|
-
const scope = syncResult.scope || BASE_SCOPE;
|
|
134
|
-
const history = { ...(config.bundleConfirmHistory || {}) };
|
|
135
|
-
|
|
136
|
-
for (const step of bundle.onboarding || []) {
|
|
137
|
-
if (step.type !== 'confirm') {
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const result = confirmResults[step.id];
|
|
142
|
-
if (!result) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const fingerprint = deps.getConfirmStepFingerprint(step);
|
|
147
|
-
history[fingerprint] = {
|
|
148
|
-
fingerprint,
|
|
149
|
-
stepId: step.id,
|
|
150
|
-
checkCommand: step.checkCommand,
|
|
151
|
-
status: result.status,
|
|
152
|
-
scope,
|
|
153
|
-
bundleHash,
|
|
154
|
-
checkedAt: new Date().toISOString(),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
deps.updateProjectConfig(projectName, {
|
|
159
|
-
bundleValues: Object.keys(mergedValues).length > 0 ? mergedValues : undefined,
|
|
160
|
-
bundleSecretKeys: mergedSecretKeys.length > 0 ? mergedSecretKeys : undefined,
|
|
161
|
-
bundleConfirmHistory: Object.keys(history).length > 0 ? history : undefined,
|
|
162
|
-
});
|
|
163
|
-
}
|