@1agh/maude 0.28.1 → 0.30.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/README.md +3 -3
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -2
- package/apps/studio/annotations-align.ts +149 -0
- package/apps/studio/annotations-bindings.ts +197 -0
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +681 -151
- package/apps/studio/annotations-groups.ts +270 -0
- package/apps/studio/annotations-layer.tsx +4537 -0
- package/apps/studio/annotations-model.ts +2077 -0
- package/apps/studio/annotations-snap.ts +125 -0
- package/{plugins/design/dev-server → apps/studio}/api.ts +616 -70
- package/{plugins/design/dev-server → apps/studio}/artboard-activity-overlay.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_motion-sample-playwright.mjs +129 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_png-playwright.mjs +1 -1
- package/apps/studio/bin/annotate.mjs +732 -0
- package/apps/studio/bin/annotate.sh +17 -0
- package/{plugins/design/dev-server → apps/studio}/bin/canvas-edit.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/draw-proof.sh +37 -2
- package/{plugins/design/dev-server → apps/studio}/bin/preflight.sh +1 -1
- package/apps/studio/bin/read-annotations.mjs +573 -0
- package/apps/studio/bin/read-annotations.sh +11 -0
- package/{plugins/design/dev-server → apps/studio}/bin/runtime-health.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/screenshot.sh +62 -2
- package/{plugins/design/dev-server → apps/studio}/bin/server-up.sh +9 -3
- package/apps/studio/bin/to-lottie-verify.html +68 -0
- package/apps/studio/bin/to-lottie.sh +128 -0
- package/{plugins/design/dev-server → apps/studio}/build.ts +6 -4
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +79 -10
- package/{plugins/design/dev-server → apps/studio}/canvas-comment-mount.tsx +1 -1
- package/apps/studio/canvas-create.ts +104 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-cursors.ts +48 -12
- package/{plugins/design/dev-server → apps/studio}/canvas-edit.ts +257 -7
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +165 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-inline.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-resolver.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib.tsx +31 -12
- package/{plugins/design/dev-server → apps/studio}/canvas-shell.tsx +360 -48
- package/apps/studio/client/app.jsx +6742 -0
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/apps/studio/client/index.html +16 -0
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +1161 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/3-shell.css +129 -0
- package/apps/studio/client/styles/4-components-maude.css +74 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/4-components.css +396 -34
- package/apps/studio/client/styles/5-maude-overrides.css +137 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/_index.css +9 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles.css +1 -1
- package/apps/studio/client/tour/overlay.jsx +279 -0
- package/apps/studio/client/tour/usage-tour.js +48 -0
- package/apps/studio/client/whats-new-seen.js +52 -0
- package/apps/studio/client/whats-new.jsx +250 -0
- package/{plugins/design/dev-server → apps/studio}/commands/annotation-strokes-command.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/commands/equal-spacing-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/move-artboards-command.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +32 -11
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +5 -4
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +18 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +21 -21
- package/apps/studio/dist/client.bundle.js +25545 -0
- package/apps/studio/dist/comment-mount.js +2046 -0
- package/apps/studio/dist/styles.css +8018 -0
- package/apps/studio/dom-selection.ts +342 -0
- package/apps/studio/draw/animate.ts +333 -0
- package/{plugins/design/dev-server → apps/studio}/draw/brush.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/composition.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/geometry.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/index.ts +4 -1
- package/{plugins/design/dev-server → apps/studio}/draw/layout.ts +1 -1
- package/apps/studio/draw/morph.ts +204 -0
- package/{plugins/design/dev-server → apps/studio}/draw/optimize.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/palette.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/primitives.ts +1 -1
- package/apps/studio/draw/serialize-animate.ts +324 -0
- package/{plugins/design/dev-server → apps/studio}/draw/serialize.ts +9 -3
- package/apps/studio/draw/test/animate.test.ts +172 -0
- package/apps/studio/draw/test/morph.test.ts +107 -0
- package/apps/studio/draw/test/serialize-animate.test.ts +142 -0
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-detector.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-handles.tsx +7 -29
- package/{plugins/design/dev-server → apps/studio}/export-dialog.tsx +16 -4
- package/{plugins/design/dev-server → apps/studio}/history.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/http.ts +226 -6
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +15 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +50 -4
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +2 -8
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +23 -2
- package/{plugins/design/dev-server → apps/studio}/sync/agent.ts +231 -57
- package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +45 -0
- package/apps/studio/sync/cold-start.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/sync/connection-state.ts +58 -2
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +563 -221
- package/apps/studio/sync/journal.ts +190 -0
- package/apps/studio/sync/migrate-seed.ts +321 -0
- package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +22 -3
- package/{plugins/design/dev-server → apps/studio}/sync/status.ts +15 -4
- package/{plugins/design/dev-server → apps/studio}/test/activity.test.ts +1 -7
- package/apps/studio/test/annotate-write.test.ts +184 -0
- package/apps/studio/test/annotations-align.test.ts +88 -0
- package/apps/studio/test/annotations-bindings.test.ts +124 -0
- package/apps/studio/test/annotations-groups.test.ts +231 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-layer.test.ts +63 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-roundtrip.test.ts +97 -0
- package/apps/studio/test/annotations-snap.test.ts +79 -0
- package/apps/studio/test/annotations-text-format.test.ts +396 -0
- package/apps/studio/test/asset-api.test.ts +149 -0
- package/apps/studio/test/canvas-create-api.test.ts +361 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-cursors.test.ts +2 -0
- package/apps/studio/test/canvas-edit.test.ts +319 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-resolver.test.ts +1 -1
- package/apps/studio/test/canvas-media-drop.test.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-origin-gate.test.ts +25 -1
- package/apps/studio/test/canvas-url.test.ts +99 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-bridge.test.ts +0 -2
- package/{plugins/design/dev-server → apps/studio}/test/collab-room.test.ts +2 -7
- package/{plugins/design/dev-server → apps/studio}/test/csp-canvas-shell.test.ts +5 -0
- package/apps/studio/test/csrf-write-guard.test.ts +52 -0
- package/apps/studio/test/figjam-v3-model.test.ts +342 -0
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +1 -0
- package/apps/studio/test/index-data-canvas-ds.test.ts +97 -0
- package/apps/studio/test/motion-sample.test.ts +35 -0
- package/{plugins/design/dev-server → apps/studio}/test/perf-harness.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/phase-3.6-smoke.test.ts +3 -1
- package/apps/studio/test/read-annotations.test.ts +409 -0
- package/{plugins/design/dev-server → apps/studio}/test/sanitize-annotation-svg.test.ts +108 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-convergence.test.ts +1 -1
- package/apps/studio/test/shared-doc-migrate.test.ts +369 -0
- package/apps/studio/test/sync-agent.test.ts +575 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-codec.test.ts +65 -0
- package/apps/studio/test/sync-cold-start.test.ts +244 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.test.ts +68 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-hardening.test.ts +0 -8
- package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.test.ts +0 -1
- package/apps/studio/test/sync-incident-replay.test.ts +211 -0
- package/apps/studio/test/sync-journal.test.ts +176 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-runtime.test.ts +360 -5
- package/{plugins/design/dev-server → apps/studio}/test/sync-status.test.ts +66 -0
- package/apps/studio/test/tour-overlay.test.tsx +56 -0
- package/apps/studio/test/use-annotation-resize.test.ts +402 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-artboard-drag.test.ts +0 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-collab.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +8 -2
- package/apps/studio/test/whats-new.test.ts +101 -0
- package/apps/studio/text-imports.d.ts +9 -0
- package/{plugins/design/dev-server → apps/studio}/tool-palette.tsx +15 -70
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -2
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +5 -3
- package/apps/studio/use-annotation-resize.tsx +912 -0
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +17 -5
- package/{plugins/design/dev-server → apps/studio}/use-annotations-visibility.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-artboard-drag.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-canvas-activity.tsx +3 -3
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +21 -16
- package/{plugins/design/dev-server → apps/studio}/use-cursor-modifiers.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-keyboard-discipline.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/use-selection-set.tsx +18 -1
- package/{plugins/design/dev-server → apps/studio}/use-snap-guides.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-tool-mode.tsx +8 -2
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +1 -1
- package/apps/studio/whats-new.json +264 -0
- package/apps/studio/whats-new.schema.json +86 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design-link.test.mjs +84 -0
- package/cli/commands/design.mjs +16 -7
- package/cli/commands/design.test.mjs +40 -0
- package/cli/commands/help.mjs +8 -2
- package/cli/commands/hub.mjs +3 -3
- package/cli/commands/hub.test.mjs +1 -1
- package/cli/commands/scenario-report.mjs +2 -9
- package/cli/lib/design-link.mjs +51 -1
- package/cli/lib/flow-design-integration.test.mjs +1 -1
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/plugin-cli-reachability.test.mjs +8 -7
- package/cli/lib/preflight.mjs +1 -1
- package/package.json +15 -15
- package/plugins/design/templates/_shell.html +28 -4
- package/plugins/design/templates/brief-board.tsx.template +61 -0
- package/plugins/design/templates/canvas.tsx.template +1 -1
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +1 -1
- package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +1 -1
- package/plugins/flow/.claude-plugin/config.schema.json +16 -0
- package/plugins/design/dev-server/annotations-layer.tsx +0 -3402
- package/plugins/design/dev-server/client/app.jsx +0 -2985
- package/plugins/design/dev-server/client/index.html +0 -15
- package/plugins/design/dev-server/dist/client.bundle.js +0 -20692
- package/plugins/design/dev-server/dist/comment-mount.js +0 -1924
- package/plugins/design/dev-server/dist/styles.css +0 -2710
- package/plugins/design/dev-server/dom-selection.ts +0 -156
- package/plugins/design/dev-server/sync/migrate-seed.ts +0 -163
- package/plugins/design/dev-server/test/canvas-edit.test.ts +0 -139
- package/plugins/design/dev-server/test/shared-doc-migrate.test.ts +0 -159
- package/plugins/design/dev-server/test/sync-agent.test.ts +0 -305
- package/plugins/design/dev-server/test/use-annotation-resize.test.ts +0 -200
- package/plugins/design/dev-server/use-annotation-resize.tsx +0 -449
- /package/{plugins/design/dev-server → apps/studio}/activity.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_enumerate-artboards-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_html-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pdf-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pptx-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pw-launch.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_screenshot-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_svg-optimize.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_svg-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/asset-sweep.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/bootstrap-check.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/check-runtime-bundles.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/draw-build.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/handoff.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/prep.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/scenario-report.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/slug.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/smoke.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/svg-optimize.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/visual-sanity.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/boot-self-heal.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-build.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-header.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-meta.schema.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-pipeline.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/hmr.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/iframe-lazy.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/0-reset.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/1-tokens.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/2-layout.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/5-utilities.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/ai-activity.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/awareness-bridge.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/git-lifecycle.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/index.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/persistence.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/protocol.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/registry.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/room.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/config.schema.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/context.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/.min-sizes.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/lib0_decoding.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/lib0_encoding.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/motion.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/motion_react.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/pixi-js.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react-dom.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react-dom_client.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react_jsx-dev-runtime.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react_jsx-runtime.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/y-protocols_awareness.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/y-protocols_sync.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/yjs.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/brush.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/composition.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/geometry.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/gradient.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/layout.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/optimize.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/palette.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/primitives.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/serialize.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/examples/README.md +0 -0
- /package/{plugins/design/dev-server → apps/studio}/examples/perf-100-artboards.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/_browser-bundles.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/canva-handoff-prompt.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/canva.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/html.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/index.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/pdf.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/png.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/pptx.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/scope.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/svg.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/zip.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/fs-watch.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/handoff.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/hmr-broadcast.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/locator.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/mem.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/runtime-bundle.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/server.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/echo-guard.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/fs-mirror.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/hubs-config.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/materialize.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/untrusted.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/_helpers.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/active-state.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/ai-activity.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotation-strokes-command.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotations-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotations-draw-modifiers.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/artboard-activity-overlay.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/binary-smoke.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/boot-self-heal.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/bundle-smoke.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-build.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-header.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-hmr-runtime.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-inline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-motion.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-meta-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-pipeline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-route.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-annotations-bridge.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-awareness-bridge.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-loopback.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-protocol.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-reseed-guard.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-stress.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/comment-mount.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/comments-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/compile-entry.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/context-resolve-tokens.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/equal-spacing-detector.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/canva.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/endpoint.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/history.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/html.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pdf.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/png.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx-deck.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pw-launch.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/scope.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/svg.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/zip.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-20-annotations.svg +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-21-annotations.svg +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fs-watch.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/git-lifecycle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/handoff-static-frames.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/handoff.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/history-rollback.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/hmr-broadcast.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/hmr-classify.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/input-router.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/locator.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/marquee-overlay.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/move-artboards-command.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/participants-chrome.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/paths.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle-error-mapping.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/server-lifecycle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/shared-doc-foundation.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/shared-doc-projection.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/snap-distance-pill.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-atomic-write.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-echo-guard.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-fs-mirror.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-meta-codec.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-untrusted.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/system-endpoint.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/tool-palette.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/undo-stack.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-agent-presence.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-annotation-selection.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-canvas-activity.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-cursor-modifiers.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-keyboard-discipline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-selection-set.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-snap-guides.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-undo-stack.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/ws-handshake.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/tsconfig.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/ws.ts +0 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./whats-new.schema.json",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"id": "in-canvas-token-editor",
|
|
6
|
+
"version": "0.30.0",
|
|
7
|
+
"date": "2026-06-12",
|
|
8
|
+
"kind": "feature",
|
|
9
|
+
"title": "A real token editor, right in the canvas",
|
|
10
|
+
"summary": "The Inspector's CSS tab grew into a Figma-style design-token editor. Numeric fields carry a property glyph and scrub left/right to change; spacing fields take Webflow-style modifiers. Any value can bind to a design-system Variable through a searchable popover that shows where the token is defined — and it resolves the right system in multi-DS projects. One unified colour picker now drives every colour field, fill and border alike, with Custom and Variables tabs. Values you've set stand out while untouched rows recede, so the diff is scannable at a glance.",
|
|
11
|
+
"surface": "design-ui",
|
|
12
|
+
"tour": [
|
|
13
|
+
{
|
|
14
|
+
"target": "[data-tour='inspector-tabs']",
|
|
15
|
+
"inspector": true,
|
|
16
|
+
"tab": "css",
|
|
17
|
+
"title": "Inspect · Layers · CSS",
|
|
18
|
+
"body": "Here's the Inspector — opened to its CSS tab. It reads and writes your maude design system itself, not a generic :root. Three tabs: Inspect, Layers, CSS.",
|
|
19
|
+
"placement": "left"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"target": "[data-tour='css-panel']",
|
|
23
|
+
"inspector": true,
|
|
24
|
+
"tab": "css",
|
|
25
|
+
"requireSelection": true,
|
|
26
|
+
"title": "Your real element, live",
|
|
27
|
+
"body": "Hold ⌘ and click any element in the canvas. The CSS panel fills with its real, editable properties — and every change writes back to the source on blur, no AI round-trip.",
|
|
28
|
+
"placement": "left"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"target": ".st-cp-row",
|
|
32
|
+
"inspector": true,
|
|
33
|
+
"tab": "css",
|
|
34
|
+
"requireSelection": true,
|
|
35
|
+
"title": "Figma-style property rows",
|
|
36
|
+
"body": "Each row leads with a property glyph. Drag a numeric field left or right to scrub the value, or just type it; spacing fields accept Webflow-style modifiers.",
|
|
37
|
+
"placement": "left"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"target": ".st-cp-tokbtn",
|
|
41
|
+
"inspector": true,
|
|
42
|
+
"tab": "css",
|
|
43
|
+
"requireSelection": true,
|
|
44
|
+
"title": "Bind to a design token",
|
|
45
|
+
"body": "Click a field's token chip for the Variables popover — Custom for a literal, Variables for the design system's tokens. Search the list; each Variable shows its provenance. One unified colour picker drives every colour field, fill and border alike.",
|
|
46
|
+
"placement": "left"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"target": ".st-cp-sechd-row",
|
|
50
|
+
"inspector": true,
|
|
51
|
+
"tab": "css",
|
|
52
|
+
"requireSelection": true,
|
|
53
|
+
"title": "Scannable, resettable",
|
|
54
|
+
"body": "Values you've set stand out; untouched rows recede so the difference from the default reads at a glance. The leading dot on each row carries both its status and its reset.",
|
|
55
|
+
"placement": "left"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "in-canvas-direct-edit",
|
|
61
|
+
"version": "0.30.0",
|
|
62
|
+
"date": "2026-06-12",
|
|
63
|
+
"kind": "feature",
|
|
64
|
+
"title": "Edit the canvas directly — text & layers",
|
|
65
|
+
"summary": "Double-click any text to retype it in place — the new copy is written straight back to the source, no AI round-trip. The Layers tab is a browsable tree with type icons: click a layer to select it in the canvas, hover to highlight, and toggle any layer's visibility from its row. Together with the CSS token editor, small tweaks no longer need a command.",
|
|
66
|
+
"surface": "design-ui",
|
|
67
|
+
"tour": [
|
|
68
|
+
{
|
|
69
|
+
"target": "[data-tour='inspector-tabs']",
|
|
70
|
+
"inspector": true,
|
|
71
|
+
"tab": "layers",
|
|
72
|
+
"requireSelection": true,
|
|
73
|
+
"title": "Browsable layers",
|
|
74
|
+
"body": "⌘-click an element, then this Layers tab shows the artboard's elements as a tree with type icons — click a row to select it in the canvas, hover to highlight.",
|
|
75
|
+
"placement": "left"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"target": ".st-layer-eye",
|
|
79
|
+
"inspector": true,
|
|
80
|
+
"tab": "layers",
|
|
81
|
+
"requireSelection": true,
|
|
82
|
+
"title": "Toggle visibility",
|
|
83
|
+
"body": "The eye on each layer row hides or shows that element while you work — handy for seeing what sits underneath. Double-click any text in the canvas to retype it in place too.",
|
|
84
|
+
"placement": "left"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "studio-chrome-polished-end-to-end",
|
|
90
|
+
"version": "0.30.0",
|
|
91
|
+
"date": "2026-06-12",
|
|
92
|
+
"kind": "feature",
|
|
93
|
+
"title": "Studio chrome, polished end to end",
|
|
94
|
+
"summary": "The whole browser feels hand-finished now. Drag the file and inspector panels to resize them (or nudge with the arrow keys — your widths are remembered), watch a calm skeleton while a canvas compiles, and press ? for a full keyboard-shortcuts cheat sheet. Collaborator cursors and Claude's own cursor now match the design system, annotations snap to the dot grid as you drag, and focus rings, tooltips and scrollbars are consistent throughout. The View menu's Layers and Zoom are wired up, and a shortcut clash is gone — the inspector is ⌘⇧I, so I stays free for the canvas highlighter.",
|
|
95
|
+
"surface": "design-ui"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": "hub-sync-cold-start-safety",
|
|
99
|
+
"version": "0.30.0",
|
|
100
|
+
"date": "2026-06-12",
|
|
101
|
+
"kind": "feature",
|
|
102
|
+
"title": "Hub sync that can't eat your work",
|
|
103
|
+
"summary": "Boot two machines or checkouts linked to the same hub in any order — your local canvas work is safe. When both sides changed the same canvas, Maude keeps a copy of each, takes the newer one, and tells you exactly how to bring back the other; a clean catch-up just updates quietly. The sync status is honest now too: you can see which canvases are synced, pending, or rejected, and why.",
|
|
104
|
+
"surface": "design-ui"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"id": "canvas-annotations-figjam-v3",
|
|
108
|
+
"version": "0.30.0",
|
|
109
|
+
"date": "2026-06-12",
|
|
110
|
+
"kind": "feature",
|
|
111
|
+
"title": "Annotations grew up: diagram on the canvas",
|
|
112
|
+
"summary": "Marquee-select strokes and just drag them, group with ⌘G, copy/paste, align and reorder. Shapes rotate (hover near a corner), resize from edges with size-matching guides, hold text (double-click any shape), and switch kind — square, circle, diamond, triangle — right from the toolbar. Arrows snap to shapes and re-route as you move things, and the new Section tool (⇧S) frames a region that moves with its content. AI tools can read the board and draw on it too.",
|
|
113
|
+
"surface": "design-ui",
|
|
114
|
+
"tour": [
|
|
115
|
+
{
|
|
116
|
+
"target": ".dc-tool-palette",
|
|
117
|
+
"title": "New tools in the palette",
|
|
118
|
+
"body": "Section (⇧S) frames a region; the Shape tool's primitives can all hold text now — select a shape and press Enter to type."
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "studio-full-functionality",
|
|
124
|
+
"version": "0.29.0",
|
|
125
|
+
"date": "2026-06-08",
|
|
126
|
+
"kind": "feature",
|
|
127
|
+
"title": "The studio is fully wired now",
|
|
128
|
+
"summary": "Everything in the chrome is live: the top bar shows the real zoom + artboard count, the status bar always shows hub-sync, and your avatar (plus Claude when it's editing) appears in the menubar. The ⌘K palette grew real Canvas/Tools commands (New canvas, Export, Handoff, Draw), there's a proper Export & handoff dialog (PNG/PDF/SVG/HTML/shadcn/ZIP) right in the shell, and a new display-only Inspector panel (Inspect · Layers · CSS) reads any element you ⌘-click.",
|
|
129
|
+
"surface": "design-ui",
|
|
130
|
+
"tour": [
|
|
131
|
+
{
|
|
132
|
+
"target": "[data-tour='status']",
|
|
133
|
+
"title": "Live status, finally",
|
|
134
|
+
"body": "Zoom, artboard count, presence and hub-sync now reflect the real state — no more static placeholders.",
|
|
135
|
+
"placement": "bottom"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"target": "[data-tour='inspector']",
|
|
139
|
+
"inspector": true,
|
|
140
|
+
"title": "Inspector",
|
|
141
|
+
"body": "Opened from View → Inspector (I). ⌘-click an element to read its position, size, ancestry and markup — and now edit its CSS against your tokens, live.",
|
|
142
|
+
"placement": "left"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "draw-animation-lottie",
|
|
148
|
+
"version": "0.29.0",
|
|
149
|
+
"date": "2026-06-08",
|
|
150
|
+
"kind": "feature",
|
|
151
|
+
"title": "Animate draw marks → ship one Lottie",
|
|
152
|
+
"summary": "/design:draw now handles motion briefs (morph, pulse, blink) and proves the animation is actually live. /design:to-lottie productionizes it into one Lottie that plays 1:1 on web and React Native.",
|
|
153
|
+
"surface": "design-ui"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"id": "studio-maude-ds-redesign",
|
|
157
|
+
"version": "0.29.0",
|
|
158
|
+
"date": "2026-06-08",
|
|
159
|
+
"kind": "feature",
|
|
160
|
+
"title": "The studio, redesigned in maude",
|
|
161
|
+
"summary": "The canvas browser chrome is now built in the maude design system itself — a dark-first studio shell with a branded menubar + real dropdowns, a collapsible file-tree sidebar with a rail, a cohesive bottom context bar, a maude-styled comments panel, and a clean light handoff. New: a ⌘K command palette for jumping to the design-system view, comments, theme, reload, and help. The in-canvas chrome (tools, minimap, selection halos) was re-skinned to the same indigo accent so the whole surface reads as one product.",
|
|
162
|
+
"surface": "design-ui",
|
|
163
|
+
"tour": [
|
|
164
|
+
{
|
|
165
|
+
"target": "[data-tour='brand']",
|
|
166
|
+
"title": "Built in maude",
|
|
167
|
+
"body": "The studio chrome now dogfoods the maude DS — one cohesive material across the menubar, sidebar, canvas and status bar.",
|
|
168
|
+
"placement": "bottom"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"target": "[data-tour='menus']",
|
|
172
|
+
"title": "Press ⌘K",
|
|
173
|
+
"body": "A command palette jumps you to the design-system view, comments, theme toggle, reload, and help — no mouse needed.",
|
|
174
|
+
"placement": "bottom"
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"id": "annotation-tooling-polish",
|
|
180
|
+
"version": "0.29.0",
|
|
181
|
+
"date": "2026-06-08",
|
|
182
|
+
"kind": "improvement",
|
|
183
|
+
"title": "Richer annotations — highlighter, lists & text shortcuts",
|
|
184
|
+
"summary": "Annotations got a full polish pass: a new highlighter tool (translucent marker with multiply blend), dashed strokes on shapes, FigJam-style sticky corner, multi-line text with Enter, italic/underline/lists, and Cmd+B/I/U formatting shortcuts that work the same way in sticky notes, shapes, and the text tool.",
|
|
185
|
+
"surface": "design-ui",
|
|
186
|
+
"tour": [
|
|
187
|
+
{
|
|
188
|
+
"target": "[data-tour='viewport']",
|
|
189
|
+
"canvas": true,
|
|
190
|
+
"title": "New: Highlighter",
|
|
191
|
+
"body": "Open a canvas and press P to enter annotate mode, then pick the Highlighter from the toolbar — a translucent marker whose overlapping strokes darken with multiply blend. Sticky notes, shapes and text all take Cmd+B/I/U too.",
|
|
192
|
+
"placement": "auto"
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"id": "canvas-media-images-links",
|
|
198
|
+
"version": "0.29.0",
|
|
199
|
+
"date": "2026-06-08",
|
|
200
|
+
"kind": "feature",
|
|
201
|
+
"title": "Drop images & paste links onto the canvas",
|
|
202
|
+
"summary": "Drag a screenshot from your desktop — or paste a clipboard image or a URL — straight onto the canvas. Images sit alongside your annotations; links render as a tidy preview chip you can open in one click.",
|
|
203
|
+
"surface": "design-ui"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"id": "in-app-whats-new-tour",
|
|
207
|
+
"version": "0.29.0",
|
|
208
|
+
"date": "2026-06-08",
|
|
209
|
+
"kind": "feature",
|
|
210
|
+
"title": "What's New, right in the canvas browser",
|
|
211
|
+
"summary": "The Maude UI now tells you what shipped — a dismissible notice plus a panel you can reopen from the menubar. Each closed-out feature adds an entry automatically.",
|
|
212
|
+
"surface": "design-ui",
|
|
213
|
+
"tour": [
|
|
214
|
+
{
|
|
215
|
+
"target": "[data-tour='whatsnew']",
|
|
216
|
+
"title": "Your What's New badge",
|
|
217
|
+
"body": "This ✦ badge lights up when a new maude version ships features. Click it any time to reopen this panel."
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"target": "[data-tour='help']",
|
|
221
|
+
"title": "Tours live in Help too",
|
|
222
|
+
"body": "Open Help to replay the full \"how Maude works\" walkthrough whenever you want."
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"id": "canvas-create-delete-from-browser",
|
|
228
|
+
"version": "0.28.1",
|
|
229
|
+
"date": "2026-06-03",
|
|
230
|
+
"kind": "feature",
|
|
231
|
+
"title": "Create & delete canvases from the browser",
|
|
232
|
+
"summary": "Spin up a blank brief-board straight from the file tree (+ board) and remove canvases without leaving the UI — no /design:new round-trip needed.",
|
|
233
|
+
"learnMore": "https://github.com/1aGh/maude#readme",
|
|
234
|
+
"surface": "design-ui"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"id": "canvas-activity-overlay",
|
|
238
|
+
"version": "0.28.0",
|
|
239
|
+
"date": "2026-06-02",
|
|
240
|
+
"kind": "feature",
|
|
241
|
+
"title": "Live canvas activity overlay",
|
|
242
|
+
"summary": "See at a glance which artboard Claude (or a teammate) is editing — a soft rim + badge highlights the active canvas and fades when work settles.",
|
|
243
|
+
"surface": "design-ui"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"id": "draw-as-code-svg-agent",
|
|
247
|
+
"version": "0.28.0",
|
|
248
|
+
"date": "2026-05-30",
|
|
249
|
+
"kind": "feature",
|
|
250
|
+
"title": "Draw production SVGs as code",
|
|
251
|
+
"summary": "/design:draw generates logos, icons, and diagrams through a deterministic geometry engine — no hand-guessed path data — and proofs them across the 16/24/48/256 verify ladder.",
|
|
252
|
+
"surface": "design-ui"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"id": "self-hostable-hub-sync",
|
|
256
|
+
"version": "0.27.0",
|
|
257
|
+
"date": "2026-05-28",
|
|
258
|
+
"kind": "feature",
|
|
259
|
+
"title": "Self-hostable hub + live file sync",
|
|
260
|
+
"summary": "Run your own Maude hub and co-edit canvases with bidirectional file sync, offline-aware status, and conflict handling.",
|
|
261
|
+
"surface": "design-ui"
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/1aGh/maude/main/apps/studio/whats-new.schema.json",
|
|
4
|
+
"title": "Maude What's New feed",
|
|
5
|
+
"description": "User-facing product-update entries surfaced in the Maude UI (and mirrored to the docs site). Single source of truth — ships with the dev-server, appended on /flow:done, stamped at release. See .ai/plans/feature-in-app-whats-new-tour.md (DDR-A).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["entries"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"$schema": { "type": "string" },
|
|
11
|
+
"entries": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"items": { "$ref": "#/$defs/entry" }
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"$defs": {
|
|
17
|
+
"entry": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"required": ["id", "kind", "title", "summary"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"id": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Stable slug (usually the plan slug). Used for de-dup and as the React key.",
|
|
25
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
26
|
+
},
|
|
27
|
+
"version": {
|
|
28
|
+
"type": ["string", "null"],
|
|
29
|
+
"description": "Semver the feature shipped in, or null while pending (stamped at release).",
|
|
30
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+"
|
|
31
|
+
},
|
|
32
|
+
"date": {
|
|
33
|
+
"type": ["string", "null"],
|
|
34
|
+
"description": "Release date YYYY-MM-DD, or null while pending."
|
|
35
|
+
},
|
|
36
|
+
"kind": { "enum": ["feature", "improvement", "usage", "fix"] },
|
|
37
|
+
"title": { "type": "string", "minLength": 1 },
|
|
38
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
39
|
+
"learnMore": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"description": "Optional URL to docs / release notes. Constrained to http(s) — the feed renders this as an <a href>, so a javascript:/data: scheme is rejected at the data-contract layer (defense-in-depth alongside React's URL sanitizer).",
|
|
42
|
+
"pattern": "^https?://"
|
|
43
|
+
},
|
|
44
|
+
"surface": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Which UI surface this targets (e.g. design-ui). Future-proofing."
|
|
47
|
+
},
|
|
48
|
+
"tour": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"description": "Optional spotlight steps that highlight the new UI (consumed by the tour engine — Phase 3).",
|
|
51
|
+
"items": { "$ref": "#/$defs/tourStep" }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"tourStep": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": ["target", "title", "body"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"target": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "CSS selector or [data-tour=\"<key>\"] anchor to spotlight. Prefer the stable [data-tour] anchors over styling classes (which churn on redesigns)."
|
|
63
|
+
},
|
|
64
|
+
"title": { "type": "string", "minLength": 1 },
|
|
65
|
+
"body": { "type": "string", "minLength": 1 },
|
|
66
|
+
"placement": { "enum": ["top", "bottom", "left", "right", "auto"] },
|
|
67
|
+
"canvas": {
|
|
68
|
+
"type": "boolean",
|
|
69
|
+
"description": "Setup: ensure a canvas is open before the step (the tour opens the first one if none)."
|
|
70
|
+
},
|
|
71
|
+
"inspector": {
|
|
72
|
+
"type": "boolean",
|
|
73
|
+
"description": "Setup: open the right-hand Inspector panel before the step."
|
|
74
|
+
},
|
|
75
|
+
"tab": {
|
|
76
|
+
"enum": ["inspect", "layers", "css"],
|
|
77
|
+
"description": "Setup: switch the Inspector to this tab before the step."
|
|
78
|
+
},
|
|
79
|
+
"requireSelection": {
|
|
80
|
+
"type": "boolean",
|
|
81
|
+
"description": "The target only exists once an element is ⌘-clicked in the (cross-origin) canvas. The card shows a '⌘-click to continue' hint and the spotlight snaps onto the real row when a selection lands."
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// whats-new.ts — server-side loader for the Maude "What's New" feed.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth: `<DEV_SERVER_ROOT>/whats-new.json` (DDR-A). The feed
|
|
4
|
+
// describes **Maude's own product** updates — it is resolved from the maude
|
|
5
|
+
// package root (via paths.ts, NOT cwd), so the dev-server surfaces the same
|
|
6
|
+
// product news whether it runs in this repo or a downstream user's project.
|
|
7
|
+
//
|
|
8
|
+
// Disk paths MUST come from paths.ts (DDR-045) — never
|
|
9
|
+
// `dirname(fileURLToPath(import.meta.url))`, which is the virtual `/$bunfs/root`
|
|
10
|
+
// inside a `bun --compile` standalone binary.
|
|
11
|
+
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { DEV_SERVER_ROOT } from './paths.ts';
|
|
15
|
+
|
|
16
|
+
export type WhatsNewKind = 'feature' | 'improvement' | 'usage' | 'fix';
|
|
17
|
+
|
|
18
|
+
export interface WhatsNewTourStep {
|
|
19
|
+
target: string;
|
|
20
|
+
title: string;
|
|
21
|
+
body: string;
|
|
22
|
+
placement?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WhatsNewEntry {
|
|
26
|
+
id: string;
|
|
27
|
+
version: string | null;
|
|
28
|
+
date: string | null;
|
|
29
|
+
kind: WhatsNewKind;
|
|
30
|
+
title: string;
|
|
31
|
+
summary: string;
|
|
32
|
+
learnMore?: string;
|
|
33
|
+
surface?: string;
|
|
34
|
+
tour?: WhatsNewTourStep[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface WhatsNewFeed {
|
|
38
|
+
/** The installed maude version (key the client compares "seen" against). */
|
|
39
|
+
version: string;
|
|
40
|
+
entries: WhatsNewEntry[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let cache: WhatsNewFeed | null = null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Read the installed maude version from the design plugin manifest.
|
|
47
|
+
* `apps/studio/` → `plugins/design/.claude-plugin/plugin.json`.
|
|
48
|
+
* That manifest ships in BOTH npm installs and marketplace-cache clones
|
|
49
|
+
* (same rationale as build.ts `readPluginVersion`). Falls back to `dev`.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveMaudeVersion(root: string = DEV_SERVER_ROOT): string {
|
|
52
|
+
const manifest = join(root, '..', '..', 'plugins', 'design', '.claude-plugin', 'plugin.json');
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(readFileSync(manifest, 'utf8')) as { version?: unknown };
|
|
55
|
+
if (typeof parsed.version === 'string') return parsed.version;
|
|
56
|
+
} catch {
|
|
57
|
+
/* fall through */
|
|
58
|
+
}
|
|
59
|
+
return 'dev';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Load `<root>/whats-new.json`. Fails soft to an empty entry list — a missing
|
|
64
|
+
* or malformed feed must never 500 the dev-server (it's a non-critical chrome
|
|
65
|
+
* surface). Caches the default-root result; pass `{ root }` for an uncached
|
|
66
|
+
* read (tests) and `{ fresh: true }` to bypass the cache.
|
|
67
|
+
*/
|
|
68
|
+
export function loadWhatsNew(opts: { root?: string; fresh?: boolean } = {}): WhatsNewFeed {
|
|
69
|
+
const usingDefaultRoot = opts.root === undefined;
|
|
70
|
+
if (cache && usingDefaultRoot && !opts.fresh) return cache;
|
|
71
|
+
|
|
72
|
+
const root = opts.root ?? DEV_SERVER_ROOT;
|
|
73
|
+
const file = join(root, 'whats-new.json');
|
|
74
|
+
let entries: WhatsNewEntry[] = [];
|
|
75
|
+
try {
|
|
76
|
+
if (existsSync(file)) {
|
|
77
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8')) as { entries?: unknown };
|
|
78
|
+
if (Array.isArray(parsed.entries)) entries = parsed.entries as WhatsNewEntry[];
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
/* malformed feed → empty, never throw */
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const feed: WhatsNewFeed = { version: resolveMaudeVersion(root), entries };
|
|
85
|
+
if (usingDefaultRoot) cache = feed;
|
|
86
|
+
return feed;
|
|
87
|
+
}
|
package/cli/bin/maude.mjs
CHANGED
|
@@ -50,6 +50,16 @@ async function main(argv) {
|
|
|
50
50
|
return run({ args: [], pkgRoot: PKG_ROOT });
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// `maude studio [...]` — top-level alias for `maude design serve` (DDR-095:
|
|
54
|
+
// the verb now matches the apps/studio home). Checked BEFORE the COMMANDS map
|
|
55
|
+
// so it never falls through to the unknown-command branch; it is deliberately
|
|
56
|
+
// NOT a COMMANDS entry (that would dispatch design.run with positional[0]
|
|
57
|
+
// wrong). `maude design serve` keeps working unchanged.
|
|
58
|
+
if (cmd === 'studio') {
|
|
59
|
+
const { run } = await COMMANDS.design();
|
|
60
|
+
return run({ args: ['serve', ...args.slice(1)], pkgRoot: PKG_ROOT });
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
const loader = COMMANDS[cmd];
|
|
54
64
|
if (!loader) {
|
|
55
65
|
process.stderr.write(
|
|
@@ -282,6 +282,90 @@ test('status reports zero-syncable when _sync.json is notSyncable (DDR-060 / 9.1
|
|
|
282
282
|
cleanup();
|
|
283
283
|
});
|
|
284
284
|
|
|
285
|
+
// --------------------------------------------------- DDR-102 status surfaces
|
|
286
|
+
|
|
287
|
+
test('DDR-102: status renders docs counts, rejected slugs, and the conflict recovery hint', async () => {
|
|
288
|
+
await runCli(['design', 'link', URL, '--token', 'mau_test']);
|
|
289
|
+
writeFileSync(
|
|
290
|
+
join(workspace, '.design/_sync.json'),
|
|
291
|
+
JSON.stringify({
|
|
292
|
+
state: 'online',
|
|
293
|
+
queuedOps: 0,
|
|
294
|
+
lastSyncAt: 1760000000000,
|
|
295
|
+
offlineSince: null,
|
|
296
|
+
flash: null,
|
|
297
|
+
updatedAt: Date.now(),
|
|
298
|
+
url: URL,
|
|
299
|
+
canvases: 83,
|
|
300
|
+
docs: { synced: 81, pending: 0, rejected: 2 },
|
|
301
|
+
rejectedSlugs: ['system-tokens', 'system-type'],
|
|
302
|
+
conflicts: [
|
|
303
|
+
{
|
|
304
|
+
slug: 'ui-maskot',
|
|
305
|
+
kind: 'cold-start-diverged',
|
|
306
|
+
winner: 'local',
|
|
307
|
+
snapshots: {
|
|
308
|
+
local: '2026-06-11T10:00:00.000Z',
|
|
309
|
+
hub: '2026-06-11T10:00:00.001Z',
|
|
310
|
+
},
|
|
311
|
+
at: 1760000001000,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
}),
|
|
315
|
+
'utf8'
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
const human = await runCli(['design', 'status']);
|
|
319
|
+
assert.equal(human.status, 0, human.stderr);
|
|
320
|
+
assert.match(human.stdout, /docs: 81 synced · 0 pending · 2 rejected/);
|
|
321
|
+
assert.match(human.stdout, /not syncing:\s+system-tokens, system-type/);
|
|
322
|
+
assert.match(human.stdout, /ui-maskot — diverged, kept local \(newest-wins\)/);
|
|
323
|
+
assert.match(human.stdout, /local@2026-06-11T10:00:00\.000Z/);
|
|
324
|
+
assert.match(human.stdout, /hub@2026-06-11T10:00:00\.001Z/);
|
|
325
|
+
assert.match(human.stdout, /\/design:rollback ui-maskot/);
|
|
326
|
+
|
|
327
|
+
// --json passes the new fields through verbatim.
|
|
328
|
+
const json = await runCli(['design', 'status', '--json']);
|
|
329
|
+
const payload = JSON.parse(json.stdout);
|
|
330
|
+
assert.equal(payload.sync.docs.rejected, 2);
|
|
331
|
+
assert.equal(payload.sync.conflicts[0].winner, 'local');
|
|
332
|
+
cleanup();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('DDR-102: status renders an OLD-shape _sync.json (no docs/rejectedSlugs) unchanged', async () => {
|
|
336
|
+
await runCli(['design', 'link', URL, '--token', 'mau_test']);
|
|
337
|
+
writeFileSync(
|
|
338
|
+
join(workspace, '.design/_sync.json'),
|
|
339
|
+
JSON.stringify({
|
|
340
|
+
state: 'online',
|
|
341
|
+
queuedOps: 0,
|
|
342
|
+
lastSyncAt: null,
|
|
343
|
+
offlineSince: null,
|
|
344
|
+
flash: null,
|
|
345
|
+
updatedAt: Date.now(),
|
|
346
|
+
url: URL,
|
|
347
|
+
canvases: 5,
|
|
348
|
+
conflicts: [],
|
|
349
|
+
}),
|
|
350
|
+
'utf8'
|
|
351
|
+
);
|
|
352
|
+
const human = await runCli(['design', 'status']);
|
|
353
|
+
assert.equal(human.status, 0, human.stderr);
|
|
354
|
+
assert.match(human.stdout, /sync agent:\s+online/);
|
|
355
|
+
assert.doesNotMatch(human.stdout, /docs:/);
|
|
356
|
+
assert.doesNotMatch(human.stdout, /not syncing:/);
|
|
357
|
+
cleanup();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
test('DDR-102: re-linking the same hub prints the token-replacement notice', async () => {
|
|
361
|
+
await runCli(['design', 'link', URL, '--token', 'mau_first']);
|
|
362
|
+
const second = await runCli(['design', 'link', URL, '--token', 'mau_second']);
|
|
363
|
+
assert.equal(second.status, 0, second.stderr);
|
|
364
|
+
assert.match(second.stdout, /replacing the stored token for/);
|
|
365
|
+
assert.match(second.stdout, /EVERY project linked to this hub on this machine/);
|
|
366
|
+
cleanup();
|
|
367
|
+
});
|
|
368
|
+
|
|
285
369
|
// --------------------------------------------------- DDR-054 F2/F4 trust gate
|
|
286
370
|
|
|
287
371
|
const REMOTE_URL = 'http://hub.invalid:9999'; // .invalid never resolves (RFC 6761)
|
package/cli/commands/design.mjs
CHANGED
|
@@ -40,6 +40,9 @@ const BIN_VERBS = new Set([
|
|
|
40
40
|
'draw-build',
|
|
41
41
|
'draw-proof',
|
|
42
42
|
'svg-optimize',
|
|
43
|
+
'to-lottie',
|
|
44
|
+
'read-annotations',
|
|
45
|
+
'annotate',
|
|
43
46
|
]);
|
|
44
47
|
|
|
45
48
|
// Bin verbs that boot the dev-server (directly, or by shelling into server-up.sh).
|
|
@@ -86,11 +89,16 @@ function runBinDispatch(verb, { args, pkgRoot }) {
|
|
|
86
89
|
process.stderr.write(`maude design: "${verb}" is not a dev-tooling verb.\n${usage()}`);
|
|
87
90
|
process.exit(2);
|
|
88
91
|
}
|
|
92
|
+
// CLAUDE_PLUGIN_ROOT stays the design *plugin* dir (plugins/design) — that's
|
|
93
|
+
// its true meaning, and it remains 2 levels under pkgRoot so the helpers'
|
|
94
|
+
// `$PLUGIN_ROOT/../../cli` side-channel + `$PLUGIN_ROOT/../..` pkg-root math
|
|
95
|
+
// still resolve. The bin scripts themselves now live under apps/studio/bin
|
|
96
|
+
// (DDR-095) and resolve the dev-server tree via $SCRIPT_DIR/.. regardless.
|
|
89
97
|
const pluginRoot = join(pkgRoot, 'plugins', 'design');
|
|
90
|
-
const script = join(
|
|
98
|
+
const script = join(pkgRoot, 'apps', 'studio', 'bin', `${verb}.sh`);
|
|
91
99
|
if (!existsSync(script)) {
|
|
92
100
|
process.stderr.write(
|
|
93
|
-
`maude design ${verb}: helper not found at ${script}. Reinstall maude (the
|
|
101
|
+
`maude design ${verb}: helper not found at ${script}. Reinstall maude (the studio bin ships in the npm package).\n`
|
|
94
102
|
);
|
|
95
103
|
process.exit(1);
|
|
96
104
|
}
|
|
@@ -127,7 +135,7 @@ Lifecycle:
|
|
|
127
135
|
Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
128
136
|
screenshot · server-up · prep · slug · bootstrap-check · runtime-health
|
|
129
137
|
smoke · canvas-edit · handoff · asset-sweep · visual-sanity
|
|
130
|
-
draw-build · draw-proof · svg-optimize
|
|
138
|
+
draw-build · draw-proof · svg-optimize · to-lottie · read-annotations · annotate
|
|
131
139
|
Invoke the bundled helper of the same name. maude resolves it from its
|
|
132
140
|
own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
|
|
133
141
|
stderr, and exit code pass straight through (so command-substitution
|
|
@@ -140,7 +148,8 @@ Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
|
140
148
|
|
|
141
149
|
serve [--port N] [--root PATH]
|
|
142
150
|
Start the design plugin's dev server in the current repo. Equivalent
|
|
143
|
-
to invoking 'claude-design-server'.
|
|
151
|
+
to 'maude studio' (top-level alias) or invoking 'claude-design-server'.
|
|
152
|
+
Forwards all remaining args.
|
|
144
153
|
|
|
145
154
|
init [--name <slug>] [--ds <name>] [--force] [--dry-run]
|
|
146
155
|
[--no-discovery | --discovery-payload <path>]
|
|
@@ -259,8 +268,8 @@ async function runServe({ args, pkgRoot }) {
|
|
|
259
268
|
process.exit(1);
|
|
260
269
|
}
|
|
261
270
|
|
|
262
|
-
const tsEntry = resolve(pkgRoot, '
|
|
263
|
-
const mjsEntry = resolve(pkgRoot, '
|
|
271
|
+
const tsEntry = resolve(pkgRoot, 'apps', 'studio', 'server.ts');
|
|
272
|
+
const mjsEntry = resolve(pkgRoot, 'apps', 'studio', 'server.mjs');
|
|
264
273
|
|
|
265
274
|
const hasBun = await new Promise((res) => {
|
|
266
275
|
const probe = spawn('bun', ['--version'], { stdio: 'ignore' });
|
|
@@ -414,7 +423,7 @@ function checkDevDeps({ pkgRoot }) {
|
|
|
414
423
|
// with a less actionable error.
|
|
415
424
|
const required = ['magic-string', 'oxc-parser'];
|
|
416
425
|
const missing = [];
|
|
417
|
-
const paths = [resolve(pkgRoot, '
|
|
426
|
+
const paths = [resolve(pkgRoot, 'apps', 'studio'), resolve(pkgRoot)];
|
|
418
427
|
for (const dep of required) {
|
|
419
428
|
try {
|
|
420
429
|
require.resolve(dep, { paths });
|
|
@@ -150,3 +150,43 @@ test('isPlausiblePlatformBinary — accepts maude-<slug>/maude, rejects everythi
|
|
|
150
150
|
assert.equal(isPlausiblePlatformBinary(''), false);
|
|
151
151
|
assert.equal(isPlausiblePlatformBinary(null), false);
|
|
152
152
|
});
|
|
153
|
+
|
|
154
|
+
// DDR-095 — `maude studio` is a top-level alias for `maude design serve`. Both
|
|
155
|
+
// must resolve the same server-entry path. We prove parity by booting each
|
|
156
|
+
// against a temp dir with no .design/: the dev-server fails loud (exit 1) with
|
|
157
|
+
// an identical first-line signature, which only happens if `studio` routed
|
|
158
|
+
// through design-serve resolution (`apps/studio/server.{ts,mjs}` / the binary).
|
|
159
|
+
test('`maude studio` aliases `maude design serve` (identical boot resolution)', () => {
|
|
160
|
+
const BIN_PATH = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'maude.mjs');
|
|
161
|
+
function bootAgainstEmpty(argv) {
|
|
162
|
+
const cwd = mkdtempSync(join(tmpdir(), 'maude-studio-'));
|
|
163
|
+
try {
|
|
164
|
+
const r = spawnSync(process.execPath, [BIN_PATH, ...argv, '--root', cwd], {
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
timeout: 30000,
|
|
167
|
+
});
|
|
168
|
+
// Each invocation mkdtemp's its own root, and the diagnostic embeds that
|
|
169
|
+
// path — mask it so we compare the path-independent signature (the test's
|
|
170
|
+
// actual intent: same exit code + same error shape from both entrypoints).
|
|
171
|
+
const firstErr = ((r.stderr || '').split('\n').find(Boolean) ?? '').replaceAll(cwd, '<root>');
|
|
172
|
+
return { status: r.status, firstErr };
|
|
173
|
+
} finally {
|
|
174
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const viaDesign = bootAgainstEmpty(['design', 'serve']);
|
|
178
|
+
const viaStudio = bootAgainstEmpty(['studio']);
|
|
179
|
+
// Both fail loud (no .design/) — same exit code, same first-line diagnostic.
|
|
180
|
+
assert.notEqual(viaStudio.status, 0, `studio should not boot cleanly: ${viaStudio.firstErr}`);
|
|
181
|
+
assert.equal(viaStudio.status, viaDesign.status);
|
|
182
|
+
assert.equal(viaStudio.firstErr, viaDesign.firstErr);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('`maude studio` is recognized (not an unknown command)', () => {
|
|
186
|
+
const BIN_PATH = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'maude.mjs');
|
|
187
|
+
const r = spawnSync(process.execPath, [BIN_PATH, 'studio', '--root', '/nonexistent-xyz'], {
|
|
188
|
+
encoding: 'utf8',
|
|
189
|
+
timeout: 30000,
|
|
190
|
+
});
|
|
191
|
+
assert.doesNotMatch(r.stderr || '', /unknown command/);
|
|
192
|
+
});
|