@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.
Files changed (506) hide show
  1. package/apps/studio/acp/bridge.ts +18 -13
  2. package/apps/studio/acp/probe.ts +268 -16
  3. package/apps/studio/acp/transcript-io.ts +394 -0
  4. package/apps/studio/acp/transcript.ts +103 -38
  5. package/apps/studio/api.ts +139 -26
  6. package/apps/studio/bin/_import-figma.mjs +57 -11
  7. package/apps/studio/bin/_seed-fixture.mjs +163 -0
  8. package/apps/studio/canvas-imports.ts +89 -0
  9. package/apps/studio/client/app.jsx +257 -7
  10. package/apps/studio/client/export-center.jsx +15 -7
  11. package/apps/studio/client/panels/ReadinessList.jsx +7 -1
  12. package/apps/studio/client/panels/SyncPanel.jsx +125 -4
  13. package/apps/studio/client/report-bug.jsx +19 -1
  14. package/apps/studio/client/styles/3-shell-maude.css +34 -0
  15. package/apps/studio/client/styles/4-components.css +26 -0
  16. package/apps/studio/collab/persistence.ts +132 -16
  17. package/apps/studio/collab/registry.ts +10 -18
  18. package/apps/studio/debug-bundle.ts +13 -0
  19. package/apps/studio/dist/client.bundle.js +1128 -1128
  20. package/apps/studio/dist/styles.css +1 -1
  21. package/apps/studio/export-dialog.tsx +54 -0
  22. package/apps/studio/exporters/degraded.ts +19 -3
  23. package/apps/studio/exporters/ghostscript.ts +194 -0
  24. package/apps/studio/exporters/pdf-fonts.ts +261 -0
  25. package/apps/studio/exporters/pdf.ts +152 -3
  26. package/apps/studio/exporters/remote.ts +36 -1
  27. package/apps/studio/fs-watch.ts +45 -1
  28. package/apps/studio/http.ts +7 -1
  29. package/apps/studio/mem.ts +45 -9
  30. package/apps/studio/readiness.ts +42 -7
  31. package/apps/studio/server.ts +11 -4
  32. package/apps/studio/sync/agent.ts +136 -29
  33. package/apps/studio/sync/asset-push.ts +1 -47
  34. package/apps/studio/sync/codec.ts +122 -31
  35. package/apps/studio/sync/cold-start-apply.ts +7 -0
  36. package/apps/studio/sync/cold-start.ts +118 -22
  37. package/apps/studio/sync/comment-identity.ts +68 -0
  38. package/apps/studio/sync/connection-state.ts +15 -1
  39. package/apps/studio/sync/file-ledger.ts +117 -0
  40. package/apps/studio/sync/file-plane.ts +623 -27
  41. package/apps/studio/sync/index.ts +711 -20
  42. package/apps/studio/sync/journal-client.ts +13 -1
  43. package/apps/studio/sync/migrate-seed.ts +40 -3
  44. package/apps/studio/sync/presentation.ts +26 -3
  45. package/apps/studio/sync/retry-after.ts +169 -0
  46. package/apps/studio/sync/seed-progress.ts +218 -0
  47. package/apps/studio/sync/status.ts +122 -5
  48. package/apps/studio/sync/transport-error.ts +111 -0
  49. package/apps/studio/whats-new.json +91 -0
  50. package/cli/bin/maude.mjs +2 -0
  51. package/cli/commands/codex.mjs +191 -0
  52. package/cli/commands/harness.mjs +1051 -0
  53. package/cli/commands/help.mjs +13 -0
  54. package/cli/lib/design-link.mjs +190 -2
  55. package/cli/lib/harness/capabilities.mjs +302 -0
  56. package/cli/lib/harness/codex-runtime.mjs +889 -0
  57. package/cli/lib/harness/compatibility.mjs +27 -0
  58. package/cli/lib/harness/discover-claude.mjs +1393 -0
  59. package/cli/lib/harness/managed-state.mjs +1296 -0
  60. package/cli/lib/harness/model.mjs +86 -0
  61. package/cli/lib/harness/secrets.mjs +390 -0
  62. package/cli/lib/harness/targets/codex.mjs +1141 -0
  63. package/cli/lib/harness/targets/opencode.mjs +807 -0
  64. package/cli/lib/harness/transaction.mjs +1099 -0
  65. package/cli/lib/hubs-config.mjs +35 -8
  66. package/cli/templates/harness/opencode/maude-projector.ts +58 -0
  67. package/docs/harness-capability-matrix.md +125 -0
  68. package/docs/harness-environment-projection.md +95 -0
  69. package/package.json +32 -9
  70. package/plugins/flow/.claude-plugin/config.schema.json +8 -0
  71. package/apps/studio/.ai/cache/_stats.json +0 -7
  72. package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
  73. package/apps/studio/bin/_curl-local.test.mjs +0 -280
  74. package/apps/studio/bin/_pw-launch.test.mjs +0 -90
  75. package/apps/studio/bin/_smart-frames.test.mjs +0 -195
  76. package/apps/studio/bin/_transcribe.test.mjs +0 -80
  77. package/apps/studio/bun.lock +0 -928
  78. package/apps/studio/draw/test/animate.test.ts +0 -172
  79. package/apps/studio/draw/test/brush.test.ts +0 -213
  80. package/apps/studio/draw/test/composition.test.ts +0 -141
  81. package/apps/studio/draw/test/geometry.test.ts +0 -199
  82. package/apps/studio/draw/test/gradient.test.ts +0 -167
  83. package/apps/studio/draw/test/layout.test.ts +0 -120
  84. package/apps/studio/draw/test/morph.test.ts +0 -107
  85. package/apps/studio/draw/test/optimize.test.ts +0 -40
  86. package/apps/studio/draw/test/palette.test.ts +0 -123
  87. package/apps/studio/draw/test/primitives.test.ts +0 -129
  88. package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
  89. package/apps/studio/draw/test/serialize.test.ts +0 -105
  90. package/apps/studio/figma/assets.test.ts +0 -464
  91. package/apps/studio/figma/client.test.ts +0 -395
  92. package/apps/studio/figma/codegen-client.test.ts +0 -276
  93. package/apps/studio/figma/codegen-fonts.test.ts +0 -103
  94. package/apps/studio/figma/codegen-values.test.ts +0 -179
  95. package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
  96. package/apps/studio/figma/fig-decode.test.ts +0 -788
  97. package/apps/studio/figma/fig-differential.test.ts +0 -182
  98. package/apps/studio/figma/fig-translator.test.ts +0 -192
  99. package/apps/studio/figma/fig-vector.test.ts +0 -113
  100. package/apps/studio/figma/from-codegen.test.ts +0 -408
  101. package/apps/studio/figma/sanitize.test.ts +0 -325
  102. package/apps/studio/figma/tailwind-map.test.ts +0 -142
  103. package/apps/studio/figma/to-artboard.test.ts +0 -808
  104. package/apps/studio/figma/to-render.test.ts +0 -180
  105. package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
  106. package/apps/studio/figma/to-strokes.test.ts +0 -705
  107. package/apps/studio/figma/to-tokens.test.ts +0 -321
  108. package/apps/studio/figma/url.test.ts +0 -167
  109. package/apps/studio/footage/schema.test.ts +0 -287
  110. package/apps/studio/generation/adapters/groq.test.ts +0 -80
  111. package/apps/studio/generation/audio-library.test.ts +0 -95
  112. package/apps/studio/generation/captions.test.ts +0 -78
  113. package/apps/studio/generation/elevenlabs.test.ts +0 -223
  114. package/apps/studio/generation/gemini.test.ts +0 -350
  115. package/apps/studio/generation/jobs.test.ts +0 -128
  116. package/apps/studio/generation/keys.test.ts +0 -75
  117. package/apps/studio/generation/prefs.test.ts +0 -95
  118. package/apps/studio/generation/types.test.ts +0 -123
  119. package/apps/studio/generation/whisper-models.test.ts +0 -179
  120. package/apps/studio/test/_helpers.ts +0 -108
  121. package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
  122. package/apps/studio/test/acp-activity.test.ts +0 -154
  123. package/apps/studio/test/acp-ai-activity.test.ts +0 -182
  124. package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
  125. package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
  126. package/apps/studio/test/acp-branch-guard.test.ts +0 -123
  127. package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
  128. package/apps/studio/test/acp-bridge.test.ts +0 -301
  129. package/apps/studio/test/acp-capabilities.test.ts +0 -123
  130. package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
  131. package/apps/studio/test/acp-commands.test.ts +0 -119
  132. package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
  133. package/apps/studio/test/acp-elicitation.test.ts +0 -251
  134. package/apps/studio/test/acp-env.test.ts +0 -95
  135. package/apps/studio/test/acp-mode-banner.test.ts +0 -45
  136. package/apps/studio/test/acp-origin-gate.test.ts +0 -160
  137. package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
  138. package/apps/studio/test/acp-permission.test.ts +0 -278
  139. package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
  140. package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
  141. package/apps/studio/test/acp-session-plugins.test.ts +0 -209
  142. package/apps/studio/test/acp-toolgroup.test.ts +0 -76
  143. package/apps/studio/test/acp-transcript-view.test.ts +0 -71
  144. package/apps/studio/test/acp-transcript.test.ts +0 -238
  145. package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
  146. package/apps/studio/test/acp-usage.test.ts +0 -143
  147. package/apps/studio/test/acp-write-gate.test.ts +0 -323
  148. package/apps/studio/test/acp-write-scope.test.ts +0 -533
  149. package/apps/studio/test/active-state.test.ts +0 -186
  150. package/apps/studio/test/activity.test.ts +0 -189
  151. package/apps/studio/test/ai-activity.test.ts +0 -113
  152. package/apps/studio/test/annotate-write.test.ts +0 -1074
  153. package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
  154. package/apps/studio/test/annotations-align.test.ts +0 -88
  155. package/apps/studio/test/annotations-api.test.ts +0 -145
  156. package/apps/studio/test/annotations-bindings.test.ts +0 -262
  157. package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
  158. package/apps/studio/test/annotations-groups.test.ts +0 -231
  159. package/apps/studio/test/annotations-layer.test.ts +0 -1011
  160. package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
  161. package/apps/studio/test/annotations-snap.test.ts +0 -135
  162. package/apps/studio/test/annotations-text-format.test.ts +0 -396
  163. package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
  164. package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
  165. package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
  166. package/apps/studio/test/artboard-kinds.test.tsx +0 -83
  167. package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
  168. package/apps/studio/test/asset-api.test.ts +0 -149
  169. package/apps/studio/test/assets-s3.test.ts +0 -249
  170. package/apps/studio/test/binary-smoke.test.ts +0 -47
  171. package/apps/studio/test/boot-self-heal.test.ts +0 -87
  172. package/apps/studio/test/browse-posture.test.tsx +0 -107
  173. package/apps/studio/test/bundle-smoke.test.ts +0 -46
  174. package/apps/studio/test/camera-reveal.test.tsx +0 -173
  175. package/apps/studio/test/canvas-artifacts.test.ts +0 -125
  176. package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
  177. package/apps/studio/test/canvas-build.test.ts +0 -141
  178. package/apps/studio/test/canvas-create-api.test.ts +0 -676
  179. package/apps/studio/test/canvas-cursors.test.ts +0 -164
  180. package/apps/studio/test/canvas-edit.test.ts +0 -470
  181. package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
  182. package/apps/studio/test/canvas-header.test.ts +0 -127
  183. package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
  184. package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
  185. package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
  186. package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
  187. package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
  188. package/apps/studio/test/canvas-list-watch.test.ts +0 -388
  189. package/apps/studio/test/canvas-media-drop.test.ts +0 -187
  190. package/apps/studio/test/canvas-meta-api.test.ts +0 -707
  191. package/apps/studio/test/canvas-move-api.test.ts +0 -587
  192. package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
  193. package/apps/studio/test/canvas-pipeline.test.ts +0 -180
  194. package/apps/studio/test/canvas-rects.test.ts +0 -198
  195. package/apps/studio/test/canvas-reorder.test.ts +0 -211
  196. package/apps/studio/test/canvas-route.test.ts +0 -179
  197. package/apps/studio/test/canvas-shell-base.test.ts +0 -107
  198. package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
  199. package/apps/studio/test/canvas-url.test.ts +0 -138
  200. package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
  201. package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
  202. package/apps/studio/test/capture-core.test.ts +0 -32
  203. package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
  204. package/apps/studio/test/chat-attachments.test.ts +0 -117
  205. package/apps/studio/test/chat-context.test.ts +0 -129
  206. package/apps/studio/test/chat-markdown.test.tsx +0 -58
  207. package/apps/studio/test/clip-addressing.test.ts +0 -738
  208. package/apps/studio/test/clip-ops.test.ts +0 -922
  209. package/apps/studio/test/cloud-build.test.ts +0 -95
  210. package/apps/studio/test/cloud-connect-note.test.ts +0 -135
  211. package/apps/studio/test/cloud-endpoints.test.ts +0 -590
  212. package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
  213. package/apps/studio/test/cloud-history-posture.test.ts +0 -230
  214. package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
  215. package/apps/studio/test/cloud-renew.test.ts +0 -205
  216. package/apps/studio/test/cloud-session-role.test.ts +0 -161
  217. package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
  218. package/apps/studio/test/cold-start-apply.test.ts +0 -303
  219. package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
  220. package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
  221. package/apps/studio/test/collab-bridge.test.ts +0 -79
  222. package/apps/studio/test/collab-loopback.test.ts +0 -63
  223. package/apps/studio/test/collab-origin-gate.test.ts +0 -323
  224. package/apps/studio/test/collab-protocol.test.ts +0 -146
  225. package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
  226. package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
  227. package/apps/studio/test/collab-room.test.ts +0 -188
  228. package/apps/studio/test/collab-session-survival.test.tsx +0 -176
  229. package/apps/studio/test/collab-stress.test.ts +0 -129
  230. package/apps/studio/test/comment-mount.test.ts +0 -97
  231. package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
  232. package/apps/studio/test/comments-api.test.ts +0 -277
  233. package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
  234. package/apps/studio/test/comments-overlay.test.ts +0 -117
  235. package/apps/studio/test/compile-entry.test.ts +0 -133
  236. package/apps/studio/test/component-map.test.ts +0 -48
  237. package/apps/studio/test/config-projection.test.ts +0 -104
  238. package/apps/studio/test/config-reload.test.ts +0 -230
  239. package/apps/studio/test/config-version.test.ts +0 -88
  240. package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
  241. package/apps/studio/test/convert-to-absolute.test.ts +0 -333
  242. package/apps/studio/test/credential-grammar.test.ts +0 -107
  243. package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
  244. package/apps/studio/test/csrf-write-guard.test.ts +0 -141
  245. package/apps/studio/test/debug-bundle.test.ts +0 -105
  246. package/apps/studio/test/design-setup-readiness.test.ts +0 -155
  247. package/apps/studio/test/detach-component.test.ts +0 -94
  248. package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
  249. package/apps/studio/test/dom-selection.test.ts +0 -198
  250. package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
  251. package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
  252. package/apps/studio/test/edit-persistence.test.ts +0 -91
  253. package/apps/studio/test/edit-scope-api.test.ts +0 -119
  254. package/apps/studio/test/edit-source-command.test.ts +0 -142
  255. package/apps/studio/test/edit-suppress.test.ts +0 -170
  256. package/apps/studio/test/editing-presence.test.ts +0 -103
  257. package/apps/studio/test/element-resize.test.ts +0 -136
  258. package/apps/studio/test/element-structural-api.test.ts +0 -434
  259. package/apps/studio/test/element-structural-edit.test.ts +0 -750
  260. package/apps/studio/test/ensure-browser.test.ts +0 -92
  261. package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
  262. package/apps/studio/test/export-assemble.test.ts +0 -53
  263. package/apps/studio/test/export-browser-lane.test.ts +0 -126
  264. package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
  265. package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
  266. package/apps/studio/test/export-center.test.tsx +0 -287
  267. package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
  268. package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
  269. package/apps/studio/test/export-lane.test.ts +0 -245
  270. package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
  271. package/apps/studio/test/exporters/canva.test.ts +0 -63
  272. package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
  273. package/apps/studio/test/exporters/endpoint.test.ts +0 -121
  274. package/apps/studio/test/exporters/history.test.ts +0 -107
  275. package/apps/studio/test/exporters/html.test.ts +0 -26
  276. package/apps/studio/test/exporters/jobs.test.ts +0 -342
  277. package/apps/studio/test/exporters/pdf.test.ts +0 -85
  278. package/apps/studio/test/exporters/png.test.ts +0 -103
  279. package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
  280. package/apps/studio/test/exporters/pptx.test.ts +0 -31
  281. package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
  282. package/apps/studio/test/exporters/runtime.test.ts +0 -59
  283. package/apps/studio/test/exporters/scope.test.ts +0 -292
  284. package/apps/studio/test/exporters/svg.test.ts +0 -29
  285. package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
  286. package/apps/studio/test/exporters/zip.test.ts +0 -104
  287. package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
  288. package/apps/studio/test/figjam-v3-model.test.ts +0 -342
  289. package/apps/studio/test/figma-explode.test.ts +0 -438
  290. package/apps/studio/test/figma-provenance.test.ts +0 -108
  291. package/apps/studio/test/figma-routes.test.ts +0 -294
  292. package/apps/studio/test/file-lock.test.ts +0 -84
  293. package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -13
  294. package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
  295. package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
  296. package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
  297. package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
  298. package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
  299. package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
  300. package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
  301. package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
  302. package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
  303. package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
  304. package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
  305. package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
  306. package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
  307. package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
  308. package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
  309. package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
  310. package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
  311. package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
  312. package/apps/studio/test/footage-store.test.ts +0 -100
  313. package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
  314. package/apps/studio/test/fs-watch.test.ts +0 -41
  315. package/apps/studio/test/gemma-models.test.ts +0 -245
  316. package/apps/studio/test/generate-route.test.ts +0 -106
  317. package/apps/studio/test/git-api.test.ts +0 -0
  318. package/apps/studio/test/git-branches.test.ts +0 -341
  319. package/apps/studio/test/git-cloud-posture.test.ts +0 -59
  320. package/apps/studio/test/git-grouping.test.ts +0 -106
  321. package/apps/studio/test/git-lifecycle.test.ts +0 -100
  322. package/apps/studio/test/git-log-format.test.ts +0 -95
  323. package/apps/studio/test/git-safe-rel.test.ts +0 -132
  324. package/apps/studio/test/git-system-engine.test.ts +0 -135
  325. package/apps/studio/test/git-watch.test.ts +0 -97
  326. package/apps/studio/test/github-api.test.ts +0 -577
  327. package/apps/studio/test/grid-track-handles.test.ts +0 -160
  328. package/apps/studio/test/handoff-static-frames.test.ts +0 -215
  329. package/apps/studio/test/handoff.test.ts +0 -329
  330. package/apps/studio/test/history-rollback.test.ts +0 -88
  331. package/apps/studio/test/hmr-broadcast.test.ts +0 -236
  332. package/apps/studio/test/hmr-classify.test.ts +0 -87
  333. package/apps/studio/test/hub-link.test.ts +0 -80
  334. package/apps/studio/test/identity-cache.test.ts +0 -83
  335. package/apps/studio/test/import-asset-browser.test.ts +0 -64
  336. package/apps/studio/test/import-asset-route.test.ts +0 -71
  337. package/apps/studio/test/import-asset.test.ts +0 -427
  338. package/apps/studio/test/import-brand-browser.test.ts +0 -88
  339. package/apps/studio/test/import-brand-route.test.ts +0 -120
  340. package/apps/studio/test/import-brand.test.ts +0 -206
  341. package/apps/studio/test/import-figma.test.ts +0 -667
  342. package/apps/studio/test/import-tokens.test.ts +0 -722
  343. package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
  344. package/apps/studio/test/input-router.test.ts +0 -757
  345. package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
  346. package/apps/studio/test/inspect-selections.test.ts +0 -219
  347. package/apps/studio/test/knob-props-authored.test.ts +0 -87
  348. package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
  349. package/apps/studio/test/locator.test.ts +0 -214
  350. package/apps/studio/test/marquee-overlay.test.ts +0 -94
  351. package/apps/studio/test/media-commit-chain.test.ts +0 -210
  352. package/apps/studio/test/mode-toggle.test.tsx +0 -226
  353. package/apps/studio/test/motion-sample.test.ts +0 -35
  354. package/apps/studio/test/move-artboards-command.test.ts +0 -108
  355. package/apps/studio/test/participants-chrome.test.ts +0 -65
  356. package/apps/studio/test/paths.test.ts +0 -88
  357. package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
  358. package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
  359. package/apps/studio/test/perf-harness.ts +0 -193
  360. package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
  361. package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
  362. package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
  363. package/apps/studio/test/photo-edit-api.test.ts +0 -201
  364. package/apps/studio/test/photo-filters.test.ts +0 -149
  365. package/apps/studio/test/photo-pipeline.test.ts +0 -106
  366. package/apps/studio/test/photo-taxonomy.test.ts +0 -96
  367. package/apps/studio/test/print-marks.test.ts +0 -113
  368. package/apps/studio/test/print-units.test.ts +0 -173
  369. package/apps/studio/test/read-annotations.test.ts +0 -727
  370. package/apps/studio/test/read-only-gate.test.ts +0 -188
  371. package/apps/studio/test/read-only-role.test.ts +0 -95
  372. package/apps/studio/test/readiness.test.ts +0 -226
  373. package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
  374. package/apps/studio/test/reorder-api.test.ts +0 -210
  375. package/apps/studio/test/repo-concurrency.test.ts +0 -146
  376. package/apps/studio/test/repo-lock.test.ts +0 -350
  377. package/apps/studio/test/report-proxy.test.ts +0 -125
  378. package/apps/studio/test/ripple.test.ts +0 -197
  379. package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
  380. package/apps/studio/test/runtime-bundle.test.ts +0 -69
  381. package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
  382. package/apps/studio/test/scaffold-design.test.ts +0 -122
  383. package/apps/studio/test/server-lifecycle.test.ts +0 -38
  384. package/apps/studio/test/session-runtime-state.test.ts +0 -226
  385. package/apps/studio/test/session-scope.test.ts +0 -100
  386. package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
  387. package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
  388. package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
  389. package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
  390. package/apps/studio/test/shared-doc-projection.test.ts +0 -238
  391. package/apps/studio/test/shell-importmap.test.ts +0 -56
  392. package/apps/studio/test/sizing-mode.test.ts +0 -102
  393. package/apps/studio/test/slash-commands.test.ts +0 -117
  394. package/apps/studio/test/snap-distance-pill.test.ts +0 -68
  395. package/apps/studio/test/spacing-handles.test.ts +0 -138
  396. package/apps/studio/test/specimen-select.test.ts +0 -88
  397. package/apps/studio/test/sync-agent.test.ts +0 -660
  398. package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
  399. package/apps/studio/test/sync-asset-push.test.ts +0 -931
  400. package/apps/studio/test/sync-atomic-write.test.ts +0 -62
  401. package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
  402. package/apps/studio/test/sync-autocommit.test.ts +0 -537
  403. package/apps/studio/test/sync-canvas-path.test.ts +0 -200
  404. package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
  405. package/apps/studio/test/sync-codec.test.ts +0 -230
  406. package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
  407. package/apps/studio/test/sync-cold-start.test.ts +0 -304
  408. package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
  409. package/apps/studio/test/sync-connection-state.test.ts +0 -337
  410. package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
  411. package/apps/studio/test/sync-decide-file.test.ts +0 -420
  412. package/apps/studio/test/sync-doc-name.test.ts +0 -281
  413. package/apps/studio/test/sync-echo-guard.test.ts +0 -96
  414. package/apps/studio/test/sync-file-ledger.test.ts +0 -334
  415. package/apps/studio/test/sync-file-membership.test.ts +0 -347
  416. package/apps/studio/test/sync-file-plane.test.ts +0 -976
  417. package/apps/studio/test/sync-file-pull.test.ts +0 -333
  418. package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
  419. package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
  420. package/apps/studio/test/sync-hardening.test.ts +0 -586
  421. package/apps/studio/test/sync-hub-listing.test.ts +0 -46
  422. package/apps/studio/test/sync-hubs-config.test.ts +0 -133
  423. package/apps/studio/test/sync-incident-replay.test.ts +0 -211
  424. package/apps/studio/test/sync-journal.test.ts +0 -176
  425. package/apps/studio/test/sync-meta-codec.test.ts +0 -199
  426. package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
  427. package/apps/studio/test/sync-move-retirement.test.ts +0 -231
  428. package/apps/studio/test/sync-panel-surface.test.ts +0 -153
  429. package/apps/studio/test/sync-path-pull.test.ts +0 -531
  430. package/apps/studio/test/sync-presentation.test.ts +0 -262
  431. package/apps/studio/test/sync-pull-budget.test.ts +0 -169
  432. package/apps/studio/test/sync-remote-docs.test.ts +0 -333
  433. package/apps/studio/test/sync-resync-routes.test.ts +0 -168
  434. package/apps/studio/test/sync-runtime.test.ts +0 -1675
  435. package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
  436. package/apps/studio/test/sync-settings-routes.test.ts +0 -195
  437. package/apps/studio/test/sync-settings.test.ts +0 -151
  438. package/apps/studio/test/sync-status.test.ts +0 -261
  439. package/apps/studio/test/sync-supervisor.test.ts +0 -262
  440. package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
  441. package/apps/studio/test/sync-trash.test.ts +0 -132
  442. package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
  443. package/apps/studio/test/sync-untrusted.test.ts +0 -103
  444. package/apps/studio/test/system-endpoint.test.ts +0 -144
  445. package/apps/studio/test/text-editability-stamp.test.ts +0 -131
  446. package/apps/studio/test/timeline-comp-target.test.ts +0 -139
  447. package/apps/studio/test/timeline-media-cache.test.ts +0 -41
  448. package/apps/studio/test/timeline-parse.test.ts +0 -184
  449. package/apps/studio/test/timeline-scale.test.ts +0 -65
  450. package/apps/studio/test/timeline-snap.test.ts +0 -85
  451. package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
  452. package/apps/studio/test/tool-palette.test.tsx +0 -55
  453. package/apps/studio/test/tour-overlay.test.tsx +0 -90
  454. package/apps/studio/test/trusted-request-host.test.ts +0 -66
  455. package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
  456. package/apps/studio/test/undo-stack.test.ts +0 -244
  457. package/apps/studio/test/use-agent-presence.test.tsx +0 -117
  458. package/apps/studio/test/use-annotation-resize.test.ts +0 -402
  459. package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
  460. package/apps/studio/test/use-artboard-drag.test.ts +0 -324
  461. package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
  462. package/apps/studio/test/use-collab.test.ts +0 -0
  463. package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
  464. package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
  465. package/apps/studio/test/use-selection-set.test.tsx +0 -166
  466. package/apps/studio/test/use-snap-guides.test.ts +0 -271
  467. package/apps/studio/test/use-tool-mode.test.tsx +0 -186
  468. package/apps/studio/test/use-undo-stack.test.tsx +0 -223
  469. package/apps/studio/test/video-asset.test.ts +0 -163
  470. package/apps/studio/test/video-comp-fixture.test.ts +0 -50
  471. package/apps/studio/test/video-comp.test.ts +0 -270
  472. package/apps/studio/test/video-encode-lib.test.ts +0 -63
  473. package/apps/studio/test/video-render-bridge.test.ts +0 -171
  474. package/apps/studio/test/whats-new.test.ts +0 -113
  475. package/apps/studio/test/whisper-setup.test.ts +0 -97
  476. package/apps/studio/test/workspace-containment.test.ts +0 -382
  477. package/apps/studio/test/workspace-signin.test.ts +0 -292
  478. package/apps/studio/test/ws-handshake.test.ts +0 -33
  479. package/cli/commands/cache.test.mjs +0 -166
  480. package/cli/commands/design-link.test.mjs +0 -419
  481. package/cli/commands/design.test.mjs +0 -240
  482. package/cli/commands/doctor.test.mjs +0 -237
  483. package/cli/commands/hub-workspace.test.mjs +0 -275
  484. package/cli/commands/hub.test.mjs +0 -225
  485. package/cli/commands/kg.test.mjs +0 -142
  486. package/cli/commands/preflight.test.mjs +0 -46
  487. package/cli/lib/argv.test.mjs +0 -46
  488. package/cli/lib/cache.test.mjs +0 -303
  489. package/cli/lib/cell-plan.test.mjs +0 -225
  490. package/cli/lib/config-lint.test.mjs +0 -117
  491. package/cli/lib/ddr-to-kgai.test.mjs +0 -118
  492. package/cli/lib/design-ownership.test.mjs +0 -329
  493. package/cli/lib/fetch-asset.test.mjs +0 -213
  494. package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
  495. package/cli/lib/figma-import-controls.test.mjs +0 -70
  496. package/cli/lib/flow-design-integration.test.mjs +0 -165
  497. package/cli/lib/gitignore-block.test.mjs +0 -136
  498. package/cli/lib/gitignore-drift.test.mjs +0 -156
  499. package/cli/lib/hubs-config.test.mjs +0 -165
  500. package/cli/lib/pkg-root.test.mjs +0 -111
  501. package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
  502. package/cli/lib/plugin-name-namespace.test.mjs +0 -71
  503. package/cli/lib/reconstruct-toolset.test.mjs +0 -194
  504. package/cli/lib/stack-detect.test.mjs +0 -121
  505. package/cli/lib/update-check.test.mjs +0 -32
  506. package/cli/lib/workspace-plan.test.mjs +0 -699
