@1agh/maude 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/studio/acp/bridge.ts +18 -13
- package/apps/studio/acp/probe.ts +268 -16
- package/apps/studio/acp/transcript-io.ts +394 -0
- package/apps/studio/acp/transcript.ts +103 -38
- package/apps/studio/api.ts +139 -26
- package/apps/studio/bin/_import-figma.mjs +57 -11
- package/apps/studio/bin/_seed-fixture.mjs +163 -0
- package/apps/studio/canvas-imports.ts +89 -0
- package/apps/studio/client/app.jsx +257 -7
- package/apps/studio/client/export-center.jsx +15 -7
- package/apps/studio/client/panels/ReadinessList.jsx +7 -1
- package/apps/studio/client/panels/SyncPanel.jsx +125 -4
- package/apps/studio/client/report-bug.jsx +19 -1
- package/apps/studio/client/styles/3-shell-maude.css +34 -0
- package/apps/studio/client/styles/4-components.css +26 -0
- package/apps/studio/collab/persistence.ts +132 -16
- package/apps/studio/collab/registry.ts +10 -18
- package/apps/studio/debug-bundle.ts +13 -0
- package/apps/studio/dist/client.bundle.js +1128 -1128
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/export-dialog.tsx +54 -0
- package/apps/studio/exporters/degraded.ts +19 -3
- package/apps/studio/exporters/ghostscript.ts +194 -0
- package/apps/studio/exporters/pdf-fonts.ts +261 -0
- package/apps/studio/exporters/pdf.ts +152 -3
- package/apps/studio/exporters/remote.ts +36 -1
- package/apps/studio/fs-watch.ts +45 -1
- package/apps/studio/http.ts +7 -1
- package/apps/studio/mem.ts +45 -9
- package/apps/studio/readiness.ts +42 -7
- package/apps/studio/server.ts +11 -4
- package/apps/studio/sync/agent.ts +136 -29
- package/apps/studio/sync/asset-push.ts +1 -47
- package/apps/studio/sync/codec.ts +122 -31
- package/apps/studio/sync/cold-start-apply.ts +7 -0
- package/apps/studio/sync/cold-start.ts +118 -22
- package/apps/studio/sync/comment-identity.ts +68 -0
- package/apps/studio/sync/connection-state.ts +15 -1
- package/apps/studio/sync/file-ledger.ts +117 -0
- package/apps/studio/sync/file-plane.ts +623 -27
- package/apps/studio/sync/index.ts +711 -20
- package/apps/studio/sync/journal-client.ts +13 -1
- package/apps/studio/sync/migrate-seed.ts +40 -3
- package/apps/studio/sync/presentation.ts +26 -3
- package/apps/studio/sync/retry-after.ts +169 -0
- package/apps/studio/sync/seed-progress.ts +218 -0
- package/apps/studio/sync/status.ts +122 -5
- package/apps/studio/sync/transport-error.ts +111 -0
- package/apps/studio/whats-new.json +91 -0
- package/cli/bin/maude.mjs +2 -0
- package/cli/commands/codex.mjs +191 -0
- package/cli/commands/harness.mjs +1051 -0
- package/cli/commands/help.mjs +13 -0
- package/cli/lib/design-link.mjs +190 -2
- package/cli/lib/harness/capabilities.mjs +302 -0
- package/cli/lib/harness/codex-runtime.mjs +889 -0
- package/cli/lib/harness/compatibility.mjs +27 -0
- package/cli/lib/harness/discover-claude.mjs +1393 -0
- package/cli/lib/harness/managed-state.mjs +1296 -0
- package/cli/lib/harness/model.mjs +86 -0
- package/cli/lib/harness/secrets.mjs +390 -0
- package/cli/lib/harness/targets/codex.mjs +1141 -0
- package/cli/lib/harness/targets/opencode.mjs +807 -0
- package/cli/lib/harness/transaction.mjs +1099 -0
- package/cli/lib/hubs-config.mjs +35 -8
- package/cli/templates/harness/opencode/maude-projector.ts +58 -0
- package/docs/harness-capability-matrix.md +125 -0
- package/docs/harness-environment-projection.md +95 -0
- package/package.json +32 -9
- package/plugins/flow/.claude-plugin/config.schema.json +8 -0
- package/apps/studio/.ai/cache/_stats.json +0 -7
- package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
- package/apps/studio/bin/_curl-local.test.mjs +0 -280
- package/apps/studio/bin/_pw-launch.test.mjs +0 -90
- package/apps/studio/bin/_smart-frames.test.mjs +0 -195
- package/apps/studio/bin/_transcribe.test.mjs +0 -80
- package/apps/studio/bun.lock +0 -928
- package/apps/studio/draw/test/animate.test.ts +0 -172
- package/apps/studio/draw/test/brush.test.ts +0 -213
- package/apps/studio/draw/test/composition.test.ts +0 -141
- package/apps/studio/draw/test/geometry.test.ts +0 -199
- package/apps/studio/draw/test/gradient.test.ts +0 -167
- package/apps/studio/draw/test/layout.test.ts +0 -120
- package/apps/studio/draw/test/morph.test.ts +0 -107
- package/apps/studio/draw/test/optimize.test.ts +0 -40
- package/apps/studio/draw/test/palette.test.ts +0 -123
- package/apps/studio/draw/test/primitives.test.ts +0 -129
- package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
- package/apps/studio/draw/test/serialize.test.ts +0 -105
- package/apps/studio/figma/assets.test.ts +0 -464
- package/apps/studio/figma/client.test.ts +0 -395
- package/apps/studio/figma/codegen-client.test.ts +0 -276
- package/apps/studio/figma/codegen-fonts.test.ts +0 -103
- package/apps/studio/figma/codegen-values.test.ts +0 -179
- package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
- package/apps/studio/figma/fig-decode.test.ts +0 -788
- package/apps/studio/figma/fig-differential.test.ts +0 -182
- package/apps/studio/figma/fig-translator.test.ts +0 -192
- package/apps/studio/figma/fig-vector.test.ts +0 -113
- package/apps/studio/figma/from-codegen.test.ts +0 -408
- package/apps/studio/figma/sanitize.test.ts +0 -325
- package/apps/studio/figma/tailwind-map.test.ts +0 -142
- package/apps/studio/figma/to-artboard.test.ts +0 -808
- package/apps/studio/figma/to-render.test.ts +0 -180
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
- package/apps/studio/figma/to-strokes.test.ts +0 -705
- package/apps/studio/figma/to-tokens.test.ts +0 -321
- package/apps/studio/figma/url.test.ts +0 -167
- package/apps/studio/footage/schema.test.ts +0 -287
- package/apps/studio/generation/adapters/groq.test.ts +0 -80
- package/apps/studio/generation/audio-library.test.ts +0 -95
- package/apps/studio/generation/captions.test.ts +0 -78
- package/apps/studio/generation/elevenlabs.test.ts +0 -223
- package/apps/studio/generation/gemini.test.ts +0 -350
- package/apps/studio/generation/jobs.test.ts +0 -128
- package/apps/studio/generation/keys.test.ts +0 -75
- package/apps/studio/generation/prefs.test.ts +0 -95
- package/apps/studio/generation/types.test.ts +0 -123
- package/apps/studio/generation/whisper-models.test.ts +0 -179
- package/apps/studio/test/_helpers.ts +0 -108
- package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
- package/apps/studio/test/acp-activity.test.ts +0 -154
- package/apps/studio/test/acp-ai-activity.test.ts +0 -182
- package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
- package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
- package/apps/studio/test/acp-branch-guard.test.ts +0 -123
- package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
- package/apps/studio/test/acp-bridge.test.ts +0 -301
- package/apps/studio/test/acp-capabilities.test.ts +0 -123
- package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
- package/apps/studio/test/acp-commands.test.ts +0 -119
- package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
- package/apps/studio/test/acp-elicitation.test.ts +0 -251
- package/apps/studio/test/acp-env.test.ts +0 -95
- package/apps/studio/test/acp-mode-banner.test.ts +0 -45
- package/apps/studio/test/acp-origin-gate.test.ts +0 -160
- package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
- package/apps/studio/test/acp-permission.test.ts +0 -278
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
- package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
- package/apps/studio/test/acp-session-plugins.test.ts +0 -209
- package/apps/studio/test/acp-toolgroup.test.ts +0 -76
- package/apps/studio/test/acp-transcript-view.test.ts +0 -71
- package/apps/studio/test/acp-transcript.test.ts +0 -238
- package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
- package/apps/studio/test/acp-usage.test.ts +0 -143
- package/apps/studio/test/acp-write-gate.test.ts +0 -323
- package/apps/studio/test/acp-write-scope.test.ts +0 -533
- package/apps/studio/test/active-state.test.ts +0 -186
- package/apps/studio/test/activity.test.ts +0 -189
- package/apps/studio/test/ai-activity.test.ts +0 -113
- package/apps/studio/test/annotate-write.test.ts +0 -1074
- package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
- package/apps/studio/test/annotations-align.test.ts +0 -88
- package/apps/studio/test/annotations-api.test.ts +0 -145
- package/apps/studio/test/annotations-bindings.test.ts +0 -262
- package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
- package/apps/studio/test/annotations-groups.test.ts +0 -231
- package/apps/studio/test/annotations-layer.test.ts +0 -1011
- package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
- package/apps/studio/test/annotations-snap.test.ts +0 -135
- package/apps/studio/test/annotations-text-format.test.ts +0 -396
- package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
- package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
- package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
- package/apps/studio/test/artboard-kinds.test.tsx +0 -83
- package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
- package/apps/studio/test/asset-api.test.ts +0 -149
- package/apps/studio/test/assets-s3.test.ts +0 -249
- package/apps/studio/test/binary-smoke.test.ts +0 -47
- package/apps/studio/test/boot-self-heal.test.ts +0 -87
- package/apps/studio/test/browse-posture.test.tsx +0 -107
- package/apps/studio/test/bundle-smoke.test.ts +0 -46
- package/apps/studio/test/camera-reveal.test.tsx +0 -173
- package/apps/studio/test/canvas-artifacts.test.ts +0 -125
- package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
- package/apps/studio/test/canvas-build.test.ts +0 -141
- package/apps/studio/test/canvas-create-api.test.ts +0 -676
- package/apps/studio/test/canvas-cursors.test.ts +0 -164
- package/apps/studio/test/canvas-edit.test.ts +0 -470
- package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
- package/apps/studio/test/canvas-header.test.ts +0 -127
- package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
- package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
- package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
- package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
- package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
- package/apps/studio/test/canvas-list-watch.test.ts +0 -388
- package/apps/studio/test/canvas-media-drop.test.ts +0 -187
- package/apps/studio/test/canvas-meta-api.test.ts +0 -707
- package/apps/studio/test/canvas-move-api.test.ts +0 -587
- package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
- package/apps/studio/test/canvas-pipeline.test.ts +0 -180
- package/apps/studio/test/canvas-rects.test.ts +0 -198
- package/apps/studio/test/canvas-reorder.test.ts +0 -211
- package/apps/studio/test/canvas-route.test.ts +0 -179
- package/apps/studio/test/canvas-shell-base.test.ts +0 -107
- package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
- package/apps/studio/test/canvas-url.test.ts +0 -138
- package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
- package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
- package/apps/studio/test/capture-core.test.ts +0 -32
- package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
- package/apps/studio/test/chat-attachments.test.ts +0 -117
- package/apps/studio/test/chat-context.test.ts +0 -129
- package/apps/studio/test/chat-markdown.test.tsx +0 -58
- package/apps/studio/test/clip-addressing.test.ts +0 -738
- package/apps/studio/test/clip-ops.test.ts +0 -922
- package/apps/studio/test/cloud-build.test.ts +0 -95
- package/apps/studio/test/cloud-connect-note.test.ts +0 -135
- package/apps/studio/test/cloud-endpoints.test.ts +0 -590
- package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
- package/apps/studio/test/cloud-history-posture.test.ts +0 -230
- package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
- package/apps/studio/test/cloud-renew.test.ts +0 -205
- package/apps/studio/test/cloud-session-role.test.ts +0 -161
- package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
- package/apps/studio/test/cold-start-apply.test.ts +0 -303
- package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
- package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
- package/apps/studio/test/collab-bridge.test.ts +0 -79
- package/apps/studio/test/collab-loopback.test.ts +0 -63
- package/apps/studio/test/collab-origin-gate.test.ts +0 -323
- package/apps/studio/test/collab-protocol.test.ts +0 -146
- package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
- package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
- package/apps/studio/test/collab-room.test.ts +0 -188
- package/apps/studio/test/collab-session-survival.test.tsx +0 -176
- package/apps/studio/test/collab-stress.test.ts +0 -129
- package/apps/studio/test/comment-mount.test.ts +0 -97
- package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
- package/apps/studio/test/comments-api.test.ts +0 -277
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
- package/apps/studio/test/comments-overlay.test.ts +0 -117
- package/apps/studio/test/compile-entry.test.ts +0 -133
- package/apps/studio/test/component-map.test.ts +0 -48
- package/apps/studio/test/config-projection.test.ts +0 -104
- package/apps/studio/test/config-reload.test.ts +0 -230
- package/apps/studio/test/config-version.test.ts +0 -88
- package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
- package/apps/studio/test/convert-to-absolute.test.ts +0 -333
- package/apps/studio/test/credential-grammar.test.ts +0 -107
- package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
- package/apps/studio/test/csrf-write-guard.test.ts +0 -141
- package/apps/studio/test/debug-bundle.test.ts +0 -105
- package/apps/studio/test/design-setup-readiness.test.ts +0 -155
- package/apps/studio/test/detach-component.test.ts +0 -94
- package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
- package/apps/studio/test/dom-selection.test.ts +0 -198
- package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
- package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
- package/apps/studio/test/edit-persistence.test.ts +0 -91
- package/apps/studio/test/edit-scope-api.test.ts +0 -119
- package/apps/studio/test/edit-source-command.test.ts +0 -142
- package/apps/studio/test/edit-suppress.test.ts +0 -170
- package/apps/studio/test/editing-presence.test.ts +0 -103
- package/apps/studio/test/element-resize.test.ts +0 -136
- package/apps/studio/test/element-structural-api.test.ts +0 -434
- package/apps/studio/test/element-structural-edit.test.ts +0 -750
- package/apps/studio/test/ensure-browser.test.ts +0 -92
- package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
- package/apps/studio/test/export-assemble.test.ts +0 -53
- package/apps/studio/test/export-browser-lane.test.ts +0 -126
- package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
- package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
- package/apps/studio/test/export-center.test.tsx +0 -287
- package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
- package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
- package/apps/studio/test/export-lane.test.ts +0 -245
- package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
- package/apps/studio/test/exporters/canva.test.ts +0 -63
- package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
- package/apps/studio/test/exporters/endpoint.test.ts +0 -121
- package/apps/studio/test/exporters/history.test.ts +0 -107
- package/apps/studio/test/exporters/html.test.ts +0 -26
- package/apps/studio/test/exporters/jobs.test.ts +0 -342
- package/apps/studio/test/exporters/pdf.test.ts +0 -85
- package/apps/studio/test/exporters/png.test.ts +0 -103
- package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
- package/apps/studio/test/exporters/pptx.test.ts +0 -31
- package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
- package/apps/studio/test/exporters/runtime.test.ts +0 -59
- package/apps/studio/test/exporters/scope.test.ts +0 -292
- package/apps/studio/test/exporters/svg.test.ts +0 -29
- package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
- package/apps/studio/test/exporters/zip.test.ts +0 -104
- package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
- package/apps/studio/test/figjam-v3-model.test.ts +0 -342
- package/apps/studio/test/figma-explode.test.ts +0 -438
- package/apps/studio/test/figma-provenance.test.ts +0 -108
- package/apps/studio/test/figma-routes.test.ts +0 -294
- package/apps/studio/test/file-lock.test.ts +0 -84
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -13
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
- package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
- package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
- package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
- package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
- package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
- package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
- package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
- package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
- package/apps/studio/test/footage-store.test.ts +0 -100
- package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
- package/apps/studio/test/fs-watch.test.ts +0 -41
- package/apps/studio/test/gemma-models.test.ts +0 -245
- package/apps/studio/test/generate-route.test.ts +0 -106
- package/apps/studio/test/git-api.test.ts +0 -0
- package/apps/studio/test/git-branches.test.ts +0 -341
- package/apps/studio/test/git-cloud-posture.test.ts +0 -59
- package/apps/studio/test/git-grouping.test.ts +0 -106
- package/apps/studio/test/git-lifecycle.test.ts +0 -100
- package/apps/studio/test/git-log-format.test.ts +0 -95
- package/apps/studio/test/git-safe-rel.test.ts +0 -132
- package/apps/studio/test/git-system-engine.test.ts +0 -135
- package/apps/studio/test/git-watch.test.ts +0 -97
- package/apps/studio/test/github-api.test.ts +0 -577
- package/apps/studio/test/grid-track-handles.test.ts +0 -160
- package/apps/studio/test/handoff-static-frames.test.ts +0 -215
- package/apps/studio/test/handoff.test.ts +0 -329
- package/apps/studio/test/history-rollback.test.ts +0 -88
- package/apps/studio/test/hmr-broadcast.test.ts +0 -236
- package/apps/studio/test/hmr-classify.test.ts +0 -87
- package/apps/studio/test/hub-link.test.ts +0 -80
- package/apps/studio/test/identity-cache.test.ts +0 -83
- package/apps/studio/test/import-asset-browser.test.ts +0 -64
- package/apps/studio/test/import-asset-route.test.ts +0 -71
- package/apps/studio/test/import-asset.test.ts +0 -427
- package/apps/studio/test/import-brand-browser.test.ts +0 -88
- package/apps/studio/test/import-brand-route.test.ts +0 -120
- package/apps/studio/test/import-brand.test.ts +0 -206
- package/apps/studio/test/import-figma.test.ts +0 -667
- package/apps/studio/test/import-tokens.test.ts +0 -722
- package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
- package/apps/studio/test/input-router.test.ts +0 -757
- package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
- package/apps/studio/test/inspect-selections.test.ts +0 -219
- package/apps/studio/test/knob-props-authored.test.ts +0 -87
- package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
- package/apps/studio/test/locator.test.ts +0 -214
- package/apps/studio/test/marquee-overlay.test.ts +0 -94
- package/apps/studio/test/media-commit-chain.test.ts +0 -210
- package/apps/studio/test/mode-toggle.test.tsx +0 -226
- package/apps/studio/test/motion-sample.test.ts +0 -35
- package/apps/studio/test/move-artboards-command.test.ts +0 -108
- package/apps/studio/test/participants-chrome.test.ts +0 -65
- package/apps/studio/test/paths.test.ts +0 -88
- package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
- package/apps/studio/test/perf-harness.ts +0 -193
- package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
- package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
- package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
- package/apps/studio/test/photo-edit-api.test.ts +0 -201
- package/apps/studio/test/photo-filters.test.ts +0 -149
- package/apps/studio/test/photo-pipeline.test.ts +0 -106
- package/apps/studio/test/photo-taxonomy.test.ts +0 -96
- package/apps/studio/test/print-marks.test.ts +0 -113
- package/apps/studio/test/print-units.test.ts +0 -173
- package/apps/studio/test/read-annotations.test.ts +0 -727
- package/apps/studio/test/read-only-gate.test.ts +0 -188
- package/apps/studio/test/read-only-role.test.ts +0 -95
- package/apps/studio/test/readiness.test.ts +0 -226
- package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
- package/apps/studio/test/reorder-api.test.ts +0 -210
- package/apps/studio/test/repo-concurrency.test.ts +0 -146
- package/apps/studio/test/repo-lock.test.ts +0 -350
- package/apps/studio/test/report-proxy.test.ts +0 -125
- package/apps/studio/test/ripple.test.ts +0 -197
- package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
- package/apps/studio/test/runtime-bundle.test.ts +0 -69
- package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
- package/apps/studio/test/scaffold-design.test.ts +0 -122
- package/apps/studio/test/server-lifecycle.test.ts +0 -38
- package/apps/studio/test/session-runtime-state.test.ts +0 -226
- package/apps/studio/test/session-scope.test.ts +0 -100
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
- package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
- package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
- package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
- package/apps/studio/test/shared-doc-projection.test.ts +0 -238
- package/apps/studio/test/shell-importmap.test.ts +0 -56
- package/apps/studio/test/sizing-mode.test.ts +0 -102
- package/apps/studio/test/slash-commands.test.ts +0 -117
- package/apps/studio/test/snap-distance-pill.test.ts +0 -68
- package/apps/studio/test/spacing-handles.test.ts +0 -138
- package/apps/studio/test/specimen-select.test.ts +0 -88
- package/apps/studio/test/sync-agent.test.ts +0 -660
- package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
- package/apps/studio/test/sync-asset-push.test.ts +0 -931
- package/apps/studio/test/sync-atomic-write.test.ts +0 -62
- package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
- package/apps/studio/test/sync-autocommit.test.ts +0 -537
- package/apps/studio/test/sync-canvas-path.test.ts +0 -200
- package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
- package/apps/studio/test/sync-codec.test.ts +0 -230
- package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
- package/apps/studio/test/sync-cold-start.test.ts +0 -304
- package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
- package/apps/studio/test/sync-connection-state.test.ts +0 -337
- package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
- package/apps/studio/test/sync-decide-file.test.ts +0 -420
- package/apps/studio/test/sync-doc-name.test.ts +0 -281
- package/apps/studio/test/sync-echo-guard.test.ts +0 -96
- package/apps/studio/test/sync-file-ledger.test.ts +0 -334
- package/apps/studio/test/sync-file-membership.test.ts +0 -347
- package/apps/studio/test/sync-file-plane.test.ts +0 -976
- package/apps/studio/test/sync-file-pull.test.ts +0 -333
- package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
- package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
- package/apps/studio/test/sync-hardening.test.ts +0 -586
- package/apps/studio/test/sync-hub-listing.test.ts +0 -46
- package/apps/studio/test/sync-hubs-config.test.ts +0 -133
- package/apps/studio/test/sync-incident-replay.test.ts +0 -211
- package/apps/studio/test/sync-journal.test.ts +0 -176
- package/apps/studio/test/sync-meta-codec.test.ts +0 -199
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
- package/apps/studio/test/sync-move-retirement.test.ts +0 -231
- package/apps/studio/test/sync-panel-surface.test.ts +0 -153
- package/apps/studio/test/sync-path-pull.test.ts +0 -531
- package/apps/studio/test/sync-presentation.test.ts +0 -262
- package/apps/studio/test/sync-pull-budget.test.ts +0 -169
- package/apps/studio/test/sync-remote-docs.test.ts +0 -333
- package/apps/studio/test/sync-resync-routes.test.ts +0 -168
- package/apps/studio/test/sync-runtime.test.ts +0 -1675
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
- package/apps/studio/test/sync-settings-routes.test.ts +0 -195
- package/apps/studio/test/sync-settings.test.ts +0 -151
- package/apps/studio/test/sync-status.test.ts +0 -261
- package/apps/studio/test/sync-supervisor.test.ts +0 -262
- package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
- package/apps/studio/test/sync-trash.test.ts +0 -132
- package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
- package/apps/studio/test/sync-untrusted.test.ts +0 -103
- package/apps/studio/test/system-endpoint.test.ts +0 -144
- package/apps/studio/test/text-editability-stamp.test.ts +0 -131
- package/apps/studio/test/timeline-comp-target.test.ts +0 -139
- package/apps/studio/test/timeline-media-cache.test.ts +0 -41
- package/apps/studio/test/timeline-parse.test.ts +0 -184
- package/apps/studio/test/timeline-scale.test.ts +0 -65
- package/apps/studio/test/timeline-snap.test.ts +0 -85
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
- package/apps/studio/test/tool-palette.test.tsx +0 -55
- package/apps/studio/test/tour-overlay.test.tsx +0 -90
- package/apps/studio/test/trusted-request-host.test.ts +0 -66
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
- package/apps/studio/test/undo-stack.test.ts +0 -244
- package/apps/studio/test/use-agent-presence.test.tsx +0 -117
- package/apps/studio/test/use-annotation-resize.test.ts +0 -402
- package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
- package/apps/studio/test/use-artboard-drag.test.ts +0 -324
- package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
- package/apps/studio/test/use-collab.test.ts +0 -0
- package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
- package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
- package/apps/studio/test/use-selection-set.test.tsx +0 -166
- package/apps/studio/test/use-snap-guides.test.ts +0 -271
- package/apps/studio/test/use-tool-mode.test.tsx +0 -186
- package/apps/studio/test/use-undo-stack.test.tsx +0 -223
- package/apps/studio/test/video-asset.test.ts +0 -163
- package/apps/studio/test/video-comp-fixture.test.ts +0 -50
- package/apps/studio/test/video-comp.test.ts +0 -270
- package/apps/studio/test/video-encode-lib.test.ts +0 -63
- package/apps/studio/test/video-render-bridge.test.ts +0 -171
- package/apps/studio/test/whats-new.test.ts +0 -113
- package/apps/studio/test/whisper-setup.test.ts +0 -97
- package/apps/studio/test/workspace-containment.test.ts +0 -382
- package/apps/studio/test/workspace-signin.test.ts +0 -292
- package/apps/studio/test/ws-handshake.test.ts +0 -33
- package/cli/commands/cache.test.mjs +0 -166
- package/cli/commands/design-link.test.mjs +0 -419
- package/cli/commands/design.test.mjs +0 -240
- package/cli/commands/doctor.test.mjs +0 -237
- package/cli/commands/hub-workspace.test.mjs +0 -275
- package/cli/commands/hub.test.mjs +0 -225
- package/cli/commands/kg.test.mjs +0 -142
- package/cli/commands/preflight.test.mjs +0 -46
- package/cli/lib/argv.test.mjs +0 -46
- package/cli/lib/cache.test.mjs +0 -303
- package/cli/lib/cell-plan.test.mjs +0 -225
- package/cli/lib/config-lint.test.mjs +0 -117
- package/cli/lib/ddr-to-kgai.test.mjs +0 -118
- package/cli/lib/design-ownership.test.mjs +0 -329
- package/cli/lib/fetch-asset.test.mjs +0 -213
- package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
- package/cli/lib/figma-import-controls.test.mjs +0 -70
- package/cli/lib/flow-design-integration.test.mjs +0 -165
- package/cli/lib/gitignore-block.test.mjs +0 -136
- package/cli/lib/gitignore-drift.test.mjs +0 -156
- package/cli/lib/hubs-config.test.mjs +0 -165
- package/cli/lib/pkg-root.test.mjs +0 -111
- package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
- package/cli/lib/plugin-name-namespace.test.mjs +0 -71
- package/cli/lib/reconstruct-toolset.test.mjs +0 -194
- package/cli/lib/stack-detect.test.mjs +0 -121
- package/cli/lib/update-check.test.mjs +0 -32
- package/cli/lib/workspace-plan.test.mjs +0 -699
|
@@ -1218,6 +1218,37 @@ const PDF_DPI_OPTIONS = [
|
|
|
1218
1218
|
];
|
|
1219
1219
|
const PDF_DPI_DEFAULT = 'auto';
|
|
1220
1220
|
|
|
1221
|
+
// issue #116 — how the export treats text. Mirrors export-dialog.tsx's
|
|
1222
|
+
// PDF_TEXT_OPTIONS (same mirror obligation as PDF_DPI_OPTIONS above).
|
|
1223
|
+
//
|
|
1224
|
+
// The list is FIXED regardless of whether Ghostscript is present on this
|
|
1225
|
+
// machine. Hiding "Convert to outlines" when gs is missing would need a new
|
|
1226
|
+
// capability route, and would answer the user's question ("can I send this to
|
|
1227
|
+
// a printer?") by making the answer invisible; a refusal that names the
|
|
1228
|
+
// one-line install is more honest and reaches them at the moment they care.
|
|
1229
|
+
const PDF_TEXT_OPTIONS = [
|
|
1230
|
+
{
|
|
1231
|
+
id: 'keep',
|
|
1232
|
+
label: 'Keep selectable (default)',
|
|
1233
|
+
description:
|
|
1234
|
+
'Text stays selectable and searchable. You are warned if a font came out unprintable.',
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
id: 'embed',
|
|
1238
|
+
label: 'Verify fonts embedded',
|
|
1239
|
+
description:
|
|
1240
|
+
'Same file, but the export fails instead of shipping a font a print shop would reject.',
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
id: 'outline',
|
|
1244
|
+
label: 'Convert to outlines (print-safe)',
|
|
1245
|
+
description:
|
|
1246
|
+
'Every glyph becomes a vector path — no fonts left to break. Text is no longer selectable ' +
|
|
1247
|
+
'and the file can grow a lot. Needs Ghostscript installed locally; cloud workspaces have it.',
|
|
1248
|
+
},
|
|
1249
|
+
];
|
|
1250
|
+
const PDF_TEXT_DEFAULT = 'keep';
|
|
1251
|
+
|
|
1221
1252
|
// feature-bulk-media-insert — best-effort MIME guess from a filename extension.
|
|
1222
1253
|
// Only used to classify a natively-picked file (Rust returns `{name, bytes}`,
|
|
1223
1254
|
// no type) for the destination-toggle's image/video/audio split; the actual
|
|
@@ -1602,6 +1633,7 @@ function ExportDialog({
|
|
|
1602
1633
|
const [pdfMarksCrop, setPdfMarksCrop] = useState(false);
|
|
1603
1634
|
const [pdfMarksRegistration, setPdfMarksRegistration] = useState(false);
|
|
1604
1635
|
const [pdfDpiId, setPdfDpiId] = useState(PDF_DPI_DEFAULT);
|
|
1636
|
+
const [pdfTextId, setPdfTextId] = useState(PDF_TEXT_DEFAULT);
|
|
1605
1637
|
// DDR-148 addendum — mp4/webm of a registered video-comp render through
|
|
1606
1638
|
// renderMediaOnWeb, which produces real audio (Remotion owns the
|
|
1607
1639
|
// TransitionSeries/volume-closure timeline). gif has no audio track at all
|
|
@@ -1714,6 +1746,10 @@ function ExportDialog({
|
|
|
1714
1746
|
// itself stays vector regardless of this.
|
|
1715
1747
|
const pdfDpi = PDF_DPI_OPTIONS.find((d) => d.id === pdfDpiId)?.value;
|
|
1716
1748
|
if (pdfDpi !== undefined) options.dpi = pdfDpi;
|
|
1749
|
+
// issue #116 — omitted for `keep` rather than sent explicitly: the
|
|
1750
|
+
// adapter's default IS keep, so an untouched dialog produces the exact
|
|
1751
|
+
// request body it did before this feature existed.
|
|
1752
|
+
if (pdfTextId !== 'keep') options.text = pdfTextId;
|
|
1717
1753
|
}
|
|
1718
1754
|
// Scope targeting hints (resolveScope reads these): `artboardId` makes
|
|
1719
1755
|
// "Active artboard" export the right screen instead of `:first-of-type`;
|
|
@@ -2022,6 +2058,27 @@ function ExportDialog({
|
|
|
2022
2058
|
The page stays vector; this only sets the capture density for raster content on it
|
|
2023
2059
|
(dropped photos, large-format art).
|
|
2024
2060
|
</div>
|
|
2061
|
+
<div className="st-dialog-row">
|
|
2062
|
+
<label className="st-dialog-lbl" htmlFor="st-export-pdf-text">
|
|
2063
|
+
Text
|
|
2064
|
+
</label>
|
|
2065
|
+
<select
|
|
2066
|
+
id="st-export-pdf-text"
|
|
2067
|
+
className="st-select"
|
|
2068
|
+
data-testid="export-pdf-text"
|
|
2069
|
+
value={pdfTextId}
|
|
2070
|
+
onChange={(e) => setPdfTextId(e.target.value)}
|
|
2071
|
+
>
|
|
2072
|
+
{PDF_TEXT_OPTIONS.map((t) => (
|
|
2073
|
+
<option key={t.id} value={t.id}>
|
|
2074
|
+
{t.label}
|
|
2075
|
+
</option>
|
|
2076
|
+
))}
|
|
2077
|
+
</select>
|
|
2078
|
+
</div>
|
|
2079
|
+
<div className="st-mono" style={{ fontSize: 11, color: 'var(--fg-3)' }}>
|
|
2080
|
+
{PDF_TEXT_OPTIONS.find((t) => t.id === pdfTextId)?.description}
|
|
2081
|
+
</div>
|
|
2025
2082
|
<div className="st-dialog-row">
|
|
2026
2083
|
<label
|
|
2027
2084
|
className="st-dialog-lbl"
|
|
@@ -4548,6 +4605,10 @@ function Viewport({
|
|
|
4548
4605
|
cfg,
|
|
4549
4606
|
loadingPath,
|
|
4550
4607
|
onIframeLoad,
|
|
4608
|
+
canvasError,
|
|
4609
|
+
canvasReloadNonce,
|
|
4610
|
+
onRetryCanvasLoad,
|
|
4611
|
+
loadedPath,
|
|
4551
4612
|
showQuickSetup,
|
|
4552
4613
|
onStartQuickSetup,
|
|
4553
4614
|
previewPath,
|
|
@@ -4564,8 +4625,21 @@ function Viewport({
|
|
|
4564
4625
|
useEffect(() => {
|
|
4565
4626
|
if (previewPath) previewRef.current?.focus();
|
|
4566
4627
|
}, [previewPath]);
|
|
4628
|
+
// One observable word for "what is the canvas pane actually doing" — the
|
|
4629
|
+
// top-frame signal the #115 E2E scenario waits on, and the only place these
|
|
4630
|
+
// three states are named together. `ready` is `dgn:'loaded'`-backed, so it
|
|
4631
|
+
// cannot be faked by a timer expiring (which is exactly how the bug used to
|
|
4632
|
+
// look successful: skeleton gone, pane white).
|
|
4633
|
+
const canvasState =
|
|
4634
|
+
canvasError && canvasError.path === activePath
|
|
4635
|
+
? 'error'
|
|
4636
|
+
: activePath && activePath !== SYSTEM_TAB && loadedPath === activePath
|
|
4637
|
+
? 'ready'
|
|
4638
|
+
: loadingPath && loadingPath === activePath
|
|
4639
|
+
? 'loading'
|
|
4640
|
+
: 'idle';
|
|
4567
4641
|
return (
|
|
4568
|
-
<div className="viewport st-stage" data-tour="viewport">
|
|
4642
|
+
<div className="viewport st-stage" data-tour="viewport" data-canvas-state={canvasState}>
|
|
4569
4643
|
{previewPath && (
|
|
4570
4644
|
// feature-studio-file-preview — an overlay, not a tab: the canvas
|
|
4571
4645
|
// iframe (if any) stays mounted underneath so switching back to it
|
|
@@ -4638,7 +4712,10 @@ function Viewport({
|
|
|
4638
4712
|
}
|
|
4639
4713
|
return (
|
|
4640
4714
|
<iframe
|
|
4641
|
-
key
|
|
4715
|
+
// The nonce is part of the key ONLY so the #115 Retry can force a
|
|
4716
|
+
// remount; it is otherwise constant, so normal switching keys on the
|
|
4717
|
+
// path exactly as before.
|
|
4718
|
+
key={`${t.path}#${canvasReloadNonce}`}
|
|
4642
4719
|
ref={(el) => registerIframe(t.path, el)}
|
|
4643
4720
|
src={canvasUrl(t.path, cfg)}
|
|
4644
4721
|
className={t.path === activePath ? 'active' : ''}
|
|
@@ -4669,6 +4746,45 @@ function Viewport({
|
|
|
4669
4746
|
</div>
|
|
4670
4747
|
</div>
|
|
4671
4748
|
)}
|
|
4749
|
+
{canvasError && canvasError.path === activePath && (
|
|
4750
|
+
// issue #115 — what the blank pane used to be. Names which of the two
|
|
4751
|
+
// failures happened and offers the recovery that used to require
|
|
4752
|
+
// quitting the app (or knowing that switching projects and back
|
|
4753
|
+
// re-reads /_config).
|
|
4754
|
+
<div className="st-canvas-error" role="alert" data-testid="canvas-load-error">
|
|
4755
|
+
<div className="st-canvas-error-card">
|
|
4756
|
+
<div className="st-canvas-error-title">
|
|
4757
|
+
{canvasError.kind === 'server'
|
|
4758
|
+
? "Maude's server isn't responding"
|
|
4759
|
+
: "This canvas didn't finish loading"}
|
|
4760
|
+
</div>
|
|
4761
|
+
<div className="st-canvas-error-body">
|
|
4762
|
+
{canvasError.kind === 'server' ? (
|
|
4763
|
+
<>
|
|
4764
|
+
The canvas couldn't be reached. This usually means Maude's
|
|
4765
|
+
server restarted underneath this window — your files on disk
|
|
4766
|
+
are untouched.
|
|
4767
|
+
</>
|
|
4768
|
+
) : (
|
|
4769
|
+
<>
|
|
4770
|
+
The server is up, but{' '}
|
|
4771
|
+
<code>{sanitizeDisplayText(basename(canvasError.path))}</code>{' '}
|
|
4772
|
+
never finished compiling. Its own error, if it has one, is in
|
|
4773
|
+
the canvas frame.
|
|
4774
|
+
</>
|
|
4775
|
+
)}
|
|
4776
|
+
</div>
|
|
4777
|
+
<button
|
|
4778
|
+
type="button"
|
|
4779
|
+
className="btn btn--primary"
|
|
4780
|
+
data-testid="canvas-load-retry"
|
|
4781
|
+
onClick={() => onRetryCanvasLoad?.(canvasError.path)}
|
|
4782
|
+
>
|
|
4783
|
+
Reload canvas
|
|
4784
|
+
</button>
|
|
4785
|
+
</div>
|
|
4786
|
+
</div>
|
|
4787
|
+
)}
|
|
4672
4788
|
</div>
|
|
4673
4789
|
);
|
|
4674
4790
|
}
|
|
@@ -9763,6 +9879,47 @@ function App() {
|
|
|
9763
9879
|
// Phase 9 Task 8 — hub-down offline mode banner. Driven by the 'sync:status'
|
|
9764
9880
|
// WS message the linked-mode sync runtime emits. null in solo mode.
|
|
9765
9881
|
const [syncStatus, setSyncStatus] = useState(null);
|
|
9882
|
+
// feature-large-project-seed — the NATIVE half of seed progress.
|
|
9883
|
+
//
|
|
9884
|
+
// A seed against a large project is minutes to hours of work, and the target
|
|
9885
|
+
// user (DDR-177) never opens a terminal. The Sync panel is the detail view;
|
|
9886
|
+
// this is what reaches them when the panel is not on screen: the window
|
|
9887
|
+
// title while it runs, and ONE notification per phase transition.
|
|
9888
|
+
//
|
|
9889
|
+
// Per TRANSITION, never per file. A 2 961-file seed must produce two
|
|
9890
|
+
// notifications, not 2 961 — `send_notification` throttles on the Rust side
|
|
9891
|
+
// too, but a client that leans on that is a client that would spam a plain
|
|
9892
|
+
// browser tab through the Web fallback.
|
|
9893
|
+
const seedPhaseRef = useRef(null);
|
|
9894
|
+
useEffect(() => {
|
|
9895
|
+
const p = syncStatus?.files?.progress;
|
|
9896
|
+
if (!p) return;
|
|
9897
|
+
const prev = seedPhaseRef.current;
|
|
9898
|
+
seedPhaseRef.current = p.phase;
|
|
9899
|
+
if (prev === null || prev === p.phase) return;
|
|
9900
|
+
if (p.phase === 'converged' && (prev === 'seeding' || prev === 'paused')) {
|
|
9901
|
+
notifyDesktop('Project synced', `${p.delivered} files are up to date.`);
|
|
9902
|
+
} else if (p.phase === 'blocked') {
|
|
9903
|
+
const total = (p.blocked ?? []).reduce((n, b) => n + b.count, 0);
|
|
9904
|
+
notifyDesktop(
|
|
9905
|
+
'Sync needs a decision',
|
|
9906
|
+
`${total} file${total === 1 ? '' : 's'} could not be sent. Open the Sync panel for the reason.`
|
|
9907
|
+
);
|
|
9908
|
+
}
|
|
9909
|
+
}, [syncStatus?.files?.progress]);
|
|
9910
|
+
// The title carries the count while a seed runs, and is restored afterwards —
|
|
9911
|
+
// it is the one surface visible without opening anything.
|
|
9912
|
+
useEffect(() => {
|
|
9913
|
+
if (typeof document === 'undefined') return undefined;
|
|
9914
|
+
const p = syncStatus?.files?.progress;
|
|
9915
|
+
const base = document.title.replace(/\s+—\s+syncing\s+\d+\/\d+$/, '');
|
|
9916
|
+
if (p && (p.phase === 'seeding' || p.phase === 'paused') && p.tracked > 0) {
|
|
9917
|
+
document.title = `${base} — syncing ${p.delivered}/${p.tracked}`;
|
|
9918
|
+
} else {
|
|
9919
|
+
document.title = base;
|
|
9920
|
+
}
|
|
9921
|
+
return undefined;
|
|
9922
|
+
}, [syncStatus?.files?.progress]);
|
|
9766
9923
|
// DDR-218 — the folder's cloud link ({url, credentialed} | null), lifted from
|
|
9767
9924
|
// CloudBar (status resolve / attach / detach). Gates the GitPanel's
|
|
9768
9925
|
// cloud-managed posture; linked-but-uncredentialed keeps the full panel.
|
|
@@ -9790,6 +9947,24 @@ function App() {
|
|
|
9790
9947
|
// Canvas-compile skeleton (single-canvas model → one path at a time).
|
|
9791
9948
|
const [loadingPath, setLoadingPath] = useState(null);
|
|
9792
9949
|
const loadFallbackTimer = useRef(null);
|
|
9950
|
+
// issue #115 — a canvas that never reported `loaded`. `{ path, kind }`, where
|
|
9951
|
+
// kind is 'server' (the canvas origin did not answer /_health — a dead or
|
|
9952
|
+
// respawned sidecar) or 'compile' (the origin is up, the canvas itself never
|
|
9953
|
+
// mounted). Rendered instead of the blank pane the cap used to leave behind.
|
|
9954
|
+
const [canvasError, setCanvasError] = useState(null);
|
|
9955
|
+
// Bumped by the error panel's Retry. Folded into the iframe `key` so a retry
|
|
9956
|
+
// REMOUNTS the frame — re-setting `src` to the identical URL would not
|
|
9957
|
+
// re-navigate, and after a respawn the URL is identical in every case except
|
|
9958
|
+
// the port that `loadServerConfig()` is about to correct.
|
|
9959
|
+
const [canvasReloadNonce, setCanvasReloadNonce] = useState(0);
|
|
9960
|
+
// The canvas whose SHELL DOCUMENT has actually loaded, per its `dgn:'loaded'`
|
|
9961
|
+
// post. Distinct from `!loadingPath`, which the 2.5 s onLoad fallback and the
|
|
9962
|
+
// 15 s cap also clear — this one only ever means "the shell ran". That makes
|
|
9963
|
+
// it the honest signal for `data-canvas-state` below, and the one the #115 E2E
|
|
9964
|
+
// scenario asserts: the shell's inline script posts it whether or not the
|
|
9965
|
+
// canvas TSX went on to build, so it isolates "the origin was reachable" from
|
|
9966
|
+
// "the canvas compiled" — exactly the axis #115 is about.
|
|
9967
|
+
const [loadedPath, setLoadedPath] = useState(null);
|
|
9793
9968
|
// Resizable side panels (DS components-resize-panels) + the active drag side.
|
|
9794
9969
|
const sbSize = usePanelSize('maude-sb-w', { min: 200, max: 420, def: 252 });
|
|
9795
9970
|
const rpSize = usePanelSize('maude-rp-w', { min: 260, max: 480, def: 304 });
|
|
@@ -9825,11 +10000,6 @@ function App() {
|
|
|
9825
10000
|
setLoadingPath((p) => (p === path ? null : p));
|
|
9826
10001
|
}, 2500);
|
|
9827
10002
|
}, []);
|
|
9828
|
-
useEffect(() => {
|
|
9829
|
-
if (!loadingPath) return;
|
|
9830
|
-
const cap = setTimeout(() => setLoadingPath(null), 15000);
|
|
9831
|
-
return () => clearTimeout(cap);
|
|
9832
|
-
}, [loadingPath]);
|
|
9833
10003
|
// Loaded at boot from /_config and re-fetched on the server's
|
|
9834
10004
|
// `config-updated` push (config.json hot-reload — /design:setup-ds rewrites
|
|
9835
10005
|
// it mid-session) — informs canvasUrl() so TSX iframes can pass the right
|
|
@@ -9846,6 +10016,44 @@ function App() {
|
|
|
9846
10016
|
// for one frame, each fired the request its shell exists to refuse, and then
|
|
9847
10017
|
// unmounted. Nothing was broken and everything looked broken.
|
|
9848
10018
|
const [cfg, setCfg] = useState({ designRel: '.design', cloud: undefined });
|
|
10019
|
+
// THE CAP MUST NOT CLEAR TO WHITE — issue #115. This used to be a bare
|
|
10020
|
+
// `setLoadingPath(null)`, which is the most useless thing it could do: when
|
|
10021
|
+
// the canvas origin is unreachable the shell HTML never loads, so the shell's
|
|
10022
|
+
// own `#canvas-mount-error` surface (templates/_shell.html) does not exist to
|
|
10023
|
+
// report anything, and dropping the skeleton left a blank pane with no error,
|
|
10024
|
+
// no reason and no way back inside the app. Probe the canvas origin to tell
|
|
10025
|
+
// the two failures apart — a dead server (the #115 stale-origin case, and any
|
|
10026
|
+
// sidecar crash) versus a canvas that genuinely never finished compiling —
|
|
10027
|
+
// and hand the user the recovery in both cases.
|
|
10028
|
+
//
|
|
10029
|
+
// DECLARED AFTER `cfg`, ON PURPOSE — the same rule the block below states for
|
|
10030
|
+
// the git flags, and this effect is what taught us it is not decorative. Its
|
|
10031
|
+
// dependency array reads `cfg?.canvasOrigin`, and A DEPENDENCY ARRAY IS
|
|
10032
|
+
// EVALUATED DURING RENDER: sitting above the `useState` above, it hit `cfg` in
|
|
10033
|
+
// its temporal dead zone, so `App` threw `Cannot access 'cfg' before
|
|
10034
|
+
// initialization` on its very first render and the WHOLE STUDIO mounted
|
|
10035
|
+
// nothing — a white page for every user, not only the desktop shell the fix
|
|
10036
|
+
// was written for. It reached the branch because the PR carried a merge
|
|
10037
|
+
// conflict, which stops GitHub from building a merge ref, which means the
|
|
10038
|
+
// client-boot gate never ran on it (issue #112 close-out).
|
|
10039
|
+
useEffect(() => {
|
|
10040
|
+
if (!loadingPath) return;
|
|
10041
|
+
const path = loadingPath;
|
|
10042
|
+
const cap = setTimeout(async () => {
|
|
10043
|
+
let kind = 'compile';
|
|
10044
|
+
try {
|
|
10045
|
+
const r = await fetch(`${cfg?.canvasOrigin || ''}/_health`, {
|
|
10046
|
+
cache: 'no-store',
|
|
10047
|
+
});
|
|
10048
|
+
if (!r.ok) kind = 'server';
|
|
10049
|
+
} catch {
|
|
10050
|
+
kind = 'server';
|
|
10051
|
+
}
|
|
10052
|
+
setCanvasError({ path, kind });
|
|
10053
|
+
setLoadingPath((p) => (p === path ? null : p));
|
|
10054
|
+
}, 15000);
|
|
10055
|
+
return () => clearTimeout(cap);
|
|
10056
|
+
}, [loadingPath, cfg?.canvasOrigin]);
|
|
9849
10057
|
// WHO IS SAVING THIS PROJECT — one expression, read by every surface that
|
|
9850
10058
|
// would otherwise offer to save it, poll for it, or badge it (DDR-218, widened
|
|
9851
10059
|
// by feature-cloud-managed-git-posture).
|
|
@@ -11471,12 +11679,30 @@ function App() {
|
|
|
11471
11679
|
// 25 s keeps the socket active (Bun resets the idle timer on any frame,
|
|
11472
11680
|
// inbound OR outbound); the server ignores an unknown message type.
|
|
11473
11681
|
let pingTimer = null;
|
|
11682
|
+
// A RECONNECT MEANS THE PEER MAY BE A DIFFERENT PROCESS — issue #115.
|
|
11683
|
+
// The desktop supervisor respawns the sidecar when it dies (DDR-235's Bun
|
|
11684
|
+
// fault is a recurring one), and everything this page cached from `/_config`
|
|
11685
|
+
// was published by the process that just went away. `canvasOrigin` is the
|
|
11686
|
+
// one that bites: it is an OS-assigned ephemeral port (server.ts's
|
|
11687
|
+
// `startCanvasServer(0)`), so it is DIFFERENT in every process, while the
|
|
11688
|
+
// main origin walks a deterministic ladder from 4399 and usually reclaims
|
|
11689
|
+
// its old port. The result was a half-live page — socket back up, status bar
|
|
11690
|
+
// `live`, tree and panels fine — whose every canvas iframe navigated to a
|
|
11691
|
+
// dead port. Since a canvas switch mounts a FRESH iframe (single-canvas
|
|
11692
|
+
// model, keyed by path), the already-open canvas kept rendering and only
|
|
11693
|
+
// switching went white, silently and permanently.
|
|
11694
|
+
//
|
|
11695
|
+
// So: re-derive the config from whoever is answering now. Only on a
|
|
11696
|
+
// RE-connect — the boot effect above already did the first fetch.
|
|
11697
|
+
let everConnected = false;
|
|
11474
11698
|
function connect() {
|
|
11475
11699
|
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
11476
11700
|
const ws = new WebSocket(proto + '//' + location.host + '/_ws');
|
|
11477
11701
|
wsRef.current = ws;
|
|
11478
11702
|
ws.addEventListener('open', () => {
|
|
11479
11703
|
setWsConnected(true);
|
|
11704
|
+
if (everConnected) loadServerConfig();
|
|
11705
|
+
everConnected = true;
|
|
11480
11706
|
clearInterval(pingTimer);
|
|
11481
11707
|
pingTimer = setInterval(() => {
|
|
11482
11708
|
if (ws.readyState === WebSocket.OPEN) ws.send('{"type":"ping"}');
|
|
@@ -11826,11 +12052,27 @@ function App() {
|
|
|
11826
12052
|
setActivePath(path);
|
|
11827
12053
|
setFocusedCommentId(null);
|
|
11828
12054
|
setPreviewPath(null);
|
|
12055
|
+
setCanvasError(null);
|
|
12056
|
+
setLoadedPath(null);
|
|
11829
12057
|
// Canvas-compile skeleton — cleared by the iframe's dgn:'loaded' message,
|
|
11830
12058
|
// the onLoad fallback timer (legacy .html), or a hard 15s cap.
|
|
11831
12059
|
if (path !== SYSTEM_TAB) setLoadingPath(path);
|
|
11832
12060
|
}, []);
|
|
11833
12061
|
|
|
12062
|
+
// Retry from the #115 error panel: re-read /_config FIRST (the stale
|
|
12063
|
+
// `canvasOrigin` is the likeliest reason we are here at all), then remount the
|
|
12064
|
+
// iframe via the nonce so it navigates against the corrected origin.
|
|
12065
|
+
const retryCanvasLoad = useCallback(
|
|
12066
|
+
(path) => {
|
|
12067
|
+
setCanvasError(null);
|
|
12068
|
+
setLoadedPath(null);
|
|
12069
|
+
loadServerConfig();
|
|
12070
|
+
setCanvasReloadNonce((n) => n + 1);
|
|
12071
|
+
if (path && path !== SYSTEM_TAB) setLoadingPath(path);
|
|
12072
|
+
},
|
|
12073
|
+
[loadServerConfig]
|
|
12074
|
+
);
|
|
12075
|
+
|
|
11834
12076
|
/**
|
|
11835
12077
|
* First open lands on a rendered canvas — Cloud Phase 27 C3.
|
|
11836
12078
|
*
|
|
@@ -13132,6 +13374,10 @@ function App() {
|
|
|
13132
13374
|
// iframe finished loading — drop the compile skeleton, push current
|
|
13133
13375
|
// comments + carry over focused pin if any
|
|
13134
13376
|
setLoadingPath((p) => (p === m.file ? null : p));
|
|
13377
|
+
setLoadedPath(m.file);
|
|
13378
|
+
// …and retire any #115 error panel for this canvas: it just proved it
|
|
13379
|
+
// can load (a late load, or a successful Retry).
|
|
13380
|
+
setCanvasError((e) => (e && e.path === m.file ? null : e));
|
|
13135
13381
|
// Presentation Mode suppresses comment pins (same gate as the push
|
|
13136
13382
|
// effect above), so a canvas opened while presenting starts pin-free.
|
|
13137
13383
|
const list = presentMode ? [] : commentsByFile[m.file] || [];
|
|
@@ -15259,6 +15505,10 @@ function App() {
|
|
|
15259
15505
|
cfg={cfg}
|
|
15260
15506
|
loadingPath={loadingPath}
|
|
15261
15507
|
onIframeLoad={onIframeLoad}
|
|
15508
|
+
canvasError={canvasError}
|
|
15509
|
+
canvasReloadNonce={canvasReloadNonce}
|
|
15510
|
+
onRetryCanvasLoad={retryCanvasLoad}
|
|
15511
|
+
loadedPath={loadedPath}
|
|
15262
15512
|
showQuickSetup={
|
|
15263
15513
|
isNativeApp() && !viewerMode && !!setupReadiness && !setupReadiness.ready
|
|
15264
15514
|
}
|
|
@@ -307,9 +307,11 @@ function StatusPill({ job }) {
|
|
|
307
307
|
: job.status === 'done'
|
|
308
308
|
? degraded && job.degraded.audioDropped
|
|
309
309
|
? 'Ready · no audio'
|
|
310
|
-
: degraded
|
|
311
|
-
? 'Ready ·
|
|
312
|
-
:
|
|
310
|
+
: degraded && job.degraded.fontsNotEmbedded?.length
|
|
311
|
+
? 'Ready · font warning'
|
|
312
|
+
: degraded
|
|
313
|
+
? 'Ready · degraded'
|
|
314
|
+
: 'Ready'
|
|
313
315
|
: 'Failed';
|
|
314
316
|
const eta = job.status === 'running' ? etaLabel(job) : null;
|
|
315
317
|
return (
|
|
@@ -331,12 +333,18 @@ function StatusPill({ job }) {
|
|
|
331
333
|
*/
|
|
332
334
|
function DegradedNote({ degraded }) {
|
|
333
335
|
if (!degraded) return null;
|
|
336
|
+
// The font case names the fonts, because "reduced fidelity" is useless to
|
|
337
|
+
// someone about to send this to a printer — what they need is which faces
|
|
338
|
+
// came out unprintable (issue #116).
|
|
339
|
+
const fonts = degraded.fontsNotEmbedded ?? [];
|
|
340
|
+
const headline = degraded.audioDropped
|
|
341
|
+
? 'Exported without audio.'
|
|
342
|
+
: fonts.length
|
|
343
|
+
? `Fonts a print shop will reject: ${fonts.join(', ')}.`
|
|
344
|
+
: 'Exported with reduced fidelity.';
|
|
334
345
|
return (
|
|
335
346
|
<div className="st-export-degraded" data-testid="export-degraded-note">
|
|
336
|
-
<span aria-hidden="true">⚠</span>{
|
|
337
|
-
{degraded.audioDropped
|
|
338
|
-
? 'Exported without audio.'
|
|
339
|
-
: 'Exported with reduced fidelity.'}
|
|
347
|
+
<span aria-hidden="true">⚠</span> {headline}
|
|
340
348
|
{degraded.remedy ? <div className="st-export-degraded__fix">{degraded.remedy}</div> : null}
|
|
341
349
|
</div>
|
|
342
350
|
);
|
|
@@ -292,7 +292,13 @@ function Row({ item, refresh }) {
|
|
|
292
292
|
) : null}
|
|
293
293
|
</span>
|
|
294
294
|
) : null}
|
|
295
|
-
{
|
|
295
|
+
{/* Shown whenever a path resolved — NOT only in the signin state. DDR-166
|
|
296
|
+
Decision 3 calls this binding ("so a pre-existing PATH-hijacked `claude`
|
|
297
|
+
isn't invisible to the one human capable of noticing it's wrong"), and
|
|
298
|
+
gating it on `action === 'signin'` hid it in the one state whose most
|
|
299
|
+
likely cause IS something unexpected fronting the binary (issue #107,
|
|
300
|
+
attacker finding F4). */}
|
|
301
|
+
{item.resolvedPath ? (
|
|
296
302
|
<span className="rdy-fix-tx rdy-resolved-path">
|
|
297
303
|
{item.resolvedViaMaude ? 'Installed by Maude: ' : 'Found on your PATH: '}
|
|
298
304
|
<code>{item.resolvedPath}</code>
|
|
@@ -98,6 +98,39 @@ function readFiles(raw) {
|
|
|
98
98
|
return raw;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* The seed progress model, or null when absent/untrustworthy.
|
|
103
|
+
*
|
|
104
|
+
* Absent is the norm on an older dev-server, and this panel must render
|
|
105
|
+
* exactly as it did before when it is — every field here is additive.
|
|
106
|
+
*/
|
|
107
|
+
function readProgress(raw) {
|
|
108
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
109
|
+
if (![raw.tracked, raw.delivered, raw.remaining].every(isCount)) return null;
|
|
110
|
+
if (typeof raw.phase !== 'string') return null;
|
|
111
|
+
const blocked = Array.isArray(raw.blocked)
|
|
112
|
+
? raw.blocked.filter((b) => b && typeof b.class === 'string' && isCount(b.count))
|
|
113
|
+
: [];
|
|
114
|
+
return { ...raw, blocked };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** One sentence per phase, in the user's terms — never the machine's. */
|
|
118
|
+
const PHASE_TEXT = {
|
|
119
|
+
scanning: 'Looking through the project…',
|
|
120
|
+
seeding: null, // the counts say it better than a sentence would
|
|
121
|
+
paused: 'Paused — nothing is lost; this resumes by itself.',
|
|
122
|
+
blocked: 'Nothing is moving on its own — the files below need a decision.',
|
|
123
|
+
converged: 'Everything is up to date.',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** What each wall means, and what a person can do about it. */
|
|
127
|
+
const BLOCKED_TEXT = {
|
|
128
|
+
'too-large': 'too big for this workspace',
|
|
129
|
+
quota: "this hour's upload allowance is used up",
|
|
130
|
+
unreachable: 'the workspace could not be reached',
|
|
131
|
+
refused: 'the workspace would not take them',
|
|
132
|
+
};
|
|
133
|
+
|
|
101
134
|
/** Consent-class notices (feature-before-first-external-users Task 1), or []
|
|
102
135
|
* when the shape can't be trusted. Absent is the norm — the payload carries
|
|
103
136
|
* `notices` only when a boot raised one (shared-doc ON, TSX bodies). */
|
|
@@ -279,6 +312,7 @@ export default function SyncPanel({
|
|
|
279
312
|
const files = readFiles(status?.files);
|
|
280
313
|
|
|
281
314
|
const delivery = useMemo(() => readDelivery(status?.files?.delivery), [status?.files?.delivery]);
|
|
315
|
+
const progress = useMemo(() => readProgress(status?.files?.progress), [status?.files?.progress]);
|
|
282
316
|
|
|
283
317
|
// Sync settings (Task 2) — fetched once on mount; `settings` stays null when
|
|
284
318
|
// no hub is linked, which is also the render gate for the whole section.
|
|
@@ -648,17 +682,98 @@ export default function SyncPanel({
|
|
|
648
682
|
{files && (
|
|
649
683
|
<section aria-label="Project files" data-testid="sync-files">
|
|
650
684
|
<div className="gp-sect-label">
|
|
651
|
-
project files
|
|
652
|
-
|
|
653
|
-
<div className="sp-assets-line">
|
|
654
|
-
{`${files.synced} synced` + (files.pulled > 0 ? ` · ${files.pulled} pulled` : '')}
|
|
685
|
+
project files{' '}
|
|
686
|
+
<span className="gp-group-count">{progress ? progress.tracked : files.synced}</span>
|
|
655
687
|
</div>
|
|
688
|
+
{progress ? (
|
|
689
|
+
<>
|
|
690
|
+
<div className="sp-progress-track" data-testid="sync-files-progress">
|
|
691
|
+
<div
|
|
692
|
+
className="sp-progress-fill"
|
|
693
|
+
style={{
|
|
694
|
+
width: `${
|
|
695
|
+
progress.tracked > 0
|
|
696
|
+
? Math.min(100, Math.round((progress.delivered / progress.tracked) * 100))
|
|
697
|
+
: 100
|
|
698
|
+
}%`,
|
|
699
|
+
}}
|
|
700
|
+
/>
|
|
701
|
+
</div>
|
|
702
|
+
<div className="sp-assets-line" data-testid="sync-files-remaining">
|
|
703
|
+
{`${progress.delivered} of ${progress.tracked} delivered`}
|
|
704
|
+
{progress.remaining > 0 ? ` · ${progress.remaining} waiting` : ''}
|
|
705
|
+
</div>
|
|
706
|
+
{PHASE_TEXT[progress.phase] && (
|
|
707
|
+
<div className="sp-assets-line" data-testid="sync-files-phase">
|
|
708
|
+
{PHASE_TEXT[progress.phase]}
|
|
709
|
+
</div>
|
|
710
|
+
)}
|
|
711
|
+
{progress.passCapped && progress.remaining > 0 && (
|
|
712
|
+
<div className="sp-assets-line">
|
|
713
|
+
More is on the way — the last pass reached its limit and picks up where it
|
|
714
|
+
left off.
|
|
715
|
+
</div>
|
|
716
|
+
)}
|
|
717
|
+
{progress.blocked.map((b) => (
|
|
718
|
+
<div
|
|
719
|
+
key={b.class}
|
|
720
|
+
className="sp-assets-retry"
|
|
721
|
+
data-testid={`sync-blocked-${b.class}`}
|
|
722
|
+
>
|
|
723
|
+
{b.count} file{b.count === 1 ? '' : 's'} —{' '}
|
|
724
|
+
{BLOCKED_TEXT[b.class] ?? 'the workspace would not take them'}.
|
|
725
|
+
</div>
|
|
726
|
+
))}
|
|
727
|
+
{/*
|
|
728
|
+
THE RAW COUNTERS STAY. A panel derived from the same source it
|
|
729
|
+
displays cannot be cross-checked, and DDR-214's whole lesson is
|
|
730
|
+
that a status surface has to be falsifiable — so the numbers the
|
|
731
|
+
passes actually reported remain here to disagree with.
|
|
732
|
+
*/}
|
|
733
|
+
<div className="sp-assets-line sp-raw-counters">
|
|
734
|
+
{`raw: ${files.synced} synced`}
|
|
735
|
+
{files.pushed ? ` · ${files.pushed} pushed` : ''}
|
|
736
|
+
{files.pulled > 0 ? ` · ${files.pulled} pulled` : ''}
|
|
737
|
+
</div>
|
|
738
|
+
</>
|
|
739
|
+
) : (
|
|
740
|
+
<div className="sp-assets-line">
|
|
741
|
+
{`${files.synced} synced` + (files.pulled > 0 ? ` · ${files.pulled} pulled` : '')}
|
|
742
|
+
</div>
|
|
743
|
+
)}
|
|
656
744
|
{files.conflicts > 0 && (
|
|
657
745
|
<div className="sp-assets-retry" data-testid="sync-files-conflicts">
|
|
658
746
|
{files.conflicts} conflict{files.conflicts === 1 ? '' : 's'} — the older copies are
|
|
659
747
|
kept in Trash, below.
|
|
660
748
|
</div>
|
|
661
749
|
)}
|
|
750
|
+
{/*
|
|
751
|
+
A PAUSE IS NOT A FAILURE, and it gets its own words. The
|
|
752
|
+
workspace asked us to slow down; nothing is wrong, nothing is
|
|
753
|
+
lost, and the only correct action is to wait — which is exactly
|
|
754
|
+
what a person cannot infer from a count of failures (issue #109).
|
|
755
|
+
It comes FIRST because it explains the failure line below it.
|
|
756
|
+
*/}
|
|
757
|
+
{files.rateLimited && (
|
|
758
|
+
<div className="sp-assets-retry" data-testid="sync-files-rate-limited">
|
|
759
|
+
<strong>syncing paused for a moment.</strong> The workspace asked this machine to
|
|
760
|
+
slow down.{' '}
|
|
761
|
+
{files.rateLimited.waiting > 0
|
|
762
|
+
? `${files.rateLimited.waiting} file${files.rateLimited.waiting === 1 ? '' : 's'} still on the way — nothing is lost, they arrive when the pause lifts.`
|
|
763
|
+
: 'It resumes by itself.'}
|
|
764
|
+
</div>
|
|
765
|
+
)}
|
|
766
|
+
{/*
|
|
767
|
+
AND A FAILURE IS NOT A SYNC. This had no field at all, so a pass
|
|
768
|
+
that refused every file rendered as "N synced" and a person saw
|
|
769
|
+
broken images with the cause only in a terminal they never open.
|
|
770
|
+
*/}
|
|
771
|
+
{files.failed > 0 && !files.rateLimited && (
|
|
772
|
+
<div className="sp-assets-retry" data-testid="sync-files-failed">
|
|
773
|
+
{files.failed} file{files.failed === 1 ? '' : 's'} did not come through on the last
|
|
774
|
+
check — sync retries them by itself. The list is below.
|
|
775
|
+
</div>
|
|
776
|
+
)}
|
|
662
777
|
{/*
|
|
663
778
|
A HELD BREAKER, said out loud. These used to exist only as a
|
|
664
779
|
console.warn, which on a machine whose user never opens a
|
|
@@ -717,6 +832,12 @@ export default function SyncPanel({
|
|
|
717
832
|
</li>
|
|
718
833
|
))}
|
|
719
834
|
{delivery.fine.length > 200 && <li>…and {delivery.fine.length - 200} more</li>}
|
|
835
|
+
{files.deliveryTruncated > 0 && (
|
|
836
|
+
<li className="sp-truncated">
|
|
837
|
+
…and {files.deliveryTruncated} more not listed here — the list is capped so
|
|
838
|
+
the files that need attention always fit.
|
|
839
|
+
</li>
|
|
840
|
+
)}
|
|
720
841
|
</ul>
|
|
721
842
|
</details>
|
|
722
843
|
)}
|
|
@@ -321,6 +321,7 @@ export function ReportBugDialog({ open, onClose, activeCanvas = null }) {
|
|
|
321
321
|
attachments: {
|
|
322
322
|
screenshots: shots.length,
|
|
323
323
|
serverLogTail: consent.logTail && !!bundle?.logs?.serverLogTail,
|
|
324
|
+
processStats: consent.logTail && !!bundle?.process,
|
|
324
325
|
crashLogs: consent.crashLogs ? crashLogs.length : 0,
|
|
325
326
|
},
|
|
326
327
|
logs: {},
|
|
@@ -330,6 +331,19 @@ export function ReportBugDialog({ open, onClose, activeCanvas = null }) {
|
|
|
330
331
|
if (consent.logTail && bundle?.logs?.serverLogTail) {
|
|
331
332
|
report.logs.serverLogTail = bundle.logs.serverLogTail;
|
|
332
333
|
}
|
|
334
|
+
// Server process memory — three integers, rides the SAME consent as the log
|
|
335
|
+
// tail because it is diagnostics of the same kind (and, like the tail, is
|
|
336
|
+
// only meaningful alongside it). Issue #119 arrived as a RAM figure the
|
|
337
|
+
// reporter read off Activity Monitor, with nothing in the report to confirm
|
|
338
|
+
// it; the memory watch that should have logged the problem was measuring a
|
|
339
|
+
// counter that does not move under Bun, so the log tail was silent too.
|
|
340
|
+
if (consent.logTail && bundle?.process) {
|
|
341
|
+
report.process = {
|
|
342
|
+
rssBytes: bundle.process.rssBytes,
|
|
343
|
+
heapUsedBytes: bundle.process.heapUsedBytes,
|
|
344
|
+
uptimeSeconds: bundle.process.uptimeSeconds,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
333
347
|
if (consent.crashLogs && crashLogs.length && isNativeApp()) {
|
|
334
348
|
report.logs.crashLogs = [];
|
|
335
349
|
for (const log of crashLogs) {
|
|
@@ -568,7 +582,11 @@ export function ReportBugDialog({ open, onClose, activeCanvas = null }) {
|
|
|
568
582
|
/>
|
|
569
583
|
<span>
|
|
570
584
|
Recent server log ({bundle.logs.serverLogTail.split('\n').length} lines,
|
|
571
|
-
paths & secrets scrubbed)
|
|
585
|
+
paths & secrets scrubbed)
|
|
586
|
+
{bundle?.process
|
|
587
|
+
? ` + server memory (${Math.round(bundle.process.rssBytes / 1048576)} MB)`
|
|
588
|
+
: ''}{' '}
|
|
589
|
+
—{' '}
|
|
572
590
|
<details className="rb-details">
|
|
573
591
|
<summary>view</summary>
|
|
574
592
|
<pre className="rb-log">{bundle.logs.serverLogTail}</pre>
|