@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.
- package/README.md +3 -1
- package/apps/studio/acp/bridge.ts +18 -13
- package/apps/studio/acp/index.ts +43 -7
- package/apps/studio/acp/transcript-io.ts +394 -0
- package/apps/studio/acp/transcript.ts +103 -38
- package/apps/studio/annotations-layer.tsx +191 -116
- package/apps/studio/annotations-model.ts +39 -0
- package/apps/studio/annotations-sync.ts +50 -0
- package/apps/studio/api.ts +821 -55
- package/apps/studio/bin/_import-figma.mjs +57 -11
- package/apps/studio/bin/_seed-fixture.mjs +163 -0
- package/apps/studio/bin/annotate.mjs +3 -1
- package/apps/studio/bin/server-up.sh +17 -2
- package/apps/studio/canvas-edit.ts +391 -7
- package/apps/studio/canvas-imports.ts +89 -0
- package/apps/studio/canvas-lib.tsx +82 -18
- package/apps/studio/canvas-notice-message.ts +16 -0
- package/apps/studio/canvas-notifications.tsx +19 -0
- package/apps/studio/canvas-shell.tsx +57 -6
- package/apps/studio/client/app.jsx +943 -248
- package/apps/studio/client/apply-edit-request.ts +55 -0
- package/apps/studio/client/export-center.jsx +125 -67
- package/apps/studio/client/github.js +38 -1
- package/apps/studio/client/index-loader.ts +76 -0
- package/apps/studio/client/panels/CloudBar.jsx +52 -6
- package/apps/studio/client/panels/GitPanel.jsx +103 -0
- package/apps/studio/client/panels/OnboardingWizard.jsx +36 -7
- package/apps/studio/client/panels/RepoBranchSwitcher.jsx +92 -27
- package/apps/studio/client/panels/SourceConflictPanel.jsx +166 -0
- package/apps/studio/client/panels/SyncPanel.jsx +238 -4
- package/apps/studio/client/panels/TeamProjects.jsx +376 -0
- package/apps/studio/client/panels/file-deep-link-dialog.jsx +54 -0
- package/apps/studio/client/photo-knobs.jsx +3 -0
- package/apps/studio/client/report-bug.jsx +19 -1
- package/apps/studio/client/share-dialog.jsx +91 -0
- package/apps/studio/client/share-link.js +94 -0
- package/apps/studio/client/styles/3-shell-maude.css +69 -18
- package/apps/studio/client/styles/4-components.css +44 -1
- package/apps/studio/client/tree-row-menu.jsx +48 -3
- package/apps/studio/client/whats-new.jsx +26 -32
- package/apps/studio/cloud/endpoints.ts +132 -0
- package/apps/studio/collab/index.ts +4 -0
- package/apps/studio/collab/persistence.ts +137 -17
- package/apps/studio/collab/registry.ts +19 -21
- package/apps/studio/collab/room.ts +13 -2
- package/apps/studio/context.ts +59 -0
- package/apps/studio/debug-bundle.ts +13 -0
- package/apps/studio/dist/client.bundle.js +1911 -1879
- package/apps/studio/dist/runtime/.min-sizes.json +1 -0
- package/apps/studio/dist/runtime/sonner.js +1 -0
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/export-dialog.tsx +54 -0
- package/apps/studio/exporters/degraded.ts +19 -3
- package/apps/studio/exporters/ghostscript.ts +194 -0
- package/apps/studio/exporters/pdf-fonts.ts +261 -0
- package/apps/studio/exporters/pdf.ts +152 -3
- package/apps/studio/exporters/remote.ts +36 -1
- package/apps/studio/fs-watch.ts +45 -1
- package/apps/studio/http.ts +296 -19
- package/apps/studio/inspect.ts +19 -0
- package/apps/studio/managed-projects.ts +150 -0
- package/apps/studio/mem.ts +45 -9
- package/apps/studio/notifications.tsx +292 -0
- package/apps/studio/runtime-bundle.ts +2 -0
- package/apps/studio/server.ts +69 -6
- package/apps/studio/sync/accepted-cold-start.ts +225 -0
- package/apps/studio/sync/accepted-link.ts +320 -0
- package/apps/studio/sync/action-stage.ts +343 -0
- package/apps/studio/sync/agent.ts +104 -45
- package/apps/studio/sync/asset-push.ts +1 -47
- package/apps/studio/sync/cell-file-events.ts +3 -0
- package/apps/studio/sync/codec.ts +192 -34
- package/apps/studio/sync/cold-start-apply.ts +7 -0
- package/apps/studio/sync/cold-start.ts +118 -22
- package/apps/studio/sync/comment-identity.ts +68 -0
- package/apps/studio/sync/connection-state.ts +15 -1
- package/apps/studio/sync/ctl-provider.ts +15 -2
- package/apps/studio/sync/document-discovery.ts +81 -0
- package/apps/studio/sync/file-ledger.ts +117 -0
- package/apps/studio/sync/file-membership.ts +10 -2
- package/apps/studio/sync/file-plane.ts +926 -47
- package/apps/studio/sync/index.ts +1786 -36
- package/apps/studio/sync/journal-client.ts +13 -1
- package/apps/studio/sync/migrate-seed.ts +150 -22
- package/apps/studio/sync/poke.ts +4 -2
- package/apps/studio/sync/presentation.ts +311 -5
- package/apps/studio/sync/projection.ts +820 -23
- package/apps/studio/sync/repeated-module.ts +73 -0
- package/apps/studio/sync/retry-after.ts +169 -0
- package/apps/studio/sync/revision-barrier.ts +129 -0
- package/apps/studio/sync/seed-progress.ts +218 -0
- package/apps/studio/sync/seed-repair.ts +46 -0
- package/apps/studio/sync/source-merge.ts +100 -0
- package/apps/studio/sync/source-ops.ts +289 -0
- package/apps/studio/sync/source-recovery.ts +70 -0
- package/apps/studio/sync/source-validation.ts +56 -0
- package/apps/studio/sync/status.ts +201 -6
- package/apps/studio/sync/transaction-client.ts +460 -0
- package/apps/studio/sync/transport-error.ts +111 -0
- package/apps/studio/sync/writer-registry.ts +236 -0
- package/apps/studio/text-caret.ts +35 -0
- package/apps/studio/undo-hud.tsx +9 -87
- package/apps/studio/use-canvas-media-drop.tsx +4 -39
- package/apps/studio/whats-new.json +173 -0
- package/cli/bin/maude.mjs +2 -0
- package/cli/commands/codex.mjs +191 -0
- package/cli/commands/harness.mjs +1051 -0
- package/cli/commands/help.mjs +13 -0
- package/cli/lib/design-link.mjs +190 -2
- package/cli/lib/harness/capabilities.mjs +302 -0
- package/cli/lib/harness/codex-runtime.mjs +892 -0
- package/cli/lib/harness/compatibility.mjs +27 -0
- package/cli/lib/harness/discover-claude.mjs +1393 -0
- package/cli/lib/harness/managed-state.mjs +1296 -0
- package/cli/lib/harness/model.mjs +86 -0
- package/cli/lib/harness/secrets.mjs +390 -0
- package/cli/lib/harness/targets/codex.mjs +1141 -0
- package/cli/lib/harness/targets/opencode.mjs +807 -0
- package/cli/lib/harness/transaction.mjs +1099 -0
- package/cli/lib/hubs-config.mjs +35 -8
- package/cli/templates/harness/opencode/maude-projector.ts +58 -0
- package/docs/harness-capability-matrix.md +125 -0
- package/docs/harness-environment-projection.md +95 -0
- package/package.json +33 -9
- package/plugins/design/dependencies.json +3 -3
- package/plugins/design/templates/_shell.html +47 -0
- package/plugins/flow/.claude-plugin/config.schema.json +8 -0
- package/plugins/flow/dependencies.json +3 -3
- package/apps/studio/.ai/cache/_stats.json +0 -7
- package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
- package/apps/studio/bin/_curl-local.test.mjs +0 -280
- package/apps/studio/bin/_pw-launch.test.mjs +0 -90
- package/apps/studio/bin/_smart-frames.test.mjs +0 -195
- package/apps/studio/bin/_transcribe.test.mjs +0 -80
- package/apps/studio/bun.lock +0 -928
- package/apps/studio/draw/test/animate.test.ts +0 -172
- package/apps/studio/draw/test/brush.test.ts +0 -213
- package/apps/studio/draw/test/composition.test.ts +0 -141
- package/apps/studio/draw/test/geometry.test.ts +0 -199
- package/apps/studio/draw/test/gradient.test.ts +0 -167
- package/apps/studio/draw/test/layout.test.ts +0 -120
- package/apps/studio/draw/test/morph.test.ts +0 -107
- package/apps/studio/draw/test/optimize.test.ts +0 -40
- package/apps/studio/draw/test/palette.test.ts +0 -123
- package/apps/studio/draw/test/primitives.test.ts +0 -129
- package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
- package/apps/studio/draw/test/serialize.test.ts +0 -105
- package/apps/studio/figma/assets.test.ts +0 -464
- package/apps/studio/figma/client.test.ts +0 -395
- package/apps/studio/figma/codegen-client.test.ts +0 -276
- package/apps/studio/figma/codegen-fonts.test.ts +0 -103
- package/apps/studio/figma/codegen-values.test.ts +0 -179
- package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
- package/apps/studio/figma/fig-decode.test.ts +0 -788
- package/apps/studio/figma/fig-differential.test.ts +0 -182
- package/apps/studio/figma/fig-translator.test.ts +0 -192
- package/apps/studio/figma/fig-vector.test.ts +0 -113
- package/apps/studio/figma/from-codegen.test.ts +0 -408
- package/apps/studio/figma/sanitize.test.ts +0 -325
- package/apps/studio/figma/tailwind-map.test.ts +0 -142
- package/apps/studio/figma/to-artboard.test.ts +0 -808
- package/apps/studio/figma/to-render.test.ts +0 -180
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
- package/apps/studio/figma/to-strokes.test.ts +0 -705
- package/apps/studio/figma/to-tokens.test.ts +0 -321
- package/apps/studio/figma/url.test.ts +0 -167
- package/apps/studio/footage/schema.test.ts +0 -287
- package/apps/studio/generation/adapters/groq.test.ts +0 -80
- package/apps/studio/generation/audio-library.test.ts +0 -95
- package/apps/studio/generation/captions.test.ts +0 -78
- package/apps/studio/generation/elevenlabs.test.ts +0 -223
- package/apps/studio/generation/gemini.test.ts +0 -350
- package/apps/studio/generation/jobs.test.ts +0 -128
- package/apps/studio/generation/keys.test.ts +0 -75
- package/apps/studio/generation/prefs.test.ts +0 -95
- package/apps/studio/generation/types.test.ts +0 -123
- package/apps/studio/generation/whisper-models.test.ts +0 -179
- package/apps/studio/test/_helpers.ts +0 -108
- package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
- package/apps/studio/test/acp-activity.test.ts +0 -154
- package/apps/studio/test/acp-ai-activity.test.ts +0 -182
- package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
- package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
- package/apps/studio/test/acp-branch-guard.test.ts +0 -123
- package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
- package/apps/studio/test/acp-bridge.test.ts +0 -545
- package/apps/studio/test/acp-capabilities.test.ts +0 -123
- package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
- package/apps/studio/test/acp-commands.test.ts +0 -119
- package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
- package/apps/studio/test/acp-elicitation.test.ts +0 -251
- package/apps/studio/test/acp-env.test.ts +0 -95
- package/apps/studio/test/acp-mode-banner.test.ts +0 -45
- package/apps/studio/test/acp-origin-gate.test.ts +0 -160
- package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
- package/apps/studio/test/acp-permission.test.ts +0 -278
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
- package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
- package/apps/studio/test/acp-session-plugins.test.ts +0 -209
- package/apps/studio/test/acp-toolgroup.test.ts +0 -76
- package/apps/studio/test/acp-transcript-view.test.ts +0 -71
- package/apps/studio/test/acp-transcript.test.ts +0 -238
- package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
- package/apps/studio/test/acp-usage.test.ts +0 -143
- package/apps/studio/test/acp-write-gate.test.ts +0 -323
- package/apps/studio/test/acp-write-scope.test.ts +0 -533
- package/apps/studio/test/active-state.test.ts +0 -186
- package/apps/studio/test/activity.test.ts +0 -189
- package/apps/studio/test/ai-activity.test.ts +0 -113
- package/apps/studio/test/annotate-write.test.ts +0 -1074
- package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
- package/apps/studio/test/annotations-align.test.ts +0 -88
- package/apps/studio/test/annotations-api.test.ts +0 -145
- package/apps/studio/test/annotations-bindings.test.ts +0 -262
- package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
- package/apps/studio/test/annotations-groups.test.ts +0 -231
- package/apps/studio/test/annotations-layer.test.ts +0 -1011
- package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
- package/apps/studio/test/annotations-snap.test.ts +0 -135
- package/apps/studio/test/annotations-text-format.test.ts +0 -396
- package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
- package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
- package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
- package/apps/studio/test/artboard-kinds.test.tsx +0 -83
- package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
- package/apps/studio/test/asset-api.test.ts +0 -149
- package/apps/studio/test/assets-s3.test.ts +0 -249
- package/apps/studio/test/binary-smoke.test.ts +0 -47
- package/apps/studio/test/boot-self-heal.test.ts +0 -87
- package/apps/studio/test/browse-posture.test.tsx +0 -107
- package/apps/studio/test/bundle-smoke.test.ts +0 -46
- package/apps/studio/test/camera-reveal.test.tsx +0 -173
- package/apps/studio/test/canvas-artifacts.test.ts +0 -125
- package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
- package/apps/studio/test/canvas-build.test.ts +0 -141
- package/apps/studio/test/canvas-create-api.test.ts +0 -676
- package/apps/studio/test/canvas-cursors.test.ts +0 -164
- package/apps/studio/test/canvas-edit.test.ts +0 -470
- package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
- package/apps/studio/test/canvas-header.test.ts +0 -127
- package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
- package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
- package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
- package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
- package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
- package/apps/studio/test/canvas-list-watch.test.ts +0 -388
- package/apps/studio/test/canvas-media-drop.test.ts +0 -187
- package/apps/studio/test/canvas-meta-api.test.ts +0 -707
- package/apps/studio/test/canvas-move-api.test.ts +0 -587
- package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
- package/apps/studio/test/canvas-pipeline.test.ts +0 -180
- package/apps/studio/test/canvas-rects.test.ts +0 -198
- package/apps/studio/test/canvas-reorder.test.ts +0 -211
- package/apps/studio/test/canvas-route.test.ts +0 -179
- package/apps/studio/test/canvas-shell-base.test.ts +0 -107
- package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
- package/apps/studio/test/canvas-url.test.ts +0 -138
- package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
- package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
- package/apps/studio/test/capture-core.test.ts +0 -32
- package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
- package/apps/studio/test/chat-attachments.test.ts +0 -117
- package/apps/studio/test/chat-context.test.ts +0 -129
- package/apps/studio/test/chat-markdown.test.tsx +0 -58
- package/apps/studio/test/clip-addressing.test.ts +0 -738
- package/apps/studio/test/clip-ops.test.ts +0 -922
- package/apps/studio/test/cloud-build.test.ts +0 -95
- package/apps/studio/test/cloud-connect-note.test.ts +0 -135
- package/apps/studio/test/cloud-endpoints.test.ts +0 -590
- package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
- package/apps/studio/test/cloud-history-posture.test.ts +0 -230
- package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
- package/apps/studio/test/cloud-renew.test.ts +0 -205
- package/apps/studio/test/cloud-session-role.test.ts +0 -161
- package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
- package/apps/studio/test/cold-start-apply.test.ts +0 -303
- package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
- package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
- package/apps/studio/test/collab-bridge.test.ts +0 -79
- package/apps/studio/test/collab-loopback.test.ts +0 -63
- package/apps/studio/test/collab-origin-gate.test.ts +0 -323
- package/apps/studio/test/collab-protocol.test.ts +0 -146
- package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
- package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
- package/apps/studio/test/collab-room.test.ts +0 -188
- package/apps/studio/test/collab-session-survival.test.tsx +0 -176
- package/apps/studio/test/collab-stress.test.ts +0 -129
- package/apps/studio/test/comment-mount.test.ts +0 -97
- package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
- package/apps/studio/test/comments-api.test.ts +0 -277
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
- package/apps/studio/test/comments-overlay.test.ts +0 -117
- package/apps/studio/test/compile-entry.test.ts +0 -133
- package/apps/studio/test/component-map.test.ts +0 -48
- package/apps/studio/test/config-projection.test.ts +0 -104
- package/apps/studio/test/config-reload.test.ts +0 -230
- package/apps/studio/test/config-version.test.ts +0 -88
- package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
- package/apps/studio/test/convert-to-absolute.test.ts +0 -333
- package/apps/studio/test/credential-grammar.test.ts +0 -107
- package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
- package/apps/studio/test/csrf-write-guard.test.ts +0 -141
- package/apps/studio/test/debug-bundle.test.ts +0 -105
- package/apps/studio/test/design-setup-readiness.test.ts +0 -155
- package/apps/studio/test/detach-component.test.ts +0 -94
- package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
- package/apps/studio/test/dom-selection.test.ts +0 -198
- package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
- package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
- package/apps/studio/test/edit-persistence.test.ts +0 -91
- package/apps/studio/test/edit-scope-api.test.ts +0 -119
- package/apps/studio/test/edit-source-command.test.ts +0 -142
- package/apps/studio/test/edit-suppress.test.ts +0 -170
- package/apps/studio/test/editing-presence.test.ts +0 -103
- package/apps/studio/test/element-resize.test.ts +0 -136
- package/apps/studio/test/element-structural-api.test.ts +0 -434
- package/apps/studio/test/element-structural-edit.test.ts +0 -750
- package/apps/studio/test/ensure-browser.test.ts +0 -92
- package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
- package/apps/studio/test/export-assemble.test.ts +0 -53
- package/apps/studio/test/export-browser-lane.test.ts +0 -126
- package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
- package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
- package/apps/studio/test/export-center.test.tsx +0 -287
- package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
- package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
- package/apps/studio/test/export-lane.test.ts +0 -245
- package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
- package/apps/studio/test/exporters/canva.test.ts +0 -63
- package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
- package/apps/studio/test/exporters/endpoint.test.ts +0 -121
- package/apps/studio/test/exporters/history.test.ts +0 -107
- package/apps/studio/test/exporters/html.test.ts +0 -26
- package/apps/studio/test/exporters/jobs.test.ts +0 -342
- package/apps/studio/test/exporters/pdf.test.ts +0 -85
- package/apps/studio/test/exporters/png.test.ts +0 -103
- package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
- package/apps/studio/test/exporters/pptx.test.ts +0 -31
- package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
- package/apps/studio/test/exporters/runtime.test.ts +0 -59
- package/apps/studio/test/exporters/scope.test.ts +0 -292
- package/apps/studio/test/exporters/svg.test.ts +0 -29
- package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
- package/apps/studio/test/exporters/zip.test.ts +0 -104
- package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
- package/apps/studio/test/figjam-v3-model.test.ts +0 -342
- package/apps/studio/test/figma-explode.test.ts +0 -438
- package/apps/studio/test/figma-provenance.test.ts +0 -108
- package/apps/studio/test/figma-routes.test.ts +0 -294
- package/apps/studio/test/file-lock.test.ts +0 -84
- package/apps/studio/test/fixtures/backgrounding-claude-auth.sh +0 -12
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -23
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
- package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
- package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
- package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
- package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
- package/apps/studio/test/fixtures/noisy-claude-auth.mjs +0 -27
- package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
- package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
- package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
- package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
- package/apps/studio/test/fixtures/wedged-claude-auth.sh +0 -11
- package/apps/studio/test/footage-store.test.ts +0 -100
- package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
- package/apps/studio/test/fs-watch.test.ts +0 -41
- package/apps/studio/test/gemma-models.test.ts +0 -245
- package/apps/studio/test/generate-route.test.ts +0 -106
- package/apps/studio/test/git-api.test.ts +0 -0
- package/apps/studio/test/git-branches.test.ts +0 -341
- package/apps/studio/test/git-cloud-posture.test.ts +0 -59
- package/apps/studio/test/git-grouping.test.ts +0 -106
- package/apps/studio/test/git-lifecycle.test.ts +0 -100
- package/apps/studio/test/git-log-format.test.ts +0 -95
- package/apps/studio/test/git-safe-rel.test.ts +0 -132
- package/apps/studio/test/git-system-engine.test.ts +0 -135
- package/apps/studio/test/git-watch.test.ts +0 -97
- package/apps/studio/test/github-api.test.ts +0 -577
- package/apps/studio/test/grid-track-handles.test.ts +0 -160
- package/apps/studio/test/handoff-static-frames.test.ts +0 -215
- package/apps/studio/test/handoff.test.ts +0 -329
- package/apps/studio/test/history-rollback.test.ts +0 -88
- package/apps/studio/test/hmr-broadcast.test.ts +0 -236
- package/apps/studio/test/hmr-classify.test.ts +0 -87
- package/apps/studio/test/hub-link.test.ts +0 -80
- package/apps/studio/test/identity-cache.test.ts +0 -83
- package/apps/studio/test/import-asset-browser.test.ts +0 -64
- package/apps/studio/test/import-asset-route.test.ts +0 -71
- package/apps/studio/test/import-asset.test.ts +0 -427
- package/apps/studio/test/import-brand-browser.test.ts +0 -88
- package/apps/studio/test/import-brand-route.test.ts +0 -120
- package/apps/studio/test/import-brand.test.ts +0 -206
- package/apps/studio/test/import-figma.test.ts +0 -667
- package/apps/studio/test/import-tokens.test.ts +0 -722
- package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
- package/apps/studio/test/input-router.test.ts +0 -757
- package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
- package/apps/studio/test/inspect-selections.test.ts +0 -219
- package/apps/studio/test/knob-props-authored.test.ts +0 -87
- package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
- package/apps/studio/test/locator.test.ts +0 -214
- package/apps/studio/test/marquee-overlay.test.ts +0 -94
- package/apps/studio/test/media-commit-chain.test.ts +0 -210
- package/apps/studio/test/mode-toggle.test.tsx +0 -226
- package/apps/studio/test/motion-sample.test.ts +0 -35
- package/apps/studio/test/move-artboards-command.test.ts +0 -108
- package/apps/studio/test/participants-chrome.test.ts +0 -65
- package/apps/studio/test/paths.test.ts +0 -88
- package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
- package/apps/studio/test/perf-harness.ts +0 -193
- package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
- package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
- package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
- package/apps/studio/test/photo-edit-api.test.ts +0 -201
- package/apps/studio/test/photo-filters.test.ts +0 -149
- package/apps/studio/test/photo-pipeline.test.ts +0 -106
- package/apps/studio/test/photo-taxonomy.test.ts +0 -96
- package/apps/studio/test/print-marks.test.ts +0 -113
- package/apps/studio/test/print-units.test.ts +0 -173
- package/apps/studio/test/read-annotations.test.ts +0 -727
- package/apps/studio/test/read-only-gate.test.ts +0 -188
- package/apps/studio/test/read-only-role.test.ts +0 -95
- package/apps/studio/test/readiness.test.ts +0 -337
- package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
- package/apps/studio/test/reorder-api.test.ts +0 -210
- package/apps/studio/test/repo-concurrency.test.ts +0 -146
- package/apps/studio/test/repo-lock.test.ts +0 -350
- package/apps/studio/test/report-proxy.test.ts +0 -125
- package/apps/studio/test/ripple.test.ts +0 -197
- package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
- package/apps/studio/test/runtime-bundle.test.ts +0 -69
- package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
- package/apps/studio/test/scaffold-design.test.ts +0 -122
- package/apps/studio/test/server-lifecycle.test.ts +0 -38
- package/apps/studio/test/session-runtime-state.test.ts +0 -226
- package/apps/studio/test/session-scope.test.ts +0 -100
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
- package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
- package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
- package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
- package/apps/studio/test/shared-doc-projection.test.ts +0 -238
- package/apps/studio/test/shell-importmap.test.ts +0 -56
- package/apps/studio/test/sizing-mode.test.ts +0 -102
- package/apps/studio/test/slash-commands.test.ts +0 -117
- package/apps/studio/test/snap-distance-pill.test.ts +0 -68
- package/apps/studio/test/spacing-handles.test.ts +0 -138
- package/apps/studio/test/specimen-select.test.ts +0 -88
- package/apps/studio/test/sync-agent.test.ts +0 -660
- package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
- package/apps/studio/test/sync-asset-push.test.ts +0 -931
- package/apps/studio/test/sync-atomic-write.test.ts +0 -62
- package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
- package/apps/studio/test/sync-autocommit.test.ts +0 -537
- package/apps/studio/test/sync-canvas-path.test.ts +0 -200
- package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
- package/apps/studio/test/sync-codec.test.ts +0 -230
- package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
- package/apps/studio/test/sync-cold-start.test.ts +0 -304
- package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
- package/apps/studio/test/sync-connection-state.test.ts +0 -337
- package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
- package/apps/studio/test/sync-decide-file.test.ts +0 -420
- package/apps/studio/test/sync-doc-name.test.ts +0 -281
- package/apps/studio/test/sync-echo-guard.test.ts +0 -96
- package/apps/studio/test/sync-file-ledger.test.ts +0 -334
- package/apps/studio/test/sync-file-membership.test.ts +0 -347
- package/apps/studio/test/sync-file-plane.test.ts +0 -976
- package/apps/studio/test/sync-file-pull.test.ts +0 -333
- package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
- package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
- package/apps/studio/test/sync-hardening.test.ts +0 -586
- package/apps/studio/test/sync-hub-listing.test.ts +0 -46
- package/apps/studio/test/sync-hubs-config.test.ts +0 -133
- package/apps/studio/test/sync-incident-replay.test.ts +0 -211
- package/apps/studio/test/sync-journal.test.ts +0 -176
- package/apps/studio/test/sync-meta-codec.test.ts +0 -199
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
- package/apps/studio/test/sync-move-retirement.test.ts +0 -231
- package/apps/studio/test/sync-panel-surface.test.ts +0 -153
- package/apps/studio/test/sync-path-pull.test.ts +0 -531
- package/apps/studio/test/sync-presentation.test.ts +0 -262
- package/apps/studio/test/sync-pull-budget.test.ts +0 -169
- package/apps/studio/test/sync-remote-docs.test.ts +0 -333
- package/apps/studio/test/sync-resync-routes.test.ts +0 -168
- package/apps/studio/test/sync-runtime.test.ts +0 -1675
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
- package/apps/studio/test/sync-settings-routes.test.ts +0 -195
- package/apps/studio/test/sync-settings.test.ts +0 -151
- package/apps/studio/test/sync-status.test.ts +0 -261
- package/apps/studio/test/sync-supervisor.test.ts +0 -262
- package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
- package/apps/studio/test/sync-trash.test.ts +0 -132
- package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
- package/apps/studio/test/sync-untrusted.test.ts +0 -103
- package/apps/studio/test/system-endpoint.test.ts +0 -144
- package/apps/studio/test/text-editability-stamp.test.ts +0 -131
- package/apps/studio/test/timeline-comp-target.test.ts +0 -139
- package/apps/studio/test/timeline-media-cache.test.ts +0 -41
- package/apps/studio/test/timeline-parse.test.ts +0 -184
- package/apps/studio/test/timeline-scale.test.ts +0 -65
- package/apps/studio/test/timeline-snap.test.ts +0 -85
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
- package/apps/studio/test/tool-palette.test.tsx +0 -55
- package/apps/studio/test/tour-overlay.test.tsx +0 -90
- package/apps/studio/test/trusted-request-host.test.ts +0 -66
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
- package/apps/studio/test/undo-stack.test.ts +0 -244
- package/apps/studio/test/use-agent-presence.test.tsx +0 -117
- package/apps/studio/test/use-annotation-resize.test.ts +0 -402
- package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
- package/apps/studio/test/use-artboard-drag.test.ts +0 -324
- package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
- package/apps/studio/test/use-collab.test.ts +0 -0
- package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
- package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
- package/apps/studio/test/use-selection-set.test.tsx +0 -166
- package/apps/studio/test/use-snap-guides.test.ts +0 -271
- package/apps/studio/test/use-tool-mode.test.tsx +0 -186
- package/apps/studio/test/use-undo-stack.test.tsx +0 -223
- package/apps/studio/test/video-asset.test.ts +0 -163
- package/apps/studio/test/video-comp-fixture.test.ts +0 -50
- package/apps/studio/test/video-comp.test.ts +0 -270
- package/apps/studio/test/video-encode-lib.test.ts +0 -63
- package/apps/studio/test/video-render-bridge.test.ts +0 -171
- package/apps/studio/test/whats-new.test.ts +0 -113
- package/apps/studio/test/whisper-setup.test.ts +0 -97
- package/apps/studio/test/workspace-containment.test.ts +0 -382
- package/apps/studio/test/workspace-signin.test.ts +0 -292
- package/apps/studio/test/ws-handshake.test.ts +0 -33
- package/cli/commands/cache.test.mjs +0 -166
- package/cli/commands/design-link.test.mjs +0 -419
- package/cli/commands/design.test.mjs +0 -240
- package/cli/commands/doctor.test.mjs +0 -237
- package/cli/commands/hub-workspace.test.mjs +0 -275
- package/cli/commands/hub.test.mjs +0 -225
- package/cli/commands/kg.test.mjs +0 -142
- package/cli/commands/preflight.test.mjs +0 -46
- package/cli/lib/argv.test.mjs +0 -46
- package/cli/lib/cache.test.mjs +0 -303
- package/cli/lib/cell-plan.test.mjs +0 -225
- package/cli/lib/config-lint.test.mjs +0 -117
- package/cli/lib/ddr-to-kgai.test.mjs +0 -118
- package/cli/lib/design-ownership.test.mjs +0 -329
- package/cli/lib/fetch-asset.test.mjs +0 -213
- package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
- package/cli/lib/figma-import-controls.test.mjs +0 -70
- package/cli/lib/flow-design-integration.test.mjs +0 -165
- package/cli/lib/gitignore-block.test.mjs +0 -136
- package/cli/lib/gitignore-drift.test.mjs +0 -156
- package/cli/lib/hubs-config.test.mjs +0 -165
- package/cli/lib/pkg-root.test.mjs +0 -111
- package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
- package/cli/lib/plugin-name-namespace.test.mjs +0 -71
- package/cli/lib/reconstruct-toolset.test.mjs +0 -194
- package/cli/lib/stack-detect.test.mjs +0 -121
- package/cli/lib/update-check.test.mjs +0 -32
- package/cli/lib/workspace-plan.test.mjs +0 -699
package/apps/studio/mem.ts
CHANGED
|
@@ -5,8 +5,30 @@
|
|
|
5
5
|
// not the primary path. The primary path is the explicit `iframe:closed` event
|
|
6
6
|
// emitted on the bus, which calls cleanupFn synchronously.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// #119 — these thresholds are read against `rss`, NOT `heapTotal`.
|
|
9
|
+
//
|
|
10
|
+
// The watch originally polled `process.memoryUsage().heapTotal`, which is a V8
|
|
11
|
+
// intuition that does not carry over: under Bun/JSC it barely moves for the
|
|
12
|
+
// allocations that actually grow this process. Measured while the server read
|
|
13
|
+
// 554 MB of chat transcripts, `rss` peaked at 1.29 GB while `heapTotal` peaked
|
|
14
|
+
// at 5 MB — three orders of magnitude apart. Neither threshold below was
|
|
15
|
+
// reachable, so the one guard written for a runaway-memory failure could never
|
|
16
|
+
// fire, and the `[mem]` line that would have named the problem never reached
|
|
17
|
+
// the log ring (and therefore never reached a bug report's `serverLogTail`).
|
|
18
|
+
// The bug it was meant to catch shipped past it in silence.
|
|
19
|
+
//
|
|
20
|
+
// `rss` is the number the user sees in Activity Monitor, which is also the
|
|
21
|
+
// number they report. Sized for a server whose steady state is a few hundred
|
|
22
|
+
// MB: WARN is "something is wrong", PANIC is "intervene before the machine
|
|
23
|
+
// starts swapping".
|
|
24
|
+
const RSS_WARN_BYTES = 1024 * 1024 * 1024; // 1 GB — log only
|
|
25
|
+
const RSS_PANIC_BYTES = 2 * 1024 * 1024 * 1024; // 2 GB — log + force GC
|
|
26
|
+
|
|
27
|
+
/** Once past PANIC, back off exponentially instead of forcing a full GC on
|
|
28
|
+
* every tick forever. `Bun.gc(true)` is synchronous — it runs on the same
|
|
29
|
+
* single thread that serves the ACP socket and every HTTP route — so a
|
|
30
|
+
* permanently-crossed threshold must not become a permanent stutter. */
|
|
31
|
+
const PANIC_BACKOFF_MAX = 16;
|
|
10
32
|
|
|
11
33
|
let registry: FinalizationRegistry<{ id: string; cleanupFn: () => void }> | null = null;
|
|
12
34
|
|
|
@@ -73,17 +95,31 @@ let heapTimer: ReturnType<typeof setInterval> | null = null;
|
|
|
73
95
|
|
|
74
96
|
export function startHeapWatch(intervalMs = 60_000) {
|
|
75
97
|
if (heapTimer) return;
|
|
98
|
+
let ticksUntilPanic = 0;
|
|
99
|
+
let panicBackoff = 1;
|
|
76
100
|
heapTimer = setInterval(() => {
|
|
77
101
|
const u = process.memoryUsage();
|
|
78
|
-
|
|
102
|
+
const mb = (n: number) => (n / 1024 / 1024).toFixed(0);
|
|
103
|
+
if (u.rss > RSS_PANIC_BYTES) {
|
|
104
|
+
// ALWAYS log — the log line is the diagnostic that survives into a bug
|
|
105
|
+
// report, and it must not be suppressed by the GC backoff below.
|
|
79
106
|
console.warn(
|
|
80
|
-
`[mem]
|
|
107
|
+
`[mem] rss ${mb(u.rss)}MB > panic threshold (heapUsed ${mb(u.heapUsed)}MB) — memory is not being reclaimed`
|
|
81
108
|
);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
if (ticksUntilPanic > 0) {
|
|
110
|
+
ticksUntilPanic--;
|
|
111
|
+
} else {
|
|
112
|
+
const gc = (globalThis as { Bun?: { gc?: (sync: boolean) => void } }).Bun?.gc;
|
|
113
|
+
if (gc) gc(true);
|
|
114
|
+
ticksUntilPanic = panicBackoff;
|
|
115
|
+
panicBackoff = Math.min(panicBackoff * 2, PANIC_BACKOFF_MAX);
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
ticksUntilPanic = 0;
|
|
119
|
+
panicBackoff = 1;
|
|
120
|
+
if (u.rss > RSS_WARN_BYTES) {
|
|
121
|
+
console.warn(`[mem] rss ${mb(u.rss)}MB > warn threshold (heapUsed ${mb(u.heapUsed)}MB)`);
|
|
122
|
+
}
|
|
87
123
|
}
|
|
88
124
|
}, intervalMs);
|
|
89
125
|
// Don't keep the event loop alive just for the heap watch.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/** Shared shell/canvas notifications. Sonner owns layout, gestures and announcements;
|
|
2
|
+
* our clock also pauses for app overlays, hidden queue entries and Save dialogs. */
|
|
3
|
+
import {
|
|
4
|
+
type CSSProperties,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
useEffect,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
useSyncExternalStore,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import { Toaster, toast } from 'sonner';
|
|
12
|
+
|
|
13
|
+
export type NoticeKind = 'info' | 'success' | 'error' | 'warning' | 'undo';
|
|
14
|
+
export interface Notice {
|
|
15
|
+
id?: string;
|
|
16
|
+
title: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
content?: ReactNode;
|
|
19
|
+
kind?: NoticeKind;
|
|
20
|
+
group?: string;
|
|
21
|
+
duration?: number;
|
|
22
|
+
/** Change only for a new lifecycle phase, never for a progress update. */
|
|
23
|
+
timerKey?: string;
|
|
24
|
+
paused?: boolean;
|
|
25
|
+
action?: { label: string; onClick: () => void };
|
|
26
|
+
onDismiss?: () => void;
|
|
27
|
+
}
|
|
28
|
+
type Entry = Notice & { id: string };
|
|
29
|
+
let entries: Entry[] = [];
|
|
30
|
+
let sequence = 0;
|
|
31
|
+
const listeners = new Set<() => void>();
|
|
32
|
+
const publish = () => {
|
|
33
|
+
for (const listener of listeners) listener();
|
|
34
|
+
};
|
|
35
|
+
const subscribe = (listener: () => void) => {
|
|
36
|
+
listeners.add(listener);
|
|
37
|
+
return () => {
|
|
38
|
+
listeners.delete(listener);
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const snapshot = () => entries;
|
|
42
|
+
|
|
43
|
+
export function notify(notice: Notice): string {
|
|
44
|
+
const id = notice.id ?? `notice-${++sequence}`;
|
|
45
|
+
const existing = entries.findIndex((entry) => entry.id === id);
|
|
46
|
+
if (existing < 0) entries = [...entries, { ...notice, id }];
|
|
47
|
+
else entries = entries.map((entry) => (entry.id === id ? { ...notice, id } : entry));
|
|
48
|
+
publish();
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let canvasSlot = 0;
|
|
53
|
+
let canvasWindowStart = -Infinity;
|
|
54
|
+
let canvasWindowCount = 0;
|
|
55
|
+
/** Untrusted canvas traffic gets two reusable slots, leaving room for shell notices.
|
|
56
|
+
* Limit publications as well as retention; editing can emit dozens per second. */
|
|
57
|
+
export function notifyCanvasText(title: string, kind: NoticeKind = 'info'): string | null {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
if (now < canvasWindowStart || now - canvasWindowStart >= 1000) {
|
|
60
|
+
canvasWindowStart = now;
|
|
61
|
+
canvasWindowCount = 0;
|
|
62
|
+
}
|
|
63
|
+
if (canvasWindowCount >= 5) return null;
|
|
64
|
+
canvasWindowCount++;
|
|
65
|
+
const previousUndo =
|
|
66
|
+
kind === 'undo'
|
|
67
|
+
? entries.find((entry) => entry.group === 'canvas' && entry.kind === 'undo')
|
|
68
|
+
: undefined;
|
|
69
|
+
const id = previousUndo?.id ?? `canvas-notice-${canvasSlot++ % 2}`;
|
|
70
|
+
return notify({
|
|
71
|
+
id,
|
|
72
|
+
title: title.slice(0, 4000),
|
|
73
|
+
kind,
|
|
74
|
+
group: 'canvas',
|
|
75
|
+
timerKey: `${++sequence}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Programmatic removal (unmount/navigation) does not acknowledge the notice. */
|
|
80
|
+
export function dismissNotice(id: string): void {
|
|
81
|
+
entries = entries.filter((entry) => entry.id !== id);
|
|
82
|
+
publish();
|
|
83
|
+
}
|
|
84
|
+
function acknowledge(id: string) {
|
|
85
|
+
const entry = entries.find((item) => item.id === id);
|
|
86
|
+
dismissNotice(id);
|
|
87
|
+
entry?.onDismiss?.();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function noticeDuration(entry: Notice): number {
|
|
91
|
+
return (
|
|
92
|
+
entry.duration ??
|
|
93
|
+
(entry.action || ['error', 'warning', 'undo'].includes(entry.kind ?? '') ? 10_000 : 5_000)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Keep full diagnostics in their owning panel, including for screen readers. */
|
|
98
|
+
export function summarizeNoticeText(text: string): string {
|
|
99
|
+
const compact = text.trim().replace(/\s+/g, ' ');
|
|
100
|
+
return compact.length > 280 ? `${compact.slice(0, 279)}…` : compact;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function NoticeCard({ entry }: { entry: Entry }) {
|
|
104
|
+
return (
|
|
105
|
+
<div
|
|
106
|
+
className="maude-notice"
|
|
107
|
+
data-kind={entry.kind ?? 'info'}
|
|
108
|
+
data-testid={`notice-${entry.id}`}
|
|
109
|
+
>
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
className="maude-notice-close"
|
|
113
|
+
aria-label="Dismiss notification"
|
|
114
|
+
onClick={(event) => {
|
|
115
|
+
event.currentTarget.blur();
|
|
116
|
+
acknowledge(entry.id);
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
×
|
|
120
|
+
</button>
|
|
121
|
+
<div className="maude-notice-title">{summarizeNoticeText(entry.title)}</div>
|
|
122
|
+
{entry.description && (
|
|
123
|
+
<div className="maude-notice-summary">{summarizeNoticeText(entry.description)}</div>
|
|
124
|
+
)}
|
|
125
|
+
{entry.content}
|
|
126
|
+
{entry.action && (
|
|
127
|
+
<button
|
|
128
|
+
type="button"
|
|
129
|
+
className="maude-notice-action"
|
|
130
|
+
onClick={(event) => {
|
|
131
|
+
event.currentTarget.blur();
|
|
132
|
+
entry.action?.onClick();
|
|
133
|
+
acknowledge(entry.id);
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
{entry.action.label}
|
|
137
|
+
</button>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function MountedNotice({
|
|
144
|
+
entry,
|
|
145
|
+
visible,
|
|
146
|
+
paused,
|
|
147
|
+
}: {
|
|
148
|
+
entry: Entry;
|
|
149
|
+
visible: boolean;
|
|
150
|
+
paused: boolean;
|
|
151
|
+
}) {
|
|
152
|
+
const duration = noticeDuration(entry);
|
|
153
|
+
const presentationId = useRef<string | null>(null);
|
|
154
|
+
const remaining = useRef(duration);
|
|
155
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: a new lifecycle phase gets a fresh duration.
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
remaining.current = duration;
|
|
158
|
+
}, [duration, entry.timerKey]);
|
|
159
|
+
// Keep the clock outside Sonner's card: hiding a group must preserve its time.
|
|
160
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: restart the clock when its lifecycle phase changes.
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (!visible || paused || entry.paused || duration === Infinity) return;
|
|
163
|
+
const started = Date.now();
|
|
164
|
+
const timer = setTimeout(() => acknowledge(entry.id), Math.max(0, remaining.current));
|
|
165
|
+
return () => {
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
remaining.current = Math.max(0, remaining.current - (Date.now() - started));
|
|
168
|
+
};
|
|
169
|
+
}, [visible, paused, entry.paused, duration, entry.timerKey, entry.id]);
|
|
170
|
+
// Sonner invokes onDismiss even for programmatic removal. Invalidate the
|
|
171
|
+
// presentation before hiding so opening history never acknowledges a job.
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (visible) {
|
|
174
|
+
const token = presentationId.current ?? `${entry.id}:view-${++sequence}`;
|
|
175
|
+
presentationId.current = token;
|
|
176
|
+
toast.custom(() => <NoticeCard entry={entry} />, {
|
|
177
|
+
id: token,
|
|
178
|
+
duration: Infinity,
|
|
179
|
+
onDismiss: () => {
|
|
180
|
+
if (presentationId.current === token) acknowledge(entry.id);
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
} else if (presentationId.current) {
|
|
184
|
+
const token = presentationId.current;
|
|
185
|
+
presentationId.current = null;
|
|
186
|
+
toast.dismiss(token);
|
|
187
|
+
}
|
|
188
|
+
}, [entry, visible]);
|
|
189
|
+
useEffect(
|
|
190
|
+
() => () => {
|
|
191
|
+
const token = presentationId.current;
|
|
192
|
+
presentationId.current = null;
|
|
193
|
+
if (token) toast.dismiss(token);
|
|
194
|
+
},
|
|
195
|
+
[]
|
|
196
|
+
);
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const NOTICE_CSS = `
|
|
201
|
+
.maude-notifications [data-sonner-toaster] { --width: min(360px, calc(100vw - 32px)); z-index: 8000; }
|
|
202
|
+
.maude-notifications [data-sonner-toast] { width: var(--width); }
|
|
203
|
+
.maude-notifications [data-sonner-toast][data-expanded=false][data-front=false] {
|
|
204
|
+
overflow: hidden; border-radius: var(--radius-md, 8px);
|
|
205
|
+
}
|
|
206
|
+
.maude-notifications[data-paused=true] { visibility: hidden; pointer-events: none; }
|
|
207
|
+
.maude-notice { box-sizing: border-box; position: relative; width: 100%; padding: 16px;
|
|
208
|
+
border: 1px solid var(--border-default, #45454c); border-left: 3px solid var(--accent, #d63b1f);
|
|
209
|
+
border-radius: var(--radius-md, 8px); background: var(--bg-2, #26262b); color: var(--fg-0, #fafafa);
|
|
210
|
+
box-shadow: 0 8px 28px #0004; font: 13px/1.5 var(--font-sans, system-ui, sans-serif);
|
|
211
|
+
display: flex; flex-direction: column; gap: 8px; overflow-wrap: anywhere; }
|
|
212
|
+
.maude-notice[data-kind=error], .maude-notice[data-kind=warning] { border-left-color: var(--status-error, #d65b4d); }
|
|
213
|
+
.maude-notice-title { font-weight: 600; padding-right: 20px; }
|
|
214
|
+
.maude-notice-summary, .maude-notice-title, .maude-notice .st-export-degraded {
|
|
215
|
+
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
|
|
216
|
+
overflow-wrap: anywhere; }
|
|
217
|
+
.maude-notice-summary { color: var(--fg-1, #ddd); }
|
|
218
|
+
.maude-notice-close { position: absolute; right: 8px; top: 8px; border: 0; border-radius: 4px;
|
|
219
|
+
background: transparent; color: inherit; cursor: pointer; font-size: 18px; padding: 0 6px; }
|
|
220
|
+
.maude-notice-action { align-self: flex-start; border: 0; background: transparent; color: inherit;
|
|
221
|
+
font: inherit; text-decoration: underline; cursor: pointer; padding: 2px 0; }
|
|
222
|
+
.maude-notice button:focus-visible { outline: 2px solid var(--accent, #d63b1f); outline-offset: 2px; }
|
|
223
|
+
.maude-notice .st-toast-actions { flex-wrap: wrap; }
|
|
224
|
+
@media (prefers-reduced-motion: reduce) {
|
|
225
|
+
.maude-notifications [data-sonner-toast], .maude-notifications [data-sonner-toaster] {
|
|
226
|
+
animation: none !important; transition: none !important;
|
|
227
|
+
}
|
|
228
|
+
}`;
|
|
229
|
+
|
|
230
|
+
const NO_GROUPS: string[] = [];
|
|
231
|
+
export function NotificationHost({
|
|
232
|
+
paused = false,
|
|
233
|
+
hiddenGroups = NO_GROUPS,
|
|
234
|
+
}: {
|
|
235
|
+
paused?: boolean;
|
|
236
|
+
hiddenGroups?: string[];
|
|
237
|
+
}) {
|
|
238
|
+
const notices = useSyncExternalStore(subscribe, snapshot, snapshot);
|
|
239
|
+
const hostRef = useRef<HTMLDivElement>(null);
|
|
240
|
+
const [hovered, setHovered] = useState(false);
|
|
241
|
+
const [focused, setFocused] = useState(false);
|
|
242
|
+
const [hidden, setHidden] = useState(() => typeof document !== 'undefined' && document.hidden);
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
const change = () => setHidden(document.hidden);
|
|
245
|
+
document.addEventListener('visibilitychange', change);
|
|
246
|
+
return () => document.removeEventListener('visibilitychange', change);
|
|
247
|
+
}, []);
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
if (!notices.length) {
|
|
250
|
+
setHovered(false);
|
|
251
|
+
setFocused(false);
|
|
252
|
+
}
|
|
253
|
+
// Removing a focused DOM node does not reliably emit blur in browsers.
|
|
254
|
+
if (focused && !hostRef.current?.contains(document.activeElement)) setFocused(false);
|
|
255
|
+
}, [notices, focused]);
|
|
256
|
+
const visible = notices.filter((entry) => !hiddenGroups.includes(entry.group ?? ''));
|
|
257
|
+
// Publish only the latest three; older entries keep their clocks while waiting.
|
|
258
|
+
// This also keeps visibility and clocks aligned when a hidden group returns.
|
|
259
|
+
const timedIds = new Set(visible.slice(-3).map((entry) => entry.id));
|
|
260
|
+
return (
|
|
261
|
+
<div
|
|
262
|
+
ref={hostRef}
|
|
263
|
+
className="maude-notifications"
|
|
264
|
+
data-paused={paused}
|
|
265
|
+
onPointerEnter={() => setHovered(true)}
|
|
266
|
+
onPointerLeave={() => setHovered(false)}
|
|
267
|
+
onFocusCapture={() => setFocused(true)}
|
|
268
|
+
onBlurCapture={(event) => {
|
|
269
|
+
if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setFocused(false);
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
<style>{NOTICE_CSS}</style>
|
|
273
|
+
<Toaster
|
|
274
|
+
position="bottom-left"
|
|
275
|
+
offset={{ left: 16, bottom: 84 }}
|
|
276
|
+
mobileOffset={{ left: 16, right: 16, bottom: 84 }}
|
|
277
|
+
visibleToasts={3}
|
|
278
|
+
expand={focused}
|
|
279
|
+
style={{ '--width': 'min(360px, calc(100vw - 32px))' } as CSSProperties}
|
|
280
|
+
containerAriaLabel="Notifications"
|
|
281
|
+
/>
|
|
282
|
+
{notices.map((entry) => (
|
|
283
|
+
<MountedNotice
|
|
284
|
+
key={entry.id}
|
|
285
|
+
entry={entry}
|
|
286
|
+
visible={timedIds.has(entry.id)}
|
|
287
|
+
paused={paused || hovered || focused || hidden || !timedIds.has(entry.id)}
|
|
288
|
+
/>
|
|
289
|
+
))}
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
@@ -47,6 +47,8 @@ export const RUNTIME_PACKAGES = [
|
|
|
47
47
|
'react-dom/client',
|
|
48
48
|
'react/jsx-runtime',
|
|
49
49
|
'react/jsx-dev-runtime',
|
|
50
|
+
// Toasts in standalone canvases resolve without node_modules in packaged installs.
|
|
51
|
+
'sonner',
|
|
50
52
|
// Pixi.js v8 — per-iframe runtime bundle for the non-destructive photo editor
|
|
51
53
|
// (feature-photo-editor). The canvas-lib `<PhotoLayer>` reaches the WebGL
|
|
52
54
|
// compositor (`photo/pipeline.ts`) through a LAZY runtime `import('pixi.js')`,
|
package/apps/studio/server.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// else binds to a port. The orchestrator (slash commands) reads _server.json
|
|
15
15
|
// to detect a live instance and avoid duplicate boots.
|
|
16
16
|
|
|
17
|
+
import path from 'node:path';
|
|
17
18
|
import { createAcp } from './acp/index.ts';
|
|
18
19
|
import { cancelInstall, cancelSignin } from './acp/login-state.ts';
|
|
19
20
|
import { createActivity } from './activity.ts';
|
|
@@ -78,22 +79,54 @@ let collab: ReturnType<typeof createCollab> | null = null;
|
|
|
78
79
|
let inspectHandle: ReturnType<typeof createInspectRegistry> | null = null;
|
|
79
80
|
|
|
80
81
|
const api = createApi(ctx, {
|
|
81
|
-
onCommentsChanged:
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
onCommentsChanged: (file, comments, base) => {
|
|
83
|
+
// Accepted-revisions mode (DDR-241): the change is PROPOSED; the room's
|
|
84
|
+
// document changes when the project publishes it. Fire-and-forget — the
|
|
85
|
+
// proposal is durable in the outbox before this returns, and the sidebar
|
|
86
|
+
// below already shows the author their own comment.
|
|
87
|
+
const runtime = ctx.syncControl?.current?.();
|
|
88
|
+
const proposed = runtime?.proposeLane?.(
|
|
89
|
+
api.fileSlug(file),
|
|
90
|
+
'comments',
|
|
91
|
+
JSON.stringify(comments),
|
|
92
|
+
base ? { baseText: JSON.stringify(base) } : {}
|
|
93
|
+
);
|
|
94
|
+
if (proposed) {
|
|
95
|
+
void proposed.catch(() => {});
|
|
96
|
+
ctx.bus.emit('comments', { file, comments });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
85
99
|
// Phase 8 Task 3 — bridge into the live Y.Array so collab peers see the
|
|
86
100
|
// change without waiting for cold-open re-seeding. No-op when no room is
|
|
87
101
|
// live for this canvas slug.
|
|
102
|
+
//
|
|
103
|
+
// Issue #111 — this runs BEFORE the mutation reaches disk (see
|
|
104
|
+
// `publishComments`), and `comments` is the post-mutation list handed over
|
|
105
|
+
// in memory. It used to be `await api.loadCommentsForFile(file)`: a disk
|
|
106
|
+
// round-trip sitting between the file write and this publish, wide enough
|
|
107
|
+
// for a `Room.flush()` to project the pre-mutation doc back over the file.
|
|
108
|
+
// Nothing here touches disk any more, and the doc is updated synchronously,
|
|
109
|
+
// so there is no window for a flush to be the stale writer.
|
|
88
110
|
if (collab) {
|
|
89
111
|
collab.registry.syncRoomFromComments(api.fileSlug(file), comments);
|
|
90
112
|
}
|
|
113
|
+
// After every comments mutation, re-broadcast the updated list.
|
|
114
|
+
ctx.bus.emit('comments', { file, comments });
|
|
91
115
|
},
|
|
92
116
|
// Phase 8 Task 5 — same bridge for annotations. PUT /_api/annotations writes
|
|
93
117
|
// the SVG blob to disk; we mirror it into the live Y.Map for collab peers.
|
|
94
|
-
onAnnotationsChanged: (file, svg) => {
|
|
118
|
+
onAnnotationsChanged: (file, svg, writeId, base) => {
|
|
119
|
+
const runtime = ctx.syncControl?.current?.();
|
|
120
|
+
const proposed = runtime?.proposeLane?.(api.fileSlug(file), 'annotations', svg, {
|
|
121
|
+
...(writeId ? { writeId } : {}),
|
|
122
|
+
...(base !== undefined ? { baseText: base } : {}),
|
|
123
|
+
});
|
|
124
|
+
if (proposed) {
|
|
125
|
+
void proposed.catch(() => {});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
95
128
|
if (collab) {
|
|
96
|
-
collab.registry.syncRoomFromAnnotations(api.fileSlug(file), svg);
|
|
129
|
+
collab.registry.syncRoomFromAnnotations(api.fileSlug(file), svg, writeId);
|
|
97
130
|
}
|
|
98
131
|
},
|
|
99
132
|
// feature-file-tree-drag-drop-folders (Task 3) — moveCanvas's collab guard
|
|
@@ -113,6 +146,13 @@ const api = createApi(ctx, {
|
|
|
113
146
|
return false;
|
|
114
147
|
}
|
|
115
148
|
},
|
|
149
|
+
proposeFolder: (op) => ctx.syncControl?.current?.()?.proposeFolder?.(op) ?? null,
|
|
150
|
+
onMetaChanged: (file, text, baseText) => {
|
|
151
|
+
const proposed = ctx.syncControl
|
|
152
|
+
?.current?.()
|
|
153
|
+
?.proposeLane?.(api.fileSlug(file), 'meta', text, baseText ? { baseText } : {});
|
|
154
|
+
if (proposed) void proposed.catch(() => {});
|
|
155
|
+
},
|
|
116
156
|
flushAndDropRoom: async (slug) => {
|
|
117
157
|
if (collab) await collab.registry.forceDrop(slug);
|
|
118
158
|
},
|
|
@@ -129,6 +169,19 @@ inspectHandle = inspects;
|
|
|
129
169
|
// arrives without a vouched session.
|
|
130
170
|
await inspects.for('').load();
|
|
131
171
|
|
|
172
|
+
// Semantic structural notifications include remote sync operations as well as
|
|
173
|
+
// API actions. Keep every session's agent/inspector context on the live path.
|
|
174
|
+
ctx.bus.on('canvas-list-update', (change) => {
|
|
175
|
+
if (!change?.rel) return;
|
|
176
|
+
const file = path.posix.join(ctx.paths.designRel, change.rel);
|
|
177
|
+
if (change.action === 'moved' && change.fromRel) {
|
|
178
|
+
const fromFile = path.posix.join(ctx.paths.designRel, change.fromRel);
|
|
179
|
+
for (const inspect of inspects.all()) inspect.retarget(fromFile, file);
|
|
180
|
+
} else if (change.action === 'removed') {
|
|
181
|
+
for (const inspect of inspects.all()) inspect.remove(file);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
132
185
|
collab = createCollab(ctx, api);
|
|
133
186
|
const aiActivity = createAiActivity(ctx);
|
|
134
187
|
|
|
@@ -145,6 +198,16 @@ ctx.bus.on('ai-activity', (payload: { file: string; entry: AiActivityEntry | nul
|
|
|
145
198
|
payload.entry ? { name: payload.entry.author, since: payload.entry.startedAt } : null
|
|
146
199
|
);
|
|
147
200
|
});
|
|
201
|
+
// T16 — an AI edit whose heartbeat went silent (the driver crashed) did not
|
|
202
|
+
// finish: whatever it wrote stays unpublished for the person's decision. An
|
|
203
|
+
// explicit /end already closed its action, so this is a no-op then.
|
|
204
|
+
ctx.bus.on('ai-activity', (payload: { file: string; entry: AiActivityEntry | null }) => {
|
|
205
|
+
if (payload.entry) return;
|
|
206
|
+
void ctx.syncControl
|
|
207
|
+
?.current?.()
|
|
208
|
+
?.endAiAction?.(`edit:${payload.file}`, 'failed')
|
|
209
|
+
?.catch(() => {});
|
|
210
|
+
});
|
|
148
211
|
const gitLifecycle = createGitLifecycle(ctx, collab.registry);
|
|
149
212
|
// Phase 13 / DDR-029 — fs-watch-driven canvas activity overlay. Subscribes to
|
|
150
213
|
// `fs:any` and emits `activity:change`; ws.ts forwards it to canvas iframes.
|