gitspace 0.2.0-rc.1
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/.claude/settings.local.json +21 -0
- package/.gitspace/bundle.json +50 -0
- package/.gitspace/select/01-status.sh +40 -0
- package/.gitspace/setup/01-install-deps.sh +12 -0
- package/.gitspace/setup/02-typecheck.sh +16 -0
- package/AGENTS.md +439 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +25 -0
- package/README.md +607 -0
- package/bin/gssh +62 -0
- package/bun.lock +647 -0
- package/docs/CONNECTION.md +623 -0
- package/docs/GATEWAY-WORKER.md +319 -0
- package/docs/GETTING-STARTED.md +448 -0
- package/docs/GITSPACE-PLATFORM.md +1819 -0
- package/docs/INFRASTRUCTURE.md +1347 -0
- package/docs/PROTOCOL.md +619 -0
- package/docs/QUICKSTART.md +174 -0
- package/docs/RELAY.md +327 -0
- package/docs/REMOTE-DESIGN.md +549 -0
- package/docs/ROADMAP.md +564 -0
- package/docs/SITE_DOCS_FIGMA_MAKE.md +1167 -0
- package/docs/STACK-DESIGN.md +588 -0
- package/docs/UNIFIED_ARCHITECTURE.md +292 -0
- package/experiments/pty-benchmark.ts +148 -0
- package/experiments/pty-latency.ts +100 -0
- package/experiments/router/client.ts +199 -0
- package/experiments/router/protocol.ts +74 -0
- package/experiments/router/router.ts +217 -0
- package/experiments/router/session.ts +180 -0
- package/experiments/router/test.ts +133 -0
- package/experiments/socket-bandwidth.ts +77 -0
- package/homebrew/gitspace.rb +45 -0
- package/landing-page/ATTRIBUTIONS.md +3 -0
- package/landing-page/README.md +11 -0
- package/landing-page/bun.lock +801 -0
- package/landing-page/guidelines/Guidelines.md +61 -0
- package/landing-page/index.html +37 -0
- package/landing-page/package.json +90 -0
- package/landing-page/postcss.config.mjs +15 -0
- package/landing-page/public/_redirects +1 -0
- package/landing-page/public/favicon.png +0 -0
- package/landing-page/src/app/App.tsx +53 -0
- package/landing-page/src/app/components/figma/ImageWithFallback.tsx +27 -0
- package/landing-page/src/app/components/ui/accordion.tsx +66 -0
- package/landing-page/src/app/components/ui/alert-dialog.tsx +157 -0
- package/landing-page/src/app/components/ui/alert.tsx +66 -0
- package/landing-page/src/app/components/ui/aspect-ratio.tsx +11 -0
- package/landing-page/src/app/components/ui/avatar.tsx +53 -0
- package/landing-page/src/app/components/ui/badge.tsx +46 -0
- package/landing-page/src/app/components/ui/breadcrumb.tsx +109 -0
- package/landing-page/src/app/components/ui/button.tsx +57 -0
- package/landing-page/src/app/components/ui/calendar.tsx +75 -0
- package/landing-page/src/app/components/ui/card.tsx +92 -0
- package/landing-page/src/app/components/ui/carousel.tsx +241 -0
- package/landing-page/src/app/components/ui/chart.tsx +353 -0
- package/landing-page/src/app/components/ui/checkbox.tsx +32 -0
- package/landing-page/src/app/components/ui/collapsible.tsx +33 -0
- package/landing-page/src/app/components/ui/command.tsx +177 -0
- package/landing-page/src/app/components/ui/context-menu.tsx +252 -0
- package/landing-page/src/app/components/ui/dialog.tsx +135 -0
- package/landing-page/src/app/components/ui/drawer.tsx +132 -0
- package/landing-page/src/app/components/ui/dropdown-menu.tsx +257 -0
- package/landing-page/src/app/components/ui/form.tsx +168 -0
- package/landing-page/src/app/components/ui/hover-card.tsx +44 -0
- package/landing-page/src/app/components/ui/input-otp.tsx +77 -0
- package/landing-page/src/app/components/ui/input.tsx +21 -0
- package/landing-page/src/app/components/ui/label.tsx +24 -0
- package/landing-page/src/app/components/ui/menubar.tsx +276 -0
- package/landing-page/src/app/components/ui/navigation-menu.tsx +168 -0
- package/landing-page/src/app/components/ui/pagination.tsx +127 -0
- package/landing-page/src/app/components/ui/popover.tsx +48 -0
- package/landing-page/src/app/components/ui/progress.tsx +31 -0
- package/landing-page/src/app/components/ui/radio-group.tsx +45 -0
- package/landing-page/src/app/components/ui/resizable.tsx +56 -0
- package/landing-page/src/app/components/ui/scroll-area.tsx +58 -0
- package/landing-page/src/app/components/ui/select.tsx +189 -0
- package/landing-page/src/app/components/ui/separator.tsx +28 -0
- package/landing-page/src/app/components/ui/sheet.tsx +139 -0
- package/landing-page/src/app/components/ui/sidebar.tsx +726 -0
- package/landing-page/src/app/components/ui/skeleton.tsx +13 -0
- package/landing-page/src/app/components/ui/slider.tsx +63 -0
- package/landing-page/src/app/components/ui/sonner.tsx +25 -0
- package/landing-page/src/app/components/ui/switch.tsx +31 -0
- package/landing-page/src/app/components/ui/table.tsx +116 -0
- package/landing-page/src/app/components/ui/tabs.tsx +66 -0
- package/landing-page/src/app/components/ui/textarea.tsx +18 -0
- package/landing-page/src/app/components/ui/toggle-group.tsx +73 -0
- package/landing-page/src/app/components/ui/toggle.tsx +47 -0
- package/landing-page/src/app/components/ui/tooltip.tsx +61 -0
- package/landing-page/src/app/components/ui/use-mobile.ts +21 -0
- package/landing-page/src/app/components/ui/utils.ts +6 -0
- package/landing-page/src/components/docs/DocsContent.tsx +718 -0
- package/landing-page/src/components/docs/DocsSidebar.tsx +84 -0
- package/landing-page/src/components/landing/CTA.tsx +59 -0
- package/landing-page/src/components/landing/Comparison.tsx +84 -0
- package/landing-page/src/components/landing/FaultyTerminal.tsx +424 -0
- package/landing-page/src/components/landing/Features.tsx +201 -0
- package/landing-page/src/components/landing/Hero.tsx +142 -0
- package/landing-page/src/components/landing/Pricing.tsx +140 -0
- package/landing-page/src/components/landing/Roadmap.tsx +86 -0
- package/landing-page/src/components/landing/Security.tsx +81 -0
- package/landing-page/src/components/landing/TerminalWindow.tsx +27 -0
- package/landing-page/src/components/landing/UseCases.tsx +55 -0
- package/landing-page/src/components/landing/Workflow.tsx +101 -0
- package/landing-page/src/components/layout/DashboardNavbar.tsx +37 -0
- package/landing-page/src/components/layout/Footer.tsx +55 -0
- package/landing-page/src/components/layout/LandingNavbar.tsx +82 -0
- package/landing-page/src/components/ui/badge.tsx +39 -0
- package/landing-page/src/components/ui/breadcrumb.tsx +115 -0
- package/landing-page/src/components/ui/button.tsx +57 -0
- package/landing-page/src/components/ui/card.tsx +79 -0
- package/landing-page/src/components/ui/mock-terminal.tsx +68 -0
- package/landing-page/src/components/ui/separator.tsx +28 -0
- package/landing-page/src/lib/utils.ts +6 -0
- package/landing-page/src/main.tsx +10 -0
- package/landing-page/src/pages/Dashboard.tsx +133 -0
- package/landing-page/src/pages/DocsPage.tsx +79 -0
- package/landing-page/src/pages/LandingPage.tsx +31 -0
- package/landing-page/src/pages/TerminalView.tsx +106 -0
- package/landing-page/src/styles/fonts.css +0 -0
- package/landing-page/src/styles/index.css +3 -0
- package/landing-page/src/styles/tailwind.css +4 -0
- package/landing-page/src/styles/theme.css +181 -0
- package/landing-page/vite.config.ts +19 -0
- package/npm/darwin-arm64/bin/gssh +0 -0
- package/npm/darwin-arm64/package.json +20 -0
- package/package.json +74 -0
- package/scripts/build.ts +284 -0
- package/scripts/release.ts +140 -0
- package/src/__tests__/test-utils.ts +298 -0
- package/src/commands/__tests__/serve-messages.test.ts +190 -0
- package/src/commands/access.ts +298 -0
- package/src/commands/add.ts +452 -0
- package/src/commands/auth.ts +364 -0
- package/src/commands/connect.ts +287 -0
- package/src/commands/directory.ts +16 -0
- package/src/commands/host.ts +396 -0
- package/src/commands/identity.ts +184 -0
- package/src/commands/list.ts +200 -0
- package/src/commands/relay.ts +315 -0
- package/src/commands/remove.ts +241 -0
- package/src/commands/serve.ts +1493 -0
- package/src/commands/share.ts +456 -0
- package/src/commands/status.ts +125 -0
- package/src/commands/switch.ts +353 -0
- package/src/commands/tmux.ts +317 -0
- package/src/core/__tests__/access.test.ts +240 -0
- package/src/core/access.ts +277 -0
- package/src/core/bundle.ts +342 -0
- package/src/core/config.ts +510 -0
- package/src/core/git.ts +317 -0
- package/src/core/github.ts +151 -0
- package/src/core/identity.ts +631 -0
- package/src/core/linear.ts +225 -0
- package/src/core/shell.ts +161 -0
- package/src/core/trusted-relays.ts +315 -0
- package/src/index.ts +821 -0
- package/src/lib/remote-session/index.ts +7 -0
- package/src/lib/remote-session/protocol.ts +267 -0
- package/src/lib/remote-session/session-handler.ts +581 -0
- package/src/lib/remote-session/workspace-scanner.ts +167 -0
- package/src/lib/tmux-lite/README.md +81 -0
- package/src/lib/tmux-lite/cli.ts +796 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +349 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +291 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +142 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +339 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +477 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +499 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +371 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +573 -0
- package/src/lib/tmux-lite/crypto/access-control.test.ts +512 -0
- package/src/lib/tmux-lite/crypto/access-control.ts +320 -0
- package/src/lib/tmux-lite/crypto/frames.test.ts +262 -0
- package/src/lib/tmux-lite/crypto/frames.ts +141 -0
- package/src/lib/tmux-lite/crypto/handshake.ts +894 -0
- package/src/lib/tmux-lite/crypto/identity.test.ts +220 -0
- package/src/lib/tmux-lite/crypto/identity.ts +286 -0
- package/src/lib/tmux-lite/crypto/index.ts +51 -0
- package/src/lib/tmux-lite/crypto/invites.test.ts +381 -0
- package/src/lib/tmux-lite/crypto/invites.ts +215 -0
- package/src/lib/tmux-lite/crypto/keyexchange.ts +435 -0
- package/src/lib/tmux-lite/crypto/keys.test.ts +58 -0
- package/src/lib/tmux-lite/crypto/keys.ts +47 -0
- package/src/lib/tmux-lite/crypto/secretbox.test.ts +169 -0
- package/src/lib/tmux-lite/crypto/secretbox.ts +124 -0
- package/src/lib/tmux-lite/handshake-handler.ts +451 -0
- package/src/lib/tmux-lite/protocol.test.ts +307 -0
- package/src/lib/tmux-lite/protocol.ts +266 -0
- package/src/lib/tmux-lite/relay-client.ts +506 -0
- package/src/lib/tmux-lite/server.ts +1250 -0
- package/src/lib/tmux-lite/shell-integration.sh +37 -0
- package/src/lib/tmux-lite/terminal-queries.test.ts +54 -0
- package/src/lib/tmux-lite/terminal-queries.ts +49 -0
- package/src/relay/__tests__/e2e-flow.test.ts +1284 -0
- package/src/relay/__tests__/helpers/auth.ts +354 -0
- package/src/relay/__tests__/helpers/ports.ts +51 -0
- package/src/relay/__tests__/protocol-validation.test.ts +265 -0
- package/src/relay/authorization.ts +303 -0
- package/src/relay/embedded-assets.generated.d.ts +15 -0
- package/src/relay/identity.ts +352 -0
- package/src/relay/index.ts +57 -0
- package/src/relay/pipes.test.ts +427 -0
- package/src/relay/pipes.ts +195 -0
- package/src/relay/protocol.ts +804 -0
- package/src/relay/registries.test.ts +437 -0
- package/src/relay/registries.ts +593 -0
- package/src/relay/server.test.ts +1323 -0
- package/src/relay/server.ts +1092 -0
- package/src/relay/signing.ts +238 -0
- package/src/relay/types.ts +69 -0
- package/src/serve/client-session-manager.ts +622 -0
- package/src/serve/daemon.ts +497 -0
- package/src/serve/pty-session.ts +236 -0
- package/src/serve/types.ts +169 -0
- package/src/shared/components/Flow.tsx +453 -0
- package/src/shared/components/Flow.tui.tsx +343 -0
- package/src/shared/components/Flow.web.tsx +442 -0
- package/src/shared/components/Inbox.tsx +446 -0
- package/src/shared/components/Inbox.tui.tsx +262 -0
- package/src/shared/components/Inbox.web.tsx +329 -0
- package/src/shared/components/MachineList.tsx +187 -0
- package/src/shared/components/MachineList.tui.tsx +161 -0
- package/src/shared/components/MachineList.web.tsx +210 -0
- package/src/shared/components/ProjectList.tsx +176 -0
- package/src/shared/components/ProjectList.tui.tsx +109 -0
- package/src/shared/components/ProjectList.web.tsx +143 -0
- package/src/shared/components/SpacesBrowser.tsx +332 -0
- package/src/shared/components/SpacesBrowser.tui.tsx +163 -0
- package/src/shared/components/SpacesBrowser.web.tsx +221 -0
- package/src/shared/components/index.ts +103 -0
- package/src/shared/hooks/index.ts +16 -0
- package/src/shared/hooks/useNavigation.ts +226 -0
- package/src/shared/index.ts +122 -0
- package/src/shared/providers/LocalMachineProvider.ts +425 -0
- package/src/shared/providers/MachineProvider.ts +165 -0
- package/src/shared/providers/RemoteMachineProvider.ts +444 -0
- package/src/shared/providers/index.ts +26 -0
- package/src/shared/types.ts +145 -0
- package/src/tui/adapters.ts +120 -0
- package/src/tui/app.tsx +1816 -0
- package/src/tui/components/Terminal.tsx +580 -0
- package/src/tui/hooks/index.ts +35 -0
- package/src/tui/hooks/useAppState.ts +314 -0
- package/src/tui/hooks/useDaemonStatus.ts +174 -0
- package/src/tui/hooks/useInboxTUI.ts +113 -0
- package/src/tui/hooks/useRemoteMachines.ts +209 -0
- package/src/tui/index.ts +24 -0
- package/src/tui/state.ts +299 -0
- package/src/tui/terminal-bracketed-paste.test.ts +45 -0
- package/src/tui/terminal-bracketed-paste.ts +47 -0
- package/src/types/bundle.ts +112 -0
- package/src/types/config.ts +89 -0
- package/src/types/errors.ts +206 -0
- package/src/types/identity.ts +284 -0
- package/src/types/workspace-fuzzy.ts +49 -0
- package/src/types/workspace.ts +151 -0
- package/src/utils/bun-socket-writer.ts +80 -0
- package/src/utils/deps.ts +127 -0
- package/src/utils/fuzzy-match.ts +125 -0
- package/src/utils/logger.ts +127 -0
- package/src/utils/markdown.ts +254 -0
- package/src/utils/onboarding.ts +229 -0
- package/src/utils/prompts.ts +114 -0
- package/src/utils/run-commands.ts +112 -0
- package/src/utils/run-scripts.ts +142 -0
- package/src/utils/sanitize.ts +98 -0
- package/src/utils/secrets.ts +122 -0
- package/src/utils/shell-escape.ts +40 -0
- package/src/utils/utf8.ts +79 -0
- package/src/utils/workspace-state.ts +47 -0
- package/src/web/README.md +73 -0
- package/src/web/bun.lock +575 -0
- package/src/web/eslint.config.js +23 -0
- package/src/web/index.html +16 -0
- package/src/web/package.json +37 -0
- package/src/web/public/vite.svg +1 -0
- package/src/web/src/App.tsx +604 -0
- package/src/web/src/assets/react.svg +1 -0
- package/src/web/src/components/Terminal.tsx +207 -0
- package/src/web/src/hooks/useRelayConnection.ts +224 -0
- package/src/web/src/hooks/useTerminal.ts +699 -0
- package/src/web/src/index.css +55 -0
- package/src/web/src/lib/crypto/__tests__/web-terminal.test.ts +1158 -0
- package/src/web/src/lib/crypto/frames.ts +205 -0
- package/src/web/src/lib/crypto/handshake.ts +396 -0
- package/src/web/src/lib/crypto/identity.ts +128 -0
- package/src/web/src/lib/crypto/keyexchange.ts +246 -0
- package/src/web/src/lib/crypto/relay-signing.ts +53 -0
- package/src/web/src/lib/invite.ts +58 -0
- package/src/web/src/lib/storage/identity-store.ts +94 -0
- package/src/web/src/main.tsx +10 -0
- package/src/web/src/types/identity.ts +45 -0
- package/src/web/tsconfig.app.json +28 -0
- package/src/web/tsconfig.json +7 -0
- package/src/web/tsconfig.node.json +26 -0
- package/src/web/vite.config.ts +31 -0
- package/todo-security.md +92 -0
- package/tsconfig.json +23 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-wal +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-wal +0 -0
- package/worker/bun.lock +237 -0
- package/worker/package.json +22 -0
- package/worker/schema.sql +96 -0
- package/worker/src/handlers/auth.ts +451 -0
- package/worker/src/handlers/subdomains.ts +376 -0
- package/worker/src/handlers/user.ts +98 -0
- package/worker/src/index.ts +70 -0
- package/worker/src/middleware/auth.ts +152 -0
- package/worker/src/services/cloudflare.ts +609 -0
- package/worker/src/types.ts +96 -0
- package/worker/tsconfig.json +15 -0
- package/worker/wrangler.toml +26 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/** @jsxImportSource react */
|
|
2
|
+
/**
|
|
3
|
+
* SpacesBrowser - Web Display Component
|
|
4
|
+
*
|
|
5
|
+
* Dumb presentational component for web.
|
|
6
|
+
* Receives all state and actions from useSpacesBrowser hook.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { UseSpacesBrowserReturn } from './SpacesBrowser.js';
|
|
10
|
+
import { formatTime } from './SpacesBrowser.js';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Component
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export function SpacesBrowserWeb(props: UseSpacesBrowserReturn) {
|
|
17
|
+
const {
|
|
18
|
+
items,
|
|
19
|
+
machineName,
|
|
20
|
+
isEmpty,
|
|
21
|
+
selectIndex,
|
|
22
|
+
toggleWorkspace,
|
|
23
|
+
attachSession,
|
|
24
|
+
refresh,
|
|
25
|
+
back,
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
// Empty state
|
|
29
|
+
if (isEmpty) {
|
|
30
|
+
return (
|
|
31
|
+
<div className="h-screen flex flex-col bg-gray-900">
|
|
32
|
+
<Header machineName={machineName} onBack={back} onRefresh={refresh} />
|
|
33
|
+
<div className="flex-1 flex flex-col items-center justify-center text-gray-400 px-4">
|
|
34
|
+
<div className="text-lg mb-2 text-center">No workspaces found</div>
|
|
35
|
+
<div className="text-sm text-gray-500 text-center">
|
|
36
|
+
Create workspaces with <code className="text-green-400">gssh add</code>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<Footer />
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="h-screen flex flex-col bg-gray-900">
|
|
46
|
+
<Header machineName={machineName} onBack={back} onRefresh={refresh} />
|
|
47
|
+
|
|
48
|
+
{/* Tree list */}
|
|
49
|
+
<div className="flex-1 overflow-y-auto">
|
|
50
|
+
{items.map((item) => {
|
|
51
|
+
const { isSelected, index } = item;
|
|
52
|
+
|
|
53
|
+
if (item.type === 'project') {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
key={`project-${item.name}`}
|
|
57
|
+
className="px-4 py-3 text-xs text-gray-500 uppercase tracking-wide bg-gray-800 border-b border-gray-700 min-h-[44px] flex items-center"
|
|
58
|
+
>
|
|
59
|
+
{item.name} ({item.workspaceCount})
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (item.type === 'workspace') {
|
|
65
|
+
const ws = item.workspace;
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
key={`ws-${ws.id}`}
|
|
69
|
+
onClick={(e) => {
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
console.log('[SpacesBrowser] Workspace clicked:', ws.id, ws.name);
|
|
72
|
+
selectIndex(index);
|
|
73
|
+
toggleWorkspace(ws.id);
|
|
74
|
+
}}
|
|
75
|
+
className={`
|
|
76
|
+
px-4 py-4 cursor-pointer border-b border-gray-800 flex items-center justify-between min-h-[56px]
|
|
77
|
+
${isSelected ? 'bg-gray-700 border-l-4 border-l-blue-500' : 'hover:bg-gray-800 active:bg-gray-700'}
|
|
78
|
+
${ws.isStale ? 'opacity-60' : ''}
|
|
79
|
+
`}
|
|
80
|
+
>
|
|
81
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
82
|
+
<span className="text-gray-500 w-5 flex-shrink-0 text-center">
|
|
83
|
+
{item.expanded ? '▼' : '▶'}
|
|
84
|
+
</span>
|
|
85
|
+
<div className="min-w-0 flex-1">
|
|
86
|
+
<div className="text-white font-medium truncate">{ws.name}</div>
|
|
87
|
+
{ws.branch && (
|
|
88
|
+
<div className="text-xs text-gray-500 truncate">
|
|
89
|
+
<span className="text-purple-400">{ws.branch}</span>
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="text-right flex-shrink-0 ml-2">
|
|
95
|
+
{ws.sessionCount > 0 && (
|
|
96
|
+
<span className="text-xs px-2 py-1 rounded bg-green-900 text-green-300">
|
|
97
|
+
{ws.sessionCount}
|
|
98
|
+
</span>
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (item.type === 'session') {
|
|
106
|
+
const session = item.session;
|
|
107
|
+
return (
|
|
108
|
+
<div
|
|
109
|
+
key={`session-${session.id}`}
|
|
110
|
+
onClick={(e) => {
|
|
111
|
+
e.stopPropagation();
|
|
112
|
+
console.log('[SpacesBrowser] Session clicked:', session.id, session.name);
|
|
113
|
+
selectIndex(index);
|
|
114
|
+
attachSession({ sessionId: session.id });
|
|
115
|
+
}}
|
|
116
|
+
className={`
|
|
117
|
+
pl-10 sm:pl-12 pr-4 py-3 cursor-pointer border-b border-gray-800 flex items-center justify-between min-h-[52px]
|
|
118
|
+
${isSelected ? 'bg-gray-700 border-l-4 border-l-blue-500' : 'hover:bg-gray-800 active:bg-gray-700'}
|
|
119
|
+
`}
|
|
120
|
+
>
|
|
121
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
122
|
+
<span className={`w-2.5 h-2.5 rounded-full flex-shrink-0 ${session.attached ? 'bg-yellow-500' : 'bg-green-500'}`} />
|
|
123
|
+
<div className="min-w-0 flex-1">
|
|
124
|
+
<span className="text-gray-300 truncate block">{session.name.split(':').pop()}</span>
|
|
125
|
+
{session.processTitle && (
|
|
126
|
+
<span className="text-xs text-yellow-400 truncate block">{session.processTitle}</span>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div className="text-xs text-gray-500 flex-shrink-0 ml-2">
|
|
131
|
+
{session.attached ? 'attached' : formatTime(session.createdAt)}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (item.type === 'new-session') {
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
key={`new-${item.workspaceId}`}
|
|
141
|
+
onClick={(e) => {
|
|
142
|
+
e.stopPropagation();
|
|
143
|
+
console.log('[SpacesBrowser] New session clicked for workspace:', item.workspaceId);
|
|
144
|
+
selectIndex(index);
|
|
145
|
+
attachSession({ workspaceId: item.workspaceId });
|
|
146
|
+
}}
|
|
147
|
+
className={`
|
|
148
|
+
pl-10 sm:pl-12 pr-4 py-3 cursor-pointer border-b border-gray-800 min-h-[48px] flex items-center
|
|
149
|
+
${isSelected ? 'bg-gray-700 border-l-4 border-l-blue-500' : 'hover:bg-gray-800 active:bg-gray-700'}
|
|
150
|
+
`}
|
|
151
|
+
>
|
|
152
|
+
<span className="text-blue-400">+ New Session</span>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
})}
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<Footer />
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Subcomponents
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
function Header({
|
|
171
|
+
machineName,
|
|
172
|
+
onBack,
|
|
173
|
+
onRefresh,
|
|
174
|
+
}: {
|
|
175
|
+
machineName: string | null;
|
|
176
|
+
onBack: () => void;
|
|
177
|
+
onRefresh: () => void;
|
|
178
|
+
}) {
|
|
179
|
+
return (
|
|
180
|
+
<div className="bg-gray-800 px-4 py-3 flex items-center justify-between border-b border-gray-700 min-h-[52px]">
|
|
181
|
+
<div className="flex items-center gap-3 min-w-0 flex-1">
|
|
182
|
+
<button
|
|
183
|
+
onClick={onBack}
|
|
184
|
+
className="text-sm text-gray-400 hover:text-white active:text-blue-400 py-2 pr-2 -ml-2 min-h-[44px] flex items-center flex-shrink-0"
|
|
185
|
+
>
|
|
186
|
+
← <span className="hidden sm:inline ml-1">Back</span>
|
|
187
|
+
</button>
|
|
188
|
+
<div className="text-white font-medium truncate">
|
|
189
|
+
{machineName || 'Workspaces'}
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
<button
|
|
193
|
+
onClick={onRefresh}
|
|
194
|
+
className="text-sm text-gray-400 hover:text-white active:text-blue-400 py-2 pl-2 -mr-2 min-h-[44px] flex items-center flex-shrink-0"
|
|
195
|
+
>
|
|
196
|
+
Refresh
|
|
197
|
+
</button>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function Footer() {
|
|
203
|
+
return (
|
|
204
|
+
<div className="bg-gray-800 px-4 py-2 border-t border-gray-700 safe-bottom">
|
|
205
|
+
{/* Desktop keyboard hints */}
|
|
206
|
+
<div className="hidden sm:flex gap-4 text-xs text-gray-500 flex-wrap">
|
|
207
|
+
<span>↑↓ Navigate</span>
|
|
208
|
+
<span>Enter Select</span>
|
|
209
|
+
<span>n New</span>
|
|
210
|
+
<span>x Kill</span>
|
|
211
|
+
<span>d Delete</span>
|
|
212
|
+
<span>r Refresh</span>
|
|
213
|
+
<span>Esc Back</span>
|
|
214
|
+
</div>
|
|
215
|
+
{/* Mobile hint */}
|
|
216
|
+
<div className="sm:hidden text-xs text-gray-500 text-center">
|
|
217
|
+
Tap to expand • Tap session to attach
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared components exports
|
|
3
|
+
*
|
|
4
|
+
* NOTE: Web components (*.web.js) are NOT exported here because they
|
|
5
|
+
* depend on react-dom which is not available in CLI/TUI context.
|
|
6
|
+
* Import web components directly from their files in the web project.
|
|
7
|
+
*
|
|
8
|
+
* TUI components are also not exported here to avoid @opentui/core deps.
|
|
9
|
+
* Import TUI components directly from their files in the TUI project.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// MachineList
|
|
13
|
+
export type {
|
|
14
|
+
ConnectionStatus,
|
|
15
|
+
MachineInfo,
|
|
16
|
+
UseMachineListProps,
|
|
17
|
+
MachineListItem,
|
|
18
|
+
UseMachineListReturn,
|
|
19
|
+
} from './MachineList.js';
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
useMachineList,
|
|
23
|
+
formatLastSeen,
|
|
24
|
+
getStatusColor,
|
|
25
|
+
getMachineLabel,
|
|
26
|
+
} from './MachineList.js';
|
|
27
|
+
|
|
28
|
+
// SpacesBrowser
|
|
29
|
+
export type {
|
|
30
|
+
WorkspaceInfo,
|
|
31
|
+
SessionInfo,
|
|
32
|
+
TreeItem,
|
|
33
|
+
TreeItemWithState,
|
|
34
|
+
UseSpacesBrowserProps,
|
|
35
|
+
UseSpacesBrowserReturn,
|
|
36
|
+
} from './SpacesBrowser.js';
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
useSpacesBrowser,
|
|
40
|
+
formatTime,
|
|
41
|
+
} from './SpacesBrowser.js';
|
|
42
|
+
|
|
43
|
+
// Inbox
|
|
44
|
+
export type {
|
|
45
|
+
InboxItemType,
|
|
46
|
+
InboxItem,
|
|
47
|
+
ParsedSessionName,
|
|
48
|
+
SessionGroup,
|
|
49
|
+
WorkspaceGroup,
|
|
50
|
+
ProjectGroup,
|
|
51
|
+
InboxDisplayItem,
|
|
52
|
+
UseInboxProps,
|
|
53
|
+
UseInboxReturn,
|
|
54
|
+
} from './Inbox.js';
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
useInbox,
|
|
58
|
+
parseSessionName,
|
|
59
|
+
getInboxIcon,
|
|
60
|
+
getInboxTypeLabel,
|
|
61
|
+
formatTimeAgo,
|
|
62
|
+
} from './Inbox.js';
|
|
63
|
+
|
|
64
|
+
// ProjectList
|
|
65
|
+
export type {
|
|
66
|
+
ProjectInfo,
|
|
67
|
+
ProjectListItem,
|
|
68
|
+
UseProjectListProps,
|
|
69
|
+
UseProjectListReturn,
|
|
70
|
+
} from './ProjectList.js';
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
useProjectList,
|
|
74
|
+
getProjectDisplayName,
|
|
75
|
+
getShortRepoName,
|
|
76
|
+
formatWorkspaceCount,
|
|
77
|
+
} from './ProjectList.js';
|
|
78
|
+
|
|
79
|
+
// Flow (Modal System)
|
|
80
|
+
export type {
|
|
81
|
+
FlowNone,
|
|
82
|
+
FlowMessage,
|
|
83
|
+
FlowLoading,
|
|
84
|
+
FlowHelp,
|
|
85
|
+
FlowConfirm,
|
|
86
|
+
FlowConfirmTyped,
|
|
87
|
+
FlowInput,
|
|
88
|
+
FlowSelect,
|
|
89
|
+
FlowWizardStep,
|
|
90
|
+
FlowWizard,
|
|
91
|
+
FlowState,
|
|
92
|
+
UseFlowProps,
|
|
93
|
+
UseFlowReturn,
|
|
94
|
+
} from './Flow.js';
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
useFlow,
|
|
98
|
+
getDefaultShortcuts,
|
|
99
|
+
isFlowInput,
|
|
100
|
+
isFlowConfirmTyped,
|
|
101
|
+
isFlowWizard,
|
|
102
|
+
hasInputValue,
|
|
103
|
+
} from './Flow.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
NavigationState,
|
|
7
|
+
NavigationAction,
|
|
8
|
+
} from './useNavigation.js';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
createInitialNavigationState,
|
|
12
|
+
navigationReducer,
|
|
13
|
+
getCurrentMachineId,
|
|
14
|
+
getCurrentProjectName,
|
|
15
|
+
canGoBack,
|
|
16
|
+
} from './useNavigation.js';
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navigation State Hook
|
|
3
|
+
*
|
|
4
|
+
* Manages navigation between screens (machines, projects, workspaces, sessions).
|
|
5
|
+
* Platform-agnostic - works with both TUI and Web.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { NavigationLocation, PanelFocus } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Navigation state
|
|
12
|
+
*/
|
|
13
|
+
export interface NavigationState {
|
|
14
|
+
/** Current location in the app */
|
|
15
|
+
location: NavigationLocation;
|
|
16
|
+
/** Which panel has focus */
|
|
17
|
+
focus: PanelFocus;
|
|
18
|
+
/** History stack for back navigation */
|
|
19
|
+
history: NavigationLocation[];
|
|
20
|
+
/** Selected indices for each panel */
|
|
21
|
+
selectedIndices: {
|
|
22
|
+
machines: number;
|
|
23
|
+
projects: number;
|
|
24
|
+
workspaces: number;
|
|
25
|
+
};
|
|
26
|
+
/** Expanded items (e.g., workspaces showing sessions) */
|
|
27
|
+
expanded: Set<string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Navigation actions
|
|
32
|
+
*/
|
|
33
|
+
export type NavigationAction =
|
|
34
|
+
| { type: 'NAVIGATE'; location: NavigationLocation }
|
|
35
|
+
| { type: 'GO_BACK' }
|
|
36
|
+
| { type: 'SET_FOCUS'; focus: PanelFocus }
|
|
37
|
+
| { type: 'SWITCH_FOCUS' }
|
|
38
|
+
| { type: 'SELECT_INDEX'; panel: 'machines' | 'projects' | 'workspaces'; index: number }
|
|
39
|
+
| { type: 'MOVE_UP' }
|
|
40
|
+
| { type: 'MOVE_DOWN' }
|
|
41
|
+
| { type: 'TOGGLE_EXPANDED'; id: string }
|
|
42
|
+
| { type: 'RESET' };
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create initial navigation state
|
|
46
|
+
*/
|
|
47
|
+
export function createInitialNavigationState(
|
|
48
|
+
startWithMachines: boolean = false
|
|
49
|
+
): NavigationState {
|
|
50
|
+
return {
|
|
51
|
+
location: startWithMachines
|
|
52
|
+
? { screen: 'machines' }
|
|
53
|
+
: { screen: 'projects', machineId: 'local' },
|
|
54
|
+
focus: startWithMachines ? 'machines' : 'projects',
|
|
55
|
+
history: [],
|
|
56
|
+
selectedIndices: {
|
|
57
|
+
machines: 0,
|
|
58
|
+
projects: 0,
|
|
59
|
+
workspaces: 0,
|
|
60
|
+
},
|
|
61
|
+
expanded: new Set(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Navigation reducer
|
|
67
|
+
*/
|
|
68
|
+
export function navigationReducer(
|
|
69
|
+
state: NavigationState,
|
|
70
|
+
action: NavigationAction,
|
|
71
|
+
counts: { machines: number; projects: number; workspaces: number }
|
|
72
|
+
): NavigationState {
|
|
73
|
+
switch (action.type) {
|
|
74
|
+
case 'NAVIGATE': {
|
|
75
|
+
// Push current location to history before navigating
|
|
76
|
+
const newHistory = [...state.history, state.location];
|
|
77
|
+
|
|
78
|
+
// Determine focus based on screen
|
|
79
|
+
let focus: PanelFocus = state.focus;
|
|
80
|
+
if (action.location.screen === 'machines') {
|
|
81
|
+
focus = 'machines';
|
|
82
|
+
} else if (action.location.screen === 'projects') {
|
|
83
|
+
focus = 'projects';
|
|
84
|
+
} else if (action.location.screen === 'workspaces' || action.location.screen === 'session') {
|
|
85
|
+
focus = 'workspaces';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...state,
|
|
90
|
+
location: action.location,
|
|
91
|
+
history: newHistory,
|
|
92
|
+
focus,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
case 'GO_BACK': {
|
|
97
|
+
if (state.history.length === 0) {
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
const newHistory = [...state.history];
|
|
101
|
+
const previousLocation = newHistory.pop()!;
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
...state,
|
|
105
|
+
location: previousLocation,
|
|
106
|
+
history: newHistory,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
case 'SET_FOCUS': {
|
|
111
|
+
return {
|
|
112
|
+
...state,
|
|
113
|
+
focus: action.focus,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
case 'SWITCH_FOCUS': {
|
|
118
|
+
// Cycle through available panels based on current screen
|
|
119
|
+
const { screen } = state.location;
|
|
120
|
+
let nextFocus: PanelFocus;
|
|
121
|
+
|
|
122
|
+
if (screen === 'machines') {
|
|
123
|
+
// Only machines panel available
|
|
124
|
+
nextFocus = 'machines';
|
|
125
|
+
} else if (screen === 'projects') {
|
|
126
|
+
// Toggle between machines and projects
|
|
127
|
+
nextFocus = state.focus === 'machines' ? 'projects' : 'machines';
|
|
128
|
+
} else {
|
|
129
|
+
// Toggle between projects and workspaces
|
|
130
|
+
nextFocus = state.focus === 'projects' ? 'workspaces' : 'projects';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
...state,
|
|
135
|
+
focus: nextFocus,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
case 'SELECT_INDEX': {
|
|
140
|
+
const maxIndex = counts[action.panel] - 1;
|
|
141
|
+
const index = Math.max(0, Math.min(action.index, maxIndex));
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
...state,
|
|
145
|
+
selectedIndices: {
|
|
146
|
+
...state.selectedIndices,
|
|
147
|
+
[action.panel]: index,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
case 'MOVE_UP': {
|
|
153
|
+
const panel = state.focus === 'inbox' ? 'workspaces' : state.focus;
|
|
154
|
+
const currentIndex = state.selectedIndices[panel as keyof typeof state.selectedIndices] ?? 0;
|
|
155
|
+
const newIndex = Math.max(0, currentIndex - 1);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
...state,
|
|
159
|
+
selectedIndices: {
|
|
160
|
+
...state.selectedIndices,
|
|
161
|
+
[panel]: newIndex,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
case 'MOVE_DOWN': {
|
|
167
|
+
const panel = state.focus === 'inbox' ? 'workspaces' : state.focus;
|
|
168
|
+
const maxIndex = counts[panel as keyof typeof counts] - 1;
|
|
169
|
+
const currentIndex = state.selectedIndices[panel as keyof typeof state.selectedIndices] ?? 0;
|
|
170
|
+
const newIndex = Math.min(maxIndex, currentIndex + 1);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
...state,
|
|
174
|
+
selectedIndices: {
|
|
175
|
+
...state.selectedIndices,
|
|
176
|
+
[panel]: newIndex,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
case 'TOGGLE_EXPANDED': {
|
|
182
|
+
const newExpanded = new Set(state.expanded);
|
|
183
|
+
if (newExpanded.has(action.id)) {
|
|
184
|
+
newExpanded.delete(action.id);
|
|
185
|
+
} else {
|
|
186
|
+
newExpanded.add(action.id);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
...state,
|
|
190
|
+
expanded: newExpanded,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
case 'RESET': {
|
|
195
|
+
return createInitialNavigationState(state.location.screen === 'machines');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
default:
|
|
199
|
+
return state;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Helper to get current machine ID from location
|
|
205
|
+
*/
|
|
206
|
+
export function getCurrentMachineId(state: NavigationState): string | null {
|
|
207
|
+
const { location } = state;
|
|
208
|
+
if (location.screen === 'machines') return null;
|
|
209
|
+
return location.machineId;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Helper to get current project name from location
|
|
214
|
+
*/
|
|
215
|
+
export function getCurrentProjectName(state: NavigationState): string | null {
|
|
216
|
+
const { location } = state;
|
|
217
|
+
if (location.screen === 'machines' || location.screen === 'projects') return null;
|
|
218
|
+
return location.projectName;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Helper to check if we can go back
|
|
223
|
+
*/
|
|
224
|
+
export function canGoBack(state: NavigationState): boolean {
|
|
225
|
+
return state.history.length > 0;
|
|
226
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared module exports
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic types, providers, hooks, and components for TUI and Web.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
MachineStatus,
|
|
10
|
+
MachineInfo as SharedMachineInfo,
|
|
11
|
+
Project,
|
|
12
|
+
Workspace,
|
|
13
|
+
WorkspaceSession,
|
|
14
|
+
InboxItem,
|
|
15
|
+
InboxItemType,
|
|
16
|
+
SessionStream,
|
|
17
|
+
NavigationLocation,
|
|
18
|
+
PanelFocus,
|
|
19
|
+
} from './types.js';
|
|
20
|
+
|
|
21
|
+
// Providers
|
|
22
|
+
export type {
|
|
23
|
+
MachineProvider,
|
|
24
|
+
CreateSessionOptions,
|
|
25
|
+
AttachSessionOptions,
|
|
26
|
+
MachineProviderEvent,
|
|
27
|
+
MachineProviderEventHandler,
|
|
28
|
+
EventedMachineProvider,
|
|
29
|
+
RemoteMachineProviderConfig,
|
|
30
|
+
} from './providers/index.js';
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
LocalMachineProvider,
|
|
34
|
+
getLocalMachineProvider,
|
|
35
|
+
RemoteMachineProvider,
|
|
36
|
+
createRemoteMachineProvider,
|
|
37
|
+
} from './providers/index.js';
|
|
38
|
+
|
|
39
|
+
// Hooks
|
|
40
|
+
export type {
|
|
41
|
+
NavigationState,
|
|
42
|
+
NavigationAction,
|
|
43
|
+
} from './hooks/index.js';
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
createInitialNavigationState,
|
|
47
|
+
navigationReducer,
|
|
48
|
+
getCurrentMachineId,
|
|
49
|
+
getCurrentProjectName,
|
|
50
|
+
canGoBack,
|
|
51
|
+
} from './hooks/index.js';
|
|
52
|
+
|
|
53
|
+
// Components - MachineList
|
|
54
|
+
export type {
|
|
55
|
+
ConnectionStatus,
|
|
56
|
+
MachineInfo,
|
|
57
|
+
UseMachineListProps,
|
|
58
|
+
MachineListItem,
|
|
59
|
+
UseMachineListReturn,
|
|
60
|
+
} from './components/index.js';
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
useMachineList,
|
|
64
|
+
formatLastSeen,
|
|
65
|
+
getStatusColor,
|
|
66
|
+
getMachineLabel,
|
|
67
|
+
} from './components/index.js';
|
|
68
|
+
|
|
69
|
+
// Components - SpacesBrowser
|
|
70
|
+
export type {
|
|
71
|
+
WorkspaceInfo,
|
|
72
|
+
SessionInfo,
|
|
73
|
+
TreeItem,
|
|
74
|
+
TreeItemWithState,
|
|
75
|
+
UseSpacesBrowserProps,
|
|
76
|
+
UseSpacesBrowserReturn,
|
|
77
|
+
} from './components/index.js';
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
useSpacesBrowser,
|
|
81
|
+
formatTime,
|
|
82
|
+
} from './components/index.js';
|
|
83
|
+
|
|
84
|
+
// Components - Inbox
|
|
85
|
+
export type {
|
|
86
|
+
InboxItem as SharedInboxItem,
|
|
87
|
+
InboxItemType as SharedInboxItemType,
|
|
88
|
+
ParsedSessionName,
|
|
89
|
+
SessionGroup,
|
|
90
|
+
WorkspaceGroup,
|
|
91
|
+
ProjectGroup,
|
|
92
|
+
InboxDisplayItem,
|
|
93
|
+
UseInboxProps,
|
|
94
|
+
UseInboxReturn,
|
|
95
|
+
} from './components/index.js';
|
|
96
|
+
|
|
97
|
+
export {
|
|
98
|
+
useInbox,
|
|
99
|
+
parseSessionName,
|
|
100
|
+
getInboxIcon,
|
|
101
|
+
getInboxTypeLabel,
|
|
102
|
+
formatTimeAgo,
|
|
103
|
+
} from './components/index.js';
|
|
104
|
+
|
|
105
|
+
// Components - ProjectList
|
|
106
|
+
export type {
|
|
107
|
+
ProjectInfo,
|
|
108
|
+
ProjectListItem,
|
|
109
|
+
UseProjectListProps,
|
|
110
|
+
UseProjectListReturn,
|
|
111
|
+
} from './components/index.js';
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
useProjectList,
|
|
115
|
+
getProjectDisplayName,
|
|
116
|
+
getShortRepoName,
|
|
117
|
+
formatWorkspaceCount,
|
|
118
|
+
} from './components/index.js';
|
|
119
|
+
|
|
120
|
+
// Components - renderers (import separately for tree-shaking)
|
|
121
|
+
// Web: import { MachineListWeb, SpacesBrowserWeb, InboxWeb, ProjectListWeb } from '@spaces/shared/components'
|
|
122
|
+
// TUI: import { MachineListTUI, SpacesBrowserTUI, InboxTUI, ProjectListTUI } from '@spaces/shared/components'
|