@1agh/maude 1.0.9 → 1.2.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/apps/studio/acp/bridge.ts +18 -13
- package/apps/studio/acp/probe.ts +268 -16
- package/apps/studio/acp/transcript-io.ts +394 -0
- package/apps/studio/acp/transcript.ts +103 -38
- package/apps/studio/api.ts +139 -26
- package/apps/studio/bin/_import-figma.mjs +57 -11
- package/apps/studio/bin/_seed-fixture.mjs +163 -0
- package/apps/studio/canvas-imports.ts +89 -0
- package/apps/studio/client/app.jsx +257 -7
- package/apps/studio/client/export-center.jsx +15 -7
- package/apps/studio/client/panels/ReadinessList.jsx +7 -1
- package/apps/studio/client/panels/SyncPanel.jsx +125 -4
- package/apps/studio/client/report-bug.jsx +19 -1
- package/apps/studio/client/styles/3-shell-maude.css +34 -0
- package/apps/studio/client/styles/4-components.css +26 -0
- package/apps/studio/collab/persistence.ts +132 -16
- package/apps/studio/collab/registry.ts +10 -18
- package/apps/studio/debug-bundle.ts +13 -0
- package/apps/studio/dist/client.bundle.js +1128 -1128
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/export-dialog.tsx +54 -0
- package/apps/studio/exporters/degraded.ts +19 -3
- package/apps/studio/exporters/ghostscript.ts +194 -0
- package/apps/studio/exporters/pdf-fonts.ts +261 -0
- package/apps/studio/exporters/pdf.ts +152 -3
- package/apps/studio/exporters/remote.ts +36 -1
- package/apps/studio/fs-watch.ts +45 -1
- package/apps/studio/http.ts +7 -1
- package/apps/studio/mem.ts +45 -9
- package/apps/studio/readiness.ts +42 -7
- package/apps/studio/server.ts +11 -4
- package/apps/studio/sync/agent.ts +136 -29
- package/apps/studio/sync/asset-push.ts +1 -47
- package/apps/studio/sync/codec.ts +122 -31
- package/apps/studio/sync/cold-start-apply.ts +7 -0
- package/apps/studio/sync/cold-start.ts +118 -22
- package/apps/studio/sync/comment-identity.ts +68 -0
- package/apps/studio/sync/connection-state.ts +15 -1
- package/apps/studio/sync/file-ledger.ts +117 -0
- package/apps/studio/sync/file-plane.ts +623 -27
- package/apps/studio/sync/index.ts +711 -20
- package/apps/studio/sync/journal-client.ts +13 -1
- package/apps/studio/sync/migrate-seed.ts +40 -3
- package/apps/studio/sync/presentation.ts +26 -3
- package/apps/studio/sync/retry-after.ts +169 -0
- package/apps/studio/sync/seed-progress.ts +218 -0
- package/apps/studio/sync/status.ts +122 -5
- package/apps/studio/sync/transport-error.ts +111 -0
- package/apps/studio/whats-new.json +91 -0
- package/cli/bin/maude.mjs +2 -0
- package/cli/commands/codex.mjs +191 -0
- package/cli/commands/harness.mjs +1051 -0
- package/cli/commands/help.mjs +13 -0
- package/cli/lib/design-link.mjs +190 -2
- package/cli/lib/harness/capabilities.mjs +302 -0
- package/cli/lib/harness/codex-runtime.mjs +889 -0
- package/cli/lib/harness/compatibility.mjs +27 -0
- package/cli/lib/harness/discover-claude.mjs +1393 -0
- package/cli/lib/harness/managed-state.mjs +1296 -0
- package/cli/lib/harness/model.mjs +86 -0
- package/cli/lib/harness/secrets.mjs +390 -0
- package/cli/lib/harness/targets/codex.mjs +1141 -0
- package/cli/lib/harness/targets/opencode.mjs +807 -0
- package/cli/lib/harness/transaction.mjs +1099 -0
- package/cli/lib/hubs-config.mjs +35 -8
- package/cli/templates/harness/opencode/maude-projector.ts +58 -0
- package/docs/harness-capability-matrix.md +125 -0
- package/docs/harness-environment-projection.md +95 -0
- package/package.json +32 -9
- package/plugins/flow/.claude-plugin/config.schema.json +8 -0
- package/apps/studio/.ai/cache/_stats.json +0 -7
- package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
- package/apps/studio/bin/_curl-local.test.mjs +0 -280
- package/apps/studio/bin/_pw-launch.test.mjs +0 -90
- package/apps/studio/bin/_smart-frames.test.mjs +0 -195
- package/apps/studio/bin/_transcribe.test.mjs +0 -80
- package/apps/studio/bun.lock +0 -928
- package/apps/studio/draw/test/animate.test.ts +0 -172
- package/apps/studio/draw/test/brush.test.ts +0 -213
- package/apps/studio/draw/test/composition.test.ts +0 -141
- package/apps/studio/draw/test/geometry.test.ts +0 -199
- package/apps/studio/draw/test/gradient.test.ts +0 -167
- package/apps/studio/draw/test/layout.test.ts +0 -120
- package/apps/studio/draw/test/morph.test.ts +0 -107
- package/apps/studio/draw/test/optimize.test.ts +0 -40
- package/apps/studio/draw/test/palette.test.ts +0 -123
- package/apps/studio/draw/test/primitives.test.ts +0 -129
- package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
- package/apps/studio/draw/test/serialize.test.ts +0 -105
- package/apps/studio/figma/assets.test.ts +0 -464
- package/apps/studio/figma/client.test.ts +0 -395
- package/apps/studio/figma/codegen-client.test.ts +0 -276
- package/apps/studio/figma/codegen-fonts.test.ts +0 -103
- package/apps/studio/figma/codegen-values.test.ts +0 -179
- package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
- package/apps/studio/figma/fig-decode.test.ts +0 -788
- package/apps/studio/figma/fig-differential.test.ts +0 -182
- package/apps/studio/figma/fig-translator.test.ts +0 -192
- package/apps/studio/figma/fig-vector.test.ts +0 -113
- package/apps/studio/figma/from-codegen.test.ts +0 -408
- package/apps/studio/figma/sanitize.test.ts +0 -325
- package/apps/studio/figma/tailwind-map.test.ts +0 -142
- package/apps/studio/figma/to-artboard.test.ts +0 -808
- package/apps/studio/figma/to-render.test.ts +0 -180
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
- package/apps/studio/figma/to-strokes.test.ts +0 -705
- package/apps/studio/figma/to-tokens.test.ts +0 -321
- package/apps/studio/figma/url.test.ts +0 -167
- package/apps/studio/footage/schema.test.ts +0 -287
- package/apps/studio/generation/adapters/groq.test.ts +0 -80
- package/apps/studio/generation/audio-library.test.ts +0 -95
- package/apps/studio/generation/captions.test.ts +0 -78
- package/apps/studio/generation/elevenlabs.test.ts +0 -223
- package/apps/studio/generation/gemini.test.ts +0 -350
- package/apps/studio/generation/jobs.test.ts +0 -128
- package/apps/studio/generation/keys.test.ts +0 -75
- package/apps/studio/generation/prefs.test.ts +0 -95
- package/apps/studio/generation/types.test.ts +0 -123
- package/apps/studio/generation/whisper-models.test.ts +0 -179
- package/apps/studio/test/_helpers.ts +0 -108
- package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
- package/apps/studio/test/acp-activity.test.ts +0 -154
- package/apps/studio/test/acp-ai-activity.test.ts +0 -182
- package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
- package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
- package/apps/studio/test/acp-branch-guard.test.ts +0 -123
- package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
- package/apps/studio/test/acp-bridge.test.ts +0 -301
- package/apps/studio/test/acp-capabilities.test.ts +0 -123
- package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
- package/apps/studio/test/acp-commands.test.ts +0 -119
- package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
- package/apps/studio/test/acp-elicitation.test.ts +0 -251
- package/apps/studio/test/acp-env.test.ts +0 -95
- package/apps/studio/test/acp-mode-banner.test.ts +0 -45
- package/apps/studio/test/acp-origin-gate.test.ts +0 -160
- package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
- package/apps/studio/test/acp-permission.test.ts +0 -278
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
- package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
- package/apps/studio/test/acp-session-plugins.test.ts +0 -209
- package/apps/studio/test/acp-toolgroup.test.ts +0 -76
- package/apps/studio/test/acp-transcript-view.test.ts +0 -71
- package/apps/studio/test/acp-transcript.test.ts +0 -238
- package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
- package/apps/studio/test/acp-usage.test.ts +0 -143
- package/apps/studio/test/acp-write-gate.test.ts +0 -323
- package/apps/studio/test/acp-write-scope.test.ts +0 -533
- package/apps/studio/test/active-state.test.ts +0 -186
- package/apps/studio/test/activity.test.ts +0 -189
- package/apps/studio/test/ai-activity.test.ts +0 -113
- package/apps/studio/test/annotate-write.test.ts +0 -1074
- package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
- package/apps/studio/test/annotations-align.test.ts +0 -88
- package/apps/studio/test/annotations-api.test.ts +0 -145
- package/apps/studio/test/annotations-bindings.test.ts +0 -262
- package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
- package/apps/studio/test/annotations-groups.test.ts +0 -231
- package/apps/studio/test/annotations-layer.test.ts +0 -1011
- package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
- package/apps/studio/test/annotations-snap.test.ts +0 -135
- package/apps/studio/test/annotations-text-format.test.ts +0 -396
- package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
- package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
- package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
- package/apps/studio/test/artboard-kinds.test.tsx +0 -83
- package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
- package/apps/studio/test/asset-api.test.ts +0 -149
- package/apps/studio/test/assets-s3.test.ts +0 -249
- package/apps/studio/test/binary-smoke.test.ts +0 -47
- package/apps/studio/test/boot-self-heal.test.ts +0 -87
- package/apps/studio/test/browse-posture.test.tsx +0 -107
- package/apps/studio/test/bundle-smoke.test.ts +0 -46
- package/apps/studio/test/camera-reveal.test.tsx +0 -173
- package/apps/studio/test/canvas-artifacts.test.ts +0 -125
- package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
- package/apps/studio/test/canvas-build.test.ts +0 -141
- package/apps/studio/test/canvas-create-api.test.ts +0 -676
- package/apps/studio/test/canvas-cursors.test.ts +0 -164
- package/apps/studio/test/canvas-edit.test.ts +0 -470
- package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
- package/apps/studio/test/canvas-header.test.ts +0 -127
- package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
- package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
- package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
- package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
- package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
- package/apps/studio/test/canvas-list-watch.test.ts +0 -388
- package/apps/studio/test/canvas-media-drop.test.ts +0 -187
- package/apps/studio/test/canvas-meta-api.test.ts +0 -707
- package/apps/studio/test/canvas-move-api.test.ts +0 -587
- package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
- package/apps/studio/test/canvas-pipeline.test.ts +0 -180
- package/apps/studio/test/canvas-rects.test.ts +0 -198
- package/apps/studio/test/canvas-reorder.test.ts +0 -211
- package/apps/studio/test/canvas-route.test.ts +0 -179
- package/apps/studio/test/canvas-shell-base.test.ts +0 -107
- package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
- package/apps/studio/test/canvas-url.test.ts +0 -138
- package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
- package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
- package/apps/studio/test/capture-core.test.ts +0 -32
- package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
- package/apps/studio/test/chat-attachments.test.ts +0 -117
- package/apps/studio/test/chat-context.test.ts +0 -129
- package/apps/studio/test/chat-markdown.test.tsx +0 -58
- package/apps/studio/test/clip-addressing.test.ts +0 -738
- package/apps/studio/test/clip-ops.test.ts +0 -922
- package/apps/studio/test/cloud-build.test.ts +0 -95
- package/apps/studio/test/cloud-connect-note.test.ts +0 -135
- package/apps/studio/test/cloud-endpoints.test.ts +0 -590
- package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
- package/apps/studio/test/cloud-history-posture.test.ts +0 -230
- package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
- package/apps/studio/test/cloud-renew.test.ts +0 -205
- package/apps/studio/test/cloud-session-role.test.ts +0 -161
- package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
- package/apps/studio/test/cold-start-apply.test.ts +0 -303
- package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
- package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
- package/apps/studio/test/collab-bridge.test.ts +0 -79
- package/apps/studio/test/collab-loopback.test.ts +0 -63
- package/apps/studio/test/collab-origin-gate.test.ts +0 -323
- package/apps/studio/test/collab-protocol.test.ts +0 -146
- package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
- package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
- package/apps/studio/test/collab-room.test.ts +0 -188
- package/apps/studio/test/collab-session-survival.test.tsx +0 -176
- package/apps/studio/test/collab-stress.test.ts +0 -129
- package/apps/studio/test/comment-mount.test.ts +0 -97
- package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
- package/apps/studio/test/comments-api.test.ts +0 -277
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
- package/apps/studio/test/comments-overlay.test.ts +0 -117
- package/apps/studio/test/compile-entry.test.ts +0 -133
- package/apps/studio/test/component-map.test.ts +0 -48
- package/apps/studio/test/config-projection.test.ts +0 -104
- package/apps/studio/test/config-reload.test.ts +0 -230
- package/apps/studio/test/config-version.test.ts +0 -88
- package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
- package/apps/studio/test/convert-to-absolute.test.ts +0 -333
- package/apps/studio/test/credential-grammar.test.ts +0 -107
- package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
- package/apps/studio/test/csrf-write-guard.test.ts +0 -141
- package/apps/studio/test/debug-bundle.test.ts +0 -105
- package/apps/studio/test/design-setup-readiness.test.ts +0 -155
- package/apps/studio/test/detach-component.test.ts +0 -94
- package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
- package/apps/studio/test/dom-selection.test.ts +0 -198
- package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
- package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
- package/apps/studio/test/edit-persistence.test.ts +0 -91
- package/apps/studio/test/edit-scope-api.test.ts +0 -119
- package/apps/studio/test/edit-source-command.test.ts +0 -142
- package/apps/studio/test/edit-suppress.test.ts +0 -170
- package/apps/studio/test/editing-presence.test.ts +0 -103
- package/apps/studio/test/element-resize.test.ts +0 -136
- package/apps/studio/test/element-structural-api.test.ts +0 -434
- package/apps/studio/test/element-structural-edit.test.ts +0 -750
- package/apps/studio/test/ensure-browser.test.ts +0 -92
- package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
- package/apps/studio/test/export-assemble.test.ts +0 -53
- package/apps/studio/test/export-browser-lane.test.ts +0 -126
- package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
- package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
- package/apps/studio/test/export-center.test.tsx +0 -287
- package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
- package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
- package/apps/studio/test/export-lane.test.ts +0 -245
- package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
- package/apps/studio/test/exporters/canva.test.ts +0 -63
- package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
- package/apps/studio/test/exporters/endpoint.test.ts +0 -121
- package/apps/studio/test/exporters/history.test.ts +0 -107
- package/apps/studio/test/exporters/html.test.ts +0 -26
- package/apps/studio/test/exporters/jobs.test.ts +0 -342
- package/apps/studio/test/exporters/pdf.test.ts +0 -85
- package/apps/studio/test/exporters/png.test.ts +0 -103
- package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
- package/apps/studio/test/exporters/pptx.test.ts +0 -31
- package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
- package/apps/studio/test/exporters/runtime.test.ts +0 -59
- package/apps/studio/test/exporters/scope.test.ts +0 -292
- package/apps/studio/test/exporters/svg.test.ts +0 -29
- package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
- package/apps/studio/test/exporters/zip.test.ts +0 -104
- package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
- package/apps/studio/test/figjam-v3-model.test.ts +0 -342
- package/apps/studio/test/figma-explode.test.ts +0 -438
- package/apps/studio/test/figma-provenance.test.ts +0 -108
- package/apps/studio/test/figma-routes.test.ts +0 -294
- package/apps/studio/test/file-lock.test.ts +0 -84
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -13
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
- package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
- package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
- package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
- package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
- package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
- package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
- package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
- package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
- package/apps/studio/test/footage-store.test.ts +0 -100
- package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
- package/apps/studio/test/fs-watch.test.ts +0 -41
- package/apps/studio/test/gemma-models.test.ts +0 -245
- package/apps/studio/test/generate-route.test.ts +0 -106
- package/apps/studio/test/git-api.test.ts +0 -0
- package/apps/studio/test/git-branches.test.ts +0 -341
- package/apps/studio/test/git-cloud-posture.test.ts +0 -59
- package/apps/studio/test/git-grouping.test.ts +0 -106
- package/apps/studio/test/git-lifecycle.test.ts +0 -100
- package/apps/studio/test/git-log-format.test.ts +0 -95
- package/apps/studio/test/git-safe-rel.test.ts +0 -132
- package/apps/studio/test/git-system-engine.test.ts +0 -135
- package/apps/studio/test/git-watch.test.ts +0 -97
- package/apps/studio/test/github-api.test.ts +0 -577
- package/apps/studio/test/grid-track-handles.test.ts +0 -160
- package/apps/studio/test/handoff-static-frames.test.ts +0 -215
- package/apps/studio/test/handoff.test.ts +0 -329
- package/apps/studio/test/history-rollback.test.ts +0 -88
- package/apps/studio/test/hmr-broadcast.test.ts +0 -236
- package/apps/studio/test/hmr-classify.test.ts +0 -87
- package/apps/studio/test/hub-link.test.ts +0 -80
- package/apps/studio/test/identity-cache.test.ts +0 -83
- package/apps/studio/test/import-asset-browser.test.ts +0 -64
- package/apps/studio/test/import-asset-route.test.ts +0 -71
- package/apps/studio/test/import-asset.test.ts +0 -427
- package/apps/studio/test/import-brand-browser.test.ts +0 -88
- package/apps/studio/test/import-brand-route.test.ts +0 -120
- package/apps/studio/test/import-brand.test.ts +0 -206
- package/apps/studio/test/import-figma.test.ts +0 -667
- package/apps/studio/test/import-tokens.test.ts +0 -722
- package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
- package/apps/studio/test/input-router.test.ts +0 -757
- package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
- package/apps/studio/test/inspect-selections.test.ts +0 -219
- package/apps/studio/test/knob-props-authored.test.ts +0 -87
- package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
- package/apps/studio/test/locator.test.ts +0 -214
- package/apps/studio/test/marquee-overlay.test.ts +0 -94
- package/apps/studio/test/media-commit-chain.test.ts +0 -210
- package/apps/studio/test/mode-toggle.test.tsx +0 -226
- package/apps/studio/test/motion-sample.test.ts +0 -35
- package/apps/studio/test/move-artboards-command.test.ts +0 -108
- package/apps/studio/test/participants-chrome.test.ts +0 -65
- package/apps/studio/test/paths.test.ts +0 -88
- package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
- package/apps/studio/test/perf-harness.ts +0 -193
- package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
- package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
- package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
- package/apps/studio/test/photo-edit-api.test.ts +0 -201
- package/apps/studio/test/photo-filters.test.ts +0 -149
- package/apps/studio/test/photo-pipeline.test.ts +0 -106
- package/apps/studio/test/photo-taxonomy.test.ts +0 -96
- package/apps/studio/test/print-marks.test.ts +0 -113
- package/apps/studio/test/print-units.test.ts +0 -173
- package/apps/studio/test/read-annotations.test.ts +0 -727
- package/apps/studio/test/read-only-gate.test.ts +0 -188
- package/apps/studio/test/read-only-role.test.ts +0 -95
- package/apps/studio/test/readiness.test.ts +0 -226
- package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
- package/apps/studio/test/reorder-api.test.ts +0 -210
- package/apps/studio/test/repo-concurrency.test.ts +0 -146
- package/apps/studio/test/repo-lock.test.ts +0 -350
- package/apps/studio/test/report-proxy.test.ts +0 -125
- package/apps/studio/test/ripple.test.ts +0 -197
- package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
- package/apps/studio/test/runtime-bundle.test.ts +0 -69
- package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
- package/apps/studio/test/scaffold-design.test.ts +0 -122
- package/apps/studio/test/server-lifecycle.test.ts +0 -38
- package/apps/studio/test/session-runtime-state.test.ts +0 -226
- package/apps/studio/test/session-scope.test.ts +0 -100
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
- package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
- package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
- package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
- package/apps/studio/test/shared-doc-projection.test.ts +0 -238
- package/apps/studio/test/shell-importmap.test.ts +0 -56
- package/apps/studio/test/sizing-mode.test.ts +0 -102
- package/apps/studio/test/slash-commands.test.ts +0 -117
- package/apps/studio/test/snap-distance-pill.test.ts +0 -68
- package/apps/studio/test/spacing-handles.test.ts +0 -138
- package/apps/studio/test/specimen-select.test.ts +0 -88
- package/apps/studio/test/sync-agent.test.ts +0 -660
- package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
- package/apps/studio/test/sync-asset-push.test.ts +0 -931
- package/apps/studio/test/sync-atomic-write.test.ts +0 -62
- package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
- package/apps/studio/test/sync-autocommit.test.ts +0 -537
- package/apps/studio/test/sync-canvas-path.test.ts +0 -200
- package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
- package/apps/studio/test/sync-codec.test.ts +0 -230
- package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
- package/apps/studio/test/sync-cold-start.test.ts +0 -304
- package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
- package/apps/studio/test/sync-connection-state.test.ts +0 -337
- package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
- package/apps/studio/test/sync-decide-file.test.ts +0 -420
- package/apps/studio/test/sync-doc-name.test.ts +0 -281
- package/apps/studio/test/sync-echo-guard.test.ts +0 -96
- package/apps/studio/test/sync-file-ledger.test.ts +0 -334
- package/apps/studio/test/sync-file-membership.test.ts +0 -347
- package/apps/studio/test/sync-file-plane.test.ts +0 -976
- package/apps/studio/test/sync-file-pull.test.ts +0 -333
- package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
- package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
- package/apps/studio/test/sync-hardening.test.ts +0 -586
- package/apps/studio/test/sync-hub-listing.test.ts +0 -46
- package/apps/studio/test/sync-hubs-config.test.ts +0 -133
- package/apps/studio/test/sync-incident-replay.test.ts +0 -211
- package/apps/studio/test/sync-journal.test.ts +0 -176
- package/apps/studio/test/sync-meta-codec.test.ts +0 -199
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
- package/apps/studio/test/sync-move-retirement.test.ts +0 -231
- package/apps/studio/test/sync-panel-surface.test.ts +0 -153
- package/apps/studio/test/sync-path-pull.test.ts +0 -531
- package/apps/studio/test/sync-presentation.test.ts +0 -262
- package/apps/studio/test/sync-pull-budget.test.ts +0 -169
- package/apps/studio/test/sync-remote-docs.test.ts +0 -333
- package/apps/studio/test/sync-resync-routes.test.ts +0 -168
- package/apps/studio/test/sync-runtime.test.ts +0 -1675
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
- package/apps/studio/test/sync-settings-routes.test.ts +0 -195
- package/apps/studio/test/sync-settings.test.ts +0 -151
- package/apps/studio/test/sync-status.test.ts +0 -261
- package/apps/studio/test/sync-supervisor.test.ts +0 -262
- package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
- package/apps/studio/test/sync-trash.test.ts +0 -132
- package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
- package/apps/studio/test/sync-untrusted.test.ts +0 -103
- package/apps/studio/test/system-endpoint.test.ts +0 -144
- package/apps/studio/test/text-editability-stamp.test.ts +0 -131
- package/apps/studio/test/timeline-comp-target.test.ts +0 -139
- package/apps/studio/test/timeline-media-cache.test.ts +0 -41
- package/apps/studio/test/timeline-parse.test.ts +0 -184
- package/apps/studio/test/timeline-scale.test.ts +0 -65
- package/apps/studio/test/timeline-snap.test.ts +0 -85
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
- package/apps/studio/test/tool-palette.test.tsx +0 -55
- package/apps/studio/test/tour-overlay.test.tsx +0 -90
- package/apps/studio/test/trusted-request-host.test.ts +0 -66
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
- package/apps/studio/test/undo-stack.test.ts +0 -244
- package/apps/studio/test/use-agent-presence.test.tsx +0 -117
- package/apps/studio/test/use-annotation-resize.test.ts +0 -402
- package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
- package/apps/studio/test/use-artboard-drag.test.ts +0 -324
- package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
- package/apps/studio/test/use-collab.test.ts +0 -0
- package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
- package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
- package/apps/studio/test/use-selection-set.test.tsx +0 -166
- package/apps/studio/test/use-snap-guides.test.ts +0 -271
- package/apps/studio/test/use-tool-mode.test.tsx +0 -186
- package/apps/studio/test/use-undo-stack.test.tsx +0 -223
- package/apps/studio/test/video-asset.test.ts +0 -163
- package/apps/studio/test/video-comp-fixture.test.ts +0 -50
- package/apps/studio/test/video-comp.test.ts +0 -270
- package/apps/studio/test/video-encode-lib.test.ts +0 -63
- package/apps/studio/test/video-render-bridge.test.ts +0 -171
- package/apps/studio/test/whats-new.test.ts +0 -113
- package/apps/studio/test/whisper-setup.test.ts +0 -97
- package/apps/studio/test/workspace-containment.test.ts +0 -382
- package/apps/studio/test/workspace-signin.test.ts +0 -292
- package/apps/studio/test/ws-handshake.test.ts +0 -33
- package/cli/commands/cache.test.mjs +0 -166
- package/cli/commands/design-link.test.mjs +0 -419
- package/cli/commands/design.test.mjs +0 -240
- package/cli/commands/doctor.test.mjs +0 -237
- package/cli/commands/hub-workspace.test.mjs +0 -275
- package/cli/commands/hub.test.mjs +0 -225
- package/cli/commands/kg.test.mjs +0 -142
- package/cli/commands/preflight.test.mjs +0 -46
- package/cli/lib/argv.test.mjs +0 -46
- package/cli/lib/cache.test.mjs +0 -303
- package/cli/lib/cell-plan.test.mjs +0 -225
- package/cli/lib/config-lint.test.mjs +0 -117
- package/cli/lib/ddr-to-kgai.test.mjs +0 -118
- package/cli/lib/design-ownership.test.mjs +0 -329
- package/cli/lib/fetch-asset.test.mjs +0 -213
- package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
- package/cli/lib/figma-import-controls.test.mjs +0 -70
- package/cli/lib/flow-design-integration.test.mjs +0 -165
- package/cli/lib/gitignore-block.test.mjs +0 -136
- package/cli/lib/gitignore-drift.test.mjs +0 -156
- package/cli/lib/hubs-config.test.mjs +0 -165
- package/cli/lib/pkg-root.test.mjs +0 -111
- package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
- package/cli/lib/plugin-name-namespace.test.mjs +0 -71
- package/cli/lib/reconstruct-toolset.test.mjs +0 -194
- package/cli/lib/stack-detect.test.mjs +0 -121
- package/cli/lib/update-check.test.mjs +0 -32
- package/cli/lib/workspace-plan.test.mjs +0 -699
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
// canvas-rects.test.ts — feature-whiteboard-ai-toolkit. Unit + fixture
|
|
2
|
-
// coverage for the STATIC (no-browser) fallback shim behind
|
|
3
|
-
// `maude design canvas-rects`. The LIVE lane (window.__maudeCanvasRects,
|
|
4
|
-
// canvas-lib.tsx) is verified via a real render (agent-browser), not here —
|
|
5
|
-
// this file covers the deterministic offline path: JSX seed harvesting, the
|
|
6
|
-
// default-grid layout, and the meta.json position merge, which together must
|
|
7
|
-
// mirror DesignCanvasInner's `initialArtboards()` (canvas-lib.tsx) exactly so
|
|
8
|
-
// the static fallback never disagrees with what the browser would compute.
|
|
9
|
-
|
|
10
|
-
import { describe, expect, test } from 'bun:test';
|
|
11
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
12
|
-
import { tmpdir } from 'node:os';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
|
|
15
|
-
import { harvestSeeds, resolveArtboards, synthDefaultGrid } from '../bin/_canvas-rects-static.mjs';
|
|
16
|
-
|
|
17
|
-
describe('harvestSeeds', () => {
|
|
18
|
-
test('extracts id/width/height in document order', () => {
|
|
19
|
-
const source = `
|
|
20
|
-
<DCArtboard id="hero" label="Hero" width={1200} height={800}>x</DCArtboard>
|
|
21
|
-
<DCArtboard id="footer" label="Footer" width={1200} height={400}>y</DCArtboard>
|
|
22
|
-
`;
|
|
23
|
-
expect(harvestSeeds(source)).toEqual([
|
|
24
|
-
{ id: 'hero', w: 1200, h: 800 },
|
|
25
|
-
{ id: 'footer', w: 1200, h: 400 },
|
|
26
|
-
]);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('defaults width/height to VP_GRID (1280x820) when absent', () => {
|
|
30
|
-
const source = `<DCArtboard id="bare" label="Bare">x</DCArtboard>`;
|
|
31
|
-
expect(harvestSeeds(source)).toEqual([{ id: 'bare', w: 1280, h: 820 }]);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('mints __ab_N when id is missing', () => {
|
|
35
|
-
const source = `<DCArtboard label="No id" width={100} height={100}>x</DCArtboard>`;
|
|
36
|
-
expect(harvestSeeds(source)).toEqual([{ id: '__ab_0', w: 100, h: 100 }]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('is robust to attribute order', () => {
|
|
40
|
-
const source = `<DCArtboard height={500} width={900} id="reordered">x</DCArtboard>`;
|
|
41
|
-
expect(harvestSeeds(source)).toEqual([{ id: 'reordered', w: 900, h: 500 }]);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('empty source yields no seeds', () => {
|
|
45
|
-
expect(harvestSeeds('')).toEqual([]);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('synthDefaultGrid', () => {
|
|
50
|
-
test('mirrors canvas-lib.tsx VP_GRID (3 cols, 80px gutter, cell = max dims)', () => {
|
|
51
|
-
const seeds = [
|
|
52
|
-
{ id: 'a', w: 1200, h: 800 },
|
|
53
|
-
{ id: 'b', w: 1440, h: 900 }, // largest — sets the cell size
|
|
54
|
-
{ id: 'c', w: 1200, h: 800 },
|
|
55
|
-
{ id: 'd', w: 1200, h: 800 }, // wraps to row 1 (col 0)
|
|
56
|
-
];
|
|
57
|
-
const rects = synthDefaultGrid(seeds);
|
|
58
|
-
expect(rects).toEqual([
|
|
59
|
-
{ id: 'a', x: 0, y: 0, w: 1200, h: 800 },
|
|
60
|
-
{ id: 'b', x: 1440 + 80, y: 0, w: 1440, h: 900 },
|
|
61
|
-
{ id: 'c', x: (1440 + 80) * 2, y: 0, w: 1200, h: 800 },
|
|
62
|
-
{ id: 'd', x: 0, y: 900 + 80, w: 1200, h: 800 },
|
|
63
|
-
]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('empty seeds yields no rects', () => {
|
|
67
|
-
expect(synthDefaultGrid([])).toEqual([]);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('resolveArtboards', () => {
|
|
72
|
-
const source = `
|
|
73
|
-
<DCArtboard id="a" label="A" width={1200} height={800}>x</DCArtboard>
|
|
74
|
-
<DCArtboard id="b" label="B" width={1200} height={800}>y</DCArtboard>
|
|
75
|
-
`;
|
|
76
|
-
|
|
77
|
-
test('no meta layout — falls back to the default grid entirely', () => {
|
|
78
|
-
expect(resolveArtboards(source, [])).toEqual([
|
|
79
|
-
{ id: 'a', x: 0, y: 0, w: 1200, h: 800 },
|
|
80
|
-
{ id: 'b', x: 1280, w: 1200, h: 800, y: 0 },
|
|
81
|
-
]);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('meta layout overrides x/y but JSX width/height stays authoritative (DDR-027)', () => {
|
|
85
|
-
const layout = [{ id: 'a', x: 5000, y: 3000 }];
|
|
86
|
-
const out = resolveArtboards(source, layout);
|
|
87
|
-
expect(out[0]).toEqual({ id: 'a', x: 5000, y: 3000, w: 1200, h: 800 });
|
|
88
|
-
// 'b' has no matching layout entry — stays on the default grid.
|
|
89
|
-
expect(out[1]).toEqual({ id: 'b', x: 1280, y: 0, w: 1200, h: 800 });
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('a legacy meta w/h wins over the JSX default (back-compat tolerance)', () => {
|
|
93
|
-
const layout = [{ id: 'a', x: 10, y: 20, w: 999, h: 555 }];
|
|
94
|
-
expect(resolveArtboards(source, layout)[0]).toEqual({ id: 'a', x: 10, y: 20, w: 999, h: 555 });
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('non-finite / zero meta values fall back to the default', () => {
|
|
98
|
-
const layout = [{ id: 'a', x: Number.NaN, y: 20, w: 0, h: -5 }];
|
|
99
|
-
expect(resolveArtboards(source, layout)[0]).toEqual({ id: 'a', x: 0, y: 20, w: 1200, h: 800 });
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('canvas-rects.sh static fallback (fixture, no browser)', () => {
|
|
104
|
-
test('emits a manifest matching the canvas fixture, elements always empty', () => {
|
|
105
|
-
const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-fixture-'));
|
|
106
|
-
try {
|
|
107
|
-
mkdirSync(join(root, '.design', 'ui'), { recursive: true });
|
|
108
|
-
writeFileSync(
|
|
109
|
-
join(root, '.design', 'ui', 'Fixture.tsx'),
|
|
110
|
-
`export default function Fixture() {
|
|
111
|
-
return (
|
|
112
|
-
<DesignCanvas>
|
|
113
|
-
<DCArtboard id="one" label="One" width={1000} height={600} />
|
|
114
|
-
</DesignCanvas>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
`
|
|
118
|
-
);
|
|
119
|
-
writeFileSync(
|
|
120
|
-
join(root, '.design', 'ui', 'Fixture.meta.json'),
|
|
121
|
-
JSON.stringify({ layout: { artboards: [{ id: 'one', x: 42, y: 7 }] } })
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const proc = Bun.spawnSync([
|
|
125
|
-
'node',
|
|
126
|
-
new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
|
|
127
|
-
'--rel',
|
|
128
|
-
'ui/Fixture.tsx',
|
|
129
|
-
'--root',
|
|
130
|
-
root,
|
|
131
|
-
]);
|
|
132
|
-
const manifest = JSON.parse(proc.stdout.toString().trim());
|
|
133
|
-
expect(manifest).toEqual({
|
|
134
|
-
artboards: [{ id: 'one', x: 42, y: 7, w: 1000, h: 600 }],
|
|
135
|
-
elements: [],
|
|
136
|
-
elementsTruncated: false,
|
|
137
|
-
});
|
|
138
|
-
expect(proc.stderr.toString()).toMatch(/no live dev server/);
|
|
139
|
-
} finally {
|
|
140
|
-
rmSync(root, { recursive: true, force: true });
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test('a missing canvas file emits an empty manifest, not an error', () => {
|
|
145
|
-
const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-fixture-'));
|
|
146
|
-
try {
|
|
147
|
-
mkdirSync(join(root, '.design'), { recursive: true });
|
|
148
|
-
const proc = Bun.spawnSync([
|
|
149
|
-
'node',
|
|
150
|
-
new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
|
|
151
|
-
'--rel',
|
|
152
|
-
'ui/Nope.tsx',
|
|
153
|
-
'--root',
|
|
154
|
-
root,
|
|
155
|
-
]);
|
|
156
|
-
expect(JSON.parse(proc.stdout.toString().trim())).toEqual({
|
|
157
|
-
artboards: [],
|
|
158
|
-
elements: [],
|
|
159
|
-
elementsTruncated: false,
|
|
160
|
-
});
|
|
161
|
-
} finally {
|
|
162
|
-
rmSync(root, { recursive: true, force: true });
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// Security regression (feature-whiteboard-ai-toolkit review, F-path-traversal):
|
|
167
|
-
// --rel used to be joined straight into designRoot with no containment
|
|
168
|
-
// check — a `../` value could read anything readable by the process,
|
|
169
|
-
// unlike the sibling read-annotations.mjs/annotate.mjs lookups (which
|
|
170
|
-
// route the same rel-path shape through fileSlug() flattening). --rel here
|
|
171
|
-
// must stay a real nested path (it locates the actual .tsx on disk), so
|
|
172
|
-
// the fix is a resolve()+startsWith() containment assert instead.
|
|
173
|
-
test('--rel that resolves outside designRoot is rejected, not read', () => {
|
|
174
|
-
const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-traversal-'));
|
|
175
|
-
try {
|
|
176
|
-
mkdirSync(join(root, '.design', 'ui'), { recursive: true });
|
|
177
|
-
// A secret OUTSIDE .design that a traversal would try to reach.
|
|
178
|
-
writeFileSync(join(root, 'secret.tsx'), 'export default function Secret(){return null}');
|
|
179
|
-
|
|
180
|
-
const proc = Bun.spawnSync([
|
|
181
|
-
'node',
|
|
182
|
-
new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
|
|
183
|
-
'--rel',
|
|
184
|
-
'../secret.tsx',
|
|
185
|
-
'--root',
|
|
186
|
-
root,
|
|
187
|
-
]);
|
|
188
|
-
expect(JSON.parse(proc.stdout.toString().trim())).toEqual({
|
|
189
|
-
artboards: [],
|
|
190
|
-
elements: [],
|
|
191
|
-
elementsTruncated: false,
|
|
192
|
-
});
|
|
193
|
-
expect(proc.stderr.toString()).toMatch(/escapes designRoot/);
|
|
194
|
-
} finally {
|
|
195
|
-
rmSync(root, { recursive: true, force: true });
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
});
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
// canvas-edit.ts moveElement/applyMove — DDR-138, phase-12.1. Node-move reorder:
|
|
2
|
-
// relocate a whole JSXElement to a new sibling/parent position via oxc-parser +
|
|
3
|
-
// magic-string, re-indenting on reparent, with guardrails + a reparse gate. Tests
|
|
4
|
-
// verify order, formatting, the movedId recompute (must match the pipeline id the
|
|
5
|
-
// browser gets after reload), the data-dc-element re-settle key, and every refusal.
|
|
6
|
-
|
|
7
|
-
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
|
|
9
|
-
import { applyMove, CanvasEditError } from '../canvas-edit.ts';
|
|
10
|
-
import { transpileCanvasSource } from '../canvas-pipeline.ts';
|
|
11
|
-
|
|
12
|
-
const CANVAS = '/abs/Canvas.tsx';
|
|
13
|
-
|
|
14
|
-
/** The `id="…"` sequence in document order — reflects sibling/child order. */
|
|
15
|
-
function idOrder(source: string): string[] {
|
|
16
|
-
return [...source.matchAll(/\bid="([^"]+)"/g)].map((m) => m[1] as string);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Map author `id="X"` → the data-cd-id the pipeline injects (data-cd-id lands
|
|
20
|
-
* right after the tag name, before other attrs, so it precedes id="X"). */
|
|
21
|
-
function cdIds(source: string): Record<string, string> {
|
|
22
|
-
const { withIds } = transpileCanvasSource(CANVAS, source);
|
|
23
|
-
const out: Record<string, string> = {};
|
|
24
|
-
for (const m of withIds.matchAll(/data-cd-id="([0-9a-f]{8})"[^>]*?\bid="([^"]+)"/g)) {
|
|
25
|
-
out[m[2] as string] = m[1] as string;
|
|
26
|
-
}
|
|
27
|
-
return out;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const LIST = `function Demo() {
|
|
31
|
-
return (
|
|
32
|
-
<section>
|
|
33
|
-
<div id="a">A</div>
|
|
34
|
-
<div id="b">B</div>
|
|
35
|
-
<div id="c">C</div>
|
|
36
|
-
</section>
|
|
37
|
-
);
|
|
38
|
-
}`;
|
|
39
|
-
|
|
40
|
-
describe('canvas-edit / applyMove — sibling reorder', () => {
|
|
41
|
-
test('move first element after last (reorder down)', () => {
|
|
42
|
-
const ids = cdIds(LIST);
|
|
43
|
-
const res = applyMove(CANVAS, LIST, ids.a as string, ids.c as string, 'after');
|
|
44
|
-
expect(idOrder(res.source)).toEqual(['b', 'c', 'a']);
|
|
45
|
-
// moved element keeps the siblings' 6-space indent
|
|
46
|
-
expect(res.source).toContain('\n <div id="a">A</div>');
|
|
47
|
-
// untouched siblings are byte-identical
|
|
48
|
-
expect(res.source).toContain(' <div id="b">B</div>\n <div id="c">C</div>');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('move last element before first (reorder up)', () => {
|
|
52
|
-
const ids = cdIds(LIST);
|
|
53
|
-
const res = applyMove(CANVAS, LIST, ids.c as string, ids.a as string, 'before');
|
|
54
|
-
expect(idOrder(res.source)).toEqual(['c', 'a', 'b']);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('movedId matches the pipeline id the browser gets after reload', () => {
|
|
58
|
-
const ids = cdIds(LIST);
|
|
59
|
-
const res = applyMove(CANVAS, LIST, ids.a as string, ids.c as string, 'after');
|
|
60
|
-
// The recomputed movedId must equal what the pipeline assigns to <div id="a">
|
|
61
|
-
// in the NEW source — that's the whole re-settle contract.
|
|
62
|
-
expect(res.movedId).toBe(cdIds(res.source).a as string);
|
|
63
|
-
expect(res.movedId).not.toBeNull();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('output always re-parses (reparse gate never fires on a valid move)', () => {
|
|
67
|
-
const ids = cdIds(LIST);
|
|
68
|
-
const res = applyMove(CANVAS, LIST, ids.b as string, ids.a as string, 'before');
|
|
69
|
-
const parsed = transpileCanvasSource(CANVAS, res.source);
|
|
70
|
-
expect(parsed.withIds).toContain('<section');
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const NEST = `function Demo() {
|
|
75
|
-
return (
|
|
76
|
-
<section>
|
|
77
|
-
<div id="a">A</div>
|
|
78
|
-
<article id="box">
|
|
79
|
-
<p id="p">P</p>
|
|
80
|
-
</article>
|
|
81
|
-
</section>
|
|
82
|
-
);
|
|
83
|
-
}`;
|
|
84
|
-
|
|
85
|
-
describe('canvas-edit / applyMove — reparent', () => {
|
|
86
|
-
test('inside-end nests the element as the last child, re-indented', () => {
|
|
87
|
-
const ids = cdIds(NEST);
|
|
88
|
-
const res = applyMove(CANVAS, NEST, ids.a as string, ids.box as string, 'inside-end');
|
|
89
|
-
expect(idOrder(res.source)).toEqual(['box', 'p', 'a']);
|
|
90
|
-
// re-indented one level deeper than the article (8 spaces)
|
|
91
|
-
expect(res.source).toContain('\n <div id="a">A</div>');
|
|
92
|
-
// parses clean
|
|
93
|
-
expect(transpileCanvasSource(CANVAS, res.source).withIds).toContain('id="a"');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('inside-start nests the element as the first child', () => {
|
|
97
|
-
const ids = cdIds(NEST);
|
|
98
|
-
const res = applyMove(CANVAS, NEST, ids.a as string, ids.box as string, 'inside-start');
|
|
99
|
-
expect(idOrder(res.source)).toEqual(['box', 'a', 'p']);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('canvas-edit / applyMove — re-settle hints', () => {
|
|
104
|
-
test('semanticId surfaces the moved element data-dc-element verbatim', () => {
|
|
105
|
-
const src = `function Demo() {
|
|
106
|
-
return (
|
|
107
|
-
<section>
|
|
108
|
-
<div id="a" data-dc-element="hero">A</div>
|
|
109
|
-
<div id="b">B</div>
|
|
110
|
-
</section>
|
|
111
|
-
);
|
|
112
|
-
}`;
|
|
113
|
-
const ids = cdIds(src);
|
|
114
|
-
const res = applyMove(CANVAS, src, ids.a as string, ids.b as string, 'after');
|
|
115
|
-
expect(res.semanticId).toBe('hero');
|
|
116
|
-
expect(res.source).toContain('data-dc-element="hero"');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('canvas-edit / applyMove — guardrails', () => {
|
|
121
|
-
test('refuses moving an element relative to itself', () => {
|
|
122
|
-
const ids = cdIds(LIST);
|
|
123
|
-
expect(() => applyMove(CANVAS, LIST, ids.a as string, ids.a as string, 'after')).toThrow(
|
|
124
|
-
CanvasEditError
|
|
125
|
-
);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('refuses moving an element into its own subtree', () => {
|
|
129
|
-
const src = `function Demo() {
|
|
130
|
-
return (
|
|
131
|
-
<section id="sec">
|
|
132
|
-
<div id="a">A</div>
|
|
133
|
-
<div id="b">B</div>
|
|
134
|
-
</section>
|
|
135
|
-
);
|
|
136
|
-
}`;
|
|
137
|
-
const ids = cdIds(src);
|
|
138
|
-
// move <section id="sec"> (parent) inside <div id="a"> (its own descendant)
|
|
139
|
-
expect(() =>
|
|
140
|
-
applyMove(CANVAS, src, ids.sec as string, ids.a as string, 'inside-start')
|
|
141
|
-
).toThrow(/own subtree/);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test('refuses nesting into a self-closing target', () => {
|
|
145
|
-
const src = `function Demo() {
|
|
146
|
-
return (
|
|
147
|
-
<section>
|
|
148
|
-
<div id="a">A</div>
|
|
149
|
-
<img id="img" src="x.png" />
|
|
150
|
-
</section>
|
|
151
|
-
);
|
|
152
|
-
}`;
|
|
153
|
-
const ids = cdIds(src);
|
|
154
|
-
expect(() =>
|
|
155
|
-
applyMove(CANVAS, src, ids.a as string, ids.img as string, 'inside-start')
|
|
156
|
-
).toThrow(/self-closing/);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test('refuses an unknown moved id', () => {
|
|
160
|
-
expect(() => applyMove(CANVAS, LIST, 'deadbeef', cdIds(LIST).a as string, 'after')).toThrow(
|
|
161
|
-
/not found/
|
|
162
|
-
);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
test('refuses an unknown reference id', () => {
|
|
166
|
-
expect(() => applyMove(CANVAS, LIST, cdIds(LIST).a as string, 'deadbeef', 'after')).toThrow(
|
|
167
|
-
/not found/
|
|
168
|
-
);
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// Reused-component instance reorder (phase-12.1 follow-up). Three <Col> usages
|
|
173
|
-
// render three DOM nodes that share ONE data-cd-id (the id of the element inside
|
|
174
|
-
// Col's body). Passing the DOM occurrence index maps the move onto the parent's
|
|
175
|
-
// distinct <Col> USAGE elements, so the columns actually reorder.
|
|
176
|
-
const REUSE = `function Col({ t }) {
|
|
177
|
-
return <div id="col"><span id="lbl">{t}</span></div>;
|
|
178
|
-
}
|
|
179
|
-
function Demo() {
|
|
180
|
-
return (
|
|
181
|
-
<section>
|
|
182
|
-
<Col t="one" />
|
|
183
|
-
<Col t="two" />
|
|
184
|
-
<Col t="three" />
|
|
185
|
-
</section>
|
|
186
|
-
);
|
|
187
|
-
}`;
|
|
188
|
-
|
|
189
|
-
describe('canvas-edit / applyMove — reused-component instances', () => {
|
|
190
|
-
test('occurrence index maps a shared id to the parent <Col> usage', () => {
|
|
191
|
-
const ids = cdIds(REUSE);
|
|
192
|
-
const colId = ids.col as string; // the shared component-internal id (3 instances)
|
|
193
|
-
// Move instance 0 (t="one") AFTER instance 2 (t="three") → order two, three, one.
|
|
194
|
-
const res = applyMove(CANVAS, REUSE, colId, colId, 'after', 0, 2);
|
|
195
|
-
const titles = [...res.source.matchAll(/t="([^"]+)"/g)].map((m) => m[1]);
|
|
196
|
-
expect(titles).toEqual(['two', 'three', 'one']);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('same shared id + same occurrence index is still a self-move', () => {
|
|
200
|
-
const colId = cdIds(REUSE).col as string;
|
|
201
|
-
expect(() => applyMove(CANVAS, REUSE, colId, colId, 'after', 1, 1)).toThrow(/itself/);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test('resolves from a DEEP element inside the component too', () => {
|
|
205
|
-
const ids = cdIds(REUSE);
|
|
206
|
-
const lblId = ids.lbl as string; // <span> inside Col — also shared across instances
|
|
207
|
-
const res = applyMove(CANVAS, REUSE, lblId, lblId, 'before', 2, 0);
|
|
208
|
-
const titles = [...res.source.matchAll(/t="([^"]+)"/g)].map((m) => m[1]);
|
|
209
|
-
expect(titles).toEqual(['three', 'one', 'two']);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// Integration test for the /.design/ui/*.tsx canvas route.
|
|
2
|
-
//
|
|
3
|
-
// Boots a real Bun.serve dev-server against a sandbox that contains a single
|
|
4
|
-
// canvas TSX file, then verifies:
|
|
5
|
-
// - GET returns 200 + application/javascript + an ETag header
|
|
6
|
-
// - If-None-Match: <etag> returns 304 with no body
|
|
7
|
-
// - The cached body parses as JS via the same Bun.Transpiler the route uses
|
|
8
|
-
// - _locator.json is written for the canvas slug
|
|
9
|
-
// - Path-traversal attempts get rejected
|
|
10
|
-
// - Non-existent canvases return 404
|
|
11
|
-
|
|
12
|
-
import { describe, expect, test } from 'bun:test';
|
|
13
|
-
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
14
|
-
import { tmpdir } from 'node:os';
|
|
15
|
-
import { join } from 'node:path';
|
|
16
|
-
import type { Subprocess } from 'bun';
|
|
17
|
-
|
|
18
|
-
import { readLocator } from '../locator.ts';
|
|
19
|
-
import { bootServer, killProc, nextPort } from './_helpers.ts';
|
|
20
|
-
|
|
21
|
-
interface CanvasSandbox {
|
|
22
|
-
root: string;
|
|
23
|
-
designRoot: string;
|
|
24
|
-
cleanup: () => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function makeCanvasSandbox(canvasName: string, canvasSource: string): CanvasSandbox {
|
|
28
|
-
const root = mkdtempSync(join(tmpdir(), 'mdcc-canvas-route-'));
|
|
29
|
-
const designRoot = join(root, '.design');
|
|
30
|
-
mkdirSync(join(designRoot, 'ui'), { recursive: true });
|
|
31
|
-
writeFileSync(
|
|
32
|
-
join(designRoot, 'config.json'),
|
|
33
|
-
JSON.stringify({
|
|
34
|
-
name: 'test',
|
|
35
|
-
designRoot: '.design',
|
|
36
|
-
canvasGroups: [
|
|
37
|
-
{ label: 'UI', path: 'ui' },
|
|
38
|
-
{ label: 'System', path: 'system' },
|
|
39
|
-
],
|
|
40
|
-
})
|
|
41
|
-
);
|
|
42
|
-
writeFileSync(join(designRoot, 'ui', canvasName), canvasSource);
|
|
43
|
-
return { root, designRoot, cleanup: () => rmSync(root, { recursive: true, force: true }) };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const SIMPLE_TSX = `
|
|
47
|
-
export default function Hello() {
|
|
48
|
-
return (
|
|
49
|
-
<section>
|
|
50
|
-
<h1>Hello, world.</h1>
|
|
51
|
-
<p>Subhead.</p>
|
|
52
|
-
</section>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
`;
|
|
56
|
-
|
|
57
|
-
describe('TSX canvas route', () => {
|
|
58
|
-
let proc: Subprocess | null = null;
|
|
59
|
-
let port = 0;
|
|
60
|
-
let sb: CanvasSandbox | null = null;
|
|
61
|
-
|
|
62
|
-
async function boot(canvasName: string, source: string) {
|
|
63
|
-
sb = makeCanvasSandbox(canvasName, source);
|
|
64
|
-
port = nextPort();
|
|
65
|
-
proc = await bootServer(sb.root, port);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function teardown() {
|
|
69
|
-
if (proc) await killProc(proc);
|
|
70
|
-
if (sb) sb.cleanup();
|
|
71
|
-
proc = null;
|
|
72
|
-
sb = null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
test('returns 200 + JS + ETag for a valid canvas', async () => {
|
|
76
|
-
await boot('Hello.tsx', SIMPLE_TSX);
|
|
77
|
-
try {
|
|
78
|
-
const r = await fetch(`http://localhost:${port}/.design/ui/Hello.tsx`);
|
|
79
|
-
expect(r.status).toBe(200);
|
|
80
|
-
expect(r.headers.get('content-type')).toMatch(/javascript/);
|
|
81
|
-
const etag = r.headers.get('etag');
|
|
82
|
-
expect(etag).toBeTruthy();
|
|
83
|
-
// Phase 24 (DDR-067) — the canvas etag is `<source-hash>-<bootId>-<epoch>`:
|
|
84
|
-
// the boot id + chrome epoch are folded in so a chrome edit (which doesn't
|
|
85
|
-
// change the canvas source hash) still busts the browser's cached transpile.
|
|
86
|
-
expect(etag).toMatch(/^[0-9a-f]+-[a-z0-9]+-\d+$/i);
|
|
87
|
-
const body = await r.text();
|
|
88
|
-
// Body should contain data-cd-id metadata + an export — proves the two
|
|
89
|
-
// passes ran end to end.
|
|
90
|
-
expect(body).toMatch(/data-cd-id/);
|
|
91
|
-
// Bun.build emits `export { Hello as default }` (renamed-default form)
|
|
92
|
-
// rather than `export default Hello`. Both are valid ESM; match either.
|
|
93
|
-
expect(body).toMatch(/export\s+\{[\s\S]*\bdefault\b[\s\S]*\}|export\s+default\b/);
|
|
94
|
-
} finally {
|
|
95
|
-
await teardown();
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('returns 304 on a matching If-None-Match', async () => {
|
|
100
|
-
await boot('Hello.tsx', SIMPLE_TSX);
|
|
101
|
-
try {
|
|
102
|
-
const first = await fetch(`http://localhost:${port}/.design/ui/Hello.tsx`);
|
|
103
|
-
const etag = first.headers.get('etag') as string;
|
|
104
|
-
const second = await fetch(`http://localhost:${port}/.design/ui/Hello.tsx`, {
|
|
105
|
-
headers: { 'If-None-Match': etag },
|
|
106
|
-
});
|
|
107
|
-
expect(second.status).toBe(304);
|
|
108
|
-
// 304 body should be empty.
|
|
109
|
-
const body = await second.text();
|
|
110
|
-
expect(body.length).toBe(0);
|
|
111
|
-
} finally {
|
|
112
|
-
await teardown();
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('writes _locator.json with the canvas slug populated', async () => {
|
|
117
|
-
await boot('Docs Site.tsx', SIMPLE_TSX);
|
|
118
|
-
try {
|
|
119
|
-
await fetch(`http://localhost:${port}/.design/ui/Docs%20Site.tsx`);
|
|
120
|
-
const locFile = join(sb?.designRoot, '_locator.json');
|
|
121
|
-
// The locator is written synchronously before the response — the file
|
|
122
|
-
// must exist + carry the canvas slug.
|
|
123
|
-
expect(existsSync(locFile)).toBe(true);
|
|
124
|
-
const map = await readLocator(locFile, 'ui/Docs Site');
|
|
125
|
-
expect(map).not.toBeNull();
|
|
126
|
-
// SIMPLE_TSX has three JSX elements: section, h1, p.
|
|
127
|
-
expect(Object.keys(map as Record<string, unknown>).length).toBe(3);
|
|
128
|
-
} finally {
|
|
129
|
-
await teardown();
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('returns 404 for a missing canvas', async () => {
|
|
134
|
-
await boot('Hello.tsx', SIMPLE_TSX);
|
|
135
|
-
try {
|
|
136
|
-
const r = await fetch(`http://localhost:${port}/.design/ui/Missing.tsx`);
|
|
137
|
-
expect(r.status).toBe(404);
|
|
138
|
-
} finally {
|
|
139
|
-
await teardown();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test('rejects path traversal via .. (403 from safePathUnderRoot)', async () => {
|
|
144
|
-
await boot('Hello.tsx', SIMPLE_TSX);
|
|
145
|
-
try {
|
|
146
|
-
const r = await fetch(`http://localhost:${port}/.design/ui/../../etc/passwd.tsx`);
|
|
147
|
-
// safePathUnderRoot kicks the request out before our TSX dispatch runs.
|
|
148
|
-
expect([400, 403, 404]).toContain(r.status);
|
|
149
|
-
} finally {
|
|
150
|
-
await teardown();
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test('returns 500 on a malformed canvas with a useful error body', async () => {
|
|
155
|
-
await boot('Broken.tsx', 'export default function X() { return <div></span>; }');
|
|
156
|
-
try {
|
|
157
|
-
const r = await fetch(`http://localhost:${port}/.design/ui/Broken.tsx`);
|
|
158
|
-
expect(r.status).toBe(500);
|
|
159
|
-
const body = await r.text();
|
|
160
|
-
expect(body).toMatch(/Transpile error/i);
|
|
161
|
-
} finally {
|
|
162
|
-
await teardown();
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test('cache: second GET returns the same ETag without re-reading the file', async () => {
|
|
167
|
-
await boot('Hello.tsx', SIMPLE_TSX);
|
|
168
|
-
try {
|
|
169
|
-
const a = await fetch(`http://localhost:${port}/.design/ui/Hello.tsx`);
|
|
170
|
-
const b = await fetch(`http://localhost:${port}/.design/ui/Hello.tsx`);
|
|
171
|
-
expect(a.headers.get('etag')).toBe(b.headers.get('etag'));
|
|
172
|
-
const bodyA = await a.text();
|
|
173
|
-
const bodyB = await b.text();
|
|
174
|
-
expect(bodyA).toBe(bodyB);
|
|
175
|
-
} finally {
|
|
176
|
-
await teardown();
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
});
|