@dfosco/storyboard 0.7.1 → 0.9.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/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +14128 -10953
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tiny-canvas.css +1 -1
- package/package.json +138 -128
- package/scaffold/AGENTS.md +9 -7
- package/scaffold/README.md +18 -0
- package/scaffold/deploy.yml +21 -0
- package/scaffold/gitignore +8 -14
- package/scaffold/preview.yml +40 -0
- package/scaffold/{manifest.json → scaffold.config.json} +73 -3
- package/scaffold/scripts/aggregate-artifacts.mjs +257 -0
- package/scaffold/skills/canvas/SKILL.md +1 -1
- package/scaffold/skills/migrate-0.5.0/SKILL.md +1 -1
- package/scaffold/skills/ship/SKILL.md +2 -2
- package/scaffold/skills/worktree/SKILL.md +1 -1
- package/scaffold/src/_prototype.jsx +17 -0
- package/scaffold/src/_story.jsx +13 -0
- package/scaffold/src/library/README.md +34 -0
- package/scaffold/src/library/_app.jsx +41 -0
- package/scaffold/src/library/_app.module.css +2 -0
- package/scaffold/src/library/create.jsx +10 -0
- package/scaffold/src/library/index.jsx +14 -0
- package/scaffold/src/library/mount.jsx +51 -0
- package/scaffold/src/library/prototypes-entry.jsx +57 -0
- package/scaffold/src/library/routes.jsx +205 -0
- package/scaffold/src/library/viewfinder.jsx +13 -0
- package/scaffold/src/library/workspace.jsx +17 -0
- package/scripts/aggregate-artifacts.mjs +257 -0
- package/src/canvas/style.css +16 -16
- package/src/core/artifact/operations.js +54 -15
- package/src/core/artifact/schemas/canvas.schema.json +7 -1
- package/src/core/autosync/server.test.js +1 -1
- package/src/core/canvas/hot-pool.js +21 -33
- package/src/core/canvas/materializer.js +39 -13
- package/src/core/canvas/selectedWidgets.js +1 -1
- package/src/core/canvas/server.js +376 -100
- package/src/core/canvas/server.test.js +472 -2
- package/src/core/canvas/terminal-server.js +144 -57
- package/src/core/canvas/undoRedo.js +174 -0
- package/src/core/canvas/undoRedo.test.js +250 -0
- package/src/core/cli/artifact.js +2 -0
- package/src/core/cli/buildManifest.js +34 -0
- package/src/core/cli/canvasRedo.js +44 -0
- package/src/core/cli/canvasUndo.js +40 -0
- package/src/core/cli/create.js +151 -23
- package/src/core/cli/dev.js +23 -35
- package/src/core/cli/index.js +21 -0
- package/src/core/cli/schemas.js +8 -4
- package/src/core/cli/serverUrl.js +24 -0
- package/src/core/cli/setup.js +14 -25
- package/src/core/cli/terminal-welcome.js +12 -6
- package/src/core/cli/updateVersion.js +42 -2
- package/src/core/cli/workleaf.js +140 -0
- package/src/core/comments/api.js +1 -1
- package/src/core/comments/queries.js +3 -0
- package/src/core/comments/ui/CommentWindow.jsx +3 -2
- package/src/core/comments/ui/comment-layout.css +14 -14
- package/src/core/data/artifactIndex.js +235 -0
- package/src/core/data/artifactIndex.test.js +203 -0
- package/src/core/data/artifactManifest.js +290 -0
- package/src/core/data/artifactManifest.test.js +207 -0
- package/src/core/data/viewfinder.js +47 -7
- package/src/core/index.js +24 -1
- package/src/core/inspector/highlighter.js +1 -1
- package/src/core/inspector/mouseMode.js +2 -2
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar.jsx +2 -2
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +12 -9
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +45 -31
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +9 -5
- package/src/core/lib/components/ui/dialog/dialog.jsx +12 -3
- package/src/core/lib/components/ui/dialog/dialog.module.css +118 -0
- package/src/core/lib/components/ui/dialog/index.js +4 -34
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +3 -3
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +19 -9
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +8 -8
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +15 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +14 -7
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +8 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +4 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +8 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +2 -2
- package/src/core/lib/components/ui/label/label.jsx +1 -2
- package/src/core/lib/components/ui/panel/panel-close.jsx +7 -4
- package/src/core/lib/components/ui/panel/panel-content.jsx +7 -9
- package/src/core/lib/components/ui/panel/panel-title.jsx +3 -3
- package/src/core/lib/components/ui/panel/panel.jsx +11 -2
- package/src/core/lib/components/ui/separator/separator.jsx +6 -4
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +7 -6
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +13 -6
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +5 -5
- package/src/core/modes/modes.css +4 -4
- package/src/core/mountStoryboardCore.js +287 -83
- package/src/core/mountStoryboardCore.test.js +198 -0
- package/src/core/rename-watcher/config.json +1 -1
- package/src/core/rename-watcher/watcher.js +330 -37
- package/src/core/rename-watcher/watcher.test.js +253 -0
- package/src/core/scaffold/fragments.js +287 -0
- package/src/core/scaffold/fragments.test.js +401 -0
- package/src/core/scaffold/index.js +291 -0
- package/src/core/scaffold/migrateLegacyGitignore.js +157 -0
- package/src/core/scaffold/scaffold-integration.test.js +247 -0
- package/src/core/scaffold.js +4 -97
- package/src/core/stores/canvasInteractionStore.js +120 -0
- package/src/core/stores/canvasInteractionStore.test.js +126 -0
- package/src/core/stores/configSchema.js +64 -8
- package/src/core/stores/configSchema.test.js +3 -0
- package/src/core/stores/customerModeConfig.js +24 -3
- package/src/core/stores/customerModeConfig.test.js +46 -0
- package/src/core/stores/presentationStore.js +118 -0
- package/src/core/stores/presentationStore.test.js +114 -0
- package/src/core/stores/recentArtifacts.js +49 -2
- package/src/core/stores/recentArtifacts.test.js +59 -6
- package/src/core/stores/themeBootstrap.js +264 -0
- package/src/core/stores/themeBootstrap.test.js +211 -0
- package/src/core/stores/themeStore.test.js +154 -0
- package/src/core/stores/themeStore.ts +235 -220
- package/src/core/stores/uiConfig.js +10 -2
- package/src/core/styles/generateThemesCss.js +63 -0
- package/src/core/styles/tailwind.css +150 -94
- package/src/core/styles/workspace-chrome.css +13 -0
- package/src/core/tools/handlers/paletteTheme.js +11 -8
- package/src/core/ui/ActionMenuButton.jsx +2 -1
- package/src/core/ui/AutosyncMenuButton.css +7 -7
- package/src/core/ui/BranchSelect.module.css +5 -5
- package/src/core/ui/CanvasCreateMenu.jsx +1 -19
- package/src/core/ui/ChromeSlot.jsx +92 -0
- package/src/core/ui/ChromeSlot.test.jsx +140 -0
- package/src/core/ui/CoreUIBar.css +5 -5
- package/src/core/ui/CoreUIBar.jsx +170 -142
- package/src/core/ui/InspectorPanel.css +5 -5
- package/src/core/ui/InspectorPanel.jsx +9 -9
- package/src/core/ui/PwaInstallBanner.css +5 -5
- package/src/core/ui/PwaInstallBanner.jsx +5 -5
- package/src/core/ui/ThemeMenuButton.jsx +45 -30
- package/src/core/ui/core-ui-colors.css +28 -66
- package/src/core/ui/sidepanel.css +12 -12
- package/src/core/vite/server-plugin.js +13 -0
- package/src/core/workleaf/cleanup.js +102 -0
- package/src/core/workleaf/create.js +199 -0
- package/src/core/workleaf/delete.js +101 -0
- package/src/core/workleaf/list.js +57 -0
- package/src/core/workleaf/merge.js +238 -0
- package/src/core/workleaf/paths.js +146 -0
- package/src/core/workleaf/paths.test.js +230 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +130 -34
- package/src/core/workshop/features/createFlow/server.js +5 -1
- package/src/core/workshop/features/createPrototype/server.js +5 -1
- package/src/core/workshop/features/templateIndex.js +28 -1
- package/src/core/worktree/port.js +48 -5
- package/src/core/worktree/port.test.js +42 -0
- package/src/internals/ArtifactForm/ArtifactForm.jsx +173 -112
- package/src/internals/ArtifactForm/ArtifactForm.module.css +51 -69
- package/src/internals/ArtifactForm/artifactSchemas.js +40 -5
- package/src/internals/AuthModal/AuthModal.module.css +34 -34
- package/src/internals/BaseUiForm/BaseUiForm.jsx +293 -0
- package/src/internals/BaseUiForm/BaseUiForm.module.css +542 -0
- package/src/internals/BranchBar/BranchBar.module.css +4 -4
- package/src/internals/BranchesDropdown/BranchesDropdown.jsx +69 -0
- package/src/internals/BranchesDropdown/BranchesDropdown.module.css +84 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +41 -29
- package/src/internals/CommandPalette/CreateArtifactForm.jsx +150 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +20 -110
- package/src/internals/CommandPalette/WidgetArtifactDialog.css +16 -16
- package/src/internals/CommandPalette/WidgetArtifactDialog.jsx +1 -1
- package/src/internals/CommandPalette/command-palette.css +14 -14
- package/src/internals/CommandPalette/createHelpers.js +30 -0
- package/src/internals/CreatePage/CreatePage.jsx +57 -0
- package/src/internals/CreatePage/CreatePage.module.css +34 -0
- package/src/internals/Dialog.jsx +51 -0
- package/src/internals/FlowError.module.css +5 -5
- package/src/internals/PrototypeErrorBoundary.module.css +15 -15
- package/src/internals/SimpleWorkspace/SimpleWorkspace.jsx +534 -0
- package/src/internals/SimpleWorkspace/SimpleWorkspace.module.css +323 -0
- package/src/internals/Tooltip.jsx +39 -0
- package/src/internals/Viewfinder.jsx +229 -64
- package/src/internals/Viewfinder.module.css +253 -182
- package/src/internals/canvas/CanvasControls.module.css +11 -11
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +11 -37
- package/src/internals/canvas/CanvasPage.jsx +358 -217
- package/src/internals/canvas/CanvasPage.module.css +20 -19
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +39 -26
- package/src/internals/canvas/CanvasToolbar.module.css +11 -11
- package/src/internals/canvas/ConnectorLayer.jsx +39 -2
- package/src/internals/canvas/ConnectorLayer.module.css +10 -10
- package/src/internals/canvas/PageSelector.jsx +15 -1
- package/src/internals/canvas/PageSelector.module.css +41 -27
- package/src/internals/canvas/canvasApi.js +40 -5
- package/src/internals/canvas/canvasTheme.js +22 -111
- package/src/internals/canvas/isolation/createIsolationMiddleware.js +68 -0
- package/src/internals/canvas/isolation/mountIsolationApp.jsx +88 -0
- package/src/internals/canvas/isolation/prototypeRoutes.jsx +140 -0
- package/src/internals/canvas/isolation/prototypesEntry.jsx +28 -0
- package/src/internals/canvas/isolation/storiesEntry.jsx +20 -0
- package/src/internals/canvas/isolation/storyRoutes.jsx +55 -0
- package/src/internals/canvas/useUndoRedo.js +75 -60
- package/src/internals/canvas/useUndoRedo.test.js +46 -178
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +16 -36
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +12 -12
- package/src/internals/canvas/widgets/CropOverlay.module.css +23 -23
- package/src/internals/canvas/widgets/ExpandedPane.module.css +8 -8
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +1 -1
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +15 -36
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +15 -15
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +30 -21
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +5 -5
- package/src/internals/canvas/widgets/ImageWidget.jsx +7 -2
- package/src/internals/canvas/widgets/ImageWidget.module.css +3 -3
- package/src/internals/canvas/widgets/LinkPreview.module.css +79 -80
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +31 -31
- package/src/internals/canvas/widgets/PromptWidget.jsx +2 -16
- package/src/internals/canvas/widgets/PromptWidget.module.css +33 -33
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +92 -17
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +58 -56
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +118 -4
- package/src/internals/canvas/widgets/ResizeHandle.module.css +4 -4
- package/src/internals/canvas/widgets/StorySetWidget.jsx +53 -25
- package/src/internals/canvas/widgets/StoryWidget.jsx +71 -56
- package/src/internals/canvas/widgets/StoryWidget.module.css +22 -20
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +13 -15
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +4 -4
- package/src/internals/canvas/widgets/TerminalWidget.jsx +56 -45
- package/src/internals/canvas/widgets/TerminalWidget.module.css +10 -10
- package/src/internals/canvas/widgets/TilesWidget.module.css +17 -17
- package/src/internals/canvas/widgets/WidgetChrome.jsx +1 -1
- package/src/internals/canvas/widgets/WidgetChrome.module.css +76 -61
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +2 -2
- package/src/internals/canvas/widgets/embedOverlay.module.css +14 -4
- package/src/internals/canvas/widgets/embedTheme.js +12 -104
- package/src/internals/canvas/widgets/expandUtils.js +19 -19
- package/src/internals/canvas/widgets/normalizeLegacyEmbedSrc.js +74 -0
- package/src/internals/canvas/widgets/widgetConfig.js +5 -5
- package/src/internals/context.jsx +22 -1
- package/src/internals/context.test.jsx +47 -0
- package/src/internals/hooks/useArtifactIndex.js +31 -0
- package/src/internals/hooks/useArtifactIndex.test.js +45 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +14 -8
- package/src/internals/index.js +6 -0
- package/src/internals/loadConsumerWrapper.js +60 -0
- package/src/internals/story/ComponentSetPage.jsx +75 -34
- package/src/internals/story/ComponentSetPage.module.css +14 -14
- package/src/internals/story/StoryPage.jsx +16 -25
- package/src/internals/story/StoryPage.module.css +2 -2
- package/src/internals/vite/data-plugin.js +317 -149
- package/src/internals/vite/data-plugin.test.js +11 -11
- package/{scaffold/storyboard.config.json → storyboard.config.json} +25 -0
- package/terminal.config.json +1 -1
- package/src/core/lib/components/ui/card/card-action.jsx +0 -11
- package/src/core/lib/components/ui/card/card-content.jsx +0 -11
- package/src/core/lib/components/ui/card/card-description.jsx +0 -11
- package/src/core/lib/components/ui/card/card-footer.jsx +0 -11
- package/src/core/lib/components/ui/card/card-header.jsx +0 -19
- package/src/core/lib/components/ui/card/card-title.jsx +0 -11
- package/src/core/lib/components/ui/card/card.jsx +0 -17
- package/src/core/lib/components/ui/card/index.js +0 -25
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/index.js +0 -13
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +0 -7
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +0 -23
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +0 -11
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +0 -4
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +0 -15
- package/src/core/lib/components/ui/popover/index.js +0 -28
- package/src/core/lib/components/ui/popover/popover-close.jsx +0 -7
- package/src/core/lib/components/ui/popover/popover-content.jsx +0 -22
- package/src/core/lib/components/ui/popover/popover-description.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-header.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-portal.jsx +0 -4
- package/src/core/lib/components/ui/popover/popover-title.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +0 -8
- package/src/core/lib/components/ui/popover/popover.jsx +0 -4
- package/src/core/lib/components/ui/select/index.js +0 -37
- package/src/core/lib/components/ui/select/select-content.jsx +0 -30
- package/src/core/lib/components/ui/select/select-group-heading.jsx +0 -17
- package/src/core/lib/components/ui/select/select-group.jsx +0 -15
- package/src/core/lib/components/ui/select/select-item.jsx +0 -26
- package/src/core/lib/components/ui/select/select-label.jsx +0 -11
- package/src/core/lib/components/ui/select/select-portal.jsx +0 -4
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-separator.jsx +0 -15
- package/src/core/lib/components/ui/select/select-trigger.jsx +0 -25
- package/src/core/lib/components/ui/select/select.jsx +0 -4
- package/src/core/lib/components/ui/sheet/index.js +0 -34
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +0 -35
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +0 -4
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet.jsx +0 -4
- package/src/core/lib/components/ui/toggle/index.js +0 -8
- package/src/core/lib/components/ui/toggle/toggle.jsx +0 -36
- package/src/core/lib/components/ui/toggle-group/index.js +0 -10
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +0 -29
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +0 -43
- package/src/internals/canvas/StoryErrorBoundary.jsx +0 -47
- package/src/internals/canvas/WebGLContextPool.jsx +0 -291
- package/src/internals/canvas/WebGLContextPool.test.jsx +0 -165
- package/src/internals/canvas/componentIsolate.jsx +0 -144
- package/src/internals/canvas/componentSetIsolate.jsx +0 -300
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +0 -89
- package/src/internals/canvas/widgets/InlineStoryRenderer.jsx +0 -129
- package/src/internals/canvas/widgets/InlineStoryRenderer.test.jsx +0 -68
- package/src/internals/canvas/widgets/StorySetWidget.module.css +0 -89
- package/src/primer/ThemeSync.jsx +0 -73
- package/src/primer/index.js +0 -1
package/src/canvas/style.css
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/* tiny-canvas styles */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
-
--tc-border-radius: var(--
|
|
5
|
-
--tc-shadow-rest: var(--shadow-resting
|
|
6
|
-
--tc-shadow-float: var(--shadow-floating
|
|
7
|
-
--tc-border-color: var(--
|
|
8
|
-
--tc-bg-muted: var(--
|
|
9
|
-
--tc-dot-color: var(--overlay-backdrop
|
|
4
|
+
--tc-border-radius: var(--radius, 12px);
|
|
5
|
+
--tc-shadow-rest: var(--shadow-resting, 0 1px 3px rgba(0, 0, 0, 0.12));
|
|
6
|
+
--tc-shadow-float: var(--shadow-floating, 0 4px 12px rgba(0, 0, 0, 0.15));
|
|
7
|
+
--tc-border-color: var(--color-border-muted, rgba(0, 0, 0, 0.15));
|
|
8
|
+
--tc-bg-muted: var(--color-background-muted, #f6f8fa);
|
|
9
|
+
--tc-dot-color: var(--color-overlay-backdrop, rgba(0, 0, 0, 0.08));
|
|
10
10
|
--tc-grid-size: var(--golden-number, 36px);
|
|
11
11
|
--tc-grid-offset: calc(var(--tc-grid-size) / -2);
|
|
12
12
|
--tc-dot-radius: 2px;
|
|
@@ -46,22 +46,22 @@
|
|
|
46
46
|
|
|
47
47
|
@media (prefers-color-scheme: dark) {
|
|
48
48
|
.tc-canvas:not([data-color-mode="light"]) {
|
|
49
|
-
--tc-bg-muted: var(--
|
|
50
|
-
--tc-dot-color: var(--overlay-backdrop
|
|
51
|
-
--tc-border-color: var(--
|
|
52
|
-
--tc-shadow-rest: var(--shadow-resting
|
|
53
|
-
--tc-shadow-float: var(--shadow-floating
|
|
49
|
+
--tc-bg-muted: var(--color-background-muted, #161b22);
|
|
50
|
+
--tc-dot-color: var(--color-overlay-backdrop, rgba(255, 255, 255, 0.1));
|
|
51
|
+
--tc-border-color: var(--color-border-muted, rgba(255, 255, 255, 0.15));
|
|
52
|
+
--tc-shadow-rest: var(--shadow-resting, 0 1px 3px rgba(0, 0, 0, 0.3));
|
|
53
|
+
--tc-shadow-float: var(--shadow-floating, 0 4px 12px rgba(0, 0, 0, 0.4));
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/* Dark mode — explicit override */
|
|
58
58
|
|
|
59
59
|
.tc-canvas[data-color-mode="dark"] {
|
|
60
|
-
--tc-bg-muted: var(--
|
|
61
|
-
--tc-dot-color: var(--overlay-backdrop
|
|
62
|
-
--tc-border-color: var(--
|
|
63
|
-
--tc-shadow-rest: var(--shadow-resting
|
|
64
|
-
--tc-shadow-float: var(--shadow-floating
|
|
60
|
+
--tc-bg-muted: var(--color-background-muted, #161b22);
|
|
61
|
+
--tc-dot-color: var(--color-overlay-backdrop, rgba(255, 255, 255, 0.1));
|
|
62
|
+
--tc-border-color: var(--color-border-muted, rgba(255, 255, 255, 0.15));
|
|
63
|
+
--tc-shadow-rest: var(--shadow-resting, 0 1px 3px rgba(0, 0, 0, 0.3));
|
|
64
|
+
--tc-shadow-float: var(--shadow-floating, 0 4px 12px rgba(0, 0, 0, 0.4));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/* Draggable */
|
|
@@ -128,8 +128,6 @@ function createPrototype(values, root) {
|
|
|
128
128
|
? path.join(prototypesDir, `${values.folder}.folder`, values.name)
|
|
129
129
|
: path.join(prototypesDir, values.name)
|
|
130
130
|
|
|
131
|
-
fs.mkdirSync(targetDir, { recursive: true })
|
|
132
|
-
|
|
133
131
|
const files = []
|
|
134
132
|
const relDir = path.relative(root, targetDir)
|
|
135
133
|
|
|
@@ -148,6 +146,22 @@ function createPrototype(values, root) {
|
|
|
148
146
|
return { success: false, errors: [{ message: partialError }] }
|
|
149
147
|
}
|
|
150
148
|
|
|
149
|
+
// Pre-resolve the partial's component file *before* writing anything.
|
|
150
|
+
// If the partial's template/recipe directory is missing or empty we'd
|
|
151
|
+
// otherwise leave an orphan .prototype.json on disk and Vite would
|
|
152
|
+
// then try (and fail) to lazy-load a non-existent index.jsx. Validate
|
|
153
|
+
// first, write second.
|
|
154
|
+
let componentFile = null
|
|
155
|
+
if (partialEntry && !values.url) {
|
|
156
|
+
const partialDir = path.join(root, 'src', partialEntry.baseDir, partialEntry.name)
|
|
157
|
+
componentFile = findComponentFile(partialDir)
|
|
158
|
+
if (!componentFile) {
|
|
159
|
+
return { success: false, errors: [{ message: `No .jsx or .tsx file found in src/${partialEntry.baseDir}/${partialEntry.name}/` }] }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
164
|
+
|
|
151
165
|
// Write .prototype.json (with $global from partial when applicable)
|
|
152
166
|
const protoFile = `${values.name}.prototype.json`
|
|
153
167
|
const protoBody = JSON.parse(prototypeJson(values))
|
|
@@ -159,22 +173,14 @@ function createPrototype(values, root) {
|
|
|
159
173
|
|
|
160
174
|
// Write index.jsx (only for non-external prototypes)
|
|
161
175
|
if (!values.url) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const partialDir = path.join(root, 'src', partialEntry.baseDir, partialEntry.name)
|
|
165
|
-
const componentFile = findComponentFile(partialDir)
|
|
166
|
-
if (!componentFile) {
|
|
167
|
-
return { success: false, errors: [{ message: `No .jsx or .tsx file found in src/${partialEntry.baseDir}/${partialEntry.name}/` }] }
|
|
168
|
-
}
|
|
169
|
-
body = renderPartialIndexJsx({
|
|
176
|
+
const body = partialEntry
|
|
177
|
+
? renderPartialIndexJsx({
|
|
170
178
|
partialEntry,
|
|
171
179
|
componentFile,
|
|
172
180
|
componentName: toPascalCase(values.name),
|
|
173
181
|
title: values.title || values.name,
|
|
174
182
|
})
|
|
175
|
-
|
|
176
|
-
body = prototypeIndexJsx(values.name)
|
|
177
|
-
}
|
|
183
|
+
: prototypeIndexJsx(values.name)
|
|
178
184
|
fs.writeFileSync(path.join(targetDir, 'index.jsx'), body, 'utf-8')
|
|
179
185
|
files.push(`${relDir}/index.jsx`)
|
|
180
186
|
}
|
|
@@ -191,7 +197,30 @@ function createPrototype(values, root) {
|
|
|
191
197
|
|
|
192
198
|
function createCanvas(values, root) {
|
|
193
199
|
const canvasDir = path.join(root, 'src', 'canvas')
|
|
194
|
-
|
|
200
|
+
|
|
201
|
+
// Folder resolution mirrors the canvas-server /create endpoint:
|
|
202
|
+
// - if folder is empty → write at root
|
|
203
|
+
// - if <folder>.folder/ exists → use it (workspace grouping)
|
|
204
|
+
// - if <folder>/ exists → use it (multi-page grouping)
|
|
205
|
+
// - otherwise create a new dir per `folderKind`
|
|
206
|
+
// ("workspace" → .folder/, default "pages" → plain dir)
|
|
207
|
+
let targetDir = canvasDir
|
|
208
|
+
let usedFolderKind = null
|
|
209
|
+
if (values.folder) {
|
|
210
|
+
const dotFolderDir = path.join(canvasDir, `${values.folder}.folder`)
|
|
211
|
+
const plainDir = path.join(canvasDir, values.folder)
|
|
212
|
+
if (fs.existsSync(dotFolderDir)) {
|
|
213
|
+
targetDir = dotFolderDir
|
|
214
|
+
usedFolderKind = 'workspace'
|
|
215
|
+
} else if (fs.existsSync(plainDir) && fs.statSync(plainDir).isDirectory()) {
|
|
216
|
+
targetDir = plainDir
|
|
217
|
+
usedFolderKind = 'pages'
|
|
218
|
+
} else {
|
|
219
|
+
const useWorkspace = values.folderKind === 'workspace'
|
|
220
|
+
targetDir = useWorkspace ? dotFolderDir : plainDir
|
|
221
|
+
usedFolderKind = useWorkspace ? 'workspace' : 'pages'
|
|
222
|
+
}
|
|
223
|
+
}
|
|
195
224
|
fs.mkdirSync(targetDir, { recursive: true })
|
|
196
225
|
|
|
197
226
|
const files = []
|
|
@@ -212,8 +241,18 @@ function createCanvas(values, root) {
|
|
|
212
241
|
files.push(path.relative(root, path.join(targetDir, jsxFile)))
|
|
213
242
|
}
|
|
214
243
|
|
|
244
|
+
// Route always strips `.folder/` (per the data plugin), so both kinds
|
|
245
|
+
// produce the same `/canvas/<folder>/<name>` URL shape.
|
|
215
246
|
const canvasRoute = `/canvas/${values.folder ? `${values.folder}/` : ''}${values.name}`
|
|
216
|
-
return {
|
|
247
|
+
return {
|
|
248
|
+
success: true,
|
|
249
|
+
type: 'canvas',
|
|
250
|
+
name: values.name,
|
|
251
|
+
path: path.relative(root, targetDir),
|
|
252
|
+
route: canvasRoute,
|
|
253
|
+
folderKind: usedFolderKind,
|
|
254
|
+
files,
|
|
255
|
+
}
|
|
217
256
|
}
|
|
218
257
|
|
|
219
258
|
function createComponent(values, root) {
|
|
@@ -19,7 +19,13 @@
|
|
|
19
19
|
},
|
|
20
20
|
"folder": {
|
|
21
21
|
"type": "string",
|
|
22
|
-
"description": "Parent folder directory"
|
|
22
|
+
"description": "Parent folder directory (name only — no .folder suffix). If the folder already exists, its kind wins; otherwise `folderKind` decides whether to create a workspace folder (.folder/) or a multi-page canvas group (plain dir)."
|
|
23
|
+
},
|
|
24
|
+
"folderKind": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"enum": ["workspace", "pages"],
|
|
27
|
+
"default": "pages",
|
|
28
|
+
"description": "When `folder` is set and doesn't yet exist: `workspace` creates `<folder>.folder/` (each canvas appears under a workspace folder header), `pages` creates a plain `<folder>/` dir (canvases become pages of a shared multi-page group). Ignored when the folder already exists."
|
|
23
29
|
},
|
|
24
30
|
"grid": {
|
|
25
31
|
"type": "boolean",
|
|
@@ -21,7 +21,7 @@ describe('autosync scope helpers', () => {
|
|
|
21
21
|
expect(matchesAutosyncScope('canvas', 'src/canvas/notes.txt')).toBe(true)
|
|
22
22
|
expect(matchesAutosyncScope('canvas', 'assets/canvas/images/photo.png')).toBe(true)
|
|
23
23
|
expect(matchesAutosyncScope('canvas', 'assets/canvas/snapshots/snapshot-widget--latest.webp')).toBe(true)
|
|
24
|
-
expect(matchesAutosyncScope('canvas', 'assets/.storyboard-public/terminal-snapshots/
|
|
24
|
+
expect(matchesAutosyncScope('canvas', 'assets/.storyboard-public/terminal-snapshots/agents.snapshot.json')).toBe(true)
|
|
25
25
|
expect(matchesAutosyncScope('canvas', 'src/prototypes/demo/default.flow.json')).toBe(false)
|
|
26
26
|
})
|
|
27
27
|
|
|
@@ -82,7 +82,6 @@ export class HotPool {
|
|
|
82
82
|
#healthTimer = null
|
|
83
83
|
#prereqsAvailable = null
|
|
84
84
|
#wsSend = null
|
|
85
|
-
#webglReadySlots = 0
|
|
86
85
|
|
|
87
86
|
// Agent config (null for bare shell pools)
|
|
88
87
|
#agentConfig = null
|
|
@@ -110,7 +109,6 @@ export class HotPool {
|
|
|
110
109
|
this.#loadBalancer = config.load_balancer !== false
|
|
111
110
|
this.#wsSend = wsSend
|
|
112
111
|
this.#agentConfig = agentConfig
|
|
113
|
-
this.#webglReadySlots = Math.max(0, config.webgl_ready_slots ?? 0)
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
get poolId() { return this.#poolId }
|
|
@@ -169,17 +167,16 @@ export class HotPool {
|
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
/**
|
|
172
|
-
* Non-mutating probe: would the next acquire() return a session
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
170
|
+
* Non-mutating probe: would the next acquire() return a session? Used by
|
|
171
|
+
* callers that want to know whether to render in hot mode without claiming
|
|
172
|
+
* a slot (the actual claim happens later when the WS connects).
|
|
173
|
+
* Returns { ready }.
|
|
176
174
|
*/
|
|
177
175
|
peek() {
|
|
178
|
-
if (!this.#enabled || this.#queue.length === 0) return { ready: false
|
|
176
|
+
if (!this.#enabled || this.#queue.length === 0) return { ready: false }
|
|
179
177
|
const idx = this.#queue.findIndex(s => s.state === 'ready')
|
|
180
|
-
if (idx === -1) return { ready: false
|
|
181
|
-
|
|
182
|
-
return { ready: true, webglReady }
|
|
178
|
+
if (idx === -1) return { ready: false }
|
|
179
|
+
return { ready: true }
|
|
183
180
|
}
|
|
184
181
|
|
|
185
182
|
acquire() {
|
|
@@ -193,12 +190,8 @@ export class HotPool {
|
|
|
193
190
|
return null
|
|
194
191
|
}
|
|
195
192
|
|
|
196
|
-
// Session is WebGL-ready if its queue position was within webgl_ready_slots
|
|
197
|
-
const webglReady = this.#webglReadySlots > 0 && idx < this.#webglReadySlots
|
|
198
|
-
|
|
199
193
|
const session = this.#queue.splice(idx, 1)[0]
|
|
200
194
|
session.state = 'acquired'
|
|
201
|
-
session.webglReady = webglReady
|
|
202
195
|
this.#acquired.set(session.id, session)
|
|
203
196
|
const age = ((Date.now() - session.createdAt) / 1000).toFixed(1)
|
|
204
197
|
const readyCount = this.#queue.filter(s => s.state === 'ready').length
|
|
@@ -206,10 +199,10 @@ export class HotPool {
|
|
|
206
199
|
// Scale-up: queue drained to 0 ready → enter pressure mode
|
|
207
200
|
if (readyCount === 0 && !this.#pressured) {
|
|
208
201
|
this.#pressured = true
|
|
209
|
-
this.#log(`→ ACQUIRED ${session.id} tmux=${session.tmuxName} (age: ${age}s
|
|
202
|
+
this.#log(`→ ACQUIRED ${session.id} tmux=${session.tmuxName} (age: ${age}s) — ⚡ PRESSURE ON (scaling to max_pool_size=${this.#maxPoolSize})`)
|
|
210
203
|
this.#resetCooldown()
|
|
211
204
|
} else {
|
|
212
|
-
this.#log(`→ ACQUIRED ${session.id} tmux=${session.tmuxName} (age: ${age}s,
|
|
205
|
+
this.#log(`→ ACQUIRED ${session.id} tmux=${session.tmuxName} (age: ${age}s, queue: ${readyCount}/${this.#fillTarget})`)
|
|
213
206
|
this.#resetCooldown()
|
|
214
207
|
}
|
|
215
208
|
|
|
@@ -273,7 +266,6 @@ export class HotPool {
|
|
|
273
266
|
load_balancer: this.#loadBalancer,
|
|
274
267
|
load_balancer_cooldown_mins: this.#cooldownMs / 60_000,
|
|
275
268
|
verbose: this.#verbose,
|
|
276
|
-
webgl_ready_slots: this.#webglReadySlots,
|
|
277
269
|
},
|
|
278
270
|
agentConfig: this.#agentConfig ? {
|
|
279
271
|
startupCommand: this.#agentConfig.startupCommand,
|
|
@@ -294,7 +286,6 @@ export class HotPool {
|
|
|
294
286
|
if (config.max_pool_size !== undefined) this.#maxPoolSize = Math.max(0, config.max_pool_size)
|
|
295
287
|
if (config.load_balancer_cooldown_mins !== undefined) this.#cooldownMs = config.load_balancer_cooldown_mins * 60_000
|
|
296
288
|
if (config.load_balancer !== undefined) this.#loadBalancer = !!config.load_balancer
|
|
297
|
-
if (config.webgl_ready_slots !== undefined) this.#webglReadySlots = Math.max(0, config.webgl_ready_slots)
|
|
298
289
|
const newSize = Math.min(Math.max(0, config.pool_size ?? this.#poolSize), this.#maxPoolSize)
|
|
299
290
|
const newEnabled = config.enabled !== false
|
|
300
291
|
if (config.verbose !== undefined) this.#verbose = !!config.verbose
|
|
@@ -551,8 +542,8 @@ export class HotPool {
|
|
|
551
542
|
const paneContent = execSync(
|
|
552
543
|
// H1: include scrollback so the readiness echo can still be
|
|
553
544
|
// matched after the agent's TUI repaints over it.
|
|
554
|
-
`tmux capture-pane -t "${tmuxName}" -p -S -200`,
|
|
555
|
-
{ encoding: 'utf8', timeout: 1000 }
|
|
545
|
+
`tmux capture-pane -t "${tmuxName}" -p -S -200 2>/dev/null`,
|
|
546
|
+
{ encoding: 'utf8', timeout: 1000, stdio: ['ignore', 'pipe', 'ignore'] }
|
|
556
547
|
)
|
|
557
548
|
// Strip ANSI escape sequences — agent CLIs use heavy formatting
|
|
558
549
|
// eslint-disable-next-line no-control-regex
|
|
@@ -580,14 +571,13 @@ export class HotPool {
|
|
|
580
571
|
return this.#tmuxSessionExists(tmuxName)
|
|
581
572
|
}
|
|
582
573
|
|
|
583
|
-
//
|
|
574
|
+
// postStartup is NOT sent here intentionally. It's deferred to widget
|
|
575
|
+
// handoff (see terminal-server.js warm path) so it runs *after* the
|
|
576
|
+
// identity/role injection — mode-toggling slash commands like
|
|
577
|
+
// `/autopilot` must come last so canvas context lands in conversation
|
|
578
|
+
// history before the agent enters autopilot mode.
|
|
584
579
|
if (postStartup) {
|
|
585
|
-
|
|
586
|
-
await new Promise(r => setTimeout(r, 500))
|
|
587
|
-
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(postStartup)}`, { stdio: 'ignore' })
|
|
588
|
-
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
589
|
-
this.#log(`⊕ AGENT ${sessionId} postStartup sent: ${postStartup}`)
|
|
590
|
-
} catch { /* empty */ }
|
|
580
|
+
this.#log(`⊕ AGENT ${sessionId} postStartup "${postStartup}" deferred to widget handoff`)
|
|
591
581
|
}
|
|
592
582
|
|
|
593
583
|
this.#log(`⊕ AGENT ${sessionId} ready (${signalFilePath ? 'file' : 'signal'}: "${readinessSignal || 'file'}")`)
|
|
@@ -615,8 +605,8 @@ export class HotPool {
|
|
|
615
605
|
if (this.#agentConfig?.startupCommand) {
|
|
616
606
|
try {
|
|
617
607
|
const cmd = execSync(
|
|
618
|
-
`tmux display-message -t "${session.tmuxName}" -p "#{pane_current_command}"`,
|
|
619
|
-
{ encoding: 'utf8', timeout: 1000 }
|
|
608
|
+
`tmux display-message -t "${session.tmuxName}" -p "#{pane_current_command}" 2>/dev/null`,
|
|
609
|
+
{ encoding: 'utf8', timeout: 1000, stdio: ['ignore', 'pipe', 'ignore'] }
|
|
620
610
|
).trim()
|
|
621
611
|
// Agent exited if the pane is back to a shell
|
|
622
612
|
const shells = ['zsh', 'bash', 'sh', 'fish']
|
|
@@ -707,7 +697,6 @@ export class HotPoolManager {
|
|
|
707
697
|
load_balancer: config.load_balancer !== false,
|
|
708
698
|
enabled: this.#enabled,
|
|
709
699
|
verbose: !!config.verbose,
|
|
710
|
-
webgl_ready_slots: poolsConfig[poolId]?.webgl_ready_slots ?? 0,
|
|
711
700
|
})
|
|
712
701
|
|
|
713
702
|
// Terminal pool (bare shells)
|
|
@@ -772,10 +761,10 @@ export class HotPoolManager {
|
|
|
772
761
|
return pool.acquire()
|
|
773
762
|
}
|
|
774
763
|
|
|
775
|
-
/** Non-mutating probe: { ready
|
|
764
|
+
/** Non-mutating probe: { ready } for the specified pool. */
|
|
776
765
|
peek(poolId) {
|
|
777
766
|
const pool = this.#pools.get(poolId)
|
|
778
|
-
if (!pool) return { ready: false
|
|
767
|
+
if (!pool) return { ready: false }
|
|
779
768
|
return pool.peek()
|
|
780
769
|
}
|
|
781
770
|
|
|
@@ -819,7 +808,6 @@ export class HotPoolManager {
|
|
|
819
808
|
load_balancer: config.load_balancer,
|
|
820
809
|
enabled: config.enabled,
|
|
821
810
|
verbose: config.verbose,
|
|
822
|
-
webgl_ready_slots: poolsConfig[id]?.webgl_ready_slots,
|
|
823
811
|
}
|
|
824
812
|
pool.reconfigure(poolConfig)
|
|
825
813
|
}
|
|
@@ -7,17 +7,36 @@
|
|
|
7
7
|
* Event types:
|
|
8
8
|
* canvas_created — full initial state (first line)
|
|
9
9
|
* widget_added — append a widget
|
|
10
|
-
* widget_updated — patch widget props
|
|
11
|
-
* widget_moved — update widget position
|
|
12
|
-
* widget_removed — remove a widget by id
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* widget_updated — patch widget props (may carry `prevProps` for undo)
|
|
11
|
+
* widget_moved — update widget position (may carry `prevPosition` for undo)
|
|
12
|
+
* widget_removed — remove a widget by id (carries `widget` for undo;
|
|
13
|
+
* legacy events only had `widgetId`)
|
|
14
|
+
* settings_updated — patch canvas-level settings (may carry `prevSettings` for undo)
|
|
15
|
+
* source_updated — replace the sources array (may carry `prevSources` for undo)
|
|
16
|
+
* widgets_replaced — replace the entire widgets array (compaction only, not undoable)
|
|
16
17
|
* connector_added — append a connector between two widgets
|
|
17
|
-
* connector_removed — remove a connector by id
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* connector_removed — remove a connector by id (carries `connector` for undo;
|
|
19
|
+
* legacy events only had `connectorId`)
|
|
20
|
+
* connectors_replaced — replace the entire connectors array (compaction only, not undoable)
|
|
21
|
+
* connector_waypoints_set — set/replace manual routing waypoints (may carry `prevWaypoints`)
|
|
22
|
+
* connector_waypoints_cleared — drop manual routing (may carry `prevWaypoints`)
|
|
23
|
+
* connector_updated — patch connector anchors/meta (may carry `prevUpdates` for undo)
|
|
24
|
+
*
|
|
25
|
+
* Event metadata (all events):
|
|
26
|
+
* id — short random id stamped by the server, used by undo/redo
|
|
27
|
+
* to target a specific event. Legacy events without an id are
|
|
28
|
+
* non-undoable but materialize normally.
|
|
29
|
+
* meta.kind — present on undo/redo emissions ('undo' | 'redo'). The
|
|
30
|
+
* materializer ignores meta; it's informational for tools
|
|
31
|
+
* and a future timeline UI.
|
|
32
|
+
* meta.of — the id of the event this undo/redo targets.
|
|
33
|
+
*
|
|
34
|
+
* Undo model: the materializer never "skips" events. Undo is a normal
|
|
35
|
+
* forward event (a real `widget_added`/`widget_removed`/`widget_updated`)
|
|
36
|
+
* that happens to carry meta.kind === 'undo'. Folding is one pass, no
|
|
37
|
+
* special cases. Inverse payloads (`prevProps`, `prevPosition`, full
|
|
38
|
+
* `widget`/`connector` on removes, etc.) are read only by the server's
|
|
39
|
+
* POST /undo and POST /redo endpoints when computing the inverse event.
|
|
21
40
|
*/
|
|
22
41
|
|
|
23
42
|
/**
|
|
@@ -134,13 +153,16 @@ export function materialize(events) {
|
|
|
134
153
|
}
|
|
135
154
|
|
|
136
155
|
case 'widget_removed': {
|
|
156
|
+
// Back-compat: legacy events only had `widgetId`; new events carry
|
|
157
|
+
// the full `widget` object so undo can re-add without history walk.
|
|
158
|
+
const removedId = evt.widget?.id ?? evt.widgetId
|
|
137
159
|
state.widgets = (state.widgets || []).filter(
|
|
138
|
-
(w) => w.id !==
|
|
160
|
+
(w) => w.id !== removedId,
|
|
139
161
|
)
|
|
140
162
|
// Cascade: remove connectors referencing the deleted widget
|
|
141
163
|
if (state.connectors?.length) {
|
|
142
164
|
state.connectors = state.connectors.filter(
|
|
143
|
-
(c) => c.start.widgetId !==
|
|
165
|
+
(c) => c.start.widgetId !== removedId && c.end.widgetId !== removedId,
|
|
144
166
|
)
|
|
145
167
|
}
|
|
146
168
|
break
|
|
@@ -179,8 +201,12 @@ export function materialize(events) {
|
|
|
179
201
|
}
|
|
180
202
|
|
|
181
203
|
case 'connector_removed': {
|
|
204
|
+
// Back-compat: legacy events only had `connectorId`; new events
|
|
205
|
+
// carry the full `connector` object so undo can re-add without
|
|
206
|
+
// history walk.
|
|
207
|
+
const removedId = evt.connector?.id ?? evt.connectorId
|
|
182
208
|
state.connectors = (state.connectors || []).filter(
|
|
183
|
-
(c) => c.id !==
|
|
209
|
+
(c) => c.id !== removedId,
|
|
184
210
|
)
|
|
185
211
|
break
|
|
186
212
|
}
|
|
@@ -34,7 +34,7 @@ function createPathResolver(root) {
|
|
|
34
34
|
|
|
35
35
|
function scanFiles() {
|
|
36
36
|
const results = []
|
|
37
|
-
const ignore = new Set(['node_modules', 'dist', '.git', '.worktrees'])
|
|
37
|
+
const ignore = new Set(['node_modules', 'dist', '.git', '.worktrees', 'worktrees', 'workleafs'])
|
|
38
38
|
function walk(dir, rel) {
|
|
39
39
|
let entries
|
|
40
40
|
try { entries = fs.readdirSync(dir, { withFileTypes: true }) } catch { return }
|