@1agh/maude 1.0.11 → 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/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/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/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 +72 -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 -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
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// One log shape, three producers — feature-cloud-managed-git-posture.
|
|
2
|
-
//
|
|
3
|
-
// A History row is drawn by ONE renderer (`GitPanel`), and it can now be fed by
|
|
4
|
-
// three different readers: system-git (`logSystem`), isomorphic-git (`logIso`)
|
|
5
|
-
// and the cloud cell (`apps/hub/src/history.mjs`). The first and the third are
|
|
6
|
-
// the same code — that is what `git/log-format.ts` is for. The second is a
|
|
7
|
-
// separate implementation against a separate library, and it is the one that
|
|
8
|
-
// can quietly drift.
|
|
9
|
-
//
|
|
10
|
-
// The failure mode is specific and quiet: a reader that stops emitting `date`
|
|
11
|
-
// (or emits `authorName` instead of `author`) does not throw anywhere. It draws
|
|
12
|
-
// a row with a blank field, on whichever of the two engines the reader happens
|
|
13
|
-
// to be on — so it is invisible on the machine of whoever made the change.
|
|
14
|
-
|
|
15
|
-
import { describe, expect, test } from 'bun:test';
|
|
16
|
-
import { readFileSync } from 'node:fs';
|
|
17
|
-
import { join } from 'node:path';
|
|
18
|
-
|
|
19
|
-
import { GIT_LOG_FORMAT, gitLogArgs, gitLogEnv, parseGitLog } from '../git/log-format.ts';
|
|
20
|
-
|
|
21
|
-
const SERVICE = readFileSync(join(import.meta.dir, '..', 'git', 'service.ts'), 'utf8');
|
|
22
|
-
|
|
23
|
-
/** The contract `GitLogEntry` declares and `GitPanel` reads. */
|
|
24
|
-
const FIELDS = ['sha', 'message', 'author', 'email', 'date'] as const;
|
|
25
|
-
|
|
26
|
-
describe('parseGitLog', () => {
|
|
27
|
-
test('produces exactly the declared fields', () => {
|
|
28
|
-
const rec = `abc123\x1fa message\x1fAda\x1fada@example.com\x1f2026-08-18T10:00:00+02:00\x1e`;
|
|
29
|
-
const [entry] = parseGitLog(rec);
|
|
30
|
-
expect(Object.keys(entry).sort()).toEqual([...FIELDS].sort());
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('survives every separator a commit subject can carry', () => {
|
|
34
|
-
const msg = 'fix: tabs\tquotes " and a | pipe, plus a comma';
|
|
35
|
-
const [entry] = parseGitLog(`sha\x1f${msg}\x1fAda\x1fa@b.c\x1f2026-08-18T10:00:00Z\x1e`);
|
|
36
|
-
expect(entry.message).toBe(msg);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('a short record still yields strings, never undefined', () => {
|
|
40
|
-
// A renderer must never have to defend against a half-parsed row.
|
|
41
|
-
const [entry] = parseGitLog('justasha\x1fonly a message\x1e');
|
|
42
|
-
for (const f of FIELDS) expect(typeof entry[f]).toBe('string');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('garbage is an empty list, never a throw', () => {
|
|
46
|
-
expect(parseGitLog('')).toEqual([]);
|
|
47
|
-
expect(parseGitLog('\x1e\x1e \x1e')).toEqual([]);
|
|
48
|
-
// biome-ignore lint/suspicious/noExplicitAny: deliberately hostile input
|
|
49
|
-
expect(parseGitLog(null as any)).toEqual([]);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('gitLogArgs / gitLogEnv travel together', () => {
|
|
54
|
-
test('the format string is the one the parser splits on', () => {
|
|
55
|
-
expect(GIT_LOG_FORMAT).toContain('%x1f');
|
|
56
|
-
expect(GIT_LOG_FORMAT).toContain('%x1e');
|
|
57
|
-
expect(gitLogArgs(30)).toEqual(['log', '-n30', `--pretty=format:${GIT_LOG_FORMAT}`]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('a scoped log terminates its pathspec AND asks for literal pathspecs', () => {
|
|
61
|
-
// The `--` terminator alone does not close pathspec magic (`:(exclude)…`);
|
|
62
|
-
// GIT_LITERAL_PATHSPECS does, and the two must never be separated.
|
|
63
|
-
const args = gitLogArgs(10, '.design/ui/Card.tsx');
|
|
64
|
-
expect(args[args.length - 2]).toBe('--');
|
|
65
|
-
expect(args[args.length - 1]).toBe('.design/ui/Card.tsx');
|
|
66
|
-
expect(gitLogEnv('.design/ui/Card.tsx')).toEqual({ GIT_LITERAL_PATHSPECS: '1' });
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('an unscoped log asks for neither', () => {
|
|
70
|
-
expect(gitLogArgs(10)).not.toContain('--');
|
|
71
|
-
expect(gitLogEnv(undefined)).toBeUndefined();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('the isomorphic-git engine has not drifted from the shared shape', () => {
|
|
76
|
-
test('logSystem reads through the shared module rather than re-typing it', () => {
|
|
77
|
-
expect(SERVICE).toContain('gitLogArgs(limit, filepath), gitLogEnv(filepath)');
|
|
78
|
-
expect(SERVICE).toContain('return parseGitLog(r.stdout);');
|
|
79
|
-
// The old literal must be GONE, not merely unused — a leftover copy is the
|
|
80
|
-
// thing a later edit picks up.
|
|
81
|
-
expect(SERVICE).not.toContain("const fmt = '%H%x1f");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('logIso still emits exactly the same five fields', () => {
|
|
85
|
-
// Source-level, because `logIso` is a private fallback with no seam to call
|
|
86
|
-
// it through: forcing the engine would mean exporting it, which invents an
|
|
87
|
-
// API for the test to check. The literal it returns IS the contract.
|
|
88
|
-
const body = SERVICE.slice(SERVICE.indexOf('async function logIso('));
|
|
89
|
-
const literal = body.slice(body.indexOf('return {'), body.indexOf('};') + 2);
|
|
90
|
-
for (const f of FIELDS) expect(literal).toContain(`${f}:`);
|
|
91
|
-
// …and nothing else, so a sixth field can't appear on one engine only.
|
|
92
|
-
const keys = [...literal.matchAll(/^\s{8}([a-zA-Z]+):/gm)].map((m) => m[1]);
|
|
93
|
-
expect(keys.sort()).toEqual([...FIELDS].sort());
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
// `designRel` and the rels built on it, validated before they reach git —
|
|
2
|
-
// F-13 / B12 of the v1.0.0 gate set.
|
|
3
|
-
//
|
|
4
|
-
// The finding was NOT "argv injection": every `runGit` / `run` call that carries
|
|
5
|
-
// a dynamic path already puts it after a `--` separator, so a leading `-` is a
|
|
6
|
-
// filename to git rather than a flag. The finding is CONTAINMENT, which `--`
|
|
7
|
-
// does nothing about. A rel carrying `..` is a perfectly well-formed pathspec
|
|
8
|
-
// that names a file outside the design root — and the autocommit path feeds
|
|
9
|
-
// exactly such rels into `git add -- <paths>` inside a workspace cell, with no
|
|
10
|
-
// human at the keyboard to notice `.github/workflows/release.yml` acquiring a
|
|
11
|
-
// commit.
|
|
12
|
-
//
|
|
13
|
-
// So the shapes below are the hostile ones, and the two consumers that matter
|
|
14
|
-
// are pinned: the containment PREFIX (which must never silently degrade to
|
|
15
|
-
// "no filter") and the staging BATCH (which must drop the poisoned rel and keep
|
|
16
|
-
// committing everybody else's work).
|
|
17
|
-
|
|
18
|
-
import { describe, expect, test } from 'bun:test';
|
|
19
|
-
|
|
20
|
-
import { isSafeGitRel, partitionSafeGitRels, safeGitPrefix } from '../git/safe-rel.ts';
|
|
21
|
-
|
|
22
|
-
const HOSTILE: [string, string][] = [
|
|
23
|
-
['../escape', 'parent traversal — the whole point'],
|
|
24
|
-
['a/../../b', 'traversal in the middle, where a prefix check would not see it'],
|
|
25
|
-
['..', 'bare parent'],
|
|
26
|
-
['.', 'bare current — a pathspec meaning "everything"'],
|
|
27
|
-
['a/./b', 'a no-op segment that normalises differently in two places'],
|
|
28
|
-
['/etc/passwd', 'absolute'],
|
|
29
|
-
['C:/Windows/System32', 'Windows-absolute'],
|
|
30
|
-
['a\\..\\b', 'backslash separators — traversal that survives a forward-slash check'],
|
|
31
|
-
['--upload-pack=/bin/sh', 'the flag-shaped rel the `--` separator exists for'],
|
|
32
|
-
['-rf', 'a shorter one'],
|
|
33
|
-
['a\u0000/../../b', 'NUL — truncates at the syscall boundary, so it is two paths'],
|
|
34
|
-
['a\u001f/b', 'other control characters'],
|
|
35
|
-
['a /b', 'trailing space in a segment — invisible in every UI that shows it'],
|
|
36
|
-
['', 'empty'],
|
|
37
|
-
[`${'x/'.repeat(300)}y`, 'past the length cap'],
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const BENIGN = [
|
|
41
|
-
'.design/ui/screen.tsx',
|
|
42
|
-
'.design/system/ds/README.md',
|
|
43
|
-
'.design/assets/a1b2c3d4.png',
|
|
44
|
-
'assets/logo.svg',
|
|
45
|
-
'.design/preview/_layout.css',
|
|
46
|
-
'.design/ui/My Canvas.tsx',
|
|
47
|
-
'.design/ui/-not-leading.tsx'.replace('/-not', '/not'),
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
describe('isSafeGitRel', () => {
|
|
51
|
-
for (const [rel, why] of HOSTILE) {
|
|
52
|
-
test(`refuses ${JSON.stringify(rel)} — ${why}`, () => {
|
|
53
|
-
expect(isSafeGitRel(rel)).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
for (const rel of BENIGN) {
|
|
58
|
-
test(`admits ${JSON.stringify(rel)}`, () => {
|
|
59
|
-
expect(isSafeGitRel(rel)).toBe(true);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
test('a non-string is refused rather than coerced', () => {
|
|
64
|
-
for (const v of [null, undefined, 42, {}, ['a']]) {
|
|
65
|
-
expect(isSafeGitRel(v)).toBe(false);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('safeGitPrefix — an absent prefix and a REFUSED one are different answers', () => {
|
|
71
|
-
test('absent is the empty prefix (no containment filter), and that is legitimate', () => {
|
|
72
|
-
expect(safeGitPrefix(undefined)).toBe('');
|
|
73
|
-
expect(safeGitPrefix('')).toBe('');
|
|
74
|
-
expect(safeGitPrefix(null)).toBe('');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('a normal design root normalises', () => {
|
|
78
|
-
expect(safeGitPrefix('.design')).toBe('.design');
|
|
79
|
-
expect(safeGitPrefix('/.design/')).toBe('.design');
|
|
80
|
-
expect(safeGitPrefix('design\\root')).toBe('design/root');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('a hostile prefix is null — NOT the empty string', () => {
|
|
84
|
-
// This distinction is the whole reason the function returns `string | null`.
|
|
85
|
-
// Empty means "match everything", so a caller that mapped a refusal onto ''
|
|
86
|
-
// would answer a traversal attempt by WIDENING the scope to the whole
|
|
87
|
-
// repository. The caller (`normPrefix`) falls back to '.design' instead.
|
|
88
|
-
//
|
|
89
|
-
// A LEADING SLASH IS NOT HOSTILE HERE, and this is the one place the prefix
|
|
90
|
-
// reading differs from the pathspec reading. `context.ts` already strips
|
|
91
|
-
// `^/+` off `cfg.designRoot`, i.e. a configured `/.design` has always meant
|
|
92
|
-
// "`.design`, relative to the repo root" — so `/etc/passwd` reads as the
|
|
93
|
-
// prefix `etc/passwd`, which names a directory that does not exist and
|
|
94
|
-
// therefore matches nothing. Harmless as a CONTAINMENT FILTER; still
|
|
95
|
-
// refused by `isSafeGitRel` where it would be used as a PATHSPEC.
|
|
96
|
-
const rootRelative = new Set(['/etc/passwd']);
|
|
97
|
-
for (const [rel] of HOSTILE) {
|
|
98
|
-
if (rel === '') continue; // '' is the absent case, tested above
|
|
99
|
-
if (rootRelative.has(rel)) {
|
|
100
|
-
expect(safeGitPrefix(rel)).toBe('etc/passwd');
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
expect(safeGitPrefix(rel)).toBeNull();
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe('partitionSafeGitRels — one poisoned rel must not wedge the batch', () => {
|
|
109
|
-
test('splits a mixed batch, keeping the order of each side', () => {
|
|
110
|
-
const { safe, refused } = partitionSafeGitRels([
|
|
111
|
-
'.design/ui/a.tsx',
|
|
112
|
-
'../../.github/workflows/release.yml',
|
|
113
|
-
'.design/ui/b.tsx',
|
|
114
|
-
'-rf',
|
|
115
|
-
'.design/system/ds/README.md',
|
|
116
|
-
]);
|
|
117
|
-
expect(safe).toEqual(['.design/ui/a.tsx', '.design/ui/b.tsx', '.design/system/ds/README.md']);
|
|
118
|
-
expect(refused).toEqual(['../../.github/workflows/release.yml', '-rf']);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test('an all-clean batch is unchanged', () => {
|
|
122
|
-
const { safe, refused } = partitionSafeGitRels(BENIGN);
|
|
123
|
-
expect(safe).toEqual(BENIGN);
|
|
124
|
-
expect(refused).toEqual([]);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('an all-hostile batch stages nothing rather than throwing', () => {
|
|
128
|
-
const { safe, refused } = partitionSafeGitRels(['../a', '/b', '..']);
|
|
129
|
-
expect(safe).toEqual([]);
|
|
130
|
-
expect(refused).toHaveLength(3);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
// The engine a CELL actually runs — Cloud Phase 27 D2.
|
|
2
|
-
//
|
|
3
|
-
// WHY THIS FILE EXISTS. `MAUDE_USE_SYSTEM_GIT=1` used to be an escape hatch
|
|
4
|
-
// nobody set, so `commitSystem` and the system-git halves of checkout / branch /
|
|
5
|
-
// discard / fold had no coverage at all while their isomorphic-git twins had
|
|
6
|
-
// plenty. D2 makes every cloud tenant's saves go through exactly those halves
|
|
7
|
-
// (studio-child.mjs pins it, because two git engines over one index is not a
|
|
8
|
-
// race a careful caller can avoid — it is two programs writing one file).
|
|
9
|
-
//
|
|
10
|
-
// Shipping that flip while its code path was the untested one would be trading a
|
|
11
|
-
// known bug for an unmeasured one. These are the same assertions the iso engine
|
|
12
|
-
// already gets, run against the engine the cloud uses.
|
|
13
|
-
|
|
14
|
-
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
|
15
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
16
|
-
import { tmpdir } from 'node:os';
|
|
17
|
-
import { join } from 'node:path';
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
gitCheckout,
|
|
21
|
-
gitCommit,
|
|
22
|
-
gitCreateBranch,
|
|
23
|
-
gitDiscard,
|
|
24
|
-
gitListBranches,
|
|
25
|
-
gitStatus,
|
|
26
|
-
} from '../git/service.ts';
|
|
27
|
-
|
|
28
|
-
let dir: string;
|
|
29
|
-
let saved: string | undefined;
|
|
30
|
-
|
|
31
|
-
function run(args: string[], cwd: string) {
|
|
32
|
-
const r = Bun.spawnSync(['git', ...args], { cwd });
|
|
33
|
-
return { code: r.exitCode, stdout: r.stdout.toString(), stderr: r.stderr.toString() };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
beforeEach(() => {
|
|
37
|
-
saved = process.env.MAUDE_USE_SYSTEM_GIT;
|
|
38
|
-
// The whole point: the flag is read LIVE, so it can be scoped to this file
|
|
39
|
-
// instead of leaking into every other suite through a module-load const.
|
|
40
|
-
process.env.MAUDE_USE_SYSTEM_GIT = '1';
|
|
41
|
-
|
|
42
|
-
dir = mkdtempSync(join(tmpdir(), 'maude-system-git-'));
|
|
43
|
-
run(['init', '-b', 'main'], dir);
|
|
44
|
-
run(['config', 'user.name', 'Test'], dir);
|
|
45
|
-
run(['config', 'user.email', 'test@example.com'], dir);
|
|
46
|
-
mkdirSync(join(dir, '.design', 'ui'), { recursive: true });
|
|
47
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'export const v = 1;\n');
|
|
48
|
-
run(['add', '-A'], dir);
|
|
49
|
-
run(['commit', '-m', 'seed'], dir);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
afterEach(() => {
|
|
53
|
-
if (saved === undefined) {
|
|
54
|
-
delete process.env.MAUDE_USE_SYSTEM_GIT;
|
|
55
|
-
} else process.env.MAUDE_USE_SYSTEM_GIT = saved;
|
|
56
|
-
rmSync(dir, { recursive: true, force: true });
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('the system-git engine a cell runs on', () => {
|
|
60
|
-
test('a save commits exactly the selected file and nothing else', async () => {
|
|
61
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'export const v = 2;\n');
|
|
62
|
-
writeFileSync(join(dir, '.design', 'ui', 'Other.tsx'), 'export const other = 1;\n');
|
|
63
|
-
|
|
64
|
-
const res = await gitCommit(dir, 'update home', ['.design/ui/Home.tsx'], {
|
|
65
|
-
designPrefix: '.design',
|
|
66
|
-
});
|
|
67
|
-
expect(res.ok).toBe(true);
|
|
68
|
-
|
|
69
|
-
// The other file is still uncommitted — "Save selected" must mean selected.
|
|
70
|
-
const after = await gitStatus(dir, { designPrefix: '.design' });
|
|
71
|
-
expect(after.files.map((f) => f.path)).toEqual(['.design/ui/Other.tsx']);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('save-all commits every change in scope', async () => {
|
|
75
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'export const v = 3;\n');
|
|
76
|
-
writeFileSync(join(dir, '.design', 'ui', 'New.tsx'), 'export const n = 1;\n');
|
|
77
|
-
|
|
78
|
-
const res = await gitCommit(dir, 'save all', undefined, { designPrefix: '.design' });
|
|
79
|
-
expect(res.ok).toBe(true);
|
|
80
|
-
expect((await gitStatus(dir, { designPrefix: '.design' })).clean).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('nothing to save is a refusal, not an empty commit', async () => {
|
|
84
|
-
const before = run(['rev-list', '--count', 'HEAD'], dir).stdout.trim();
|
|
85
|
-
const res = await gitCommit(dir, 'nothing', undefined, { designPrefix: '.design' });
|
|
86
|
-
expect(res.ok).toBe(false);
|
|
87
|
-
expect(run(['rev-list', '--count', 'HEAD'], dir).stdout.trim()).toBe(before);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test('discard restores a tracked file and deletes an untracked one', async () => {
|
|
91
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'wrecked\n');
|
|
92
|
-
writeFileSync(join(dir, '.design', 'ui', 'Scratch.tsx'), 'temporary\n');
|
|
93
|
-
|
|
94
|
-
const res = await gitDiscard(dir, ['.design/ui/Home.tsx', '.design/ui/Scratch.tsx'], {
|
|
95
|
-
designPrefix: '.design',
|
|
96
|
-
});
|
|
97
|
-
expect(res.ok).toBe(true);
|
|
98
|
-
expect(readFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'utf8')).toBe(
|
|
99
|
-
'export const v = 1;\n'
|
|
100
|
-
);
|
|
101
|
-
expect(existsSync(join(dir, '.design', 'ui', 'Scratch.tsx'))).toBe(false);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test('a draft is created, switched to, and switched back', async () => {
|
|
105
|
-
const made = await gitCreateBranch(dir, 'nav-redesign');
|
|
106
|
-
expect(made.ok).toBe(true);
|
|
107
|
-
expect(run(['rev-parse', '--abbrev-ref', 'HEAD'], dir).stdout.trim()).toBe('nav-redesign');
|
|
108
|
-
|
|
109
|
-
const back = await gitCheckout(dir, 'main');
|
|
110
|
-
expect(back.ok).toBe(true);
|
|
111
|
-
expect(run(['rev-parse', '--abbrev-ref', 'HEAD'], dir).stdout.trim()).toBe('main');
|
|
112
|
-
|
|
113
|
-
expect((await gitListBranches(dir)).map((b) => b.name).sort()).toEqual([
|
|
114
|
-
'main',
|
|
115
|
-
'nav-redesign',
|
|
116
|
-
]);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test('switching with unsaved changes says so instead of losing them', async () => {
|
|
120
|
-
await gitCreateBranch(dir, 'draft');
|
|
121
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'export const v = 99;\n');
|
|
122
|
-
await gitCommit(dir, 'draft edit', undefined, { designPrefix: '.design' });
|
|
123
|
-
await gitCheckout(dir, 'main');
|
|
124
|
-
|
|
125
|
-
// Now dirty on main in a way the switch would clobber.
|
|
126
|
-
writeFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'export const v = 1000;\n');
|
|
127
|
-
const res = await gitCheckout(dir, 'draft');
|
|
128
|
-
expect(res.ok).toBe(false);
|
|
129
|
-
expect(res.error).toContain('Save your changes');
|
|
130
|
-
// The unsaved bytes are still there — the refusal is the point.
|
|
131
|
-
expect(readFileSync(join(dir, '.design', 'ui', 'Home.tsx'), 'utf8')).toBe(
|
|
132
|
-
'export const v = 1000;\n'
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// Phase 27 Task 5 (E2) — live dirty-state broadcast.
|
|
2
|
-
//
|
|
3
|
-
// Unit: the `isVersionable` gate. Integration: boot a real server against a git
|
|
4
|
-
// sandbox, open the inspector WS, edit a canvas `.tsx`, and prove a `git-status`
|
|
5
|
-
// message with the changed file arrives — the "badge increments within 500 ms"
|
|
6
|
-
// acceptance (generous 2 s ceiling for fs.watch + debounce + git on CI).
|
|
7
|
-
|
|
8
|
-
import { describe, expect, test } from 'bun:test';
|
|
9
|
-
import { writeFileSync } from 'node:fs';
|
|
10
|
-
import { join } from 'node:path';
|
|
11
|
-
|
|
12
|
-
import { __testing } from '../git/watch.ts';
|
|
13
|
-
import { bootServer, killProc, makeSandbox, nextPort } from './_helpers.ts';
|
|
14
|
-
|
|
15
|
-
describe('git/watch — isVersionable', () => {
|
|
16
|
-
const { isVersionable } = __testing;
|
|
17
|
-
test('matches versionable design content', () => {
|
|
18
|
-
for (const p of [
|
|
19
|
-
'ui/Pricing.tsx',
|
|
20
|
-
'ui/Pricing.css',
|
|
21
|
-
'ui/Pricing.meta.json',
|
|
22
|
-
'ui-pricing.annotations.svg',
|
|
23
|
-
'_comments/ui-pricing.json',
|
|
24
|
-
'_annotations/ui-pricing.svg',
|
|
25
|
-
]) {
|
|
26
|
-
expect(isVersionable(p)).toBe(true);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
test('ignores non-versionable noise', () => {
|
|
30
|
-
for (const p of ['ui/fixture.html', 'notes.txt', '_server.json', 'README.md']) {
|
|
31
|
-
expect(isVersionable(p)).toBe(false);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
function sh(dir: string, args: string[]) {
|
|
37
|
-
Bun.spawnSync(['git', ...args], {
|
|
38
|
-
cwd: dir,
|
|
39
|
-
env: { ...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null' },
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
describe('git/watch — live broadcast', () => {
|
|
44
|
-
test('editing a canvas .tsx broadcasts git-status with the changed file', async () => {
|
|
45
|
-
const { root, designRoot } = makeSandbox();
|
|
46
|
-
sh(root, ['init', '-q', '-b', 'main']);
|
|
47
|
-
sh(root, ['config', 'user.email', 'tester@maude.local']);
|
|
48
|
-
sh(root, ['config', 'user.name', 'Tester']);
|
|
49
|
-
sh(root, ['config', 'commit.gpgsign', 'false']);
|
|
50
|
-
sh(root, ['add', '-A']);
|
|
51
|
-
sh(root, ['commit', '-qm', 'seed']);
|
|
52
|
-
|
|
53
|
-
const port = nextPort();
|
|
54
|
-
const proc = await bootServer(root, port);
|
|
55
|
-
let socket: WebSocket | null = null;
|
|
56
|
-
try {
|
|
57
|
-
const messages: Array<{ type: string; payload?: { files?: Array<{ path: string }> } }> = [];
|
|
58
|
-
const sock = new WebSocket(`ws://localhost:${port}/_ws`);
|
|
59
|
-
socket = sock;
|
|
60
|
-
await new Promise<void>((res, rej) => {
|
|
61
|
-
sock.addEventListener('open', () => res());
|
|
62
|
-
sock.addEventListener('error', () => rej(new Error('ws error')));
|
|
63
|
-
setTimeout(() => rej(new Error('ws open timeout')), 2000);
|
|
64
|
-
});
|
|
65
|
-
sock.addEventListener('message', (ev) => {
|
|
66
|
-
try {
|
|
67
|
-
messages.push(JSON.parse(String(ev.data)));
|
|
68
|
-
} catch {
|
|
69
|
-
/* ignore non-JSON */
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Edit a NEW canvas .tsx — triggers fs:any → gitWatch → git-status.
|
|
74
|
-
writeFileSync(join(designRoot, 'ui', 'Live.tsx'), 'export default () => null\n');
|
|
75
|
-
|
|
76
|
-
// Poll for the broadcast (debounce 300 ms + git status latency).
|
|
77
|
-
const deadline = Date.now() + 2000;
|
|
78
|
-
let hit: (typeof messages)[number] | undefined;
|
|
79
|
-
while (Date.now() < deadline) {
|
|
80
|
-
hit = messages.find(
|
|
81
|
-
(m) =>
|
|
82
|
-
m.type === 'git-status' && m.payload?.files?.some((f) => f.path.endsWith('Live.tsx'))
|
|
83
|
-
);
|
|
84
|
-
if (hit) break;
|
|
85
|
-
await Bun.sleep(50);
|
|
86
|
-
}
|
|
87
|
-
expect(hit).toBeDefined();
|
|
88
|
-
} finally {
|
|
89
|
-
try {
|
|
90
|
-
socket?.close();
|
|
91
|
-
} catch {
|
|
92
|
-
/* ignore */
|
|
93
|
-
}
|
|
94
|
-
await killProc(proc);
|
|
95
|
-
}
|
|
96
|
-
}, 10_000);
|
|
97
|
-
});
|