@dfosco/storyboard-core 4.2.0-beta.2 → 4.2.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commandpalette.config.json +109 -24
- package/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +17379 -28568
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +5 -2
- 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/manifest.json +5 -0
- package/scaffold/skills/canvas/SKILL.md +5 -4
- package/scaffold/skills/ship/SKILL.md +1 -1
- package/scaffold/storyboard.config.json +14 -1
- package/scaffold/toolbar.config.json +1 -1
- package/src/ActionMenuButton.jsx +100 -0
- package/src/AutosyncMenuButton.css +67 -0
- package/src/AutosyncMenuButton.jsx +241 -0
- package/src/BranchSelect.jsx +29 -0
- package/src/BranchSelect.module.css +30 -0
- package/src/CanvasAgentsMenu.jsx +87 -0
- package/src/CanvasCreateMenu.jsx +609 -0
- package/src/CanvasSnap.css +27 -0
- package/src/CanvasSnap.jsx +51 -0
- package/src/CanvasUndoRedo.css +36 -0
- package/src/CanvasUndoRedo.jsx +62 -0
- package/src/CanvasZoomControl.css +53 -0
- package/src/CanvasZoomControl.jsx +49 -0
- package/src/CanvasZoomToFit.css +18 -0
- package/src/CanvasZoomToFit.jsx +26 -0
- package/src/CommandMenu.css +8 -0
- package/src/CommandMenu.jsx +286 -0
- package/src/CommandPalette.jsx +35 -0
- package/src/CommandPaletteTrigger.jsx +25 -0
- package/src/CommentsMenuButton.jsx +38 -0
- package/src/CoreUIBar.css +47 -0
- package/src/CoreUIBar.jsx +855 -0
- package/src/CreateMenuButton.jsx +116 -0
- package/src/HideChromeTrigger.jsx +40 -0
- package/src/InspectorPanel.css +109 -0
- package/src/InspectorPanel.jsx +629 -0
- package/src/PwaInstallBanner.css +42 -0
- package/src/PwaInstallBanner.jsx +124 -0
- package/src/SidePanel.jsx +260 -0
- package/src/ThemeMenuButton.jsx +136 -0
- package/src/autosync/server.js +202 -5
- package/src/autosync/server.test.js +112 -0
- package/src/canvas/__tests__/agent-integration.test.js +593 -0
- package/src/canvas/__tests__/helpers/browser.js +95 -0
- package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/canvas/__tests__/helpers/perf.js +118 -0
- package/src/canvas/__tests__/helpers/setup.js +176 -0
- package/src/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/canvas/__tests__/helpers/transcript.js +129 -0
- package/src/canvas/__tests__/terminal-integration.test.js +175 -0
- package/src/canvas/hot-pool.js +757 -0
- package/src/canvas/materializer.js +31 -0
- package/src/canvas/materializer.test.js +56 -0
- package/src/canvas/selectedWidgets.js +65 -7
- package/src/canvas/server.js +1801 -22
- package/src/canvas/server.test.js +239 -0
- package/src/canvas/terminal-config.js +331 -0
- package/src/canvas/terminal-registry.js +38 -0
- package/src/canvas/terminal-server.js +1037 -29
- package/src/canvas/writeGuard.js +51 -3
- package/src/canvasConfig.js +67 -1
- package/src/canvasConfig.test.js +79 -1
- package/src/cli/agent.js +85 -0
- package/src/cli/branch.js +232 -0
- package/src/cli/canvasAdd.js +59 -12
- package/src/cli/canvasBatch.js +98 -0
- package/src/cli/canvasBounds.js +1 -1
- package/src/cli/canvasRead.js +1 -1
- package/src/cli/canvasUpdate.js +179 -0
- package/src/cli/create.js +38 -14
- package/src/cli/dev.js +157 -83
- package/src/cli/exit.js +23 -24
- package/src/cli/index.js +55 -2
- package/src/cli/proxy.js +96 -37
- package/src/cli/schemas.js +22 -4
- package/src/cli/server.js +148 -25
- package/src/cli/serverUrl.js +8 -3
- package/src/cli/sessions.js +131 -5
- package/src/cli/setup.js +109 -11
- package/src/cli/terminal-commands.js +16 -8
- package/src/cli/terminal-messaging.js +231 -0
- package/src/cli/terminal-welcome.js +365 -33
- package/src/commandActions.js +1 -0
- package/src/commandPaletteConfig.js +9 -0
- package/src/comments/auth.js +2 -1
- package/src/comments/ui/AuthModal.jsx +114 -0
- package/src/comments/ui/CommentWindow.jsx +329 -0
- package/src/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/comments/ui/Composer.jsx +64 -0
- package/src/comments/ui/authModal.test.js +1 -1
- package/src/comments/ui/commentWindow.js +16 -17
- package/src/comments/ui/commentsDrawer.js +25 -26
- package/src/comments/ui/composer.js +23 -24
- package/src/comments/ui/index.js +2 -3
- package/src/configSchema.js +59 -1
- package/src/configStore.js +161 -0
- package/src/core-ui-colors.css +12 -0
- package/src/devtools.js +17 -19
- package/src/devtools.test.js +18 -9
- package/src/featureFlags.js +12 -5
- package/src/fuzzySearch.test.js +10 -0
- package/src/index.js +14 -2
- package/src/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/lib/components/ui/alert/alert.jsx +25 -0
- package/src/lib/components/ui/alert/index.js +15 -15
- package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/lib/components/ui/avatar/index.js +20 -20
- package/src/lib/components/ui/badge/badge.jsx +31 -0
- package/src/lib/components/ui/badge/index.js +2 -2
- package/src/lib/components/ui/button/button.jsx +100 -0
- package/src/lib/components/ui/button/index.js +9 -9
- package/src/lib/components/ui/card/card-action.jsx +11 -0
- package/src/lib/components/ui/card/card-content.jsx +11 -0
- package/src/lib/components/ui/card/card-description.jsx +11 -0
- package/src/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/lib/components/ui/card/card-header.jsx +19 -0
- package/src/lib/components/ui/card/card-title.jsx +11 -0
- package/src/lib/components/ui/card/card.jsx +17 -0
- package/src/lib/components/ui/card/index.js +23 -23
- package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/lib/components/ui/checkbox/index.js +5 -5
- package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/lib/components/ui/collapsible/index.js +11 -11
- package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/lib/components/ui/dialog/index.js +32 -32
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/index.js +52 -52
- package/src/lib/components/ui/input/index.js +5 -5
- package/src/lib/components/ui/input/input.jsx +19 -0
- package/src/lib/components/ui/label/index.js +5 -5
- package/src/lib/components/ui/label/label.jsx +19 -0
- package/src/lib/components/ui/panel/index.js +21 -21
- package/src/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/lib/components/ui/panel/panel.jsx +4 -0
- package/src/lib/components/ui/popover/index.js +26 -26
- package/src/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/lib/components/ui/popover/popover.jsx +4 -0
- package/src/lib/components/ui/searchable-list.jsx +159 -0
- package/src/lib/components/ui/select/index.js +35 -35
- package/src/lib/components/ui/select/select-content.jsx +30 -0
- package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/lib/components/ui/select/select-group.jsx +15 -0
- package/src/lib/components/ui/select/select-item.jsx +26 -0
- package/src/lib/components/ui/select/select-label.jsx +11 -0
- package/src/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/lib/components/ui/select/select.jsx +4 -0
- package/src/lib/components/ui/separator/index.js +5 -5
- package/src/lib/components/ui/separator/separator.jsx +22 -0
- package/src/lib/components/ui/sheet/index.js +32 -32
- package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/lib/components/ui/textarea/index.js +5 -5
- package/src/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/lib/components/ui/toggle/index.js +6 -9
- package/src/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/lib/components/ui/toggle-group/index.js +8 -8
- package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/lib/components/ui/tooltip/index.js +3 -3
- package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/lib/components/ui/trigger-button/index.js +3 -3
- package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/logger/devLogger.js +238 -0
- package/src/logger/devLogger.test.js +193 -0
- package/src/modes.test.js +4 -4
- package/src/mountStoryboardCore.js +123 -27
- package/src/paletteProviders.js +3 -0
- package/src/paletteProviders.test.js +2 -2
- package/src/server/index.js +98 -36
- package/src/sidepanel.css +214 -0
- package/src/styles/tailwind.css +1 -1
- package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
- package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
- package/src/svelte-plugin-ui/components/Icon.css +11 -0
- package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
- package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
- package/src/svelte-plugin-ui/components/Viewfinder.jsx +512 -0
- package/src/svelte-plugin-ui/mount.ts +12 -16
- package/src/toolRegistry.js +4 -4
- package/src/toolbarConfigStore.js +30 -0
- package/src/tools/handlers/autosync.js +1 -1
- package/src/tools/handlers/canvasAddWidget.js +1 -1
- package/src/tools/handlers/canvasAgents.js +19 -0
- package/src/tools/handlers/canvasToolbar.js +8 -8
- package/src/tools/handlers/commandPalette.js +9 -0
- package/src/tools/handlers/comments.js +1 -1
- package/src/tools/handlers/create.js +1 -1
- package/src/tools/handlers/devtools.js +16 -0
- package/src/tools/handlers/devtools.test.js +38 -0
- package/src/tools/handlers/flows.js +1 -1
- package/src/tools/handlers/hideChrome.js +9 -0
- package/src/tools/handlers/paletteTheme.js +35 -0
- package/src/tools/handlers/theme.js +1 -1
- package/src/tools/registry.js +4 -1
- package/src/tools/surfaces/commandList.js +3 -3
- package/src/tools/surfaces/mainToolbar.js +3 -3
- package/src/tools/surfaces/registry.js +4 -4
- package/src/ui/design-modes.ts +2 -2
- package/src/ui/viewfinder.ts +1 -1
- package/src/vite/server-plugin.js +242 -60
- package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/workshop/features/createCanvas/index.js +1 -1
- package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/workshop/features/createFlow/index.js +1 -1
- package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/workshop/features/createPage/index.js +1 -1
- package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/workshop/features/createPrototype/index.js +1 -1
- package/src/workshop/features/createPrototype/server.js +98 -0
- package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/workshop/features/createStory/index.js +1 -1
- package/src/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/workshop/ui/mount.ts +1 -1
- package/src/worktree/port.js +48 -0
- package/src/worktree/serverRegistry.js +120 -0
- package/toolbar.config.json +93 -42
- package/widgets.config.json +580 -12
- package/src/ActionMenuButton.svelte +0 -119
- package/src/AutosyncMenuButton.svelte +0 -397
- package/src/CanvasCreateMenu.svelte +0 -295
- package/src/CanvasSnap.svelte +0 -87
- package/src/CanvasUndoRedo.svelte +0 -108
- package/src/CanvasZoomControl.svelte +0 -111
- package/src/CanvasZoomToFit.svelte +0 -52
- package/src/CommandMenu.svelte +0 -249
- package/src/CommandPalette.svelte +0 -33
- package/src/CommentsMenuButton.svelte +0 -53
- package/src/CoreUIBar.svelte +0 -847
- package/src/CreateMenuButton.svelte +0 -133
- package/src/DocPanel.svelte +0 -299
- package/src/InspectorPanel.svelte +0 -745
- package/src/PwaInstallBanner.svelte +0 -124
- package/src/SidePanel.svelte +0 -480
- package/src/ThemeMenuButton.svelte +0 -132
- package/src/comments/ui/AuthModal.svelte +0 -108
- package/src/comments/ui/CommentWindow.svelte +0 -333
- package/src/comments/ui/CommentsDrawer.svelte +0 -96
- package/src/comments/ui/Composer.svelte +0 -65
- package/src/lib/components/ui/alert/alert-action.svelte +0 -19
- package/src/lib/components/ui/alert/alert-description.svelte +0 -22
- package/src/lib/components/ui/alert/alert-title.svelte +0 -22
- package/src/lib/components/ui/alert/alert.svelte +0 -38
- package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
- package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
- package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
- package/src/lib/components/ui/avatar/avatar.svelte +0 -24
- package/src/lib/components/ui/badge/badge.svelte +0 -44
- package/src/lib/components/ui/button/button.svelte +0 -108
- package/src/lib/components/ui/card/card-action.svelte +0 -21
- package/src/lib/components/ui/card/card-content.svelte +0 -19
- package/src/lib/components/ui/card/card-description.svelte +0 -19
- package/src/lib/components/ui/card/card-footer.svelte +0 -18
- package/src/lib/components/ui/card/card-header.svelte +0 -21
- package/src/lib/components/ui/card/card-title.svelte +0 -14
- package/src/lib/components/ui/card/card.svelte +0 -21
- package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
- package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
- package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
- package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
- package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
- package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
- package/src/lib/components/ui/input/input.svelte +0 -40
- package/src/lib/components/ui/label/label.svelte +0 -20
- package/src/lib/components/ui/panel/panel-body.svelte +0 -13
- package/src/lib/components/ui/panel/panel-close.svelte +0 -16
- package/src/lib/components/ui/panel/panel-content.svelte +0 -33
- package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
- package/src/lib/components/ui/panel/panel-header.svelte +0 -16
- package/src/lib/components/ui/panel/panel-title.svelte +0 -14
- package/src/lib/components/ui/panel/panel.svelte +0 -15
- package/src/lib/components/ui/popover/popover-close.svelte +0 -7
- package/src/lib/components/ui/popover/popover-content.svelte +0 -27
- package/src/lib/components/ui/popover/popover-description.svelte +0 -19
- package/src/lib/components/ui/popover/popover-header.svelte +0 -19
- package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
- package/src/lib/components/ui/popover/popover-title.svelte +0 -19
- package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
- package/src/lib/components/ui/popover/popover.svelte +0 -7
- package/src/lib/components/ui/select/select-content.svelte +0 -40
- package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
- package/src/lib/components/ui/select/select-group.svelte +0 -17
- package/src/lib/components/ui/select/select-item.svelte +0 -38
- package/src/lib/components/ui/select/select-label.svelte +0 -18
- package/src/lib/components/ui/select/select-portal.svelte +0 -7
- package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
- package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
- package/src/lib/components/ui/select/select-separator.svelte +0 -17
- package/src/lib/components/ui/select/select-trigger.svelte +0 -27
- package/src/lib/components/ui/select/select.svelte +0 -11
- package/src/lib/components/ui/separator/separator.svelte +0 -23
- package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
- package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
- package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
- package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet.svelte +0 -7
- package/src/lib/components/ui/textarea/textarea.svelte +0 -21
- package/src/lib/components/ui/toggle/toggle.svelte +0 -45
- package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
- package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
- package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
- package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
- package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
- package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
- package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
- package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
- package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
- package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
- package/src/tools/handlers/docs.js +0 -11
- package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
- package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
- package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
- package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
- package/src/workshop/ui/WorkshopPanel.svelte +0 -97
package/src/autosync/server.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* - Enable/disable autosync per scope (canvas/prototype)
|
|
7
7
|
* - Direct commit + push on the current branch (scoped files only)
|
|
8
8
|
* - Push watcher: every 30s runs enabled scopes in relay sequence
|
|
9
|
+
* - Persists state to .storyboard/autosync.json to survive server restarts
|
|
10
|
+
* - Pauses on branch change, resumes when user returns to target branch
|
|
9
11
|
*
|
|
10
12
|
* Routes (mounted at /_storyboard/autosync/):
|
|
11
13
|
* GET /branches — list local git branches (excludes main/master)
|
|
@@ -16,7 +18,7 @@
|
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
import { execFileSync } from 'node:child_process'
|
|
19
|
-
import { existsSync } from 'node:fs'
|
|
21
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, renameSync, unlinkSync } from 'node:fs'
|
|
20
22
|
import { join, resolve } from 'node:path'
|
|
21
23
|
|
|
22
24
|
// ── Module-level watcher state (singleton, survives page reloads) ──
|
|
@@ -29,6 +31,8 @@ let lastSyncTime = null
|
|
|
29
31
|
let lastError = null
|
|
30
32
|
let syncing = false
|
|
31
33
|
let syncingScope = null
|
|
34
|
+
let pausedOnBranchChange = false
|
|
35
|
+
let previousActiveBranch = null
|
|
32
36
|
|
|
33
37
|
let enabledScopes = { canvas: false, prototype: false }
|
|
34
38
|
let lastSyncByScope = { canvas: null, prototype: null }
|
|
@@ -42,6 +46,158 @@ const AUTOSYNC_SCOPES = new Set(SCOPE_ORDER)
|
|
|
42
46
|
// Branch names must match git ref format — alphanumeric, hyphens, dots, slashes
|
|
43
47
|
const BRANCH_NAME_RE = /^[\w][\w.\-/]*$/
|
|
44
48
|
|
|
49
|
+
// ── Persistence (.storyboard/autosync.json) ──
|
|
50
|
+
|
|
51
|
+
const PERSIST_DIR = '.storyboard'
|
|
52
|
+
const PERSIST_FILE = 'autosync.json'
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load persisted autosync state from disk. Returns null on missing/corrupt files.
|
|
56
|
+
*/
|
|
57
|
+
export function loadPersistedState(root) {
|
|
58
|
+
const filePath = join(root, PERSIST_DIR, PERSIST_FILE)
|
|
59
|
+
try {
|
|
60
|
+
if (!existsSync(filePath)) return null
|
|
61
|
+
const raw = readFileSync(filePath, 'utf-8')
|
|
62
|
+
const data = JSON.parse(raw)
|
|
63
|
+
if (!data || typeof data !== 'object') return null
|
|
64
|
+
return validatePersistedState(data)
|
|
65
|
+
} catch {
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Validate loaded state — reject invalid/protected branches and bad types.
|
|
72
|
+
*/
|
|
73
|
+
function validatePersistedState(data) {
|
|
74
|
+
const result = {}
|
|
75
|
+
|
|
76
|
+
if (data.targetBranch && isValidBranch(data.targetBranch) && !isProtectedBranch(data.targetBranch)) {
|
|
77
|
+
result.targetBranch = data.targetBranch
|
|
78
|
+
}
|
|
79
|
+
if (data.originalBranch && isValidBranch(data.originalBranch)) {
|
|
80
|
+
result.originalBranch = data.originalBranch
|
|
81
|
+
}
|
|
82
|
+
if (data.previousActiveBranch && isValidBranch(data.previousActiveBranch)) {
|
|
83
|
+
result.previousActiveBranch = data.previousActiveBranch
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
result.pausedOnBranchChange = data.pausedOnBranchChange === true
|
|
87
|
+
result.lastSyncTime = typeof data.lastSyncTime === 'string' ? data.lastSyncTime : null
|
|
88
|
+
result.lastSyncByScope = {
|
|
89
|
+
canvas: typeof data.lastSyncByScope?.canvas === 'string' ? data.lastSyncByScope.canvas : null,
|
|
90
|
+
prototype: typeof data.lastSyncByScope?.prototype === 'string' ? data.lastSyncByScope.prototype : null,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (data.enabledScopes && typeof data.enabledScopes === 'object') {
|
|
94
|
+
result.enabledScopes = {
|
|
95
|
+
canvas: data.enabledScopes.canvas === true,
|
|
96
|
+
prototype: data.enabledScopes.prototype === true,
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
result.enabledScopes = { canvas: false, prototype: false }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Must have a targetBranch and at least one enabled scope to be restorable
|
|
103
|
+
if (!result.targetBranch || (!result.enabledScopes.canvas && !result.enabledScopes.prototype)) {
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return result
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Persist current autosync state to disk (atomic write via tmp + rename).
|
|
112
|
+
*/
|
|
113
|
+
export function persistState(root) {
|
|
114
|
+
const dirPath = join(root, PERSIST_DIR)
|
|
115
|
+
const filePath = join(dirPath, PERSIST_FILE)
|
|
116
|
+
const tmpPath = filePath + '.tmp'
|
|
117
|
+
try {
|
|
118
|
+
const currentBranch = getCurrentBranch(root)
|
|
119
|
+
const data = {
|
|
120
|
+
enabledScopes: { ...enabledScopes },
|
|
121
|
+
targetBranch,
|
|
122
|
+
originalBranch,
|
|
123
|
+
previousActiveBranch,
|
|
124
|
+
currentBranch,
|
|
125
|
+
pausedOnBranchChange,
|
|
126
|
+
lastSyncTime,
|
|
127
|
+
lastSyncByScope: { ...lastSyncByScope },
|
|
128
|
+
}
|
|
129
|
+
if (!existsSync(dirPath)) mkdirSync(dirPath, { recursive: true })
|
|
130
|
+
writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n', 'utf-8')
|
|
131
|
+
renameSync(tmpPath, filePath)
|
|
132
|
+
} catch {
|
|
133
|
+
// Best-effort persistence — don't break autosync if disk write fails
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Remove persisted state file (on explicit full disable).
|
|
139
|
+
*/
|
|
140
|
+
export function clearPersistedState(root) {
|
|
141
|
+
const filePath = join(root, PERSIST_DIR, PERSIST_FILE)
|
|
142
|
+
try {
|
|
143
|
+
if (existsSync(filePath)) unlinkSync(filePath)
|
|
144
|
+
} catch { /* ignore — file may already be gone */ }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Restore module-level state from a validated persisted snapshot.
|
|
149
|
+
*/
|
|
150
|
+
function applyPersistedState(data) {
|
|
151
|
+
enabledScopes = { ...data.enabledScopes }
|
|
152
|
+
targetBranch = data.targetBranch
|
|
153
|
+
originalBranch = data.originalBranch || data.targetBranch
|
|
154
|
+
previousActiveBranch = data.previousActiveBranch || null
|
|
155
|
+
pausedOnBranchChange = data.pausedOnBranchChange || false
|
|
156
|
+
lastSyncTime = data.lastSyncTime || null
|
|
157
|
+
lastSyncByScope = { ...data.lastSyncByScope }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── Branch reconciliation ──
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Reconcile branch state — pause on drift, resume on return.
|
|
164
|
+
* Called at server startup and on each scheduler tick.
|
|
165
|
+
* Returns true if autosync is active (not paused), false if paused.
|
|
166
|
+
*/
|
|
167
|
+
export function reconcileBranch(root) {
|
|
168
|
+
if (!targetBranch || !hasAnyScopeEnabled()) return true
|
|
169
|
+
|
|
170
|
+
let current
|
|
171
|
+
try {
|
|
172
|
+
current = getCurrentBranch(root)
|
|
173
|
+
} catch {
|
|
174
|
+
return false // can't determine branch — don't sync
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (current === targetBranch) {
|
|
178
|
+
// Back on the target branch — resume if we were paused
|
|
179
|
+
if (pausedOnBranchChange) {
|
|
180
|
+
pausedOnBranchChange = false
|
|
181
|
+
previousActiveBranch = null
|
|
182
|
+
persistState(root)
|
|
183
|
+
}
|
|
184
|
+
return true
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Branch drift — pause if not already paused
|
|
188
|
+
if (!pausedOnBranchChange) {
|
|
189
|
+
pausedOnBranchChange = true
|
|
190
|
+
previousActiveBranch = targetBranch
|
|
191
|
+
persistState(root)
|
|
192
|
+
}
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function isProtectedBranch(name) {
|
|
197
|
+
const normalized = String(name || '').toLowerCase()
|
|
198
|
+
return normalized === 'main' || normalized === 'master'
|
|
199
|
+
}
|
|
200
|
+
|
|
45
201
|
// ── Git helpers (argv-based, no shell) ──
|
|
46
202
|
|
|
47
203
|
function git(args, root) {
|
|
@@ -130,11 +286,13 @@ export function matchesAutosyncScope(scope, filePath) {
|
|
|
130
286
|
return file === 'src/prototypes' || file.startsWith('src/prototypes/')
|
|
131
287
|
}
|
|
132
288
|
|
|
133
|
-
// canvas scope
|
|
289
|
+
// canvas scope — includes canvas data, canvas assets, and public storyboard assets
|
|
134
290
|
return (
|
|
135
291
|
file === 'src/canvas' ||
|
|
136
292
|
file.startsWith('src/canvas/') ||
|
|
137
|
-
file.endsWith('.canvas.jsonl')
|
|
293
|
+
file.endsWith('.canvas.jsonl') ||
|
|
294
|
+
file.startsWith('assets/canvas/') ||
|
|
295
|
+
file.startsWith('assets/.storyboard-public/')
|
|
138
296
|
)
|
|
139
297
|
}
|
|
140
298
|
|
|
@@ -200,6 +358,8 @@ function resetRuntimeState({ clearBranch = true } = {}) {
|
|
|
200
358
|
enabledScopes = { canvas: false, prototype: false }
|
|
201
359
|
syncing = false
|
|
202
360
|
syncingScope = null
|
|
361
|
+
pausedOnBranchChange = false
|
|
362
|
+
previousActiveBranch = null
|
|
203
363
|
if (clearBranch) {
|
|
204
364
|
targetBranch = null
|
|
205
365
|
originalBranch = null
|
|
@@ -235,6 +395,8 @@ function buildStatusPayload(root) {
|
|
|
235
395
|
lastErrorByScope: { ...lastErrorByScope },
|
|
236
396
|
syncing,
|
|
237
397
|
syncingScope,
|
|
398
|
+
pausedOnBranchChange,
|
|
399
|
+
previousActiveBranch,
|
|
238
400
|
}
|
|
239
401
|
}
|
|
240
402
|
|
|
@@ -345,6 +507,8 @@ function runSyncCycle(root, scope) {
|
|
|
345
507
|
lastSyncByScope[scope] = nowIso
|
|
346
508
|
lastErrorByScope[scope] = null
|
|
347
509
|
lastError = null
|
|
510
|
+
// Persist state after actual commit+push (committed is still true only if push succeeded)
|
|
511
|
+
if (committed) persistState(root)
|
|
348
512
|
}
|
|
349
513
|
syncing = false
|
|
350
514
|
syncingScope = null
|
|
@@ -356,6 +520,9 @@ function runSyncCycle(root, scope) {
|
|
|
356
520
|
function runRelayCycle(root, scopes = getEnabledScopesInOrder()) {
|
|
357
521
|
if (syncing || scopes.length === 0) return true
|
|
358
522
|
|
|
523
|
+
// Reconcile branch state — pause on drift, resume on return
|
|
524
|
+
if (!reconcileBranch(root)) return true // paused — skip sync
|
|
525
|
+
|
|
359
526
|
let ok = true
|
|
360
527
|
let firstRelaySyncTime = null
|
|
361
528
|
|
|
@@ -390,6 +557,19 @@ function startScheduler(root) {
|
|
|
390
557
|
// ── Route handler ──
|
|
391
558
|
|
|
392
559
|
export function createAutosyncHandler({ root, sendJson }) {
|
|
560
|
+
// ── Restore persisted state on server startup ──
|
|
561
|
+
const persisted = loadPersistedState(root)
|
|
562
|
+
if (persisted) {
|
|
563
|
+
applyPersistedState(persisted)
|
|
564
|
+
reconcileBranch(root)
|
|
565
|
+
|
|
566
|
+
// Start scheduler if any scope is enabled — reconcileBranch handles
|
|
567
|
+
// pause/resume on each tick, so the scheduler runs even when paused
|
|
568
|
+
if (hasAnyScopeEnabled()) {
|
|
569
|
+
startScheduler(root)
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
393
573
|
return async (req, res, { body, path: routePath, method }) => {
|
|
394
574
|
// GET /branches — list local branches
|
|
395
575
|
if (routePath === '/branches' && method === 'GET') {
|
|
@@ -441,9 +621,18 @@ export function createAutosyncHandler({ root, sendJson }) {
|
|
|
441
621
|
const normalizedScope = normalizeAutosyncScope(scope)
|
|
442
622
|
const hadEnabledScopes = hasAnyScopeEnabled()
|
|
443
623
|
|
|
624
|
+
// Allow retargeting when paused on a different branch
|
|
444
625
|
if (hadEnabledScopes && targetBranch !== branch) {
|
|
445
|
-
|
|
446
|
-
|
|
626
|
+
if (pausedOnBranchChange) {
|
|
627
|
+
// Clear pause and retarget to the new branch
|
|
628
|
+
pausedOnBranchChange = false
|
|
629
|
+
previousActiveBranch = null
|
|
630
|
+
targetBranch = branch
|
|
631
|
+
originalBranch = currentBranch
|
|
632
|
+
} else {
|
|
633
|
+
sendJson(res, 409, { error: `Autosync is active on ${targetBranch}. Disable all scopes before switching branch.` })
|
|
634
|
+
return
|
|
635
|
+
}
|
|
447
636
|
}
|
|
448
637
|
|
|
449
638
|
if (!hadEnabledScopes) {
|
|
@@ -453,6 +642,9 @@ export function createAutosyncHandler({ root, sendJson }) {
|
|
|
453
642
|
|
|
454
643
|
enabledScopes[normalizedScope] = true
|
|
455
644
|
lastErrorByScope[normalizedScope] = null
|
|
645
|
+
pausedOnBranchChange = false
|
|
646
|
+
previousActiveBranch = null
|
|
647
|
+
persistState(root)
|
|
456
648
|
startScheduler(root)
|
|
457
649
|
|
|
458
650
|
// Immediate first sync for the enabled scope.
|
|
@@ -476,7 +668,12 @@ export function createAutosyncHandler({ root, sendJson }) {
|
|
|
476
668
|
}
|
|
477
669
|
|
|
478
670
|
if (!hasAnyScopeEnabled()) {
|
|
671
|
+
// Explicit full disable — clear persisted state entirely
|
|
479
672
|
stopAutosync(root, { clearBranch: true, clearErrors: true })
|
|
673
|
+
clearPersistedState(root)
|
|
674
|
+
} else {
|
|
675
|
+
// Partial disable — persist the remaining state
|
|
676
|
+
persistState(root)
|
|
480
677
|
}
|
|
481
678
|
|
|
482
679
|
sendJson(res, 200, buildStatusPayload(root))
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
1
4
|
import {
|
|
2
5
|
normalizeAutosyncScope,
|
|
3
6
|
matchesAutosyncScope,
|
|
4
7
|
filterFilesForAutosyncScope,
|
|
5
8
|
isRetryablePushError,
|
|
9
|
+
loadPersistedState,
|
|
10
|
+
persistState,
|
|
11
|
+
clearPersistedState,
|
|
6
12
|
} from './server.js'
|
|
7
13
|
|
|
8
14
|
describe('autosync scope helpers', () => {
|
|
@@ -14,6 +20,9 @@ describe('autosync scope helpers', () => {
|
|
|
14
20
|
it('matches canvas scope files', () => {
|
|
15
21
|
expect(matchesAutosyncScope('canvas', 'src/canvas/widgets.canvas.jsonl')).toBe(true)
|
|
16
22
|
expect(matchesAutosyncScope('canvas', 'src/canvas/notes.txt')).toBe(true)
|
|
23
|
+
expect(matchesAutosyncScope('canvas', 'assets/canvas/images/photo.png')).toBe(true)
|
|
24
|
+
expect(matchesAutosyncScope('canvas', 'assets/canvas/snapshots/snapshot-widget--latest.webp')).toBe(true)
|
|
25
|
+
expect(matchesAutosyncScope('canvas', 'assets/.storyboard-public/terminal-snapshots/agent-abc.snapshot.json')).toBe(true)
|
|
17
26
|
expect(matchesAutosyncScope('canvas', 'src/prototypes/demo/default.flow.json')).toBe(false)
|
|
18
27
|
})
|
|
19
28
|
|
|
@@ -45,3 +54,106 @@ describe('autosync scope helpers', () => {
|
|
|
45
54
|
expect(isRetryablePushError('some other git error')).toBe(false)
|
|
46
55
|
})
|
|
47
56
|
})
|
|
57
|
+
|
|
58
|
+
describe('autosync persistence', () => {
|
|
59
|
+
let tmpRoot
|
|
60
|
+
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
tmpRoot = join(tmpdir(), `autosync-test-${Date.now()}-${Math.random().toString(36).slice(2)}`)
|
|
63
|
+
mkdirSync(join(tmpRoot, '.storyboard'), { recursive: true })
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
afterEach(() => {
|
|
67
|
+
try { rmSync(tmpRoot, { recursive: true, force: true }) } catch { /* ignore */ }
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('returns null for missing file', () => {
|
|
71
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('returns null for corrupt JSON', () => {
|
|
75
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), 'not json', 'utf-8')
|
|
76
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('returns null for empty object', () => {
|
|
80
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), '{}', 'utf-8')
|
|
81
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('returns null when no scopes enabled', () => {
|
|
85
|
+
const data = {
|
|
86
|
+
targetBranch: 'feature/test',
|
|
87
|
+
enabledScopes: { canvas: false, prototype: false },
|
|
88
|
+
}
|
|
89
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), JSON.stringify(data), 'utf-8')
|
|
90
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('returns null for protected branch names', () => {
|
|
94
|
+
const data = {
|
|
95
|
+
targetBranch: 'main',
|
|
96
|
+
enabledScopes: { canvas: true, prototype: false },
|
|
97
|
+
}
|
|
98
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), JSON.stringify(data), 'utf-8')
|
|
99
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('loads valid persisted state', () => {
|
|
103
|
+
const data = {
|
|
104
|
+
targetBranch: 'feature/test',
|
|
105
|
+
originalBranch: 'feature/test',
|
|
106
|
+
enabledScopes: { canvas: true, prototype: false },
|
|
107
|
+
pausedOnBranchChange: false,
|
|
108
|
+
lastSyncTime: '2026-04-26T19:00:00.000Z',
|
|
109
|
+
lastSyncByScope: { canvas: '2026-04-26T19:00:00.000Z', prototype: null },
|
|
110
|
+
}
|
|
111
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), JSON.stringify(data), 'utf-8')
|
|
112
|
+
|
|
113
|
+
const result = loadPersistedState(tmpRoot)
|
|
114
|
+
expect(result).not.toBe(null)
|
|
115
|
+
expect(result.targetBranch).toBe('feature/test')
|
|
116
|
+
expect(result.enabledScopes.canvas).toBe(true)
|
|
117
|
+
expect(result.enabledScopes.prototype).toBe(false)
|
|
118
|
+
expect(result.pausedOnBranchChange).toBe(false)
|
|
119
|
+
expect(result.lastSyncTime).toBe('2026-04-26T19:00:00.000Z')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('loads paused state with previousActiveBranch', () => {
|
|
123
|
+
const data = {
|
|
124
|
+
targetBranch: 'feature/test',
|
|
125
|
+
originalBranch: 'feature/test',
|
|
126
|
+
previousActiveBranch: 'feature/test',
|
|
127
|
+
enabledScopes: { canvas: true, prototype: true },
|
|
128
|
+
pausedOnBranchChange: true,
|
|
129
|
+
}
|
|
130
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), JSON.stringify(data), 'utf-8')
|
|
131
|
+
|
|
132
|
+
const result = loadPersistedState(tmpRoot)
|
|
133
|
+
expect(result.pausedOnBranchChange).toBe(true)
|
|
134
|
+
expect(result.previousActiveBranch).toBe('feature/test')
|
|
135
|
+
expect(result.enabledScopes.canvas).toBe(true)
|
|
136
|
+
expect(result.enabledScopes.prototype).toBe(true)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('rejects invalid branch names in persisted state', () => {
|
|
140
|
+
const data = {
|
|
141
|
+
targetBranch: '',
|
|
142
|
+
enabledScopes: { canvas: true },
|
|
143
|
+
}
|
|
144
|
+
writeFileSync(join(tmpRoot, '.storyboard', 'autosync.json'), JSON.stringify(data), 'utf-8')
|
|
145
|
+
expect(loadPersistedState(tmpRoot)).toBe(null)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('clearPersistedState removes the file', () => {
|
|
149
|
+
const filePath = join(tmpRoot, '.storyboard', 'autosync.json')
|
|
150
|
+
writeFileSync(filePath, '{}', 'utf-8')
|
|
151
|
+
expect(existsSync(filePath)).toBe(true)
|
|
152
|
+
clearPersistedState(tmpRoot)
|
|
153
|
+
expect(existsSync(filePath)).toBe(false)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('clearPersistedState is safe when file does not exist', () => {
|
|
157
|
+
expect(() => clearPersistedState(tmpRoot)).not.toThrow()
|
|
158
|
+
})
|
|
159
|
+
})
|