@@ -1,165 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { test } from 'node:test';
6
-
7
- import {
8
- addHub,
9
- getHub,
10
- hubsConfigPath,
11
- loadHubsConfig,
12
- normalizeUrl,
13
- removeHub,
14
- saveHubsConfig,
15
- setHubCodeModules,
16
- } from './hubs-config.mjs';
17
-
18
- function withTmpConfig(fn) {
19
- const dir = mkdtempSync(join(tmpdir(), 'maude-hubs-cfg-'));
20
- const path = join(dir, 'hubs.json');
21
- const prior = process.env.HUBS_CONFIG_PATH;
22
- process.env.HUBS_CONFIG_PATH = path;
23
- try {
24
- return fn(path);
25
- } finally {
26
- // `env.X = undefined` sets the STRING "undefined", so the override leaked
27
- // out of the harness and every later `addHub` in the same process wrote a
28
- // file literally named `undefined` into the repo root. `delete` is the
29
- // only way to actually unset it.
30
- if (prior === undefined) delete process.env.HUBS_CONFIG_PATH;
31
- else process.env.HUBS_CONFIG_PATH = prior;
32
- rmSync(dir, { recursive: true, force: true });
33
- }
34
- }
35
-
36
- test('hubsConfigPath honors HUBS_CONFIG_PATH override', () => {
37
- withTmpConfig((path) => {
38
- assert.equal(hubsConfigPath(), path);
39
- });
40
- });
41
-
42
- test('loadHubsConfig returns empty when file missing', () => {
43
- withTmpConfig(() => {
44
- assert.deepEqual(loadHubsConfig(), { hubs: {} });
45
- });
46
- });
47
-
48
- test('saveHubsConfig writes file at 0600 with parent dir creation', () => {
49
- withTmpConfig((path) => {
50
- saveHubsConfig({ hubs: { 'https://h.example': { token: 'mau_x', linkedAt: 1 } } });
51
- assert.ok(existsSync(path));
52
- const parsed = JSON.parse(readFileSync(path, 'utf8'));
53
- assert.equal(parsed.hubs['https://h.example'].token, 'mau_x');
54
- });
55
- });
56
-
57
- test('addHub upserts the same URL', () => {
58
- withTmpConfig(() => {
59
- addHub('https://h.example', 'mau_first');
60
- addHub('https://h.example', 'mau_second');
61
- const { hubs } = loadHubsConfig();
62
- assert.equal(Object.keys(hubs).length, 1);
63
- assert.equal(hubs['https://h.example'].token, 'mau_second');
64
- });
65
- });
66
-
67
- test('removeHub returns false when entry absent, true when removed', () => {
68
- withTmpConfig(() => {
69
- assert.equal(removeHub('https://nope.example'), false);
70
- addHub('https://h.example', 'mau_x');
71
- assert.equal(removeHub('https://h.example'), true);
72
- assert.equal(getHub('https://h.example'), null);
73
- });
74
- });
75
-
76
- test('getHub returns the record when present', () => {
77
- withTmpConfig(() => {
78
- addHub('https://h.example', 'mau_x');
79
- const rec = getHub('https://h.example');
80
- assert.ok(rec);
81
- assert.equal(rec.token, 'mau_x');
82
- assert.equal(typeof rec.linkedAt, 'number');
83
- });
84
- });
85
-
86
- test('normalizeUrl lowercases scheme + host, strips trailing slash', () => {
87
- assert.equal(normalizeUrl('HTTPS://Foo.Example.com/'), 'https://foo.example.com');
88
- assert.equal(normalizeUrl('http://localhost:1234'), 'http://localhost:1234');
89
- assert.equal(normalizeUrl('https://foo.example.com/path'), 'https://foo.example.com/path');
90
- });
91
-
92
- test('normalizeUrl throws on bad input', () => {
93
- assert.throws(() => normalizeUrl(''), /url must be a non-empty string/);
94
- assert.throws(() => normalizeUrl('not a url'), /invalid url/);
95
- });
96
-
97
- test('addHub keys URLs case-insensitively (same hub after host normalization)', () => {
98
- withTmpConfig(() => {
99
- addHub('https://HUB.example.com', 'mau_first');
100
- addHub('https://hub.example.com/', 'mau_second');
101
- const { hubs } = loadHubsConfig();
102
- assert.equal(Object.keys(hubs).length, 1);
103
- assert.equal(hubs['https://hub.example.com'].token, 'mau_second');
104
- });
105
- });
106
-
107
- // Cloud Phase 25 C2 — the studio writes `role` into this shared file, and a
108
- // CLI relink used to replace the record wholesale and drop it. Not an access
109
- // hole (the cell refuses the write regardless), but it would silently show a
110
- // viewer the editing UI again, which is exactly what the flag exists to stop.
111
- test('a relink preserves the vouched role, and still clears per-machine attestations', () => {
112
- withTmpConfig(() => {
113
- addHub('https://p.cloud.maude.sh', 'mau_first', { adoptedAt: 111 });
114
- // The studio stamps the role after a workspace sign-in.
115
- const cfg = loadHubsConfig();
116
- cfg.hubs['https://p.cloud.maude.sh'].role = 'viewer';
117
- saveHubsConfig(cfg);
118
-
119
- const after = addHub('https://p.cloud.maude.sh', 'mau_second');
120
- assert.equal(after.token, 'mau_second');
121
- assert.equal(after.role, 'viewer', 'the role survives a relink');
122
- assert.equal(after.adoptedAt, undefined, 'a per-machine attestation does not');
123
- });
124
- });
125
-
126
- // The code-module consent — the finding was that `codeModulesAllowed` was
127
- // declared, read by the receiver, and set by NOTHING. So the gate could never
128
- // open and `code-module` had no transport at all in hub-owned mode: an owner
129
- // could push one through the door and no peer would ever accept it, which is
130
- // the same "delivered nowhere" shape the file plane was built to fix.
131
- //
132
- // Through `withTmpConfig` like every other test here — the config is a real
133
- // file on a real path, so a test that skips the harness reads whatever the
134
- // previous one left behind.
135
-
136
- test('the consent records, and survives a token re-save', () => {
137
- withTmpConfig(() => {
138
- const url = 'https://consent.example.test';
139
- addHub(url, 'tok-1');
140
- assert.equal(getHub(url).codeModulesAllowed, undefined, 'absent means no');
141
-
142
- setHubCodeModules(url, true);
143
- assert.equal(getHub(url).codeModulesAllowed, true);
144
-
145
- // A silent token renewal must not revoke a decision the person made.
146
- addHub(url, 'tok-2');
147
- assert.equal(getHub(url).codeModulesAllowed, true);
148
- assert.equal(getHub(url).token, 'tok-2');
149
- });
150
- });
151
-
152
- test('the consent is false for anything that is not an explicit yes', () => {
153
- withTmpConfig(() => {
154
- const url = 'https://consent-strict.example.test';
155
- addHub(url, 't');
156
- setHubCodeModules(url, 'yes');
157
- assert.equal(getHub(url).codeModulesAllowed, false);
158
- });
159
- });
160
-
161
- test('setting consent on an unlinked hub does nothing', () => {
162
- withTmpConfig(() => {
163
- assert.equal(setHubCodeModules('https://nobody.example.test', true), false);
164
- });
165
- });
@@ -1,111 +0,0 @@
1
- // pkg-root.mjs tests (DDR-166 T0b).
2
- //
3
- // The regression this locks down: a naive single-anchor check
4
- // (`apps/studio/bin/screenshot.sh` alone) false-positives inside the Tauri
5
- // desktop build, because `stage-resources.mjs` stages a full working copy of
6
- // `apps/studio` into `target/debug/apps/studio/` for the sidecar's own
7
- // runtime resolution — that staged copy has no `cli/`, so a compiled `maude`
8
- // binary walking up from `target/debug/maude` matched it and stopped one
9
- // level too early, resolving PKG_ROOT to `target/debug` instead of the real
10
- // repo root. Caught by live testing against the real Tauri build (not a
11
- // synthetic path), not by static review — worth a regression test.
12
-
13
- import assert from 'node:assert/strict';
14
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
15
- import { tmpdir } from 'node:os';
16
- import { join } from 'node:path';
17
- import { test } from 'node:test';
18
-
19
- import { isPkgRoot, resolvePkgRoot, resolveTauriResourcePkgRoot } from './pkg-root.mjs';
20
-
21
- function makeRealRoot(base) {
22
- mkdirSync(join(base, 'apps', 'studio', 'bin'), { recursive: true });
23
- writeFileSync(join(base, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
24
- mkdirSync(join(base, 'cli', 'commands'), { recursive: true });
25
- writeFileSync(join(base, 'cli', 'commands', 'design.mjs'), 'export const run = () => {};\n');
26
- }
27
-
28
- test('isPkgRoot requires BOTH anchors — the staged-resources false-positive is rejected', () => {
29
- const tmp = mkdtempSync(join(tmpdir(), 'maude-pkgroot-'));
30
- try {
31
- // The exact shape of the bug: apps/studio/bin/screenshot.sh present
32
- // (mirrors stage-resources.mjs's staged copy), no cli/ at all.
33
- mkdirSync(join(tmp, 'apps', 'studio', 'bin'), { recursive: true });
34
- writeFileSync(join(tmp, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
35
- assert.equal(isPkgRoot(tmp), false);
36
-
37
- // cli/ alone, no apps/studio — also not a real root.
38
- const tmp2 = mkdtempSync(join(tmpdir(), 'maude-pkgroot-'));
39
- try {
40
- mkdirSync(join(tmp2, 'cli', 'commands'), { recursive: true });
41
- writeFileSync(join(tmp2, 'cli', 'commands', 'design.mjs'), '');
42
- assert.equal(isPkgRoot(tmp2), false);
43
- } finally {
44
- rmSync(tmp2, { recursive: true, force: true });
45
- }
46
-
47
- // Both anchors together — a genuine package root.
48
- makeRealRoot(tmp);
49
- assert.equal(isPkgRoot(tmp), true);
50
- } finally {
51
- rmSync(tmp, { recursive: true, force: true });
52
- }
53
- });
54
-
55
- test('resolveTauriResourcePkgRoot finds the .app sibling Resources tree (RCA G2)', () => {
56
- // Mirror the packaged macOS layout: binary in Contents/MacOS, staged tree in
57
- // the SIBLING Contents/Resources — NOT an ancestor of the binary, which is why
58
- // the plain walk-up misses it and every `maude design <verb>` broke.
59
- const app = mkdtempSync(join(tmpdir(), 'maude-app-'));
60
- try {
61
- const macosDir = join(app, 'Contents', 'MacOS');
62
- const resources = join(app, 'Contents', 'Resources');
63
- mkdirSync(macosDir, { recursive: true });
64
- makeRealRoot(resources); // stages apps/studio/bin/screenshot.sh + cli/commands/design.mjs
65
-
66
- // From the binary's own dir, the sibling probe must find Resources.
67
- assert.equal(resolveTauriResourcePkgRoot(macosDir), resources);
68
-
69
- // Regression guard: Resources WITHOUT cli/ (the shipped-broken v0.45.1 shape)
70
- // must NOT resolve — that's exactly the false-positive isPkgRoot rejects.
71
- const broken = mkdtempSync(join(tmpdir(), 'maude-app-broken-'));
72
- try {
73
- const bMacos = join(broken, 'Contents', 'MacOS');
74
- const bRes = join(broken, 'Contents', 'Resources', 'apps', 'studio', 'bin');
75
- mkdirSync(bMacos, { recursive: true });
76
- mkdirSync(bRes, { recursive: true });
77
- writeFileSync(join(bRes, 'screenshot.sh'), '#!/bin/sh\n'); // no cli/ staged
78
- assert.equal(resolveTauriResourcePkgRoot(bMacos), null);
79
- } finally {
80
- rmSync(broken, { recursive: true, force: true });
81
- }
82
- } finally {
83
- rmSync(app, { recursive: true, force: true });
84
- }
85
- });
86
-
87
- test('resolvePkgRoot honors MAUDE_PKG_ROOT only when it actually satisfies both anchors', () => {
88
- const real = mkdtempSync(join(tmpdir(), 'maude-pkgroot-real-'));
89
- const fake = mkdtempSync(join(tmpdir(), 'maude-pkgroot-fake-'));
90
- const prevOverride = process.env.MAUDE_PKG_ROOT;
91
- try {
92
- makeRealRoot(real);
93
- // Fake: only the staged-resources-shaped anchor, same false-positive shape.
94
- mkdirSync(join(fake, 'apps', 'studio', 'bin'), { recursive: true });
95
- writeFileSync(join(fake, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
96
-
97
- process.env.MAUDE_PKG_ROOT = real;
98
- assert.equal(resolvePkgRoot(), real);
99
-
100
- process.env.MAUDE_PKG_ROOT = fake;
101
- // Falls through past the (rejected) override to whatever the real
102
- // walk-up finds in THIS test process — just assert it's NOT the fake
103
- // dir, since accepting it would be exactly the regression.
104
- assert.notEqual(resolvePkgRoot(), fake);
105
- } finally {
106
- if (prevOverride === undefined) delete process.env.MAUDE_PKG_ROOT;
107
- else process.env.MAUDE_PKG_ROOT = prevOverride;
108
- rmSync(real, { recursive: true, force: true });
109
- rmSync(fake, { recursive: true, force: true });
110
- }
111
- });
@@ -1,57 +0,0 @@
1
- // DDR-061 + DDR-062 regression guard.
2
- //
3
- // DDR-061: a plugin must NEVER invoke a `cli/lib/*.mjs` module by a relative
4
- // path unconditionally: in a marketplace install the plugin is copied alone into
5
- // `cache/<marketplace>/<plugin>/<version>/`, so the sibling `cli/` does not
6
- // exist and the call crashes with MODULE_NOT_FOUND. The reachable contract is
7
- // the on-PATH `maude` binary (a declared plugin dependency).
8
- //
9
- // So any plugin file that runs `node … cli/lib/<x>.mjs` is only allowed when the
10
- // SAME file also offers a `command -v maude` fallback (the sibling-first /
11
- // maude-fallback pattern). This test fails loudly if a new straggler lands.
12
- //
13
- // DDR-062: plugin MARKDOWN must reach the studio bash helpers through
14
- // `maude design <verb>`, never `bash "$CLAUDE_PLUGIN_ROOT/dev-server/bin/<x>.sh"`
15
- // or `bash apps/studio/bin/<x>.sh`. The marketplace never copies the studio app
16
- // beside a plugin, and a flow command's $CLAUDE_PLUGIN_ROOT points at
17
- // plugins/flow (no bin/ at all). Per DDR-095 the helpers live under
18
- // apps/studio/bin (was plugins/design/dev-server/bin). Prose mentions of the
19
- // path are fine; INVOCATIONS (bash/sh/exec/$( prefixed) are banned.
20
-
21
- import assert from 'node:assert/strict';
22
- import { execSync } from 'node:child_process';
23
- import { readFileSync } from 'node:fs';
24
- import { test } from 'node:test';
25
-
26
- test('no plugin runs `node cli/lib/*.mjs` without an on-PATH maude fallback', () => {
27
- const out = execSync(
28
- String.raw`grep -rlE 'node[^\n]*cli/lib/[a-z0-9_-]+\.mjs' plugins/ || true`,
29
- {
30
- encoding: 'utf8',
31
- }
32
- );
33
- const files = out.trim().split('\n').filter(Boolean);
34
- const offenders = files.filter((f) => !/command -v maude/.test(readFileSync(f, 'utf8')));
35
- assert.deepEqual(
36
- offenders,
37
- [],
38
- `These plugin files invoke a relative cli/lib module with no \`command -v maude\` fallback — they will crash in a marketplace install (DDR-061). Route through \`maude <subcommand>\` or guard with a sibling-exists check + maude fallback:\n ${offenders.join('\n ')}`
39
- );
40
- });
41
-
42
- test('no plugin markdown invokes a $CLAUDE_PLUGIN_ROOT/dev-server/bin/*.sh helper (DDR-062)', () => {
43
- // INVOCATION = the bin path preceded by bash / sh / exec, or inside a $(…)
44
- // command substitution. Prose mentions of the path (backtick-wrapped, no verb)
45
- // are exempt — they don't run anything. Matches both the $CLAUDE_PLUGIN_ROOT
46
- // form and the repo-relative `plugins/<x>/dev-server/bin/` form.
47
- const pattern = String.raw`(bash|sh|exec) +"?(\$\{?CLAUDE_PLUGIN_ROOT\}?|plugins/[a-z]+)/dev-server/bin/[A-Za-z0-9_-]+\.sh|\$\("?\$?\{?CLAUDE_PLUGIN_ROOT\}?/dev-server/bin/[A-Za-z0-9_-]+\.sh|(bash|sh|exec) +"?[^"\n]*apps/studio/bin/[A-Za-z0-9_-]+\.sh|\$\("?[^"\n]*apps/studio/bin/[A-Za-z0-9_-]+\.sh`;
48
- const out = execSync(`grep -rnE '${pattern}' plugins --include='*.md' || true`, {
49
- encoding: 'utf8',
50
- });
51
- const hits = out.trim().split('\n').filter(Boolean);
52
- assert.deepEqual(
53
- hits,
54
- [],
55
- `These plugin markdown lines INVOKE a dev-server bin helper directly — they break in marketplace installs (the dev-server is never copied beside a plugin) and in flow commands (whose $CLAUDE_PLUGIN_ROOT has no dev-server/). Route through \`maude design <verb>\` instead (DDR-062):\n ${hits.join('\n ')}`
56
- );
57
- });
@@ -1,71 +0,0 @@
1
- // DDR-006 (superseded) regression guard.
2
- //
3
- // Claude Code now prepends the `<plugin>:` namespace to every plugin
4
- // command/agent/skill itself (fixed upstream in Claude Code 2.1.216 — see
5
- // changelog "Fixed plugin skills with a `name` frontmatter field losing
6
- // their plugin prefix in slash-command autocomplete" — and Claude Code
7
- // 2.1.218 explicitly reserves `:` in agent names for that namespacing).
8
- // Baking the prefix into our own `name:` frontmatter, which DDR-006
9
- // (2026-05-13) required as a workaround for the OLD (opposite) bug, now
10
- // produces a doubled prefix — `/design:design:new`, `flow:flow:a11y-auditor`.
11
- //
12
- // Two invariants this guards:
13
- // 1. `name:` frontmatter in plugins/{design,flow}/{commands,agents,skills}/
14
- // must be the BARE slug — no `design:`/`flow:` prefix.
15
- // 2. `subagent_type:` references to our OWN plugin agents must carry
16
- // exactly ONE `<plugin>:` prefix (the form the runtime's own namespace
17
- // + our bare `name:` resolves to) — never zero (broken lookup against
18
- // a namespaced registry) and never two (stale pre-fix leftover).
19
-
20
- import assert from 'node:assert/strict';
21
- import { execSync } from 'node:child_process';
22
- import { test } from 'node:test';
23
-
24
- function grep(pattern, extraArgs = '') {
25
- const out = execSync(
26
- `grep -rn ${extraArgs} '${pattern}' plugins/design plugins/flow --include='*.md' || true`,
27
- { encoding: 'utf8' }
28
- );
29
- return out.trim().split('\n').filter(Boolean);
30
- }
31
-
32
- test('no plugin name: frontmatter carries a redundant design:/flow: prefix', () => {
33
- const offenders = grep('^name: \\(design\\|flow\\):');
34
- assert.deepEqual(
35
- offenders,
36
- [],
37
- `These files declare name: with the plugin prefix baked in — Claude Code adds the plugin namespace itself now, so this doubles into e.g. /design:design:new (DDR-006 superseded):\n ${offenders.join('\n ')}`
38
- );
39
- });
40
-
41
- test('no doubled design:design: / flow:flow: namespace anywhere in plugin markdown', () => {
42
- const offenders = grep('design:design:\\|flow:flow:');
43
- assert.deepEqual(
44
- offenders,
45
- [],
46
- `Doubled plugin namespace found — strip one level (DDR-006 superseded):\n ${offenders.join('\n ')}`
47
- );
48
- });
49
-
50
- test('subagent_type references to our own plugin agents carry exactly one <plugin>: prefix', () => {
51
- // Bare `subagent_type: <slug>` where <slug> looks like one of our
52
- // agent-style names (-critic/-agent/-auditor/-hacker/-keeper/-director/
53
- // -analyst suffix) but has no plugin prefix — excludes Claude Code
54
- // built-ins (e.g. code-simplifier, which is not one of our plugin agents)
55
- // and the `"<critic-name>"` template placeholder.
56
- const bareOffenders = grep(
57
- 'subagent_type:.*"\\?[a-z][a-z0-9-]*\\(-critic\\|-agent\\|-auditor\\|-hacker\\|-keeper\\|-director\\|-analyst\\)"\\?'
58
- ).filter((line) => !/design:|flow:|<critic-name>|code-simplifier/.test(line));
59
- assert.deepEqual(
60
- bareOffenders,
61
- [],
62
- `These subagent_type references to a plugin-owned agent are missing the <plugin>: prefix and will fail to resolve against the namespaced registry:\n ${bareOffenders.join('\n ')}`
63
- );
64
-
65
- const doubledOffenders = grep('subagent_type:.*\\(design:design:\\|flow:flow:\\)');
66
- assert.deepEqual(
67
- doubledOffenders,
68
- [],
69
- `These subagent_type references are double-prefixed (DDR-006 superseded):\n ${doubledOffenders.join('\n ')}`
70
- );
71
- });
@@ -1,194 +0,0 @@
1
- // DDR-174 regression guard (T15).
2
- //
3
- // The whole security architecture of `/design:import --reconstruct` rests on
4
- // ONE fact: every agent turn that ever reads the untrusted source image —
5
- // `reconstruct-agent` (authoring) AND `reconstruct-critic` (the reality-check
6
- // comparator) — has `tools: Read, Write, Glob, Grep` and NEVER `Bash`,
7
- // `WebSearch`, or `WebFetch`. DDR-174's own Consequences section calls for
8
- // exactly this test: "a targeted grep-based test mirroring
9
- // plugin-cli-reachability.test.mjs's pattern should assert BOTH the authoring
10
- // agent's AND the comparator agent's frontmatter never gain
11
- // Bash/WebSearch/WebFetch, not just this DDR's prose." A future maintainer
12
- // "helpfully" widening either agent's toolset (e.g. "just give it Bash so it
13
- // can screenshot itself") would silently reopen DDR-174's entire closure —
14
- // this fails loudly instead.
15
-
16
- import assert from 'node:assert/strict';
17
- import { readFileSync } from 'node:fs';
18
- import { test } from 'node:test';
19
-
20
- const AGENTS = [
21
- 'plugins/design/agents/reconstruct-agent.md',
22
- 'plugins/design/agents/reconstruct-critic.md',
23
- ];
24
-
25
- const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
26
-
27
- function readFrontmatter(path) {
28
- const text = readFileSync(path, 'utf8');
29
- const fm = FRONTMATTER_RE.exec(text);
30
- assert.ok(fm, `${path}: no frontmatter block found`);
31
- return fm[1];
32
- }
33
-
34
- function readToolsLine(path) {
35
- const fm = readFrontmatter(path);
36
- const toolsLine = fm.split('\n').find((l) => l.startsWith('tools:'));
37
- assert.ok(toolsLine, `${path}: frontmatter has no tools: line`);
38
- return toolsLine;
39
- }
40
-
41
- for (const path of AGENTS) {
42
- test(`${path}: tools: line never grants Bash`, () => {
43
- const line = readToolsLine(path);
44
- assert.ok(
45
- !/\bBash\b/.test(line),
46
- `${path} declares Bash — this reopens DDR-174's core closure (the agent reads an untrusted image and must never hold a shell). Line: ${line}`
47
- );
48
- });
49
-
50
- test(`${path}: tools: line never grants WebSearch or WebFetch`, () => {
51
- const line = readToolsLine(path);
52
- assert.ok(
53
- !/\bWebSearch\b/.test(line) && !/\bWebFetch\b/.test(line),
54
- `${path} declares WebSearch/WebFetch — DDR-174 requires these agents have no tool call that reaches the network. Line: ${line}`
55
- );
56
- });
57
-
58
- test(`${path}: tools: line is exactly Read, Write, Glob, Grep`, () => {
59
- const line = readToolsLine(path);
60
- const tools = line
61
- .replace(/^tools:\s*/, '')
62
- .split(',')
63
- .map((t) => t.trim())
64
- .filter(Boolean);
65
- assert.deepEqual(
66
- [...tools].sort(),
67
- ['Glob', 'Grep', 'Read', 'Write'],
68
- `${path}: expected exactly Read/Write/Glob/Grep per DDR-174 Decision 1, got: ${line}`
69
- );
70
- });
71
-
72
- // DDR-174 Addendum (post-implementation adversarial review) — Write has no
73
- // path restriction (Claude Code has no per-subagent path-scoping mechanism,
74
- // verified authoritatively, not assumed) and the only real closure for a
75
- // non-bypassPermissions session is a human approval prompt on any write.
76
- // `permissionMode: default` is what makes that prompt happen instead of
77
- // silently inheriting the parent session's (possibly bypassPermissions)
78
- // mode. A future maintainer removing this line silently re-widens the
79
- // agent's effective write reach for every downstream consumer NOT running
80
- // bypassPermissions.
81
- test(`${path}: frontmatter declares permissionMode: default (DDR-174 Addendum)`, () => {
82
- const fm = readFrontmatter(path);
83
- const line = fm.split('\n').find((l) => l.startsWith('permissionMode:'));
84
- assert.ok(
85
- line,
86
- `${path}: missing permissionMode: default — without it this agent silently inherits the parent session's permission mode (e.g. bypassPermissions), losing the one real per-write approval gate available for its unrestricted Write tool (DDR-174 Addendum)`
87
- );
88
- assert.equal(
89
- line.replace(/^permissionMode:\s*/, '').trim(),
90
- 'default',
91
- `${path}: permissionMode must be exactly "default" (prompts on every write), not a looser mode. Line: ${line}`
92
- );
93
- });
94
- }
95
-
96
- test('import.md diff-check is whole-repo scoped, not just $DESIGN_ROOT (DDR-174 Addendum)', () => {
97
- // The first implementation scoped `git status --porcelain -- "$DESIGN_ROOT"`,
98
- // which made a write to .claude/settings.json, CLAUDE.md, or plugins/**
99
- // structurally invisible to the check — an adversarial review built a full
100
- // exploit chain out of exactly that gap. Assert the pathspec was actually
101
- // widened, not just documented as widened in prose.
102
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
103
- assert.ok(
104
- !/git -C "\$REPO" status --porcelain -- "\$DESIGN_ROOT"/.test(importMd),
105
- 'import.md must NOT scope the diff-check to $DESIGN_ROOT only — this was the exact gap the DDR-174 Addendum closes (a write outside $DESIGN_ROOT, e.g. to .claude/settings.json, would be invisible to a $DESIGN_ROOT-scoped check)'
106
- );
107
- const wholeRepoOccurrences = (importMd.match(/git -C "\$REPO" status --porcelain\b/g) || [])
108
- .length;
109
- assert.ok(
110
- wholeRepoOccurrences >= 2,
111
- `import.md must run an UNSCOPED \`git -C "$REPO" status --porcelain\` for both the BEFORE (step 4) and AFTER (step 5b) snapshots — found ${wholeRepoOccurrences} occurrence(s)`
112
- );
113
- });
114
-
115
- test('import.md snapshots the two well-known global Claude Code config paths (DDR-174 Addendum)', () => {
116
- // A repo-scoped git diff can never see $HOME/.claude/** — these are the two
117
- // specific files an adversarial review named as attack targets (a planted
118
- // hook, or a poisoned global CLAUDE.md loaded into every future session).
119
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
120
- assert.ok(
121
- importMd.includes('$HOME/.claude/settings.json') &&
122
- importMd.includes('$HOME/.claude/CLAUDE.md'),
123
- 'import.md must snapshot $HOME/.claude/settings.json and $HOME/.claude/CLAUDE.md before/after each round and hard-fail on any change (DDR-174 Addendum) — these are outside any repo-scoped diff check'
124
- );
125
- });
126
-
127
- test('import.md stat calls are portable (GNU-first, BSD-fallback), not BSD-only (DDR-174 Addendum confirmation pass)', () => {
128
- // The first Addendum revision used BSD-only `stat -f` unconditionally — it
129
- // silently no-ops on Linux (a platform this project ships a .deb for),
130
- // because GNU `stat -f` means something else entirely and errors out,
131
- // swallowed by the trailing `2>/dev/null`. Both empty strings compare
132
- // equal, so the check trivially "passes" without ever having checked
133
- // anything. Assert every stat call tries GNU syntax (`stat -c`) first.
134
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
135
- // Only scan actual shell inside fenced ```bash blocks — prose elsewhere
136
- // legitimately mentions `stat -f` by name when explaining the old bug.
137
- const codeBlocks = [...importMd.matchAll(/```bash\n([\s\S]*?)```/g)].map((m) => m[1]).join('\n');
138
- const bareStatF = codeBlocks.match(/(?<!\|\| )\bstat -f\b/g) || [];
139
- assert.deepEqual(
140
- bareStatF,
141
- [],
142
- `import.md has a \`stat -f\` call in executable shell with no \`stat -c\` GNU fallback tried first — this silently no-ops on Linux (DDR-174 Addendum confirmation-pass finding). Found ${bareStatF.length} bare occurrence(s).`
143
- );
144
- const statCOccurrences = (codeBlocks.match(/stat -c '/g) || []).length;
145
- assert.ok(
146
- statCOccurrences >= 4,
147
- `expected at least 4 GNU-first \`stat -c\` attempts (2 for the non-git repo-wide fallback, 2 for the global-config snapshot) — found ${statCOccurrences}`
148
- );
149
- });
150
-
151
- test('import.md non-git fallback excludes _history/ (DDR-174 Addendum confirmation pass)', () => {
152
- // The reconstruct loop writes its own screenshots/verdict files under
153
- // _history/_reconstruct/<slug>/ every round. A git-repo target gets this
154
- // excluded for free via .gitignore; the non-git `find`-based fallback has
155
- // no such filter and would false-positive-abort on its own round-1 output
156
- // the moment round 2's diff check runs, in a non-git target repo.
157
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
158
- const findOccurrences = importMd.match(/find "\$REPO" -type f[^\n]*/g) || [];
159
- assert.ok(
160
- findOccurrences.length >= 2,
161
- 'expected the non-git fallback find command in both step 4 and step 5b'
162
- );
163
- for (const line of findOccurrences) {
164
- assert.ok(
165
- line.includes("-not -path '*/_history/*'"),
166
- `non-git fallback find command must exclude _history/ (its own round-N artifacts) or every multi-round run in a non-git target repo false-positive-aborts: ${line}`
167
- );
168
- }
169
- });
170
-
171
- test('import.md uses mktemp for the _active.json patch, not a fixed /tmp filename (DDR-174 Addendum)', () => {
172
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
173
- assert.ok(
174
- !/\/tmp\/active\.json\.tmp/.test(importMd),
175
- 'import.md must not use a fixed, predictable /tmp filename for the _active.json patch — a symlink race target on a shared machine (DDR-174 Addendum adversarial finding)'
176
- );
177
- assert.ok(/mktemp/.test(importMd), 'import.md must use mktemp for its temp file(s)');
178
- });
179
-
180
- test('design-critic.md is never repurposed as the reconstruct comparator (DDR-174 Decision 1 Round-2)', () => {
181
- // The comparator must be reconstruct-critic (Bash-free), never the default
182
- // Bash-capable design-critic — assert import.md's orchestrator spawns the
183
- // dedicated agent, not design-critic, for the reality-check step.
184
- const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
185
- const reconstructSection = importMd.slice(importMd.indexOf('## `--reconstruct'));
186
- assert.ok(
187
- reconstructSection.includes('design:reconstruct-critic'),
188
- 'import.md --reconstruct mode must spawn design:reconstruct-critic for the reality-check step'
189
- );
190
- assert.ok(
191
- !/subagent_type:\s*"design:design-critic"/.test(reconstructSection),
192
- 'import.md --reconstruct mode must NOT spawn the default design-critic as its comparator (DDR-174 Decision 1 Round-2) — it is Bash-capable and reopens the trifecta this DDR closes'
193
- );
194
- });