@dfosco/storyboard 0.5.0-alpha.0
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/commandpalette.config.json +152 -0
- package/dist/storyboard-ui.css +1 -0
- package/dist/storyboard-ui.js +21328 -0
- package/dist/storyboard-ui.js.map +1 -0
- package/dist/tailwind.css +2 -0
- package/dist/tiny-canvas.css +1 -0
- package/dist/tiny-canvas.js +389 -0
- package/package.json +121 -0
- package/paste.config.json +67 -0
- package/scaffold/AGENTS.md +432 -0
- package/scaffold/agents/prompt-agent.agent.md +181 -0
- package/scaffold/agents/terminal-agent.agent.md +351 -0
- package/scaffold/codex/config.toml +246 -0
- package/scaffold/deploy.yml +103 -0
- package/scaffold/githooks/pre-push +114 -0
- package/scaffold/gitignore +64 -0
- package/scaffold/manifest.json +56 -0
- package/scaffold/preview.yml +181 -0
- package/scaffold/scripts/link.sh +26 -0
- package/scaffold/scripts/unlink.sh +10 -0
- package/scaffold/skills/agent-browser/SKILL.md +260 -0
- package/scaffold/skills/canvas/SKILL.md +364 -0
- package/scaffold/skills/create/SKILL.md +501 -0
- package/scaffold/skills/ship/SKILL.md +237 -0
- package/scaffold/skills/storyboard/SKILL.md +360 -0
- package/scaffold/skills/update-storyboard/SKILL.md +16 -0
- package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
- package/scaffold/skills/vitest/GENERATION.md +5 -0
- package/scaffold/skills/vitest/SKILL.md +52 -0
- package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
- package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
- package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
- package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
- package/scaffold/skills/vitest/references/core-cli.md +166 -0
- package/scaffold/skills/vitest/references/core-config.md +174 -0
- package/scaffold/skills/vitest/references/core-describe.md +193 -0
- package/scaffold/skills/vitest/references/core-expect.md +219 -0
- package/scaffold/skills/vitest/references/core-hooks.md +244 -0
- package/scaffold/skills/vitest/references/core-test-api.md +233 -0
- package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
- package/scaffold/skills/vitest/references/features-context.md +238 -0
- package/scaffold/skills/vitest/references/features-coverage.md +207 -0
- package/scaffold/skills/vitest/references/features-filtering.md +211 -0
- package/scaffold/skills/vitest/references/features-mocking.md +265 -0
- package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
- package/scaffold/skills/worktree/SKILL.md +93 -0
- package/scaffold/storyboard.config.json +44 -0
- package/src/canvas/Canvas.jsx +78 -0
- package/src/canvas/Draggable.jsx +235 -0
- package/src/canvas/index.d.ts +41 -0
- package/src/canvas/index.js +6 -0
- package/src/canvas/style.css +118 -0
- package/src/canvas/useResetCanvas.js +17 -0
- package/src/canvas/utils.js +136 -0
- package/src/core/assets/fonts/IoskeleyMono-Bold.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Italic.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Medium.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Regular.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-SemiBold.woff2 +0 -0
- package/src/core/autosync/server.js +714 -0
- package/src/core/autosync/server.test.js +158 -0
- package/src/core/canvas/__tests__/agent-integration.test.js +596 -0
- package/src/core/canvas/__tests__/helpers/browser.js +95 -0
- package/src/core/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/core/canvas/__tests__/helpers/perf.js +118 -0
- package/src/core/canvas/__tests__/helpers/setup.js +176 -0
- package/src/core/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/core/canvas/__tests__/helpers/transcript.js +132 -0
- package/src/core/canvas/__tests__/terminal-integration.test.js +177 -0
- package/src/core/canvas/collision.js +292 -0
- package/src/core/canvas/collision.test.js +371 -0
- package/src/core/canvas/compact.js +83 -0
- package/src/core/canvas/deriveCanvasId.test.js +40 -0
- package/src/core/canvas/githubEmbeds.js +527 -0
- package/src/core/canvas/githubEmbeds.test.js +302 -0
- package/src/core/canvas/hot-pool.js +766 -0
- package/src/core/canvas/identity.js +107 -0
- package/src/core/canvas/identity.test.js +100 -0
- package/src/core/canvas/materializer.js +259 -0
- package/src/core/canvas/materializer.test.js +356 -0
- package/src/core/canvas/selectedWidgets.js +270 -0
- package/src/core/canvas/selectedWidgets.test.js +321 -0
- package/src/core/canvas/server.js +3134 -0
- package/src/core/canvas/server.test.js +379 -0
- package/src/core/canvas/terminal-config.js +330 -0
- package/src/core/canvas/terminal-registry.js +465 -0
- package/src/core/canvas/terminal-server.js +1436 -0
- package/src/core/canvas/writeGuard.js +53 -0
- package/src/core/cli/agent.js +85 -0
- package/src/core/cli/branch.js +386 -0
- package/src/core/cli/canvasAdd.js +241 -0
- package/src/core/cli/canvasBatch.js +98 -0
- package/src/core/cli/canvasBounds.js +160 -0
- package/src/core/cli/canvasRead.js +236 -0
- package/src/core/cli/canvasUpdate.js +179 -0
- package/src/core/cli/code.js +67 -0
- package/src/core/cli/compact.js +62 -0
- package/src/core/cli/create.js +674 -0
- package/src/core/cli/dev-helpers.js +53 -0
- package/src/core/cli/dev-helpers.test.js +53 -0
- package/src/core/cli/dev.js +430 -0
- package/src/core/cli/exit.js +38 -0
- package/src/core/cli/flags.js +174 -0
- package/src/core/cli/flags.test.js +155 -0
- package/src/core/cli/index.js +233 -0
- package/src/core/cli/intro.js +37 -0
- package/src/core/cli/proxy.js +319 -0
- package/src/core/cli/proxy.test.js +63 -0
- package/src/core/cli/schemas.js +223 -0
- package/src/core/cli/server.js +192 -0
- package/src/core/cli/serverUrl.js +61 -0
- package/src/core/cli/sessions.js +459 -0
- package/src/core/cli/setup.js +404 -0
- package/src/core/cli/terminal-commands.js +287 -0
- package/src/core/cli/terminal-messaging.js +231 -0
- package/src/core/cli/terminal-welcome.js +515 -0
- package/src/core/cli/updateVersion.js +124 -0
- package/src/core/comments/api.js +284 -0
- package/src/core/comments/api.test.js +282 -0
- package/src/core/comments/auth.js +151 -0
- package/src/core/comments/auth.test.js +167 -0
- package/src/core/comments/commentCache.js +109 -0
- package/src/core/comments/commentCache.test.js +48 -0
- package/src/core/comments/commentDrafts.js +68 -0
- package/src/core/comments/commentMode.js +63 -0
- package/src/core/comments/commentMode.test.js +90 -0
- package/src/core/comments/config.js +47 -0
- package/src/core/comments/config.test.js +77 -0
- package/src/core/comments/graphql.js +65 -0
- package/src/core/comments/graphql.test.js +95 -0
- package/src/core/comments/index.js +42 -0
- package/src/core/comments/metadata.js +52 -0
- package/src/core/comments/metadata.test.js +110 -0
- package/src/core/comments/queries.js +245 -0
- package/src/core/comments/ui/AuthModal.jsx +114 -0
- package/src/core/comments/ui/CommentOverlay.js +52 -0
- package/src/core/comments/ui/CommentWindow.jsx +329 -0
- package/src/core/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/core/comments/ui/Composer.jsx +64 -0
- package/src/core/comments/ui/authModal.js +66 -0
- package/src/core/comments/ui/authModal.test.js +76 -0
- package/src/core/comments/ui/comment-cursor-dark.svg +1 -0
- package/src/core/comments/ui/comment-cursor.svg +1 -0
- package/src/core/comments/ui/comment-layout.css +142 -0
- package/src/core/comments/ui/commentWindow.js +121 -0
- package/src/core/comments/ui/comments.css +242 -0
- package/src/core/comments/ui/commentsDrawer.js +84 -0
- package/src/core/comments/ui/composer.js +136 -0
- package/src/core/comments/ui/index.js +14 -0
- package/src/core/comments/ui/mount.js +687 -0
- package/src/core/comments/ui/mount.test.js +336 -0
- package/src/core/data/dotPath.js +53 -0
- package/src/core/data/dotPath.test.js +114 -0
- package/src/core/data/loader.js +409 -0
- package/src/core/data/loader.test.js +599 -0
- package/src/core/data/viewfinder.js +363 -0
- package/src/core/data/viewfinder.test.js +456 -0
- package/src/core/devtools/devtools-consumer.js +28 -0
- package/src/core/devtools/devtools.js +144 -0
- package/src/core/devtools/devtools.test.js +75 -0
- package/src/core/devtools/sceneDebug.js +112 -0
- package/src/core/devtools/sceneDebug.test.js +141 -0
- package/src/core/index.js +124 -0
- package/src/core/inspector/fiberWalker.js +239 -0
- package/src/core/inspector/highlighter.js +275 -0
- package/src/core/inspector/mouseMode.js +259 -0
- package/src/core/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert.jsx +25 -0
- package/src/core/lib/components/ui/alert/index.js +17 -0
- package/src/core/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/core/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/core/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/core/lib/components/ui/avatar/index.js +22 -0
- package/src/core/lib/components/ui/badge/badge.jsx +31 -0
- package/src/core/lib/components/ui/badge/index.js +2 -0
- package/src/core/lib/components/ui/button/button.jsx +100 -0
- package/src/core/lib/components/ui/button/index.js +12 -0
- package/src/core/lib/components/ui/card/card-action.jsx +11 -0
- package/src/core/lib/components/ui/card/card-content.jsx +11 -0
- package/src/core/lib/components/ui/card/card-description.jsx +11 -0
- package/src/core/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/core/lib/components/ui/card/card-header.jsx +19 -0
- package/src/core/lib/components/ui/card/card-title.jsx +11 -0
- package/src/core/lib/components/ui/card/card.jsx +17 -0
- package/src/core/lib/components/ui/card/index.js +25 -0
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/core/lib/components/ui/checkbox/index.js +6 -0
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/index.js +13 -0
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/core/lib/components/ui/dialog/index.js +34 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/index.js +54 -0
- package/src/core/lib/components/ui/input/index.js +7 -0
- package/src/core/lib/components/ui/input/input.jsx +19 -0
- package/src/core/lib/components/ui/label/index.js +7 -0
- package/src/core/lib/components/ui/label/label.jsx +19 -0
- package/src/core/lib/components/ui/panel/index.js +24 -0
- package/src/core/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/core/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/core/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/core/lib/components/ui/panel/panel.jsx +4 -0
- package/src/core/lib/components/ui/popover/index.js +28 -0
- package/src/core/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/core/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/core/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/core/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/core/lib/components/ui/popover/popover.jsx +4 -0
- package/src/core/lib/components/ui/searchable-list.jsx +160 -0
- package/src/core/lib/components/ui/select/index.js +37 -0
- package/src/core/lib/components/ui/select/select-content.jsx +30 -0
- package/src/core/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/core/lib/components/ui/select/select-group.jsx +15 -0
- package/src/core/lib/components/ui/select/select-item.jsx +26 -0
- package/src/core/lib/components/ui/select/select-label.jsx +11 -0
- package/src/core/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/core/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/core/lib/components/ui/select/select.jsx +4 -0
- package/src/core/lib/components/ui/separator/index.js +7 -0
- package/src/core/lib/components/ui/separator/separator.jsx +22 -0
- package/src/core/lib/components/ui/sheet/index.js +34 -0
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/core/lib/components/ui/textarea/index.js +7 -0
- package/src/core/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/core/lib/components/ui/toggle/index.js +8 -0
- package/src/core/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/core/lib/components/ui/toggle-group/index.js +10 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/core/lib/components/ui/tooltip/index.js +3 -0
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/core/lib/components/ui/trigger-button/index.js +6 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/core/lib/utils/index.js +6 -0
- package/src/core/logger/devLogger.js +238 -0
- package/src/core/logger/devLogger.test.js +193 -0
- package/src/core/modes/modes.css +98 -0
- package/src/core/modes/modes.js +492 -0
- package/src/core/modes/modes.test.js +562 -0
- package/src/core/mountStoryboardCore.js +478 -0
- package/src/core/rename-watcher/config.json +23 -0
- package/src/core/rename-watcher/watcher.js +531 -0
- package/src/core/scaffold.js +100 -0
- package/src/core/server/index.js +391 -0
- package/src/core/session/bodyClasses.js +128 -0
- package/src/core/session/bodyClasses.test.js +192 -0
- package/src/core/session/hashSubscribe.js +19 -0
- package/src/core/session/hashSubscribe.test.js +62 -0
- package/src/core/session/hideMode.js +424 -0
- package/src/core/session/hideMode.test.js +268 -0
- package/src/core/session/interceptHideParams.js +35 -0
- package/src/core/session/interceptHideParams.test.js +90 -0
- package/src/core/session/localStorage.js +134 -0
- package/src/core/session/localStorage.test.js +148 -0
- package/src/core/session/session.js +76 -0
- package/src/core/session/session.test.js +91 -0
- package/src/core/stores/canvasConfig.js +134 -0
- package/src/core/stores/canvasConfig.test.js +120 -0
- package/src/core/stores/commandActions.js +284 -0
- package/src/core/stores/commandPaletteConfig.js +31 -0
- package/src/core/stores/configSchema.js +232 -0
- package/src/core/stores/configSchema.test.js +72 -0
- package/src/core/stores/configStore.js +161 -0
- package/src/core/stores/customerModeConfig.js +30 -0
- package/src/core/stores/featureFlags.js +127 -0
- package/src/core/stores/paletteProviders.js +360 -0
- package/src/core/stores/paletteProviders.test.js +186 -0
- package/src/core/stores/plugins.js +40 -0
- package/src/core/stores/plugins.test.js +68 -0
- package/src/core/stores/recentArtifacts.js +68 -0
- package/src/core/stores/recentArtifacts.test.js +71 -0
- package/src/core/stores/sidePanelStore.ts +143 -0
- package/src/core/stores/themeStore.ts +291 -0
- package/src/core/stores/toolRegistry.js +227 -0
- package/src/core/stores/toolStateStore.js +183 -0
- package/src/core/stores/toolStateStore.test.js +220 -0
- package/src/core/stores/toolbarConfigStore.js +165 -0
- package/src/core/stores/uiConfig.js +64 -0
- package/src/core/stores/uiConfig.test.js +63 -0
- package/src/core/styles/tailwind.css +204 -0
- package/src/core/tools/handlers/autosync.js +12 -0
- package/src/core/tools/handlers/canvasAddWidget.js +11 -0
- package/src/core/tools/handlers/canvasAgents.js +20 -0
- package/src/core/tools/handlers/canvasToolbar.js +56 -0
- package/src/core/tools/handlers/commandPalette.js +9 -0
- package/src/core/tools/handlers/comments.js +16 -0
- package/src/core/tools/handlers/create.js +39 -0
- package/src/core/tools/handlers/devtools.js +122 -0
- package/src/core/tools/handlers/devtools.test.js +87 -0
- package/src/core/tools/handlers/featureFlags.js +21 -0
- package/src/core/tools/handlers/flows.js +68 -0
- package/src/core/tools/handlers/hideChrome.js +9 -0
- package/src/core/tools/handlers/hideToolbars.js +25 -0
- package/src/core/tools/handlers/inspector.js +19 -0
- package/src/core/tools/handlers/paletteTheme.js +35 -0
- package/src/core/tools/handlers/theme.js +9 -0
- package/src/core/tools/registry.js +26 -0
- package/src/core/tools/surfaces/canvasToolbar.js +10 -0
- package/src/core/tools/surfaces/commandList.js +10 -0
- package/src/core/tools/surfaces/mainToolbar.js +11 -0
- package/src/core/tools/surfaces/registry.js +19 -0
- package/src/core/ui/ActionMenuButton.jsx +114 -0
- package/src/core/ui/AutosyncMenuButton.css +67 -0
- package/src/core/ui/AutosyncMenuButton.jsx +242 -0
- package/src/core/ui/BranchSelect.jsx +29 -0
- package/src/core/ui/BranchSelect.module.css +30 -0
- package/src/core/ui/CanvasAgentsMenu.jsx +89 -0
- package/src/core/ui/CanvasCreateMenu.jsx +611 -0
- package/src/core/ui/CanvasSnap.css +27 -0
- package/src/core/ui/CanvasSnap.jsx +51 -0
- package/src/core/ui/CanvasUndoRedo.css +36 -0
- package/src/core/ui/CanvasUndoRedo.jsx +62 -0
- package/src/core/ui/CanvasZoomControl.css +53 -0
- package/src/core/ui/CanvasZoomControl.jsx +49 -0
- package/src/core/ui/CanvasZoomToFit.css +18 -0
- package/src/core/ui/CanvasZoomToFit.jsx +26 -0
- package/src/core/ui/CommandMenu.css +8 -0
- package/src/core/ui/CommandMenu.jsx +287 -0
- package/src/core/ui/CommandPalette.jsx +35 -0
- package/src/core/ui/CommandPaletteTrigger.jsx +25 -0
- package/src/core/ui/CommentsMenuButton.jsx +40 -0
- package/src/core/ui/CoreUIBar.css +47 -0
- package/src/core/ui/CoreUIBar.jsx +905 -0
- package/src/core/ui/CreateMenuButton.jsx +117 -0
- package/src/core/ui/HideChromeTrigger.jsx +48 -0
- package/src/core/ui/Icon.jsx +279 -0
- package/src/core/ui/InspectorPanel.css +109 -0
- package/src/core/ui/InspectorPanel.jsx +632 -0
- package/src/core/ui/PwaInstallBanner.css +42 -0
- package/src/core/ui/PwaInstallBanner.jsx +124 -0
- package/src/core/ui/SidePanel.jsx +261 -0
- package/src/core/ui/ThemeMenuButton.jsx +139 -0
- package/src/core/ui/core-ui-colors.css +129 -0
- package/src/core/ui/design-modes.ts +7 -0
- package/src/core/ui/sidepanel.css +301 -0
- package/src/core/ui/viewfinder.ts +7 -0
- package/src/core/ui-entry.js +30 -0
- package/src/core/utils/fuzzySearch.js +117 -0
- package/src/core/utils/fuzzySearch.test.js +119 -0
- package/src/core/utils/mobileViewport.js +57 -0
- package/src/core/utils/mobileViewport.test.js +68 -0
- package/src/core/utils/prodMode.js +38 -0
- package/src/core/utils/smoothCorners.js +20 -0
- package/src/core/vite/docs-handler.js +155 -0
- package/src/core/vite/server-plugin.js +797 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/core/workshop/features/createCanvas/index.js +14 -0
- package/src/core/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/core/workshop/features/createFlow/index.js +19 -0
- package/src/core/workshop/features/createFlow/server.js +663 -0
- package/src/core/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/core/workshop/features/createPage/index.js +11 -0
- package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/core/workshop/features/createPrototype/index.js +19 -0
- package/src/core/workshop/features/createPrototype/server.js +433 -0
- package/src/core/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/core/workshop/features/createStory/index.js +14 -0
- package/src/core/workshop/features/registry-server.js +22 -0
- package/src/core/workshop/features/registry.js +28 -0
- package/src/core/workshop/features/templateIndex.js +155 -0
- package/src/core/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/core/workshop/ui/mount.ts +6 -0
- package/src/core/worktree/port.js +268 -0
- package/src/core/worktree/port.test.js +222 -0
- package/src/core/worktree/serverRegistry.js +120 -0
- package/src/internals/AuthModal/AuthModal.jsx +132 -0
- package/src/internals/AuthModal/AuthModal.module.css +221 -0
- package/src/internals/BranchBar/BranchBar.jsx +87 -0
- package/src/internals/BranchBar/BranchBar.module.css +247 -0
- package/src/internals/BranchBar/useBranches.js +93 -0
- package/src/internals/BranchBar/useBranches.test.js +68 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +1361 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +219 -0
- package/src/internals/CommandPalette/command-palette.css +180 -0
- package/src/internals/FlowError.module.css +30 -0
- package/src/internals/Icon.jsx +279 -0
- package/src/internals/StoryboardContext.js +3 -0
- package/src/internals/Viewfinder.jsx +1479 -0
- package/src/internals/Viewfinder.module.css +1540 -0
- package/src/internals/Workspace.jsx +7 -0
- package/src/internals/__mocks__/virtual-storyboard-data-index.js +4 -0
- package/src/internals/canvas/CanvasControls.jsx +112 -0
- package/src/internals/canvas/CanvasControls.module.css +135 -0
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +387 -0
- package/src/internals/canvas/CanvasPage.dragdrop.test.jsx +350 -0
- package/src/internals/canvas/CanvasPage.jsx +3092 -0
- package/src/internals/canvas/CanvasPage.module.css +187 -0
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +358 -0
- package/src/internals/canvas/CanvasToolbar.jsx +73 -0
- package/src/internals/canvas/CanvasToolbar.module.css +92 -0
- package/src/internals/canvas/ComponentErrorBoundary.jsx +50 -0
- package/src/internals/canvas/ConnectorLayer.jsx +208 -0
- package/src/internals/canvas/ConnectorLayer.module.css +129 -0
- package/src/internals/canvas/MarqueeOverlay.jsx +20 -0
- package/src/internals/canvas/PageSelector.jsx +587 -0
- package/src/internals/canvas/PageSelector.module.css +261 -0
- package/src/internals/canvas/PageSelector.test.jsx +113 -0
- package/src/internals/canvas/WebGLContextPool.jsx +292 -0
- package/src/internals/canvas/WebGLContextPool.test.jsx +165 -0
- package/src/internals/canvas/canvasApi.js +164 -0
- package/src/internals/canvas/canvasReloadGuard.js +37 -0
- package/src/internals/canvas/canvasReloadGuard.test.js +27 -0
- package/src/internals/canvas/canvasTheme.js +118 -0
- package/src/internals/canvas/componentIsolate.jsx +165 -0
- package/src/internals/canvas/componentSetIsolate.jsx +257 -0
- package/src/internals/canvas/computeCanvasBounds.test.js +121 -0
- package/src/internals/canvas/connectorGeometry.js +132 -0
- package/src/internals/canvas/hotPoolDevLogs.js +25 -0
- package/src/internals/canvas/textSelection.js +10 -0
- package/src/internals/canvas/textSelection.test.js +26 -0
- package/src/internals/canvas/useCanvas.js +126 -0
- package/src/internals/canvas/useCanvas.test.js +26 -0
- package/src/internals/canvas/useMarqueeSelect.js +213 -0
- package/src/internals/canvas/useMarqueeSelect.test.js +78 -0
- package/src/internals/canvas/useUndoRedo.js +86 -0
- package/src/internals/canvas/useUndoRedo.test.js +231 -0
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +293 -0
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +161 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.jsx +2 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/ComponentWidget.jsx +14 -0
- package/src/internals/canvas/widgets/ComponentWidget.module.css +0 -0
- package/src/internals/canvas/widgets/CropOverlay.jsx +179 -0
- package/src/internals/canvas/widgets/CropOverlay.module.css +154 -0
- package/src/internals/canvas/widgets/ExpandedPane.jsx +474 -0
- package/src/internals/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/internals/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +296 -0
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +222 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +151 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +83 -0
- package/src/internals/canvas/widgets/ImageWidget.jsx +287 -0
- package/src/internals/canvas/widgets/ImageWidget.module.css +81 -0
- package/src/internals/canvas/widgets/LinkPreview.jsx +439 -0
- package/src/internals/canvas/widgets/LinkPreview.module.css +585 -0
- package/src/internals/canvas/widgets/LinkPreview.test.jsx +193 -0
- package/src/internals/canvas/widgets/MarkdownBlock.jsx +354 -0
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +377 -0
- package/src/internals/canvas/widgets/MarkdownBlock.test.jsx +92 -0
- package/src/internals/canvas/widgets/PromptWidget.jsx +428 -0
- package/src/internals/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +463 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +579 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +10 -0
- package/src/internals/canvas/widgets/ResizeHandle.jsx +67 -0
- package/src/internals/canvas/widgets/ResizeHandle.module.css +29 -0
- package/src/internals/canvas/widgets/StickyNote.jsx +92 -0
- package/src/internals/canvas/widgets/StickyNote.module.css +70 -0
- package/src/internals/canvas/widgets/StickyNote.test.jsx +116 -0
- package/src/internals/canvas/widgets/StorySetWidget.jsx +208 -0
- package/src/internals/canvas/widgets/StorySetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/StoryWidget.jsx +334 -0
- package/src/internals/canvas/widgets/StoryWidget.module.css +211 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/internals/canvas/widgets/TerminalWidget.jsx +704 -0
- package/src/internals/canvas/widgets/TerminalWidget.module.css +444 -0
- package/src/internals/canvas/widgets/TilesWidget.jsx +300 -0
- package/src/internals/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/internals/canvas/widgets/WidgetChrome.jsx +580 -0
- package/src/internals/canvas/widgets/WidgetChrome.module.css +421 -0
- package/src/internals/canvas/widgets/WidgetWrapper.jsx +15 -0
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +25 -0
- package/src/internals/canvas/widgets/codepenUrl.js +75 -0
- package/src/internals/canvas/widgets/codepenUrl.test.js +76 -0
- package/src/internals/canvas/widgets/embedInteraction.test.jsx +173 -0
- package/src/internals/canvas/widgets/embedOverlay.module.css +35 -0
- package/src/internals/canvas/widgets/embedTheme.js +148 -0
- package/src/internals/canvas/widgets/expandUtils.js +559 -0
- package/src/internals/canvas/widgets/expandUtils.test.js +155 -0
- package/src/internals/canvas/widgets/figmaUrl.js +118 -0
- package/src/internals/canvas/widgets/figmaUrl.test.js +139 -0
- package/src/internals/canvas/widgets/githubUrl.js +82 -0
- package/src/internals/canvas/widgets/githubUrl.test.js +74 -0
- package/src/internals/canvas/widgets/iframeDevLogs.js +49 -0
- package/src/internals/canvas/widgets/iframeDevLogs.test.jsx +81 -0
- package/src/internals/canvas/widgets/index.js +42 -0
- package/src/internals/canvas/widgets/pasteRules.js +295 -0
- package/src/internals/canvas/widgets/pasteRules.test.js +474 -0
- package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +211 -0
- package/src/internals/canvas/widgets/tilePool.js +23 -0
- package/src/internals/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/leaf.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/internals/canvas/widgets/widgetConfig.js +291 -0
- package/src/internals/canvas/widgets/widgetConfig.test.js +68 -0
- package/src/internals/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/internals/canvas/widgets/widgetProps.js +133 -0
- package/src/internals/context/FormContext.js +13 -0
- package/src/internals/context/FormContext.test.js +48 -0
- package/src/internals/context.jsx +481 -0
- package/src/internals/context.test.jsx +296 -0
- package/src/internals/hashPreserver.js +73 -0
- package/src/internals/hashPreserver.test.js +107 -0
- package/src/internals/hooks/useConfig.js +14 -0
- package/src/internals/hooks/useFeatureFlag.js +14 -0
- package/src/internals/hooks/useFlows.js +50 -0
- package/src/internals/hooks/useFlows.test.js +134 -0
- package/src/internals/hooks/useHideMode.js +31 -0
- package/src/internals/hooks/useHideMode.test.js +43 -0
- package/src/internals/hooks/useLocalStorage.js +57 -0
- package/src/internals/hooks/useLocalStorage.test.js +75 -0
- package/src/internals/hooks/useMode.js +43 -0
- package/src/internals/hooks/useObject.js +101 -0
- package/src/internals/hooks/useObject.test.js +74 -0
- package/src/internals/hooks/useOverride.js +84 -0
- package/src/internals/hooks/useOverride.test.js +71 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/internals/hooks/useRecord.js +158 -0
- package/src/internals/hooks/useRecord.test.js +221 -0
- package/src/internals/hooks/useScene.js +38 -0
- package/src/internals/hooks/useScene.test.js +66 -0
- package/src/internals/hooks/useSceneData.js +108 -0
- package/src/internals/hooks/useSceneData.test.js +136 -0
- package/src/internals/hooks/useSession.js +4 -0
- package/src/internals/hooks/useSession.test.js +8 -0
- package/src/internals/hooks/useThemeState.js +61 -0
- package/src/internals/hooks/useThemeState.test.js +66 -0
- package/src/internals/hooks/useUndoRedo.js +28 -0
- package/src/internals/hooks/useUndoRedo.test.js +64 -0
- package/src/internals/index.js +58 -0
- package/src/internals/story/ComponentSetPage.jsx +198 -0
- package/src/internals/story/ComponentSetPage.module.css +129 -0
- package/src/internals/story/StoryPage.jsx +147 -0
- package/src/internals/story/StoryPage.module.css +18 -0
- package/src/internals/test-utils.js +45 -0
- package/src/internals/vite/data-plugin.js +1508 -0
- package/src/internals/vite/data-plugin.test.js +1223 -0
- package/src/test-utils.js +44 -0
- package/toolbar.config.json +271 -0
- package/widgets.config.json +1537 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Widget — Shell Session Integration Tests (Group 1)
|
|
3
|
+
*
|
|
4
|
+
* Tests the core terminal widget lifecycle:
|
|
5
|
+
* - Widget creation via canvas API
|
|
6
|
+
* - tmux session startup
|
|
7
|
+
* - Welcome menu rendering
|
|
8
|
+
* - Shell session selection and basic command execution
|
|
9
|
+
* - Browser rendering verification
|
|
10
|
+
* - Session list API
|
|
11
|
+
*
|
|
12
|
+
* Prerequisites: dev server running, tmux installed, agent-browser installed.
|
|
13
|
+
* Run with: npm run test:integration
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
17
|
+
import * as canvasApi from './helpers/canvas-api.js'
|
|
18
|
+
import * as tmux from './helpers/tmux.js'
|
|
19
|
+
import * as browser from './helpers/browser.js'
|
|
20
|
+
import * as transcript from './helpers/transcript.js'
|
|
21
|
+
import * as perf from './helpers/perf.js'
|
|
22
|
+
import { preflight, createTestCanvas, deleteTestCanvas, writeResults } from './helpers/setup.js'
|
|
23
|
+
|
|
24
|
+
const CANVAS_NAME = '__test__-terminal'
|
|
25
|
+
const BROWSER_SESSION = 'test-terminal'
|
|
26
|
+
|
|
27
|
+
let serverUrl
|
|
28
|
+
let terminalWidgetId
|
|
29
|
+
let tmuxSessionName
|
|
30
|
+
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
const { url } = await preflight()
|
|
33
|
+
serverUrl = url
|
|
34
|
+
createTestCanvas(CANVAS_NAME)
|
|
35
|
+
|
|
36
|
+
// Give the dev server a moment to pick up the new canvas file
|
|
37
|
+
await new Promise((r) => setTimeout(r, 2000))
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
afterAll(() => {
|
|
41
|
+
// Flush transcripts
|
|
42
|
+
const paths = transcript.flushAll()
|
|
43
|
+
|
|
44
|
+
// Write results
|
|
45
|
+
writeResults(perf.toJSON(), paths)
|
|
46
|
+
perf.report()
|
|
47
|
+
|
|
48
|
+
// Cleanup: kill test tmux sessions
|
|
49
|
+
if (tmuxSessionName) tmux.killSession(tmuxSessionName)
|
|
50
|
+
|
|
51
|
+
// Cleanup: close browser
|
|
52
|
+
browser.close(BROWSER_SESSION)
|
|
53
|
+
|
|
54
|
+
// Cleanup: delete test canvas
|
|
55
|
+
deleteTestCanvas(CANVAS_NAME)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('Group 1: Terminal Widget — Shell Session', () => {
|
|
59
|
+
it('T1.1 — Create terminal widget via API', async () => {
|
|
60
|
+
const result = await canvasApi.createWidget(CANVAS_NAME, 'terminal', {}, { x: 100, y: 100 })
|
|
61
|
+
|
|
62
|
+
expect(result.success).toBe(true)
|
|
63
|
+
expect(result.widget).toBeDefined()
|
|
64
|
+
expect(result.widget.type).toBe('terminal')
|
|
65
|
+
expect(result.widget.id).toBeTruthy()
|
|
66
|
+
// Terminal widgets should get an auto-generated prettyName
|
|
67
|
+
expect(result.widget.props?.prettyName).toBeTruthy()
|
|
68
|
+
|
|
69
|
+
terminalWidgetId = result.widget.id
|
|
70
|
+
|
|
71
|
+
// Verify it appears in canvas read
|
|
72
|
+
const canvas = await canvasApi.readCanvas(CANVAS_NAME)
|
|
73
|
+
const widget = canvas.widgets?.find((w) => w.id === terminalWidgetId)
|
|
74
|
+
expect(widget).toBeDefined()
|
|
75
|
+
expect(widget.type).toBe('terminal')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('T1.2 — Terminal session starts in tmux', async () => {
|
|
79
|
+
// Open the canvas in the browser
|
|
80
|
+
const canvasUrl = `${serverUrl}/storyboard/canvas/${CANVAS_NAME}`
|
|
81
|
+
browser.open(BROWSER_SESSION, canvasUrl)
|
|
82
|
+
browser.waitForLoad(BROWSER_SESSION, 'networkidle')
|
|
83
|
+
|
|
84
|
+
// Take a snapshot to find the terminal widget and click it
|
|
85
|
+
const _snap = browser.snapshot(BROWSER_SESSION, '-i')
|
|
86
|
+
void _snap
|
|
87
|
+
|
|
88
|
+
// The terminal widget should have a "Start" or "Continue" button/area
|
|
89
|
+
// Try clicking the terminal widget area to start the session
|
|
90
|
+
try {
|
|
91
|
+
browser.click(BROWSER_SESSION, `[data-widget-id="${terminalWidgetId}"]`)
|
|
92
|
+
} catch {
|
|
93
|
+
// If data-widget-id selector doesn't work, try clicking via snapshot refs
|
|
94
|
+
// The terminal widget may need a different interaction to start
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Wait for a tmux session to appear with the sb- prefix
|
|
98
|
+
try {
|
|
99
|
+
tmuxSessionName = await tmux.waitForSession(/^sb-/, 15000)
|
|
100
|
+
transcript.createTranscript(tmuxSessionName, { widgetId: terminalWidgetId, canvasName: CANVAS_NAME })
|
|
101
|
+
transcript.logEvent(tmuxSessionName, 'Session started')
|
|
102
|
+
} catch {
|
|
103
|
+
// Session may take longer if it's the first terminal
|
|
104
|
+
tmuxSessionName = await tmux.waitForSession(/^sb-/, 30000)
|
|
105
|
+
transcript.createTranscript(tmuxSessionName, { widgetId: terminalWidgetId, canvasName: CANVAS_NAME })
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
expect(tmuxSessionName).toBeTruthy()
|
|
109
|
+
expect(tmuxSessionName).toMatch(/^sb-/)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('T1.3 — Welcome menu appears', async () => {
|
|
113
|
+
if (!tmuxSessionName) return
|
|
114
|
+
|
|
115
|
+
// Wait for the welcome menu to render
|
|
116
|
+
const output = await tmux.waitForOutput(tmuxSessionName, /shell|choose|workload/i, 15000)
|
|
117
|
+
transcript.logSection(tmuxSessionName, 'T1.3')
|
|
118
|
+
|
|
119
|
+
expect(output).toMatch(/shell/i)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('T1.4 — Select Shell from welcome menu', async () => {
|
|
123
|
+
if (!tmuxSessionName) return
|
|
124
|
+
transcript.logSection(tmuxSessionName, 'T1.4')
|
|
125
|
+
|
|
126
|
+
// Navigate to Shell option and select it
|
|
127
|
+
// The welcome menu uses @clack/prompts — Shell is typically one of the options
|
|
128
|
+
// Send arrow keys to find Shell, then Enter to select
|
|
129
|
+
// Shell might be the last option before "Browse sessions"
|
|
130
|
+
tmux.sendKeys(tmuxSessionName, 'Down Down Enter')
|
|
131
|
+
|
|
132
|
+
// Wait for shell prompt ($ or % or > or similar)
|
|
133
|
+
await tmux.waitForOutput(tmuxSessionName, /\$|%|>|#/, 10000)
|
|
134
|
+
|
|
135
|
+
const output = tmux.capturePane(tmuxSessionName)
|
|
136
|
+
// Should no longer show the welcome menu, should show a shell prompt
|
|
137
|
+
expect(output).toBeTruthy()
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('T1.5 — Run basic shell command', async () => {
|
|
141
|
+
if (!tmuxSessionName) return
|
|
142
|
+
transcript.logSection(tmuxSessionName, 'T1.5')
|
|
143
|
+
|
|
144
|
+
// Send a command with a unique marker
|
|
145
|
+
tmux.sendText(tmuxSessionName, 'echo STORYBOARD_TEST_MARKER_12345')
|
|
146
|
+
tmux.sendKeys(tmuxSessionName, 'Enter')
|
|
147
|
+
|
|
148
|
+
// Wait for the marker to appear in output
|
|
149
|
+
const output = await tmux.waitForOutput(tmuxSessionName, /STORYBOARD_TEST_MARKER_12345/, 10000)
|
|
150
|
+
expect(output).toContain('STORYBOARD_TEST_MARKER_12345')
|
|
151
|
+
|
|
152
|
+
// Verify in the browser as well
|
|
153
|
+
try {
|
|
154
|
+
const _snap = browser.snapshot(BROWSER_SESSION)
|
|
155
|
+
void _snap
|
|
156
|
+
// The terminal output should be visible in the browser's terminal widget
|
|
157
|
+
// Note: ghostty-web rendering may not expose text in the accessibility tree
|
|
158
|
+
// This is a best-effort check
|
|
159
|
+
} catch {
|
|
160
|
+
// Browser verification is best-effort for terminal content
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('T1.6 — Terminal session appears in session list', async () => {
|
|
165
|
+
const sessions = await canvasApi.listTerminalSessions()
|
|
166
|
+
|
|
167
|
+
// Should have at least one session
|
|
168
|
+
expect(sessions).toBeDefined()
|
|
169
|
+
|
|
170
|
+
// The response format depends on the API — it might be an array or an object
|
|
171
|
+
if (Array.isArray(sessions)) {
|
|
172
|
+
expect(sessions.length).toBeGreaterThan(0)
|
|
173
|
+
} else if (typeof sessions === 'object') {
|
|
174
|
+
expect(Object.keys(sessions).length).toBeGreaterThan(0)
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
})
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Collision Detection — Find collision-free positions for widgets.
|
|
3
|
+
*
|
|
4
|
+
* When placing or moving widgets, this module checks for overlaps with
|
|
5
|
+
* existing widgets and adjusts the position until no collisions remain.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import widgetsConfig from '../../../widgets.config.json' with { type: 'json' }
|
|
9
|
+
|
|
10
|
+
const FALLBACK_SIZE = { width: 270, height: 170 }
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hardcoded fallbacks for widget types that don't specify defaults in config.
|
|
14
|
+
*/
|
|
15
|
+
const HARDCODED_DEFAULTS = {
|
|
16
|
+
'markdown': { width: 530, height: 240 },
|
|
17
|
+
'image': { width: 400, height: 300 },
|
|
18
|
+
'link-preview': { width: 320, height: 200 },
|
|
19
|
+
'component': { width: 300, height: 200 },
|
|
20
|
+
'story': { width: 780, height: 420 },
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default widget sizes derived from widgets.config.json prop defaults,
|
|
25
|
+
* with hardcoded fallbacks for types that don't specify both width+height.
|
|
26
|
+
*/
|
|
27
|
+
export const DEFAULT_SIZES = buildDefaultSizes()
|
|
28
|
+
|
|
29
|
+
function buildDefaultSizes() {
|
|
30
|
+
const sizes = {}
|
|
31
|
+
const widgets = widgetsConfig.widgets || {}
|
|
32
|
+
for (const [type, config] of Object.entries(widgets)) {
|
|
33
|
+
const props = config.props || {}
|
|
34
|
+
const hardcoded = HARDCODED_DEFAULTS[type]
|
|
35
|
+
const w = props.width?.default ?? hardcoded?.width ?? FALLBACK_SIZE.width
|
|
36
|
+
const h = props.height?.default ?? hardcoded?.height ?? FALLBACK_SIZE.height
|
|
37
|
+
sizes[type] = { width: w, height: h }
|
|
38
|
+
}
|
|
39
|
+
return sizes
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the default size for a widget type from widgets.config.json.
|
|
44
|
+
* @param {string} type - Widget type
|
|
45
|
+
* @returns {{ width: number, height: number }}
|
|
46
|
+
*/
|
|
47
|
+
export function getDefaultSize(type) {
|
|
48
|
+
return DEFAULT_SIZES[type] || FALLBACK_SIZE
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the bounding box of a widget.
|
|
53
|
+
* @param {object} widget - Widget with position and props
|
|
54
|
+
* @returns {{ x: number, y: number, width: number, height: number }}
|
|
55
|
+
*/
|
|
56
|
+
export function getWidgetBounds(widget) {
|
|
57
|
+
const { position = { x: 0, y: 0 }, props = {}, type } = widget
|
|
58
|
+
const defaults = getDefaultSize(type)
|
|
59
|
+
return {
|
|
60
|
+
x: position.x,
|
|
61
|
+
y: position.y,
|
|
62
|
+
width: props.width ?? defaults.width,
|
|
63
|
+
height: props.height ?? defaults.height,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compute persistent bounds metadata for a widget.
|
|
69
|
+
* Returns { width, height, startX, startY, endX, endY }.
|
|
70
|
+
* @param {object} widget - Widget with position, props, and type
|
|
71
|
+
* @returns {{ width: number, height: number, startX: number, startY: number, endX: number, endY: number }}
|
|
72
|
+
*/
|
|
73
|
+
export function computeWidgetBounds(widget) {
|
|
74
|
+
const { x, y, width, height } = getWidgetBounds(widget)
|
|
75
|
+
return {
|
|
76
|
+
width,
|
|
77
|
+
height,
|
|
78
|
+
startX: x,
|
|
79
|
+
startY: y,
|
|
80
|
+
endX: x + width,
|
|
81
|
+
endY: y + height,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Stamp bounds metadata onto a widget, returning a new widget object.
|
|
87
|
+
* @param {object} widget
|
|
88
|
+
* @returns {object} Widget with `bounds` field
|
|
89
|
+
*/
|
|
90
|
+
export function stampBounds(widget) {
|
|
91
|
+
return { ...widget, bounds: computeWidgetBounds(widget) }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Stamp bounds on every widget in an array.
|
|
96
|
+
* @param {object[]} widgets
|
|
97
|
+
* @returns {object[]}
|
|
98
|
+
*/
|
|
99
|
+
export function stampBoundsAll(widgets) {
|
|
100
|
+
return widgets.map(stampBounds)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if two rectangles overlap.
|
|
105
|
+
* @param {{ x: number, y: number, width: number, height: number }} a
|
|
106
|
+
* @param {{ x: number, y: number, width: number, height: number }} b
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
export function rectsOverlap(a, b) {
|
|
110
|
+
return !(
|
|
111
|
+
a.x + a.width <= b.x || // a is to the left of b
|
|
112
|
+
b.x + b.width <= a.x || // b is to the left of a
|
|
113
|
+
a.y + a.height <= b.y || // a is above b
|
|
114
|
+
b.y + b.height <= a.y // b is above a
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if a proposed position collides with any existing widget.
|
|
120
|
+
* @param {{ x: number, y: number, width: number, height: number }} rect - Proposed bounds
|
|
121
|
+
* @param {object[]} widgets - Existing widgets array
|
|
122
|
+
* @param {string} [excludeId] - Widget ID to exclude (for move operations)
|
|
123
|
+
* @returns {object[]} - All colliding widgets (empty array if none)
|
|
124
|
+
*/
|
|
125
|
+
export function findCollisions(rect, widgets, excludeId = null) {
|
|
126
|
+
const colliders = []
|
|
127
|
+
for (const widget of widgets) {
|
|
128
|
+
if (excludeId && widget.id === excludeId) continue
|
|
129
|
+
const bounds = getWidgetBounds(widget)
|
|
130
|
+
if (rectsOverlap(rect, bounds)) {
|
|
131
|
+
colliders.push(widget)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return colliders
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Check if a proposed position collides with any existing widget.
|
|
139
|
+
* Returns the first colliding widget (for backwards compatibility).
|
|
140
|
+
* @param {{ x: number, y: number, width: number, height: number }} rect - Proposed bounds
|
|
141
|
+
* @param {object[]} widgets - Existing widgets array
|
|
142
|
+
* @param {string} [excludeId] - Widget ID to exclude (for move operations)
|
|
143
|
+
* @returns {object|null} - The first colliding widget, or null if no collision
|
|
144
|
+
*/
|
|
145
|
+
export function findCollision(rect, widgets, excludeId = null) {
|
|
146
|
+
const colliders = findCollisions(rect, widgets, excludeId)
|
|
147
|
+
return colliders.length > 0 ? colliders[0] : null
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Snap a value to grid.
|
|
152
|
+
* @param {number} value
|
|
153
|
+
* @param {number} gridSize
|
|
154
|
+
* @returns {number}
|
|
155
|
+
*/
|
|
156
|
+
export function snapToGrid(value, gridSize) {
|
|
157
|
+
return Math.round(value / gridSize) * gridSize
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Find a collision-free position for a widget.
|
|
162
|
+
*
|
|
163
|
+
* Strategy:
|
|
164
|
+
* 1. Try the initial position
|
|
165
|
+
* 2. If collision, find the max endX among all colliders and move past it
|
|
166
|
+
* 3. Repeat until no collisions or maxIterations exhausted
|
|
167
|
+
* 4. If horizontal resolution exhausted, fall back to moving down
|
|
168
|
+
* 5. Snap final position to grid
|
|
169
|
+
*
|
|
170
|
+
* @param {object} options
|
|
171
|
+
* @param {number} options.x - Initial X position
|
|
172
|
+
* @param {number} options.y - Initial Y position
|
|
173
|
+
* @param {number} options.width - Widget width
|
|
174
|
+
* @param {number} options.height - Widget height
|
|
175
|
+
* @param {object[]} options.widgets - Existing widgets array
|
|
176
|
+
* @param {string} [options.excludeId] - Widget ID to exclude (for move operations)
|
|
177
|
+
* @param {number} [options.gridSize=24] - Grid size for snapping
|
|
178
|
+
* @param {number} [options.gap] - Gap between widgets (defaults to gridSize)
|
|
179
|
+
* @param {number} [options.maxIterations=50] - Max collision resolution attempts
|
|
180
|
+
* @returns {{ x: number, y: number, adjusted: boolean }}
|
|
181
|
+
*/
|
|
182
|
+
export function findFreePosition({
|
|
183
|
+
x,
|
|
184
|
+
y,
|
|
185
|
+
width,
|
|
186
|
+
height,
|
|
187
|
+
widgets,
|
|
188
|
+
excludeId = null,
|
|
189
|
+
gridSize = 24,
|
|
190
|
+
gap = null,
|
|
191
|
+
maxIterations = 50,
|
|
192
|
+
}) {
|
|
193
|
+
const spacing = gap ?? gridSize
|
|
194
|
+
let currentX = x
|
|
195
|
+
let currentY = y
|
|
196
|
+
let adjusted = false
|
|
197
|
+
|
|
198
|
+
// Phase 1: Try moving right past all colliders
|
|
199
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
200
|
+
const rect = { x: currentX, y: currentY, width, height }
|
|
201
|
+
const colliders = findCollisions(rect, widgets, excludeId)
|
|
202
|
+
|
|
203
|
+
if (colliders.length === 0) {
|
|
204
|
+
return {
|
|
205
|
+
x: snapToGrid(currentX, gridSize),
|
|
206
|
+
y: snapToGrid(currentY, gridSize),
|
|
207
|
+
adjusted,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Jump past the rightmost edge of all colliders
|
|
212
|
+
let maxEndX = 0
|
|
213
|
+
for (const c of colliders) {
|
|
214
|
+
const b = getWidgetBounds(c)
|
|
215
|
+
const endX = b.x + b.width
|
|
216
|
+
if (endX > maxEndX) maxEndX = endX
|
|
217
|
+
}
|
|
218
|
+
currentX = maxEndX + spacing
|
|
219
|
+
adjusted = true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Phase 2: Reset X, try moving down
|
|
223
|
+
currentX = x
|
|
224
|
+
|
|
225
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
226
|
+
const rect = { x: currentX, y: currentY, width, height }
|
|
227
|
+
const colliders = findCollisions(rect, widgets, excludeId)
|
|
228
|
+
|
|
229
|
+
if (colliders.length === 0) {
|
|
230
|
+
return {
|
|
231
|
+
x: snapToGrid(currentX, gridSize),
|
|
232
|
+
y: snapToGrid(currentY, gridSize),
|
|
233
|
+
adjusted,
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Jump past the bottommost edge of all colliders
|
|
238
|
+
let maxEndY = 0
|
|
239
|
+
for (const c of colliders) {
|
|
240
|
+
const b = getWidgetBounds(c)
|
|
241
|
+
const endY = b.y + b.height
|
|
242
|
+
if (endY > maxEndY) maxEndY = endY
|
|
243
|
+
}
|
|
244
|
+
currentY = maxEndY + spacing
|
|
245
|
+
adjusted = true
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Fallback: return the last attempted position (snapped)
|
|
249
|
+
return {
|
|
250
|
+
x: snapToGrid(currentX, gridSize),
|
|
251
|
+
y: snapToGrid(currentY, gridSize),
|
|
252
|
+
adjusted,
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Resolve collision for a widget being placed or moved.
|
|
258
|
+
* Convenience wrapper that extracts size from widget type/props.
|
|
259
|
+
*
|
|
260
|
+
* @param {object} options
|
|
261
|
+
* @param {number} options.x - Target X position
|
|
262
|
+
* @param {number} options.y - Target Y position
|
|
263
|
+
* @param {string} options.type - Widget type
|
|
264
|
+
* @param {object} [options.props={}] - Widget props (may contain width/height)
|
|
265
|
+
* @param {object[]} options.widgets - Existing widgets array
|
|
266
|
+
* @param {string} [options.excludeId] - Widget ID to exclude
|
|
267
|
+
* @param {number} [options.gridSize=24] - Grid size
|
|
268
|
+
* @returns {{ x: number, y: number, adjusted: boolean }}
|
|
269
|
+
*/
|
|
270
|
+
export function resolvePosition({
|
|
271
|
+
x,
|
|
272
|
+
y,
|
|
273
|
+
type,
|
|
274
|
+
props = {},
|
|
275
|
+
widgets,
|
|
276
|
+
excludeId = null,
|
|
277
|
+
gridSize = 24,
|
|
278
|
+
}) {
|
|
279
|
+
const defaults = getDefaultSize(type)
|
|
280
|
+
const width = props.width ?? defaults.width
|
|
281
|
+
const height = props.height ?? defaults.height
|
|
282
|
+
|
|
283
|
+
return findFreePosition({
|
|
284
|
+
x,
|
|
285
|
+
y,
|
|
286
|
+
width,
|
|
287
|
+
height,
|
|
288
|
+
widgets,
|
|
289
|
+
excludeId,
|
|
290
|
+
gridSize,
|
|
291
|
+
})
|
|
292
|
+
}
|