@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,235 +0,0 @@
|
|
|
1
|
-
// DDR-184 (+ DDR-185, hardened per its security addendum) — the curated tool
|
|
2
|
-
// allow-list the bridge auto-approves so the design workflow never stalls on
|
|
3
|
-
// a per-edit / per-`maude` permission prompt (the "Manual mode blocks every
|
|
4
|
-
// edit" complaint). Three things under test:
|
|
5
|
-
//
|
|
6
|
-
// (1) WIRE contract — the list lands on `_meta.claudeCode.options.allowedTools`
|
|
7
|
-
// (SDK `allowedTools`, sdk.d.ts:1331), coexisting with the DDR-144
|
|
8
|
-
// `settingSources` narrowing and the DDR-143 `plugins` carrier. Same
|
|
9
|
-
// adapter/SDK-INTERNAL `_meta` path as acp-session-plugins.test.ts — a
|
|
10
|
-
// bump that stops forwarding it must fail HERE, not silently re-prompt.
|
|
11
|
-
// (2) SOURCE-OF-TRUTH guard — the Bash rules are EXACTLY `Bash(maude:*)`
|
|
12
|
-
// plus a closed read-only fs verb set (DDR-185) — nothing else. A
|
|
13
|
-
// security fan-out found the ORIGINAL DDR-185 cut's `Bash(agent-browser:*)`
|
|
14
|
-
// entry was a zero-confirmation session-hijack primitive (agent-browser's
|
|
15
|
-
// own bundled skill recommends a persistent, real-login Chrome profile)
|
|
16
|
-
// and `Bash(find:*)` was unrestricted command execution via `-exec`, not
|
|
17
|
-
// "mutation" as first characterized — both are cut, not patched, because
|
|
18
|
-
// neither residual is fixable via prefix-matching. `agent-browser` is
|
|
19
|
-
// now reached ONLY through the hardened `agent-browser-safe` verb
|
|
20
|
-
// (`Bash(maude:*)` covers it — no separate allow-list entry). If any of
|
|
21
|
-
// this drifts, this test fails loudly.
|
|
22
|
-
// (3) `WebSearch`/`WebFetch` (DDR-185) are present as bare native tool names
|
|
23
|
-
// — no prefix-matching involved, so no source-of-truth guard needed the
|
|
24
|
-
// way the Bash rules need one.
|
|
25
|
-
// (4) NO WRITE TOOL is on this list (feature-acp-write-path-scope). This
|
|
26
|
-
// file used to assert the exact opposite — that Edit/Write/NotebookEdit
|
|
27
|
-
// WERE present — so read the test's own comment before "restoring" it.
|
|
28
|
-
// Write auto-approval moved into the bridge's path gate, which is the
|
|
29
|
-
// only place a per-call target path exists; see acp-write-scope.test.ts.
|
|
30
|
-
|
|
31
|
-
import { describe, expect, test } from 'bun:test';
|
|
32
|
-
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
33
|
-
import { dirname, join } from 'node:path';
|
|
34
|
-
|
|
35
|
-
import { MAUDE_DEFAULT_ALLOWED_TOOLS, newSessionParams } from '../acp/bridge.ts';
|
|
36
|
-
import type { SdkPluginConfig } from '../acp/plugin-bootstrap.ts';
|
|
37
|
-
import { WRITE_TOOL_NAMES } from '../acp/write-scope.ts';
|
|
38
|
-
|
|
39
|
-
type Meta = {
|
|
40
|
-
systemPrompt?: { append?: string };
|
|
41
|
-
claudeCode?: {
|
|
42
|
-
options?: {
|
|
43
|
-
allowedTools?: string[];
|
|
44
|
-
plugins?: SdkPluginConfig[];
|
|
45
|
-
settingSources?: string[];
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const PLUGINS: SdkPluginConfig[] = [
|
|
51
|
-
{ type: 'local', path: '/bundle/plugins/design', skipMcpDiscovery: true },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
describe('newSessionParams — allowedTools carrier shape (DDR-184)', () => {
|
|
55
|
-
test('the allow-list rides _meta.claudeCode.options.allowedTools', () => {
|
|
56
|
-
const opts = (newSessionParams('/repo', undefined)._meta as Meta).claudeCode?.options;
|
|
57
|
-
expect(opts?.allowedTools).toEqual([...MAUDE_DEFAULT_ALLOWED_TOOLS]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('allowedTools is a COPY, not the shared module constant (no accidental mutation)', () => {
|
|
61
|
-
const opts = (newSessionParams('/repo')._meta as Meta).claudeCode?.options;
|
|
62
|
-
expect(opts?.allowedTools).not.toBe(MAUDE_DEFAULT_ALLOWED_TOOLS);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('coexists with settingSources (DDR-144) and plugins (DDR-143) under one options', () => {
|
|
66
|
-
const opts = (newSessionParams('/repo', 'BRIEF', PLUGINS)._meta as Meta).claudeCode?.options;
|
|
67
|
-
expect(opts?.settingSources).toEqual(['user']);
|
|
68
|
-
expect(opts?.plugins).toEqual(PLUGINS);
|
|
69
|
-
expect(opts?.allowedTools).toEqual([...MAUDE_DEFAULT_ALLOWED_TOOLS]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('present even with no plugins (npm / web / power-user path)', () => {
|
|
73
|
-
const opts = (newSessionParams('/repo', 'BRIEF', [])._meta as Meta).claudeCode?.options;
|
|
74
|
-
expect(opts?.plugins).toBeUndefined();
|
|
75
|
-
expect(opts?.allowedTools).toEqual([...MAUDE_DEFAULT_ALLOWED_TOOLS]);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('MAUDE_DEFAULT_ALLOWED_TOOLS — source-of-truth guard (DDR-184 / DDR-062)', () => {
|
|
80
|
-
const bashRules = MAUDE_DEFAULT_ALLOWED_TOOLS.filter((t) => t.startsWith('Bash'));
|
|
81
|
-
|
|
82
|
-
test('the READ-ONLY file tools are present', () => {
|
|
83
|
-
for (const t of ['Read', 'Glob', 'Grep']) {
|
|
84
|
-
expect(MAUDE_DEFAULT_ALLOWED_TOOLS).toContain(t);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('NO write tool is name-allowed — they are path-gated instead (feature-acp-write-path-scope)', () => {
|
|
89
|
-
// This assertion is the whole point of the change, so it is worth being
|
|
90
|
-
// explicit about WHY it inverts what this file used to assert.
|
|
91
|
-
//
|
|
92
|
-
// A bare tool name on this list means the CLI approves the call itself and
|
|
93
|
-
// `requestPermission` is NEVER invoked — so a path condition cannot be
|
|
94
|
-
// attached to an entry here, at all. Auto-approving a write therefore had
|
|
95
|
-
// to be moved into the bridge's own gate (`classifyWrite` →
|
|
96
|
-
// `writeTargetsInsideProject`), where a per-call path exists. DDR-184's
|
|
97
|
-
// no-prompt-per-edit outcome is fully preserved for in-project writes; what
|
|
98
|
-
// changed is that a write to `~/.zshenv` now prompts instead of landing
|
|
99
|
-
// silently with no rollback.
|
|
100
|
-
//
|
|
101
|
-
// If someone "fixes" a re-prompting regression by putting Write back on this
|
|
102
|
-
// list, this test is what tells them they just reopened the hole.
|
|
103
|
-
for (const t of [...WRITE_TOOL_NAMES]) {
|
|
104
|
-
expect(MAUDE_DEFAULT_ALLOWED_TOOLS).not.toContain(t);
|
|
105
|
-
}
|
|
106
|
-
// Guard the shape too — an `Edit(...)`-style scoped entry would also bypass
|
|
107
|
-
// the bridge gate, and `not.toContain` on the bare name would miss it.
|
|
108
|
-
for (const t of MAUDE_DEFAULT_ALLOWED_TOOLS) {
|
|
109
|
-
const bare = t.replace(/\(.*$/, '');
|
|
110
|
-
expect(WRITE_TOOL_NAMES.has(bare)).toBe(false);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('WebSearch and WebFetch are present (DDR-185)', () => {
|
|
115
|
-
for (const t of ['WebSearch', 'WebFetch']) {
|
|
116
|
-
expect(MAUDE_DEFAULT_ALLOWED_TOOLS).toContain(t);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test('the Bash rules are EXACTLY this closed set — never a bare/un-scoped Bash', () => {
|
|
121
|
-
// A bare `Bash` (or `Bash(*)`) would auto-approve arbitrary command execution
|
|
122
|
-
// — exactly the blanket surface DDR-179 kept behind the prompt. Guard against
|
|
123
|
-
// anyone widening it: the list may auto-approve `maude` and the closed
|
|
124
|
-
// read-only fs verb set (DDR-185) — nothing else. In particular:
|
|
125
|
-
// - `Bash(curl:*)` must NEVER appear — curl is routed through the
|
|
126
|
-
// `curl-local` verb (covered by `Bash(maude:*)`) instead.
|
|
127
|
-
// - `Bash(agent-browser:*)` must NEVER appear — a security fan-out found
|
|
128
|
-
// it was a zero-confirmation session-hijack primitive; agent-browser is
|
|
129
|
-
// routed through the `agent-browser-safe` verb instead.
|
|
130
|
-
// - `Bash(find:*)` must NEVER appear — `find -exec` is unrestricted
|
|
131
|
-
// command execution, not "mutation"; there is no verb substitute, it
|
|
132
|
-
// is simply cut.
|
|
133
|
-
// - the read-only fs verb group must NEVER appear — every one of them
|
|
134
|
-
// accepts `>`, making the rule an arbitrary-write grant. See the
|
|
135
|
-
// dedicated test below.
|
|
136
|
-
expect(bashRules).toEqual(['Bash(maude:*)']);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test('NO redirect-capable bare-command Bash rule — `cat > file` is an arbitrary write (F1)', () => {
|
|
140
|
-
// SECURITY (security-auditor F1, PoC'd live against claude 2.1.220). The
|
|
141
|
-
// read-only fs group (ls/cat/pwd/head/tail/wc/tree/file/stat) USED to be on
|
|
142
|
-
// this list, justified as adding no incremental READ capability. True, and
|
|
143
|
-
// beside the point: Claude Code's `Bash(<cmd>:*)` prefix rule does not
|
|
144
|
-
// reject shell redirection, so `cat > ~/.zshenv <<'EOF' … EOF` matched
|
|
145
|
-
// `Bash(cat:*)`, was self-approved by the CLI, never reached
|
|
146
|
-
// `requestPermission`, and wrote model-authored arbitrary content to an
|
|
147
|
-
// arbitrary path — with no write tool involved at all. That is the A2
|
|
148
|
-
// primitive the write-path gate exists to close, reachable by a CHEAPER
|
|
149
|
-
// route than the write tools themselves.
|
|
150
|
-
//
|
|
151
|
-
// Cut rather than patched (same call DDR-185 made for `find` and
|
|
152
|
-
// `agent-browser`): a prefix rule cannot inspect what follows the command
|
|
153
|
-
// name, so there is nothing to patch. If they come back, they must come
|
|
154
|
-
// back as a hardened `maude design` wrapper verb, which CAN reject `>`.
|
|
155
|
-
//
|
|
156
|
-
// This test is what makes re-adding any of them a loud failure rather than
|
|
157
|
-
// a silent reopening of the hole.
|
|
158
|
-
for (const verb of ['ls', 'cat', 'pwd', 'head', 'tail', 'wc', 'tree', 'file', 'stat']) {
|
|
159
|
-
expect(MAUDE_DEFAULT_ALLOWED_TOOLS).not.toContain(`Bash(${verb}:*)`);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
test('the `maude` Bash rule is load-bearing on DDR-062: every design helper is a `maude design <verb>`', () => {
|
|
164
|
-
// Resolve cli/commands/design.mjs relative to this test file's real path
|
|
165
|
-
// (mirrors acp-session-plugins.test.ts's realpath dance for compiled roots).
|
|
166
|
-
const here = dirname(realpathSync(import.meta.url.replace('file://', '')));
|
|
167
|
-
const designCli = join(here, '..', '..', '..', 'cli', 'commands', 'design.mjs');
|
|
168
|
-
expect(existsSync(designCli)).toBe(true);
|
|
169
|
-
const src = readFileSync(designCli, 'utf8');
|
|
170
|
-
// The dispatch table the `Bash(maude:*)` scope rests on — helpers reached via
|
|
171
|
-
// `maude design <verb>`, not raw `bash <path>.sh` (DDR-062). If this marker
|
|
172
|
-
// disappears, the one-rule assumption needs re-checking.
|
|
173
|
-
expect(src).toContain('BIN_VERBS');
|
|
174
|
-
expect(src).toMatch(/maude design <verb>/);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('the `curl-local` verb exists and is reached via `maude design <verb>` (DDR-185)', () => {
|
|
178
|
-
// The mechanism the `Bash(agent-browser:*)`/fs-list comment in bridge.ts
|
|
179
|
-
// promises for curl: real host enforcement via a first-party verb, not a
|
|
180
|
-
// Bash prefix rule. If this verb disappears from BIN_VERBS, the DDR-185
|
|
181
|
-
// curl story (and the bootstrap-brief nudge pointing at it) goes stale.
|
|
182
|
-
const here = dirname(realpathSync(import.meta.url.replace('file://', '')));
|
|
183
|
-
const designCli = join(here, '..', '..', '..', 'cli', 'commands', 'design.mjs');
|
|
184
|
-
const src = readFileSync(designCli, 'utf8');
|
|
185
|
-
expect(src).toMatch(/'curl-local'/);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
test('the `agent-browser-safe` verb exists and is reached via `maude design <verb>` (DDR-185 security addendum)', () => {
|
|
189
|
-
// The replacement for the reverted `Bash(agent-browser:*)` entry — real
|
|
190
|
-
// subcommand/flag enforcement via a first-party verb, not a Bash prefix
|
|
191
|
-
// rule. If this verb disappears from BIN_VERBS, motion-critic.md/edit.md's
|
|
192
|
-
// documented raw agent-browser calls go back to prompting (not silently
|
|
193
|
-
// insecure — but the friction-reduction this DDR promises goes stale).
|
|
194
|
-
const here = dirname(realpathSync(import.meta.url.replace('file://', '')));
|
|
195
|
-
const designCli = join(here, '..', '..', '..', 'cli', 'commands', 'design.mjs');
|
|
196
|
-
const src = readFileSync(designCli, 'utf8');
|
|
197
|
-
expect(src).toMatch(/'agent-browser-safe'/);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test('plugin markdown no longer documents a RAW agent-browser SCREENSHOT/OPEN/NAVIGATE call (DDR-185 security addendum)', () => {
|
|
201
|
-
// motion-critic.md and edit.md are the two files that originally justified
|
|
202
|
-
// `Bash(agent-browser:*)` (raw calls not reached via `maude design <verb>`).
|
|
203
|
-
// screenshot/open/navigate now go through the hardened wrapper — a
|
|
204
|
-
// regression here means either those calls silently went back to
|
|
205
|
-
// prompting every time, or (worse) someone re-introduced a raw call the
|
|
206
|
-
// allow-list no longer covers. `eval` is the deliberate exception (round
|
|
207
|
-
// 3: removed from the wrapper's own allow-list entirely — arbitrary JS
|
|
208
|
-
// execution can't be argv-constrained — so it's EXPECTED to stay a raw,
|
|
209
|
-
// prompting `agent-browser eval` call; see both files' own comments).
|
|
210
|
-
const here = dirname(realpathSync(import.meta.url.replace('file://', '')));
|
|
211
|
-
const pluginsDir = join(here, '..', '..', '..', 'plugins', 'design');
|
|
212
|
-
for (const rel of ['agents/motion-critic.md', 'commands/edit.md']) {
|
|
213
|
-
const src = readFileSync(join(pluginsDir, rel), 'utf8');
|
|
214
|
-
expect(src).not.toMatch(/(?<!maude design )agent-browser (screenshot|open|navigate)\b/);
|
|
215
|
-
expect(src).toContain('agent-browser eval'); // deliberately raw — see comment above
|
|
216
|
-
}
|
|
217
|
-
// Only motion-critic.md actually calls the wrapper (for `screenshot`) —
|
|
218
|
-
// edit.md's sole agent-browser use was `eval`, which reverted fully to
|
|
219
|
-
// raw, so it has no `agent-browser-safe` invocation left at all.
|
|
220
|
-
const motionCritic = readFileSync(join(pluginsDir, 'agents/motion-critic.md'), 'utf8');
|
|
221
|
-
expect(motionCritic).toContain('maude design agent-browser-safe');
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
test('agent-browser-safe does NOT support eval (DDR-185 round-3 security addendum)', () => {
|
|
225
|
-
// A future accidental re-add of eval to the wrapper's own allow-list
|
|
226
|
-
// would silently reopen the zero-click session-hijack chain (ethical-
|
|
227
|
-
// hacker Finding 1: eval's fetch()/window.location defeat
|
|
228
|
-
// --allowed-domains entirely, and no argv check can constrain arbitrary
|
|
229
|
-
// JS execution). Source-of-truth guard against bridge.ts's own wrapper.
|
|
230
|
-
const here = dirname(realpathSync(import.meta.url.replace('file://', '')));
|
|
231
|
-
const wrapperPath = join(here, '..', 'bin', '_agent-browser-safe.mjs');
|
|
232
|
-
const src = readFileSync(wrapperPath, 'utf8');
|
|
233
|
-
expect(src).not.toMatch(/^\s*eval:\s*\[/m);
|
|
234
|
-
});
|
|
235
|
-
});
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
// DDR-143 — session-scoped plugin auto-bootstrap: the WIRE contract.
|
|
2
|
-
//
|
|
3
|
-
// Two layers: (1) the newSession params carrier — the resolved plugin configs
|
|
4
|
-
// must land on `_meta.claudeCode.options.plugins`, coexisting with the studio
|
|
5
|
-
// brief's `_meta.systemPrompt.append`; (2) the UPGRADE GUARD — that `_meta` path
|
|
6
|
-
// is adapter/SDK-INTERNAL and undocumented, so a dependency bump that stops
|
|
7
|
-
// forwarding `_meta.claudeCode.options` (adapter) or drops `plugins` (SDK) must
|
|
8
|
-
// fail HERE, loudly, instead of silently shipping a desktop app whose chat
|
|
9
|
-
// resolves no `/design:*` on a pristine machine.
|
|
10
|
-
|
|
11
|
-
import { describe, expect, test } from 'bun:test';
|
|
12
|
-
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
13
|
-
import { dirname, join } from 'node:path';
|
|
14
|
-
|
|
15
|
-
import { newSessionParams } from '../acp/bridge.ts';
|
|
16
|
-
import type { SdkPluginConfig } from '../acp/plugin-bootstrap.ts';
|
|
17
|
-
|
|
18
|
-
const PLUGINS: SdkPluginConfig[] = [
|
|
19
|
-
{ type: 'local', path: '/bundle/plugins/design', skipMcpDiscovery: true },
|
|
20
|
-
{ type: 'local', path: '/bundle/plugins/flow', skipMcpDiscovery: true },
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
type Meta = {
|
|
24
|
-
systemPrompt?: { append?: string };
|
|
25
|
-
claudeCode?: {
|
|
26
|
-
options?: {
|
|
27
|
-
plugins?: SdkPluginConfig[];
|
|
28
|
-
settingSources?: string[];
|
|
29
|
-
settings?: { enabledPlugins?: Record<string, boolean> };
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
describe('newSessionParams — plugin carrier shape', () => {
|
|
35
|
-
test('with plugins: they ride _meta.claudeCode.options.plugins', () => {
|
|
36
|
-
const p = newSessionParams('/repo', undefined, PLUGINS);
|
|
37
|
-
expect(p.cwd).toBe('/repo');
|
|
38
|
-
expect((p._meta as Meta).claudeCode?.options?.plugins).toEqual(PLUGINS);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('empty plugins: claudeCode carries settingSources but NO plugins (power-user / web no-op)', () => {
|
|
42
|
-
const p = newSessionParams('/repo', 'BRIEF', []);
|
|
43
|
-
const opts = (p._meta as Meta).claudeCode?.options;
|
|
44
|
-
expect(opts?.plugins).toBeUndefined();
|
|
45
|
-
expect(opts?.settingSources).toEqual(['user']); // security narrowing always present
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('undefined plugins: claudeCode carries settingSources, no plugins', () => {
|
|
49
|
-
const p = newSessionParams('/repo', 'BRIEF');
|
|
50
|
-
const opts = (p._meta as Meta).claudeCode?.options;
|
|
51
|
-
expect(opts?.plugins).toBeUndefined();
|
|
52
|
-
expect(opts?.settingSources).toEqual(['user']);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('brief + plugins coexist under one _meta (both siblings intact)', () => {
|
|
56
|
-
const p = newSessionParams('/repo', 'BRIEF', PLUGINS);
|
|
57
|
-
const meta = p._meta as Meta;
|
|
58
|
-
expect(meta.systemPrompt?.append).toBe('BRIEF');
|
|
59
|
-
expect(meta.claudeCode?.options?.plugins).toEqual(PLUGINS);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('plugins only, no brief: still no systemPrompt, but claudeCode present', () => {
|
|
63
|
-
const p = newSessionParams('/repo', undefined, PLUGINS);
|
|
64
|
-
const meta = p._meta as Meta;
|
|
65
|
-
expect(meta.systemPrompt).toBeUndefined();
|
|
66
|
-
expect(meta.claudeCode?.options?.plugins).toEqual(PLUGINS);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('nothing injected: _meta still carries the settingSources security narrowing', () => {
|
|
70
|
-
const p = newSessionParams('/repo', undefined, []);
|
|
71
|
-
const meta = p._meta as Meta;
|
|
72
|
-
expect(meta.systemPrompt).toBeUndefined();
|
|
73
|
-
expect(meta.claudeCode?.options?.plugins).toBeUndefined();
|
|
74
|
-
// Every Maude bridge session is auto-approving → settingSources is ALWAYS narrowed.
|
|
75
|
-
expect(meta.claudeCode?.options?.settingSources).toEqual(['user']);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('settingSources is narrowed to user-only on EVERY session (DDR-144 F2)', () => {
|
|
79
|
-
for (const p of [
|
|
80
|
-
newSessionParams('/repo'),
|
|
81
|
-
newSessionParams('/repo', 'BRIEF'),
|
|
82
|
-
newSessionParams('/repo', 'BRIEF', PLUGINS),
|
|
83
|
-
newSessionParams('/repo', undefined, PLUGINS),
|
|
84
|
-
]) {
|
|
85
|
-
expect((p._meta as Meta).claudeCode?.options?.settingSources).toEqual(['user']);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// DDR-168 — the structural double-registration guard: a non-empty `plugins`
|
|
90
|
-
// must also force off any natively-loaded user-level copy of the same id via
|
|
91
|
-
// the SDK's "flag" settings layer, so the bundled copy is the ONLY one that
|
|
92
|
-
// ever loads.
|
|
93
|
-
test('with plugins: forces design@maude off via options.settings.enabledPlugins (double-registration guard)', () => {
|
|
94
|
-
const p = newSessionParams('/repo', undefined, PLUGINS);
|
|
95
|
-
expect((p._meta as Meta).claudeCode?.options?.settings?.enabledPlugins).toEqual({
|
|
96
|
-
'design@maude': false,
|
|
97
|
-
// kgai (third-party, injected by the desktop bundle for autonomous capture —
|
|
98
|
-
// feature-kgai-ecosystem-integration Phase 8). Suppressing a user-installed
|
|
99
|
-
// copy matters MORE here than for our own plugins: it would run its own
|
|
100
|
-
// SessionStart install.sh and point at a different engine version than the
|
|
101
|
-
// pinned, signed sidecar we ship.
|
|
102
|
-
kgai: false,
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('empty plugins: options.settings is entirely absent (web/npm path unaffected)', () => {
|
|
107
|
-
const p = newSessionParams('/repo', 'BRIEF', []);
|
|
108
|
-
expect((p._meta as Meta).claudeCode?.options?.settings).toBeUndefined();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test('undefined plugins: options.settings is entirely absent', () => {
|
|
112
|
-
const p = newSessionParams('/repo', 'BRIEF');
|
|
113
|
-
expect((p._meta as Meta).claudeCode?.options?.settings).toBeUndefined();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe('upgrade guard — installed adapter + SDK still honor the plugins contract', () => {
|
|
118
|
-
const adapterEntry = join(
|
|
119
|
-
import.meta.dir,
|
|
120
|
-
'..',
|
|
121
|
-
'node_modules',
|
|
122
|
-
'@agentclientprotocol',
|
|
123
|
-
'claude-agent-acp',
|
|
124
|
-
'dist',
|
|
125
|
-
'acp-agent.js'
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
test('adapter newSession reads _meta.claudeCode.options and forwards it to query()', () => {
|
|
129
|
-
expect(existsSync(adapterEntry)).toBe(true);
|
|
130
|
-
const src = readFileSync(adapterEntry, 'utf8');
|
|
131
|
-
// Verified at claude-agent-acp@0.49.0 (acp-agent.js newSession):
|
|
132
|
-
// const userProvidedOptions = sessionMeta?.claudeCode?.options; (:2302)
|
|
133
|
-
// const options = { …, ...userProvidedOptions, … }; (:2333)
|
|
134
|
-
// const q = query({ prompt: input, options }); (:2455)
|
|
135
|
-
// `plugins` is not in the override list after the spread, so it survives into
|
|
136
|
-
// query(). A bump that renames/drops any link in this chain must fail here —
|
|
137
|
-
// then adapt, or fall back to settings.enabledPlugins + a local marketplace
|
|
138
|
-
// (plan Task 1 fallback).
|
|
139
|
-
expect(src).toMatch(/claudeCode\s*(\?\.|\.)\s*options/);
|
|
140
|
-
expect(src).toContain('userProvidedOptions');
|
|
141
|
-
expect(src).toMatch(/\.\.\.userProvidedOptions/);
|
|
142
|
-
expect(src).toMatch(/query\(\{[\s\S]{0,80}options[\s\S]{0,40}\}\)/);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test('SDK Options declares plugins?: SdkPluginConfig[] (the accepted field)', () => {
|
|
146
|
-
// Resolve the transitive @anthropic-ai/claude-agent-sdk. Resolve from the
|
|
147
|
-
// adapter's REAL dir (pnpm store), where the SDK is a peer sibling — the
|
|
148
|
-
// apps/studio symlink alone doesn't expose the pnpm peer node_modules.
|
|
149
|
-
let sdkPkg: string | null = null;
|
|
150
|
-
try {
|
|
151
|
-
const realAdapterDir = dirname(realpathSync(adapterEntry));
|
|
152
|
-
sdkPkg = Bun.resolveSync('@anthropic-ai/claude-agent-sdk/package.json', realAdapterDir);
|
|
153
|
-
} catch {
|
|
154
|
-
sdkPkg = null;
|
|
155
|
-
}
|
|
156
|
-
expect(sdkPkg).not.toBeNull();
|
|
157
|
-
const dts = join(dirname(sdkPkg as string), 'sdk.d.ts');
|
|
158
|
-
expect(existsSync(dts)).toBe(true);
|
|
159
|
-
const src = readFileSync(dts, 'utf8');
|
|
160
|
-
// sdk.d.ts:1683 `plugins?: SdkPluginConfig[];` + :3766 the { type:'local'; path } shape.
|
|
161
|
-
expect(src).toMatch(/plugins\?\s*:\s*SdkPluginConfig\[\]/);
|
|
162
|
-
expect(src).toMatch(/SdkPluginConfig\s*=\s*\{/);
|
|
163
|
-
expect(src).toMatch(/type:\s*'local'/);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// DDR-168 — the same style of guard, for the `options.settings` mechanism the
|
|
167
|
-
// double-registration fix depends on: `settings` must NOT be among the fields
|
|
168
|
-
// the adapter overrides after the `...userProvidedOptions` spread (else our
|
|
169
|
-
// `enabledPlugins: false` override would be silently discarded), and the SDK
|
|
170
|
-
// must still declare `Settings.enabledPlugins` as an accepted field.
|
|
171
|
-
test('adapter forwards `settings` from userProvidedOptions and only ever overrides it conditionally when the caller left it unset', () => {
|
|
172
|
-
expect(existsSync(adapterEntry)).toBe(true);
|
|
173
|
-
const src = readFileSync(adapterEntry, 'utf8');
|
|
174
|
-
// Locate the `...userProvidedOptions` spread and inspect what follows it up
|
|
175
|
-
// to the `query({ options })` call. Verified live at claude-agent-acp@0.57.0:
|
|
176
|
-
// the object DOES contain a later `settings:` assignment (a
|
|
177
|
-
// CLAUDE_MODEL_CONFIG env-var fallback) — but it's gated behind
|
|
178
|
-
// `!userProvidedOptions?.settings && …`, i.e. it only fires when the caller
|
|
179
|
-
// did NOT already provide a settings object. A caller-provided `settings`
|
|
180
|
-
// (ours, carrying `enabledPlugins`) always wins. A bump that drops that
|
|
181
|
-
// guard — making the fallback unconditional — must fail here, since it
|
|
182
|
-
// would silently clobber DDR-168's double-registration override.
|
|
183
|
-
const spreadIdx = src.indexOf('...userProvidedOptions');
|
|
184
|
-
expect(spreadIdx).toBeGreaterThan(-1);
|
|
185
|
-
const queryIdx = src.indexOf('query(', spreadIdx);
|
|
186
|
-
expect(queryIdx).toBeGreaterThan(spreadIdx);
|
|
187
|
-
const window = src.slice(spreadIdx, queryIdx);
|
|
188
|
-
expect(window).toMatch(/!userProvidedOptions\?\.settings\s*&&/);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
test("SDK Options declares settings (Settings.enabledPlugins is the field DDR-168's guard relies on)", () => {
|
|
192
|
-
let sdkPkg: string | null = null;
|
|
193
|
-
try {
|
|
194
|
-
const realAdapterDir = dirname(realpathSync(adapterEntry));
|
|
195
|
-
sdkPkg = Bun.resolveSync('@anthropic-ai/claude-agent-sdk/package.json', realAdapterDir);
|
|
196
|
-
} catch {
|
|
197
|
-
sdkPkg = null;
|
|
198
|
-
}
|
|
199
|
-
expect(sdkPkg).not.toBeNull();
|
|
200
|
-
const dts = join(dirname(sdkPkg as string), 'sdk.d.ts');
|
|
201
|
-
expect(existsSync(dts)).toBe(true);
|
|
202
|
-
const src = readFileSync(dts, 'utf8');
|
|
203
|
-
// sdk.d.ts:1831 `settings?: Settings;` (or similarly named field on Options) +
|
|
204
|
-
// :5193 `Settings.enabledPlugins` — a bump that renames/drops either must
|
|
205
|
-
// fail here, then adapt, rather than silently reopening double-registration.
|
|
206
|
-
expect(src).toMatch(/settings\?\s*:/);
|
|
207
|
-
expect(src).toMatch(/enabledPlugins\??\s*:/);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// Pure unit tests for client/panels/ToolGroup.jsx's grouping/summary helpers
|
|
2
|
-
// (Task C1 — collapsed consecutive-tool-call groups).
|
|
3
|
-
|
|
4
|
-
import { describe, expect, test } from 'bun:test';
|
|
5
|
-
|
|
6
|
-
import { groupToolCalls, summarizeGroup } from '../client/panels/ToolGroup.jsx';
|
|
7
|
-
|
|
8
|
-
describe('groupToolCalls', () => {
|
|
9
|
-
test('a lone tool-call stays a single item, not a group', () => {
|
|
10
|
-
const parts = [{ type: 'tool-call', toolCallId: '1', toolName: 'Read file' }];
|
|
11
|
-
expect(groupToolCalls(parts)).toEqual([{ type: 'single', part: parts[0] }]);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test('2+ CONSECUTIVE tool-calls fold into one group', () => {
|
|
15
|
-
const parts = [
|
|
16
|
-
{ type: 'tool-call', toolCallId: '1', toolName: 'Read file' },
|
|
17
|
-
{ type: 'tool-call', toolCallId: '2', toolName: 'Run command' },
|
|
18
|
-
{ type: 'tool-call', toolCallId: '3', toolName: 'Write file' },
|
|
19
|
-
];
|
|
20
|
-
const grouped = groupToolCalls(parts);
|
|
21
|
-
expect(grouped).toEqual([{ type: 'tool-group', parts }]);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('text/reasoning parts break a run into separate groups', () => {
|
|
25
|
-
const parts = [
|
|
26
|
-
{ type: 'tool-call', toolCallId: '1', toolName: 'Read file' },
|
|
27
|
-
{ type: 'tool-call', toolCallId: '2', toolName: 'Write file' },
|
|
28
|
-
{ type: 'text', text: 'done reading and writing' },
|
|
29
|
-
{ type: 'tool-call', toolCallId: '3', toolName: 'Run command' },
|
|
30
|
-
];
|
|
31
|
-
const grouped = groupToolCalls(parts);
|
|
32
|
-
expect(grouped).toEqual([
|
|
33
|
-
{ type: 'tool-group', parts: [parts[0], parts[1]] },
|
|
34
|
-
{ type: 'single', part: parts[2] },
|
|
35
|
-
{ type: 'single', part: parts[3] }, // lone tool-call after the break — not a group
|
|
36
|
-
]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('a mix of text and reasoning parts each stay single, in order', () => {
|
|
40
|
-
const parts = [
|
|
41
|
-
{ type: 'text', text: 'thinking about it' },
|
|
42
|
-
{ type: 'reasoning', text: '...' },
|
|
43
|
-
{ type: 'text', text: 'here is my answer' },
|
|
44
|
-
];
|
|
45
|
-
expect(groupToolCalls(parts)).toEqual(parts.map((part) => ({ type: 'single', part })));
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('tolerates an empty/missing parts array', () => {
|
|
49
|
-
expect(groupToolCalls([])).toEqual([]);
|
|
50
|
-
expect(groupToolCalls(undefined)).toEqual([]);
|
|
51
|
-
expect(groupToolCalls(null)).toEqual([]);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe('summarizeGroup', () => {
|
|
56
|
-
test('all entries sharing one title collapse to "Ran N × <title>"', () => {
|
|
57
|
-
const parts = [{ toolName: 'Read file' }, { toolName: 'Read file' }, { toolName: 'Read file' }];
|
|
58
|
-
expect(summarizeGroup(parts)).toBe('Ran 3 × Read file');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('mixed titles list the distinct ones, capped at 3 with an ellipsis', () => {
|
|
62
|
-
const parts = [
|
|
63
|
-
{ toolName: 'Read file' },
|
|
64
|
-
{ toolName: 'Run command' },
|
|
65
|
-
{ toolName: 'Web search' },
|
|
66
|
-
{ toolName: 'Write file' },
|
|
67
|
-
{ toolName: 'Read file' }, // duplicate — must not inflate the unique count
|
|
68
|
-
];
|
|
69
|
-
const summary = summarizeGroup(parts);
|
|
70
|
-
expect(summary).toBe('Ran 5 tools — Read file, Run command, Web search…');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('a missing toolName falls back to the generic label, not undefined', () => {
|
|
74
|
-
expect(summarizeGroup([{}, {}])).toBe('Ran 2 × tool');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// Pure unit tests for client/panels/transcript-view.js (Task C4).
|
|
2
|
-
|
|
3
|
-
import { describe, expect, test } from 'bun:test';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
DEFAULT_TRANSCRIPT_VIEW,
|
|
7
|
-
filterTranscriptParts,
|
|
8
|
-
TRANSCRIPT_VIEWS,
|
|
9
|
-
transcriptForcesExpand,
|
|
10
|
-
} from '../client/panels/transcript-view.js';
|
|
11
|
-
|
|
12
|
-
const PARTS = [
|
|
13
|
-
{ type: 'reasoning', text: 'let me think' },
|
|
14
|
-
{ type: 'tool-call', toolCallId: '1', toolName: 'Read file' },
|
|
15
|
-
{ type: 'text', text: 'first answer' },
|
|
16
|
-
{ type: 'reasoning', text: 'more thinking' },
|
|
17
|
-
{ type: 'text', text: 'final answer' },
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
describe('filterTranscriptParts', () => {
|
|
21
|
-
test('normal hides reasoning, keeps text + tool-calls in order', () => {
|
|
22
|
-
const result = filterTranscriptParts(PARTS, 'normal');
|
|
23
|
-
expect(result.map((p) => p.type)).toEqual(['tool-call', 'text', 'text']);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('thinking keeps everything, including reasoning', () => {
|
|
27
|
-
expect(filterTranscriptParts(PARTS, 'thinking')).toEqual(PARTS);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('verbose also keeps everything (the extra verbosity is a render-detail toggle)', () => {
|
|
31
|
-
expect(filterTranscriptParts(PARTS, 'verbose')).toEqual(PARTS);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('summary keeps ONLY the last text part', () => {
|
|
35
|
-
const result = filterTranscriptParts(PARTS, 'summary');
|
|
36
|
-
expect(result).toEqual([{ type: 'text', text: 'final answer' }]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('summary with no text parts at all returns empty, not a crash', () => {
|
|
40
|
-
expect(filterTranscriptParts([{ type: 'tool-call', toolCallId: '1' }], 'summary')).toEqual([]);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('an unrecognized mode fails toward normal (less noise), not everything', () => {
|
|
44
|
-
expect(filterTranscriptParts(PARTS, 'nonsense')).toEqual(
|
|
45
|
-
filterTranscriptParts(PARTS, 'normal')
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('tolerates missing/empty input', () => {
|
|
50
|
-
expect(filterTranscriptParts(undefined, 'normal')).toEqual([]);
|
|
51
|
-
expect(filterTranscriptParts(null, 'thinking')).toEqual([]);
|
|
52
|
-
expect(filterTranscriptParts([], 'summary')).toEqual([]);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('transcriptForcesExpand', () => {
|
|
57
|
-
test('only verbose forces expansion', () => {
|
|
58
|
-
expect(transcriptForcesExpand('verbose')).toBe(true);
|
|
59
|
-
expect(transcriptForcesExpand('normal')).toBe(false);
|
|
60
|
-
expect(transcriptForcesExpand('thinking')).toBe(false);
|
|
61
|
-
expect(transcriptForcesExpand('summary')).toBe(false);
|
|
62
|
-
expect(transcriptForcesExpand(undefined)).toBe(false);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('constants', () => {
|
|
67
|
-
test('the view list + default are stable and consistent', () => {
|
|
68
|
-
expect(TRANSCRIPT_VIEWS).toEqual(['normal', 'thinking', 'verbose', 'summary']);
|
|
69
|
-
expect(TRANSCRIPT_VIEWS).toContain(DEFAULT_TRANSCRIPT_VIEW);
|
|
70
|
-
});
|
|
71
|
-
});
|