@1agh/maude 1.0.11 → 1.3.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.
Files changed (567) hide show
  1. package/README.md +3 -1
  2. package/apps/studio/acp/bridge.ts +18 -13
  3. package/apps/studio/acp/index.ts +43 -7
  4. package/apps/studio/acp/transcript-io.ts +394 -0
  5. package/apps/studio/acp/transcript.ts +103 -38
  6. package/apps/studio/annotations-layer.tsx +191 -116
  7. package/apps/studio/annotations-model.ts +39 -0
  8. package/apps/studio/annotations-sync.ts +50 -0
  9. package/apps/studio/api.ts +821 -55
  10. package/apps/studio/bin/_import-figma.mjs +57 -11
  11. package/apps/studio/bin/_seed-fixture.mjs +163 -0
  12. package/apps/studio/bin/annotate.mjs +3 -1
  13. package/apps/studio/bin/server-up.sh +17 -2
  14. package/apps/studio/canvas-edit.ts +391 -7
  15. package/apps/studio/canvas-imports.ts +89 -0
  16. package/apps/studio/canvas-lib.tsx +82 -18
  17. package/apps/studio/canvas-notice-message.ts +16 -0
  18. package/apps/studio/canvas-notifications.tsx +19 -0
  19. package/apps/studio/canvas-shell.tsx +57 -6
  20. package/apps/studio/client/app.jsx +943 -248
  21. package/apps/studio/client/apply-edit-request.ts +55 -0
  22. package/apps/studio/client/export-center.jsx +125 -67
  23. package/apps/studio/client/github.js +38 -1
  24. package/apps/studio/client/index-loader.ts +76 -0
  25. package/apps/studio/client/panels/CloudBar.jsx +52 -6
  26. package/apps/studio/client/panels/GitPanel.jsx +103 -0
  27. package/apps/studio/client/panels/OnboardingWizard.jsx +36 -7
  28. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +92 -27
  29. package/apps/studio/client/panels/SourceConflictPanel.jsx +166 -0
  30. package/apps/studio/client/panels/SyncPanel.jsx +238 -4
  31. package/apps/studio/client/panels/TeamProjects.jsx +376 -0
  32. package/apps/studio/client/panels/file-deep-link-dialog.jsx +54 -0
  33. package/apps/studio/client/photo-knobs.jsx +3 -0
  34. package/apps/studio/client/report-bug.jsx +19 -1
  35. package/apps/studio/client/share-dialog.jsx +91 -0
  36. package/apps/studio/client/share-link.js +94 -0
  37. package/apps/studio/client/styles/3-shell-maude.css +69 -18
  38. package/apps/studio/client/styles/4-components.css +44 -1
  39. package/apps/studio/client/tree-row-menu.jsx +48 -3
  40. package/apps/studio/client/whats-new.jsx +26 -32
  41. package/apps/studio/cloud/endpoints.ts +132 -0
  42. package/apps/studio/collab/index.ts +4 -0
  43. package/apps/studio/collab/persistence.ts +137 -17
  44. package/apps/studio/collab/registry.ts +19 -21
  45. package/apps/studio/collab/room.ts +13 -2
  46. package/apps/studio/context.ts +59 -0
  47. package/apps/studio/debug-bundle.ts +13 -0
  48. package/apps/studio/dist/client.bundle.js +1911 -1879
  49. package/apps/studio/dist/runtime/.min-sizes.json +1 -0
  50. package/apps/studio/dist/runtime/sonner.js +1 -0
  51. package/apps/studio/dist/styles.css +1 -1
  52. package/apps/studio/export-dialog.tsx +54 -0
  53. package/apps/studio/exporters/degraded.ts +19 -3
  54. package/apps/studio/exporters/ghostscript.ts +194 -0
  55. package/apps/studio/exporters/pdf-fonts.ts +261 -0
  56. package/apps/studio/exporters/pdf.ts +152 -3
  57. package/apps/studio/exporters/remote.ts +36 -1
  58. package/apps/studio/fs-watch.ts +45 -1
  59. package/apps/studio/http.ts +296 -19
  60. package/apps/studio/inspect.ts +19 -0
  61. package/apps/studio/managed-projects.ts +150 -0
  62. package/apps/studio/mem.ts +45 -9
  63. package/apps/studio/notifications.tsx +292 -0
  64. package/apps/studio/runtime-bundle.ts +2 -0
  65. package/apps/studio/server.ts +69 -6
  66. package/apps/studio/sync/accepted-cold-start.ts +225 -0
  67. package/apps/studio/sync/accepted-link.ts +320 -0
  68. package/apps/studio/sync/action-stage.ts +343 -0
  69. package/apps/studio/sync/agent.ts +104 -45
  70. package/apps/studio/sync/asset-push.ts +1 -47
  71. package/apps/studio/sync/cell-file-events.ts +3 -0
  72. package/apps/studio/sync/codec.ts +192 -34
  73. package/apps/studio/sync/cold-start-apply.ts +7 -0
  74. package/apps/studio/sync/cold-start.ts +118 -22
  75. package/apps/studio/sync/comment-identity.ts +68 -0
  76. package/apps/studio/sync/connection-state.ts +15 -1
  77. package/apps/studio/sync/ctl-provider.ts +15 -2
  78. package/apps/studio/sync/document-discovery.ts +81 -0
  79. package/apps/studio/sync/file-ledger.ts +117 -0
  80. package/apps/studio/sync/file-membership.ts +10 -2
  81. package/apps/studio/sync/file-plane.ts +926 -47
  82. package/apps/studio/sync/index.ts +1786 -36
  83. package/apps/studio/sync/journal-client.ts +13 -1
  84. package/apps/studio/sync/migrate-seed.ts +150 -22
  85. package/apps/studio/sync/poke.ts +4 -2
  86. package/apps/studio/sync/presentation.ts +311 -5
  87. package/apps/studio/sync/projection.ts +820 -23
  88. package/apps/studio/sync/repeated-module.ts +73 -0
  89. package/apps/studio/sync/retry-after.ts +169 -0
  90. package/apps/studio/sync/revision-barrier.ts +129 -0
  91. package/apps/studio/sync/seed-progress.ts +218 -0
  92. package/apps/studio/sync/seed-repair.ts +46 -0
  93. package/apps/studio/sync/source-merge.ts +100 -0
  94. package/apps/studio/sync/source-ops.ts +289 -0
  95. package/apps/studio/sync/source-recovery.ts +70 -0
  96. package/apps/studio/sync/source-validation.ts +56 -0
  97. package/apps/studio/sync/status.ts +201 -6
  98. package/apps/studio/sync/transaction-client.ts +460 -0
  99. package/apps/studio/sync/transport-error.ts +111 -0
  100. package/apps/studio/sync/writer-registry.ts +236 -0
  101. package/apps/studio/text-caret.ts +35 -0
  102. package/apps/studio/undo-hud.tsx +9 -87
  103. package/apps/studio/use-canvas-media-drop.tsx +4 -39
  104. package/apps/studio/whats-new.json +173 -0
  105. package/cli/bin/maude.mjs +2 -0
  106. package/cli/commands/codex.mjs +191 -0
  107. package/cli/commands/harness.mjs +1051 -0
  108. package/cli/commands/help.mjs +13 -0
  109. package/cli/lib/design-link.mjs +190 -2
  110. package/cli/lib/harness/capabilities.mjs +302 -0
  111. package/cli/lib/harness/codex-runtime.mjs +892 -0
  112. package/cli/lib/harness/compatibility.mjs +27 -0
  113. package/cli/lib/harness/discover-claude.mjs +1393 -0
  114. package/cli/lib/harness/managed-state.mjs +1296 -0
  115. package/cli/lib/harness/model.mjs +86 -0
  116. package/cli/lib/harness/secrets.mjs +390 -0
  117. package/cli/lib/harness/targets/codex.mjs +1141 -0
  118. package/cli/lib/harness/targets/opencode.mjs +807 -0
  119. package/cli/lib/harness/transaction.mjs +1099 -0
  120. package/cli/lib/hubs-config.mjs +35 -8
  121. package/cli/templates/harness/opencode/maude-projector.ts +58 -0
  122. package/docs/harness-capability-matrix.md +125 -0
  123. package/docs/harness-environment-projection.md +95 -0
  124. package/package.json +33 -9
  125. package/plugins/design/dependencies.json +3 -3
  126. package/plugins/design/templates/_shell.html +47 -0
  127. package/plugins/flow/.claude-plugin/config.schema.json +8 -0
  128. package/plugins/flow/dependencies.json +3 -3
  129. package/apps/studio/.ai/cache/_stats.json +0 -7
  130. package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
  131. package/apps/studio/bin/_curl-local.test.mjs +0 -280
  132. package/apps/studio/bin/_pw-launch.test.mjs +0 -90
  133. package/apps/studio/bin/_smart-frames.test.mjs +0 -195
  134. package/apps/studio/bin/_transcribe.test.mjs +0 -80
  135. package/apps/studio/bun.lock +0 -928
  136. package/apps/studio/draw/test/animate.test.ts +0 -172
  137. package/apps/studio/draw/test/brush.test.ts +0 -213
  138. package/apps/studio/draw/test/composition.test.ts +0 -141
  139. package/apps/studio/draw/test/geometry.test.ts +0 -199
  140. package/apps/studio/draw/test/gradient.test.ts +0 -167
  141. package/apps/studio/draw/test/layout.test.ts +0 -120
  142. package/apps/studio/draw/test/morph.test.ts +0 -107
  143. package/apps/studio/draw/test/optimize.test.ts +0 -40
  144. package/apps/studio/draw/test/palette.test.ts +0 -123
  145. package/apps/studio/draw/test/primitives.test.ts +0 -129
  146. package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
  147. package/apps/studio/draw/test/serialize.test.ts +0 -105
  148. package/apps/studio/figma/assets.test.ts +0 -464
  149. package/apps/studio/figma/client.test.ts +0 -395
  150. package/apps/studio/figma/codegen-client.test.ts +0 -276
  151. package/apps/studio/figma/codegen-fonts.test.ts +0 -103
  152. package/apps/studio/figma/codegen-values.test.ts +0 -179
  153. package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
  154. package/apps/studio/figma/fig-decode.test.ts +0 -788
  155. package/apps/studio/figma/fig-differential.test.ts +0 -182
  156. package/apps/studio/figma/fig-translator.test.ts +0 -192
  157. package/apps/studio/figma/fig-vector.test.ts +0 -113
  158. package/apps/studio/figma/from-codegen.test.ts +0 -408
  159. package/apps/studio/figma/sanitize.test.ts +0 -325
  160. package/apps/studio/figma/tailwind-map.test.ts +0 -142
  161. package/apps/studio/figma/to-artboard.test.ts +0 -808
  162. package/apps/studio/figma/to-render.test.ts +0 -180
  163. package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
  164. package/apps/studio/figma/to-strokes.test.ts +0 -705
  165. package/apps/studio/figma/to-tokens.test.ts +0 -321
  166. package/apps/studio/figma/url.test.ts +0 -167
  167. package/apps/studio/footage/schema.test.ts +0 -287
  168. package/apps/studio/generation/adapters/groq.test.ts +0 -80
  169. package/apps/studio/generation/audio-library.test.ts +0 -95
  170. package/apps/studio/generation/captions.test.ts +0 -78
  171. package/apps/studio/generation/elevenlabs.test.ts +0 -223
  172. package/apps/studio/generation/gemini.test.ts +0 -350
  173. package/apps/studio/generation/jobs.test.ts +0 -128
  174. package/apps/studio/generation/keys.test.ts +0 -75
  175. package/apps/studio/generation/prefs.test.ts +0 -95
  176. package/apps/studio/generation/types.test.ts +0 -123
  177. package/apps/studio/generation/whisper-models.test.ts +0 -179
  178. package/apps/studio/test/_helpers.ts +0 -108
  179. package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
  180. package/apps/studio/test/acp-activity.test.ts +0 -154
  181. package/apps/studio/test/acp-ai-activity.test.ts +0 -182
  182. package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
  183. package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
  184. package/apps/studio/test/acp-branch-guard.test.ts +0 -123
  185. package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
  186. package/apps/studio/test/acp-bridge.test.ts +0 -545
  187. package/apps/studio/test/acp-capabilities.test.ts +0 -123
  188. package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
  189. package/apps/studio/test/acp-commands.test.ts +0 -119
  190. package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
  191. package/apps/studio/test/acp-elicitation.test.ts +0 -251
  192. package/apps/studio/test/acp-env.test.ts +0 -95
  193. package/apps/studio/test/acp-mode-banner.test.ts +0 -45
  194. package/apps/studio/test/acp-origin-gate.test.ts +0 -160
  195. package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
  196. package/apps/studio/test/acp-permission.test.ts +0 -278
  197. package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
  198. package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
  199. package/apps/studio/test/acp-session-plugins.test.ts +0 -209
  200. package/apps/studio/test/acp-toolgroup.test.ts +0 -76
  201. package/apps/studio/test/acp-transcript-view.test.ts +0 -71
  202. package/apps/studio/test/acp-transcript.test.ts +0 -238
  203. package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
  204. package/apps/studio/test/acp-usage.test.ts +0 -143
  205. package/apps/studio/test/acp-write-gate.test.ts +0 -323
  206. package/apps/studio/test/acp-write-scope.test.ts +0 -533
  207. package/apps/studio/test/active-state.test.ts +0 -186
  208. package/apps/studio/test/activity.test.ts +0 -189
  209. package/apps/studio/test/ai-activity.test.ts +0 -113
  210. package/apps/studio/test/annotate-write.test.ts +0 -1074
  211. package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
  212. package/apps/studio/test/annotations-align.test.ts +0 -88
  213. package/apps/studio/test/annotations-api.test.ts +0 -145
  214. package/apps/studio/test/annotations-bindings.test.ts +0 -262
  215. package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
  216. package/apps/studio/test/annotations-groups.test.ts +0 -231
  217. package/apps/studio/test/annotations-layer.test.ts +0 -1011
  218. package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
  219. package/apps/studio/test/annotations-snap.test.ts +0 -135
  220. package/apps/studio/test/annotations-text-format.test.ts +0 -396
  221. package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
  222. package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
  223. package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
  224. package/apps/studio/test/artboard-kinds.test.tsx +0 -83
  225. package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
  226. package/apps/studio/test/asset-api.test.ts +0 -149
  227. package/apps/studio/test/assets-s3.test.ts +0 -249
  228. package/apps/studio/test/binary-smoke.test.ts +0 -47
  229. package/apps/studio/test/boot-self-heal.test.ts +0 -87
  230. package/apps/studio/test/browse-posture.test.tsx +0 -107
  231. package/apps/studio/test/bundle-smoke.test.ts +0 -46
  232. package/apps/studio/test/camera-reveal.test.tsx +0 -173
  233. package/apps/studio/test/canvas-artifacts.test.ts +0 -125
  234. package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
  235. package/apps/studio/test/canvas-build.test.ts +0 -141
  236. package/apps/studio/test/canvas-create-api.test.ts +0 -676
  237. package/apps/studio/test/canvas-cursors.test.ts +0 -164
  238. package/apps/studio/test/canvas-edit.test.ts +0 -470
  239. package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
  240. package/apps/studio/test/canvas-header.test.ts +0 -127
  241. package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
  242. package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
  243. package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
  244. package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
  245. package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
  246. package/apps/studio/test/canvas-list-watch.test.ts +0 -388
  247. package/apps/studio/test/canvas-media-drop.test.ts +0 -187
  248. package/apps/studio/test/canvas-meta-api.test.ts +0 -707
  249. package/apps/studio/test/canvas-move-api.test.ts +0 -587
  250. package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
  251. package/apps/studio/test/canvas-pipeline.test.ts +0 -180
  252. package/apps/studio/test/canvas-rects.test.ts +0 -198
  253. package/apps/studio/test/canvas-reorder.test.ts +0 -211
  254. package/apps/studio/test/canvas-route.test.ts +0 -179
  255. package/apps/studio/test/canvas-shell-base.test.ts +0 -107
  256. package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
  257. package/apps/studio/test/canvas-url.test.ts +0 -138
  258. package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
  259. package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
  260. package/apps/studio/test/capture-core.test.ts +0 -32
  261. package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
  262. package/apps/studio/test/chat-attachments.test.ts +0 -117
  263. package/apps/studio/test/chat-context.test.ts +0 -129
  264. package/apps/studio/test/chat-markdown.test.tsx +0 -58
  265. package/apps/studio/test/clip-addressing.test.ts +0 -738
  266. package/apps/studio/test/clip-ops.test.ts +0 -922
  267. package/apps/studio/test/cloud-build.test.ts +0 -95
  268. package/apps/studio/test/cloud-connect-note.test.ts +0 -135
  269. package/apps/studio/test/cloud-endpoints.test.ts +0 -590
  270. package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
  271. package/apps/studio/test/cloud-history-posture.test.ts +0 -230
  272. package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
  273. package/apps/studio/test/cloud-renew.test.ts +0 -205
  274. package/apps/studio/test/cloud-session-role.test.ts +0 -161
  275. package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
  276. package/apps/studio/test/cold-start-apply.test.ts +0 -303
  277. package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
  278. package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
  279. package/apps/studio/test/collab-bridge.test.ts +0 -79
  280. package/apps/studio/test/collab-loopback.test.ts +0 -63
  281. package/apps/studio/test/collab-origin-gate.test.ts +0 -323
  282. package/apps/studio/test/collab-protocol.test.ts +0 -146
  283. package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
  284. package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
  285. package/apps/studio/test/collab-room.test.ts +0 -188
  286. package/apps/studio/test/collab-session-survival.test.tsx +0 -176
  287. package/apps/studio/test/collab-stress.test.ts +0 -129
  288. package/apps/studio/test/comment-mount.test.ts +0 -97
  289. package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
  290. package/apps/studio/test/comments-api.test.ts +0 -277
  291. package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
  292. package/apps/studio/test/comments-overlay.test.ts +0 -117
  293. package/apps/studio/test/compile-entry.test.ts +0 -133
  294. package/apps/studio/test/component-map.test.ts +0 -48
  295. package/apps/studio/test/config-projection.test.ts +0 -104
  296. package/apps/studio/test/config-reload.test.ts +0 -230
  297. package/apps/studio/test/config-version.test.ts +0 -88
  298. package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
  299. package/apps/studio/test/convert-to-absolute.test.ts +0 -333
  300. package/apps/studio/test/credential-grammar.test.ts +0 -107
  301. package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
  302. package/apps/studio/test/csrf-write-guard.test.ts +0 -141
  303. package/apps/studio/test/debug-bundle.test.ts +0 -105
  304. package/apps/studio/test/design-setup-readiness.test.ts +0 -155
  305. package/apps/studio/test/detach-component.test.ts +0 -94
  306. package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
  307. package/apps/studio/test/dom-selection.test.ts +0 -198
  308. package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
  309. package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
  310. package/apps/studio/test/edit-persistence.test.ts +0 -91
  311. package/apps/studio/test/edit-scope-api.test.ts +0 -119
  312. package/apps/studio/test/edit-source-command.test.ts +0 -142
  313. package/apps/studio/test/edit-suppress.test.ts +0 -170
  314. package/apps/studio/test/editing-presence.test.ts +0 -103
  315. package/apps/studio/test/element-resize.test.ts +0 -136
  316. package/apps/studio/test/element-structural-api.test.ts +0 -434
  317. package/apps/studio/test/element-structural-edit.test.ts +0 -750
  318. package/apps/studio/test/ensure-browser.test.ts +0 -92
  319. package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
  320. package/apps/studio/test/export-assemble.test.ts +0 -53
  321. package/apps/studio/test/export-browser-lane.test.ts +0 -126
  322. package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
  323. package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
  324. package/apps/studio/test/export-center.test.tsx +0 -287
  325. package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
  326. package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
  327. package/apps/studio/test/export-lane.test.ts +0 -245
  328. package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
  329. package/apps/studio/test/exporters/canva.test.ts +0 -63
  330. package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
  331. package/apps/studio/test/exporters/endpoint.test.ts +0 -121
  332. package/apps/studio/test/exporters/history.test.ts +0 -107
  333. package/apps/studio/test/exporters/html.test.ts +0 -26
  334. package/apps/studio/test/exporters/jobs.test.ts +0 -342
  335. package/apps/studio/test/exporters/pdf.test.ts +0 -85
  336. package/apps/studio/test/exporters/png.test.ts +0 -103
  337. package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
  338. package/apps/studio/test/exporters/pptx.test.ts +0 -31
  339. package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
  340. package/apps/studio/test/exporters/runtime.test.ts +0 -59
  341. package/apps/studio/test/exporters/scope.test.ts +0 -292
  342. package/apps/studio/test/exporters/svg.test.ts +0 -29
  343. package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
  344. package/apps/studio/test/exporters/zip.test.ts +0 -104
  345. package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
  346. package/apps/studio/test/figjam-v3-model.test.ts +0 -342
  347. package/apps/studio/test/figma-explode.test.ts +0 -438
  348. package/apps/studio/test/figma-provenance.test.ts +0 -108
  349. package/apps/studio/test/figma-routes.test.ts +0 -294
  350. package/apps/studio/test/file-lock.test.ts +0 -84
  351. package/apps/studio/test/fixtures/backgrounding-claude-auth.sh +0 -12
  352. package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -23
  353. package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
  354. package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
  355. package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
  356. package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
  357. package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
  358. package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
  359. package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
  360. package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
  361. package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
  362. package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
  363. package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
  364. package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
  365. package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
  366. package/apps/studio/test/fixtures/noisy-claude-auth.mjs +0 -27
  367. package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
  368. package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
  369. package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
  370. package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
  371. package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
  372. package/apps/studio/test/fixtures/wedged-claude-auth.sh +0 -11
  373. package/apps/studio/test/footage-store.test.ts +0 -100
  374. package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
  375. package/apps/studio/test/fs-watch.test.ts +0 -41
  376. package/apps/studio/test/gemma-models.test.ts +0 -245
  377. package/apps/studio/test/generate-route.test.ts +0 -106
  378. package/apps/studio/test/git-api.test.ts +0 -0
  379. package/apps/studio/test/git-branches.test.ts +0 -341
  380. package/apps/studio/test/git-cloud-posture.test.ts +0 -59
  381. package/apps/studio/test/git-grouping.test.ts +0 -106
  382. package/apps/studio/test/git-lifecycle.test.ts +0 -100
  383. package/apps/studio/test/git-log-format.test.ts +0 -95
  384. package/apps/studio/test/git-safe-rel.test.ts +0 -132
  385. package/apps/studio/test/git-system-engine.test.ts +0 -135
  386. package/apps/studio/test/git-watch.test.ts +0 -97
  387. package/apps/studio/test/github-api.test.ts +0 -577
  388. package/apps/studio/test/grid-track-handles.test.ts +0 -160
  389. package/apps/studio/test/handoff-static-frames.test.ts +0 -215
  390. package/apps/studio/test/handoff.test.ts +0 -329
  391. package/apps/studio/test/history-rollback.test.ts +0 -88
  392. package/apps/studio/test/hmr-broadcast.test.ts +0 -236
  393. package/apps/studio/test/hmr-classify.test.ts +0 -87
  394. package/apps/studio/test/hub-link.test.ts +0 -80
  395. package/apps/studio/test/identity-cache.test.ts +0 -83
  396. package/apps/studio/test/import-asset-browser.test.ts +0 -64
  397. package/apps/studio/test/import-asset-route.test.ts +0 -71
  398. package/apps/studio/test/import-asset.test.ts +0 -427
  399. package/apps/studio/test/import-brand-browser.test.ts +0 -88
  400. package/apps/studio/test/import-brand-route.test.ts +0 -120
  401. package/apps/studio/test/import-brand.test.ts +0 -206
  402. package/apps/studio/test/import-figma.test.ts +0 -667
  403. package/apps/studio/test/import-tokens.test.ts +0 -722
  404. package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
  405. package/apps/studio/test/input-router.test.ts +0 -757
  406. package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
  407. package/apps/studio/test/inspect-selections.test.ts +0 -219
  408. package/apps/studio/test/knob-props-authored.test.ts +0 -87
  409. package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
  410. package/apps/studio/test/locator.test.ts +0 -214
  411. package/apps/studio/test/marquee-overlay.test.ts +0 -94
  412. package/apps/studio/test/media-commit-chain.test.ts +0 -210
  413. package/apps/studio/test/mode-toggle.test.tsx +0 -226
  414. package/apps/studio/test/motion-sample.test.ts +0 -35
  415. package/apps/studio/test/move-artboards-command.test.ts +0 -108
  416. package/apps/studio/test/participants-chrome.test.ts +0 -65
  417. package/apps/studio/test/paths.test.ts +0 -88
  418. package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
  419. package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
  420. package/apps/studio/test/perf-harness.ts +0 -193
  421. package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
  422. package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
  423. package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
  424. package/apps/studio/test/photo-edit-api.test.ts +0 -201
  425. package/apps/studio/test/photo-filters.test.ts +0 -149
  426. package/apps/studio/test/photo-pipeline.test.ts +0 -106
  427. package/apps/studio/test/photo-taxonomy.test.ts +0 -96
  428. package/apps/studio/test/print-marks.test.ts +0 -113
  429. package/apps/studio/test/print-units.test.ts +0 -173
  430. package/apps/studio/test/read-annotations.test.ts +0 -727
  431. package/apps/studio/test/read-only-gate.test.ts +0 -188
  432. package/apps/studio/test/read-only-role.test.ts +0 -95
  433. package/apps/studio/test/readiness.test.ts +0 -337
  434. package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
  435. package/apps/studio/test/reorder-api.test.ts +0 -210
  436. package/apps/studio/test/repo-concurrency.test.ts +0 -146
  437. package/apps/studio/test/repo-lock.test.ts +0 -350
  438. package/apps/studio/test/report-proxy.test.ts +0 -125
  439. package/apps/studio/test/ripple.test.ts +0 -197
  440. package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
  441. package/apps/studio/test/runtime-bundle.test.ts +0 -69
  442. package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
  443. package/apps/studio/test/scaffold-design.test.ts +0 -122
  444. package/apps/studio/test/server-lifecycle.test.ts +0 -38
  445. package/apps/studio/test/session-runtime-state.test.ts +0 -226
  446. package/apps/studio/test/session-scope.test.ts +0 -100
  447. package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
  448. package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
  449. package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
  450. package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
  451. package/apps/studio/test/shared-doc-projection.test.ts +0 -238
  452. package/apps/studio/test/shell-importmap.test.ts +0 -56
  453. package/apps/studio/test/sizing-mode.test.ts +0 -102
  454. package/apps/studio/test/slash-commands.test.ts +0 -117
  455. package/apps/studio/test/snap-distance-pill.test.ts +0 -68
  456. package/apps/studio/test/spacing-handles.test.ts +0 -138
  457. package/apps/studio/test/specimen-select.test.ts +0 -88
  458. package/apps/studio/test/sync-agent.test.ts +0 -660
  459. package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
  460. package/apps/studio/test/sync-asset-push.test.ts +0 -931
  461. package/apps/studio/test/sync-atomic-write.test.ts +0 -62
  462. package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
  463. package/apps/studio/test/sync-autocommit.test.ts +0 -537
  464. package/apps/studio/test/sync-canvas-path.test.ts +0 -200
  465. package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
  466. package/apps/studio/test/sync-codec.test.ts +0 -230
  467. package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
  468. package/apps/studio/test/sync-cold-start.test.ts +0 -304
  469. package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
  470. package/apps/studio/test/sync-connection-state.test.ts +0 -337
  471. package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
  472. package/apps/studio/test/sync-decide-file.test.ts +0 -420
  473. package/apps/studio/test/sync-doc-name.test.ts +0 -281
  474. package/apps/studio/test/sync-echo-guard.test.ts +0 -96
  475. package/apps/studio/test/sync-file-ledger.test.ts +0 -334
  476. package/apps/studio/test/sync-file-membership.test.ts +0 -347
  477. package/apps/studio/test/sync-file-plane.test.ts +0 -976
  478. package/apps/studio/test/sync-file-pull.test.ts +0 -333
  479. package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
  480. package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
  481. package/apps/studio/test/sync-hardening.test.ts +0 -586
  482. package/apps/studio/test/sync-hub-listing.test.ts +0 -46
  483. package/apps/studio/test/sync-hubs-config.test.ts +0 -133
  484. package/apps/studio/test/sync-incident-replay.test.ts +0 -211
  485. package/apps/studio/test/sync-journal.test.ts +0 -176
  486. package/apps/studio/test/sync-meta-codec.test.ts +0 -199
  487. package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
  488. package/apps/studio/test/sync-move-retirement.test.ts +0 -231
  489. package/apps/studio/test/sync-panel-surface.test.ts +0 -153
  490. package/apps/studio/test/sync-path-pull.test.ts +0 -531
  491. package/apps/studio/test/sync-presentation.test.ts +0 -262
  492. package/apps/studio/test/sync-pull-budget.test.ts +0 -169
  493. package/apps/studio/test/sync-remote-docs.test.ts +0 -333
  494. package/apps/studio/test/sync-resync-routes.test.ts +0 -168
  495. package/apps/studio/test/sync-runtime.test.ts +0 -1675
  496. package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
  497. package/apps/studio/test/sync-settings-routes.test.ts +0 -195
  498. package/apps/studio/test/sync-settings.test.ts +0 -151
  499. package/apps/studio/test/sync-status.test.ts +0 -261
  500. package/apps/studio/test/sync-supervisor.test.ts +0 -262
  501. package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
  502. package/apps/studio/test/sync-trash.test.ts +0 -132
  503. package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
  504. package/apps/studio/test/sync-untrusted.test.ts +0 -103
  505. package/apps/studio/test/system-endpoint.test.ts +0 -144
  506. package/apps/studio/test/text-editability-stamp.test.ts +0 -131
  507. package/apps/studio/test/timeline-comp-target.test.ts +0 -139
  508. package/apps/studio/test/timeline-media-cache.test.ts +0 -41
  509. package/apps/studio/test/timeline-parse.test.ts +0 -184
  510. package/apps/studio/test/timeline-scale.test.ts +0 -65
  511. package/apps/studio/test/timeline-snap.test.ts +0 -85
  512. package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
  513. package/apps/studio/test/tool-palette.test.tsx +0 -55
  514. package/apps/studio/test/tour-overlay.test.tsx +0 -90
  515. package/apps/studio/test/trusted-request-host.test.ts +0 -66
  516. package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
  517. package/apps/studio/test/undo-stack.test.ts +0 -244
  518. package/apps/studio/test/use-agent-presence.test.tsx +0 -117
  519. package/apps/studio/test/use-annotation-resize.test.ts +0 -402
  520. package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
  521. package/apps/studio/test/use-artboard-drag.test.ts +0 -324
  522. package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
  523. package/apps/studio/test/use-collab.test.ts +0 -0
  524. package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
  525. package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
  526. package/apps/studio/test/use-selection-set.test.tsx +0 -166
  527. package/apps/studio/test/use-snap-guides.test.ts +0 -271
  528. package/apps/studio/test/use-tool-mode.test.tsx +0 -186
  529. package/apps/studio/test/use-undo-stack.test.tsx +0 -223
  530. package/apps/studio/test/video-asset.test.ts +0 -163
  531. package/apps/studio/test/video-comp-fixture.test.ts +0 -50
  532. package/apps/studio/test/video-comp.test.ts +0 -270
  533. package/apps/studio/test/video-encode-lib.test.ts +0 -63
  534. package/apps/studio/test/video-render-bridge.test.ts +0 -171
  535. package/apps/studio/test/whats-new.test.ts +0 -113
  536. package/apps/studio/test/whisper-setup.test.ts +0 -97
  537. package/apps/studio/test/workspace-containment.test.ts +0 -382
  538. package/apps/studio/test/workspace-signin.test.ts +0 -292
  539. package/apps/studio/test/ws-handshake.test.ts +0 -33
  540. package/cli/commands/cache.test.mjs +0 -166
  541. package/cli/commands/design-link.test.mjs +0 -419
  542. package/cli/commands/design.test.mjs +0 -240
  543. package/cli/commands/doctor.test.mjs +0 -237
  544. package/cli/commands/hub-workspace.test.mjs +0 -275
  545. package/cli/commands/hub.test.mjs +0 -225
  546. package/cli/commands/kg.test.mjs +0 -142
  547. package/cli/commands/preflight.test.mjs +0 -46
  548. package/cli/lib/argv.test.mjs +0 -46
  549. package/cli/lib/cache.test.mjs +0 -303
  550. package/cli/lib/cell-plan.test.mjs +0 -225
  551. package/cli/lib/config-lint.test.mjs +0 -117
  552. package/cli/lib/ddr-to-kgai.test.mjs +0 -118
  553. package/cli/lib/design-ownership.test.mjs +0 -329
  554. package/cli/lib/fetch-asset.test.mjs +0 -213
  555. package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
  556. package/cli/lib/figma-import-controls.test.mjs +0 -70
  557. package/cli/lib/flow-design-integration.test.mjs +0 -165
  558. package/cli/lib/gitignore-block.test.mjs +0 -136
  559. package/cli/lib/gitignore-drift.test.mjs +0 -156
  560. package/cli/lib/hubs-config.test.mjs +0 -165
  561. package/cli/lib/pkg-root.test.mjs +0 -111
  562. package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
  563. package/cli/lib/plugin-name-namespace.test.mjs +0 -71
  564. package/cli/lib/reconstruct-toolset.test.mjs +0 -194
  565. package/cli/lib/stack-detect.test.mjs +0 -121
  566. package/cli/lib/update-check.test.mjs +0 -32
  567. package/cli/lib/workspace-plan.test.mjs +0 -699
