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,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process session naming tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from 'bun:test';
|
|
6
|
-
import {
|
|
7
|
-
buildProcessSessionName,
|
|
8
|
-
encodeProcessNameForPath,
|
|
9
|
-
parseProcessSessionName,
|
|
10
|
-
PROCESS_SESSION_PREFIX,
|
|
11
|
-
PROCESS_SESSION_MAX_NAME,
|
|
12
|
-
} from '../names.js';
|
|
13
|
-
|
|
14
|
-
// ============================================================================
|
|
15
|
-
// buildProcessSessionName
|
|
16
|
-
// ============================================================================
|
|
17
|
-
|
|
18
|
-
describe('buildProcessSessionName', () => {
|
|
19
|
-
it('should build name with correct format', () => {
|
|
20
|
-
const name = buildProcessSessionName('my-workspace', 'web', 1);
|
|
21
|
-
expect(name).toBe('proc:my-workspace:web:1');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should use the PROCESS_SESSION_PREFIX', () => {
|
|
25
|
-
const name = buildProcessSessionName('ws', 'api', 2);
|
|
26
|
-
expect(name.startsWith(`${PROCESS_SESSION_PREFIX}:`)).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should truncate names exceeding max length', () => {
|
|
30
|
-
const longWorkspace = 'a'.repeat(80);
|
|
31
|
-
const name = buildProcessSessionName(longWorkspace, 'web', 1);
|
|
32
|
-
expect(name.length).toBeLessThanOrEqual(PROCESS_SESSION_MAX_NAME);
|
|
33
|
-
expect(parseProcessSessionName(name)).not.toBeNull();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should not truncate short names', () => {
|
|
37
|
-
const name = buildProcessSessionName('ws', 'api', 1);
|
|
38
|
-
expect(name).toBe('proc:ws:api:1');
|
|
39
|
-
expect(name.length).toBeLessThan(PROCESS_SESSION_MAX_NAME);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should handle instance numbers > 1', () => {
|
|
43
|
-
const name = buildProcessSessionName('ws', 'worker', 5);
|
|
44
|
-
expect(name).toBe('proc:ws:worker:5');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// ============================================================================
|
|
49
|
-
// parseProcessSessionName
|
|
50
|
-
// ============================================================================
|
|
51
|
-
|
|
52
|
-
describe('parseProcessSessionName', () => {
|
|
53
|
-
it('should parse a valid process session name', () => {
|
|
54
|
-
const result = parseProcessSessionName('proc:my-workspace:web:1');
|
|
55
|
-
expect(result).toEqual({
|
|
56
|
-
workspaceId: 'my-workspace',
|
|
57
|
-
processName: 'web',
|
|
58
|
-
instance: 1,
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should return null for non-process names', () => {
|
|
63
|
-
expect(parseProcessSessionName('alpha:ws:1')).toBeNull();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should return null for empty string', () => {
|
|
67
|
-
expect(parseProcessSessionName('')).toBeNull();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should return null for wrong prefix', () => {
|
|
71
|
-
expect(parseProcessSessionName('session:ws:web:1')).toBeNull();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should return null for too few parts', () => {
|
|
75
|
-
expect(parseProcessSessionName('proc:ws')).toBeNull();
|
|
76
|
-
expect(parseProcessSessionName('proc:ws:web')).toBeNull();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should return null for non-numeric instance', () => {
|
|
80
|
-
expect(parseProcessSessionName('proc:ws:web:abc')).toBeNull();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should handle instance 0', () => {
|
|
84
|
-
const result = parseProcessSessionName('proc:ws:web:0');
|
|
85
|
-
expect(result).toEqual({
|
|
86
|
-
workspaceId: 'ws',
|
|
87
|
-
processName: 'web',
|
|
88
|
-
instance: 0,
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// ============================================================================
|
|
94
|
-
// Round-trip
|
|
95
|
-
// ============================================================================
|
|
96
|
-
|
|
97
|
-
describe('buildProcessSessionName / parseProcessSessionName round-trip', () => {
|
|
98
|
-
it('should round-trip standard names', () => {
|
|
99
|
-
const name = buildProcessSessionName('workspace', 'dev-server', 1);
|
|
100
|
-
const parsed = parseProcessSessionName(name);
|
|
101
|
-
expect(parsed).toEqual({
|
|
102
|
-
workspaceId: 'workspace',
|
|
103
|
-
processName: 'dev-server',
|
|
104
|
-
instance: 1,
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should round-trip multi-instance', () => {
|
|
109
|
-
for (let i = 1; i <= 5; i++) {
|
|
110
|
-
const name = buildProcessSessionName('ws', 'worker', i);
|
|
111
|
-
const parsed = parseProcessSessionName(name);
|
|
112
|
-
expect(parsed?.instance).toBe(i);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe('encodeProcessNameForPath', () => {
|
|
118
|
-
it('encodes path separators and dot segments safely', () => {
|
|
119
|
-
expect(encodeProcessNameForPath('../api/server')).toBe('..%2Fapi%2Fserver');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('keeps simple names readable', () => {
|
|
123
|
-
expect(encodeProcessNameForPath('web-server')).toBe('web-server');
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process schema validation tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from 'bun:test';
|
|
6
|
-
import { validateProcessesConfig, describeProcess } from '../schema.js';
|
|
7
|
-
import type { ProcessesConfig, ProcessDefinition } from '../../../types/processes.js';
|
|
8
|
-
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// validateProcessesConfig
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
describe('validateProcessesConfig', () => {
|
|
14
|
-
it('should pass for valid config with one process', () => {
|
|
15
|
-
const config: ProcessesConfig = {
|
|
16
|
-
processes: [{ name: 'web', command: 'npm start' }],
|
|
17
|
-
};
|
|
18
|
-
const result = validateProcessesConfig(config);
|
|
19
|
-
expect(result.valid).toBe(true);
|
|
20
|
-
expect(result.errors).toEqual([]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should pass for valid config with multiple processes', () => {
|
|
24
|
-
const config: ProcessesConfig = {
|
|
25
|
-
processes: [
|
|
26
|
-
{ name: 'web', command: 'npm start' },
|
|
27
|
-
{ name: 'worker', command: 'npm run worker' },
|
|
28
|
-
],
|
|
29
|
-
};
|
|
30
|
-
const result = validateProcessesConfig(config);
|
|
31
|
-
expect(result.valid).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should pass for empty processes array', () => {
|
|
35
|
-
const config: ProcessesConfig = { processes: [] };
|
|
36
|
-
const result = validateProcessesConfig(config);
|
|
37
|
-
expect(result.valid).toBe(true);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should fail when processes is not an array', () => {
|
|
41
|
-
const config = { processes: 'not-an-array' } as unknown as ProcessesConfig;
|
|
42
|
-
const result = validateProcessesConfig(config);
|
|
43
|
-
expect(result.valid).toBe(false);
|
|
44
|
-
expect(result.errors).toContain('processes must be an array');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should fail when process has no name', () => {
|
|
48
|
-
const config = {
|
|
49
|
-
processes: [{ command: 'npm start' }],
|
|
50
|
-
} as unknown as ProcessesConfig;
|
|
51
|
-
const result = validateProcessesConfig(config);
|
|
52
|
-
expect(result.valid).toBe(false);
|
|
53
|
-
expect(result.errors).toContain('process is missing name');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should fail for duplicate process names', () => {
|
|
57
|
-
const config: ProcessesConfig = {
|
|
58
|
-
processes: [
|
|
59
|
-
{ name: 'web', command: 'npm start' },
|
|
60
|
-
{ name: 'web', command: 'npm run dev' },
|
|
61
|
-
],
|
|
62
|
-
};
|
|
63
|
-
const result = validateProcessesConfig(config);
|
|
64
|
-
expect(result.valid).toBe(false);
|
|
65
|
-
expect(result.errors).toContain('duplicate process name: web');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should fail when process has no command', () => {
|
|
69
|
-
const config = {
|
|
70
|
-
processes: [{ name: 'web' }],
|
|
71
|
-
} as unknown as ProcessesConfig;
|
|
72
|
-
const result = validateProcessesConfig(config);
|
|
73
|
-
expect(result.valid).toBe(false);
|
|
74
|
-
expect(result.errors).toContain('process web missing command');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should allow instances set to 0 (disabled process)', () => {
|
|
78
|
-
const config: ProcessesConfig = {
|
|
79
|
-
processes: [{ name: 'worker', command: 'npm run worker', instances: 0 }],
|
|
80
|
-
};
|
|
81
|
-
const result = validateProcessesConfig(config);
|
|
82
|
-
expect(result.valid).toBe(true);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should fail when instances is negative', () => {
|
|
86
|
-
const config = {
|
|
87
|
-
processes: [{ name: 'worker', command: 'npm run worker', instances: -1 }],
|
|
88
|
-
} as unknown as ProcessesConfig;
|
|
89
|
-
const result = validateProcessesConfig(config);
|
|
90
|
-
expect(result.valid).toBe(false);
|
|
91
|
-
expect(result.errors).toContain('process worker instances must be a non-negative integer');
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should fail when instances is not an integer', () => {
|
|
95
|
-
const config = {
|
|
96
|
-
processes: [{ name: 'worker', command: 'npm run worker', instances: 1.5 }],
|
|
97
|
-
} as unknown as ProcessesConfig;
|
|
98
|
-
const result = validateProcessesConfig(config);
|
|
99
|
-
expect(result.valid).toBe(false);
|
|
100
|
-
expect(result.errors).toContain('process worker instances must be a non-negative integer');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('should fail when keepRawOutput is not boolean', () => {
|
|
104
|
-
const config = {
|
|
105
|
-
processes: [
|
|
106
|
-
{ name: 'web', command: 'npm start', events: { keepRawOutput: 'yes' } },
|
|
107
|
-
],
|
|
108
|
-
} as unknown as ProcessesConfig;
|
|
109
|
-
const result = validateProcessesConfig(config);
|
|
110
|
-
expect(result.valid).toBe(false);
|
|
111
|
-
expect(result.errors[0]).toContain('keepRawOutput must be a boolean');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('should pass when keepRawOutput is boolean', () => {
|
|
115
|
-
const config: ProcessesConfig = {
|
|
116
|
-
processes: [
|
|
117
|
-
{ name: 'web', command: 'npm start', events: { keepRawOutput: true } },
|
|
118
|
-
],
|
|
119
|
-
};
|
|
120
|
-
const result = validateProcessesConfig(config);
|
|
121
|
-
expect(result.valid).toBe(true);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('should fail when ports is not an array', () => {
|
|
125
|
-
const config = {
|
|
126
|
-
processes: [{ name: 'web', command: 'npm start', ports: 'not-array' }],
|
|
127
|
-
} as unknown as ProcessesConfig;
|
|
128
|
-
const result = validateProcessesConfig(config);
|
|
129
|
-
expect(result.valid).toBe(false);
|
|
130
|
-
expect(result.errors[0]).toContain('ports must be an array');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should fail for port out of range', () => {
|
|
134
|
-
const config: ProcessesConfig = {
|
|
135
|
-
processes: [
|
|
136
|
-
{ name: 'web', command: 'npm start', ports: [{ port: 0 }] },
|
|
137
|
-
],
|
|
138
|
-
};
|
|
139
|
-
const result = validateProcessesConfig(config);
|
|
140
|
-
expect(result.valid).toBe(false);
|
|
141
|
-
expect(result.errors[0]).toContain('port must be a number between 1 and 65535');
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should fail for port over 65535', () => {
|
|
145
|
-
const config: ProcessesConfig = {
|
|
146
|
-
processes: [
|
|
147
|
-
{ name: 'web', command: 'npm start', ports: [{ port: 70000 }] },
|
|
148
|
-
],
|
|
149
|
-
};
|
|
150
|
-
const result = validateProcessesConfig(config);
|
|
151
|
-
expect(result.valid).toBe(false);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should pass for valid port config', () => {
|
|
155
|
-
const config: ProcessesConfig = {
|
|
156
|
-
processes: [
|
|
157
|
-
{ name: 'web', command: 'npm start', ports: [{ port: 3000, name: 'http', protocol: 'http' }] },
|
|
158
|
-
],
|
|
159
|
-
};
|
|
160
|
-
const result = validateProcessesConfig(config);
|
|
161
|
-
expect(result.valid).toBe(true);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should fail for invalid port protocol', () => {
|
|
165
|
-
const config = {
|
|
166
|
-
processes: [
|
|
167
|
-
{ name: 'web', command: 'npm start', ports: [{ port: 3000, protocol: 'udp' }] },
|
|
168
|
-
],
|
|
169
|
-
} as unknown as ProcessesConfig;
|
|
170
|
-
const result = validateProcessesConfig(config);
|
|
171
|
-
expect(result.valid).toBe(false);
|
|
172
|
-
expect(result.errors[0]).toContain('protocol must be http or tcp');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('should accumulate multiple errors', () => {
|
|
176
|
-
const config = {
|
|
177
|
-
processes: [
|
|
178
|
-
{ name: 'web', command: 'npm start' },
|
|
179
|
-
{ name: 'web', command: 'npm run dev' }, // duplicate
|
|
180
|
-
{ command: 'npm test' }, // missing name
|
|
181
|
-
],
|
|
182
|
-
} as unknown as ProcessesConfig;
|
|
183
|
-
const result = validateProcessesConfig(config);
|
|
184
|
-
expect(result.valid).toBe(false);
|
|
185
|
-
expect(result.errors.length).toBeGreaterThanOrEqual(2);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// ============================================================================
|
|
190
|
-
// describeProcess
|
|
191
|
-
// ============================================================================
|
|
192
|
-
|
|
193
|
-
describe('describeProcess', () => {
|
|
194
|
-
it('should describe process with command only', () => {
|
|
195
|
-
const process: ProcessDefinition = { name: 'web', command: 'npm start' };
|
|
196
|
-
expect(describeProcess(process)).toBe('web: npm start');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('should describe process with args', () => {
|
|
200
|
-
const process: ProcessDefinition = { name: 'api', command: 'node', args: ['server.js', '--port', '3000'] };
|
|
201
|
-
expect(describeProcess(process)).toBe('api: node server.js --port 3000');
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('should describe process with empty args', () => {
|
|
205
|
-
const process: ProcessDefinition = { name: 'worker', command: 'python', args: [] };
|
|
206
|
-
expect(describeProcess(process)).toBe('worker: python');
|
|
207
|
-
});
|
|
208
|
-
});
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process watchdog tests - restart policy enforcement with injected deps
|
|
3
|
-
*
|
|
4
|
-
* NOTE: The watchdog uses a module-level restartState map keyed by "workspacePath:name:instance".
|
|
5
|
-
* Each test uses a unique process name to avoid state leaking between tests.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, expect, it, mock } from 'bun:test';
|
|
9
|
-
import { reconcileProcessRestarts, type ProcessWatchdogDeps } from '../watchdog.js';
|
|
10
|
-
import type { ProcessInstanceSpec } from '../../../types/processes.js';
|
|
11
|
-
|
|
12
|
-
let testCounter = 0;
|
|
13
|
-
function uniqueName(): string {
|
|
14
|
-
return `test-proc-${++testCounter}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function makeSpec(overrides: {
|
|
18
|
-
name?: string;
|
|
19
|
-
instance?: number;
|
|
20
|
-
policy?: 'always' | 'on-failure' | 'never';
|
|
21
|
-
maxAttempts?: number;
|
|
22
|
-
backoffMs?: number;
|
|
23
|
-
maxBackoffMs?: number;
|
|
24
|
-
} = {}): ProcessInstanceSpec {
|
|
25
|
-
const name = overrides.name ?? uniqueName();
|
|
26
|
-
return {
|
|
27
|
-
name,
|
|
28
|
-
instance: overrides.instance ?? 1,
|
|
29
|
-
definition: {
|
|
30
|
-
name,
|
|
31
|
-
command: 'npm start',
|
|
32
|
-
restart: {
|
|
33
|
-
policy: overrides.policy ?? 'always',
|
|
34
|
-
maxAttempts: overrides.maxAttempts ?? 5,
|
|
35
|
-
backoffMs: overrides.backoffMs ?? 1000,
|
|
36
|
-
maxBackoffMs: overrides.maxBackoffMs ?? 30000,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function makeDeps(overrides: Partial<ProcessWatchdogDeps> = {}): ProcessWatchdogDeps {
|
|
43
|
-
return {
|
|
44
|
-
listSessions: mock(() => Promise.resolve([])),
|
|
45
|
-
startProcessInstance: mock(() => Promise.resolve({ sessionId: 'sess-1', created: true })),
|
|
46
|
-
isProcessRestartDisabled: mock(() => false),
|
|
47
|
-
disableProcessRestart: mock(() => {}),
|
|
48
|
-
hasProcessStarted: mock(() => true),
|
|
49
|
-
readProcessExit: mock(() => null),
|
|
50
|
-
now: mock(() => Date.now()),
|
|
51
|
-
...overrides,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ============================================================================
|
|
56
|
-
// reconcileProcessRestarts
|
|
57
|
-
// ============================================================================
|
|
58
|
-
|
|
59
|
-
describe('reconcileProcessRestarts', () => {
|
|
60
|
-
it('should skip processes with restart policy "never"', async () => {
|
|
61
|
-
const deps = makeDeps();
|
|
62
|
-
const specs = [makeSpec({ policy: 'never' })];
|
|
63
|
-
|
|
64
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
65
|
-
|
|
66
|
-
expect(deps.startProcessInstance).not.toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should skip processes that are currently running', async () => {
|
|
70
|
-
const spec = makeSpec();
|
|
71
|
-
const deps = makeDeps({
|
|
72
|
-
listSessions: mock(() =>
|
|
73
|
-
Promise.resolve([
|
|
74
|
-
{ id: 's1', name: `proc:ws:${spec.name}:1`, socketPath: '/tmp/s', pid: 1, attached: false, cwd: '/tmp/ws', createdAt: 0 },
|
|
75
|
-
])
|
|
76
|
-
),
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await reconcileProcessRestarts('/tmp/ws', [spec], deps);
|
|
80
|
-
|
|
81
|
-
expect(deps.startProcessInstance).not.toHaveBeenCalled();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should skip processes where restart is externally disabled', async () => {
|
|
85
|
-
const deps = makeDeps({
|
|
86
|
-
isProcessRestartDisabled: mock(() => true),
|
|
87
|
-
});
|
|
88
|
-
const specs = [makeSpec()];
|
|
89
|
-
|
|
90
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
91
|
-
|
|
92
|
-
expect(deps.startProcessInstance).not.toHaveBeenCalled();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should skip processes that have never been started', async () => {
|
|
96
|
-
const deps = makeDeps({
|
|
97
|
-
hasProcessStarted: mock(() => false),
|
|
98
|
-
});
|
|
99
|
-
const specs = [makeSpec()];
|
|
100
|
-
|
|
101
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
102
|
-
|
|
103
|
-
expect(deps.startProcessInstance).not.toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should restart a crashed process with "always" policy', async () => {
|
|
107
|
-
const deps = makeDeps();
|
|
108
|
-
const specs = [makeSpec({ policy: 'always' })];
|
|
109
|
-
|
|
110
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
111
|
-
|
|
112
|
-
expect(deps.startProcessInstance).toHaveBeenCalledTimes(1);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should restart a process with "on-failure" policy when exit code is non-zero', async () => {
|
|
116
|
-
const deps = makeDeps({
|
|
117
|
-
readProcessExit: mock(() => ({ exitCode: 1, exitedAt: Date.now() })),
|
|
118
|
-
});
|
|
119
|
-
const specs = [makeSpec({ policy: 'on-failure' })];
|
|
120
|
-
|
|
121
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
122
|
-
|
|
123
|
-
expect(deps.startProcessInstance).toHaveBeenCalledTimes(1);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should NOT restart a process with "on-failure" policy when exit code is 0', async () => {
|
|
127
|
-
const deps = makeDeps({
|
|
128
|
-
readProcessExit: mock(() => ({ exitCode: 0, exitedAt: Date.now() })),
|
|
129
|
-
});
|
|
130
|
-
const specs = [makeSpec({ policy: 'on-failure' })];
|
|
131
|
-
|
|
132
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
133
|
-
|
|
134
|
-
expect(deps.startProcessInstance).not.toHaveBeenCalled();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should disable restart after maxAttempts exceeded', async () => {
|
|
138
|
-
const startMock = mock(() => Promise.resolve({ sessionId: 's', created: true }));
|
|
139
|
-
let currentTime = 1000;
|
|
140
|
-
|
|
141
|
-
const deps = makeDeps({
|
|
142
|
-
startProcessInstance: startMock,
|
|
143
|
-
now: mock(() => {
|
|
144
|
-
currentTime += 100000; // jump forward enough to skip backoff
|
|
145
|
-
return currentTime;
|
|
146
|
-
}),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const spec = makeSpec({ maxAttempts: 2, backoffMs: 1 });
|
|
150
|
-
const specs = [spec];
|
|
151
|
-
|
|
152
|
-
// First call: attempt 1
|
|
153
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
154
|
-
expect(startMock).toHaveBeenCalledTimes(1);
|
|
155
|
-
|
|
156
|
-
// Second call: attempt 2
|
|
157
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
158
|
-
expect(startMock).toHaveBeenCalledTimes(2);
|
|
159
|
-
|
|
160
|
-
// Third call: maxAttempts exceeded, should disable
|
|
161
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
162
|
-
expect(deps.disableProcessRestart).toHaveBeenCalled();
|
|
163
|
-
expect(startMock).toHaveBeenCalledTimes(2); // no additional start
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('should respect backoff delay', async () => {
|
|
167
|
-
let currentTime = 1000;
|
|
168
|
-
const deps = makeDeps({
|
|
169
|
-
now: mock(() => currentTime),
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const specs = [makeSpec({ backoffMs: 5000 })];
|
|
173
|
-
|
|
174
|
-
// First call starts the process
|
|
175
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
176
|
-
expect(deps.startProcessInstance).toHaveBeenCalledTimes(1);
|
|
177
|
-
|
|
178
|
-
// Second call too soon - should skip due to backoff
|
|
179
|
-
currentTime += 1000; // only 1 second later, but backoff doubled to 10000
|
|
180
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
181
|
-
expect(deps.startProcessInstance).toHaveBeenCalledTimes(1); // still 1
|
|
182
|
-
|
|
183
|
-
// Third call after backoff - should restart
|
|
184
|
-
currentTime += 20000; // well past doubled backoff
|
|
185
|
-
await reconcileProcessRestarts('/tmp/ws', specs, deps);
|
|
186
|
-
expect(deps.startProcessInstance).toHaveBeenCalledTimes(2);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('keeps restart backoff isolated per workspace for same process name', async () => {
|
|
190
|
-
const name = uniqueName();
|
|
191
|
-
const spec = makeSpec({ name, backoffMs: 60_000 });
|
|
192
|
-
const startA = mock(() => Promise.resolve({ sessionId: 'a', created: true }));
|
|
193
|
-
const startB = mock(() => Promise.resolve({ sessionId: 'b', created: true }));
|
|
194
|
-
|
|
195
|
-
const depsA = makeDeps({
|
|
196
|
-
startProcessInstance: startA,
|
|
197
|
-
now: mock(() => 1000),
|
|
198
|
-
});
|
|
199
|
-
const depsB = makeDeps({
|
|
200
|
-
startProcessInstance: startB,
|
|
201
|
-
now: mock(() => 1000),
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
await reconcileProcessRestarts('/tmp/ws-a', [spec], depsA);
|
|
205
|
-
await reconcileProcessRestarts('/tmp/ws-b', [spec], depsB);
|
|
206
|
-
|
|
207
|
-
expect(startA).toHaveBeenCalledTimes(1);
|
|
208
|
-
expect(startB).toHaveBeenCalledTimes(1);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process autostart helpers
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { ProcessInstanceSpec } from '../../types/processes.js';
|
|
6
|
-
import { startProcessInstance } from './manager.js';
|
|
7
|
-
|
|
8
|
-
export async function autostartProcesses(
|
|
9
|
-
workspacePath: string,
|
|
10
|
-
specs: ProcessInstanceSpec[]
|
|
11
|
-
): Promise<void> {
|
|
12
|
-
const autostart = specs.filter((spec) => spec.definition.autostart);
|
|
13
|
-
for (const spec of autostart) {
|
|
14
|
-
await startProcessInstance(workspacePath, spec);
|
|
15
|
-
}
|
|
16
|
-
}
|