@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,205 +0,0 @@
1
- // Silent hub-credential renewal (cloud/renew.ts) — the lane that keeps a
2
- // cloud link alive past the 12 h cell-session cap without a person pressing
3
- // Connect again. Every network hop is injected; nothing here talks to a real
4
- // host.
5
-
6
- import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
7
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
8
- import { tmpdir } from 'node:os';
9
- import { join } from 'node:path';
10
-
11
- import { renewHubCredential } from '../cloud/renew.ts';
12
-
13
- const HUB_URL = 'https://alligators.cloud.test';
14
-
15
- let dir: string;
16
- let envBackup: Record<string, string | undefined>;
17
-
18
- beforeEach(() => {
19
- dir = mkdtempSync(join(tmpdir(), 'maude-renew-'));
20
- envBackup = {
21
- MAUDE_CLOUD_CONFIG: process.env.MAUDE_CLOUD_CONFIG,
22
- HUBS_CONFIG_PATH: process.env.HUBS_CONFIG_PATH,
23
- MAUDE_CLOUD_URL: process.env.MAUDE_CLOUD_URL,
24
- };
25
- process.env.MAUDE_CLOUD_CONFIG = join(dir, 'cloud.json');
26
- process.env.HUBS_CONFIG_PATH = join(dir, 'hubs.json');
27
- process.env.MAUDE_CLOUD_URL = 'https://cloud.test';
28
- });
29
-
30
- afterEach(() => {
31
- for (const [k, v] of Object.entries(envBackup)) {
32
- if (v === undefined) delete process.env[k];
33
- else process.env[k] = v;
34
- }
35
- rmSync(dir, { recursive: true, force: true });
36
- });
37
-
38
- function signIn(token = 'mpt_account'): void {
39
- writeFileSync(
40
- join(dir, 'cloud.json'),
41
- JSON.stringify({ url: 'https://cloud.test', token, connectedAt: 1 })
42
- );
43
- }
44
-
45
- function writeHubRecord(record: Record<string, unknown>): void {
46
- writeFileSync(join(dir, 'hubs.json'), JSON.stringify({ hubs: { [HUB_URL]: record } }));
47
- }
48
-
49
- function readHubRecord(): Record<string, unknown> | undefined {
50
- try {
51
- return JSON.parse(readFileSync(join(dir, 'hubs.json'), 'utf8')).hubs[HUB_URL];
52
- } catch {
53
- return undefined;
54
- }
55
- }
56
-
57
- /** Route-keyed fetch stub; records every URL it was asked for. */
58
- function fakeFetch(routes: Record<string, { status: number; body: unknown }>) {
59
- const calls: string[] = [];
60
- const doFetch = (async (input: string | URL | Request) => {
61
- const url = String(input);
62
- calls.push(url);
63
- for (const [prefix, r] of Object.entries(routes)) {
64
- if (url.startsWith(prefix)) {
65
- return new Response(JSON.stringify(r.body), { status: r.status });
66
- }
67
- }
68
- return new Response('{}', { status: 404 });
69
- }) as typeof fetch;
70
- return { doFetch, calls };
71
- }
72
-
73
- const HAPPY_ROUTES = {
74
- 'https://cloud.test/api/projects': {
75
- status: 200,
76
- body: { projects: [{ id: 'alligators', url: HUB_URL, role: 'owner' }] },
77
- },
78
- 'https://cloud.test/projects/open': {
79
- status: 200,
80
- body: { token: 'proj_tok', url: HUB_URL, role: 'owner', expiresAt: 111 },
81
- },
82
- [`${HUB_URL}/auth/login`]: {
83
- status: 200,
84
- body: { token: 'mau_new', expiresAt: 12345, user: { email: 'm@x.cz', role: 'member' } },
85
- },
86
- };
87
-
88
- describe('renewHubCredential', () => {
89
- test('signed out → not-signed-in, and no network is touched', async () => {
90
- const { doFetch, calls } = fakeFetch(HAPPY_ROUTES);
91
- const r = await renewHubCredential(HUB_URL, doFetch);
92
- expect(r).toEqual({ ok: false, reason: 'not-signed-in' });
93
- expect(calls).toHaveLength(0);
94
- });
95
-
96
- test('happy path: projects → open → cell login → hubs.json updated, role preserved', async () => {
97
- signIn();
98
- writeHubRecord({ token: 'mau_stale', linkedAt: 1, role: 'member', expiresAt: 2 });
99
- const { doFetch, calls } = fakeFetch(HAPPY_ROUTES);
100
-
101
- const r = await renewHubCredential(HUB_URL, doFetch);
102
- expect(r).toEqual({ ok: true, token: 'mau_new', expiresAt: 12345 });
103
-
104
- const stored = readHubRecord();
105
- expect(stored?.token).toBe('mau_new');
106
- expect(stored?.expiresAt).toBe(12345);
107
- // The upsert replaces the record — the vouched role must survive renewal.
108
- expect(stored?.role).toBe('member');
109
-
110
- // The cell login went to the STORED hub address, not anything the cloud named.
111
- expect(calls[2]).toBe(`${HUB_URL}/auth/login`);
112
- });
113
-
114
- test('F5: the FRESH role from the cell login wins over the stale stored one', async () => {
115
- signIn();
116
- writeHubRecord({ token: 'mau_stale', linkedAt: 1, role: 'member' });
117
- const { doFetch } = fakeFetch({
118
- ...HAPPY_ROUTES,
119
- [`${HUB_URL}/auth/login`]: {
120
- status: 200,
121
- body: { token: 'mau_new', expiresAt: 12345, user: { email: 'm@x.cz', role: 'owner' } },
122
- },
123
- });
124
- const r = await renewHubCredential(HUB_URL, doFetch);
125
- expect(r.ok).toBe(true);
126
- expect(readHubRecord()?.role).toBe('owner'); // not the stale 'member'
127
- });
128
-
129
- test('F5: an older cell that omits the role falls back to the stored one', async () => {
130
- signIn();
131
- writeHubRecord({ token: 'mau_stale', linkedAt: 1, role: 'member' });
132
- const { doFetch } = fakeFetch({
133
- ...HAPPY_ROUTES,
134
- [`${HUB_URL}/auth/login`]: { status: 200, body: { token: 'mau_new', expiresAt: 12345 } },
135
- });
136
- await renewHubCredential(HUB_URL, doFetch);
137
- expect(readHubRecord()?.role).toBe('member');
138
- });
139
-
140
- test('claim-a: an embedded-credential hubUrl is refused, no network touched', async () => {
141
- signIn();
142
- const { doFetch, calls } = fakeFetch(HAPPY_ROUTES);
143
- const r = await renewHubCredential('https://evil@alligators.cloud.test', doFetch);
144
- expect(r).toEqual({ ok: false, reason: 'no-matching-project' });
145
- expect(calls).toHaveLength(0);
146
- });
147
-
148
- test('account token revoked (401 on projects) → account-revoked, store untouched', async () => {
149
- signIn();
150
- writeHubRecord({ token: 'mau_stale', linkedAt: 1 });
151
- const { doFetch } = fakeFetch({
152
- 'https://cloud.test/api/projects': { status: 401, body: {} },
153
- });
154
- const r = await renewHubCredential(HUB_URL, doFetch);
155
- expect(r).toEqual({ ok: false, reason: 'account-revoked' });
156
- expect(readHubRecord()?.token).toBe('mau_stale');
157
- });
158
-
159
- test('hub not among the account projects → no-matching-project', async () => {
160
- signIn();
161
- const { doFetch } = fakeFetch({
162
- 'https://cloud.test/api/projects': {
163
- status: 200,
164
- body: { projects: [{ id: 'other', url: 'https://other.cloud.test', role: 'owner' }] },
165
- },
166
- });
167
- const r = await renewHubCredential(HUB_URL, doFetch);
168
- expect(r).toEqual({ ok: false, reason: 'no-matching-project' });
169
- });
170
-
171
- test('a viewer role never renews an editor credential', async () => {
172
- signIn();
173
- const { doFetch } = fakeFetch({
174
- 'https://cloud.test/api/projects': {
175
- status: 200,
176
- body: { projects: [{ id: 'alligators', url: HUB_URL, role: 'viewer' }] },
177
- },
178
- });
179
- const r = await renewHubCredential(HUB_URL, doFetch);
180
- expect(r).toEqual({ ok: false, reason: 'no-matching-project' });
181
- });
182
-
183
- test('removed member: /projects/open refuses → open-refused (the right place to die)', async () => {
184
- signIn();
185
- const { doFetch } = fakeFetch({
186
- 'https://cloud.test/api/projects': HAPPY_ROUTES['https://cloud.test/api/projects'],
187
- 'https://cloud.test/projects/open': { status: 404, body: {} },
188
- });
189
- const r = await renewHubCredential(HUB_URL, doFetch);
190
- expect(r).toEqual({ ok: false, reason: 'open-refused' });
191
- });
192
-
193
- test('cell refuses the exchange → cell-refused, store untouched', async () => {
194
- signIn();
195
- writeHubRecord({ token: 'mau_stale', linkedAt: 1 });
196
- const { doFetch } = fakeFetch({
197
- 'https://cloud.test/api/projects': HAPPY_ROUTES['https://cloud.test/api/projects'],
198
- 'https://cloud.test/projects/open': HAPPY_ROUTES['https://cloud.test/projects/open'],
199
- [`${HUB_URL}/auth/login`]: { status: 401, body: {} },
200
- });
201
- const r = await renewHubCredential(HUB_URL, doFetch);
202
- expect(r).toEqual({ ok: false, reason: 'cell-refused' });
203
- expect(readHubRecord()?.token).toBe('mau_stale');
204
- });
205
- });
@@ -1,161 +0,0 @@
1
- // Cloud Phase 27 A3/A4 + C2/C4 (DDR-209) — the studio in a cell.
2
- //
3
- // The behaviour under test is the one that makes a cell multi-tenant-safe: in
4
- // workspace mode this process serves an owner and a viewer at the SAME TIME, so
5
- // "what may this request do" cannot come from a file on disk. It comes from the
6
- // proxy in front, per request, and in the absence of proof it is `viewer`.
7
- //
8
- // The local gate this replaces fails OPEN by design — `isHubReadOnly()` returns
9
- // false from its `catch`, and `projectReadOnly()` returns false when `linkedHub`
10
- // is unset. That is correct for a tool on your own laptop and is the whole
11
- // ballgame on the internet, which is why the no-header case below is the most
12
- // important assertion in the file.
13
-
14
- import { afterAll, describe, expect, test } from 'bun:test';
15
- import type { Subprocess } from 'bun';
16
-
17
- import { bootServer, killProc, makeSandbox, nextPort } from './_helpers.ts';
18
-
19
- const procs: Subprocess[] = [];
20
- afterAll(async () => {
21
- for (const p of procs) await killProc(p);
22
- });
23
-
24
- async function bootCell() {
25
- const { root } = makeSandbox();
26
- const port = nextPort();
27
- const proc = await bootServer(root, port, {
28
- MAUDE_WORKSPACE_MODE: '1',
29
- // A dev checkout resolves Playwright (the E2E harness), which is a
30
- // legitimate devDependency here and would otherwise fail the module half of
31
- // the containment assert before workspace mode could be tested at all.
32
- MAUDE_WORKSPACE_ALLOW_DEV_MODULES: '1',
33
- HUB_DASHBOARD_URL: 'https://cloud.maude.sh',
34
- MAUDE_PROJECT_NAME: 'Alligators',
35
- });
36
- procs.push(proc);
37
- return { base: `http://localhost:${port}` };
38
- }
39
-
40
- describe('a cell resolves the role per request, and defaults to read-only', () => {
41
- test('no injected role at all ⇒ read-only, and writes are refused', async () => {
42
- const { base } = await bootCell();
43
-
44
- const cfg = (await (await fetch(`${base}/_config`)).json()) as { readOnly?: boolean };
45
- expect(cfg.readOnly).toBe(true);
46
-
47
- const res = await fetch(`${base}/_api/edit-text`, {
48
- method: 'POST',
49
- headers: { 'content-type': 'application/json' },
50
- body: JSON.stringify({ file: 'ui/Sample.tsx', id: 'x', text: 'y' }),
51
- });
52
- expect(res.status).toBe(403);
53
- expect(((await res.json()) as { reason?: string }).reason).toBe('read-only');
54
- });
55
-
56
- test('a vouched editing role opens the same write', async () => {
57
- const { base } = await bootCell();
58
-
59
- const cfg = (await (
60
- await fetch(`${base}/_config`, { headers: { 'x-maude-readonly': '0' } })
61
- ).json()) as { readOnly?: boolean };
62
- expect(cfg.readOnly).toBe(false);
63
-
64
- const res = await fetch(`${base}/_api/edit-text`, {
65
- method: 'POST',
66
- headers: { 'content-type': 'application/json', 'x-maude-readonly': '0' },
67
- body: JSON.stringify({ file: 'ui/Sample.tsx', id: 'x', text: 'y' }),
68
- });
69
- // Whatever the handler makes of the payload, the GATE let it through — the
70
- // read-only refusal is the specific thing that must not happen.
71
- expect(res.status).not.toBe(403);
72
- });
73
-
74
- test('anything other than a positive `0` is read-only', async () => {
75
- // The failure mode this rules out: a truthy-string check, where
76
- // `x-maude-readonly: false` (a plausible thing for a future caller to send)
77
- // reads as "not read-only".
78
- const { base } = await bootCell();
79
- for (const value of ['1', 'false', 'no', '', 'true', 'owner']) {
80
- const cfg = (await (
81
- await fetch(`${base}/_config`, { headers: { 'x-maude-readonly': value } })
82
- ).json()) as { readOnly?: boolean };
83
- expect(cfg.readOnly).toBe(true);
84
- }
85
- });
86
-
87
- test('two requests to ONE process get two different answers', async () => {
88
- // The actual multi-tenancy property, stated as a test: this is what a
89
- // per-PROCESS config file cannot do, and it is why A3 exists.
90
- const { base } = await bootCell();
91
- const [viewer, member] = await Promise.all([
92
- fetch(`${base}/_config`, { headers: { 'x-maude-readonly': '1' } }).then((r) => r.json()),
93
- fetch(`${base}/_config`, { headers: { 'x-maude-readonly': '0' } }).then((r) => r.json()),
94
- ]);
95
- expect((viewer as { readOnly: boolean }).readOnly).toBe(true);
96
- expect((member as { readOnly: boolean }).readOnly).toBe(false);
97
- });
98
- });
99
-
100
- describe('the cloud shell states what it is', () => {
101
- test('/_config carries the cloud block C2 and C4 render from', async () => {
102
- const { base } = await bootCell();
103
- const cfg = (await (await fetch(`${base}/_config`)).json()) as {
104
- cloud?: { dashboardUrl?: string; projectName?: string };
105
- };
106
- expect(cfg.cloud).toBeTruthy();
107
- expect(cfg.cloud?.dashboardUrl).toBe('https://cloud.maude.sh');
108
- expect(cfg.cloud?.projectName).toBe('Alligators');
109
- });
110
-
111
- // The shape every test above this line assumed away. A self-hosted
112
- // `maude hub workspace` sets MAUDE_WORKSPACE_MODE but never
113
- // HUB_DASHBOARD_URL (only cli/lib/cell-plan.mjs writes that), and the
114
- // studio used to default it to the vendor's SaaS — so the ONE way out a
115
- // browser tab offers walked a self-hoster off their own deployment onto
116
- // cloud.maude.sh. Every cloud-block test booted WITH the variable set, so
117
- // the whole suite was blind to the deployment the bug applies to.
118
- test('a self-hosted hub gets the cloud block WITHOUT a dashboard link', async () => {
119
- const { root } = makeSandbox();
120
- const port = nextPort();
121
- const proc = await bootServer(root, port, {
122
- MAUDE_WORKSPACE_MODE: '1',
123
- MAUDE_WORKSPACE_ALLOW_DEV_MODULES: '1',
124
- MAUDE_PROJECT_NAME: 'Alligators',
125
- // deliberately NO HUB_DASHBOARD_URL — this is what self-hosted looks like
126
- });
127
- procs.push(proc);
128
- const cfg = (await (await fetch(`http://localhost:${port}/_config`)).json()) as {
129
- cloud?: { dashboardUrl?: string; projectName?: string };
130
- };
131
- // The block still exists: "you are in a browser tab on somebody else's
132
- // machine" is just as true self-hosted, and C2's stated agent absence,
133
- // the account chip and the sign-out all hang off it.
134
- expect(cfg.cloud).toBeTruthy();
135
- expect(cfg.cloud?.projectName).toBe('Alligators');
136
- // Only the platform-specific field is gone — absent, so the client's
137
- // truthiness check is the single gate.
138
- expect(cfg.cloud?.dashboardUrl).toBeUndefined();
139
- });
140
-
141
- test('the canvas capability is echoed only when the proxy minted one', async () => {
142
- const { base } = await bootCell();
143
- const without = (await (await fetch(`${base}/_config`)).json()) as { canvasToken?: string };
144
- expect(without.canvasToken).toBeUndefined();
145
-
146
- const with_ = (await (
147
- await fetch(`${base}/_config`, { headers: { 'x-maude-canvas-token': 'cap-123' } })
148
- ).json()) as { canvasToken?: string };
149
- expect(with_.canvasToken).toBe('cap-123');
150
- });
151
-
152
- test('a cell SERVES the canvas surfaces it used to 404 (DDR-209 A′1)', async () => {
153
- const { base } = await bootCell();
154
- // The shell is a static harness; the browser is what evaluates it. Before
155
- // DDR-209 this was a hard 404 in workspace mode, which is precisely why
156
- // Phase 25 had to hand-roll a second studio.
157
- const shell = await fetch(`${base}/_canvas-shell.html`);
158
- expect(shell.status).toBe(200);
159
- expect(shell.headers.get('content-type')).toContain('text/html');
160
- });
161
- });
@@ -1,170 +0,0 @@
1
- // Surfaces a cloud tab must not offer — Cloud Phase 27, found by using it.
2
- //
3
- // The phase's rule is C1's: role shapes what is OFFERED, never what is VISIBLE.
4
- // That rule is about ROLES. A different question turned up the moment the real
5
- // studio actually ran in a browser: what about a control whose feature cannot
6
- // exist in THIS SHELL at all?
7
- //
8
- // Three answers, and the difference between them is the whole point:
9
- //
10
- // the agent chat ABSENT, WITH A NOTICE. It runs on your own Claude
11
- // subscription on your own machine (DDR-123). The
12
- // feature exists and you can have it — the menu row
13
- // stays, disabled, saying where. (C2)
14
- //
15
- // "Sign in to Maude ABSENT, SILENTLY. It offers to do the thing you have
16
- // Cloud" already done: you reached this tab THROUGH a Maude
17
- // account. There is nothing to explain.
18
- //
19
- // AI generation / ABSENT, SILENTLY. These configure ffmpeg, mlx-vlm, a
20
- // Subtitles / Video HuggingFace cache and your own provider keys — none
21
- // of which a browser tab has, and whose routes a cell
22
- // refuses by design (DDR-209 D1). Left in, they render
23
- // as a wall of `HTTP 404`, which is what the owner saw.
24
- //
25
- // Source-level assertions, because the menubar's dropdowns do not open under a
26
- // synthetic click and a test that cannot fail is worse than no test. What these
27
- // pin is exactly what would regress: someone re-introducing `TABS.map` or
28
- // dropping the gate on `<CloudBar />`.
29
-
30
- import { describe, expect, test } from 'bun:test';
31
- import { readFileSync } from 'node:fs';
32
- import { join } from 'node:path';
33
-
34
- const STUDIO = join(import.meta.dir, '..');
35
- const APP = readFileSync(join(STUDIO, 'client', 'app.jsx'), 'utf8');
36
- const SETTINGS = readFileSync(join(STUDIO, 'client', 'panels', 'SettingsPanel.jsx'), 'utf8');
37
-
38
- describe('the cloud shell offers nothing it cannot honour', () => {
39
- test('the local-machine settings tabs are flagged — and the list is exact', () => {
40
- // An exact list, not a `toContain`: the failure this guards is a tab that
41
- // configures machine-local state shipping to the cloud shell UNFLAGGED,
42
- // where its routes are refused by design (DDR-209 D1) and it renders as a
43
- // wall of 404s. A new tab has to be classified deliberately, which means
44
- // this assertion is SUPPOSED to fail when one is added.
45
- //
46
- // `figma` (DDR-216) is local-machine for the same reason `ai-generation`
47
- // is: the credential lives in `~/.config/maude/keys.json` on this machine,
48
- // and the import writes into this machine's design root.
49
- const flagged = [
50
- ...SETTINGS.matchAll(/\{ id: '([a-z-]+)', label: '[^']+', local: true \}/g),
51
- ].map((m) => m[1]);
52
- expect(flagged.sort()).toEqual(['ai-generation', 'figma', 'subtitles', 'video']);
53
- });
54
-
55
- test('the tab rail renders the FILTERED list, not the raw table', () => {
56
- // `TABS.map` is what shipped the wall of 404s.
57
- expect(SETTINGS).toContain('{tabs.map((t) => (');
58
- expect(SETTINGS).not.toContain('{TABS.map(');
59
- // …and every keyboard path must walk the same list, or End/Home select a
60
- // tab that is not on screen.
61
- expect(SETTINGS).not.toMatch(/setTab\(TABS\[/);
62
- expect(SETTINGS).toContain('const tabs = useMemo(');
63
- });
64
-
65
- test('a remembered tab this shell does not have cannot select nothing', () => {
66
- // Open Video on the desktop, then open Settings in the cloud.
67
- const init =
68
- /const \[tab, setTab\] = useState\(\(\) => \{[\s\S]*?\}\);/.exec(SETTINGS)?.[0] ?? '';
69
- expect(init).toContain('!(cloud && t.local)');
70
- });
71
-
72
- test('the cloud sign-in is not offered inside the cloud', () => {
73
- // `=== null`, not falsiness. `cloud` is undefined until `/_config` answers,
74
- // and treating unknown as "not cloud" mounted this bar for one frame in
75
- // every cloud tab — long enough to fire the one request the cell refuses.
76
- // Matched on the GUARD rather than the whole element, so adding a prop to
77
- // CloudBar (DDR-214 drilled the live sync payload in) does not read as a
78
- // regression in a rule that is entirely about `=== null`.
79
- expect(APP).toMatch(/\{cloud === null \? <CloudBar[^>]*\/> : null\}/);
80
- expect(APP).not.toMatch(/\{cloud \? null : <CloudBar/);
81
- });
82
-
83
- test('the local export queue does not hydrate before the shell is known', () => {
84
- expect(APP).toContain('useExportCenter({ enabled: cfg.cloud === null })');
85
- });
86
-
87
- test('every component that gates on the shell is actually GIVEN the flag', () => {
88
- // The bug this exists for: three `cfg?.cloud` reads inside a component that
89
- // never receives `cfg` — a ReferenceError at render, and a blank app.
90
- for (const call of ['<Menubar', '<Sidebar', '<SettingsPanel']) {
91
- const at = APP.indexOf(call);
92
- expect(at).toBeGreaterThan(0);
93
- const props = APP.slice(at, at + 900);
94
- // Passed RAW — a `?? null` here would erase the "not known yet" state
95
- // before any component could see it.
96
- expect(props).toContain('cloud={cfg.cloud}');
97
- }
98
- });
99
-
100
- test('no component reaches for `cfg` where only the flag was passed', () => {
101
- // `cfg` is a real variable at the top level, so a stray reference in a
102
- // child component is a ReferenceError the bundler happily emits.
103
- for (const fn of ['function Menubar({', 'function Sidebar({']) {
104
- const start = APP.indexOf(fn);
105
- expect(start).toBeGreaterThan(0);
106
- // Bounded window: the component's own body, not the whole file.
107
- const body = APP.slice(start, APP.indexOf('\nfunction ', start + 10));
108
- expect(body).not.toMatch(/\bcfg\?\./);
109
- expect(body).not.toMatch(/\bcfg\./);
110
- }
111
- });
112
- });
113
-
114
- describe('"not known yet" survives every layer between /_config and the DOM', () => {
115
- // The three-line bug: the call sites were fixed to pass `cfg.cloud` raw, and
116
- // the components still declared `cloud = null` as a default parameter. A
117
- // default fires on `undefined` — so "we have not asked yet" turned back into
118
- // "this is not the cloud" one layer further in, the sign-in bar mounted for a
119
- // frame, and the boot 404 came back looking exactly like the one just fixed.
120
- const APP_SRC = readFileSync(join(STUDIO, 'client', 'app.jsx'), 'utf8');
121
- const SETTINGS_SRC = readFileSync(join(STUDIO, 'client', 'panels', 'SettingsPanel.jsx'), 'utf8');
122
-
123
- test('no component defaults the shell flag', () => {
124
- for (const [label, src] of [
125
- ['app.jsx', APP_SRC],
126
- ['SettingsPanel.jsx', SETTINGS_SRC],
127
- ] as const) {
128
- expect(src, label).not.toMatch(/^\s*cloud = (null|false|\{\}),$/m);
129
- }
130
- });
131
- });
132
-
133
- describe('the way back out exists only where there is somewhere to go', () => {
134
- // A self-hosted `maude hub workspace` is workspace mode too — the whole
135
- // point of "one studio, three shells" — so it gets the `cloud` block, the
136
- // stated agent absence, the account chip and the sign-out. What it does NOT
137
- // have is a dashboard: one hub serves one project, and `HUB_DASHBOARD_URL`
138
- // is written only by the managed fleet (cli/lib/cell-plan.mjs).
139
- //
140
- // Both sides had defaulted that URL to the vendor's SaaS, so the ONE way out
141
- // a browser tab offers walked every self-hoster off their own deployment
142
- // onto cloud.maude.sh — a dead end for an account most of them do not have.
143
- // Fixing the server alone would not have fixed the button; the client
144
- // carried its own copy of the same fallback.
145
- test('the client never names the vendor as a fallback destination', () => {
146
- // The literal is the bug. `dashboardUrl` is either configured or absent.
147
- expect(APP).not.toContain("'https://cloud.maude.sh'");
148
- });
149
-
150
- test('the ← Dashboard anchor is gated on the URL, not on the shell', () => {
151
- const at = APP.indexOf('data-testid="cloud-back"');
152
- expect(at).toBeGreaterThan(0);
153
- const block = APP.slice(at, at + 1200);
154
- expect(block).toContain('{cloud.dashboardUrl ? (');
155
- expect(block).toContain('href={cloud.dashboardUrl}');
156
- // The project name is NOT gated with it: a tab must still say which
157
- // project it is showing, dashboard or no dashboard.
158
- expect(block).toContain('data-testid="cloud-project-name"');
159
- });
160
-
161
- test('the server sends the field only when it is configured', () => {
162
- const HTTP = readFileSync(join(STUDIO, 'http.ts'), 'utf8');
163
- // Conditional spread — the same shape `canvasToken` uses two fields down,
164
- // so an absent value is absent rather than a string nobody can act on.
165
- expect(HTTP).toContain(
166
- '...(process.env.HUB_DASHBOARD_URL\n ? { dashboardUrl: process.env.HUB_DASHBOARD_URL }\n : {}),'
167
- );
168
- expect(HTTP).not.toContain("HUB_DASHBOARD_URL ?? 'https://cloud.maude.sh'");
169
- });
170
- });