@1agh/maude 0.28.0 → 0.29.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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +286 -6
- package/{plugins/design/dev-server → apps/studio}/annotations-layer.tsx +1209 -122
- package/{plugins/design/dev-server → apps/studio}/api.ts +486 -32
- 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/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 +438 -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/scenario-report.mjs +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/screenshot.sh +62 -2
- package/apps/studio/bin/server-up.sh +234 -0
- 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}/bin/visual-sanity.sh +19 -3
- package/{plugins/design/dev-server → apps/studio}/build.ts +5 -3
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-comment-mount.tsx +2 -2
- package/apps/studio/canvas-create.ts +104 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-cursors.ts +47 -13
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +60 -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 +41 -33
- package/{plugins/design/dev-server → apps/studio}/canvas-shell.tsx +57 -42
- package/{plugins/design/dev-server → apps/studio}/client/app.jsx +1713 -530
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/{plugins/design/dev-server → apps/studio}/client/index.html +2 -1
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +459 -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 +357 -34
- package/apps/studio/client/styles/5-maude-overrides.css +123 -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 +191 -0
- package/apps/studio/client/tour/usage-tour.js +35 -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}/collab/index.ts +4 -4
- package/{plugins/design/dev-server → apps/studio}/collab/persistence.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/annotation-strokes-command.ts +1 -1
- 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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +25 -6
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +4 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +1 -1
- package/apps/studio/dist/client.bundle.js +22825 -0
- package/apps/studio/dist/comment-mount.js +1960 -0
- package/apps/studio/dist/runtime/lib0_decoding.js +1 -0
- package/apps/studio/dist/runtime/lib0_encoding.js +1 -0
- package/apps/studio/dist/runtime/motion.js +4 -0
- package/apps/studio/dist/runtime/motion_react.js +12 -0
- package/apps/studio/dist/runtime/pixi-js.js +3397 -0
- package/apps/studio/dist/runtime/react-dom.js +1 -0
- package/apps/studio/dist/runtime/react-dom_client.js +9 -0
- package/apps/studio/dist/runtime/react.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-dev-runtime.js +1 -0
- package/apps/studio/dist/runtime/react_jsx-runtime.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_awareness.js +1 -0
- package/apps/studio/dist/runtime/y-protocols_sync.js +1 -0
- package/apps/studio/dist/runtime/yjs.js +5 -0
- package/apps/studio/dist/styles.css +5695 -0
- package/{plugins/design/dev-server → apps/studio}/dom-selection.ts +75 -4
- package/apps/studio/draw/animate.ts +333 -0
- package/{plugins/design/dev-server → apps/studio}/draw/brush.ts +4 -4
- 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 +9 -6
- package/{plugins/design/dev-server → apps/studio}/draw/layout.ts +2 -2
- 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/{plugins/design/dev-server → apps/studio}/draw/test/layout.test.ts +1 -1
- 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}/draw/test/serialize.test.ts +1 -1
- 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}/examples/perf-100-artboards.tsx +1 -2
- package/{plugins/design/dev-server → apps/studio}/export-dialog.tsx +14 -2
- package/{plugins/design/dev-server → apps/studio}/exporters/index.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/http.ts +103 -2
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +8 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +6 -3
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +19 -1
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +6 -6
- package/{plugins/design/dev-server → apps/studio}/sync/materialize.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/ai-activity.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/annotations-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/annotations-layer.test.ts +69 -6
- package/{plugins/design/dev-server → apps/studio}/test/annotations-roundtrip.test.ts +98 -1
- package/apps/studio/test/annotations-text-format.test.ts +396 -0
- package/apps/studio/test/asset-api.test.ts +149 -0
- package/{plugins/design/dev-server → apps/studio}/test/boot-self-heal.test.ts +1 -1
- package/apps/studio/test/canvas-create-api.test.ts +361 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-cursors.test.ts +3 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-edit.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-hmr-runtime.test.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-inline.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-resolver.test.ts +2 -3
- package/apps/studio/test/canvas-media-drop.test.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-meta-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/canvas-origin-gate.test.ts +18 -3
- package/apps/studio/test/canvas-url.test.ts +99 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-annotations-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-bridge.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-room.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/collab-stress.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/comments-api.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/compile-entry.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/canva.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/history.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/pw-launch.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/exporters/scope.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/exporters/zip.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/git-lifecycle.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/handoff-static-frames.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/hmr-broadcast.test.ts +1 -1
- 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/runtime-bundle.test.ts +1 -1
- 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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-migrate.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-projection.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/snap-distance-pill.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-agent.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-atomic-write.test.ts +2 -3
- package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-echo-guard.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-fs-mirror.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-hardening.test.ts +4 -5
- package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.test.ts +1 -2
- package/{plugins/design/dev-server → apps/studio}/test/sync-runtime.test.ts +3 -8
- package/{plugins/design/dev-server → apps/studio}/test/sync-status.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-untrusted.test.ts +1 -2
- package/apps/studio/test/tour-overlay.test.tsx +56 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-agent-presence.test.tsx +4 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-resize.test.ts +43 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-snap-guides.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +4 -1
- 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 +4 -69
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-annotation-resize.tsx +41 -12
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +3 -7
- package/{plugins/design/dev-server → apps/studio}/use-annotations-visibility.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-artboard-drag.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/use-canvas-activity.tsx +2 -2
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +4 -5
- 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 +10 -2
- package/{plugins/design/dev-server → apps/studio}/use-snap-guides.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-tool-mode.tsx +4 -2
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +5 -6
- package/apps/studio/whats-new.json +139 -0
- package/apps/studio/whats-new.schema.json +70 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design.mjs +84 -10
- package/cli/commands/design.test.mjs +133 -1
- 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/cache.mjs +1 -1
- package/cli/lib/config-lint.mjs +1 -1
- package/cli/lib/copy-tree.mjs +1 -1
- package/cli/lib/design-link.mjs +1 -1
- package/cli/lib/flow-design-integration.test.mjs +2 -2
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/gitignore-block.test.mjs +2 -2
- package/cli/lib/plugin-cli-reachability.test.mjs +8 -7
- package/cli/lib/preflight.mjs +1 -1
- package/cli/lib/stack-detect.mjs +1 -1
- package/package.json +16 -16
- package/plugins/design/templates/_shell.html +3 -3
- 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/SUB-AGENT-PROMPTS.md +18 -3
- 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/bin/server-up.sh +0 -135
- 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/runtime/lib0_decoding.js +0 -620
- package/plugins/design/dev-server/dist/runtime/lib0_encoding.js +0 -604
- package/plugins/design/dev-server/dist/runtime/motion.js +0 -4944
- package/plugins/design/dev-server/dist/runtime/motion_react.js +0 -10056
- package/plugins/design/dev-server/dist/runtime/pixi-js.js +0 -53104
- package/plugins/design/dev-server/dist/runtime/react-dom.js +0 -231
- package/plugins/design/dev-server/dist/runtime/react-dom_client.js +0 -10357
- package/plugins/design/dev-server/dist/runtime/react.js +0 -535
- package/plugins/design/dev-server/dist/runtime/react_jsx-dev-runtime.js +0 -60
- package/plugins/design/dev-server/dist/runtime/react_jsx-runtime.js +0 -85
- package/plugins/design/dev-server/dist/runtime/y-protocols_awareness.js +0 -376
- package/plugins/design/dev-server/dist/runtime/y-protocols_sync.js +0 -100
- package/plugins/design/dev-server/dist/runtime/yjs.js +0 -6687
- package/plugins/design/dev-server/dist/styles.css +0 -2710
- 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/_png-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/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}/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-edit.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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/collab/git-lifecycle.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}/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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/test/gradient.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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/examples/README.md +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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pdf.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/png.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/pptx.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/exporters/scope.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/exporters/svg.ts +1 -1
- 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}/history.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/agent.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/connection-state.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/migrate-seed.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/sync/status.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/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-draw-modifiers.test.ts +2 -2
- 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/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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-motion.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-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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/collab-reseed-guard.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/context-resolve-tokens.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/csp-canvas-shell.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/endpoint.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/svg.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/handoff.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/history-rollback.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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/locator.test.ts +1 -1
- 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/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/sync-codec.test.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/sync-meta-codec.test.ts +1 -1
- 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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-selection.test.tsx +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-artboard-drag.test.ts +3 -3
- package/{plugins/design/dev-server → apps/studio}/test/use-canvas-activity.test.tsx +2 -2
- package/{plugins/design/dev-server → apps/studio}/test/use-collab.test.ts +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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-undo-stack.test.tsx +2 -2
- /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,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./whats-new.schema.json",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"id": "studio-full-functionality",
|
|
6
|
+
"version": "0.29.0",
|
|
7
|
+
"date": "2026-06-08",
|
|
8
|
+
"kind": "feature",
|
|
9
|
+
"title": "The studio is fully wired now",
|
|
10
|
+
"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.",
|
|
11
|
+
"surface": "design-ui",
|
|
12
|
+
"tour": [
|
|
13
|
+
{
|
|
14
|
+
"target": ".st-mb-right",
|
|
15
|
+
"title": "Live status, finally",
|
|
16
|
+
"body": "Zoom, artboard count, presence and hub-sync now reflect the real state — no more static placeholders."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"target": ".st-rpanel",
|
|
20
|
+
"title": "Inspector",
|
|
21
|
+
"body": "⌘-click an element in the canvas, then press I — pos, size, ancestry and markup, read-only (live CSS knobs land in Phase 12)."
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "draw-animation-lottie",
|
|
27
|
+
"version": "0.29.0",
|
|
28
|
+
"date": "2026-06-08",
|
|
29
|
+
"kind": "feature",
|
|
30
|
+
"title": "Animate draw marks → ship one Lottie",
|
|
31
|
+
"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.",
|
|
32
|
+
"surface": "design-ui"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "studio-maude-ds-redesign",
|
|
36
|
+
"version": "0.29.0",
|
|
37
|
+
"date": "2026-06-08",
|
|
38
|
+
"kind": "feature",
|
|
39
|
+
"title": "The studio, redesigned in maude",
|
|
40
|
+
"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.",
|
|
41
|
+
"surface": "design-ui",
|
|
42
|
+
"tour": [
|
|
43
|
+
{
|
|
44
|
+
"target": ".st-menubar .st-brand",
|
|
45
|
+
"title": "Built in maude",
|
|
46
|
+
"body": "The studio chrome now dogfoods the maude DS — one cohesive material across the menubar, sidebar, canvas and status bar."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"target": ".st-menubar .st-whatsnew",
|
|
50
|
+
"title": "Press ⌘K",
|
|
51
|
+
"body": "A new command palette jumps you to the design-system view, comments, theme toggle, reload, and help — no mouse needed."
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "annotation-tooling-polish",
|
|
57
|
+
"version": "0.29.0",
|
|
58
|
+
"date": "2026-06-08",
|
|
59
|
+
"kind": "improvement",
|
|
60
|
+
"title": "Richer annotations — highlighter, lists & text shortcuts",
|
|
61
|
+
"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.",
|
|
62
|
+
"surface": "design-ui",
|
|
63
|
+
"tour": [
|
|
64
|
+
{
|
|
65
|
+
"target": ".dc-tool-palette button[aria-label^='Highlighter']",
|
|
66
|
+
"title": "New: Highlighter",
|
|
67
|
+
"body": "A translucent marker pen (I) — overlapping strokes darken with multiply blend. Pick hue and nib width from the chrome below."
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "canvas-media-images-links",
|
|
73
|
+
"version": "0.29.0",
|
|
74
|
+
"date": "2026-06-08",
|
|
75
|
+
"kind": "feature",
|
|
76
|
+
"title": "Drop images & paste links onto the canvas",
|
|
77
|
+
"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.",
|
|
78
|
+
"surface": "design-ui"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "in-app-whats-new-tour",
|
|
82
|
+
"version": "0.29.0",
|
|
83
|
+
"date": "2026-06-08",
|
|
84
|
+
"kind": "feature",
|
|
85
|
+
"title": "What's New, right in the canvas browser",
|
|
86
|
+
"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.",
|
|
87
|
+
"surface": "design-ui",
|
|
88
|
+
"tour": [
|
|
89
|
+
{
|
|
90
|
+
"target": "[data-tour='whatsnew']",
|
|
91
|
+
"title": "Your What's New badge",
|
|
92
|
+
"body": "This ✦ badge lights up when a new maude version ships features. Click it any time to reopen this panel."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"target": "[data-tour='help']",
|
|
96
|
+
"title": "Tours live in Help too",
|
|
97
|
+
"body": "Open Help to replay the full \"how Maude works\" walkthrough whenever you want."
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "canvas-create-delete-from-browser",
|
|
103
|
+
"version": "0.28.1",
|
|
104
|
+
"date": "2026-06-03",
|
|
105
|
+
"kind": "feature",
|
|
106
|
+
"title": "Create & delete canvases from the browser",
|
|
107
|
+
"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.",
|
|
108
|
+
"learnMore": "https://github.com/1aGh/maude#readme",
|
|
109
|
+
"surface": "design-ui"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": "canvas-activity-overlay",
|
|
113
|
+
"version": "0.28.0",
|
|
114
|
+
"date": "2026-06-02",
|
|
115
|
+
"kind": "feature",
|
|
116
|
+
"title": "Live canvas activity overlay",
|
|
117
|
+
"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.",
|
|
118
|
+
"surface": "design-ui"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "draw-as-code-svg-agent",
|
|
122
|
+
"version": "0.28.0",
|
|
123
|
+
"date": "2026-05-30",
|
|
124
|
+
"kind": "feature",
|
|
125
|
+
"title": "Draw production SVGs as code",
|
|
126
|
+
"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.",
|
|
127
|
+
"surface": "design-ui"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "self-hostable-hub-sync",
|
|
131
|
+
"version": "0.27.0",
|
|
132
|
+
"date": "2026-05-28",
|
|
133
|
+
"kind": "feature",
|
|
134
|
+
"title": "Self-hostable hub + live file sync",
|
|
135
|
+
"summary": "Run your own Maude hub and co-edit canvases with bidirectional file sync, offline-aware status, and conflict handling.",
|
|
136
|
+
"surface": "design-ui"
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
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."
|
|
63
|
+
},
|
|
64
|
+
"title": { "type": "string", "minLength": 1 },
|
|
65
|
+
"body": { "type": "string", "minLength": 1 },
|
|
66
|
+
"placement": { "enum": ["top", "bottom", "left", "right", "auto"] }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -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(
|
package/cli/commands/design.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execSync, spawn, spawnSync } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { mkdir,
|
|
2
|
+
import { chmodSync, existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { parseArgs } from '../lib/argv.mjs';
|
|
@@ -40,8 +40,15 @@ const BIN_VERBS = new Set([
|
|
|
40
40
|
'draw-build',
|
|
41
41
|
'draw-proof',
|
|
42
42
|
'svg-optimize',
|
|
43
|
+
'to-lottie',
|
|
44
|
+
'read-annotations',
|
|
43
45
|
]);
|
|
44
46
|
|
|
47
|
+
// Bin verbs that boot the dev-server (directly, or by shelling into server-up.sh).
|
|
48
|
+
// For these we resolve the compiled platform binary and hand its path to the
|
|
49
|
+
// helper via MAUDE_DEV_SERVER_BIN — see runBinDispatch + DDR-084.
|
|
50
|
+
const BOOT_VERBS = new Set(['server-up', 'visual-sanity', 'smoke']);
|
|
51
|
+
|
|
45
52
|
export async function run({ args, pkgRoot }) {
|
|
46
53
|
const { positional } = parseArgs(args);
|
|
47
54
|
const sub = positional[0];
|
|
@@ -81,18 +88,35 @@ function runBinDispatch(verb, { args, pkgRoot }) {
|
|
|
81
88
|
process.stderr.write(`maude design: "${verb}" is not a dev-tooling verb.\n${usage()}`);
|
|
82
89
|
process.exit(2);
|
|
83
90
|
}
|
|
91
|
+
// CLAUDE_PLUGIN_ROOT stays the design *plugin* dir (plugins/design) — that's
|
|
92
|
+
// its true meaning, and it remains 2 levels under pkgRoot so the helpers'
|
|
93
|
+
// `$PLUGIN_ROOT/../../cli` side-channel + `$PLUGIN_ROOT/../..` pkg-root math
|
|
94
|
+
// still resolve. The bin scripts themselves now live under apps/studio/bin
|
|
95
|
+
// (DDR-095) and resolve the dev-server tree via $SCRIPT_DIR/.. regardless.
|
|
84
96
|
const pluginRoot = join(pkgRoot, 'plugins', 'design');
|
|
85
|
-
const script = join(
|
|
97
|
+
const script = join(pkgRoot, 'apps', 'studio', 'bin', `${verb}.sh`);
|
|
86
98
|
if (!existsSync(script)) {
|
|
87
99
|
process.stderr.write(
|
|
88
|
-
`maude design ${verb}: helper not found at ${script}. Reinstall maude (the
|
|
100
|
+
`maude design ${verb}: helper not found at ${script}. Reinstall maude (the studio bin ships in the npm package).\n`
|
|
89
101
|
);
|
|
90
102
|
process.exit(1);
|
|
91
103
|
}
|
|
92
104
|
const rest = args.slice(args.indexOf(verb) + 1); // everything after the verb token
|
|
105
|
+
const childEnv = { ...process.env, CLAUDE_PLUGIN_ROOT: pluginRoot };
|
|
106
|
+
// For verbs that boot the dev-server, resolve the compiled platform binary the
|
|
107
|
+
// SAME way `maude design serve` does and hand the path down. The binary embeds
|
|
108
|
+
// yjs + every runtime dep; `bun server.ts` from source does NOT (the deps live
|
|
109
|
+
// in a nested package.json the npm tarball excludes), so on a production install
|
|
110
|
+
// server.ts crashes at boot on `yjs`. server-up.sh prefers MAUDE_DEV_SERVER_BIN
|
|
111
|
+
// when set; absent ⇒ dev tree ⇒ it falls back to `bun server.ts`. Helpers that
|
|
112
|
+
// shell into server-up.sh (visual-sanity, smoke) inherit it. DDR-084.
|
|
113
|
+
if (BOOT_VERBS.has(verb) && !process.env.MAUDE_DEV_SERVER_BIN) {
|
|
114
|
+
const bin = resolveServerBinary({ pkgRoot });
|
|
115
|
+
if (bin) childEnv.MAUDE_DEV_SERVER_BIN = bin;
|
|
116
|
+
}
|
|
93
117
|
const child = spawnSync('bash', [script, ...rest], {
|
|
94
118
|
stdio: 'inherit',
|
|
95
|
-
env:
|
|
119
|
+
env: childEnv,
|
|
96
120
|
});
|
|
97
121
|
if (child.error) {
|
|
98
122
|
process.stderr.write(`maude design ${verb}: ${child.error.message}\n`);
|
|
@@ -110,7 +134,7 @@ Lifecycle:
|
|
|
110
134
|
Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
111
135
|
screenshot · server-up · prep · slug · bootstrap-check · runtime-health
|
|
112
136
|
smoke · canvas-edit · handoff · asset-sweep · visual-sanity
|
|
113
|
-
draw-build · draw-proof · svg-optimize
|
|
137
|
+
draw-build · draw-proof · svg-optimize · to-lottie · read-annotations
|
|
114
138
|
Invoke the bundled helper of the same name. maude resolves it from its
|
|
115
139
|
own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
|
|
116
140
|
stderr, and exit code pass straight through (so command-substitution
|
|
@@ -123,7 +147,8 @@ Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
|
123
147
|
|
|
124
148
|
serve [--port N] [--root PATH]
|
|
125
149
|
Start the design plugin's dev server in the current repo. Equivalent
|
|
126
|
-
to invoking 'claude-design-server'.
|
|
150
|
+
to 'maude studio' (top-level alias) or invoking 'claude-design-server'.
|
|
151
|
+
Forwards all remaining args.
|
|
127
152
|
|
|
128
153
|
init [--name <slug>] [--ds <name>] [--force] [--dry-run]
|
|
129
154
|
[--no-discovery | --discovery-payload <path>]
|
|
@@ -242,8 +267,8 @@ async function runServe({ args, pkgRoot }) {
|
|
|
242
267
|
process.exit(1);
|
|
243
268
|
}
|
|
244
269
|
|
|
245
|
-
const tsEntry = resolve(pkgRoot, '
|
|
246
|
-
const mjsEntry = resolve(pkgRoot, '
|
|
270
|
+
const tsEntry = resolve(pkgRoot, 'apps', 'studio', 'server.ts');
|
|
271
|
+
const mjsEntry = resolve(pkgRoot, 'apps', 'studio', 'server.mjs');
|
|
247
272
|
|
|
248
273
|
const hasBun = await new Promise((res) => {
|
|
249
274
|
const probe = spawn('bun', ['--version'], { stdio: 'ignore' });
|
|
@@ -295,6 +320,55 @@ function detectPlatformSlug() {
|
|
|
295
320
|
return null;
|
|
296
321
|
}
|
|
297
322
|
|
|
323
|
+
// Read-only resolution of the compiled platform binary the dev-server should
|
|
324
|
+
// boot as in a production install (it embeds yjs + every runtime dep). Mirrors
|
|
325
|
+
// runServe's order — side-channel cache (postinstall) → lazy resolve of the
|
|
326
|
+
// @1agh/maude-<slug> sibling/nested package — but performs NO caching and NEVER
|
|
327
|
+
// hard-fails: returns the path, or null when none is found. A null result means
|
|
328
|
+
// "fall back to `bun server.ts` from source" (correct in the local dev tree).
|
|
329
|
+
// Honors MAUDE_FORCE_SOURCE=1 so maintainers hacking on the dev-server source
|
|
330
|
+
// still boot their working copy. Used by runBinDispatch to hand the path to
|
|
331
|
+
// server-up.sh; runServe keeps its own inline copy (it also caches + hard-fails).
|
|
332
|
+
// Structural allowlist for a path we're about to spawn (DDR-084 hardening). The
|
|
333
|
+
// compiled binary is ALWAYS named `maude` / `maude.exe` inside a `maude-<slug>/`
|
|
334
|
+
// dir (the @1agh/maude-<slug> package, or the dev-tree `packages/maude-<slug>/`).
|
|
335
|
+
// The side-channel file's content is the one attacker-influenceable input in a
|
|
336
|
+
// shared-prefix / poisoned-clone layout — a path outside this shape is ignored
|
|
337
|
+
// (caller falls back to source), so the file can only DENY the binary, never
|
|
338
|
+
// redirect the spawn to an arbitrary executable. Paths `lazyResolveBinary`
|
|
339
|
+
// constructs always conform, so this never rejects a legit resolve.
|
|
340
|
+
export function isPlausiblePlatformBinary(p) {
|
|
341
|
+
if (!p) return false;
|
|
342
|
+
const b = basename(p);
|
|
343
|
+
if (b !== 'maude' && b !== 'maude.exe') return false;
|
|
344
|
+
return /^maude-[a-z0-9-]+$/.test(basename(dirname(p)));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function resolveServerBinary({ pkgRoot }) {
|
|
348
|
+
if (process.env.MAUDE_FORCE_SOURCE === '1') return null;
|
|
349
|
+
// In the local source checkout, return null so server-up.sh boots
|
|
350
|
+
// `bun server.ts` from source — the maintainer is editing the dev-server and
|
|
351
|
+
// needs their working copy live, not a stale compiled binary that happens to
|
|
352
|
+
// be installed via pnpm. A production install has no `packages/` dir, so this
|
|
353
|
+
// never short-circuits there. (Preserves server-up's historic dev-tree
|
|
354
|
+
// behavior — it always ran source before DDR-084.)
|
|
355
|
+
if (isLocalDevTree(pkgRoot, { existsSync })) return null;
|
|
356
|
+
const sideChannel = resolve(pkgRoot, 'cli', '.platform-binary-path');
|
|
357
|
+
try {
|
|
358
|
+
if (existsSync(sideChannel)) {
|
|
359
|
+
const candidate = readFileSync(sideChannel, 'utf8').trim();
|
|
360
|
+
// Existence AND the structural allowlist — a poisoned side-channel pointing
|
|
361
|
+
// at an arbitrary executable is ignored (falls through to lazy resolve).
|
|
362
|
+
if (candidate && existsSync(candidate) && isPlausiblePlatformBinary(candidate)) {
|
|
363
|
+
return candidate;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
} catch {
|
|
367
|
+
/* fall through to lazy resolve */
|
|
368
|
+
}
|
|
369
|
+
return lazyResolveBinary({ pkgRoot, fs: { existsSync, chmodSync } }).binPath;
|
|
370
|
+
}
|
|
371
|
+
|
|
298
372
|
function lazyResolveBinary({ pkgRoot, fs }) {
|
|
299
373
|
const slug = detectPlatformSlug();
|
|
300
374
|
if (!slug) return { binPath: null, slug: null };
|
|
@@ -348,7 +422,7 @@ function checkDevDeps({ pkgRoot }) {
|
|
|
348
422
|
// with a less actionable error.
|
|
349
423
|
const required = ['magic-string', 'oxc-parser'];
|
|
350
424
|
const missing = [];
|
|
351
|
-
const paths = [resolve(pkgRoot, '
|
|
425
|
+
const paths = [resolve(pkgRoot, 'apps', 'studio'), resolve(pkgRoot)];
|
|
352
426
|
for (const dep of required) {
|
|
353
427
|
try {
|
|
354
428
|
require.resolve(dep, { paths });
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
import assert from 'node:assert/strict';
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
|
-
import { mkdtempSync, rmSync } from 'node:fs';
|
|
11
|
+
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { tmpdir } from 'node:os';
|
|
13
13
|
import { dirname, join, resolve } from 'node:path';
|
|
14
14
|
import { test } from 'node:test';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { isPlausiblePlatformBinary, resolveServerBinary } from './design.mjs';
|
|
16
17
|
|
|
17
18
|
const BIN = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'maude.mjs');
|
|
18
19
|
|
|
@@ -54,3 +55,134 @@ test('design help lists the dev-tooling verbs', () => {
|
|
|
54
55
|
assert.match(res.stdout, new RegExp(verb), `usage should mention ${verb}`);
|
|
55
56
|
}
|
|
56
57
|
});
|
|
58
|
+
|
|
59
|
+
// resolveServerBinary — the dev-server boot-runtime resolver (DDR-084). server-up
|
|
60
|
+
// must boot the compiled platform binary on a production install (it embeds yjs +
|
|
61
|
+
// every dep; `bun server.ts` from source can't resolve them — the historic
|
|
62
|
+
// yjs-at-boot crash), but keep using SOURCE in the local dev tree so a maintainer's
|
|
63
|
+
// edits are live.
|
|
64
|
+
function fakePkgRoot({ devTree = false, sideChannelBin = null } = {}) {
|
|
65
|
+
const root = mkdtempSync(join(tmpdir(), 'maude-pkgroot-'));
|
|
66
|
+
if (devTree) {
|
|
67
|
+
mkdirSync(join(root, 'packages', 'maude-darwin-arm64'), { recursive: true });
|
|
68
|
+
writeFileSync(join(root, 'packages', 'maude-darwin-arm64', 'package.json'), '{}');
|
|
69
|
+
}
|
|
70
|
+
if (sideChannelBin) {
|
|
71
|
+
mkdirSync(join(root, 'cli'), { recursive: true });
|
|
72
|
+
writeFileSync(join(root, 'cli', '.platform-binary-path'), sideChannelBin);
|
|
73
|
+
}
|
|
74
|
+
return root;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
test('resolveServerBinary → null in the local dev tree (packages/ present) — boots source', () => {
|
|
78
|
+
const root = fakePkgRoot({ devTree: true });
|
|
79
|
+
try {
|
|
80
|
+
delete process.env.MAUDE_FORCE_SOURCE;
|
|
81
|
+
assert.equal(resolveServerBinary({ pkgRoot: root }), null);
|
|
82
|
+
} finally {
|
|
83
|
+
rmSync(root, { recursive: true, force: true });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Build an executable in a layout the allowlist accepts (`maude-<slug>/maude`)
|
|
88
|
+
// or rejects (anything else), under a throwaway dir.
|
|
89
|
+
function fakeBinary({ conforming = true } = {}) {
|
|
90
|
+
const home = mkdtempSync(join(tmpdir(), 'maude-bin-'));
|
|
91
|
+
const dir = join(home, conforming ? 'maude-darwin-arm64' : 'evil');
|
|
92
|
+
mkdirSync(dir, { recursive: true });
|
|
93
|
+
const bin = join(dir, 'maude');
|
|
94
|
+
writeFileSync(bin, '#!/bin/sh\n');
|
|
95
|
+
chmodSync(bin, 0o755);
|
|
96
|
+
return { home, bin };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
test('resolveServerBinary → null when MAUDE_FORCE_SOURCE=1 (maintainer override)', () => {
|
|
100
|
+
const { home, bin } = fakeBinary();
|
|
101
|
+
const root = fakePkgRoot({ sideChannelBin: bin }); // NOT a dev tree
|
|
102
|
+
const prev = process.env.MAUDE_FORCE_SOURCE;
|
|
103
|
+
try {
|
|
104
|
+
process.env.MAUDE_FORCE_SOURCE = '1';
|
|
105
|
+
assert.equal(resolveServerBinary({ pkgRoot: root }), null);
|
|
106
|
+
} finally {
|
|
107
|
+
if (prev === undefined) delete process.env.MAUDE_FORCE_SOURCE;
|
|
108
|
+
else process.env.MAUDE_FORCE_SOURCE = prev;
|
|
109
|
+
rmSync(root, { recursive: true, force: true });
|
|
110
|
+
rmSync(home, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('resolveServerBinary → side-channel path on a production install (no packages/)', () => {
|
|
115
|
+
const { home, bin } = fakeBinary(); // conforming maude-<slug>/maude layout
|
|
116
|
+
const root = fakePkgRoot({ sideChannelBin: bin }); // production shape
|
|
117
|
+
const prev = process.env.MAUDE_FORCE_SOURCE;
|
|
118
|
+
try {
|
|
119
|
+
delete process.env.MAUDE_FORCE_SOURCE;
|
|
120
|
+
assert.equal(resolveServerBinary({ pkgRoot: root }), bin);
|
|
121
|
+
} finally {
|
|
122
|
+
if (prev !== undefined) process.env.MAUDE_FORCE_SOURCE = prev;
|
|
123
|
+
rmSync(root, { recursive: true, force: true });
|
|
124
|
+
rmSync(home, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('resolveServerBinary → REJECTS a side-channel pointing outside the maude-<slug>/ layout (DDR-084 allowlist)', () => {
|
|
129
|
+
const { home, bin } = fakeBinary({ conforming: false }); // <tmp>/evil/maude
|
|
130
|
+
const root = fakePkgRoot({ sideChannelBin: bin }); // production shape, no real platform pkg
|
|
131
|
+
const prev = process.env.MAUDE_FORCE_SOURCE;
|
|
132
|
+
try {
|
|
133
|
+
delete process.env.MAUDE_FORCE_SOURCE;
|
|
134
|
+
// Poisoned side-channel is ignored → falls through to lazyResolve, which finds
|
|
135
|
+
// nothing in the fake root → null (server-up then boots source, not the planted bin).
|
|
136
|
+
assert.equal(resolveServerBinary({ pkgRoot: root }), null);
|
|
137
|
+
} finally {
|
|
138
|
+
if (prev !== undefined) process.env.MAUDE_FORCE_SOURCE = prev;
|
|
139
|
+
rmSync(root, { recursive: true, force: true });
|
|
140
|
+
rmSync(home, { recursive: true, force: true });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('isPlausiblePlatformBinary — accepts maude-<slug>/maude, rejects everything else', () => {
|
|
145
|
+
assert.equal(isPlausiblePlatformBinary('/x/node_modules/@1agh/maude-darwin-arm64/maude'), true);
|
|
146
|
+
assert.equal(isPlausiblePlatformBinary('/x/packages/maude-linux-x64-musl/maude'), true);
|
|
147
|
+
assert.equal(isPlausiblePlatformBinary('/x/maude-win32-x64/maude.exe'), true);
|
|
148
|
+
assert.equal(isPlausiblePlatformBinary('/tmp/evil/maude'), false); // parent not maude-<slug>
|
|
149
|
+
assert.equal(isPlausiblePlatformBinary('/x/maude-darwin-arm64/evil'), false); // basename not maude
|
|
150
|
+
assert.equal(isPlausiblePlatformBinary(''), false);
|
|
151
|
+
assert.equal(isPlausiblePlatformBinary(null), false);
|
|
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
|
+
return { status: r.status, firstErr: (r.stderr || '').split('\n').find(Boolean) ?? '' };
|
|
169
|
+
} finally {
|
|
170
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const viaDesign = bootAgainstEmpty(['design', 'serve']);
|
|
174
|
+
const viaStudio = bootAgainstEmpty(['studio']);
|
|
175
|
+
// Both fail loud (no .design/) — same exit code, same first-line diagnostic.
|
|
176
|
+
assert.notEqual(viaStudio.status, 0, `studio should not boot cleanly: ${viaStudio.firstErr}`);
|
|
177
|
+
assert.equal(viaStudio.status, viaDesign.status);
|
|
178
|
+
assert.equal(viaStudio.firstErr, viaDesign.firstErr);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('`maude studio` is recognized (not an unknown command)', () => {
|
|
182
|
+
const BIN_PATH = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'maude.mjs');
|
|
183
|
+
const r = spawnSync(process.execPath, [BIN_PATH, 'studio', '--root', '/nonexistent-xyz'], {
|
|
184
|
+
encoding: 'utf8',
|
|
185
|
+
timeout: 30000,
|
|
186
|
+
});
|
|
187
|
+
assert.doesNotMatch(r.stderr || '', /unknown command/);
|
|
188
|
+
});
|
package/cli/commands/help.mjs
CHANGED
|
@@ -29,9 +29,14 @@ COMMANDS
|
|
|
29
29
|
contract — see DDR-061); 'list' shows layers + sizes; 'stats' shows
|
|
30
30
|
hit-rate; 'inspect' pretty-prints entries; 'clear' wipes a layer or all.
|
|
31
31
|
|
|
32
|
+
studio [--port N] [--root PATH]
|
|
33
|
+
Alias for 'maude design serve' — boot the canvas studio (the design
|
|
34
|
+
dev server) in the current repo. Forwards all remaining args.
|
|
35
|
+
|
|
32
36
|
design serve [--port N] [--root PATH]
|
|
33
37
|
Start the design plugin's dev server in the current repo. Equivalent
|
|
34
|
-
to invoking 'claude-design-server'. Forwards all
|
|
38
|
+
to 'maude studio' / invoking 'claude-design-server'. Forwards all
|
|
39
|
+
remaining args.
|
|
35
40
|
|
|
36
41
|
design init [--name <slug>] [--ds <name>] [--force] [--dry-run]
|
|
37
42
|
[--no-discovery | --discovery-payload <path>]
|
|
@@ -43,7 +48,7 @@ COMMANDS
|
|
|
43
48
|
|
|
44
49
|
design <screenshot|server-up|prep|slug|bootstrap-check|runtime-health
|
|
45
50
|
|smoke|canvas-edit|handoff|asset-sweep|visual-sanity> [args]
|
|
46
|
-
Dispatch to the
|
|
51
|
+
Dispatch to the studio's bundled bash helper of the same name.
|
|
47
52
|
maude resolves it from its own package root and sets CLAUDE_PLUGIN_ROOT
|
|
48
53
|
for the child; stdout/stderr/exit-code pass straight through. This is
|
|
49
54
|
the contract plugin markdown uses instead of a raw bin path (DDR-062).
|
|
@@ -88,6 +93,7 @@ EXAMPLES
|
|
|
88
93
|
maude config get motion.complex
|
|
89
94
|
maude cache list
|
|
90
95
|
maude cache clear research/domain
|
|
96
|
+
maude studio --port 4399
|
|
91
97
|
maude design serve --port 4399
|
|
92
98
|
maude design init --no-discovery --name acme-app
|
|
93
99
|
maude design slug "Some Canvas Name"
|