@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,108 +0,0 @@
|
|
|
1
|
-
// Shared test scaffolding. Bun-test only.
|
|
2
|
-
|
|
3
|
-
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import { type Subprocess, spawn } from 'bun';
|
|
7
|
-
|
|
8
|
-
export interface Sandbox {
|
|
9
|
-
root: string;
|
|
10
|
-
designRoot: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function makeSandbox(): Sandbox {
|
|
14
|
-
const root = mkdtempSync(join(tmpdir(), 'mdcc-test-'));
|
|
15
|
-
const designRoot = join(root, '.design');
|
|
16
|
-
mkdirSync(designRoot, { recursive: true });
|
|
17
|
-
writeFileSync(
|
|
18
|
-
join(designRoot, 'config.json'),
|
|
19
|
-
JSON.stringify(
|
|
20
|
-
{
|
|
21
|
-
name: 'test',
|
|
22
|
-
designRoot: '.design',
|
|
23
|
-
canvasGroups: [
|
|
24
|
-
{ label: 'System', path: 'system' },
|
|
25
|
-
{ label: 'UI', path: 'ui' },
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
null,
|
|
29
|
-
2
|
|
30
|
-
)
|
|
31
|
-
);
|
|
32
|
-
mkdirSync(join(designRoot, 'ui'), { recursive: true });
|
|
33
|
-
writeFileSync(
|
|
34
|
-
join(designRoot, 'ui', 'fixture.html'),
|
|
35
|
-
'<!doctype html><html><head><title>fix</title></head><body><h1>fixture</h1></body></html>'
|
|
36
|
-
);
|
|
37
|
-
return { root, designRoot };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Base is spread by pid, not a fixed literal — bun test runs different test
|
|
41
|
-
// files as separate processes, each importing a fresh copy of this module, so
|
|
42
|
-
// a fixed base (e.g. 4500 for everyone) reliably collides across files. The
|
|
43
|
-
// pid spread doesn't guarantee uniqueness on its own — bootServer's pid check
|
|
44
|
-
// below is the actual safety net — but it makes collisions rare in practice.
|
|
45
|
-
let portCounter = 4500 + (process.pid % 4000);
|
|
46
|
-
export function nextPort(): number {
|
|
47
|
-
// Bump on every call so parallel tests don't collide. Bun.serve will throw
|
|
48
|
-
// EADDRINUSE if the host happened to bind one — caller retries with nextPort().
|
|
49
|
-
portCounter += 1;
|
|
50
|
-
return portCounter;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function bootServer(
|
|
54
|
-
root: string,
|
|
55
|
-
port: number,
|
|
56
|
-
extraEnv?: Record<string, string>
|
|
57
|
-
): Promise<Subprocess> {
|
|
58
|
-
const serverPath = join(import.meta.dir, '..', 'server.ts');
|
|
59
|
-
const proc = spawn({
|
|
60
|
-
cmd: ['bun', 'run', serverPath, '--port', String(port), '--root', root],
|
|
61
|
-
cwd: join(import.meta.dir, '..'),
|
|
62
|
-
env: { ...process.env, NO_OPEN: '1', NODE_ENV: 'test', ...extraEnv },
|
|
63
|
-
stdout: 'pipe',
|
|
64
|
-
stderr: 'pipe',
|
|
65
|
-
});
|
|
66
|
-
// Wait up to 10 s for the server to bind — the first spawn cold-compiles the
|
|
67
|
-
// whole studio TS, which under parallel test load regularly blows a 3 s
|
|
68
|
-
// budget (the flaky "server did not start" class of failure).
|
|
69
|
-
//
|
|
70
|
-
// THIS BUDGET IS ONLY REACHABLE BECAUSE THE SUITE RAISES THE PER-TEST TIMEOUT.
|
|
71
|
-
// bun's default is 5 s, so the TEST was killed while this loop still had half
|
|
72
|
-
// its patience left, and the failure never named a boot at all — it named
|
|
73
|
-
// whichever test happened to be booting when the machine was busiest, at
|
|
74
|
-
// exactly 5000ms, a different one every run. `test:dev-server` therefore
|
|
75
|
-
// passes `--timeout 20000` (bunfig's `[test] timeout` is NOT honored on bun
|
|
76
|
-
// 1.3.3 — measured, not assumed). Change one, change the other.
|
|
77
|
-
const start = Date.now();
|
|
78
|
-
while (Date.now() - start < 10000) {
|
|
79
|
-
try {
|
|
80
|
-
const r = await fetch(`http://localhost:${port}/_health`, {
|
|
81
|
-
signal: AbortSignal.timeout(200),
|
|
82
|
-
});
|
|
83
|
-
if (r.ok) {
|
|
84
|
-
const json = (await r.json()) as { pid?: number };
|
|
85
|
-
// A same-port collision with a concurrently-running test file's server
|
|
86
|
-
// (see the portCounter comment above) would otherwise look "ready" —
|
|
87
|
-
// /_health answers fine, just from someone else's sandbox — and every
|
|
88
|
-
// later request 404s against a designRoot that doesn't have our
|
|
89
|
-
// fixtures. Only trust the health check if it's actually our process.
|
|
90
|
-
if (json.pid === proc.pid) return proc;
|
|
91
|
-
}
|
|
92
|
-
} catch {
|
|
93
|
-
/* not up yet */
|
|
94
|
-
}
|
|
95
|
-
await Bun.sleep(50);
|
|
96
|
-
}
|
|
97
|
-
proc.kill();
|
|
98
|
-
throw new Error(`server did not start on port ${port} within 10 s`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function killProc(proc: Subprocess) {
|
|
102
|
-
proc.kill();
|
|
103
|
-
try {
|
|
104
|
-
await proc.exited;
|
|
105
|
-
} catch {
|
|
106
|
-
/* ignore */
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
// feature-acp-turn-notifications Task 2/3 — the activity snapshot the native
|
|
2
|
-
// shell's poller reads (notify.rs Task 5) to decide whether to fire an OS
|
|
3
|
-
// notification for a project that isn't the visible one. Covers:
|
|
4
|
-
// • activitySnapshot() shape + monotonic seq (bumps only on real change).
|
|
5
|
-
// • AcpBridge.awaitingInputCount reflects pending permission requests.
|
|
6
|
-
// • The Acp manager's registered probe reports 'awaiting-input', not
|
|
7
|
-
// 'running', for a chat blocked on a permission prompt — the ordering
|
|
8
|
-
// Task 2's gotcha calls out explicitly.
|
|
9
|
-
// • /_api/acp/activity is absent from both canvas-origin allowlists
|
|
10
|
-
// (Decision: NEITHER, like /_api/acp/running today).
|
|
11
|
-
|
|
12
|
-
import { afterEach, describe, expect, test } from 'bun:test';
|
|
13
|
-
import { readFileSync } from 'node:fs';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
-
|
|
16
|
-
import type { ServerWebSocket } from 'bun';
|
|
17
|
-
|
|
18
|
-
import { AcpBridge } from '../acp/bridge.ts';
|
|
19
|
-
import { createAcp } from '../acp/index.ts';
|
|
20
|
-
import { activitySnapshot, registerActivityProbe } from '../acp/running.ts';
|
|
21
|
-
import type { Context } from '../context.ts';
|
|
22
|
-
import type { WsData } from '../ws.ts';
|
|
23
|
-
|
|
24
|
-
const FIXTURE = join(import.meta.dir, 'fixtures', 'mock-acp-agent-permission.mjs');
|
|
25
|
-
const TEST_ENV_KEYS = ['MAUDE_ACP_ADAPTER_ENTRY', 'MAUDE_ACP_RUNTIME', 'MAUDE_CLAUDE_BIN'];
|
|
26
|
-
|
|
27
|
-
function useMockAgent() {
|
|
28
|
-
process.env.MAUDE_ACP_ADAPTER_ENTRY = FIXTURE;
|
|
29
|
-
process.env.MAUDE_ACP_RUNTIME = process.execPath;
|
|
30
|
-
process.env.MAUDE_CLAUDE_BIN = process.execPath;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
afterEach(() => {
|
|
34
|
-
for (const key of TEST_ENV_KEYS) delete process.env[key];
|
|
35
|
-
// Restore a no-op probe so a later file's `registerRunningChatsProbe`-style
|
|
36
|
-
// module-level state doesn't leak a stale closure across test files.
|
|
37
|
-
registerActivityProbe(() => []);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
async function until<T>(fn: () => T | undefined, timeoutMs = 12000): Promise<T> {
|
|
41
|
-
const start = performance.now();
|
|
42
|
-
for (;;) {
|
|
43
|
-
const v = fn();
|
|
44
|
-
if (v !== undefined) return v;
|
|
45
|
-
if (performance.now() - start > timeoutMs) throw new Error('timeout waiting for condition');
|
|
46
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function fakeWs(id: string) {
|
|
51
|
-
const frames: Array<Record<string, unknown>> = [];
|
|
52
|
-
const ws = {
|
|
53
|
-
data: { id } as WsData,
|
|
54
|
-
send: (raw: string) => {
|
|
55
|
-
frames.push(JSON.parse(raw));
|
|
56
|
-
},
|
|
57
|
-
} as unknown as ServerWebSocket<WsData>;
|
|
58
|
-
return { ws, frames };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
describe('activitySnapshot (running.ts)', () => {
|
|
62
|
-
test('reflects the registered probe and never throws on a bad one', () => {
|
|
63
|
-
registerActivityProbe(() => [{ chatId: 'a', state: 'running' }]);
|
|
64
|
-
expect(activitySnapshot().chats).toEqual([{ chatId: 'a', state: 'running' }]);
|
|
65
|
-
|
|
66
|
-
registerActivityProbe(() => {
|
|
67
|
-
throw new Error('boom');
|
|
68
|
-
});
|
|
69
|
-
expect(activitySnapshot().chats).toEqual([]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('seq bumps only when the (chatId, state) set actually changes', () => {
|
|
73
|
-
registerActivityProbe(() => [{ chatId: 'a', state: 'idle' }]);
|
|
74
|
-
const first = activitySnapshot().seq;
|
|
75
|
-
const second = activitySnapshot().seq; // same state — no bump
|
|
76
|
-
expect(second).toBe(first);
|
|
77
|
-
|
|
78
|
-
registerActivityProbe(() => [{ chatId: 'a', state: 'running' }]);
|
|
79
|
-
const third = activitySnapshot().seq; // real transition — bumps
|
|
80
|
-
expect(third).toBe(first + 1);
|
|
81
|
-
|
|
82
|
-
// Enumeration-order shuffle with the SAME states must NOT bump.
|
|
83
|
-
registerActivityProbe(() => [
|
|
84
|
-
{ chatId: 'b', state: 'idle' },
|
|
85
|
-
{ chatId: 'a', state: 'running' },
|
|
86
|
-
]);
|
|
87
|
-
activitySnapshot();
|
|
88
|
-
registerActivityProbe(() => [
|
|
89
|
-
{ chatId: 'a', state: 'running' },
|
|
90
|
-
{ chatId: 'b', state: 'idle' },
|
|
91
|
-
]);
|
|
92
|
-
const fourth = activitySnapshot().seq;
|
|
93
|
-
const fifth = activitySnapshot().seq;
|
|
94
|
-
expect(fifth).toBe(fourth);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe('AcpBridge.awaitingInputCount + the manager probe (Task 2 gotcha: awaiting-input wins over running)', () => {
|
|
99
|
-
test('a pending permission request reports awaiting-input, not running', async () => {
|
|
100
|
-
useMockAgent();
|
|
101
|
-
const ctx = {
|
|
102
|
-
paths: { repoRoot: process.cwd(), designRoot: '/tmp/does-not-matter-activity' },
|
|
103
|
-
} as unknown as Context;
|
|
104
|
-
const acp = createAcp(ctx);
|
|
105
|
-
|
|
106
|
-
const a = fakeWs('activity-ws-a');
|
|
107
|
-
try {
|
|
108
|
-
acp.onOpen(a.ws);
|
|
109
|
-
acp.onMessage(a.ws, JSON.stringify({ t: 'prompt', text: 'hi', chat: 'activity-chat' }));
|
|
110
|
-
const reqFrame = await until(() => a.frames.find((f) => f.t === 'permission-request'));
|
|
111
|
-
|
|
112
|
-
const snap = activitySnapshot();
|
|
113
|
-
expect(snap.chats).toContainEqual({ chatId: 'activity-chat', state: 'awaiting-input' });
|
|
114
|
-
|
|
115
|
-
acp.onMessage(
|
|
116
|
-
a.ws,
|
|
117
|
-
JSON.stringify({ t: 'permission-response', id: reqFrame.id, decision: 'allow-once' })
|
|
118
|
-
);
|
|
119
|
-
await until(() => a.frames.find((f) => f.t === 'turn-end'));
|
|
120
|
-
|
|
121
|
-
// Turn settled — no longer awaiting-input (running or idle, never stuck).
|
|
122
|
-
const after = activitySnapshot().chats.find((c) => c.chatId === 'activity-chat');
|
|
123
|
-
expect(after?.state).not.toBe('awaiting-input');
|
|
124
|
-
} finally {
|
|
125
|
-
acp.onClose(a.ws);
|
|
126
|
-
acp.stopAll();
|
|
127
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
128
|
-
}
|
|
129
|
-
}, 20000);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('AcpBridge.awaitingInputCount — direct unit', () => {
|
|
133
|
-
test('starts at 0 and counts a pending permission before resolution', async () => {
|
|
134
|
-
useMockAgent();
|
|
135
|
-
const bridge = new AcpBridge({ repoRoot: process.cwd(), onUpdate: () => {} });
|
|
136
|
-
expect(bridge.awaitingInputCount).toBe(0);
|
|
137
|
-
try {
|
|
138
|
-
const promptPromise = bridge.prompt('hi', 'c1');
|
|
139
|
-
await until(() => (bridge.awaitingInputCount > 0 ? true : undefined));
|
|
140
|
-
expect(bridge.awaitingInputCount).toBe(1);
|
|
141
|
-
await bridge.cancel(); // denies the pending request rather than hanging
|
|
142
|
-
await promptPromise;
|
|
143
|
-
expect(bridge.awaitingInputCount).toBe(0);
|
|
144
|
-
} finally {
|
|
145
|
-
await bridge.stop();
|
|
146
|
-
}
|
|
147
|
-
}, 15000);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
describe('/_api/acp/activity — NEITHER canvas-origin allowlist (Decision D + dual-allowlist rule)', () => {
|
|
151
|
-
const httpSrc = readFileSync(join(import.meta.dir, '..', 'http.ts'), 'utf8');
|
|
152
|
-
const serverSrc = readFileSync(join(import.meta.dir, '..', 'server.ts'), 'utf8');
|
|
153
|
-
|
|
154
|
-
test('the route exists on the main-origin route table', () => {
|
|
155
|
-
expect(httpSrc).toContain("'/_api/acp/activity'");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test('is absent from CANVAS_SAFE_API', () => {
|
|
159
|
-
const start = httpSrc.indexOf('CANVAS_SAFE_API = new Set([');
|
|
160
|
-
const end = httpSrc.indexOf(']);', start);
|
|
161
|
-
expect(start).toBeGreaterThan(-1);
|
|
162
|
-
const block = httpSrc.slice(start, end);
|
|
163
|
-
expect(block).not.toContain('/_api/acp/activity');
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test("is absent from startCanvasServer's routes map", () => {
|
|
167
|
-
const start = serverSrc.indexOf('function startCanvasServer');
|
|
168
|
-
const routesEnd = serverSrc.indexOf('async fetch(req, srv)', start);
|
|
169
|
-
expect(start).toBeGreaterThan(-1);
|
|
170
|
-
const block = serverSrc.slice(start, routesEnd);
|
|
171
|
-
expect(block).not.toContain('/_api/acp/activity');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test('the payload never carries a chat title, message text, or transcript field name', () => {
|
|
175
|
-
// Grep the route handler body itself (not the whole file) for the fields
|
|
176
|
-
// Decision D forbids — a title/text field appearing HERE would mean
|
|
177
|
-
// someone widened the payload without reading the comment.
|
|
178
|
-
const start = httpSrc.indexOf("'/_api/acp/activity':");
|
|
179
|
-
const end = httpSrc.indexOf('},', start);
|
|
180
|
-
const block = httpSrc.slice(start, end);
|
|
181
|
-
expect(block).not.toMatch(/title|message|transcript|content/i);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// RCA issue-acp-subagent-activity-invisible — the ACP chat "still working"
|
|
2
|
-
// indicator must survive the premature turn-end that claude-agent-acp emits
|
|
3
|
-
// while background subagents are still running (adapter settles the prompt at
|
|
4
|
-
// the main agent's `result`, #773). These lock the pure activity reducer +
|
|
5
|
-
// label so a background subagent stays visible instead of the panel looking idle.
|
|
6
|
-
|
|
7
|
-
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
activityLabel,
|
|
11
|
-
applyUpdate,
|
|
12
|
-
isSubagentTool,
|
|
13
|
-
reduceActivity,
|
|
14
|
-
} from '../client/panels/acp-runtime.js';
|
|
15
|
-
|
|
16
|
-
const call = (id: string, toolName?: string, over: Record<string, unknown> = {}) => ({
|
|
17
|
-
t: 'update' as const,
|
|
18
|
-
update: {
|
|
19
|
-
sessionUpdate: 'tool_call',
|
|
20
|
-
toolCallId: id,
|
|
21
|
-
title: over.title,
|
|
22
|
-
kind: over.kind,
|
|
23
|
-
...(toolName ? { _meta: { claudeCode: { toolName } } } : {}),
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
const done = (id: string, status = 'completed') => ({
|
|
27
|
-
t: 'update' as const,
|
|
28
|
-
update: { sessionUpdate: 'tool_call_update', toolCallId: id, status },
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('reduceActivity', () => {
|
|
32
|
-
test('a Task tool_call survives turn-end — the background subagent stays tracked', () => {
|
|
33
|
-
const m = new Map();
|
|
34
|
-
expect(
|
|
35
|
-
reduceActivity(m, call('t1', 'Task', { title: 'map the acp module', kind: 'think' }))
|
|
36
|
-
).toBe(true);
|
|
37
|
-
expect(m.size).toBe(1);
|
|
38
|
-
|
|
39
|
-
// The regression this fix exists for: turn-end must NOT wipe the map.
|
|
40
|
-
expect(reduceActivity(m, { t: 'turn-end', stopReason: 'end_turn' })).toBe(false);
|
|
41
|
-
expect(m.size).toBe(1);
|
|
42
|
-
|
|
43
|
-
// …it drains on the subagent's OWN completed update, not on turn-end.
|
|
44
|
-
expect(reduceActivity(m, done('t1'))).toBe(true);
|
|
45
|
-
expect(m.size).toBe(0);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('a hard error still wipes the map (teardown)', () => {
|
|
49
|
-
const m = new Map();
|
|
50
|
-
reduceActivity(m, call('t1', 'Read', { kind: 'read' }));
|
|
51
|
-
expect(reduceActivity(m, { t: 'error', message: 'boom' })).toBe(true);
|
|
52
|
-
expect(m.size).toBe(0);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('captures the concrete tool name for subagent classification', () => {
|
|
56
|
-
const m = new Map();
|
|
57
|
-
reduceActivity(m, call('t1', 'Task', { title: 'x', kind: 'think' }));
|
|
58
|
-
reduceActivity(m, call('t2', 'Read', { title: 'foo.ts', kind: 'read' }));
|
|
59
|
-
const tools = [...m.values()];
|
|
60
|
-
expect(isSubagentTool(tools[0])).toBe(true);
|
|
61
|
-
expect(isSubagentTool(tools[1])).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('failed updates remove the tool; unknown ids are a no-op', () => {
|
|
65
|
-
const m = new Map();
|
|
66
|
-
reduceActivity(m, call('t1', 'Bash', { kind: 'execute' }));
|
|
67
|
-
expect(reduceActivity(m, done('nope'))).toBe(false);
|
|
68
|
-
expect(reduceActivity(m, done('t1', 'failed'))).toBe(true);
|
|
69
|
-
expect(m.size).toBe(0);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('activityLabel', () => {
|
|
74
|
-
test('subagents get explicit, counted wording', () => {
|
|
75
|
-
expect(activityLabel([{ toolName: 'Task', title: 'a' }])).toBe('1 subagent running');
|
|
76
|
-
expect(activityLabel([{ toolName: 'Task' }, { toolName: 'Agent' }])).toBe(
|
|
77
|
-
'2 subagents running'
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('non-subagent tools fall back to title / count / Working…', () => {
|
|
82
|
-
expect(activityLabel([{ title: 'Edit foo.ts' }])).toBe('Edit foo.ts');
|
|
83
|
-
expect(activityLabel([{ title: 'a' }, { title: 'b' }])).toBe('2 tasks running');
|
|
84
|
-
expect(activityLabel([])).toBe('Working…');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// The F2 fix: the SAME reducer folds live-turn frames AND the post-turn-end
|
|
89
|
-
// "background continuation" frames the client used to drop. If this drifts, the
|
|
90
|
-
// dropped subagent results / consolidation render wrong (or not at all).
|
|
91
|
-
describe('applyUpdate (shared part reducer)', () => {
|
|
92
|
-
const chunk = (text: string) => ({
|
|
93
|
-
sessionUpdate: 'agent_message_chunk',
|
|
94
|
-
content: { type: 'text', text },
|
|
95
|
-
});
|
|
96
|
-
const call = (id: string, title: string, kind: string, rawInput: unknown = {}) => ({
|
|
97
|
-
sessionUpdate: 'tool_call',
|
|
98
|
-
toolCallId: id,
|
|
99
|
-
title,
|
|
100
|
-
kind,
|
|
101
|
-
rawInput,
|
|
102
|
-
});
|
|
103
|
-
const upd = (id: string, status: string, rawOutput: unknown) => ({
|
|
104
|
-
sessionUpdate: 'tool_call_update',
|
|
105
|
-
toolCallId: id,
|
|
106
|
-
status,
|
|
107
|
-
rawOutput,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('coalesces consecutive text chunks into one part', () => {
|
|
111
|
-
const parts: unknown[] = [];
|
|
112
|
-
const ti = new Map();
|
|
113
|
-
applyUpdate(parts, ti, chunk('Panel: '));
|
|
114
|
-
applyUpdate(parts, ti, chunk('9 blockers'));
|
|
115
|
-
expect(parts).toEqual([{ type: 'text', text: 'Panel: 9 blockers' }]);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('tool_call adds a pending part; tool_call_update fills the result', () => {
|
|
119
|
-
const parts: Array<Record<string, unknown>> = [];
|
|
120
|
-
const ti = new Map();
|
|
121
|
-
applyUpdate(parts, ti, call('t1', 'Write critique/001.md', 'edit', { path: 'x' }));
|
|
122
|
-
expect(parts[0]).toMatchObject({ type: 'tool-call', toolName: 'Write critique/001.md' });
|
|
123
|
-
expect(parts[0].result).toBeUndefined();
|
|
124
|
-
applyUpdate(parts, ti, upd('t1', 'completed', { ok: true }));
|
|
125
|
-
expect(parts[0]).toMatchObject({ result: { ok: true }, isError: false });
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('failed update marks isError', () => {
|
|
129
|
-
const parts: Array<Record<string, unknown>> = [];
|
|
130
|
-
const ti = new Map();
|
|
131
|
-
applyUpdate(parts, ti, call('t1', 'Bash', 'execute'));
|
|
132
|
-
applyUpdate(parts, ti, upd('t1', 'failed', null));
|
|
133
|
-
expect(parts[0].isError).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test('thought → reasoning part; usage/plan ignored', () => {
|
|
137
|
-
const parts: unknown[] = [];
|
|
138
|
-
const ti = new Map();
|
|
139
|
-
applyUpdate(parts, ti, {
|
|
140
|
-
sessionUpdate: 'agent_thought_chunk',
|
|
141
|
-
content: { type: 'text', text: 'hmm' },
|
|
142
|
-
});
|
|
143
|
-
applyUpdate(parts, ti, { sessionUpdate: 'usage_update' });
|
|
144
|
-
applyUpdate(parts, ti, { sessionUpdate: 'plan' });
|
|
145
|
-
expect(parts).toEqual([{ type: 'reasoning', text: 'hmm' }]);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('update for an unknown tool id is a no-op', () => {
|
|
149
|
-
const parts: unknown[] = [];
|
|
150
|
-
const ti = new Map();
|
|
151
|
-
applyUpdate(parts, ti, upd('nope', 'completed', {}));
|
|
152
|
-
expect(parts).toEqual([]);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// RC5 (rca/issue-canvas-hmr-optimistic-update-consistency) — the ACP chat agent
|
|
2
|
-
// must raise the same "Claude is editing" ai-activity banner as /design:edit.
|
|
3
|
-
// The tracker watches streamed tool_call / tool_call_update notifications for
|
|
4
|
-
// edit-kind tools touching canvas files and drives start/heartbeat/end.
|
|
5
|
-
|
|
6
|
-
import { describe, expect, test } from 'bun:test';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
|
|
9
|
-
import type { SessionUpdate } from '@agentclientprotocol/sdk';
|
|
10
|
-
|
|
11
|
-
import { createAgentActivityTracker } from '../acp/index.ts';
|
|
12
|
-
import type { AiActivity, AiActivityEntry } from '../collab/ai-activity.ts';
|
|
13
|
-
import { type Context, createBus } from '../context.ts';
|
|
14
|
-
|
|
15
|
-
const ROOT = join('/tmp', 'acp-ai-root');
|
|
16
|
-
const DESIGN = join(ROOT, '.design');
|
|
17
|
-
|
|
18
|
-
function mkCtx(): Context {
|
|
19
|
-
return {
|
|
20
|
-
cfg: {} as Context['cfg'],
|
|
21
|
-
projectLabel: 'test',
|
|
22
|
-
bus: createBus(),
|
|
23
|
-
paths: {
|
|
24
|
-
repoRoot: ROOT,
|
|
25
|
-
designRel: '.design',
|
|
26
|
-
designRoot: DESIGN,
|
|
27
|
-
serverInfoFile: join(DESIGN, '_server.json'),
|
|
28
|
-
activeFile: join(DESIGN, '_active.json'),
|
|
29
|
-
commentsDir: join(DESIGN, '_comments'),
|
|
30
|
-
canvasStateDir: join(DESIGN, '_canvas-state'),
|
|
31
|
-
historyDir: join(DESIGN, '_history'),
|
|
32
|
-
tokensUrlRel: '',
|
|
33
|
-
systemDirRel: 'system',
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function mkAi(): { ai: AiActivity; calls: string[] } {
|
|
39
|
-
const calls: string[] = [];
|
|
40
|
-
const entry = (file: string): AiActivityEntry => ({
|
|
41
|
-
file,
|
|
42
|
-
author: 'x',
|
|
43
|
-
startedAt: 0,
|
|
44
|
-
lastHeartbeat: 0,
|
|
45
|
-
});
|
|
46
|
-
const ai: AiActivity = {
|
|
47
|
-
start(file, author) {
|
|
48
|
-
calls.push(`start:${file}:${author}`);
|
|
49
|
-
return entry(file);
|
|
50
|
-
},
|
|
51
|
-
heartbeat(file) {
|
|
52
|
-
calls.push(`beat:${file}`);
|
|
53
|
-
return entry(file);
|
|
54
|
-
},
|
|
55
|
-
end(file) {
|
|
56
|
-
calls.push(`end:${file}`);
|
|
57
|
-
return true;
|
|
58
|
-
},
|
|
59
|
-
list: () => [],
|
|
60
|
-
get: () => null,
|
|
61
|
-
stop: () => {},
|
|
62
|
-
};
|
|
63
|
-
return { ai, calls };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const upd = (u: Record<string, unknown>): SessionUpdate => u as unknown as SessionUpdate;
|
|
67
|
-
|
|
68
|
-
describe('acp / agent activity tracker', () => {
|
|
69
|
-
test('edit tool_call on a canvas starts ai-activity with the designRel key', () => {
|
|
70
|
-
const { ai, calls } = mkAi();
|
|
71
|
-
const t = createAgentActivityTracker(mkCtx(), ai);
|
|
72
|
-
t.onUpdate(
|
|
73
|
-
upd({
|
|
74
|
-
sessionUpdate: 'tool_call',
|
|
75
|
-
toolCallId: 't1',
|
|
76
|
-
kind: 'edit',
|
|
77
|
-
locations: [{ path: join(DESIGN, 'ui', 'Foo.tsx') }],
|
|
78
|
-
})
|
|
79
|
-
);
|
|
80
|
-
expect(calls).toHaveLength(1);
|
|
81
|
-
expect(calls[0]).toStartWith('start:.design/ui/Foo.tsx:');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('follow-up update for the same file inside the beat throttle adds nothing', () => {
|
|
85
|
-
const { ai, calls } = mkAi();
|
|
86
|
-
const t = createAgentActivityTracker(mkCtx(), ai);
|
|
87
|
-
const loc = { locations: [{ path: join(DESIGN, 'ui', 'Foo.tsx') }] };
|
|
88
|
-
t.onUpdate(upd({ sessionUpdate: 'tool_call', toolCallId: 't1', kind: 'edit', ...loc }));
|
|
89
|
-
// kind omitted on the update — must be recalled from the tool_call by id.
|
|
90
|
-
t.onUpdate(upd({ sessionUpdate: 'tool_call_update', toolCallId: 't1', ...loc }));
|
|
91
|
-
expect(calls).toHaveLength(1);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('read/search tools and non-canvas paths never banner', () => {
|
|
95
|
-
const { ai, calls } = mkAi();
|
|
96
|
-
const t = createAgentActivityTracker(mkCtx(), ai);
|
|
97
|
-
t.onUpdate(
|
|
98
|
-
upd({
|
|
99
|
-
sessionUpdate: 'tool_call',
|
|
100
|
-
toolCallId: 'r1',
|
|
101
|
-
kind: 'read',
|
|
102
|
-
locations: [{ path: join(DESIGN, 'ui', 'Foo.tsx') }],
|
|
103
|
-
})
|
|
104
|
-
);
|
|
105
|
-
t.onUpdate(
|
|
106
|
-
upd({
|
|
107
|
-
sessionUpdate: 'tool_call',
|
|
108
|
-
toolCallId: 'e2',
|
|
109
|
-
kind: 'edit',
|
|
110
|
-
locations: [{ path: join(ROOT, 'src', 'App.tsx') }], // outside designRoot
|
|
111
|
-
})
|
|
112
|
-
);
|
|
113
|
-
t.onUpdate(
|
|
114
|
-
upd({
|
|
115
|
-
sessionUpdate: 'tool_call',
|
|
116
|
-
toolCallId: 'e3',
|
|
117
|
-
kind: 'edit',
|
|
118
|
-
locations: [{ path: join(DESIGN, '_history', 'x', 'Foo.tsx') }], // runtime state
|
|
119
|
-
})
|
|
120
|
-
);
|
|
121
|
-
t.onUpdate(
|
|
122
|
-
upd({
|
|
123
|
-
sessionUpdate: 'tool_call',
|
|
124
|
-
toolCallId: 'e4',
|
|
125
|
-
kind: 'edit',
|
|
126
|
-
locations: [{ path: join(DESIGN, 'ui', 'Foo.meta.json') }], // not a canvas
|
|
127
|
-
})
|
|
128
|
-
);
|
|
129
|
-
expect(calls).toEqual([]);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test('rawInput.file_path works when locations are absent', () => {
|
|
133
|
-
const { ai, calls } = mkAi();
|
|
134
|
-
const t = createAgentActivityTracker(mkCtx(), ai);
|
|
135
|
-
t.onUpdate(
|
|
136
|
-
upd({
|
|
137
|
-
sessionUpdate: 'tool_call',
|
|
138
|
-
toolCallId: 'w1',
|
|
139
|
-
kind: 'edit',
|
|
140
|
-
rawInput: { file_path: join(DESIGN, 'ui', 'Bar.tsx') },
|
|
141
|
-
})
|
|
142
|
-
);
|
|
143
|
-
expect(calls).toHaveLength(1);
|
|
144
|
-
expect(calls[0]).toStartWith('start:.design/ui/Bar.tsx:');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test('endTurn ends every banner this turn raised', () => {
|
|
148
|
-
const { ai, calls } = mkAi();
|
|
149
|
-
const t = createAgentActivityTracker(mkCtx(), ai);
|
|
150
|
-
t.onUpdate(
|
|
151
|
-
upd({
|
|
152
|
-
sessionUpdate: 'tool_call',
|
|
153
|
-
toolCallId: 't1',
|
|
154
|
-
kind: 'edit',
|
|
155
|
-
locations: [{ path: join(DESIGN, 'ui', 'Foo.tsx') }],
|
|
156
|
-
})
|
|
157
|
-
);
|
|
158
|
-
t.onUpdate(
|
|
159
|
-
upd({
|
|
160
|
-
sessionUpdate: 'tool_call',
|
|
161
|
-
toolCallId: 't2',
|
|
162
|
-
kind: 'edit',
|
|
163
|
-
locations: [{ path: join(DESIGN, 'ui', 'Bar.tsx') }],
|
|
164
|
-
})
|
|
165
|
-
);
|
|
166
|
-
t.endTurn();
|
|
167
|
-
expect(calls.filter((c) => c.startsWith('end:'))).toEqual([
|
|
168
|
-
'end:.design/ui/Foo.tsx',
|
|
169
|
-
'end:.design/ui/Bar.tsx',
|
|
170
|
-
]);
|
|
171
|
-
// A later turn on the same file must start (not silently beat) again.
|
|
172
|
-
t.onUpdate(
|
|
173
|
-
upd({
|
|
174
|
-
sessionUpdate: 'tool_call',
|
|
175
|
-
toolCallId: 't3',
|
|
176
|
-
kind: 'edit',
|
|
177
|
-
locations: [{ path: join(DESIGN, 'ui', 'Foo.tsx') }],
|
|
178
|
-
})
|
|
179
|
-
);
|
|
180
|
-
expect(calls.filter((c) => c.startsWith('start:'))).toHaveLength(3);
|
|
181
|
-
});
|
|
182
|
-
});
|