@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
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { test } from 'node:test';
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
addHub,
|
|
9
|
-
getHub,
|
|
10
|
-
hubsConfigPath,
|
|
11
|
-
loadHubsConfig,
|
|
12
|
-
normalizeUrl,
|
|
13
|
-
removeHub,
|
|
14
|
-
saveHubsConfig,
|
|
15
|
-
setHubCodeModules,
|
|
16
|
-
} from './hubs-config.mjs';
|
|
17
|
-
|
|
18
|
-
function withTmpConfig(fn) {
|
|
19
|
-
const dir = mkdtempSync(join(tmpdir(), 'maude-hubs-cfg-'));
|
|
20
|
-
const path = join(dir, 'hubs.json');
|
|
21
|
-
const prior = process.env.HUBS_CONFIG_PATH;
|
|
22
|
-
process.env.HUBS_CONFIG_PATH = path;
|
|
23
|
-
try {
|
|
24
|
-
return fn(path);
|
|
25
|
-
} finally {
|
|
26
|
-
// `env.X = undefined` sets the STRING "undefined", so the override leaked
|
|
27
|
-
// out of the harness and every later `addHub` in the same process wrote a
|
|
28
|
-
// file literally named `undefined` into the repo root. `delete` is the
|
|
29
|
-
// only way to actually unset it.
|
|
30
|
-
if (prior === undefined) delete process.env.HUBS_CONFIG_PATH;
|
|
31
|
-
else process.env.HUBS_CONFIG_PATH = prior;
|
|
32
|
-
rmSync(dir, { recursive: true, force: true });
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
test('hubsConfigPath honors HUBS_CONFIG_PATH override', () => {
|
|
37
|
-
withTmpConfig((path) => {
|
|
38
|
-
assert.equal(hubsConfigPath(), path);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('loadHubsConfig returns empty when file missing', () => {
|
|
43
|
-
withTmpConfig(() => {
|
|
44
|
-
assert.deepEqual(loadHubsConfig(), { hubs: {} });
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('saveHubsConfig writes file at 0600 with parent dir creation', () => {
|
|
49
|
-
withTmpConfig((path) => {
|
|
50
|
-
saveHubsConfig({ hubs: { 'https://h.example': { token: 'mau_x', linkedAt: 1 } } });
|
|
51
|
-
assert.ok(existsSync(path));
|
|
52
|
-
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
53
|
-
assert.equal(parsed.hubs['https://h.example'].token, 'mau_x');
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('addHub upserts the same URL', () => {
|
|
58
|
-
withTmpConfig(() => {
|
|
59
|
-
addHub('https://h.example', 'mau_first');
|
|
60
|
-
addHub('https://h.example', 'mau_second');
|
|
61
|
-
const { hubs } = loadHubsConfig();
|
|
62
|
-
assert.equal(Object.keys(hubs).length, 1);
|
|
63
|
-
assert.equal(hubs['https://h.example'].token, 'mau_second');
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('removeHub returns false when entry absent, true when removed', () => {
|
|
68
|
-
withTmpConfig(() => {
|
|
69
|
-
assert.equal(removeHub('https://nope.example'), false);
|
|
70
|
-
addHub('https://h.example', 'mau_x');
|
|
71
|
-
assert.equal(removeHub('https://h.example'), true);
|
|
72
|
-
assert.equal(getHub('https://h.example'), null);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('getHub returns the record when present', () => {
|
|
77
|
-
withTmpConfig(() => {
|
|
78
|
-
addHub('https://h.example', 'mau_x');
|
|
79
|
-
const rec = getHub('https://h.example');
|
|
80
|
-
assert.ok(rec);
|
|
81
|
-
assert.equal(rec.token, 'mau_x');
|
|
82
|
-
assert.equal(typeof rec.linkedAt, 'number');
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('normalizeUrl lowercases scheme + host, strips trailing slash', () => {
|
|
87
|
-
assert.equal(normalizeUrl('HTTPS://Foo.Example.com/'), 'https://foo.example.com');
|
|
88
|
-
assert.equal(normalizeUrl('http://localhost:1234'), 'http://localhost:1234');
|
|
89
|
-
assert.equal(normalizeUrl('https://foo.example.com/path'), 'https://foo.example.com/path');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('normalizeUrl throws on bad input', () => {
|
|
93
|
-
assert.throws(() => normalizeUrl(''), /url must be a non-empty string/);
|
|
94
|
-
assert.throws(() => normalizeUrl('not a url'), /invalid url/);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('addHub keys URLs case-insensitively (same hub after host normalization)', () => {
|
|
98
|
-
withTmpConfig(() => {
|
|
99
|
-
addHub('https://HUB.example.com', 'mau_first');
|
|
100
|
-
addHub('https://hub.example.com/', 'mau_second');
|
|
101
|
-
const { hubs } = loadHubsConfig();
|
|
102
|
-
assert.equal(Object.keys(hubs).length, 1);
|
|
103
|
-
assert.equal(hubs['https://hub.example.com'].token, 'mau_second');
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Cloud Phase 25 C2 — the studio writes `role` into this shared file, and a
|
|
108
|
-
// CLI relink used to replace the record wholesale and drop it. Not an access
|
|
109
|
-
// hole (the cell refuses the write regardless), but it would silently show a
|
|
110
|
-
// viewer the editing UI again, which is exactly what the flag exists to stop.
|
|
111
|
-
test('a relink preserves the vouched role, and still clears per-machine attestations', () => {
|
|
112
|
-
withTmpConfig(() => {
|
|
113
|
-
addHub('https://p.cloud.maude.sh', 'mau_first', { adoptedAt: 111 });
|
|
114
|
-
// The studio stamps the role after a workspace sign-in.
|
|
115
|
-
const cfg = loadHubsConfig();
|
|
116
|
-
cfg.hubs['https://p.cloud.maude.sh'].role = 'viewer';
|
|
117
|
-
saveHubsConfig(cfg);
|
|
118
|
-
|
|
119
|
-
const after = addHub('https://p.cloud.maude.sh', 'mau_second');
|
|
120
|
-
assert.equal(after.token, 'mau_second');
|
|
121
|
-
assert.equal(after.role, 'viewer', 'the role survives a relink');
|
|
122
|
-
assert.equal(after.adoptedAt, undefined, 'a per-machine attestation does not');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// The code-module consent — the finding was that `codeModulesAllowed` was
|
|
127
|
-
// declared, read by the receiver, and set by NOTHING. So the gate could never
|
|
128
|
-
// open and `code-module` had no transport at all in hub-owned mode: an owner
|
|
129
|
-
// could push one through the door and no peer would ever accept it, which is
|
|
130
|
-
// the same "delivered nowhere" shape the file plane was built to fix.
|
|
131
|
-
//
|
|
132
|
-
// Through `withTmpConfig` like every other test here — the config is a real
|
|
133
|
-
// file on a real path, so a test that skips the harness reads whatever the
|
|
134
|
-
// previous one left behind.
|
|
135
|
-
|
|
136
|
-
test('the consent records, and survives a token re-save', () => {
|
|
137
|
-
withTmpConfig(() => {
|
|
138
|
-
const url = 'https://consent.example.test';
|
|
139
|
-
addHub(url, 'tok-1');
|
|
140
|
-
assert.equal(getHub(url).codeModulesAllowed, undefined, 'absent means no');
|
|
141
|
-
|
|
142
|
-
setHubCodeModules(url, true);
|
|
143
|
-
assert.equal(getHub(url).codeModulesAllowed, true);
|
|
144
|
-
|
|
145
|
-
// A silent token renewal must not revoke a decision the person made.
|
|
146
|
-
addHub(url, 'tok-2');
|
|
147
|
-
assert.equal(getHub(url).codeModulesAllowed, true);
|
|
148
|
-
assert.equal(getHub(url).token, 'tok-2');
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test('the consent is false for anything that is not an explicit yes', () => {
|
|
153
|
-
withTmpConfig(() => {
|
|
154
|
-
const url = 'https://consent-strict.example.test';
|
|
155
|
-
addHub(url, 't');
|
|
156
|
-
setHubCodeModules(url, 'yes');
|
|
157
|
-
assert.equal(getHub(url).codeModulesAllowed, false);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test('setting consent on an unlinked hub does nothing', () => {
|
|
162
|
-
withTmpConfig(() => {
|
|
163
|
-
assert.equal(setHubCodeModules('https://nobody.example.test', true), false);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
// pkg-root.mjs tests (DDR-166 T0b).
|
|
2
|
-
//
|
|
3
|
-
// The regression this locks down: a naive single-anchor check
|
|
4
|
-
// (`apps/studio/bin/screenshot.sh` alone) false-positives inside the Tauri
|
|
5
|
-
// desktop build, because `stage-resources.mjs` stages a full working copy of
|
|
6
|
-
// `apps/studio` into `target/debug/apps/studio/` for the sidecar's own
|
|
7
|
-
// runtime resolution — that staged copy has no `cli/`, so a compiled `maude`
|
|
8
|
-
// binary walking up from `target/debug/maude` matched it and stopped one
|
|
9
|
-
// level too early, resolving PKG_ROOT to `target/debug` instead of the real
|
|
10
|
-
// repo root. Caught by live testing against the real Tauri build (not a
|
|
11
|
-
// synthetic path), not by static review — worth a regression test.
|
|
12
|
-
|
|
13
|
-
import assert from 'node:assert/strict';
|
|
14
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
15
|
-
import { tmpdir } from 'node:os';
|
|
16
|
-
import { join } from 'node:path';
|
|
17
|
-
import { test } from 'node:test';
|
|
18
|
-
|
|
19
|
-
import { isPkgRoot, resolvePkgRoot, resolveTauriResourcePkgRoot } from './pkg-root.mjs';
|
|
20
|
-
|
|
21
|
-
function makeRealRoot(base) {
|
|
22
|
-
mkdirSync(join(base, 'apps', 'studio', 'bin'), { recursive: true });
|
|
23
|
-
writeFileSync(join(base, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
|
|
24
|
-
mkdirSync(join(base, 'cli', 'commands'), { recursive: true });
|
|
25
|
-
writeFileSync(join(base, 'cli', 'commands', 'design.mjs'), 'export const run = () => {};\n');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
test('isPkgRoot requires BOTH anchors — the staged-resources false-positive is rejected', () => {
|
|
29
|
-
const tmp = mkdtempSync(join(tmpdir(), 'maude-pkgroot-'));
|
|
30
|
-
try {
|
|
31
|
-
// The exact shape of the bug: apps/studio/bin/screenshot.sh present
|
|
32
|
-
// (mirrors stage-resources.mjs's staged copy), no cli/ at all.
|
|
33
|
-
mkdirSync(join(tmp, 'apps', 'studio', 'bin'), { recursive: true });
|
|
34
|
-
writeFileSync(join(tmp, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
|
|
35
|
-
assert.equal(isPkgRoot(tmp), false);
|
|
36
|
-
|
|
37
|
-
// cli/ alone, no apps/studio — also not a real root.
|
|
38
|
-
const tmp2 = mkdtempSync(join(tmpdir(), 'maude-pkgroot-'));
|
|
39
|
-
try {
|
|
40
|
-
mkdirSync(join(tmp2, 'cli', 'commands'), { recursive: true });
|
|
41
|
-
writeFileSync(join(tmp2, 'cli', 'commands', 'design.mjs'), '');
|
|
42
|
-
assert.equal(isPkgRoot(tmp2), false);
|
|
43
|
-
} finally {
|
|
44
|
-
rmSync(tmp2, { recursive: true, force: true });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Both anchors together — a genuine package root.
|
|
48
|
-
makeRealRoot(tmp);
|
|
49
|
-
assert.equal(isPkgRoot(tmp), true);
|
|
50
|
-
} finally {
|
|
51
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('resolveTauriResourcePkgRoot finds the .app sibling Resources tree (RCA G2)', () => {
|
|
56
|
-
// Mirror the packaged macOS layout: binary in Contents/MacOS, staged tree in
|
|
57
|
-
// the SIBLING Contents/Resources — NOT an ancestor of the binary, which is why
|
|
58
|
-
// the plain walk-up misses it and every `maude design <verb>` broke.
|
|
59
|
-
const app = mkdtempSync(join(tmpdir(), 'maude-app-'));
|
|
60
|
-
try {
|
|
61
|
-
const macosDir = join(app, 'Contents', 'MacOS');
|
|
62
|
-
const resources = join(app, 'Contents', 'Resources');
|
|
63
|
-
mkdirSync(macosDir, { recursive: true });
|
|
64
|
-
makeRealRoot(resources); // stages apps/studio/bin/screenshot.sh + cli/commands/design.mjs
|
|
65
|
-
|
|
66
|
-
// From the binary's own dir, the sibling probe must find Resources.
|
|
67
|
-
assert.equal(resolveTauriResourcePkgRoot(macosDir), resources);
|
|
68
|
-
|
|
69
|
-
// Regression guard: Resources WITHOUT cli/ (the shipped-broken v0.45.1 shape)
|
|
70
|
-
// must NOT resolve — that's exactly the false-positive isPkgRoot rejects.
|
|
71
|
-
const broken = mkdtempSync(join(tmpdir(), 'maude-app-broken-'));
|
|
72
|
-
try {
|
|
73
|
-
const bMacos = join(broken, 'Contents', 'MacOS');
|
|
74
|
-
const bRes = join(broken, 'Contents', 'Resources', 'apps', 'studio', 'bin');
|
|
75
|
-
mkdirSync(bMacos, { recursive: true });
|
|
76
|
-
mkdirSync(bRes, { recursive: true });
|
|
77
|
-
writeFileSync(join(bRes, 'screenshot.sh'), '#!/bin/sh\n'); // no cli/ staged
|
|
78
|
-
assert.equal(resolveTauriResourcePkgRoot(bMacos), null);
|
|
79
|
-
} finally {
|
|
80
|
-
rmSync(broken, { recursive: true, force: true });
|
|
81
|
-
}
|
|
82
|
-
} finally {
|
|
83
|
-
rmSync(app, { recursive: true, force: true });
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('resolvePkgRoot honors MAUDE_PKG_ROOT only when it actually satisfies both anchors', () => {
|
|
88
|
-
const real = mkdtempSync(join(tmpdir(), 'maude-pkgroot-real-'));
|
|
89
|
-
const fake = mkdtempSync(join(tmpdir(), 'maude-pkgroot-fake-'));
|
|
90
|
-
const prevOverride = process.env.MAUDE_PKG_ROOT;
|
|
91
|
-
try {
|
|
92
|
-
makeRealRoot(real);
|
|
93
|
-
// Fake: only the staged-resources-shaped anchor, same false-positive shape.
|
|
94
|
-
mkdirSync(join(fake, 'apps', 'studio', 'bin'), { recursive: true });
|
|
95
|
-
writeFileSync(join(fake, 'apps', 'studio', 'bin', 'screenshot.sh'), '#!/bin/sh\n');
|
|
96
|
-
|
|
97
|
-
process.env.MAUDE_PKG_ROOT = real;
|
|
98
|
-
assert.equal(resolvePkgRoot(), real);
|
|
99
|
-
|
|
100
|
-
process.env.MAUDE_PKG_ROOT = fake;
|
|
101
|
-
// Falls through past the (rejected) override to whatever the real
|
|
102
|
-
// walk-up finds in THIS test process — just assert it's NOT the fake
|
|
103
|
-
// dir, since accepting it would be exactly the regression.
|
|
104
|
-
assert.notEqual(resolvePkgRoot(), fake);
|
|
105
|
-
} finally {
|
|
106
|
-
if (prevOverride === undefined) delete process.env.MAUDE_PKG_ROOT;
|
|
107
|
-
else process.env.MAUDE_PKG_ROOT = prevOverride;
|
|
108
|
-
rmSync(real, { recursive: true, force: true });
|
|
109
|
-
rmSync(fake, { recursive: true, force: true });
|
|
110
|
-
}
|
|
111
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// DDR-061 + DDR-062 regression guard.
|
|
2
|
-
//
|
|
3
|
-
// DDR-061: a plugin must NEVER invoke a `cli/lib/*.mjs` module by a relative
|
|
4
|
-
// path unconditionally: in a marketplace install the plugin is copied alone into
|
|
5
|
-
// `cache/<marketplace>/<plugin>/<version>/`, so the sibling `cli/` does not
|
|
6
|
-
// exist and the call crashes with MODULE_NOT_FOUND. The reachable contract is
|
|
7
|
-
// the on-PATH `maude` binary (a declared plugin dependency).
|
|
8
|
-
//
|
|
9
|
-
// So any plugin file that runs `node … cli/lib/<x>.mjs` is only allowed when the
|
|
10
|
-
// SAME file also offers a `command -v maude` fallback (the sibling-first /
|
|
11
|
-
// maude-fallback pattern). This test fails loudly if a new straggler lands.
|
|
12
|
-
//
|
|
13
|
-
// DDR-062: plugin MARKDOWN must reach the studio bash helpers through
|
|
14
|
-
// `maude design <verb>`, never `bash "$CLAUDE_PLUGIN_ROOT/dev-server/bin/<x>.sh"`
|
|
15
|
-
// or `bash apps/studio/bin/<x>.sh`. The marketplace never copies the studio app
|
|
16
|
-
// beside a plugin, and a flow command's $CLAUDE_PLUGIN_ROOT points at
|
|
17
|
-
// plugins/flow (no bin/ at all). Per DDR-095 the helpers live under
|
|
18
|
-
// apps/studio/bin (was plugins/design/dev-server/bin). Prose mentions of the
|
|
19
|
-
// path are fine; INVOCATIONS (bash/sh/exec/$( prefixed) are banned.
|
|
20
|
-
|
|
21
|
-
import assert from 'node:assert/strict';
|
|
22
|
-
import { execSync } from 'node:child_process';
|
|
23
|
-
import { readFileSync } from 'node:fs';
|
|
24
|
-
import { test } from 'node:test';
|
|
25
|
-
|
|
26
|
-
test('no plugin runs `node cli/lib/*.mjs` without an on-PATH maude fallback', () => {
|
|
27
|
-
const out = execSync(
|
|
28
|
-
String.raw`grep -rlE 'node[^\n]*cli/lib/[a-z0-9_-]+\.mjs' plugins/ || true`,
|
|
29
|
-
{
|
|
30
|
-
encoding: 'utf8',
|
|
31
|
-
}
|
|
32
|
-
);
|
|
33
|
-
const files = out.trim().split('\n').filter(Boolean);
|
|
34
|
-
const offenders = files.filter((f) => !/command -v maude/.test(readFileSync(f, 'utf8')));
|
|
35
|
-
assert.deepEqual(
|
|
36
|
-
offenders,
|
|
37
|
-
[],
|
|
38
|
-
`These plugin files invoke a relative cli/lib module with no \`command -v maude\` fallback — they will crash in a marketplace install (DDR-061). Route through \`maude <subcommand>\` or guard with a sibling-exists check + maude fallback:\n ${offenders.join('\n ')}`
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('no plugin markdown invokes a $CLAUDE_PLUGIN_ROOT/dev-server/bin/*.sh helper (DDR-062)', () => {
|
|
43
|
-
// INVOCATION = the bin path preceded by bash / sh / exec, or inside a $(…)
|
|
44
|
-
// command substitution. Prose mentions of the path (backtick-wrapped, no verb)
|
|
45
|
-
// are exempt — they don't run anything. Matches both the $CLAUDE_PLUGIN_ROOT
|
|
46
|
-
// form and the repo-relative `plugins/<x>/dev-server/bin/` form.
|
|
47
|
-
const pattern = String.raw`(bash|sh|exec) +"?(\$\{?CLAUDE_PLUGIN_ROOT\}?|plugins/[a-z]+)/dev-server/bin/[A-Za-z0-9_-]+\.sh|\$\("?\$?\{?CLAUDE_PLUGIN_ROOT\}?/dev-server/bin/[A-Za-z0-9_-]+\.sh|(bash|sh|exec) +"?[^"\n]*apps/studio/bin/[A-Za-z0-9_-]+\.sh|\$\("?[^"\n]*apps/studio/bin/[A-Za-z0-9_-]+\.sh`;
|
|
48
|
-
const out = execSync(`grep -rnE '${pattern}' plugins --include='*.md' || true`, {
|
|
49
|
-
encoding: 'utf8',
|
|
50
|
-
});
|
|
51
|
-
const hits = out.trim().split('\n').filter(Boolean);
|
|
52
|
-
assert.deepEqual(
|
|
53
|
-
hits,
|
|
54
|
-
[],
|
|
55
|
-
`These plugin markdown lines INVOKE a dev-server bin helper directly — they break in marketplace installs (the dev-server is never copied beside a plugin) and in flow commands (whose $CLAUDE_PLUGIN_ROOT has no dev-server/). Route through \`maude design <verb>\` instead (DDR-062):\n ${hits.join('\n ')}`
|
|
56
|
-
);
|
|
57
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// DDR-006 (superseded) regression guard.
|
|
2
|
-
//
|
|
3
|
-
// Claude Code now prepends the `<plugin>:` namespace to every plugin
|
|
4
|
-
// command/agent/skill itself (fixed upstream in Claude Code 2.1.216 — see
|
|
5
|
-
// changelog "Fixed plugin skills with a `name` frontmatter field losing
|
|
6
|
-
// their plugin prefix in slash-command autocomplete" — and Claude Code
|
|
7
|
-
// 2.1.218 explicitly reserves `:` in agent names for that namespacing).
|
|
8
|
-
// Baking the prefix into our own `name:` frontmatter, which DDR-006
|
|
9
|
-
// (2026-05-13) required as a workaround for the OLD (opposite) bug, now
|
|
10
|
-
// produces a doubled prefix — `/design:design:new`, `flow:flow:a11y-auditor`.
|
|
11
|
-
//
|
|
12
|
-
// Two invariants this guards:
|
|
13
|
-
// 1. `name:` frontmatter in plugins/{design,flow}/{commands,agents,skills}/
|
|
14
|
-
// must be the BARE slug — no `design:`/`flow:` prefix.
|
|
15
|
-
// 2. `subagent_type:` references to our OWN plugin agents must carry
|
|
16
|
-
// exactly ONE `<plugin>:` prefix (the form the runtime's own namespace
|
|
17
|
-
// + our bare `name:` resolves to) — never zero (broken lookup against
|
|
18
|
-
// a namespaced registry) and never two (stale pre-fix leftover).
|
|
19
|
-
|
|
20
|
-
import assert from 'node:assert/strict';
|
|
21
|
-
import { execSync } from 'node:child_process';
|
|
22
|
-
import { test } from 'node:test';
|
|
23
|
-
|
|
24
|
-
function grep(pattern, extraArgs = '') {
|
|
25
|
-
const out = execSync(
|
|
26
|
-
`grep -rn ${extraArgs} '${pattern}' plugins/design plugins/flow --include='*.md' || true`,
|
|
27
|
-
{ encoding: 'utf8' }
|
|
28
|
-
);
|
|
29
|
-
return out.trim().split('\n').filter(Boolean);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
test('no plugin name: frontmatter carries a redundant design:/flow: prefix', () => {
|
|
33
|
-
const offenders = grep('^name: \\(design\\|flow\\):');
|
|
34
|
-
assert.deepEqual(
|
|
35
|
-
offenders,
|
|
36
|
-
[],
|
|
37
|
-
`These files declare name: with the plugin prefix baked in — Claude Code adds the plugin namespace itself now, so this doubles into e.g. /design:design:new (DDR-006 superseded):\n ${offenders.join('\n ')}`
|
|
38
|
-
);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('no doubled design:design: / flow:flow: namespace anywhere in plugin markdown', () => {
|
|
42
|
-
const offenders = grep('design:design:\\|flow:flow:');
|
|
43
|
-
assert.deepEqual(
|
|
44
|
-
offenders,
|
|
45
|
-
[],
|
|
46
|
-
`Doubled plugin namespace found — strip one level (DDR-006 superseded):\n ${offenders.join('\n ')}`
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('subagent_type references to our own plugin agents carry exactly one <plugin>: prefix', () => {
|
|
51
|
-
// Bare `subagent_type: <slug>` where <slug> looks like one of our
|
|
52
|
-
// agent-style names (-critic/-agent/-auditor/-hacker/-keeper/-director/
|
|
53
|
-
// -analyst suffix) but has no plugin prefix — excludes Claude Code
|
|
54
|
-
// built-ins (e.g. code-simplifier, which is not one of our plugin agents)
|
|
55
|
-
// and the `"<critic-name>"` template placeholder.
|
|
56
|
-
const bareOffenders = grep(
|
|
57
|
-
'subagent_type:.*"\\?[a-z][a-z0-9-]*\\(-critic\\|-agent\\|-auditor\\|-hacker\\|-keeper\\|-director\\|-analyst\\)"\\?'
|
|
58
|
-
).filter((line) => !/design:|flow:|<critic-name>|code-simplifier/.test(line));
|
|
59
|
-
assert.deepEqual(
|
|
60
|
-
bareOffenders,
|
|
61
|
-
[],
|
|
62
|
-
`These subagent_type references to a plugin-owned agent are missing the <plugin>: prefix and will fail to resolve against the namespaced registry:\n ${bareOffenders.join('\n ')}`
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const doubledOffenders = grep('subagent_type:.*\\(design:design:\\|flow:flow:\\)');
|
|
66
|
-
assert.deepEqual(
|
|
67
|
-
doubledOffenders,
|
|
68
|
-
[],
|
|
69
|
-
`These subagent_type references are double-prefixed (DDR-006 superseded):\n ${doubledOffenders.join('\n ')}`
|
|
70
|
-
);
|
|
71
|
-
});
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
// DDR-174 regression guard (T15).
|
|
2
|
-
//
|
|
3
|
-
// The whole security architecture of `/design:import --reconstruct` rests on
|
|
4
|
-
// ONE fact: every agent turn that ever reads the untrusted source image —
|
|
5
|
-
// `reconstruct-agent` (authoring) AND `reconstruct-critic` (the reality-check
|
|
6
|
-
// comparator) — has `tools: Read, Write, Glob, Grep` and NEVER `Bash`,
|
|
7
|
-
// `WebSearch`, or `WebFetch`. DDR-174's own Consequences section calls for
|
|
8
|
-
// exactly this test: "a targeted grep-based test mirroring
|
|
9
|
-
// plugin-cli-reachability.test.mjs's pattern should assert BOTH the authoring
|
|
10
|
-
// agent's AND the comparator agent's frontmatter never gain
|
|
11
|
-
// Bash/WebSearch/WebFetch, not just this DDR's prose." A future maintainer
|
|
12
|
-
// "helpfully" widening either agent's toolset (e.g. "just give it Bash so it
|
|
13
|
-
// can screenshot itself") would silently reopen DDR-174's entire closure —
|
|
14
|
-
// this fails loudly instead.
|
|
15
|
-
|
|
16
|
-
import assert from 'node:assert/strict';
|
|
17
|
-
import { readFileSync } from 'node:fs';
|
|
18
|
-
import { test } from 'node:test';
|
|
19
|
-
|
|
20
|
-
const AGENTS = [
|
|
21
|
-
'plugins/design/agents/reconstruct-agent.md',
|
|
22
|
-
'plugins/design/agents/reconstruct-critic.md',
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
26
|
-
|
|
27
|
-
function readFrontmatter(path) {
|
|
28
|
-
const text = readFileSync(path, 'utf8');
|
|
29
|
-
const fm = FRONTMATTER_RE.exec(text);
|
|
30
|
-
assert.ok(fm, `${path}: no frontmatter block found`);
|
|
31
|
-
return fm[1];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function readToolsLine(path) {
|
|
35
|
-
const fm = readFrontmatter(path);
|
|
36
|
-
const toolsLine = fm.split('\n').find((l) => l.startsWith('tools:'));
|
|
37
|
-
assert.ok(toolsLine, `${path}: frontmatter has no tools: line`);
|
|
38
|
-
return toolsLine;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for (const path of AGENTS) {
|
|
42
|
-
test(`${path}: tools: line never grants Bash`, () => {
|
|
43
|
-
const line = readToolsLine(path);
|
|
44
|
-
assert.ok(
|
|
45
|
-
!/\bBash\b/.test(line),
|
|
46
|
-
`${path} declares Bash — this reopens DDR-174's core closure (the agent reads an untrusted image and must never hold a shell). Line: ${line}`
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test(`${path}: tools: line never grants WebSearch or WebFetch`, () => {
|
|
51
|
-
const line = readToolsLine(path);
|
|
52
|
-
assert.ok(
|
|
53
|
-
!/\bWebSearch\b/.test(line) && !/\bWebFetch\b/.test(line),
|
|
54
|
-
`${path} declares WebSearch/WebFetch — DDR-174 requires these agents have no tool call that reaches the network. Line: ${line}`
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test(`${path}: tools: line is exactly Read, Write, Glob, Grep`, () => {
|
|
59
|
-
const line = readToolsLine(path);
|
|
60
|
-
const tools = line
|
|
61
|
-
.replace(/^tools:\s*/, '')
|
|
62
|
-
.split(',')
|
|
63
|
-
.map((t) => t.trim())
|
|
64
|
-
.filter(Boolean);
|
|
65
|
-
assert.deepEqual(
|
|
66
|
-
[...tools].sort(),
|
|
67
|
-
['Glob', 'Grep', 'Read', 'Write'],
|
|
68
|
-
`${path}: expected exactly Read/Write/Glob/Grep per DDR-174 Decision 1, got: ${line}`
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// DDR-174 Addendum (post-implementation adversarial review) — Write has no
|
|
73
|
-
// path restriction (Claude Code has no per-subagent path-scoping mechanism,
|
|
74
|
-
// verified authoritatively, not assumed) and the only real closure for a
|
|
75
|
-
// non-bypassPermissions session is a human approval prompt on any write.
|
|
76
|
-
// `permissionMode: default` is what makes that prompt happen instead of
|
|
77
|
-
// silently inheriting the parent session's (possibly bypassPermissions)
|
|
78
|
-
// mode. A future maintainer removing this line silently re-widens the
|
|
79
|
-
// agent's effective write reach for every downstream consumer NOT running
|
|
80
|
-
// bypassPermissions.
|
|
81
|
-
test(`${path}: frontmatter declares permissionMode: default (DDR-174 Addendum)`, () => {
|
|
82
|
-
const fm = readFrontmatter(path);
|
|
83
|
-
const line = fm.split('\n').find((l) => l.startsWith('permissionMode:'));
|
|
84
|
-
assert.ok(
|
|
85
|
-
line,
|
|
86
|
-
`${path}: missing permissionMode: default — without it this agent silently inherits the parent session's permission mode (e.g. bypassPermissions), losing the one real per-write approval gate available for its unrestricted Write tool (DDR-174 Addendum)`
|
|
87
|
-
);
|
|
88
|
-
assert.equal(
|
|
89
|
-
line.replace(/^permissionMode:\s*/, '').trim(),
|
|
90
|
-
'default',
|
|
91
|
-
`${path}: permissionMode must be exactly "default" (prompts on every write), not a looser mode. Line: ${line}`
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
test('import.md diff-check is whole-repo scoped, not just $DESIGN_ROOT (DDR-174 Addendum)', () => {
|
|
97
|
-
// The first implementation scoped `git status --porcelain -- "$DESIGN_ROOT"`,
|
|
98
|
-
// which made a write to .claude/settings.json, CLAUDE.md, or plugins/**
|
|
99
|
-
// structurally invisible to the check — an adversarial review built a full
|
|
100
|
-
// exploit chain out of exactly that gap. Assert the pathspec was actually
|
|
101
|
-
// widened, not just documented as widened in prose.
|
|
102
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
103
|
-
assert.ok(
|
|
104
|
-
!/git -C "\$REPO" status --porcelain -- "\$DESIGN_ROOT"/.test(importMd),
|
|
105
|
-
'import.md must NOT scope the diff-check to $DESIGN_ROOT only — this was the exact gap the DDR-174 Addendum closes (a write outside $DESIGN_ROOT, e.g. to .claude/settings.json, would be invisible to a $DESIGN_ROOT-scoped check)'
|
|
106
|
-
);
|
|
107
|
-
const wholeRepoOccurrences = (importMd.match(/git -C "\$REPO" status --porcelain\b/g) || [])
|
|
108
|
-
.length;
|
|
109
|
-
assert.ok(
|
|
110
|
-
wholeRepoOccurrences >= 2,
|
|
111
|
-
`import.md must run an UNSCOPED \`git -C "$REPO" status --porcelain\` for both the BEFORE (step 4) and AFTER (step 5b) snapshots — found ${wholeRepoOccurrences} occurrence(s)`
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('import.md snapshots the two well-known global Claude Code config paths (DDR-174 Addendum)', () => {
|
|
116
|
-
// A repo-scoped git diff can never see $HOME/.claude/** — these are the two
|
|
117
|
-
// specific files an adversarial review named as attack targets (a planted
|
|
118
|
-
// hook, or a poisoned global CLAUDE.md loaded into every future session).
|
|
119
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
120
|
-
assert.ok(
|
|
121
|
-
importMd.includes('$HOME/.claude/settings.json') &&
|
|
122
|
-
importMd.includes('$HOME/.claude/CLAUDE.md'),
|
|
123
|
-
'import.md must snapshot $HOME/.claude/settings.json and $HOME/.claude/CLAUDE.md before/after each round and hard-fail on any change (DDR-174 Addendum) — these are outside any repo-scoped diff check'
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('import.md stat calls are portable (GNU-first, BSD-fallback), not BSD-only (DDR-174 Addendum confirmation pass)', () => {
|
|
128
|
-
// The first Addendum revision used BSD-only `stat -f` unconditionally — it
|
|
129
|
-
// silently no-ops on Linux (a platform this project ships a .deb for),
|
|
130
|
-
// because GNU `stat -f` means something else entirely and errors out,
|
|
131
|
-
// swallowed by the trailing `2>/dev/null`. Both empty strings compare
|
|
132
|
-
// equal, so the check trivially "passes" without ever having checked
|
|
133
|
-
// anything. Assert every stat call tries GNU syntax (`stat -c`) first.
|
|
134
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
135
|
-
// Only scan actual shell inside fenced ```bash blocks — prose elsewhere
|
|
136
|
-
// legitimately mentions `stat -f` by name when explaining the old bug.
|
|
137
|
-
const codeBlocks = [...importMd.matchAll(/```bash\n([\s\S]*?)```/g)].map((m) => m[1]).join('\n');
|
|
138
|
-
const bareStatF = codeBlocks.match(/(?<!\|\| )\bstat -f\b/g) || [];
|
|
139
|
-
assert.deepEqual(
|
|
140
|
-
bareStatF,
|
|
141
|
-
[],
|
|
142
|
-
`import.md has a \`stat -f\` call in executable shell with no \`stat -c\` GNU fallback tried first — this silently no-ops on Linux (DDR-174 Addendum confirmation-pass finding). Found ${bareStatF.length} bare occurrence(s).`
|
|
143
|
-
);
|
|
144
|
-
const statCOccurrences = (codeBlocks.match(/stat -c '/g) || []).length;
|
|
145
|
-
assert.ok(
|
|
146
|
-
statCOccurrences >= 4,
|
|
147
|
-
`expected at least 4 GNU-first \`stat -c\` attempts (2 for the non-git repo-wide fallback, 2 for the global-config snapshot) — found ${statCOccurrences}`
|
|
148
|
-
);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test('import.md non-git fallback excludes _history/ (DDR-174 Addendum confirmation pass)', () => {
|
|
152
|
-
// The reconstruct loop writes its own screenshots/verdict files under
|
|
153
|
-
// _history/_reconstruct/<slug>/ every round. A git-repo target gets this
|
|
154
|
-
// excluded for free via .gitignore; the non-git `find`-based fallback has
|
|
155
|
-
// no such filter and would false-positive-abort on its own round-1 output
|
|
156
|
-
// the moment round 2's diff check runs, in a non-git target repo.
|
|
157
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
158
|
-
const findOccurrences = importMd.match(/find "\$REPO" -type f[^\n]*/g) || [];
|
|
159
|
-
assert.ok(
|
|
160
|
-
findOccurrences.length >= 2,
|
|
161
|
-
'expected the non-git fallback find command in both step 4 and step 5b'
|
|
162
|
-
);
|
|
163
|
-
for (const line of findOccurrences) {
|
|
164
|
-
assert.ok(
|
|
165
|
-
line.includes("-not -path '*/_history/*'"),
|
|
166
|
-
`non-git fallback find command must exclude _history/ (its own round-N artifacts) or every multi-round run in a non-git target repo false-positive-aborts: ${line}`
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('import.md uses mktemp for the _active.json patch, not a fixed /tmp filename (DDR-174 Addendum)', () => {
|
|
172
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
173
|
-
assert.ok(
|
|
174
|
-
!/\/tmp\/active\.json\.tmp/.test(importMd),
|
|
175
|
-
'import.md must not use a fixed, predictable /tmp filename for the _active.json patch — a symlink race target on a shared machine (DDR-174 Addendum adversarial finding)'
|
|
176
|
-
);
|
|
177
|
-
assert.ok(/mktemp/.test(importMd), 'import.md must use mktemp for its temp file(s)');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('design-critic.md is never repurposed as the reconstruct comparator (DDR-174 Decision 1 Round-2)', () => {
|
|
181
|
-
// The comparator must be reconstruct-critic (Bash-free), never the default
|
|
182
|
-
// Bash-capable design-critic — assert import.md's orchestrator spawns the
|
|
183
|
-
// dedicated agent, not design-critic, for the reality-check step.
|
|
184
|
-
const importMd = readFileSync('plugins/design/commands/import.md', 'utf8');
|
|
185
|
-
const reconstructSection = importMd.slice(importMd.indexOf('## `--reconstruct'));
|
|
186
|
-
assert.ok(
|
|
187
|
-
reconstructSection.includes('design:reconstruct-critic'),
|
|
188
|
-
'import.md --reconstruct mode must spawn design:reconstruct-critic for the reality-check step'
|
|
189
|
-
);
|
|
190
|
-
assert.ok(
|
|
191
|
-
!/subagent_type:\s*"design:design-critic"/.test(reconstructSection),
|
|
192
|
-
'import.md --reconstruct mode must NOT spawn the default design-critic as its comparator (DDR-174 Decision 1 Round-2) — it is Bash-capable and reopens the trifecta this DDR closes'
|
|
193
|
-
);
|
|
194
|
-
});
|