@1agh/maude 1.0.11 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/studio/acp/bridge.ts +18 -13
- package/apps/studio/acp/transcript-io.ts +394 -0
- package/apps/studio/acp/transcript.ts +103 -38
- package/apps/studio/api.ts +139 -26
- package/apps/studio/bin/_import-figma.mjs +57 -11
- package/apps/studio/bin/_seed-fixture.mjs +163 -0
- package/apps/studio/canvas-imports.ts +89 -0
- package/apps/studio/client/app.jsx +257 -7
- package/apps/studio/client/export-center.jsx +15 -7
- package/apps/studio/client/panels/SyncPanel.jsx +125 -4
- package/apps/studio/client/report-bug.jsx +19 -1
- package/apps/studio/client/styles/3-shell-maude.css +34 -0
- package/apps/studio/client/styles/4-components.css +26 -0
- package/apps/studio/collab/persistence.ts +132 -16
- package/apps/studio/collab/registry.ts +10 -18
- package/apps/studio/debug-bundle.ts +13 -0
- package/apps/studio/dist/client.bundle.js +1128 -1128
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/export-dialog.tsx +54 -0
- package/apps/studio/exporters/degraded.ts +19 -3
- package/apps/studio/exporters/ghostscript.ts +194 -0
- package/apps/studio/exporters/pdf-fonts.ts +261 -0
- package/apps/studio/exporters/pdf.ts +152 -3
- package/apps/studio/exporters/remote.ts +36 -1
- package/apps/studio/fs-watch.ts +45 -1
- package/apps/studio/http.ts +7 -1
- package/apps/studio/mem.ts +45 -9
- package/apps/studio/server.ts +11 -4
- package/apps/studio/sync/agent.ts +136 -29
- package/apps/studio/sync/asset-push.ts +1 -47
- package/apps/studio/sync/codec.ts +122 -31
- package/apps/studio/sync/cold-start-apply.ts +7 -0
- package/apps/studio/sync/cold-start.ts +118 -22
- package/apps/studio/sync/comment-identity.ts +68 -0
- package/apps/studio/sync/connection-state.ts +15 -1
- package/apps/studio/sync/file-ledger.ts +117 -0
- package/apps/studio/sync/file-plane.ts +623 -27
- package/apps/studio/sync/index.ts +711 -20
- package/apps/studio/sync/journal-client.ts +13 -1
- package/apps/studio/sync/migrate-seed.ts +40 -3
- package/apps/studio/sync/presentation.ts +26 -3
- package/apps/studio/sync/retry-after.ts +169 -0
- package/apps/studio/sync/seed-progress.ts +218 -0
- package/apps/studio/sync/status.ts +122 -5
- package/apps/studio/sync/transport-error.ts +111 -0
- package/apps/studio/whats-new.json +72 -0
- package/cli/bin/maude.mjs +2 -0
- package/cli/commands/codex.mjs +191 -0
- package/cli/commands/harness.mjs +1051 -0
- package/cli/commands/help.mjs +13 -0
- package/cli/lib/design-link.mjs +190 -2
- package/cli/lib/harness/capabilities.mjs +302 -0
- package/cli/lib/harness/codex-runtime.mjs +889 -0
- package/cli/lib/harness/compatibility.mjs +27 -0
- package/cli/lib/harness/discover-claude.mjs +1393 -0
- package/cli/lib/harness/managed-state.mjs +1296 -0
- package/cli/lib/harness/model.mjs +86 -0
- package/cli/lib/harness/secrets.mjs +390 -0
- package/cli/lib/harness/targets/codex.mjs +1141 -0
- package/cli/lib/harness/targets/opencode.mjs +807 -0
- package/cli/lib/harness/transaction.mjs +1099 -0
- package/cli/lib/hubs-config.mjs +35 -8
- package/cli/templates/harness/opencode/maude-projector.ts +58 -0
- package/docs/harness-capability-matrix.md +125 -0
- package/docs/harness-environment-projection.md +95 -0
- package/package.json +32 -9
- package/plugins/flow/.claude-plugin/config.schema.json +8 -0
- package/apps/studio/.ai/cache/_stats.json +0 -7
- package/apps/studio/bin/_agent-browser-safe.test.mjs +0 -165
- package/apps/studio/bin/_curl-local.test.mjs +0 -280
- package/apps/studio/bin/_pw-launch.test.mjs +0 -90
- package/apps/studio/bin/_smart-frames.test.mjs +0 -195
- package/apps/studio/bin/_transcribe.test.mjs +0 -80
- package/apps/studio/bun.lock +0 -928
- package/apps/studio/draw/test/animate.test.ts +0 -172
- package/apps/studio/draw/test/brush.test.ts +0 -213
- package/apps/studio/draw/test/composition.test.ts +0 -141
- package/apps/studio/draw/test/geometry.test.ts +0 -199
- package/apps/studio/draw/test/gradient.test.ts +0 -167
- package/apps/studio/draw/test/layout.test.ts +0 -120
- package/apps/studio/draw/test/morph.test.ts +0 -107
- package/apps/studio/draw/test/optimize.test.ts +0 -40
- package/apps/studio/draw/test/palette.test.ts +0 -123
- package/apps/studio/draw/test/primitives.test.ts +0 -129
- package/apps/studio/draw/test/serialize-animate.test.ts +0 -142
- package/apps/studio/draw/test/serialize.test.ts +0 -105
- package/apps/studio/figma/assets.test.ts +0 -464
- package/apps/studio/figma/client.test.ts +0 -395
- package/apps/studio/figma/codegen-client.test.ts +0 -276
- package/apps/studio/figma/codegen-fonts.test.ts +0 -103
- package/apps/studio/figma/codegen-values.test.ts +0 -179
- package/apps/studio/figma/comments-to-strokes.test.ts +0 -194
- package/apps/studio/figma/fig-decode.test.ts +0 -788
- package/apps/studio/figma/fig-differential.test.ts +0 -182
- package/apps/studio/figma/fig-translator.test.ts +0 -192
- package/apps/studio/figma/fig-vector.test.ts +0 -113
- package/apps/studio/figma/from-codegen.test.ts +0 -408
- package/apps/studio/figma/sanitize.test.ts +0 -325
- package/apps/studio/figma/tailwind-map.test.ts +0 -142
- package/apps/studio/figma/to-artboard.test.ts +0 -808
- package/apps/studio/figma/to-render.test.ts +0 -180
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +0 -152
- package/apps/studio/figma/to-strokes.test.ts +0 -705
- package/apps/studio/figma/to-tokens.test.ts +0 -321
- package/apps/studio/figma/url.test.ts +0 -167
- package/apps/studio/footage/schema.test.ts +0 -287
- package/apps/studio/generation/adapters/groq.test.ts +0 -80
- package/apps/studio/generation/audio-library.test.ts +0 -95
- package/apps/studio/generation/captions.test.ts +0 -78
- package/apps/studio/generation/elevenlabs.test.ts +0 -223
- package/apps/studio/generation/gemini.test.ts +0 -350
- package/apps/studio/generation/jobs.test.ts +0 -128
- package/apps/studio/generation/keys.test.ts +0 -75
- package/apps/studio/generation/prefs.test.ts +0 -95
- package/apps/studio/generation/types.test.ts +0 -123
- package/apps/studio/generation/whisper-models.test.ts +0 -179
- package/apps/studio/test/_helpers.ts +0 -108
- package/apps/studio/test/acp-activity-endpoint.test.ts +0 -183
- package/apps/studio/test/acp-activity.test.ts +0 -154
- package/apps/studio/test/acp-ai-activity.test.ts +0 -182
- package/apps/studio/test/acp-attachment-serve.test.ts +0 -74
- package/apps/studio/test/acp-bootstrap-brief.test.ts +0 -178
- package/apps/studio/test/acp-branch-guard.test.ts +0 -123
- package/apps/studio/test/acp-bridge-lifetime.test.ts +0 -475
- package/apps/studio/test/acp-bridge.test.ts +0 -545
- package/apps/studio/test/acp-capabilities.test.ts +0 -123
- package/apps/studio/test/acp-caps-bridge.test.ts +0 -279
- package/apps/studio/test/acp-commands.test.ts +0 -119
- package/apps/studio/test/acp-elicitation-bridge.test.ts +0 -480
- package/apps/studio/test/acp-elicitation.test.ts +0 -251
- package/apps/studio/test/acp-env.test.ts +0 -95
- package/apps/studio/test/acp-mode-banner.test.ts +0 -45
- package/apps/studio/test/acp-origin-gate.test.ts +0 -160
- package/apps/studio/test/acp-permission-prompt.test.ts +0 -251
- package/apps/studio/test/acp-permission.test.ts +0 -278
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +0 -89
- package/apps/studio/test/acp-session-allowed-tools.test.ts +0 -235
- package/apps/studio/test/acp-session-plugins.test.ts +0 -209
- package/apps/studio/test/acp-toolgroup.test.ts +0 -76
- package/apps/studio/test/acp-transcript-view.test.ts +0 -71
- package/apps/studio/test/acp-transcript.test.ts +0 -238
- package/apps/studio/test/acp-usage-bridge.test.ts +0 -141
- package/apps/studio/test/acp-usage.test.ts +0 -143
- package/apps/studio/test/acp-write-gate.test.ts +0 -323
- package/apps/studio/test/acp-write-scope.test.ts +0 -533
- package/apps/studio/test/active-state.test.ts +0 -186
- package/apps/studio/test/activity.test.ts +0 -189
- package/apps/studio/test/ai-activity.test.ts +0 -113
- package/apps/studio/test/annotate-write.test.ts +0 -1074
- package/apps/studio/test/annotation-strokes-command.test.ts +0 -166
- package/apps/studio/test/annotations-align.test.ts +0 -88
- package/apps/studio/test/annotations-api.test.ts +0 -145
- package/apps/studio/test/annotations-bindings.test.ts +0 -262
- package/apps/studio/test/annotations-draw-modifiers.test.ts +0 -206
- package/apps/studio/test/annotations-groups.test.ts +0 -231
- package/apps/studio/test/annotations-layer.test.ts +0 -1011
- package/apps/studio/test/annotations-roundtrip.test.ts +0 -663
- package/apps/studio/test/annotations-snap.test.ts +0 -135
- package/apps/studio/test/annotations-text-format.test.ts +0 -396
- package/apps/studio/test/artboard-activity-overlay.test.tsx +0 -56
- package/apps/studio/test/artboard-guides-overlay.test.tsx +0 -152
- package/apps/studio/test/artboard-hug-commit.test.ts +0 -36
- package/apps/studio/test/artboard-kinds.test.tsx +0 -83
- package/apps/studio/test/artboard-selection-attrs.test.ts +0 -69
- package/apps/studio/test/asset-api.test.ts +0 -149
- package/apps/studio/test/assets-s3.test.ts +0 -249
- package/apps/studio/test/binary-smoke.test.ts +0 -47
- package/apps/studio/test/boot-self-heal.test.ts +0 -87
- package/apps/studio/test/browse-posture.test.tsx +0 -107
- package/apps/studio/test/bundle-smoke.test.ts +0 -46
- package/apps/studio/test/camera-reveal.test.tsx +0 -173
- package/apps/studio/test/canvas-artifacts.test.ts +0 -125
- package/apps/studio/test/canvas-build-sandbox.test.ts +0 -69
- package/apps/studio/test/canvas-build.test.ts +0 -141
- package/apps/studio/test/canvas-create-api.test.ts +0 -676
- package/apps/studio/test/canvas-cursors.test.ts +0 -164
- package/apps/studio/test/canvas-edit.test.ts +0 -470
- package/apps/studio/test/canvas-freshness-deps.test.ts +0 -64
- package/apps/studio/test/canvas-header.test.ts +0 -127
- package/apps/studio/test/canvas-hide-chrome.test.ts +0 -88
- package/apps/studio/test/canvas-hmr-runtime.test.tsx +0 -114
- package/apps/studio/test/canvas-lib-inline.test.ts +0 -146
- package/apps/studio/test/canvas-lib-motion.test.ts +0 -131
- package/apps/studio/test/canvas-lib-resolver.test.ts +0 -111
- package/apps/studio/test/canvas-list-watch.test.ts +0 -388
- package/apps/studio/test/canvas-media-drop.test.ts +0 -187
- package/apps/studio/test/canvas-meta-api.test.ts +0 -707
- package/apps/studio/test/canvas-move-api.test.ts +0 -587
- package/apps/studio/test/canvas-origin-gate.test.ts +0 -417
- package/apps/studio/test/canvas-pipeline.test.ts +0 -180
- package/apps/studio/test/canvas-rects.test.ts +0 -198
- package/apps/studio/test/canvas-reorder.test.ts +0 -211
- package/apps/studio/test/canvas-route.test.ts +0 -179
- package/apps/studio/test/canvas-shell-base.test.ts +0 -107
- package/apps/studio/test/canvas-shell-build-error.test.ts +0 -52
- package/apps/studio/test/canvas-url.test.ts +0 -138
- package/apps/studio/test/canvas-wheel-delta.test.ts +0 -42
- package/apps/studio/test/canvas-zoom-floor.test.ts +0 -73
- package/apps/studio/test/capture-core.test.ts +0 -32
- package/apps/studio/test/capture-determinism-shape.test.ts +0 -135
- package/apps/studio/test/chat-attachments.test.ts +0 -117
- package/apps/studio/test/chat-context.test.ts +0 -129
- package/apps/studio/test/chat-markdown.test.tsx +0 -58
- package/apps/studio/test/clip-addressing.test.ts +0 -738
- package/apps/studio/test/clip-ops.test.ts +0 -922
- package/apps/studio/test/cloud-build.test.ts +0 -95
- package/apps/studio/test/cloud-connect-note.test.ts +0 -135
- package/apps/studio/test/cloud-endpoints.test.ts +0 -590
- package/apps/studio/test/cloud-history-hardening.test.ts +0 -165
- package/apps/studio/test/cloud-history-posture.test.ts +0 -230
- package/apps/studio/test/cloud-managed-save-surfaces.test.ts +0 -90
- package/apps/studio/test/cloud-renew.test.ts +0 -205
- package/apps/studio/test/cloud-session-role.test.ts +0 -161
- package/apps/studio/test/cloud-shell-surfaces.test.ts +0 -170
- package/apps/studio/test/cold-start-apply.test.ts +0 -303
- package/apps/studio/test/collab-annotations-bridge.test.ts +0 -55
- package/apps/studio/test/collab-awareness-bridge.test.ts +0 -223
- package/apps/studio/test/collab-bridge.test.ts +0 -79
- package/apps/studio/test/collab-loopback.test.ts +0 -63
- package/apps/studio/test/collab-origin-gate.test.ts +0 -323
- package/apps/studio/test/collab-protocol.test.ts +0 -146
- package/apps/studio/test/collab-readonly-gate.test.ts +0 -194
- package/apps/studio/test/collab-reseed-guard.test.ts +0 -78
- package/apps/studio/test/collab-room.test.ts +0 -188
- package/apps/studio/test/collab-session-survival.test.tsx +0 -176
- package/apps/studio/test/collab-stress.test.ts +0 -129
- package/apps/studio/test/comment-mount.test.ts +0 -97
- package/apps/studio/test/comment-relay-origin-gate.test.ts +0 -117
- package/apps/studio/test/comments-api.test.ts +0 -277
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +0 -155
- package/apps/studio/test/comments-overlay.test.ts +0 -117
- package/apps/studio/test/compile-entry.test.ts +0 -133
- package/apps/studio/test/component-map.test.ts +0 -48
- package/apps/studio/test/config-projection.test.ts +0 -104
- package/apps/studio/test/config-reload.test.ts +0 -230
- package/apps/studio/test/config-version.test.ts +0 -88
- package/apps/studio/test/context-resolve-tokens.test.ts +0 -97
- package/apps/studio/test/convert-to-absolute.test.ts +0 -333
- package/apps/studio/test/credential-grammar.test.ts +0 -107
- package/apps/studio/test/csp-canvas-shell.test.ts +0 -62
- package/apps/studio/test/csrf-write-guard.test.ts +0 -141
- package/apps/studio/test/debug-bundle.test.ts +0 -105
- package/apps/studio/test/design-setup-readiness.test.ts +0 -155
- package/apps/studio/test/detach-component.test.ts +0 -94
- package/apps/studio/test/dns-rebinding-guard.test.ts +0 -101
- package/apps/studio/test/dom-selection.test.ts +0 -198
- package/apps/studio/test/dynamic-text-edit.test.ts +0 -162
- package/apps/studio/test/edit-css-occurrence.test.ts +0 -81
- package/apps/studio/test/edit-persistence.test.ts +0 -91
- package/apps/studio/test/edit-scope-api.test.ts +0 -119
- package/apps/studio/test/edit-source-command.test.ts +0 -142
- package/apps/studio/test/edit-suppress.test.ts +0 -170
- package/apps/studio/test/editing-presence.test.ts +0 -103
- package/apps/studio/test/element-resize.test.ts +0 -136
- package/apps/studio/test/element-structural-api.test.ts +0 -434
- package/apps/studio/test/element-structural-edit.test.ts +0 -750
- package/apps/studio/test/ensure-browser.test.ts +0 -92
- package/apps/studio/test/equal-spacing-detector.test.ts +0 -257
- package/apps/studio/test/export-assemble.test.ts +0 -53
- package/apps/studio/test/export-browser-lane.test.ts +0 -126
- package/apps/studio/test/export-capture-fidelity.test.ts +0 -146
- package/apps/studio/test/export-capture-hygiene.test.ts +0 -675
- package/apps/studio/test/export-center.test.tsx +0 -287
- package/apps/studio/test/export-e2e-lanes.test.ts +0 -857
- package/apps/studio/test/export-format-scope-coherence.test.ts +0 -89
- package/apps/studio/test/export-lane.test.ts +0 -245
- package/apps/studio/test/export-shim-multi-capture.test.ts +0 -83
- package/apps/studio/test/exporters/canva.test.ts +0 -63
- package/apps/studio/test/exporters/degraded-propagation.test.ts +0 -123
- package/apps/studio/test/exporters/endpoint.test.ts +0 -121
- package/apps/studio/test/exporters/history.test.ts +0 -107
- package/apps/studio/test/exporters/html.test.ts +0 -26
- package/apps/studio/test/exporters/jobs.test.ts +0 -342
- package/apps/studio/test/exporters/pdf.test.ts +0 -85
- package/apps/studio/test/exporters/png.test.ts +0 -103
- package/apps/studio/test/exporters/pptx-deck.test.ts +0 -112
- package/apps/studio/test/exporters/pptx.test.ts +0 -31
- package/apps/studio/test/exporters/pw-launch.test.ts +0 -49
- package/apps/studio/test/exporters/runtime.test.ts +0 -59
- package/apps/studio/test/exporters/scope.test.ts +0 -292
- package/apps/studio/test/exporters/svg.test.ts +0 -29
- package/apps/studio/test/exporters/unsupported-media.test.ts +0 -123
- package/apps/studio/test/exporters/zip.test.ts +0 -104
- package/apps/studio/test/fetch-asset-gate.test.ts +0 -189
- package/apps/studio/test/figjam-v3-model.test.ts +0 -342
- package/apps/studio/test/figma-explode.test.ts +0 -438
- package/apps/studio/test/figma-provenance.test.ts +0 -108
- package/apps/studio/test/figma-routes.test.ts +0 -294
- package/apps/studio/test/file-lock.test.ts +0 -84
- package/apps/studio/test/fixtures/backgrounding-claude-auth.sh +0 -12
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +0 -23
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +0 -1
- package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +0 -158
- package/apps/studio/test/fixtures/mock-acp-agent-commands.mjs +0 -44
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +0 -46
- package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +0 -42
- package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +0 -63
- package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +0 -51
- package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +0 -50
- package/apps/studio/test/fixtures/mock-acp-agent-slow.mjs +0 -45
- package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +0 -56
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +0 -37
- package/apps/studio/test/fixtures/mock-acp-agent-write.mjs +0 -118
- package/apps/studio/test/fixtures/mock-acp-agent.mjs +0 -69
- package/apps/studio/test/fixtures/noisy-claude-auth.mjs +0 -27
- package/apps/studio/test/fixtures/perf-canvas.mjs +0 -201
- package/apps/studio/test/fixtures/phase-20-annotations.svg +0 -1
- package/apps/studio/test/fixtures/phase-21-annotations.svg +0 -1
- package/apps/studio/test/fixtures/tiny-subset.woff2 +0 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +0 -82
- package/apps/studio/test/fixtures/wedged-claude-auth.sh +0 -11
- package/apps/studio/test/footage-store.test.ts +0 -100
- package/apps/studio/test/fs-mkdir-api.test.ts +0 -248
- package/apps/studio/test/fs-watch.test.ts +0 -41
- package/apps/studio/test/gemma-models.test.ts +0 -245
- package/apps/studio/test/generate-route.test.ts +0 -106
- package/apps/studio/test/git-api.test.ts +0 -0
- package/apps/studio/test/git-branches.test.ts +0 -341
- package/apps/studio/test/git-cloud-posture.test.ts +0 -59
- package/apps/studio/test/git-grouping.test.ts +0 -106
- package/apps/studio/test/git-lifecycle.test.ts +0 -100
- package/apps/studio/test/git-log-format.test.ts +0 -95
- package/apps/studio/test/git-safe-rel.test.ts +0 -132
- package/apps/studio/test/git-system-engine.test.ts +0 -135
- package/apps/studio/test/git-watch.test.ts +0 -97
- package/apps/studio/test/github-api.test.ts +0 -577
- package/apps/studio/test/grid-track-handles.test.ts +0 -160
- package/apps/studio/test/handoff-static-frames.test.ts +0 -215
- package/apps/studio/test/handoff.test.ts +0 -329
- package/apps/studio/test/history-rollback.test.ts +0 -88
- package/apps/studio/test/hmr-broadcast.test.ts +0 -236
- package/apps/studio/test/hmr-classify.test.ts +0 -87
- package/apps/studio/test/hub-link.test.ts +0 -80
- package/apps/studio/test/identity-cache.test.ts +0 -83
- package/apps/studio/test/import-asset-browser.test.ts +0 -64
- package/apps/studio/test/import-asset-route.test.ts +0 -71
- package/apps/studio/test/import-asset.test.ts +0 -427
- package/apps/studio/test/import-brand-browser.test.ts +0 -88
- package/apps/studio/test/import-brand-route.test.ts +0 -120
- package/apps/studio/test/import-brand.test.ts +0 -206
- package/apps/studio/test/import-figma.test.ts +0 -667
- package/apps/studio/test/import-tokens.test.ts +0 -722
- package/apps/studio/test/index-data-canvas-ds.test.ts +0 -97
- package/apps/studio/test/input-router.test.ts +0 -757
- package/apps/studio/test/inspect-script-syntax.test.ts +0 -53
- package/apps/studio/test/inspect-selections.test.ts +0 -219
- package/apps/studio/test/knob-props-authored.test.ts +0 -87
- package/apps/studio/test/layers-synthetic-groups.test.ts +0 -96
- package/apps/studio/test/locator.test.ts +0 -214
- package/apps/studio/test/marquee-overlay.test.ts +0 -94
- package/apps/studio/test/media-commit-chain.test.ts +0 -210
- package/apps/studio/test/mode-toggle.test.tsx +0 -226
- package/apps/studio/test/motion-sample.test.ts +0 -35
- package/apps/studio/test/move-artboards-command.test.ts +0 -108
- package/apps/studio/test/participants-chrome.test.ts +0 -65
- package/apps/studio/test/paths.test.ts +0 -88
- package/apps/studio/test/pdf-print-boxes.test.ts +0 -359
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +0 -131
- package/apps/studio/test/perf-harness.ts +0 -193
- package/apps/studio/test/phase-3.6-smoke.test.ts +0 -79
- package/apps/studio/test/photo-bg-remove-validation.test.ts +0 -71
- package/apps/studio/test/photo-canvas-bundle.test.ts +0 -79
- package/apps/studio/test/photo-edit-api.test.ts +0 -201
- package/apps/studio/test/photo-filters.test.ts +0 -149
- package/apps/studio/test/photo-pipeline.test.ts +0 -106
- package/apps/studio/test/photo-taxonomy.test.ts +0 -96
- package/apps/studio/test/print-marks.test.ts +0 -113
- package/apps/studio/test/print-units.test.ts +0 -173
- package/apps/studio/test/read-annotations.test.ts +0 -727
- package/apps/studio/test/read-only-gate.test.ts +0 -188
- package/apps/studio/test/read-only-role.test.ts +0 -95
- package/apps/studio/test/readiness.test.ts +0 -337
- package/apps/studio/test/remote-ahead-behind-cache.test.ts +0 -89
- package/apps/studio/test/reorder-api.test.ts +0 -210
- package/apps/studio/test/repo-concurrency.test.ts +0 -146
- package/apps/studio/test/repo-lock.test.ts +0 -350
- package/apps/studio/test/report-proxy.test.ts +0 -125
- package/apps/studio/test/ripple.test.ts +0 -197
- package/apps/studio/test/runtime-bundle-error-mapping.test.ts +0 -43
- package/apps/studio/test/runtime-bundle.test.ts +0 -69
- package/apps/studio/test/sanitize-annotation-svg.test.ts +0 -238
- package/apps/studio/test/scaffold-design.test.ts +0 -122
- package/apps/studio/test/server-lifecycle.test.ts +0 -38
- package/apps/studio/test/session-runtime-state.test.ts +0 -226
- package/apps/studio/test/session-scope.test.ts +0 -100
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +0 -642
- package/apps/studio/test/shared-doc-convergence.test.ts +0 -265
- package/apps/studio/test/shared-doc-foundation.test.ts +0 -63
- package/apps/studio/test/shared-doc-migrate.test.ts +0 -369
- package/apps/studio/test/shared-doc-projection.test.ts +0 -238
- package/apps/studio/test/shell-importmap.test.ts +0 -56
- package/apps/studio/test/sizing-mode.test.ts +0 -102
- package/apps/studio/test/slash-commands.test.ts +0 -117
- package/apps/studio/test/snap-distance-pill.test.ts +0 -68
- package/apps/studio/test/spacing-handles.test.ts +0 -138
- package/apps/studio/test/specimen-select.test.ts +0 -88
- package/apps/studio/test/sync-agent.test.ts +0 -660
- package/apps/studio/test/sync-annotations-cold-start.test.ts +0 -302
- package/apps/studio/test/sync-asset-push.test.ts +0 -931
- package/apps/studio/test/sync-atomic-write.test.ts +0 -62
- package/apps/studio/test/sync-attach-incremental.test.ts +0 -527
- package/apps/studio/test/sync-autocommit.test.ts +0 -537
- package/apps/studio/test/sync-canvas-path.test.ts +0 -200
- package/apps/studio/test/sync-cell-write-nudge.test.ts +0 -346
- package/apps/studio/test/sync-codec.test.ts +0 -230
- package/apps/studio/test/sync-cold-seed-dedup.test.ts +0 -187
- package/apps/studio/test/sync-cold-start.test.ts +0 -304
- package/apps/studio/test/sync-connect-honesty.test.ts +0 -114
- package/apps/studio/test/sync-connection-state.test.ts +0 -337
- package/apps/studio/test/sync-ctl-channel.test.ts +0 -508
- package/apps/studio/test/sync-decide-file.test.ts +0 -420
- package/apps/studio/test/sync-doc-name.test.ts +0 -281
- package/apps/studio/test/sync-echo-guard.test.ts +0 -96
- package/apps/studio/test/sync-file-ledger.test.ts +0 -334
- package/apps/studio/test/sync-file-membership.test.ts +0 -347
- package/apps/studio/test/sync-file-plane.test.ts +0 -976
- package/apps/studio/test/sync-file-pull.test.ts +0 -333
- package/apps/studio/test/sync-fresh-link-parity.test.ts +0 -267
- package/apps/studio/test/sync-fs-mirror.test.ts +0 -181
- package/apps/studio/test/sync-hardening.test.ts +0 -586
- package/apps/studio/test/sync-hub-listing.test.ts +0 -46
- package/apps/studio/test/sync-hubs-config.test.ts +0 -133
- package/apps/studio/test/sync-incident-replay.test.ts +0 -211
- package/apps/studio/test/sync-journal.test.ts +0 -176
- package/apps/studio/test/sync-meta-codec.test.ts +0 -199
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +0 -98
- package/apps/studio/test/sync-move-retirement.test.ts +0 -231
- package/apps/studio/test/sync-panel-surface.test.ts +0 -153
- package/apps/studio/test/sync-path-pull.test.ts +0 -531
- package/apps/studio/test/sync-presentation.test.ts +0 -262
- package/apps/studio/test/sync-pull-budget.test.ts +0 -169
- package/apps/studio/test/sync-remote-docs.test.ts +0 -333
- package/apps/studio/test/sync-resync-routes.test.ts +0 -168
- package/apps/studio/test/sync-runtime.test.ts +0 -1675
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +0 -83
- package/apps/studio/test/sync-settings-routes.test.ts +0 -195
- package/apps/studio/test/sync-settings.test.ts +0 -151
- package/apps/studio/test/sync-status.test.ts +0 -261
- package/apps/studio/test/sync-supervisor.test.ts +0 -262
- package/apps/studio/test/sync-tombstone-apply.test.ts +0 -111
- package/apps/studio/test/sync-trash.test.ts +0 -132
- package/apps/studio/test/sync-two-peer-discovery.test.ts +0 -343
- package/apps/studio/test/sync-untrusted.test.ts +0 -103
- package/apps/studio/test/system-endpoint.test.ts +0 -144
- package/apps/studio/test/text-editability-stamp.test.ts +0 -131
- package/apps/studio/test/timeline-comp-target.test.ts +0 -139
- package/apps/studio/test/timeline-media-cache.test.ts +0 -41
- package/apps/studio/test/timeline-parse.test.ts +0 -184
- package/apps/studio/test/timeline-scale.test.ts +0 -65
- package/apps/studio/test/timeline-snap.test.ts +0 -85
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +0 -86
- package/apps/studio/test/tool-palette.test.tsx +0 -55
- package/apps/studio/test/tour-overlay.test.tsx +0 -90
- package/apps/studio/test/trusted-request-host.test.ts +0 -66
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +0 -211
- package/apps/studio/test/undo-stack.test.ts +0 -244
- package/apps/studio/test/use-agent-presence.test.tsx +0 -117
- package/apps/studio/test/use-annotation-resize.test.ts +0 -402
- package/apps/studio/test/use-annotation-selection.test.tsx +0 -77
- package/apps/studio/test/use-artboard-drag.test.ts +0 -324
- package/apps/studio/test/use-canvas-activity.test.tsx +0 -206
- package/apps/studio/test/use-collab.test.ts +0 -0
- package/apps/studio/test/use-cursor-modifiers.test.ts +0 -59
- package/apps/studio/test/use-keyboard-discipline.test.ts +0 -27
- package/apps/studio/test/use-selection-set.test.tsx +0 -166
- package/apps/studio/test/use-snap-guides.test.ts +0 -271
- package/apps/studio/test/use-tool-mode.test.tsx +0 -186
- package/apps/studio/test/use-undo-stack.test.tsx +0 -223
- package/apps/studio/test/video-asset.test.ts +0 -163
- package/apps/studio/test/video-comp-fixture.test.ts +0 -50
- package/apps/studio/test/video-comp.test.ts +0 -270
- package/apps/studio/test/video-encode-lib.test.ts +0 -63
- package/apps/studio/test/video-render-bridge.test.ts +0 -171
- package/apps/studio/test/whats-new.test.ts +0 -113
- package/apps/studio/test/whisper-setup.test.ts +0 -97
- package/apps/studio/test/workspace-containment.test.ts +0 -382
- package/apps/studio/test/workspace-signin.test.ts +0 -292
- package/apps/studio/test/ws-handshake.test.ts +0 -33
- package/cli/commands/cache.test.mjs +0 -166
- package/cli/commands/design-link.test.mjs +0 -419
- package/cli/commands/design.test.mjs +0 -240
- package/cli/commands/doctor.test.mjs +0 -237
- package/cli/commands/hub-workspace.test.mjs +0 -275
- package/cli/commands/hub.test.mjs +0 -225
- package/cli/commands/kg.test.mjs +0 -142
- package/cli/commands/preflight.test.mjs +0 -46
- package/cli/lib/argv.test.mjs +0 -46
- package/cli/lib/cache.test.mjs +0 -303
- package/cli/lib/cell-plan.test.mjs +0 -225
- package/cli/lib/config-lint.test.mjs +0 -117
- package/cli/lib/ddr-to-kgai.test.mjs +0 -118
- package/cli/lib/design-ownership.test.mjs +0 -329
- package/cli/lib/fetch-asset.test.mjs +0 -213
- package/cli/lib/figma-codegen-reachability.test.mjs +0 -104
- package/cli/lib/figma-import-controls.test.mjs +0 -70
- package/cli/lib/flow-design-integration.test.mjs +0 -165
- package/cli/lib/gitignore-block.test.mjs +0 -136
- package/cli/lib/gitignore-drift.test.mjs +0 -156
- package/cli/lib/hubs-config.test.mjs +0 -165
- package/cli/lib/pkg-root.test.mjs +0 -111
- package/cli/lib/plugin-cli-reachability.test.mjs +0 -57
- package/cli/lib/plugin-name-namespace.test.mjs +0 -71
- package/cli/lib/reconstruct-toolset.test.mjs +0 -194
- package/cli/lib/stack-detect.test.mjs +0 -121
- package/cli/lib/update-check.test.mjs +0 -32
- package/cli/lib/workspace-plan.test.mjs +0 -699
package/cli/lib/hubs-config.mjs
CHANGED
|
@@ -83,28 +83,55 @@ export function saveHubsConfig(config) {
|
|
|
83
83
|
*
|
|
84
84
|
* @param {string} url
|
|
85
85
|
* @param {string} token
|
|
86
|
-
* `role`
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
86
|
+
* `role` and `expiresAt` are the prior fields carried across a relink (Cloud
|
|
87
|
+
* Phase 25 C2; `expiresAt` added 2026-09-03).
|
|
88
|
+
*
|
|
89
|
+
* `role` records what the workspace vouched for at sign-in, and this path has
|
|
90
|
+
* no fresher answer — the CLI does not sign in. Dropping it would silently
|
|
91
|
+
* show a viewer the editing UI again, which is the exact experience the flag
|
|
90
92
|
* exists to prevent; a stale value costs a redundant hidden affordance and
|
|
91
|
-
* self-corrects at the next workspace sign-in.
|
|
92
|
-
*
|
|
93
|
+
* self-corrects at the next workspace sign-in.
|
|
94
|
+
*
|
|
95
|
+
* `expiresAt` is carried ONLY when the incoming token is byte-identical to the
|
|
96
|
+
* stored one — it describes the token, not the machine, so a new token
|
|
97
|
+
* invalidates it. Dropping it unconditionally is what left a linked project
|
|
98
|
+
* with no pre-expiry renewal timer at all.
|
|
99
|
+
*
|
|
100
|
+
* Nothing ELSE is preserved: `adoptedAt` is a per-machine attestation that a
|
|
101
|
+
* relink is entitled to clear.
|
|
93
102
|
*
|
|
94
103
|
* @param {{ adoptedAt?: number }} [extra]
|
|
95
104
|
*/
|
|
96
105
|
export function addHub(url, token, extra = {}) {
|
|
97
106
|
const norm = normalizeUrl(url);
|
|
98
107
|
const cfg = loadHubsConfig();
|
|
99
|
-
const
|
|
108
|
+
const prior = cfg.hubs[norm];
|
|
109
|
+
const priorRole = prior?.role;
|
|
100
110
|
// LOCAL CONSENT SURVIVES EVERY RE-SAVE. `role` is a cache of what the hub
|
|
101
111
|
// said about you at sign-in; `codeModulesAllowed` is what YOU said about the
|
|
102
112
|
// hub, and a login response must not be able to change it.
|
|
103
|
-
const priorConsent =
|
|
113
|
+
const priorConsent = prior?.codeModulesAllowed;
|
|
114
|
+
// THE EXPIRY BELONGS TO THE TOKEN, so it survives exactly when the token does.
|
|
115
|
+
//
|
|
116
|
+
// `expiresAt` is written only by the sign-in and renew paths in
|
|
117
|
+
// `apps/studio/` — the CLI has never written it and, before this, never
|
|
118
|
+
// carried it either. So `maude design link --adopt` after a workspace
|
|
119
|
+
// sign-in silently dropped it, and a record with no expiry means
|
|
120
|
+
// `scheduleRenewal()` arms no timer at all (sync/index.ts): the credential
|
|
121
|
+
// then dies mid-session with nothing having tried to renew it.
|
|
122
|
+
//
|
|
123
|
+
// CONDITIONAL ON TOKEN IDENTITY, and that is the whole subtlety. Carrying it
|
|
124
|
+
// unconditionally would be worse than dropping it: a stale expiry against a
|
|
125
|
+
// NEW token arms the timer at the wrong instant and burns a slot in the
|
|
126
|
+
// `renewalsSinceProgress` cap for nothing. Same argument as `role` above —
|
|
127
|
+
// "this path has no fresher answer" — except that a relink CAN supply a new
|
|
128
|
+
// token, which is what makes the check necessary.
|
|
129
|
+
const priorExpiry = prior?.token === token ? prior?.expiresAt : undefined;
|
|
104
130
|
cfg.hubs[norm] = {
|
|
105
131
|
token,
|
|
106
132
|
linkedAt: Date.now(),
|
|
107
133
|
...(priorRole ? { role: priorRole } : {}),
|
|
134
|
+
...(typeof priorExpiry === 'number' ? { expiresAt: priorExpiry } : {}),
|
|
108
135
|
...(typeof priorConsent === 'boolean' ? { codeModulesAllowed: priorConsent } : {}),
|
|
109
136
|
...extra,
|
|
110
137
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const inventoryPath = join(
|
|
6
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
7
|
+
'maude-projector.inventory.json'
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
function mergeAbsent(target, additions) {
|
|
11
|
+
for (const [name, value] of Object.entries(additions ?? {})) {
|
|
12
|
+
if (!Object.hasOwn(target, name)) target[name] = value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function MaudeProjectorPlugin() {
|
|
17
|
+
let inventory = null;
|
|
18
|
+
try {
|
|
19
|
+
inventory = JSON.parse(await readFile(inventoryPath, 'utf8'));
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
if (inventory?.schemaVersion !== 1 || inventory.target !== 'opencode') return {};
|
|
24
|
+
|
|
25
|
+
for (const [name, value] of Object.entries(inventory.environment ?? {})) {
|
|
26
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(name) || typeof value !== 'string') continue;
|
|
27
|
+
const reference =
|
|
28
|
+
/^\$\{([A-Z_][A-Z0-9_]*)\}$/.exec(value)?.[1] ??
|
|
29
|
+
/^\{env:([A-Z_][A-Z0-9_]*)\}$/.exec(value)?.[1];
|
|
30
|
+
if (reference) {
|
|
31
|
+
if (process.env[reference] !== undefined) process.env[name] = process.env[reference];
|
|
32
|
+
} else {
|
|
33
|
+
process.env[name] = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
config: async (config) => {
|
|
39
|
+
config.agent ??= {};
|
|
40
|
+
config.command ??= {};
|
|
41
|
+
config.mcp ??= {};
|
|
42
|
+
config.permission ??= {};
|
|
43
|
+
mergeAbsent(config.agent, inventory.config.agent);
|
|
44
|
+
mergeAbsent(config.command, inventory.config.command);
|
|
45
|
+
mergeAbsent(config.mcp, inventory.config.mcp);
|
|
46
|
+
mergeAbsent(config.permission, inventory.config.permission);
|
|
47
|
+
config.instructions ??= [];
|
|
48
|
+
for (const path of inventory.config.instructions ?? []) {
|
|
49
|
+
if (!config.instructions.includes(path)) config.instructions.push(path);
|
|
50
|
+
}
|
|
51
|
+
config.skills ??= {};
|
|
52
|
+
config.skills.paths ??= [];
|
|
53
|
+
for (const path of inventory.config.skills?.paths ?? []) {
|
|
54
|
+
if (!config.skills.paths.includes(path)) config.skills.paths.push(path);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Harness Capability Matrix
|
|
2
|
+
|
|
3
|
+
Reviewed: 2026-09-01
|
|
4
|
+
|
|
5
|
+
This document freezes the initial semantic contract for projecting a Claude Code and Maude environment into OpenCode and Codex. Claude remains the authoring source. A target status describes one representation only; it is not a claim of full parity.
|
|
6
|
+
|
|
7
|
+
## Tested Versions
|
|
8
|
+
|
|
9
|
+
| Harness | Version | Verification |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Claude Code | 2.1.241 | Installed CLI plus current settings, hooks, subagent, skill, plugin, and MCP documentation. |
|
|
12
|
+
| OpenCode | 1.18.25 | Installed CLI; `opencode debug config` run with isolated `HOME` and `XDG_CONFIG_HOME`. |
|
|
13
|
+
| Codex | 0.152.0 | Installed CLI; generated config passed `codex --strict-config doctor --json` in an isolated `CODEX_HOME`. |
|
|
14
|
+
|
|
15
|
+
Generated output is valid only for a target version accepted by the versioned capability registry. Unknown target versions fail `check` and do not mutate target state.
|
|
16
|
+
|
|
17
|
+
## Status Contract
|
|
18
|
+
|
|
19
|
+
- `native`: the target documents compatible representation and relevant semantics.
|
|
20
|
+
- `degraded`: Maude can emit a narrower or differently-invoked representation and reports the exact loss.
|
|
21
|
+
- `unsupported`: no safe equivalent exists; Maude emits no active behavior.
|
|
22
|
+
- Security-relevant `degraded` records fail strict mode unless an explicit target override acknowledges that exact degradation.
|
|
23
|
+
- Security-relevant `unsupported` records always fail strict mode.
|
|
24
|
+
- Unknown capabilities fail closed and cannot be promoted by an override.
|
|
25
|
+
|
|
26
|
+
## Capability Matrix
|
|
27
|
+
|
|
28
|
+
| Source category | OpenCode | Codex | Fail-closed behavior |
|
|
29
|
+
| --- | --- | --- | --- |
|
|
30
|
+
| Global and project `CLAUDE.md` instructions | `native` fallback, `degraded` when a target instruction file shadows it | `native` through `project_doc_fallback_filenames`, `degraded` when `AGENTS.md` shadows it | Report the shadowing file; never overwrite or adopt it implicitly. |
|
|
31
|
+
| Imported Claude instructions | `degraded` to explicit `instructions` paths/globs | `degraded` to the `AGENTS.md` chain or a generated reference | Preserve source order and report import-semantic differences. |
|
|
32
|
+
| `.claude/rules/**/*.md` | `degraded` to scoped instruction globs | `degraded` to generated skill/instruction references | Do not claim Claude path-condition semantics when the target cannot enforce them. |
|
|
33
|
+
| Scalar Claude settings | `degraded` per registered key | `degraded` per registered key and allowed scope | Unknown keys are reported and omitted. |
|
|
34
|
+
| Map/list setting precedence | `degraded`; lower into OpenCode's merge layers | `degraded`; lower into Codex's CLI/project/profile/user/system layers | Retain all contributing sources; refuse ambiguous security conflicts. |
|
|
35
|
+
| User/project marketplace plugin selection | `degraded`; lower individual compatible assets | `native` plugin lifecycle in the pre-launch bridge; `degraded` in static projection | Runtime mirrors preserve selected plugin identity; static projection never claims lifecycle parity. |
|
|
36
|
+
| Claude custom commands | `degraded` to OpenCode commands | `degraded` to Codex skills/plugins | Preserve body and description; report frontmatter, argument, and invocation differences. |
|
|
37
|
+
| Claude subagents | `degraded` to OpenCode agents | `unsupported`; Codex custom agents inherit the parent tool registry | Do not emit a role whose Claude tool restrictions cannot be enforced; remove previously managed roles and report them. |
|
|
38
|
+
| Claude skills | `native` for target-valid `SKILL.md` assets | `native` for target-valid skills/plugin assets | Validate frontmatter and references; malformed skills are invalid source, not skipped. |
|
|
39
|
+
| STDIO MCP | `native` local MCP | `native` STDIO MCP | Preserve command/args and environment references without spawning the server. |
|
|
40
|
+
| Streamable HTTP MCP | `native` remote MCP | `native` HTTP MCP | Validate URL and reference syntax; never make a discovery-time request. |
|
|
41
|
+
| Legacy SSE MCP | `degraded` to remote transport after compatibility validation | `degraded` to streamable HTTP after compatibility validation | Disabled unless endpoint compatibility is explicitly proven. |
|
|
42
|
+
| Disabled MCP | `native` with `enabled: false` | `native` with `enabled: false` | A disabled source can never become enabled implicitly. |
|
|
43
|
+
| MCP OAuth | `degraded`; target OAuth options differ | `degraded`; target OAuth options differ | Unsupported callback/client-secret fields remain disabled and reported. |
|
|
44
|
+
| MCP headers and environment | `native` for `{env:NAME}`-style references after syntax conversion | `native` for target environment-backed header fields | Never interpolate variables; reject credential-shaped literals. |
|
|
45
|
+
| Command hooks with equivalent event, input, output, blocking, timeout, and failure semantics | `degraded` through exact compatible plugin hooks | `native` only for proven Codex hook equivalents and persisted hook trust | Any failed equivalence dimension leaves the hook disabled. |
|
|
46
|
+
| HTTP hooks | `unsupported` without a separately reviewed target-native implementation | `unsupported` | Emit no active hook and fail strict mode. |
|
|
47
|
+
| Prompt hooks | `unsupported` | `unsupported` | Parse for inventory, emit no active hook, fail strict mode. |
|
|
48
|
+
| Agent hooks | `unsupported` | `unsupported` | Parse for inventory, emit no active hook, fail strict mode. |
|
|
49
|
+
| Unknown hook handlers | `unsupported` | `unsupported` | Preserve the source inventory record, emit no active hook, and fail strict mode. |
|
|
50
|
+
| Hook matchers, output, and blocking decisions | `degraded` only when all semantics match | `degraded` only when all semantics match | Never approximate lifecycle events or discard hook output/errors. |
|
|
51
|
+
| Permission allow rules | `degraded` per exactly expressible tool/path/command scope | `degraded` through approval, sandbox, and exec-policy intersections | A scoped rule can never become blanket allow. |
|
|
52
|
+
| Permission ask rules | `degraded` where the target has the same approval boundary | `degraded` through approval policy plus sandbox/exec policy | If exact scope is unavailable, retain deny/default posture and report loss. |
|
|
53
|
+
| Permission deny rules | `degraded` per exactly expressible scope | `degraded` through sandbox and exec-policy denial; runtime `Read(path)` rules become stricter filesystem denies | Deny wins; an unrepresentable deny blocks migration or keeps runtime bypass inert. |
|
|
54
|
+
| Claude permission modes | `unsupported` as direct mappings | `degraded` to narrower approval/sandbox combinations; trusted runtime `bypassPermissions` uses a no-prompt permission profile | Static projection stays narrow. Runtime bypass activates only when every ask/deny rule is conservatively representable. |
|
|
55
|
+
| Generic environment injection | `degraded` through a bounded thin plugin using references | `degraded` through shell environment policy and MCP-specific fields | Preserve names/references only; do not read current values. |
|
|
56
|
+
| Keychain identifiers | `degraded` reference-only | `degraded` reference-only | Never read, copy, log, or back up resolved credentials. |
|
|
57
|
+
| `.ai/` state | `degraded` reference/register in place | `degraded` reference/register in place | Never copy the state tree into target directories. |
|
|
58
|
+
| `.design/` state | `degraded` reference/register in place | `degraded` reference/register in place | Never copy the state tree into target directories. |
|
|
59
|
+
| kgai prompt integration | `degraded` through bounded target-native prompt/plugin wiring | `degraded` through bounded target-native instruction/hook wiring | Treat graph output as untrusted data; transcript-dependent behavior remains disabled. |
|
|
60
|
+
| Target config ownership | `native` managed JSON entries/files through Maude manifest | `native` managed TOML entries/files through Maude manifest | Existing state requires preview and explicit adoption; external edits stop all writes. |
|
|
61
|
+
|
|
62
|
+
## Precedence Findings
|
|
63
|
+
|
|
64
|
+
Claude inputs are normalized from least to most specific while preserving every contributor: global instructions/settings/assets/MCP, user-enabled plugin assets, project instructions/settings/assets/MCP, project-enabled plugin assets, then `.claude/settings.local.json`. Claude settings lists generally accumulate, scalar/map conflicts prefer the higher-precedence layer, hooks accumulate, and permissions resolve deny before ask before allow.
|
|
65
|
+
|
|
66
|
+
OpenCode merges remote, global, custom-config, project, `.opencode`, inline, managed, and MDM configuration layers. Later conflicting values win; the projector therefore owns individual entries and one thin plugin registration rather than replacing a complete `opencode.json`.
|
|
67
|
+
|
|
68
|
+
Codex resolves CLI overrides, trusted project layers from root to current directory, the selected profile, user config, system config, and defaults, while managed requirements constrain the result. Project config cannot own provider/authentication, notification, profile-selection, or telemetry-routing settings.
|
|
69
|
+
|
|
70
|
+
## TOML Writer Decision
|
|
71
|
+
|
|
72
|
+
Codex managed merge will use exact-pinned `@decimalturn/toml-patch@3.0.5` under Node 20. It is dependency-free, supports TOML 1.1, and preserves comments, whitespace, formatting, and existing order. The writer must parse the complete existing document, mutate only manifest-owned keys in the parsed object, and patch the complete object back. Passing a partial object is forbidden because omitted user keys may be removed. Tests must cover comments, unknown keys, arrays of tables, idempotence, and malformed input.
|
|
73
|
+
|
|
74
|
+
## Active Adapter Audit
|
|
75
|
+
|
|
76
|
+
`~/Dotfiles/opencode/claude-parity.ts` is prior art, not a correctness oracle. The current adapter:
|
|
77
|
+
|
|
78
|
+
- widens any scoped `Bash(...)` allow to blanket Bash access;
|
|
79
|
+
- broadens `auto` and `bypassPermissions` to unrestricted read/edit/Bash/web/external-directory access;
|
|
80
|
+
- drops ask rules, most deny rules, MCP permission rules, and unknown tools;
|
|
81
|
+
- resolves `${NAME}` header references to live values;
|
|
82
|
+
- silently ignores malformed JSON/frontmatter and unsupported agent fields;
|
|
83
|
+
- approximates Claude `SessionStart`/`Stop`, runs discovered commands detached, and discards output/errors/timeouts/blocking behavior;
|
|
84
|
+
- injects a Codex MCP with independent `approval_policy="never"` and `sandbox_mode="workspace-write"`;
|
|
85
|
+
- has no ownership manifest, adoption, conflict detection, atomic transaction, rollback, or exhaustive inventory assertion.
|
|
86
|
+
|
|
87
|
+
None of these behaviors may be carried into the projector.
|
|
88
|
+
|
|
89
|
+
## Contract Transcript
|
|
90
|
+
|
|
91
|
+
The T0 spike used isolated homes and did not load user secrets:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
$ claude --version
|
|
95
|
+
2.1.241 (Claude Code)
|
|
96
|
+
|
|
97
|
+
$ opencode --version
|
|
98
|
+
1.18.25
|
|
99
|
+
|
|
100
|
+
$ HOME=<isolated> XDG_CONFIG_HOME=<isolated> opencode debug config
|
|
101
|
+
{ "$schema": "https://opencode.ai/config.json", "agent": {}, "plugin": [], "command": {} ... }
|
|
102
|
+
|
|
103
|
+
$ codex --version
|
|
104
|
+
codex-cli 0.152.0
|
|
105
|
+
|
|
106
|
+
$ pnpm view @decimalturn/toml-patch version time.modified engines dependencies
|
|
107
|
+
3.0.5; updated 2026-08-30; Node >=16; no dependencies
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Executable conformance in later gates must use isolated `HOME`, `XDG_CONFIG_HOME`, and `CODEX_HOME`, committed safe fixtures, and no arbitrary discovered hooks.
|
|
111
|
+
|
|
112
|
+
## Sources
|
|
113
|
+
|
|
114
|
+
- [Claude Code settings](https://docs.anthropic.com/en/docs/claude-code/settings)
|
|
115
|
+
- [Claude Code hooks](https://docs.anthropic.com/en/docs/claude-code/hooks)
|
|
116
|
+
- [Claude Code subagents](https://docs.anthropic.com/en/docs/claude-code/sub-agents)
|
|
117
|
+
- [Claude Code skills](https://docs.anthropic.com/en/docs/claude-code/skills)
|
|
118
|
+
- [OpenCode configuration](https://opencode.ai/docs/config/)
|
|
119
|
+
- [OpenCode plugins](https://opencode.ai/docs/plugins/)
|
|
120
|
+
- [OpenCode configuration source](https://github.com/anomalyco/opencode/blob/dev/packages/core/src/config.ts)
|
|
121
|
+
- [Codex configuration reference](https://developers.openai.com/codex/config-file/config-reference)
|
|
122
|
+
- [Codex AGENTS.md discovery](https://developers.openai.com/codex/agent-configuration/agents-md)
|
|
123
|
+
- [Codex hooks](https://developers.openai.com/codex/hooks)
|
|
124
|
+
- [Codex skills](https://developers.openai.com/codex/build-skills)
|
|
125
|
+
- [`@decimalturn/toml-patch`](https://www.npmjs.com/package/@decimalturn/toml-patch)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Harness environment projection
|
|
2
|
+
|
|
3
|
+
Claude Code and Maude remain the authoring source. `maude harness` generates managed,
|
|
4
|
+
target-native OpenCode and Codex files without resolving secret references or copying
|
|
5
|
+
`.ai` and `.design` state.
|
|
6
|
+
|
|
7
|
+
Every command requires exactly one scope: `--global` or `--project <root>`. Projection
|
|
8
|
+
verbs require `--targets opencode,codex`; `adopt` and `remove` require one `--target`.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
maude harness migrate --from claude --targets opencode,codex --project .
|
|
12
|
+
maude harness migrate --from claude --targets opencode,codex --project . --yes
|
|
13
|
+
maude harness sync --targets opencode,codex --project .
|
|
14
|
+
maude harness check --targets opencode,codex --project . --strict --json
|
|
15
|
+
maude harness status --project . --json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`migrate`, `diff`, and `adopt` preview by default. Mutations run only after complete
|
|
19
|
+
target-specific validation and confirmation or `--yes`. Confirmation never overrides
|
|
20
|
+
literal-secret rejection, unsupported security semantics, invalid sources or targets,
|
|
21
|
+
or ownership conflicts. `sync` commits all requested targets in one managed transaction.
|
|
22
|
+
|
|
23
|
+
Machine-local ownership, backups, recovery material, and manifests live below
|
|
24
|
+
`~/.config/maude/harness/`. `remove` touches manifest-owned output only and restores an
|
|
25
|
+
adopted backup when present. Generated reports contain references and hashes, not secret
|
|
26
|
+
values.
|
|
27
|
+
|
|
28
|
+
Exit codes are stable: `0` clean/success, `1` drift or declined preview, `2` usage,
|
|
29
|
+
`3` strict/unsupported security failure, `4` ownership conflict, `5` invalid source,
|
|
30
|
+
`6` invalid target/config/version, and `7` interrupted transaction or required recovery.
|
|
31
|
+
|
|
32
|
+
No postinstall, startup, plugin hook, or `maude init` path invokes harness mutation.
|
|
33
|
+
|
|
34
|
+
## Codex pre-launch bridge
|
|
35
|
+
|
|
36
|
+
`maude codex [args...]` is a separate machine-local bridge for daily Codex use. Before
|
|
37
|
+
launching the real Codex executable it reads the effective Claude plugin selection for
|
|
38
|
+
the current project when Codex marks that project trusted (otherwise only global Claude
|
|
39
|
+
selection applies), materializes owner-only runtime marketplace mirrors below
|
|
40
|
+
`~/.config/maude/harness/codex-runtime/`, and reconciles those plugins through Codex's
|
|
41
|
+
native `plugin marketplace` and `plugin add/remove` commands. `maude codex sync --json`
|
|
42
|
+
performs the same reconciliation without starting a session.
|
|
43
|
+
|
|
44
|
+
For a Codex-trusted project whose effective Claude settings select
|
|
45
|
+
`permissions.defaultMode: "bypassPermissions"`, the bridge adds a launch-only Codex
|
|
46
|
+
permission profile with `approval_policy="never"`, root filesystem write access, and
|
|
47
|
+
full network access. Claude `Read(path)` deny rules become stricter Codex filesystem
|
|
48
|
+
denies. Any Claude ask rule or unrepresentable deny keeps runtime bypass inert. These
|
|
49
|
+
overrides are passed on the command line and are not persisted. A pre-existing
|
|
50
|
+
`sandbox_mode`, an explicit sandbox/permission-profile override, a remote target, or an
|
|
51
|
+
ambiguous working-directory override keeps the launch fail-closed so the deny profile
|
|
52
|
+
cannot be silently disabled. Any `-C`/`--cd` path is authorized first and then forwarded
|
|
53
|
+
only in canonical form; path identity and trust are checked again immediately before
|
|
54
|
+
launch. Runtime-only defaults such as the skill context budget are also passed as CLI
|
|
55
|
+
overrides instead of rewriting user-owned Codex config.
|
|
56
|
+
|
|
57
|
+
`-C` and `--cd` are resolved before project trust and settings discovery, so authority
|
|
58
|
+
cannot be borrowed from one project and applied to another. Remote and Codex Cloud
|
|
59
|
+
sessions are rejected before runtime reconciliation, so local plugins, MCP state, and
|
|
60
|
+
permissions are never mutated for a remote launch. Runtime reconciliation is serialized
|
|
61
|
+
by the same crash-safe scope-lock primitive used by transactional harness writes.
|
|
62
|
+
|
|
63
|
+
Claude commands are exposed as namespaced Codex skills. Claude agents are reported but
|
|
64
|
+
not installed: Codex custom agents inherit the parent's tool registry, so a read-only
|
|
65
|
+
sandbox cannot enforce Claude agent tool restrictions. The bridge removes role files it
|
|
66
|
+
managed before this limitation was proven. Standalone Claude MCP servers are merged with
|
|
67
|
+
plugin MCP servers. Bearer credentials must reference an environment variable or exactly
|
|
68
|
+
match one already present in the launch environment; credential values are never pooled
|
|
69
|
+
into bridge state or persisted config. The current Codex CLI cannot write pass-through
|
|
70
|
+
environment names for STDIO MCP servers without materializing values, so the runtime bridge
|
|
71
|
+
rejects those entries; the transactional `maude harness` lowerer remains the supported path.
|
|
72
|
+
|
|
73
|
+
The bridge never writes into the current repository and does not copy `.ai` or `.design`.
|
|
74
|
+
A `CODEX_HOME` inside the current project is rejected rather than weakening that boundary.
|
|
75
|
+
A shell launcher may safely shadow the real Codex binary when it sets
|
|
76
|
+
`MAUDE_CODEX_REAL` to that binary before executing `maude codex`. This runtime path
|
|
77
|
+
complements the explicit, transactional `maude harness` migration workflow; it does not
|
|
78
|
+
adopt repository files or retire existing adapters by itself.
|
|
79
|
+
|
|
80
|
+
Real-workspace conformance can keep sources and generated target files physically
|
|
81
|
+
separate: set `MAUDE_HARNESS_SOURCE_HOME` to the read-only Claude source home and
|
|
82
|
+
`MAUDE_HARNESS_PROJECT_TARGET_ROOT` to a temporary project target root. These are
|
|
83
|
+
diagnostic/operator controls; normal migration should leave both unset. A temporary
|
|
84
|
+
source mirror may set the path-delimited `MAUDE_HARNESS_ALLOWED_PLUGIN_ROOTS` to
|
|
85
|
+
explicit read-only plugin cache roots referenced by its installation index.
|
|
86
|
+
|
|
87
|
+
The npm package contains the harness command, lowerers, capability/compatibility registry,
|
|
88
|
+
OpenCode runtime template, and Codex pre-launch bridge. Test fixtures, tests, backups, machine-local manifests,
|
|
89
|
+
logs, workspace metadata, and secrets are not part of that published harness surface.
|
|
90
|
+
|
|
91
|
+
Harness output is version-locked to the target versions listed by the capability registry
|
|
92
|
+
and to the machine-local manifest schema. `check` refuses an unsupported target or schema
|
|
93
|
+
before writing anything and prints two recovery choices: upgrade Maude for a newer registry,
|
|
94
|
+
or install the target version supported by the current Maude release. Never delete an
|
|
95
|
+
incompatible manifest or its backups as an upgrade shortcut.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -51,20 +51,39 @@
|
|
|
51
51
|
"test:e2e:desktop:onboarding": "pnpm --filter @maude/desktop-e2e e2e:onboarding",
|
|
52
52
|
"test:e2e:desktop:acp-cold-start": "pnpm --filter @maude/desktop-e2e e2e:acp-cold-start",
|
|
53
53
|
"test:e2e:desktop:parity": "pnpm --filter @maude/desktop-e2e e2e:parity",
|
|
54
|
+
"test:e2e:desktop:sidecar-respawn": "pnpm --filter @maude/desktop-e2e e2e:sidecar-respawn",
|
|
54
55
|
"test:e2e:desktop:parity:cloud": "pnpm --filter @maude/desktop-e2e e2e:parity:cloud"
|
|
55
56
|
},
|
|
56
57
|
"optionalDependencies": {
|
|
57
|
-
"@1agh/maude-darwin-arm64": "1.0
|
|
58
|
-
"@1agh/maude-darwin-x64": "1.0
|
|
59
|
-
"@1agh/maude-linux-arm64": "1.0
|
|
60
|
-
"@1agh/maude-linux-arm64-musl": "1.0
|
|
61
|
-
"@1agh/maude-linux-x64": "1.0
|
|
62
|
-
"@1agh/maude-linux-x64-musl": "1.0
|
|
63
|
-
"@1agh/maude-win32-x64": "1.0
|
|
58
|
+
"@1agh/maude-darwin-arm64": "1.2.0",
|
|
59
|
+
"@1agh/maude-darwin-x64": "1.2.0",
|
|
60
|
+
"@1agh/maude-linux-arm64": "1.2.0",
|
|
61
|
+
"@1agh/maude-linux-arm64-musl": "1.2.0",
|
|
62
|
+
"@1agh/maude-linux-x64": "1.2.0",
|
|
63
|
+
"@1agh/maude-linux-x64-musl": "1.2.0",
|
|
64
|
+
"@1agh/maude-win32-x64": "1.2.0"
|
|
64
65
|
},
|
|
65
66
|
"files": [
|
|
66
67
|
"cli",
|
|
68
|
+
"!cli/.platform-binary-path",
|
|
69
|
+
"!cli/**/*.test.mjs",
|
|
70
|
+
"!cli/fixtures",
|
|
71
|
+
"!cli/**/fixtures",
|
|
72
|
+
"!cli/**/backups",
|
|
73
|
+
"!cli/**/logs",
|
|
74
|
+
"!cli/**/.DS_Store",
|
|
67
75
|
"apps/studio",
|
|
76
|
+
"!apps/studio/.ai",
|
|
77
|
+
"!apps/studio/bun.lock",
|
|
78
|
+
"!apps/studio/test",
|
|
79
|
+
"!apps/studio/**/test",
|
|
80
|
+
"!apps/studio/**/tests",
|
|
81
|
+
"!apps/studio/**/fixtures",
|
|
82
|
+
"!apps/studio/**/backups",
|
|
83
|
+
"!apps/studio/**/logs",
|
|
84
|
+
"!apps/studio/**/*.test.*",
|
|
85
|
+
"!apps/studio/**/*.spec.*",
|
|
86
|
+
"!apps/studio/**/.DS_Store",
|
|
68
87
|
"plugins/design/dependencies.json",
|
|
69
88
|
"plugins/design/dependencies.schema.json",
|
|
70
89
|
"plugins/design/templates",
|
|
@@ -72,6 +91,8 @@
|
|
|
72
91
|
"plugins/flow/dependencies.schema.json",
|
|
73
92
|
"plugins/flow/templates",
|
|
74
93
|
"plugins/flow/.claude-plugin/config.schema.json",
|
|
94
|
+
"docs/harness-capability-matrix.md",
|
|
95
|
+
"docs/harness-environment-projection.md",
|
|
75
96
|
"LICENSE",
|
|
76
97
|
"README.md"
|
|
77
98
|
],
|
|
@@ -104,9 +125,11 @@
|
|
|
104
125
|
"lucide-react": "^1.24.0"
|
|
105
126
|
},
|
|
106
127
|
"dependencies": {
|
|
128
|
+
"@decimalturn/toml-patch": "3.0.5",
|
|
107
129
|
"ajv": "^8.20.0",
|
|
108
130
|
"ajv-formats": "^3.0.1",
|
|
109
131
|
"happy-dom": "20.10.6",
|
|
110
|
-
"svgo": "^4.0.1"
|
|
132
|
+
"svgo": "^4.0.1",
|
|
133
|
+
"yaml": "2.9.0"
|
|
111
134
|
}
|
|
112
135
|
}
|
|
@@ -459,6 +459,14 @@
|
|
|
459
459
|
"minLength": 1
|
|
460
460
|
}
|
|
461
461
|
},
|
|
462
|
+
"qualityScoped": {
|
|
463
|
+
"type": "object",
|
|
464
|
+
"description": "Scoped (changed-files / changed-packages-only) gate variants for the IMPLEMENTATION inner loop (`/flow:utils-verify`, per-task `/flow:execute`, `/flow:bug-fix`). Same flat shape as `quality` — gate name → shell command string, keys mirror `quality` (conventionally `lint`, `format`, `typecheck`, `tests`). During implementation these run INSTEAD of the repo-wide `quality.*` commands; a missing key means the inner loop defers that gate to `/flow:validate` (it never falls back to the repo-wide command). `/flow:validate` and `/flow:done` ignore this block entirely — the full `quality.*` pipeline remains the single outer gate. Monorepo example: `\"lint\": \"turbo run lint --filter='[origin/main]'\"` — note changed-only `[base]`, NOT dependents-inclusive `...[base]`, which selects nearly the whole monorepo whenever a shared package is touched; dependent breakage is `/flow:validate`'s job.",
|
|
465
|
+
"additionalProperties": {
|
|
466
|
+
"type": "string",
|
|
467
|
+
"minLength": 1
|
|
468
|
+
}
|
|
469
|
+
},
|
|
462
470
|
"integrations": {
|
|
463
471
|
"type": "object",
|
|
464
472
|
"additionalProperties": false,
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
// DDR-185 security addendum, round 3 — the hardened agent-browser wrapper
|
|
2
|
-
// behind `maude design agent-browser-safe`
|
|
3
|
-
// (apps/studio/bin/_agent-browser-safe.mjs). This suite locks the SECURITY
|
|
4
|
-
// CORE: the closed subcommand allow-list (no cookies/clipboard/storage/
|
|
5
|
-
// connect/chat/eval reachable — `eval` was REMOVED in round 3, see below),
|
|
6
|
-
// the fixed positional-argument ARITY per subcommand with NO flag
|
|
7
|
-
// vocabulary at all, and the `--config`-pin + full env-clearing that closes
|
|
8
|
-
// the project-level `agent-browser.json` auto-discovery bypass a live
|
|
9
|
-
// adversarial pass found round 2 never considered.
|
|
10
|
-
|
|
11
|
-
import { describe, expect, test } from 'bun:test';
|
|
12
|
-
import { readFileSync } from 'node:fs';
|
|
13
|
-
import {
|
|
14
|
-
ALLOWED_SUBCOMMANDS,
|
|
15
|
-
CLEARED_ENV_KEYS,
|
|
16
|
-
SUBCOMMAND_ARITY,
|
|
17
|
-
validateArgv,
|
|
18
|
-
} from './_agent-browser-safe.mjs';
|
|
19
|
-
|
|
20
|
-
describe('validateArgv — subcommand allow-list', () => {
|
|
21
|
-
for (const sub of ALLOWED_SUBCOMMANDS) {
|
|
22
|
-
test(`accepts "${sub}" with its minimum expected argument count`, () => {
|
|
23
|
-
const [min] = SUBCOMMAND_ARITY[sub];
|
|
24
|
-
const args = Array.from({ length: min }, (_, i) => `arg${i}`);
|
|
25
|
-
expect(validateArgv([sub, ...args])).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
test('round 3: "eval" is REMOVED — arbitrary JS execution can\'t be argv-constrained (ethical-hacker Finding 1)', () => {
|
|
30
|
-
// Round 2 kept eval on the allow-list; a live adversarial pass proved
|
|
31
|
-
// eval defeats --allowed-domains entirely (window.location.href escapes
|
|
32
|
-
// the navigation gate; a no-cors fetch() exfiltrates without even
|
|
33
|
-
// needing a domain match) — no argv check can close that, so the
|
|
34
|
-
// capability itself is cut, mirroring this DDR's own `find` precedent.
|
|
35
|
-
expect(ALLOWED_SUBCOMMANDS).not.toContain('eval');
|
|
36
|
-
const reason = validateArgv(['eval', '1+1']);
|
|
37
|
-
expect(reason).toContain('eval');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
for (const sub of [
|
|
41
|
-
'cookies',
|
|
42
|
-
'clipboard',
|
|
43
|
-
'storage',
|
|
44
|
-
'connect',
|
|
45
|
-
'chat',
|
|
46
|
-
'upload',
|
|
47
|
-
'auth',
|
|
48
|
-
'profiles',
|
|
49
|
-
]) {
|
|
50
|
-
test(`rejects the credential/session-hijack-capable subcommand "${sub}" (ethical-hacker Finding D)`, () => {
|
|
51
|
-
const reason = validateArgv([sub, 'get']);
|
|
52
|
-
expect(reason).toContain(sub);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
test('rejects when no subcommand is given', () => {
|
|
57
|
-
expect(validateArgv([])).not.toBeNull();
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('validateArgv — fixed arity, NO flag vocabulary at all', () => {
|
|
62
|
-
test('rejects an extra argument beyond the expected arity, whatever it looks like', () => {
|
|
63
|
-
const reason = validateArgv(['open', 'http://localhost:1', 'extra']);
|
|
64
|
-
expect(reason).toContain('exactly 1');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('rejects the --provider/-p remote-cloud-browser PoC verbatim (round-2 finding)', () => {
|
|
68
|
-
expect(
|
|
69
|
-
validateArgv(['open', 'http://localhost:1', '--provider', 'browserbase'])
|
|
70
|
-
).not.toBeNull();
|
|
71
|
-
expect(validateArgv(['open', '-p', 'browserbase', 'http://localhost:1'])).not.toBeNull();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('rejects the persistent-profile PoC verbatim (still closed under the arity model)', () => {
|
|
75
|
-
expect(
|
|
76
|
-
validateArgv(['open', '--profile', 'Default', 'https://github.com/settings/tokens'])
|
|
77
|
-
).not.toBeNull();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test('rejects the CDP-attach PoC verbatim (still closed under the arity model)', () => {
|
|
81
|
-
expect(validateArgv(['snapshot', '--cdp', '9222'])).not.toBeNull();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('a positional value that itself starts with "-" is NOT mistaken for a flag (arity-based, not prefix-based)', () => {
|
|
85
|
-
// agent-browser-safe get "-weird-thing" must still work — the arity
|
|
86
|
-
// model looks at COUNT, not at whether a token happens to start with a
|
|
87
|
-
// dash.
|
|
88
|
-
expect(validateArgv(['get', '-weird-thing'])).toBeNull();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('screenshot accepts 0 or 1 positional args (optional path)', () => {
|
|
92
|
-
expect(validateArgv(['screenshot'])).toBeNull();
|
|
93
|
-
expect(validateArgv(['screenshot', '/tmp/out.png'])).toBeNull();
|
|
94
|
-
expect(validateArgv(['screenshot', '/tmp/out.png', 'extra'])).not.toBeNull();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('get accepts 1 or 2 positional args (thing + optional selector)', () => {
|
|
98
|
-
expect(validateArgv(['get', 'text'])).toBeNull();
|
|
99
|
-
expect(validateArgv(['get', 'text', '.selector'])).toBeNull();
|
|
100
|
-
expect(validateArgv(['get'])).not.toBeNull();
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('snapshot and close accept exactly 0 arguments', () => {
|
|
104
|
-
expect(validateArgv(['snapshot'])).toBeNull();
|
|
105
|
-
expect(validateArgv(['snapshot', '-i'])).not.toBeNull();
|
|
106
|
-
expect(validateArgv(['close'])).toBeNull();
|
|
107
|
-
expect(validateArgv(['close', '--all'])).not.toBeNull();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('an ordinary allowed invocation with no extra args passes', () => {
|
|
111
|
-
expect(validateArgv(['open', 'http://localhost:3000/'])).toBeNull();
|
|
112
|
-
expect(validateArgv(['screenshot', '/tmp/out.png'])).toBeNull();
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('CLEARED_ENV_KEYS', () => {
|
|
117
|
-
test('round 3: covers AGENT_BROWSER_CONFIG (defense in depth alongside the --config pin)', () => {
|
|
118
|
-
expect(CLEARED_ENV_KEYS).toContain('AGENT_BROWSER_CONFIG');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test('round 2: covers the three vars a live verification pass found missing from round 1', () => {
|
|
122
|
-
for (const key of [
|
|
123
|
-
'AGENT_BROWSER_AUTO_CONNECT',
|
|
124
|
-
'AGENT_BROWSER_PROXY',
|
|
125
|
-
'AGENT_BROWSER_ENGINE',
|
|
126
|
-
]) {
|
|
127
|
-
expect(CLEARED_ENV_KEYS).toContain(key);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test('covers all four standard proxy env vars, both cases', () => {
|
|
132
|
-
for (const key of [
|
|
133
|
-
'HTTP_PROXY',
|
|
134
|
-
'HTTPS_PROXY',
|
|
135
|
-
'ALL_PROXY',
|
|
136
|
-
'http_proxy',
|
|
137
|
-
'https_proxy',
|
|
138
|
-
'all_proxy',
|
|
139
|
-
]) {
|
|
140
|
-
expect(CLEARED_ENV_KEYS).toContain(key);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test('still covers the original round-1 set', () => {
|
|
145
|
-
for (const key of [
|
|
146
|
-
'AGENT_BROWSER_PROFILE',
|
|
147
|
-
'AGENT_BROWSER_SESSION_NAME',
|
|
148
|
-
'AGENT_BROWSER_ACTION_POLICY',
|
|
149
|
-
'AGENT_BROWSER_CONFIRM_ACTIONS',
|
|
150
|
-
'AGENT_BROWSER_CONFIRM_INTERACTIVE',
|
|
151
|
-
]) {
|
|
152
|
-
expect(CLEARED_ENV_KEYS).toContain(key);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
describe('the forced --config target (round 3: closes ./agent-browser.json auto-discovery)', () => {
|
|
158
|
-
test('_agent-browser-safe-config.json exists and is valid, empty JSON', () => {
|
|
159
|
-
// Must stay valid JSON — agent-browser exits with an error if --config
|
|
160
|
-
// points to a missing/invalid file, which would break every allowed
|
|
161
|
-
// subcommand, not just fail safe.
|
|
162
|
-
const raw = readFileSync(new URL('./_agent-browser-safe-config.json', import.meta.url), 'utf8');
|
|
163
|
-
expect(JSON.parse(raw)).toEqual({});
|
|
164
|
-
});
|
|
165
|
-
});
|