@@ -1,162 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { applyTextEdit } from '../canvas-edit.ts';
3
- import { transpileCanvasSource } from '../canvas-pipeline.ts';
4
-
5
- // unified-text-editing follow-up — editing text that comes from a `{variable}`
6
- // or `{item.prop}` by tracing it back to its source string (a local const or a
7
- // `.map()`ed array element). The safety contract: never rewrite the wrong item
8
- // — occurrence picks the `.map()` slot, `before` verifies/rescues it, and an
9
- // unresolvable expression still throws (routes to /design:edit).
10
-
11
- const CANVAS = '/virtual/Cards.tsx';
12
- const SRC = `const TOPICS = [
13
- { key: "a", body: "Alpha body text." },
14
- { key: "b", body: "Beta body text." },
15
- { key: "c", body: "Gamma body text." },
16
- ];
17
- const TAGS = ["first", "second", "third"];
18
- const HEADLINE = "The one headline";
19
- export default function Cards() {
20
- return (
21
- <div>
22
- <h1>{HEADLINE}</h1>
23
- <section>
24
- {TOPICS.map((t) => (
25
- <article key={t.key}>
26
- <p>{t.body}</p>
27
- </article>
28
- ))}
29
- </section>
30
- <ul>
31
- {TAGS.map((tag) => (
32
- <li key={tag}>{tag}</li>
33
- ))}
34
- </ul>
35
- <p>Total: {TOPICS.length} topics</p>
36
- <span>{price.toFixed(2)}</span>
37
- </div>
38
- );
39
- }
40
- const price = 9;
41
- `;
42
-
43
- function ids(withIds: string, tag: string, inner: string): string {
44
- // Grab the data-cd-id of the <tag …>inner… element.
45
- const re = new RegExp(`<${tag}\\s+data-cd-id="([^"]+)"[^>]*>\\s*\\{?${inner}`);
46
- const m = withIds.match(re);
47
- if (!m) throw new Error(`no ${tag} matching ${inner}`);
48
- return m[1] as string;
49
- }
50
-
51
- describe('dynamic text edit — resolveDynamicTextSpan via applyTextEdit', () => {
52
- const { withIds } = transpileCanvasSource(CANVAS, SRC);
53
-
54
- test('{item.prop} in a .map — occurrence picks the array item', () => {
55
- const pId = ids(withIds, 'p', 't\\.body');
56
- // occurrence 1 → TOPICS[1].body, verified by `before`.
57
- const { source } = applyTextEdit(CANVAS, withIds, pId, 'Beta EDITED', {
58
- occurrence: 1,
59
- before: 'Beta body text.',
60
- });
61
- expect(source).toContain('body: "Beta EDITED"');
62
- expect(source).toContain('body: "Alpha body text."'); // sibling untouched
63
- expect(source).toContain('body: "Gamma body text."');
64
- });
65
-
66
- test('{item.prop} — index drift rescued by unique before-match', () => {
67
- const pId = ids(withIds, 'p', 't\\.body');
68
- // Wrong occurrence, but `before` uniquely identifies Gamma → rewrite it.
69
- const { source } = applyTextEdit(CANVAS, withIds, pId, 'Gamma EDITED', {
70
- occurrence: 0,
71
- before: 'Gamma body text.',
72
- });
73
- expect(source).toContain('body: "Gamma EDITED"');
74
- expect(source).toContain('body: "Alpha body text."');
75
- });
76
-
77
- test('{item} in a .map over a string array', () => {
78
- const liId = ids(withIds, 'li', 'tag');
79
- const { source } = applyTextEdit(CANVAS, withIds, liId, 'SECOND', {
80
- occurrence: 1,
81
- before: 'second',
82
- });
83
- expect(source).toContain('"first", "SECOND", "third"');
84
- });
85
-
86
- test('{localConst} — rewrites the const string', () => {
87
- const h1Id = ids(withIds, 'h1', 'HEADLINE');
88
- const { source } = applyTextEdit(CANVAS, withIds, h1Id, 'A new headline', {
89
- before: 'The one headline',
90
- });
91
- expect(source).toContain('HEADLINE = "A new headline"');
92
- });
93
-
94
- test('{prop.field} — component fed BEATS[k] resolves to BEATS[k].field', () => {
95
- // A reusable component whose `beat` prop is fed `BEATS[0..2]` at each usage
96
- // (the Remotion-style pattern). Editing the 2nd usage's caption must hit
97
- // BEATS[1].caption via occurrence, not card 0 or 2.
98
- const SRC2 = `const BEATS = [
99
- { n: "01", caption: "Beat one caption." },
100
- { n: "02", caption: "Beat two caption." },
101
- { n: "03", caption: "Beat three caption." },
102
- ];
103
- function GuideBeat({ beat }: { beat: (typeof BEATS)[number] }) {
104
- return <p>{beat.caption}</p>;
105
- }
106
- export default function Reel() {
107
- return (
108
- <div>
109
- <GuideBeat beat={BEATS[0]} />
110
- <GuideBeat beat={BEATS[1]} />
111
- <GuideBeat beat={BEATS[2]} />
112
- </div>
113
- );
114
- }`;
115
- const built = transpileCanvasSource(CANVAS, SRC2).withIds;
116
- const pId = /<p\s+data-cd-id="([^"]+)"[^>]*>\s*\{beat\.caption\}/.exec(built)?.[1] as string;
117
- const { source } = applyTextEdit(CANVAS, built, pId, 'Beat two EDITED', {
118
- occurrence: 1,
119
- before: 'Beat two caption.',
120
- });
121
- expect(source).toContain('caption: "Beat two EDITED"');
122
- expect(source).toContain('caption: "Beat one caption."');
123
- expect(source).toContain('caption: "Beat three caption."');
124
- });
125
-
126
- test('genuinely computed text still refuses (routes to /design:edit)', () => {
127
- const spanId = ids(withIds, 'span', 'price\\.toFixed');
128
- expect(() =>
129
- applyTextEdit(CANVAS, withIds, spanId, 'nope', { occurrence: 0, before: '9.00' })
130
- ).toThrow(/dynamic content/);
131
- });
132
-
133
- test('mixed literal+expression (Total: {n} topics) refuses', () => {
134
- // This <p> has text + expression + text → mixed, never offered.
135
- const m = withIds.match(/<p[^>]*data-cd-id="([^"]+)"[^>]*>Total:/);
136
- expect(m).toBeTruthy();
137
- expect(() => applyTextEdit(CANVAS, withIds, (m as RegExpMatchArray)[1] as string, 'x')).toThrow(
138
- /mixed or expression/
139
- );
140
- });
141
-
142
- test('no occurrence + no before on an ambiguous .map refuses (never guesses)', () => {
143
- const pId = ids(withIds, 'p', 't\\.body');
144
- // Without occurrence or before there is no way to know which card → refuse.
145
- expect(() => applyTextEdit(CANVAS, withIds, pId, 'x')).toThrow(/dynamic content/);
146
- });
147
- });
148
-
149
- describe('stamp marks var-editable text', () => {
150
- const { withIds } = transpileCanvasSource(CANVAS, SRC);
151
- test('{item.prop}, {item}, {const} get data-cd-editable="var"', () => {
152
- expect(withIds).toMatch(/<p[^>]*data-cd-editable="var"[^>]*>\s*\{t\.body\}/);
153
- expect(withIds).toMatch(/<li[^>]*data-cd-editable="var"[^>]*>\s*\{tag\}/);
154
- expect(withIds).toMatch(/<h1[^>]*data-cd-editable="var"[^>]*>\s*\{HEADLINE\}/);
155
- });
156
- test('computed + mixed text are NOT marked', () => {
157
- const span = withIds.match(/<span[^>]*>\{price\.toFixed/);
158
- expect((span as RegExpMatchArray)[0].includes('data-cd-editable')).toBe(false);
159
- const p = withIds.match(/<p[^>]*>Total:/);
160
- expect((p as RegExpMatchArray)[0].includes('data-cd-editable')).toBe(false);
161
- });
162
- });
@@ -1,81 +0,0 @@
1
- // canvas-edit.ts — Stage H3 (feature-element-editing-robustness). A whole-
2
- // component-instance move/resize passes a DOM-occurrence index into edit-css so
3
- // `applyEdit` routes the write to that instance's `<Component/>` USAGE (local to
4
- // the dragged instance) instead of the shared inner definition (global). The knob
5
- // / paste-style paths pass NO occurrence, so inner-shared-element styling stays
6
- // global-and-labeled — the H2 badge is the answer there (the chosen model).
7
- // Positional ids are round-tripped through transpileCanvasSource like the sibling
8
- // structural test, so the arithmetic stays in lockstep with the pipeline.
9
-
10
- import { describe, expect, test } from 'bun:test';
11
-
12
- import { applyEdit } from '../canvas-edit.ts';
13
- import { transpileCanvasSource } from '../canvas-pipeline.ts';
14
-
15
- const CANVAS = '/abs/Canvas.tsx';
16
-
17
- /** Map data-cd-id by element-type name (first occurrence), like canvas-edit.test.ts. */
18
- function idsOf(source: string): Record<string, string> {
19
- const { withIds } = transpileCanvasSource(CANVAS, source);
20
- const out: Record<string, string> = {};
21
- for (const m of withIds.matchAll(/<(\w+)([^>]*?)data-cd-id="([0-9a-f]{8})"/g)) {
22
- if (!out[m[1] as string]) out[m[1] as string] = m[3] as string;
23
- }
24
- return out;
25
- }
26
-
27
- const SHARED = [
28
- 'function Card() { return <article>card</article>; }',
29
- 'function Demo() {',
30
- ' return (',
31
- ' <section>',
32
- ' <Card />',
33
- ' <Card />',
34
- ' <Card />',
35
- ' </section>',
36
- ' );',
37
- '}',
38
- ].join('\n');
39
-
40
- describe('canvas-edit / applyEdit — Stage H3 occurrence routing', () => {
41
- test('with an occurrence, a style edit routes to that <Component/> usage (local)', () => {
42
- // The inner <article> id is shared across all three <Card/> usages.
43
- const innerId = idsOf(SHARED).article as string;
44
- const out = applyEdit(CANVAS, SHARED, innerId, 'style.left', '"40px"', 1); // 2nd instance
45
- // The 2nd (index 1) <Card/> usage gains the inline style; the shared inner
46
- // <article> definition is untouched, so the other two instances don't move.
47
- expect(out.source).toContain('<Card style={{ left: "40px" }}');
48
- expect(out.source.match(/<Card \/>/g)?.length).toBe(2);
49
- expect(out.source).toContain('<article>card</article>');
50
- });
51
-
52
- test('without an occurrence, the same edit stays on the shared inner element (global)', () => {
53
- const innerId = idsOf(SHARED).article as string;
54
- const out = applyEdit(CANVAS, SHARED, innerId, 'style.left', '"40px"');
55
- // No occurrence → knob / paste-style behavior: the write lands on the inner
56
- // <article>, changing every rendered instance (the "inner styling is global"
57
- // model the H2 badge labels).
58
- expect(out.source).toContain('<article style={{ left: "40px" }}>card</article>');
59
- expect(out.source).not.toContain('<Card style=');
60
- });
61
-
62
- test('a normal (non-instance) element ignores the occurrence (no-op remap)', () => {
63
- const src = 'function Demo() { return <div>x</div>; }';
64
- const id = idsOf(src).div as string;
65
- const out = applyEdit(CANVAS, src, id, 'style.padding', '14', 3);
66
- expect(out.source).toContain('<div style={{ padding: 14 }}>x</div>');
67
- });
68
-
69
- test('an element in a single-usage component ignores the occurrence (not splittable)', () => {
70
- const src = [
71
- 'function Card() { return <article>card</article>; }',
72
- 'function Demo() { return <section><Card /></section>; }',
73
- ].join('\n');
74
- const innerId = idsOf(src).article as string;
75
- // One usage → resolveUsageId returns the inner id (can't split) — the edit
76
- // lands on <article>, never fabricates a phantom usage index.
77
- const out = applyEdit(CANVAS, src, innerId, 'style.left', '"40px"', 0);
78
- expect(out.source).toContain('<article style={{ left: "40px" }}>card</article>');
79
- expect(out.source).not.toContain('<Card style=');
80
- });
81
- });
@@ -1,91 +0,0 @@
1
- // edit-persistence — DDR-148 dogfood. A CSS edit on a video-comp element must
2
- // survive into the RENDERED module, not just the optimistic DOM overlay — i.e.
3
- // source edit → build → the new value is in the compiled canvas the Player runs.
4
- // This end-to-end guard would have caught the original "my color reverts when
5
- // the video replays" bug (a trailing-comma insert produced `opacity: o, , color`
6
- // → the build FAILED → the Player kept rendering the OLD source).
7
-
8
- import { describe, expect, test } from 'bun:test';
9
- import { mkdtempSync, writeFileSync } from 'node:fs';
10
- import { tmpdir } from 'node:os';
11
- import { join } from 'node:path';
12
- import { buildCanvasModule } from '../canvas-build.ts';
13
- import { applyEdit } from '../canvas-edit.ts';
14
- import { transpileCanvasSource } from '../canvas-pipeline.ts';
15
-
16
- const CANVAS = '/tmp/edit-persist.tsx';
17
-
18
- /** buildCanvasModule needs the entrypoint on disk — write the source, then build. */
19
- async function buildAt(source: string) {
20
- const dir = mkdtempSync(join(tmpdir(), 'edit-persist-'));
21
- const abs = join(dir, 'Comp.tsx');
22
- writeFileSync(abs, source);
23
- return buildCanvasModule(abs, source);
24
- }
25
-
26
- // A frame-driven letter span (the exact shape from the intro demo): computed
27
- // transform/opacity + a trailing comma on the last property.
28
- const COMP = `import { AbsoluteFill, interpolate, useCurrentFrame } from 'remotion';
29
- export default function Comp() {
30
- const frame = useCurrentFrame();
31
- const y = interpolate(frame, [0, 20], [40, 0]);
32
- const o = interpolate(frame, [0, 20], [0, 1]);
33
- return (
34
- <AbsoluteFill>
35
- <span
36
- style={{
37
- fontSize: 132,
38
- fontWeight: 800,
39
- transform: \`translateY(\${y}px)\`,
40
- opacity: o,
41
- color: '#f0ece5',
42
- }}
43
- >
44
- maude
45
- </span>
46
- </AbsoluteFill>
47
- );
48
- }
49
- `;
50
-
51
- function spanId(source: string): string {
52
- const { withIds } = transpileCanvasSource(CANVAS, source);
53
- const m = withIds.match(/<span[^>]*?data-cd-id="([0-9a-f]{8})"/);
54
- if (!m) throw new Error('no span id');
55
- return m[1] as string;
56
- }
57
-
58
- describe('edit-persistence — a CSS edit survives into the built module', () => {
59
- test('SWAP an existing color → the new color is in the compiled canvas', async () => {
60
- const id = spanId(COMP);
61
- const edited = applyEdit(CANVAS, COMP, id, 'style.color', "'#ff0000'").source;
62
- expect(edited).toContain("color: '#ff0000'");
63
- // The value the Player actually renders is the BUILT module — assert it there.
64
- const built = await buildAt(edited);
65
- expect(built.js).toContain('#ff0000');
66
- expect(built.js).not.toContain('#f0ece5'); // old value fully replaced
67
- });
68
-
69
- test('INSERT a new prop next to a TRAILING comma → still builds + renders (the bug)', async () => {
70
- const id = spanId(COMP);
71
- // Insert a brand-new property where the last one (color) ends with a comma.
72
- const edited = applyEdit(CANVAS, COMP, id, 'style.letterSpacing', "'-0.04em'").source;
73
- expect(edited).not.toMatch(/,\s*,/); // NO double comma (the crash that reverted the render)
74
- const built = await buildAt(edited); // must not throw
75
- expect(built.js).toContain('-0.04em');
76
- expect(built.js).toContain('#f0ece5'); // untouched props survive
77
- });
78
-
79
- test('a SEQUENCE of edits all persist (no edit clobbers a prior one)', async () => {
80
- let src = COMP;
81
- const id = spanId(src);
82
- src = applyEdit(CANVAS, src, id, 'style.color', "'#00ff00'").source;
83
- src = applyEdit(CANVAS, src, id, 'style.fontWeight', '900').source;
84
- src = applyEdit(CANVAS, src, id, 'style.fontSize', '148').source;
85
- const built = await buildAt(src);
86
- expect(built.js).toContain('#00ff00');
87
- expect(built.js).toContain('148');
88
- // the frame-driven values must still be present (edits never touched them)
89
- expect(built.js).toContain('translateY');
90
- });
91
- });
@@ -1,119 +0,0 @@
1
- // GET /_api/edit-scope — the INV-3 local-vs-shared predictability verdict
2
- // (feature-element-editing-robustness Stage H). Boots a real server, serves a
3
- // canvas with a `Card` component reused 3×, then asserts:
4
- // • an element INSIDE the reused component → scope 'shared', affects 3
5
- // • a top-level artboard element → scope 'local'
6
- // • the `.map()` caveat (DDR-139) — a local element rendered N× (client-
7
- // supplied `rendered`) → scope 'shared', reason 'mapped'
8
- // • the route is main-origin only (proven separately in canvas-origin-gate).
9
-
10
- import { describe, expect, test } from 'bun:test';
11
- import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
- import { join } from 'node:path';
13
-
14
- import { bootServer, killProc, makeSandbox, nextPort } from './_helpers.ts';
15
-
16
- const CANVAS_SRC = `const Card = ({ title }) => (
17
- <div className="card">
18
- <h3>{title}</h3>
19
- </div>
20
- );
21
-
22
- export default function Gallery() {
23
- return (
24
- <DesignCanvas>
25
- <DCArtboard id="home" label="Home" width={1440} height={1024}>
26
- <section className="grid">
27
- <Card title="A" />
28
- <Card title="B" />
29
- <Card title="C" />
30
- </section>
31
- </DCArtboard>
32
- </DesignCanvas>
33
- );
34
- }
35
- `;
36
-
37
- interface LocEntry {
38
- line: number;
39
- jsxPath: string[];
40
- componentName: string;
41
- }
42
-
43
- async function boot() {
44
- const { root, designRoot } = makeSandbox();
45
- mkdirSync(join(designRoot, 'ui'), { recursive: true });
46
- writeFileSync(join(designRoot, 'ui', 'Gallery.tsx'), CANVAS_SRC);
47
- const port = nextPort();
48
- const proc = await bootServer(root, port);
49
- return { designRoot, main: `http://localhost:${port}`, proc };
50
- }
51
-
52
- /** Warm the pipeline (stamps cd-ids + writes _locator.json), return the map. */
53
- async function locatorMap(main: string, designRoot: string): Promise<Record<string, LocEntry>> {
54
- const r = await fetch(`${main}/.design/ui/Gallery.tsx`, { signal: AbortSignal.timeout(2000) });
55
- expect(r.status).toBe(200);
56
- const locator = JSON.parse(readFileSync(join(designRoot, '_locator.json'), 'utf8'));
57
- return locator['ui/Gallery'] as Record<string, LocEntry>;
58
- }
59
-
60
- function findId(map: Record<string, LocEntry>, pred: (e: LocEntry) => boolean): string {
61
- const hit = Object.entries(map).find(([, e]) => pred(e));
62
- if (!hit) throw new Error('no matching locator entry');
63
- return hit[0];
64
- }
65
-
66
- async function scope(main: string, id: string, rendered?: number) {
67
- const q = new URLSearchParams({ canvas: 'ui/Gallery', id });
68
- if (rendered != null) q.set('rendered', String(rendered));
69
- const res = await fetch(`${main}/_api/edit-scope?${q}`, { signal: AbortSignal.timeout(2000) });
70
- return { status: res.status, body: (await res.json()) as Record<string, unknown> };
71
- }
72
-
73
- describe('GET /_api/edit-scope', () => {
74
- test('reports shared for a reused-component inner element, local for a top-level one', async () => {
75
- const { designRoot, main, proc } = await boot();
76
- try {
77
- const map = await locatorMap(main, designRoot);
78
-
79
- // An element inside the reused `Card` component (componentName === 'Card').
80
- const innerId = findId(map, (e) => e.componentName === 'Card');
81
- const shared = await scope(main, innerId);
82
- expect(shared.status).toBe(200);
83
- expect(shared.body.scope).toBe('shared');
84
- expect(shared.body.componentName).toBe('Card');
85
- expect(shared.body.affects).toBe(3);
86
- expect(shared.body.reason).toBe('component');
87
-
88
- // A top-level artboard element (the <section>) — not inside a reused comp.
89
- const topId = findId(
90
- map,
91
- (e) => e.componentName !== 'Card' && e.jsxPath[e.jsxPath.length - 1] === 'section'
92
- );
93
- const local = await scope(main, topId);
94
- expect(local.status).toBe(200);
95
- expect(local.body.scope).toBe('local');
96
- expect(local.body.affects).toBe(1);
97
- expect(local.body.reason).toBe('single');
98
-
99
- // The .map() caveat (DDR-139): a local element the client says renders N×
100
- // is 'shared' ('mapped') even though its source usage count is 1.
101
- const mapped = await scope(main, topId, 4);
102
- expect(mapped.body.scope).toBe('shared');
103
- expect(mapped.body.reason).toBe('mapped');
104
- expect(mapped.body.affects).toBe(4);
105
-
106
- // A bogus id is a 400 (invalid data-cd-id shape). Note: since the
107
- // authored-id widening (feature-4, 2026-07-20) short word-ids like "zzz"
108
- // are VALID shapes (hand-authored data-cd-id attrs are preserved by the
109
- // pipeline) — only genuinely malformed values (spaces, slashes) fail.
110
- const bad = await fetch(
111
- `${main}/_api/edit-scope?canvas=ui/Gallery&id=${encodeURIComponent('../etc/passwd')}`,
112
- { signal: AbortSignal.timeout(2000) }
113
- );
114
- expect(bad.status).toBe(400);
115
- } finally {
116
- await killProc(proc as never);
117
- }
118
- });
119
- });
@@ -1,142 +0,0 @@
1
- import { beforeAll, describe, expect, mock, test } from 'bun:test';
2
-
3
- import {
4
- buildEditSourceRecord,
5
- createEditSourceCommand,
6
- EDIT_SOURCE_KIND,
7
- type EditSourceApplyFn,
8
- type EditSourcePayload,
9
- } from '../commands/edit-source-command.ts';
10
- import { type CommandSinks, rebuildCommand, registerCommand } from '../undo-stack.ts';
11
-
12
- const cssEdit: EditSourcePayload = {
13
- op: 'css',
14
- canvas: '.design/ui/Foo.tsx',
15
- id: 'cd-1',
16
- key: 'color',
17
- before: 'red',
18
- after: 'blue',
19
- };
20
-
21
- describe('createEditSourceCommand', () => {
22
- test('do() applies the AFTER value', async () => {
23
- const applyFn = mock(() => {});
24
- const cmd = createEditSourceCommand({ payload: cssEdit, applyFn });
25
- await cmd.do();
26
- expect(applyFn).toHaveBeenCalledTimes(1);
27
- expect(applyFn.mock.calls[0]?.[0]).toEqual({
28
- op: 'css',
29
- canvas: '.design/ui/Foo.tsx',
30
- id: 'cd-1',
31
- key: 'color',
32
- value: 'blue',
33
- // do() writes `after` over `before`, so `from` = before; css has no occurrence.
34
- from: 'red',
35
- occurrence: undefined,
36
- });
37
- });
38
-
39
- test('do()/undo() carry occurrence + from for a text edit (variable re-target)', async () => {
40
- const applyFn = mock(() => {});
41
- const textEdit: EditSourcePayload = {
42
- op: 'text',
43
- canvas: '.design/ui/Foo.tsx',
44
- id: 'cd-9',
45
- key: '',
46
- before: 'Old',
47
- after: 'New',
48
- occurrence: 2,
49
- };
50
- const cmd = createEditSourceCommand({ payload: textEdit, applyFn });
51
- await cmd.do();
52
- // redo/do: write New over Old → from = Old.
53
- expect(applyFn.mock.calls[0]?.[0]).toMatchObject({ value: 'New', from: 'Old', occurrence: 2 });
54
- await cmd.undo();
55
- // undo: write Old over New → from = New.
56
- expect(applyFn.mock.calls[1]?.[0]).toMatchObject({ value: 'Old', from: 'New', occurrence: 2 });
57
- });
58
-
59
- test('undo() applies the BEFORE value', async () => {
60
- const applyFn = mock(() => {});
61
- const cmd = createEditSourceCommand({ payload: cssEdit, applyFn });
62
- await cmd.undo();
63
- expect(applyFn.mock.calls[0]?.[0]?.value).toBe('red');
64
- });
65
-
66
- test('undo() of a NEW prop (before:null) applies null = reset', async () => {
67
- const applyFn = mock(() => {});
68
- const cmd = createEditSourceCommand({
69
- payload: { ...cssEdit, before: null, after: 'blue' },
70
- applyFn,
71
- });
72
- await cmd.undo();
73
- expect(applyFn.mock.calls[0]?.[0]?.value).toBeNull();
74
- });
75
-
76
- test('do() of a RESET (after:null) applies null = remove the prop', async () => {
77
- const applyFn = mock(() => {});
78
- const cmd = createEditSourceCommand({
79
- payload: { ...cssEdit, before: 'red', after: null },
80
- applyFn,
81
- });
82
- await cmd.do();
83
- expect(applyFn.mock.calls[0]?.[0]?.value).toBeNull();
84
- });
85
-
86
- test('label reflects op + key', () => {
87
- expect(createEditSourceCommand({ payload: cssEdit, applyFn: () => {} }).label).toBe(
88
- 'edit color'
89
- );
90
- expect(
91
- createEditSourceCommand({ payload: { ...cssEdit, after: null }, applyFn: () => {} }).label
92
- ).toBe('reset color');
93
- expect(
94
- createEditSourceCommand({
95
- payload: { op: 'attr', canvas: 'x', id: 'y', key: 'data-x', before: null, after: '1' },
96
- applyFn: () => {},
97
- }).label
98
- ).toBe('edit @data-x');
99
- expect(
100
- createEditSourceCommand({
101
- payload: { op: 'text', canvas: 'x', id: 'y', key: '', before: 'a', after: 'b' },
102
- applyFn: () => {},
103
- }).label
104
- ).toBe('edit text');
105
- });
106
- });
107
-
108
- describe('buildEditSourceRecord', () => {
109
- test('produces a serializable record under the edit-source kind', () => {
110
- const rec = buildEditSourceRecord(cssEdit);
111
- expect(rec.kind).toBe(EDIT_SOURCE_KIND);
112
- expect(rec.payload).toEqual(cssEdit);
113
- expect(JSON.parse(JSON.stringify(rec))).toEqual(rec); // round-trips
114
- });
115
- });
116
-
117
- describe('edit-source registry', () => {
118
- // The module self-registers on import, but sibling test files wipe the shared
119
- // builder registry in their beforeEach — re-register here so this block is
120
- // order-independent. Mirrors the real registration in edit-source-command.ts.
121
- beforeAll(() => {
122
- registerCommand<EditSourcePayload>(EDIT_SOURCE_KIND, (record, sinks) => {
123
- const applyFn = sinks.editSourceApplyFn as EditSourceApplyFn | undefined;
124
- if (!applyFn) return null;
125
- return createEditSourceCommand({ payload: record.payload, applyFn, label: record.label });
126
- });
127
- });
128
-
129
- test('rebuildCommand returns null when the editSourceApplyFn sink is unbound', () => {
130
- expect(rebuildCommand(buildEditSourceRecord(cssEdit), {} as CommandSinks)).toBeNull();
131
- });
132
-
133
- test('rebuildCommand wires the bound sink into a runnable command', async () => {
134
- const applyFn = mock(() => {});
135
- const cmd = rebuildCommand(buildEditSourceRecord(cssEdit), {
136
- editSourceApplyFn: applyFn,
137
- } as CommandSinks);
138
- expect(cmd).not.toBeNull();
139
- await cmd?.do();
140
- expect(applyFn.mock.calls[0]?.[0]?.value).toBe('blue');
141
- });
142
- });