khal-os 1.260324.2
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/.env.example +23 -0
- package/.genie/mailbox/cli-sent.jsonl +3 -0
- package/.genie/mailbox/ds1-wave2-engineer-1.json +15 -0
- package/.genie/mailbox/ds1-wave2-engineer-2.json +15 -0
- package/.genie/mailbox/ds1-wave2-engineer-3.json +15 -0
- package/.genie/state/os-observability.json +39 -0
- package/.genie/state/tmux-control-mode-terminal.json +28 -0
- package/.genie/wishes/genieos-one-theme/WISH.md +417 -0
- package/.genie/wishes/workos-prod-rbac/WISH.md +345 -0
- package/.github/workflows/ci.yml +39 -0
- package/.github/workflows/release.yml +78 -0
- package/.github/workflows/version.yml +122 -0
- package/.husky/pre-commit +1 -0
- package/.pnpm-approve-builds.json +1 -0
- package/CLAUDE.md +117 -0
- package/LICENSE +21 -0
- package/README.md +38 -0
- package/biome.json +124 -0
- package/bun.lock +1249 -0
- package/docs/workos-setup.md +116 -0
- package/ecosystem.config.cjs +26 -0
- package/instrumentation.ts +8 -0
- package/knip.json +35 -0
- package/nats.conf +7 -0
- package/next.config.ts +25 -0
- package/package.json +78 -0
- package/packages/dev3000-app/components.ts +12 -0
- package/packages/dev3000-app/manifest.ts +19 -0
- package/packages/dev3000-app/package.json +23 -0
- package/packages/dev3000-app/views/dev3000/Dev3000App.tsx +758 -0
- package/packages/dev3000-app/views/dev3000/ErrorsPanel.tsx +160 -0
- package/packages/dev3000-app/views/dev3000/dev3000-context.tsx +21 -0
- package/packages/dev3000-app/views/dev3000/index.ts +4 -0
- package/packages/dev3000-app/views/dev3000/schema.ts +55 -0
- package/packages/dev3000-app/views/dev3000/service/index.ts +358 -0
- package/packages/dev3000-app/views/dev3000/service/runtime +1 -0
- package/packages/dev3000-app/views/dev3000/subjects.ts +9 -0
- package/packages/dev3000-app/views/dev3000/types.ts +77 -0
- package/packages/files-app/components.ts +12 -0
- package/packages/files-app/manifest.ts +19 -0
- package/packages/files-app/package.json +23 -0
- package/packages/files-app/views/files/ContextMenu.tsx +151 -0
- package/packages/files-app/views/files/DeleteConfirmDialog.tsx +39 -0
- package/packages/files-app/views/files/FileItem.tsx +128 -0
- package/packages/files-app/views/files/FilesApp.tsx +509 -0
- package/packages/files-app/views/files/FilesListView.tsx +201 -0
- package/packages/files-app/views/files/FilesToolbar.tsx +117 -0
- package/packages/files-app/views/files/GridView.tsx +90 -0
- package/packages/files-app/views/files/InlineInput.tsx +131 -0
- package/packages/files-app/views/files/UploadOverlay.tsx +61 -0
- package/packages/files-app/views/files/schema.ts +49 -0
- package/packages/files-app/views/files/service/index.ts +184 -0
- package/packages/files-app/views/files/service/runtime +1 -0
- package/packages/files-app/views/files/use-files.ts +201 -0
- package/packages/files-app/views/files/use-upload.ts +105 -0
- package/packages/genie-app/components.ts +12 -0
- package/packages/genie-app/lib/subjects.ts +87 -0
- package/packages/genie-app/manifest.ts +19 -0
- package/packages/genie-app/package.json +29 -0
- package/packages/genie-app/views/genie/service/agent-lifecycle.ts +136 -0
- package/packages/genie-app/views/genie/service/cli.ts +114 -0
- package/packages/genie-app/views/genie/service/comms.ts +141 -0
- package/packages/genie-app/views/genie/service/directory.ts +167 -0
- package/packages/genie-app/views/genie/service/index.ts +219 -0
- package/packages/genie-app/views/genie/service/system.ts +123 -0
- package/packages/genie-app/views/genie/service/teams.ts +191 -0
- package/packages/genie-app/views/genie/service/terminal-proxy.ts +184 -0
- package/packages/genie-app/views/genie/service/tmux-control.ts +318 -0
- package/packages/genie-app/views/genie/service/wishes.ts +270 -0
- package/packages/genie-app/views/genie/ui/GenieApp.tsx +5 -0
- package/packages/genie-app/views/genie/ui/PaneCard.tsx +307 -0
- package/packages/genie-app/views/genie/ui/Sidebar.tsx +212 -0
- package/packages/genie-app/views/genie/ui/TabBar.tsx +70 -0
- package/packages/genie-app/views/genie/ui/WorkspaceCanvas.tsx +343 -0
- package/packages/genie-app/views/genie/ui/XTermPane.tsx +306 -0
- package/packages/genie-app/views/genie/ui/hooks/useNatsAction.ts +54 -0
- package/packages/genie-app/views/genie/ui/hooks/useNatsRequest.ts +68 -0
- package/packages/genie-app/views/genie/ui/panels/AgentsPanel.tsx +399 -0
- package/packages/genie-app/views/genie/ui/panels/ChatPanel.tsx +351 -0
- package/packages/genie-app/views/genie/ui/panels/SystemPanel.tsx +195 -0
- package/packages/genie-app/views/genie/ui/panels/TeamsPanel.tsx +560 -0
- package/packages/genie-app/views/genie/ui/panels/WishesPanel.tsx +424 -0
- package/packages/nats-viewer-app/components.ts +12 -0
- package/packages/nats-viewer-app/manifest.ts +18 -0
- package/packages/nats-viewer-app/package.json +14 -0
- package/packages/nats-viewer-app/views/nats-viewer/ActiveSubs.tsx +34 -0
- package/packages/nats-viewer-app/views/nats-viewer/MessageLog.tsx +247 -0
- package/packages/nats-viewer-app/views/nats-viewer/NatsViewer.tsx +209 -0
- package/packages/nats-viewer-app/views/nats-viewer/PublishPanel.tsx +111 -0
- package/packages/nats-viewer-app/views/nats-viewer/RequestPanel.tsx +165 -0
- package/packages/nats-viewer-app/views/nats-viewer/Sidebar.tsx +59 -0
- package/packages/nats-viewer-app/views/nats-viewer/SubjectCatalog.tsx +63 -0
- package/packages/nats-viewer-app/views/nats-viewer/SubscribeInput.tsx +59 -0
- package/packages/nats-viewer-app/views/nats-viewer/index.ts +5 -0
- package/packages/nats-viewer-app/views/nats-viewer/nats-viewer-context.tsx +31 -0
- package/packages/nats-viewer-app/views/nats-viewer/types.ts +7 -0
- package/packages/nats-viewer-app/views/nats-viewer/use-message-buffer.ts +55 -0
- package/packages/os-cli/package.json +18 -0
- package/packages/os-cli/src/commands/events.ts +176 -0
- package/packages/os-cli/src/commands/logs.ts +96 -0
- package/packages/os-cli/src/commands/status.ts +53 -0
- package/packages/os-cli/src/commands/traces.ts +115 -0
- package/packages/os-cli/src/index.ts +15 -0
- package/packages/os-cli/src/lib/formatter.ts +123 -0
- package/packages/os-cli/src/lib/nats.ts +16 -0
- package/packages/os-cli/src/lib/trace-tree.ts +144 -0
- package/packages/os-cli/tsconfig.json +12 -0
- package/packages/os-sdk/package.json +27 -0
- package/packages/os-sdk/src/api/handler.ts +67 -0
- package/packages/os-sdk/src/config.ts +68 -0
- package/packages/os-sdk/src/db/factory.test.ts +42 -0
- package/packages/os-sdk/src/db/factory.ts +72 -0
- package/packages/os-sdk/src/db/migrate.ts +140 -0
- package/packages/os-sdk/src/db/provision.ts +44 -0
- package/packages/os-sdk/src/index.ts +36 -0
- package/packages/os-sdk/src/service/console-intercept.ts +60 -0
- package/packages/os-sdk/src/service/logger.ts +88 -0
- package/packages/os-sdk/src/service/o11y-streams.ts +88 -0
- package/packages/os-sdk/src/service/runtime.ts +259 -0
- package/packages/os-sdk/src/service/trace.ts +71 -0
- package/packages/os-sdk/tsconfig.json +16 -0
- package/packages/os-ui/package.json +13 -0
- package/packages/os-ui/src/index.ts +29 -0
- package/packages/os-ui/src/server.ts +4 -0
- package/packages/os-ui/tsconfig.json +19 -0
- package/packages/settings-app/components.ts +12 -0
- package/packages/settings-app/manifest.ts +18 -0
- package/packages/settings-app/package.json +14 -0
- package/packages/settings-app/views/settings/Settings.tsx +492 -0
- package/packages/terminal-app/components.ts +12 -0
- package/packages/terminal-app/manifest.ts +20 -0
- package/packages/terminal-app/package.json +23 -0
- package/packages/terminal-app/views/terminal/schema.ts +82 -0
- package/packages/terminal-app/views/terminal/service/index.ts +133 -0
- package/packages/terminal-app/views/terminal/service/runtime +1 -0
- package/packages/terminal-app/views/terminal/service/session.ts +290 -0
- package/packages/terminal-app/views/terminal/service/shell-hooks/bashrc-hook.sh +21 -0
- package/packages/terminal-app/views/terminal/types.ts +26 -0
- package/packages/terminal-app/views/terminal/ui/MultiTerminalApp.tsx +615 -0
- package/packages/terminal-app/views/terminal/ui/SplitDragHandle.tsx +91 -0
- package/packages/terminal-app/views/terminal/ui/SplitPaneRenderer.tsx +112 -0
- package/packages/terminal-app/views/terminal/ui/TerminalPane.tsx +478 -0
- package/packages/terminal-app/views/terminal/ui/TerminalTabBar.tsx +131 -0
- package/pnpm-workspace.yaml +9 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/icons/code-server.svg +6 -0
- package/public/icons/default.svg +5 -0
- package/public/icons/dusk/1password.svg +1 -0
- package/public/icons/dusk/activity_monitor.svg +1 -0
- package/public/icons/dusk/app_store.svg +1 -0
- package/public/icons/dusk/atom.svg +1 -0
- package/public/icons/dusk/brave.svg +1 -0
- package/public/icons/dusk/calculator.svg +1 -0
- package/public/icons/dusk/calendar.svg +1 -0
- package/public/icons/dusk/chrome.svg +1 -0
- package/public/icons/dusk/chrome2.svg +1 -0
- package/public/icons/dusk/dashboard.svg +13 -0
- package/public/icons/dusk/discord.svg +1 -0
- package/public/icons/dusk/dropbox.svg +1 -0
- package/public/icons/dusk/electron.svg +1 -0
- package/public/icons/dusk/figma.svg +1 -0
- package/public/icons/dusk/finder.svg +1 -0
- package/public/icons/dusk/finder2.svg +1 -0
- package/public/icons/dusk/finder3.svg +1 -0
- package/public/icons/dusk/firefox.svg +1 -0
- package/public/icons/dusk/framer.svg +1 -0
- package/public/icons/dusk/gimp.svg +1 -0
- package/public/icons/dusk/github_desktop.svg +1 -0
- package/public/icons/dusk/hyper.svg +1 -0
- package/public/icons/dusk/hyper3.svg +1 -0
- package/public/icons/dusk/intellij.svg +1 -0
- package/public/icons/dusk/iterm2.svg +1 -0
- package/public/icons/dusk/itunes.svg +1 -0
- package/public/icons/dusk/mail.svg +1 -0
- package/public/icons/dusk/messenger.svg +1 -0
- package/public/icons/dusk/mongodb.svg +1 -0
- package/public/icons/dusk/notes.svg +1 -0
- package/public/icons/dusk/notion.svg +1 -0
- package/public/icons/dusk/obs.svg +1 -0
- package/public/icons/dusk/pages.svg +1 -0
- package/public/icons/dusk/photos.svg +1 -0
- package/public/icons/dusk/postman.svg +1 -0
- package/public/icons/dusk/preview.svg +1 -0
- package/public/icons/dusk/reminders.svg +1 -0
- package/public/icons/dusk/safari.svg +1 -0
- package/public/icons/dusk/sequel_pro.svg +1 -0
- package/public/icons/dusk/sketch.svg +1 -0
- package/public/icons/dusk/skype.svg +1 -0
- package/public/icons/dusk/slack.svg +1 -0
- package/public/icons/dusk/slack2.svg +1 -0
- package/public/icons/dusk/spotify.svg +1 -0
- package/public/icons/dusk/steam.svg +1 -0
- package/public/icons/dusk/system_preferences.svg +1 -0
- package/public/icons/dusk/tableplus.svg +1 -0
- package/public/icons/dusk/teams.svg +1 -0
- package/public/icons/dusk/telegram.svg +1 -0
- package/public/icons/dusk/terminal.svg +1 -0
- package/public/icons/dusk/todoist.svg +1 -0
- package/public/icons/dusk/trash.svg +1 -0
- package/public/icons/dusk/trello.svg +1 -0
- package/public/icons/dusk/vivaldi.svg +1 -0
- package/public/icons/dusk/vlc.svg +1 -0
- package/public/icons/dusk/vscode.svg +1 -0
- package/public/icons/dusk/whatsapp.svg +1 -0
- package/public/icons/dusk/xeyes.svg +1 -0
- package/public/icons/dusk/zoom.svg +1 -0
- package/public/icons/files.svg +5 -0
- package/public/icons/pwa/icon-192.png +0 -0
- package/public/icons/pwa/icon-512.png +0 -0
- package/public/icons/settings.svg +14 -0
- package/public/icons/terminal.svg +5 -0
- package/public/icons/text-editor.svg +7 -0
- package/public/manifest.json +38 -0
- package/public/next.svg +1 -0
- package/public/sw.js +41 -0
- package/public/vercel.svg +1 -0
- package/public/wallpapers/default.svg +10 -0
- package/public/window.svg +1 -0
- package/scripts/generate-pwa-icons.mjs +33 -0
- package/scripts/install-nats.sh +37 -0
- package/sentry.client.config.ts +21 -0
- package/sentry.edge.config.ts +12 -0
- package/sentry.server.config.ts +12 -0
- package/src/app/api/files/download/route.ts +81 -0
- package/src/app/api/files/download-zip/route.ts +102 -0
- package/src/app/api/files/upload/route.ts +58 -0
- package/src/app/api/webhooks/workos/route.ts +98 -0
- package/src/app/auth/callback/route.ts +16 -0
- package/src/app/auth/logout/route.ts +15 -0
- package/src/app/desktop/desktop-shell.tsx +110 -0
- package/src/app/desktop/layout.tsx +8 -0
- package/src/app/desktop/page.tsx +24 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +7 -0
- package/src/app/layout.tsx +64 -0
- package/src/app/offline/page.tsx +83 -0
- package/src/app/page.tsx +5 -0
- package/src/app/standalone/[appId]/page.tsx +28 -0
- package/src/app/standalone/layout.tsx +10 -0
- package/src/components/app-icon.tsx +55 -0
- package/src/components/apps/_echo/schema.ts +14 -0
- package/src/components/apps/_echo/service/index.ts +42 -0
- package/src/components/apps/app-manifest.ts +97 -0
- package/src/components/apps/app-registry.ts +55 -0
- package/src/components/apps/dev3000/Dev3000App.tsx +224 -0
- package/src/components/apps/dev3000/ErrorsPanel.tsx +160 -0
- package/src/components/apps/dev3000/Sidebar.tsx +41 -0
- package/src/components/apps/dev3000/TimelineLog.tsx +173 -0
- package/src/components/apps/dev3000/dev3000-context.tsx +29 -0
- package/src/components/apps/dev3000/index.ts +4 -0
- package/src/components/apps/dev3000/schema.ts +48 -0
- package/src/components/apps/dev3000/service/index.ts +520 -0
- package/src/components/apps/dev3000/service/runtime +1 -0
- package/src/components/apps/dev3000/types.ts +15 -0
- package/src/components/apps/dev3000/use-message-buffer.ts +46 -0
- package/src/components/apps/files/ContextMenu.tsx +151 -0
- package/src/components/apps/files/DeleteConfirmDialog.tsx +78 -0
- package/src/components/apps/files/FileItem.tsx +128 -0
- package/src/components/apps/files/FilesApp.tsx +509 -0
- package/src/components/apps/files/FilesListView.tsx +201 -0
- package/src/components/apps/files/FilesToolbar.tsx +117 -0
- package/src/components/apps/files/GridView.tsx +90 -0
- package/src/components/apps/files/InlineInput.tsx +131 -0
- package/src/components/apps/files/UploadOverlay.tsx +61 -0
- package/src/components/apps/files/schema.ts +49 -0
- package/src/components/apps/files/service/index.ts +227 -0
- package/src/components/apps/files/service/runtime +1 -0
- package/src/components/apps/files/use-files.ts +201 -0
- package/src/components/apps/files/use-upload.ts +105 -0
- package/src/components/apps/nats-viewer/ActiveSubs.tsx +34 -0
- package/src/components/apps/nats-viewer/MessageLog.tsx +247 -0
- package/src/components/apps/nats-viewer/NatsViewer.tsx +209 -0
- package/src/components/apps/nats-viewer/PublishPanel.tsx +113 -0
- package/src/components/apps/nats-viewer/RequestPanel.tsx +167 -0
- package/src/components/apps/nats-viewer/Sidebar.tsx +62 -0
- package/src/components/apps/nats-viewer/SubjectCatalog.tsx +64 -0
- package/src/components/apps/nats-viewer/SubscribeInput.tsx +59 -0
- package/src/components/apps/nats-viewer/index.ts +5 -0
- package/src/components/apps/nats-viewer/nats-viewer-context.tsx +31 -0
- package/src/components/apps/nats-viewer/types.ts +7 -0
- package/src/components/apps/nats-viewer/use-message-buffer.ts +55 -0
- package/src/components/apps/settings/Settings.tsx +492 -0
- package/src/components/apps/terminal/schema.ts +82 -0
- package/src/components/apps/terminal/service/index.ts +189 -0
- package/src/components/apps/terminal/service/runtime +1 -0
- package/src/components/apps/terminal/service/session.ts +296 -0
- package/src/components/apps/terminal/service/shell-hooks/bashrc-hook.sh +21 -0
- package/src/components/apps/terminal/types.ts +26 -0
- package/src/components/apps/terminal/ui/MultiTerminalApp.tsx +617 -0
- package/src/components/apps/terminal/ui/SplitDragHandle.tsx +91 -0
- package/src/components/apps/terminal/ui/SplitPaneRenderer.tsx +112 -0
- package/src/components/apps/terminal/ui/TerminalPane.tsx +476 -0
- package/src/components/apps/terminal/ui/TerminalTabBar.tsx +131 -0
- package/src/components/desktop/AnimatedBackground.tsx +69 -0
- package/src/components/desktop/Desktop.tsx +79 -0
- package/src/components/desktop/DesktopBackground.tsx +16 -0
- package/src/components/desktop/DesktopIcon.tsx +49 -0
- package/src/components/desktop/ShortcutViewer.tsx +136 -0
- package/src/components/desktop/WindowRenderer.tsx +34 -0
- package/src/components/desktop/WindowSwitcher.tsx +42 -0
- package/src/components/notifications/NotificationCenter.tsx +153 -0
- package/src/components/notifications/NotificationToasts.tsx +66 -0
- package/src/components/notifications/OrphanSessionToast.tsx +293 -0
- package/src/components/os-primitives/collapsible-sidebar.tsx +226 -0
- package/src/components/os-primitives/dialog.tsx +76 -0
- package/src/components/os-primitives/empty-state.tsx +43 -0
- package/src/components/os-primitives/index.ts +21 -0
- package/src/components/os-primitives/list-view.tsx +155 -0
- package/src/components/os-primitives/property-panel.tsx +108 -0
- package/src/components/os-primitives/section-header.tsx +19 -0
- package/src/components/os-primitives/sidebar-nav.tsx +110 -0
- package/src/components/os-primitives/split-pane.tsx +146 -0
- package/src/components/os-primitives/status-badge.tsx +10 -0
- package/src/components/os-primitives/status-bar.tsx +100 -0
- package/src/components/os-primitives/toolbar.tsx +152 -0
- package/src/components/taskbar/AppLauncher.tsx +114 -0
- package/src/components/taskbar/RunningApps.tsx +71 -0
- package/src/components/taskbar/SystemTray.tsx +134 -0
- package/src/components/taskbar/Taskbar.tsx +45 -0
- package/src/components/taskbar/UserMenu.tsx +138 -0
- package/src/components/taskbar/WorkspaceSwitcher.tsx +9 -0
- package/src/components/ui/ContextMenu.tsx +130 -0
- package/src/components/ui/badge.tsx +39 -0
- package/src/components/ui/button.tsx +102 -0
- package/src/components/ui/command.tsx +165 -0
- package/src/components/ui/dropdown-menu.tsx +233 -0
- package/src/components/ui/input.tsx +48 -0
- package/src/components/ui/note.tsx +55 -0
- package/src/components/ui/separator.tsx +25 -0
- package/src/components/ui/spinner.tsx +42 -0
- package/src/components/ui/switch.tsx +36 -0
- package/src/components/ui/theme-provider.tsx +24 -0
- package/src/components/ui/theme-switcher.tsx +51 -0
- package/src/components/ui/tooltip.tsx +62 -0
- package/src/components/window/MobileWindowStack.tsx +218 -0
- package/src/components/window/SnapPreview.tsx +37 -0
- package/src/components/window/StandaloneFrame.tsx +170 -0
- package/src/components/window/Window.tsx +423 -0
- package/src/components/window/WindowContent.tsx +14 -0
- package/src/components/window/WindowControlsOverlay.tsx +89 -0
- package/src/components/window/WindowFrame.tsx +124 -0
- package/src/lib/auth/index.ts +27 -0
- package/src/lib/auth/roles.ts +50 -0
- package/src/lib/auth/types.ts +32 -0
- package/src/lib/auth/use-auth.ts +53 -0
- package/src/lib/auth/webhook-handler.ts +87 -0
- package/src/lib/auth/workos.ts +67 -0
- package/src/lib/constants.ts +1 -0
- package/src/lib/desktop/dedup.ts +57 -0
- package/src/lib/desktop/schema.ts +55 -0
- package/src/lib/files/filename-validation.ts +41 -0
- package/src/lib/files/safe-path.ts +49 -0
- package/src/lib/hooks/use-desktop-nats.ts +438 -0
- package/src/lib/hooks/use-is-mobile.ts +23 -0
- package/src/lib/hooks/use-launch-app.ts +79 -0
- package/src/lib/hooks/use-nats-notifications.ts +84 -0
- package/src/lib/hooks/use-nats.ts +60 -0
- package/src/lib/hooks/use-visual-viewport.ts +72 -0
- package/src/lib/icons/resolve-window-icon.ts +10 -0
- package/src/lib/keyboard/defaults.ts +146 -0
- package/src/lib/keyboard/types.ts +52 -0
- package/src/lib/keyboard/use-global-keybinds.ts +231 -0
- package/src/lib/nats-client.ts +255 -0
- package/src/lib/nats.ts +35 -0
- package/src/lib/notifications/schema.ts +12 -0
- package/src/lib/service-loader.ts +171 -0
- package/src/lib/subjects.ts +64 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/ws-bridge.ts +288 -0
- package/src/lib/ws-protocol.ts +53 -0
- package/src/lib/ws-server.ts +167 -0
- package/src/middleware.ts +57 -0
- package/src/stores/desktop-store.ts +112 -0
- package/src/stores/keybind-store.ts +66 -0
- package/src/stores/notification-store.ts +271 -0
- package/src/stores/theme-store.ts +25 -0
- package/src/stores/window-store.ts +294 -0
- package/src/theme/animations.css +68 -0
- package/src/theme/base.css +123 -0
- package/src/theme/controls.css +35 -0
- package/src/theme/design-tokens.css +276 -0
- package/src/theme/index.css +23 -0
- package/src/theme/menus.css +45 -0
- package/src/theme/status.css +41 -0
- package/src/theme/surfaces.css +94 -0
- package/src/theme/tailwind-map.css +138 -0
- package/src/theme/taskbar.css +25 -0
- package/src/theme/terminal.css +55 -0
- package/src/theme/typography.css +26 -0
- package/src/theme/utilities.css +156 -0
- package/src/theme/window.css +103 -0
- package/src/types/desktop-entry.ts +12 -0
- package/src/types/use-descendants.d.ts +13 -0
- package/src/types/window.ts +28 -0
- package/src/types.d.ts +9 -0
- package/tauri/Cargo.lock +5464 -0
- package/tauri/Cargo.toml +19 -0
- package/tauri/build.rs +3 -0
- package/tauri/capabilities/default.json +36 -0
- package/tauri/icons/128x128.png +0 -0
- package/tauri/icons/128x128@2x.png +0 -0
- package/tauri/icons/32x32.png +0 -0
- package/tauri/icons/icon.png +0 -0
- package/tauri/src/main.rs +396 -0
- package/tauri/tauri.conf.json +23 -0
- package/tsconfig.json +43 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# Wish: WorkOS Production + RBAC Enforcement (Phase 1)
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|-------|-------|
|
|
5
|
+
| **Status** | DRAFT |
|
|
6
|
+
| **Slug** | `workos-prod-rbac` |
|
|
7
|
+
| **Date** | 2026-03-23 |
|
|
8
|
+
| **GitHub Issue** | [namastexlabs/genie-os#13](https://github.com/namastexlabs/genie-os/issues/13) |
|
|
9
|
+
| **Architecture** | [namastexlabs/genie-os#16](https://github.com/namastexlabs/genie-os/issues/16) |
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
Phase 1 of the multi-tenant Genie OS platform. Flip WorkOS from staging to production, remove the TEMP BYPASS that grants all users admin, and enforce role-based access control using WorkOS's native RBAC. This is the auth foundation that all subsequent phases (multi-org, fleet management, FGA, marketplace) build on.
|
|
14
|
+
|
|
15
|
+
## Context: Multi-Tenant Vision
|
|
16
|
+
|
|
17
|
+
This wish is Phase 1 of a 6-phase platform build (see [#16](https://github.com/namastexlabs/genie-os/issues/16)):
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Phase 1: WorkOS prod + RBAC enforcement ← THIS WISH
|
|
21
|
+
Phase 2: Multi-org + client isolation
|
|
22
|
+
Phase 3: Instance fleet management
|
|
23
|
+
Phase 4: FGA per-app permissions
|
|
24
|
+
Phase 5: Enterprise (Admin Portal, SCIM, Audit Logs)
|
|
25
|
+
Phase 6: App marketplace
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Full hierarchy (future):**
|
|
29
|
+
| Scope | Role | Access |
|
|
30
|
+
|-------|------|--------|
|
|
31
|
+
| Platform | `platform-owner` | Everything across all clients |
|
|
32
|
+
| Platform | `platform-admin` | All instances + monitoring |
|
|
33
|
+
| Platform | `platform-dev` | Assigned instances + dev tools |
|
|
34
|
+
| Client | `client-owner` | All apps deployed to their org |
|
|
35
|
+
| Client | `client-admin` | Apps + manage employees |
|
|
36
|
+
| Client | `client-member` | Only assigned apps |
|
|
37
|
+
|
|
38
|
+
**Phase 1 implements the platform scope only** (NamasteX org, our roles). Client scope comes in Phase 2.
|
|
39
|
+
|
|
40
|
+
## Scope
|
|
41
|
+
|
|
42
|
+
### IN
|
|
43
|
+
- **WorkOS production environment**: Swap staging API key, client ID, redirect URI, cookie password for production values
|
|
44
|
+
- **Remove TEMP BYPASS**: In `src/lib/auth/use-auth.ts`, replace hardcoded admin grant with actual session role
|
|
45
|
+
- **Server→client role plumbing**: Create a server component that calls `withAuth()` and passes role/permissions to client components (the `useAuth()` client hook doesn't expose role directly)
|
|
46
|
+
- **WorkOS Dashboard config**: Document exact roles, permissions, and org setup needed
|
|
47
|
+
- **Permission enforcement**: Return real role + derived permissions so `minRole` app gates work
|
|
48
|
+
- **Webhook endpoint**: Add `/api/webhooks/workos` route for role/membership change events
|
|
49
|
+
- **Preserve HeadlessChrome bypass**: Machine auth for d3k must keep working
|
|
50
|
+
- **Forward-compatible role slugs**: Use `platform-owner`, `platform-admin`, `platform-dev`, `member` — slugs that won't collide when client-scoped roles are added in Phase 2
|
|
51
|
+
|
|
52
|
+
### OUT
|
|
53
|
+
- **Multi-org / client organizations** — Phase 2
|
|
54
|
+
- **Instance fleet management** — Phase 3
|
|
55
|
+
- **FGA / per-app sharing** — Phase 4
|
|
56
|
+
- **Admin Portal, SCIM, Audit Logs** — Phase 5
|
|
57
|
+
- **App Directory / Marketplace** — Phase 6
|
|
58
|
+
- **Permissions management app in Genie OS** — Phase 2 (needs multi-org first)
|
|
59
|
+
- **Custom WorkOS UI / Widgets** — use hosted AuthKit for now
|
|
60
|
+
- **Feature flags** — available free but not needed yet
|
|
61
|
+
|
|
62
|
+
## Decisions
|
|
63
|
+
|
|
64
|
+
| Decision | Rationale |
|
|
65
|
+
|----------|-----------|
|
|
66
|
+
| Use WorkOS hosted AuthKit UI, not custom | Zero frontend auth code. Free up to 1M MAUs. |
|
|
67
|
+
| Server component for role plumbing | `useAuth()` client hook returns `{ user, loading }` only. `withAuth()` server-side returns `{ user, role, permissions }`. Use a server component wrapper that calls `withAuth()` and passes role to client context. |
|
|
68
|
+
| Role slugs: `platform-owner`, `platform-admin`, `platform-dev`, `member` | Forward-compatible with Phase 2 multi-org. WorkOS auto-prefixes org roles with `org-`, so platform roles need distinct slugs. `member` is WorkOS's default role for new memberships. |
|
|
69
|
+
| Single org for Phase 1 | Our NamasteX org only. Multi-org in Phase 2. |
|
|
70
|
+
| Webhook logs events + broadcasts via NATS | On role change, broadcast to connected clients via NATS so UI updates without full page reload. No server-side session store to invalidate — AuthKit manages cookies. |
|
|
71
|
+
| `ROLE_DEFAULTS` as fallback | If JWT permissions are empty (edge case during migration), fall back to role-based defaults. |
|
|
72
|
+
|
|
73
|
+
## Success Criteria
|
|
74
|
+
|
|
75
|
+
- [ ] WorkOS production environment active with production API key and client ID
|
|
76
|
+
- [ ] `NEXT_PUBLIC_WORKOS_REDIRECT_URI` points to production domain
|
|
77
|
+
- [ ] TEMP BYPASS removed from `use-auth.ts` — users get their actual role
|
|
78
|
+
- [ ] Server component passes role from `withAuth()` to client-side auth context
|
|
79
|
+
- [ ] A `member` role user can only access the Files app
|
|
80
|
+
- [ ] A `platform-dev` role user can access Terminal, Files, Settings, NATS Viewer
|
|
81
|
+
- [ ] A `platform-admin`/`platform-owner` role user can access all apps
|
|
82
|
+
- [ ] HeadlessChrome bypass still works for d3k
|
|
83
|
+
- [ ] Login/logout flow works end-to-end on production domain
|
|
84
|
+
- [ ] `/api/webhooks/workos` receives and processes role change events
|
|
85
|
+
- [ ] `WORKOS_WEBHOOK_SECRET` in `.env.example`
|
|
86
|
+
- [ ] `bun biome check .` and `bunx tsc --noEmit` pass
|
|
87
|
+
|
|
88
|
+
## Execution Strategy
|
|
89
|
+
|
|
90
|
+
### Wave 1 (foundation — docs + server-side role plumbing)
|
|
91
|
+
| Group | Agent | Description |
|
|
92
|
+
|-------|-------|-------------|
|
|
93
|
+
| 1 | engineer | WorkOS Dashboard setup guide + env config + server-side role provider |
|
|
94
|
+
|
|
95
|
+
### Wave 2 (parallel — client enforcement + webhooks)
|
|
96
|
+
| Group | Agent | Description |
|
|
97
|
+
|-------|-------|-------------|
|
|
98
|
+
| 2 | engineer | Remove TEMP BYPASS + wire role enforcement across UI |
|
|
99
|
+
| 3 | engineer | Webhook endpoint + NATS role-change broadcast |
|
|
100
|
+
|
|
101
|
+
### Wave 3 (quality gate)
|
|
102
|
+
| Group | Agent | Description |
|
|
103
|
+
|-------|-------|-------------|
|
|
104
|
+
| review | reviewer | Review all groups, run validation |
|
|
105
|
+
|
|
106
|
+
## Execution Groups
|
|
107
|
+
|
|
108
|
+
### Group 1: WorkOS Config + Server-Side Role Provider
|
|
109
|
+
|
|
110
|
+
**Goal:** Document dashboard setup and create the server→client role bridge that the review identified as missing.
|
|
111
|
+
|
|
112
|
+
**Deliverables:**
|
|
113
|
+
|
|
114
|
+
1. `docs/workos-setup.md` — Step-by-step guide for WorkOS dashboard:
|
|
115
|
+
- Create production environment (or switch from staging)
|
|
116
|
+
- Create NamasteX organization
|
|
117
|
+
- Define environment roles with these slugs:
|
|
118
|
+
- `platform-owner`: all permissions (NamasteX founders)
|
|
119
|
+
- `platform-admin`: `apps:access`, `settings:manage`, `members:manage` (NamasteX senior)
|
|
120
|
+
- `platform-dev`: `apps:access` (NamasteX builders)
|
|
121
|
+
- `member`: (WorkOS default — base access, maps to viewer)
|
|
122
|
+
- Define permissions using `resource:action` pattern:
|
|
123
|
+
- `apps:access` — base app access
|
|
124
|
+
- `apps:install` — install from marketplace (future)
|
|
125
|
+
- `settings:manage` — OS settings
|
|
126
|
+
- `members:manage` — invite/remove users
|
|
127
|
+
- `billing:manage` — billing/subscription (future)
|
|
128
|
+
- `instances:manage` — fleet management (future)
|
|
129
|
+
- Configure redirect URI, email verification, session config
|
|
130
|
+
- Configure webhook endpoint URL + signing secret
|
|
131
|
+
|
|
132
|
+
2. `.env.example` — Update with all WorkOS env vars:
|
|
133
|
+
```
|
|
134
|
+
WORKOS_API_KEY=sk_live_...
|
|
135
|
+
WORKOS_CLIENT_ID=client_...
|
|
136
|
+
NEXT_PUBLIC_WORKOS_REDIRECT_URI=https://<prod-domain>/auth/callback
|
|
137
|
+
WORKOS_COOKIE_PASSWORD=<32+ char random string>
|
|
138
|
+
WORKOS_WEBHOOK_SECRET=whsec_...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
3. `src/app/desktop/page.tsx` (or existing server component) — Server-side role injection:
|
|
142
|
+
- Call `withAuth()` to get `{ user, role, permissions, organizationId }`
|
|
143
|
+
- Pass `role` and `permissions` as props to the client-side desktop shell
|
|
144
|
+
- This solves the architectural gap: server `withAuth()` → prop drilling → client context
|
|
145
|
+
|
|
146
|
+
4. `src/lib/auth/roles.ts` — Update role hierarchy and aliases:
|
|
147
|
+
- Role hierarchy: `['member', 'platform-dev', 'platform-admin', 'platform-owner']`
|
|
148
|
+
- Aliases: `admin` → `platform-admin`, `developer` → `platform-dev`, `owner` → `platform-owner`, `viewer` → `member`, `user` → `member`
|
|
149
|
+
|
|
150
|
+
5. `src/components/apps/app-manifest.ts` — Update `ROLE_HIERARCHY`:
|
|
151
|
+
- `['member', 'platform-dev', 'platform-admin', 'platform-owner'] as const`
|
|
152
|
+
- Update `Role` type accordingly
|
|
153
|
+
|
|
154
|
+
**Acceptance Criteria:**
|
|
155
|
+
- [ ] `docs/workos-setup.md` exists with complete dashboard instructions
|
|
156
|
+
- [ ] `.env.example` has `WORKOS_WEBHOOK_SECRET`
|
|
157
|
+
- [ ] Server component calls `withAuth()` and passes role to client
|
|
158
|
+
- [ ] `ROLE_HIERARCHY` uses forward-compatible slugs
|
|
159
|
+
- [ ] `normalizeRole()` maps legacy slugs (`admin` → `platform-admin`, etc.)
|
|
160
|
+
- [ ] `bunx tsc --noEmit` passes
|
|
161
|
+
|
|
162
|
+
**Validation:**
|
|
163
|
+
```bash
|
|
164
|
+
test -f docs/workos-setup.md && \
|
|
165
|
+
grep -q "platform-owner" docs/workos-setup.md && \
|
|
166
|
+
grep -q "WORKOS_WEBHOOK_SECRET" .env.example && \
|
|
167
|
+
grep -q "platform-owner" src/components/apps/app-manifest.ts && \
|
|
168
|
+
grep -q "withAuth" src/app/desktop/page.tsx && \
|
|
169
|
+
bunx tsc --noEmit && \
|
|
170
|
+
echo "PASS" || echo "FAIL"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**depends-on:** none
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### Group 2: Remove TEMP BYPASS + Enforce Roles
|
|
178
|
+
|
|
179
|
+
**Goal:** Wire the actual WorkOS session role into the permission system so app gates work.
|
|
180
|
+
|
|
181
|
+
**Deliverables:**
|
|
182
|
+
|
|
183
|
+
1. `src/lib/auth/use-auth.ts` — Remove TEMP BYPASS:
|
|
184
|
+
- Accept role from server component props (passed via React context or prop drilling)
|
|
185
|
+
- Remove hardcoded `effectiveRole = 'admin'` (lines 42-44)
|
|
186
|
+
- Map server-provided role to internal role via `normalizeRole()`
|
|
187
|
+
- Derive permissions from role using `getRolePermissions()`
|
|
188
|
+
- Keep HeadlessChrome bypass intact — use `platform-owner` permissions (new top of hierarchy)
|
|
189
|
+
|
|
190
|
+
2. `src/lib/auth/workos.ts` — Align `ROLE_DEFAULTS` with new role slugs:
|
|
191
|
+
- `platform-owner`: `{ apps: ['*'], manageMembers: true }`
|
|
192
|
+
- `platform-admin`: `{ apps: ['*'], manageMembers: true }`
|
|
193
|
+
- `platform-dev`: `{ apps: ['terminal', 'files', 'settings', 'nats-viewer'], manageMembers: false }`
|
|
194
|
+
- `member`: `{ apps: ['files'], manageMembers: false }`
|
|
195
|
+
|
|
196
|
+
3. `src/components/taskbar/UserMenu.tsx` — Update role colors:
|
|
197
|
+
- Add `platform-owner` color (distinct from admin)
|
|
198
|
+
- Add `platform-admin` color
|
|
199
|
+
- Add `platform-dev` color
|
|
200
|
+
- `member` uses muted color (existing viewer color)
|
|
201
|
+
|
|
202
|
+
4. Update any component that checks role strings to use new slugs
|
|
203
|
+
|
|
204
|
+
**Acceptance Criteria:**
|
|
205
|
+
- [ ] TEMP BYPASS removed — no hardcoded `'admin'` assignment for all users
|
|
206
|
+
- [ ] `member` role user sees only Files app in desktop
|
|
207
|
+
- [ ] `platform-dev` role user sees Terminal, Files, Settings, NATS Viewer
|
|
208
|
+
- [ ] `platform-admin`/`platform-owner` sees all apps
|
|
209
|
+
- [ ] HeadlessChrome bypass returns `platform-owner`-level access
|
|
210
|
+
- [ ] `ROLE_COLORS` includes all 4 role slugs
|
|
211
|
+
- [ ] `bunx tsc --noEmit` passes
|
|
212
|
+
- [ ] `bun biome check .` passes
|
|
213
|
+
|
|
214
|
+
**Validation:**
|
|
215
|
+
```bash
|
|
216
|
+
# No TEMP BYPASS remaining
|
|
217
|
+
! grep -q "TEMP BYPASS" src/lib/auth/use-auth.ts && \
|
|
218
|
+
# New role slugs in use
|
|
219
|
+
grep -q "platform-owner" src/lib/auth/workos.ts && \
|
|
220
|
+
grep -q "platform-owner" src/components/taskbar/UserMenu.tsx && \
|
|
221
|
+
# Typecheck + lint pass
|
|
222
|
+
bunx tsc --noEmit && \
|
|
223
|
+
bun biome check . && \
|
|
224
|
+
echo "PASS" || echo "FAIL"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**depends-on:** Group 1
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
### Group 3: Webhook Endpoint + NATS Role Broadcast
|
|
232
|
+
|
|
233
|
+
**Goal:** Receive WorkOS webhook events and broadcast role changes to connected clients via NATS.
|
|
234
|
+
|
|
235
|
+
**Deliverables:**
|
|
236
|
+
|
|
237
|
+
1. `src/app/api/webhooks/workos/route.ts` — Webhook handler:
|
|
238
|
+
- Verify webhook signature using WorkOS SDK (`constructEvent()` or manual HMAC)
|
|
239
|
+
- Handle `organization_membership.updated` — extract new role, broadcast via NATS
|
|
240
|
+
- Handle `organization_membership.deleted` — broadcast membership revocation
|
|
241
|
+
- Handle `user.updated` — broadcast user metadata changes
|
|
242
|
+
- Return 200 OK on success, 400 on signature failure
|
|
243
|
+
- Route is already covered by `unauthenticatedPaths: ['/api/webhooks/:path*']`
|
|
244
|
+
|
|
245
|
+
2. `src/lib/auth/webhook-handler.ts` — Event processing + NATS broadcast:
|
|
246
|
+
- Parse WorkOS webhook payload by event type
|
|
247
|
+
- On role change: publish to NATS subject `os.auth.role-changed` with `{ userId, newRole, orgId }`
|
|
248
|
+
- On membership deleted: publish to `os.auth.membership-revoked` with `{ userId, orgId }`
|
|
249
|
+
- Connected WS clients subscribed to these subjects can force re-auth
|
|
250
|
+
- Log events for debugging (console OK in service files)
|
|
251
|
+
|
|
252
|
+
3. Clarification on session invalidation approach:
|
|
253
|
+
- AuthKit manages sessions via encrypted cookies — no server-side session store
|
|
254
|
+
- On `membership.deleted`: broadcast via NATS; client-side listener forces logout
|
|
255
|
+
- On `membership.updated` (role change): broadcast via NATS; client-side listener refreshes role from server
|
|
256
|
+
- Sessions expire naturally per WorkOS session config; webhook provides faster feedback
|
|
257
|
+
|
|
258
|
+
**Acceptance Criteria:**
|
|
259
|
+
- [ ] `POST /api/webhooks/workos` returns 200 for valid signed payloads
|
|
260
|
+
- [ ] `POST /api/webhooks/workos` returns 400 for invalid signatures
|
|
261
|
+
- [ ] NATS subjects `os.auth.role-changed` and `os.auth.membership-revoked` documented
|
|
262
|
+
- [ ] `bunx tsc --noEmit` passes
|
|
263
|
+
|
|
264
|
+
**Validation:**
|
|
265
|
+
```bash
|
|
266
|
+
test -f src/app/api/webhooks/workos/route.ts && \
|
|
267
|
+
grep -q "organization_membership" src/lib/auth/webhook-handler.ts && \
|
|
268
|
+
grep -q "os.auth" src/lib/auth/webhook-handler.ts && \
|
|
269
|
+
bunx tsc --noEmit && \
|
|
270
|
+
echo "PASS" || echo "FAIL"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**depends-on:** Group 1
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## QA Criteria
|
|
278
|
+
|
|
279
|
+
_What must be verified on dev after merge._
|
|
280
|
+
|
|
281
|
+
- [ ] Login with WorkOS production credentials works end-to-end
|
|
282
|
+
- [ ] User with `member` role sees only Files app on desktop
|
|
283
|
+
- [ ] User with `platform-dev` role sees Terminal, Files, Settings, NATS Viewer
|
|
284
|
+
- [ ] User with `platform-admin` role sees all apps + can manage members
|
|
285
|
+
- [ ] Role change in WorkOS dashboard reflects in app after webhook + NATS broadcast
|
|
286
|
+
- [ ] HeadlessChrome d3k bypass still renders desktop without login
|
|
287
|
+
- [ ] Logout clears session and redirects to login
|
|
288
|
+
- [ ] Invalid/expired sessions redirect to login
|
|
289
|
+
- [ ] Role slugs are forward-compatible (no refactoring needed for Phase 2 multi-org)
|
|
290
|
+
|
|
291
|
+
## Assumptions / Risks
|
|
292
|
+
|
|
293
|
+
| Risk | Severity | Mitigation |
|
|
294
|
+
|------|----------|------------|
|
|
295
|
+
| WorkOS staging→prod migration breaks existing sessions | Medium | Schedule during low-traffic; all users re-login once |
|
|
296
|
+
| `platform-owner` slug not yet in WorkOS dashboard | Low | Create in dashboard before deploying code. `normalizeRole()` fallback to `platform-admin`. |
|
|
297
|
+
| JWT permissions empty for existing users | Low | `ROLE_DEFAULTS` fallback handles this |
|
|
298
|
+
| Webhook signature verification needs shared secret | Low | `WORKOS_WEBHOOK_SECRET` in `.env` |
|
|
299
|
+
| Renaming roles from `admin`→`platform-admin` breaks existing code | Medium | `normalizeRole()` maps old→new. Grep for hardcoded role strings in all files. |
|
|
300
|
+
| `withAuth()` not available in all server component contexts | Low | Use Next.js middleware or layout-level server component. AuthKit middleware already runs on all protected routes. |
|
|
301
|
+
|
|
302
|
+
## Review Results
|
|
303
|
+
|
|
304
|
+
### Review 1 — Plan Review (pre-fix)
|
|
305
|
+
|
|
306
|
+
**Verdict:** FIX-FIRST
|
|
307
|
+
|
|
308
|
+
| # | Severity | Gap | Resolution |
|
|
309
|
+
|---|----------|-----|------------|
|
|
310
|
+
| 1 | HIGH | Client-side role access: `useAuth()` doesn't expose role | **Fixed:** Added server component deliverable in Group 1 that calls `withAuth()` and passes role as props |
|
|
311
|
+
| 2 | MEDIUM | `WORKOS_WEBHOOK_SECRET` missing from `.env.example` | **Fixed:** Added to Group 1, deliverable 2 |
|
|
312
|
+
| 3 | MEDIUM | Webhook session invalidation unspecified | **Fixed:** Added NATS broadcast approach in Group 3, deliverable 3 |
|
|
313
|
+
| 4 | LOW | `ROLE_COLORS` missing `owner` | **Fixed:** Incorporated in Group 2, deliverable 3 |
|
|
314
|
+
| 5 | LOW | HeadlessChrome should use top-of-hierarchy | **Fixed:** Group 2 specifies `platform-owner` permissions |
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Files to Create/Modify
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
# Create
|
|
322
|
+
docs/workos-setup.md — Dashboard setup guide (roles, permissions, session config)
|
|
323
|
+
src/app/api/webhooks/workos/route.ts — Webhook endpoint
|
|
324
|
+
src/lib/auth/webhook-handler.ts — Webhook event processing + NATS broadcast
|
|
325
|
+
|
|
326
|
+
# Modify
|
|
327
|
+
.env.example — Add WORKOS_WEBHOOK_SECRET
|
|
328
|
+
src/app/desktop/page.tsx — Server-side withAuth() → pass role to client
|
|
329
|
+
src/lib/auth/use-auth.ts — Remove TEMP BYPASS, accept role from server
|
|
330
|
+
src/lib/auth/workos.ts — Update ROLE_DEFAULTS to new slugs
|
|
331
|
+
src/lib/auth/roles.ts — New hierarchy + slug aliases
|
|
332
|
+
src/components/apps/app-manifest.ts — New ROLE_HIERARCHY with platform-* slugs
|
|
333
|
+
src/components/taskbar/UserMenu.tsx — ROLE_COLORS for all 4 slugs
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Future Wishes (Pre-Drafted)
|
|
337
|
+
|
|
338
|
+
| Phase | Wish | GitHub Issue | What |
|
|
339
|
+
|-------|------|-------------|------|
|
|
340
|
+
| 2 | Multi-Org + Client Isolation | [#16](https://github.com/namastexlabs/genie-os/issues/16) | WorkOS Organizations per client, org-level roles, org switcher, permissions management app |
|
|
341
|
+
| 3 | Instance Fleet Management | [#16](https://github.com/namastexlabs/genie-os/issues/16) | Instance registry, central admin panel, FGA instance resources |
|
|
342
|
+
| 4 | FGA App Permissions | [#14](https://github.com/namastexlabs/genie-os/issues/14) | Per-app per-instance per-user permissions, "share like Google Docs" |
|
|
343
|
+
| 5 | Enterprise Features | TBD | Admin Portal embed, Directory Sync, Audit Logs, Domain Verification |
|
|
344
|
+
| 6 | App Marketplace | [#14](https://github.com/namastexlabs/genie-os/issues/14) | Browse, publish, upvote apps; success/cost metrics; creator attribution |
|
|
345
|
+
| — | Braindump / Idea Pool | [#15](https://github.com/namastexlabs/genie-os/issues/15) | Non-disruptive idea capture in Genie OS |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, dev]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
quality-gate:
|
|
15
|
+
name: Quality Gate
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
timeout-minutes: 15
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: pnpm/action-setup@v4
|
|
23
|
+
|
|
24
|
+
- uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: 22
|
|
27
|
+
cache: pnpm
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: pnpm install --frozen-lockfile
|
|
31
|
+
|
|
32
|
+
- name: Typecheck
|
|
33
|
+
run: pnpm exec tsc --noEmit
|
|
34
|
+
|
|
35
|
+
- name: Lint
|
|
36
|
+
run: pnpm lint
|
|
37
|
+
|
|
38
|
+
- name: Build
|
|
39
|
+
run: pnpm build
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
name: Create Release
|
|
14
|
+
if: "!startsWith(github.event.head_commit.message, '[skip ci]')"
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
timeout-minutes: 10
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- name: Resolve version
|
|
23
|
+
id: ver
|
|
24
|
+
env:
|
|
25
|
+
GH_TOKEN: ${{ github.token }}
|
|
26
|
+
run: |
|
|
27
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
28
|
+
TAG="v${VERSION}"
|
|
29
|
+
|
|
30
|
+
if gh release view "${TAG}" > /dev/null 2>&1; then
|
|
31
|
+
echo "Release ${TAG} already exists — skipping"
|
|
32
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
33
|
+
else
|
|
34
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
38
|
+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
39
|
+
|
|
40
|
+
- name: Find previous release tag
|
|
41
|
+
id: prev
|
|
42
|
+
if: steps.ver.outputs.skip == 'false'
|
|
43
|
+
env:
|
|
44
|
+
GH_TOKEN: ${{ github.token }}
|
|
45
|
+
run: |
|
|
46
|
+
TAG="${{ steps.ver.outputs.tag }}"
|
|
47
|
+
PREV=$(gh release list --limit 50 --json tagName -q '.[].tagName' | grep -v "^${TAG}$" | head -1)
|
|
48
|
+
if [ -n "$PREV" ] && git merge-base --is-ancestor "$PREV" HEAD 2>/dev/null; then
|
|
49
|
+
echo "tag=${PREV}" >> "$GITHUB_OUTPUT"
|
|
50
|
+
else
|
|
51
|
+
echo "tag=" >> "$GITHUB_OUTPUT"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
- name: Generate changelog
|
|
55
|
+
id: changelog
|
|
56
|
+
if: steps.ver.outputs.skip == 'false' && steps.prev.outputs.tag != ''
|
|
57
|
+
run: |
|
|
58
|
+
PREV="${{ steps.prev.outputs.tag }}"
|
|
59
|
+
NOTES=$(git log --oneline "${PREV}..HEAD" --pretty="- %s" | head -50)
|
|
60
|
+
echo "notes<<EOF" >> "$GITHUB_OUTPUT"
|
|
61
|
+
echo "$NOTES" >> "$GITHUB_OUTPUT"
|
|
62
|
+
echo "EOF" >> "$GITHUB_OUTPUT"
|
|
63
|
+
|
|
64
|
+
- name: Create release
|
|
65
|
+
if: steps.ver.outputs.skip == 'false'
|
|
66
|
+
env:
|
|
67
|
+
GH_TOKEN: ${{ github.token }}
|
|
68
|
+
run: |
|
|
69
|
+
TAG="${{ steps.ver.outputs.tag }}"
|
|
70
|
+
NOTES="${{ steps.changelog.outputs.notes }}"
|
|
71
|
+
if [ -z "$NOTES" ]; then
|
|
72
|
+
NOTES="Genie OS release ${TAG}"
|
|
73
|
+
fi
|
|
74
|
+
printf '%s' "$NOTES" > /tmp/release-notes.md
|
|
75
|
+
gh release create "${TAG}" \
|
|
76
|
+
--target "${{ github.sha }}" \
|
|
77
|
+
--title "${TAG}" \
|
|
78
|
+
--notes-file /tmp/release-notes.md
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
name: Version
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: ["CI"]
|
|
6
|
+
types: [completed]
|
|
7
|
+
branches: [main, dev]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: version-${{ github.event.workflow_run.head_branch || 'manual' }}
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
auto-version:
|
|
19
|
+
name: Auto Version
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 10
|
|
22
|
+
if: >-
|
|
23
|
+
(github.event_name == 'workflow_dispatch') ||
|
|
24
|
+
(github.event.workflow_run.conclusion == 'success' &&
|
|
25
|
+
github.event.workflow_run.event == 'push' &&
|
|
26
|
+
!contains(github.event.workflow_run.head_commit.message, '[skip ci]') &&
|
|
27
|
+
(
|
|
28
|
+
(github.event.workflow_run.head_branch == 'main' &&
|
|
29
|
+
startsWith(github.event.workflow_run.head_commit.message, 'Merge pull request') &&
|
|
30
|
+
contains(github.event.workflow_run.head_commit.message, '/dev'))
|
|
31
|
+
||
|
|
32
|
+
(github.event.workflow_run.head_branch == 'dev')
|
|
33
|
+
))
|
|
34
|
+
|
|
35
|
+
steps:
|
|
36
|
+
- name: Determine branch and version prefix
|
|
37
|
+
id: context
|
|
38
|
+
run: |
|
|
39
|
+
BRANCH="${{ github.event.workflow_run.head_branch || 'dev' }}"
|
|
40
|
+
if [ "$BRANCH" = "main" ]; then
|
|
41
|
+
echo "branch=dev" >> "$GITHUB_OUTPUT"
|
|
42
|
+
echo "prefix=1" >> "$GITHUB_OUTPUT"
|
|
43
|
+
echo "npm_tag=latest" >> "$GITHUB_OUTPUT"
|
|
44
|
+
else
|
|
45
|
+
echo "branch=dev" >> "$GITHUB_OUTPUT"
|
|
46
|
+
echo "prefix=1" >> "$GITHUB_OUTPUT"
|
|
47
|
+
echo "npm_tag=next" >> "$GITHUB_OUTPUT"
|
|
48
|
+
fi
|
|
49
|
+
echo "Resolved: branch=dev, npm_tag=$([ "$BRANCH" = "main" ] && echo latest || echo next)"
|
|
50
|
+
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
with:
|
|
53
|
+
ref: ${{ steps.context.outputs.branch }}
|
|
54
|
+
fetch-depth: 0
|
|
55
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
56
|
+
|
|
57
|
+
- uses: pnpm/action-setup@v4
|
|
58
|
+
|
|
59
|
+
- uses: actions/setup-node@v4
|
|
60
|
+
with:
|
|
61
|
+
node-version: 22
|
|
62
|
+
cache: pnpm
|
|
63
|
+
|
|
64
|
+
- name: Install dependencies
|
|
65
|
+
run: pnpm install
|
|
66
|
+
|
|
67
|
+
- name: Configure git
|
|
68
|
+
run: |
|
|
69
|
+
git config user.name "github-actions[bot]"
|
|
70
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
71
|
+
|
|
72
|
+
- name: Derive version
|
|
73
|
+
id: version
|
|
74
|
+
run: |
|
|
75
|
+
PREFIX="${{ steps.context.outputs.prefix }}"
|
|
76
|
+
TODAY=$(date -u +%y%m%d)
|
|
77
|
+
EXISTING=$(git tag --list "v${PREFIX}.${TODAY}.*" | wc -l)
|
|
78
|
+
BUILD_NUMBER=$((EXISTING + 1))
|
|
79
|
+
VERSION="${PREFIX}.${TODAY}.${BUILD_NUMBER}"
|
|
80
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
81
|
+
echo "build_number=${BUILD_NUMBER}" >> "$GITHUB_OUTPUT"
|
|
82
|
+
echo "Derived version: ${VERSION}"
|
|
83
|
+
|
|
84
|
+
- name: Update package.json version
|
|
85
|
+
run: |
|
|
86
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
87
|
+
node -e "
|
|
88
|
+
const pkg = require('./package.json');
|
|
89
|
+
pkg.version = '${VERSION}';
|
|
90
|
+
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, '\t') + '\n');
|
|
91
|
+
"
|
|
92
|
+
|
|
93
|
+
- name: Commit and tag
|
|
94
|
+
run: |
|
|
95
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
96
|
+
BRANCH="${{ steps.context.outputs.branch }}"
|
|
97
|
+
|
|
98
|
+
git add package.json
|
|
99
|
+
if git diff --cached --quiet; then
|
|
100
|
+
echo "No version changes to commit"
|
|
101
|
+
else
|
|
102
|
+
git commit -m "chore(version): bump to ${VERSION} [skip ci]"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
git tag "v${VERSION}"
|
|
106
|
+
git push --atomic origin "HEAD:refs/heads/${BRANCH}" "refs/tags/v${VERSION}"
|
|
107
|
+
|
|
108
|
+
- name: Build
|
|
109
|
+
run: pnpm build
|
|
110
|
+
|
|
111
|
+
- name: Publish to npm
|
|
112
|
+
env:
|
|
113
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
114
|
+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
115
|
+
HUSKY: "0"
|
|
116
|
+
run: |
|
|
117
|
+
if [ -z "$NPM_TOKEN" ]; then
|
|
118
|
+
echo "⚠️ NPM_TOKEN not set — skipping publish"
|
|
119
|
+
exit 0
|
|
120
|
+
fi
|
|
121
|
+
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
|
122
|
+
npm publish --access public --tag ${{ steps.context.outputs.npm_tag }} || echo "Publish failed — version may already exist"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pnpm lint
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "node-pty@1.1.0": true }
|