agenticreplay 0.1.0 → 0.1.2
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/README.md +14 -13
- package/bin/agenticreplay.js +2 -0
- package/node_modules/@agenticreplay/adapters/dist/claude-code.d.ts +37 -0
- package/node_modules/@agenticreplay/adapters/dist/claude-code.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/claude-code.js +103 -0
- package/node_modules/@agenticreplay/adapters/dist/claude-code.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/codex.d.ts +36 -0
- package/node_modules/@agenticreplay/adapters/dist/codex.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/codex.js +130 -0
- package/node_modules/@agenticreplay/adapters/dist/codex.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/contract.d.ts +65 -0
- package/node_modules/@agenticreplay/adapters/dist/contract.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/contract.js +460 -0
- package/node_modules/@agenticreplay/adapters/dist/contract.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/cursor.d.ts +40 -0
- package/node_modules/@agenticreplay/adapters/dist/cursor.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/cursor.js +71 -0
- package/node_modules/@agenticreplay/adapters/dist/cursor.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/detect.d.ts +47 -0
- package/node_modules/@agenticreplay/adapters/dist/detect.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/detect.js +123 -0
- package/node_modules/@agenticreplay/adapters/dist/detect.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/env.d.ts +60 -0
- package/node_modules/@agenticreplay/adapters/dist/env.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/env.js +99 -0
- package/node_modules/@agenticreplay/adapters/dist/env.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/exec.d.ts +25 -0
- package/node_modules/@agenticreplay/adapters/dist/exec.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/exec.js +51 -0
- package/node_modules/@agenticreplay/adapters/dist/exec.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/generic-openai.d.ts +8 -0
- package/node_modules/@agenticreplay/adapters/dist/generic-openai.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/generic-openai.js +31 -0
- package/node_modules/@agenticreplay/adapters/dist/generic-openai.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/goose.d.ts +39 -0
- package/node_modules/@agenticreplay/adapters/dist/goose.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/goose.js +81 -0
- package/node_modules/@agenticreplay/adapters/dist/goose.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/grok.d.ts +23 -0
- package/node_modules/@agenticreplay/adapters/dist/grok.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/grok.js +50 -0
- package/node_modules/@agenticreplay/adapters/dist/grok.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/hermes.d.ts +70 -0
- package/node_modules/@agenticreplay/adapters/dist/hermes.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/hermes.js +88 -0
- package/node_modules/@agenticreplay/adapters/dist/hermes.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/index.d.ts +25 -0
- package/node_modules/@agenticreplay/adapters/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/index.js +25 -0
- package/node_modules/@agenticreplay/adapters/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/indexrag.d.ts +27 -0
- package/node_modules/@agenticreplay/adapters/dist/indexrag.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/indexrag.js +236 -0
- package/node_modules/@agenticreplay/adapters/dist/indexrag.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/kilo.d.ts +21 -0
- package/node_modules/@agenticreplay/adapters/dist/kilo.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/kilo.js +35 -0
- package/node_modules/@agenticreplay/adapters/dist/kilo.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mcode.d.ts +81 -0
- package/node_modules/@agenticreplay/adapters/dist/mcode.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mcode.js +368 -0
- package/node_modules/@agenticreplay/adapters/dist/mcode.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mcp-config.d.ts +17 -0
- package/node_modules/@agenticreplay/adapters/dist/mcp-config.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mcp-config.js +62 -0
- package/node_modules/@agenticreplay/adapters/dist/mcp-config.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mimo.d.ts +26 -0
- package/node_modules/@agenticreplay/adapters/dist/mimo.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/mimo.js +40 -0
- package/node_modules/@agenticreplay/adapters/dist/mimo.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/node.d.ts +19 -0
- package/node_modules/@agenticreplay/adapters/dist/node.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/node.js +59 -0
- package/node_modules/@agenticreplay/adapters/dist/node.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/openclaw.d.ts +19 -0
- package/node_modules/@agenticreplay/adapters/dist/openclaw.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/openclaw.js +43 -0
- package/node_modules/@agenticreplay/adapters/dist/openclaw.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-api-bases.d.ts +2 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-api-bases.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-api-bases.js +201 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-api-bases.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-capture.d.ts +26 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-capture.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-capture.js +132 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-capture.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-catalog.d.ts +5 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-catalog.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-catalog.js +43 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-catalog.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-config.d.ts +40 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-config.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-config.js +185 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode-config.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode.d.ts +10 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode.js +243 -0
- package/node_modules/@agenticreplay/adapters/dist/opencode.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/qwen.d.ts +51 -0
- package/node_modules/@agenticreplay/adapters/dist/qwen.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/qwen.js +105 -0
- package/node_modules/@agenticreplay/adapters/dist/qwen.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/registry.d.ts +19 -0
- package/node_modules/@agenticreplay/adapters/dist/registry.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/registry.js +110 -0
- package/node_modules/@agenticreplay/adapters/dist/registry.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/scaffold.d.ts +26 -0
- package/node_modules/@agenticreplay/adapters/dist/scaffold.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/scaffold.js +125 -0
- package/node_modules/@agenticreplay/adapters/dist/scaffold.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/session.d.ts +47 -0
- package/node_modules/@agenticreplay/adapters/dist/session.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/session.js +112 -0
- package/node_modules/@agenticreplay/adapters/dist/session.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/zcode.d.ts +60 -0
- package/node_modules/@agenticreplay/adapters/dist/zcode.d.ts.map +1 -0
- package/node_modules/@agenticreplay/adapters/dist/zcode.js +424 -0
- package/node_modules/@agenticreplay/adapters/dist/zcode.js.map +1 -0
- package/node_modules/@agenticreplay/adapters/package.json +29 -0
- package/node_modules/@agenticreplay/core/dist/blobs.d.ts +21 -0
- package/node_modules/@agenticreplay/core/dist/blobs.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/blobs.js +102 -0
- package/node_modules/@agenticreplay/core/dist/blobs.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/fetch.d.ts +38 -0
- package/node_modules/@agenticreplay/core/dist/fetch.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/fetch.js +47 -0
- package/node_modules/@agenticreplay/core/dist/fetch.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/graph.d.ts +106 -0
- package/node_modules/@agenticreplay/core/dist/graph.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/graph.js +394 -0
- package/node_modules/@agenticreplay/core/dist/graph.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/index.d.ts +9 -0
- package/node_modules/@agenticreplay/core/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/index.js +9 -0
- package/node_modules/@agenticreplay/core/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/paths.d.ts +45 -0
- package/node_modules/@agenticreplay/core/dist/paths.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/paths.js +149 -0
- package/node_modules/@agenticreplay/core/dist/paths.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/private-files.d.ts +37 -0
- package/node_modules/@agenticreplay/core/dist/private-files.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/private-files.js +353 -0
- package/node_modules/@agenticreplay/core/dist/private-files.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/reader.d.ts +45 -0
- package/node_modules/@agenticreplay/core/dist/reader.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/reader.js +152 -0
- package/node_modules/@agenticreplay/core/dist/reader.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/redaction.d.ts +69 -0
- package/node_modules/@agenticreplay/core/dist/redaction.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/redaction.js +768 -0
- package/node_modules/@agenticreplay/core/dist/redaction.js.map +1 -0
- package/node_modules/@agenticreplay/core/dist/writer.d.ts +75 -0
- package/node_modules/@agenticreplay/core/dist/writer.d.ts.map +1 -0
- package/node_modules/@agenticreplay/core/dist/writer.js +368 -0
- package/node_modules/@agenticreplay/core/dist/writer.js.map +1 -0
- package/node_modules/@agenticreplay/core/package.json +26 -0
- package/node_modules/@agenticreplay/fs-capture/dist/capture.d.ts +84 -0
- package/node_modules/@agenticreplay/fs-capture/dist/capture.d.ts.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/capture.js +147 -0
- package/node_modules/@agenticreplay/fs-capture/dist/capture.js.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/git.d.ts +25 -0
- package/node_modules/@agenticreplay/fs-capture/dist/git.d.ts.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/git.js +108 -0
- package/node_modules/@agenticreplay/fs-capture/dist/git.js.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/index.d.ts +4 -0
- package/node_modules/@agenticreplay/fs-capture/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/index.js +4 -0
- package/node_modules/@agenticreplay/fs-capture/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/shadow.d.ts +271 -0
- package/node_modules/@agenticreplay/fs-capture/dist/shadow.d.ts.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/dist/shadow.js +668 -0
- package/node_modules/@agenticreplay/fs-capture/dist/shadow.js.map +1 -0
- package/node_modules/@agenticreplay/fs-capture/package.json +25 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/cli.d.ts +100 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/cli.d.ts.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/cli.js +334 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/cli.js.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/framing.d.ts +41 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/framing.d.ts.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/framing.js +94 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/framing.js.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/index.d.ts +5 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/index.js +5 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/mock.d.ts +70 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/mock.d.ts.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/mock.js +138 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/mock.js.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/shim.d.ts +24 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/shim.d.ts.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/shim.js +105 -0
- package/node_modules/@agenticreplay/mcp-shim/dist/shim.js.map +1 -0
- package/node_modules/@agenticreplay/mcp-shim/package.json +26 -0
- package/node_modules/@agenticreplay/node-instrument/dist/capture.d.ts +58 -0
- package/node_modules/@agenticreplay/node-instrument/dist/capture.d.ts.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/capture.js +404 -0
- package/node_modules/@agenticreplay/node-instrument/dist/capture.js.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/index.d.ts +4 -0
- package/node_modules/@agenticreplay/node-instrument/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/index.js +4 -0
- package/node_modules/@agenticreplay/node-instrument/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/install.d.ts +47 -0
- package/node_modules/@agenticreplay/node-instrument/dist/install.d.ts.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/install.js +174 -0
- package/node_modules/@agenticreplay/node-instrument/dist/install.js.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/rewrite.d.ts +33 -0
- package/node_modules/@agenticreplay/node-instrument/dist/rewrite.d.ts.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/dist/rewrite.js +61 -0
- package/node_modules/@agenticreplay/node-instrument/dist/rewrite.js.map +1 -0
- package/node_modules/@agenticreplay/node-instrument/package.json +23 -0
- package/node_modules/@agenticreplay/plugin-api/dist/canonical.d.ts +87 -0
- package/node_modules/@agenticreplay/plugin-api/dist/canonical.d.ts.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/dist/canonical.js +10 -0
- package/node_modules/@agenticreplay/plugin-api/dist/canonical.js.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/dist/index.d.ts +3 -0
- package/node_modules/@agenticreplay/plugin-api/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/dist/index.js +3 -0
- package/node_modules/@agenticreplay/plugin-api/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/dist/plugins.d.ts +258 -0
- package/node_modules/@agenticreplay/plugin-api/dist/plugins.d.ts.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/dist/plugins.js +2 -0
- package/node_modules/@agenticreplay/plugin-api/dist/plugins.js.map +1 -0
- package/node_modules/@agenticreplay/plugin-api/package.json +22 -0
- package/node_modules/@agenticreplay/providers/dist/index.d.ts +34 -0
- package/node_modules/@agenticreplay/providers/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/index.js +34 -0
- package/node_modules/@agenticreplay/providers/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/pricing.d.ts +44 -0
- package/node_modules/@agenticreplay/providers/dist/pricing.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/pricing.js +126 -0
- package/node_modules/@agenticreplay/providers/dist/pricing.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/anthropic.d.ts +66 -0
- package/node_modules/@agenticreplay/providers/dist/translate/anthropic.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/anthropic.js +569 -0
- package/node_modules/@agenticreplay/providers/dist/translate/anthropic.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai-responses.d.ts +51 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai-responses.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai-responses.js +574 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai-responses.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai.d.ts +60 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai.js +577 -0
- package/node_modules/@agenticreplay/providers/dist/translate/openai.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/sse.d.ts +29 -0
- package/node_modules/@agenticreplay/providers/dist/translate/sse.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/sse.js +97 -0
- package/node_modules/@agenticreplay/providers/dist/translate/sse.js.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/util.d.ts +34 -0
- package/node_modules/@agenticreplay/providers/dist/translate/util.d.ts.map +1 -0
- package/node_modules/@agenticreplay/providers/dist/translate/util.js +106 -0
- package/node_modules/@agenticreplay/providers/dist/translate/util.js.map +1 -0
- package/node_modules/@agenticreplay/providers/package.json +26 -0
- package/node_modules/@agenticreplay/proxy/dist/ca.d.ts +45 -0
- package/node_modules/@agenticreplay/proxy/dist/ca.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/ca.js +264 -0
- package/node_modules/@agenticreplay/proxy/dist/ca.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/der.d.ts +51 -0
- package/node_modules/@agenticreplay/proxy/dist/der.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/der.js +144 -0
- package/node_modules/@agenticreplay/proxy/dist/der.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/dialects.d.ts +81 -0
- package/node_modules/@agenticreplay/proxy/dist/dialects.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/dialects.js +329 -0
- package/node_modules/@agenticreplay/proxy/dist/dialects.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/forward.d.ts +34 -0
- package/node_modules/@agenticreplay/proxy/dist/forward.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/forward.js +44 -0
- package/node_modules/@agenticreplay/proxy/dist/forward.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/index.d.ts +9 -0
- package/node_modules/@agenticreplay/proxy/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/index.js +9 -0
- package/node_modules/@agenticreplay/proxy/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/intercept.d.ts +234 -0
- package/node_modules/@agenticreplay/proxy/dist/intercept.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/intercept.js +1258 -0
- package/node_modules/@agenticreplay/proxy/dist/intercept.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/matching.d.ts +109 -0
- package/node_modules/@agenticreplay/proxy/dist/matching.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/matching.js +928 -0
- package/node_modules/@agenticreplay/proxy/dist/matching.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/retrieval.d.ts +93 -0
- package/node_modules/@agenticreplay/proxy/dist/retrieval.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/retrieval.js +233 -0
- package/node_modules/@agenticreplay/proxy/dist/retrieval.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/server.d.ts +327 -0
- package/node_modules/@agenticreplay/proxy/dist/server.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/server.js +2291 -0
- package/node_modules/@agenticreplay/proxy/dist/server.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/tls-hosts.d.ts +54 -0
- package/node_modules/@agenticreplay/proxy/dist/tls-hosts.d.ts.map +1 -0
- package/node_modules/@agenticreplay/proxy/dist/tls-hosts.js +178 -0
- package/node_modules/@agenticreplay/proxy/dist/tls-hosts.js.map +1 -0
- package/node_modules/@agenticreplay/proxy/package.json +28 -0
- package/node_modules/@agenticreplay/schema/dist/constants.d.ts +30 -0
- package/node_modules/@agenticreplay/schema/dist/constants.d.ts.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/constants.js +66 -0
- package/node_modules/@agenticreplay/schema/dist/constants.js.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/index.d.ts +4 -0
- package/node_modules/@agenticreplay/schema/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/index.js +4 -0
- package/node_modules/@agenticreplay/schema/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/types.d.ts +97 -0
- package/node_modules/@agenticreplay/schema/dist/types.d.ts.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/types.js +7 -0
- package/node_modules/@agenticreplay/schema/dist/types.js.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/validate.d.ts +13 -0
- package/node_modules/@agenticreplay/schema/dist/validate.d.ts.map +1 -0
- package/node_modules/@agenticreplay/schema/dist/validate.js +44 -0
- package/node_modules/@agenticreplay/schema/dist/validate.js.map +1 -0
- package/node_modules/@agenticreplay/schema/package.json +28 -0
- package/node_modules/@agenticreplay/shell-shim/dist/index.d.ts +4 -0
- package/node_modules/@agenticreplay/shell-shim/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/index.js +4 -0
- package/node_modules/@agenticreplay/shell-shim/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/install.d.ts +75 -0
- package/node_modules/@agenticreplay/shell-shim/dist/install.d.ts.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/install.js +353 -0
- package/node_modules/@agenticreplay/shell-shim/dist/install.js.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/resolve.d.ts +2 -0
- package/node_modules/@agenticreplay/shell-shim/dist/resolve.d.ts.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/resolve.js +97 -0
- package/node_modules/@agenticreplay/shell-shim/dist/resolve.js.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner-bin.d.ts +3 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner-bin.d.ts.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner-bin.js +4 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner-bin.js.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner.d.ts +45 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner.d.ts.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner.js +105 -0
- package/node_modules/@agenticreplay/shell-shim/dist/runner.js.map +1 -0
- package/node_modules/@agenticreplay/shell-shim/package.json +26 -0
- package/node_modules/@agenticreplay/viewer/dist/bundle.d.ts +11 -0
- package/node_modules/@agenticreplay/viewer/dist/bundle.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/bundle.js +36 -0
- package/node_modules/@agenticreplay/viewer/dist/bundle.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/client/main.d.ts +12 -0
- package/node_modules/@agenticreplay/viewer/dist/client/main.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/client/main.js +249 -0
- package/node_modules/@agenticreplay/viewer/dist/client/main.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/credit.d.ts +22 -0
- package/node_modules/@agenticreplay/viewer/dist/credit.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/credit.js +22 -0
- package/node_modules/@agenticreplay/viewer/dist/credit.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/css.d.ts +11 -0
- package/node_modules/@agenticreplay/viewer/dist/css.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/css.js +410 -0
- package/node_modules/@agenticreplay/viewer/dist/css.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/export.d.ts +21 -0
- package/node_modules/@agenticreplay/viewer/dist/export.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/export.js +22 -0
- package/node_modules/@agenticreplay/viewer/dist/export.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/html.d.ts +32 -0
- package/node_modules/@agenticreplay/viewer/dist/html.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/html.js +252 -0
- package/node_modules/@agenticreplay/viewer/dist/html.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/index.d.ts +16 -0
- package/node_modules/@agenticreplay/viewer/dist/index.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/index.js +16 -0
- package/node_modules/@agenticreplay/viewer/dist/index.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/render.d.ts +126 -0
- package/node_modules/@agenticreplay/viewer/dist/render.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/render.js +699 -0
- package/node_modules/@agenticreplay/viewer/dist/render.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/serve.d.ts +21 -0
- package/node_modules/@agenticreplay/viewer/dist/serve.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/serve.js +122 -0
- package/node_modules/@agenticreplay/viewer/dist/serve.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/trace-dir.d.ts +28 -0
- package/node_modules/@agenticreplay/viewer/dist/trace-dir.d.ts.map +1 -0
- package/node_modules/@agenticreplay/viewer/dist/trace-dir.js +120 -0
- package/node_modules/@agenticreplay/viewer/dist/trace-dir.js.map +1 -0
- package/node_modules/@agenticreplay/viewer/package.json +25 -0
- package/node_modules/ajv/.runkit_example.js +23 -0
- package/node_modules/ajv/LICENSE +22 -0
- package/node_modules/ajv/README.md +207 -0
- package/node_modules/ajv/dist/2019.d.ts +19 -0
- package/node_modules/ajv/dist/2019.js +61 -0
- package/node_modules/ajv/dist/2019.js.map +1 -0
- package/node_modules/ajv/dist/2020.d.ts +19 -0
- package/node_modules/ajv/dist/2020.js +55 -0
- package/node_modules/ajv/dist/2020.js.map +1 -0
- package/node_modules/ajv/dist/ajv.d.ts +18 -0
- package/node_modules/ajv/dist/ajv.js +50 -0
- package/node_modules/ajv/dist/ajv.js.map +1 -0
- package/node_modules/ajv/dist/compile/codegen/code.d.ts +40 -0
- package/node_modules/ajv/dist/compile/codegen/code.js +156 -0
- package/node_modules/ajv/dist/compile/codegen/code.js.map +1 -0
- package/node_modules/ajv/dist/compile/codegen/index.d.ts +79 -0
- package/node_modules/ajv/dist/compile/codegen/index.js +697 -0
- package/node_modules/ajv/dist/compile/codegen/index.js.map +1 -0
- package/node_modules/ajv/dist/compile/codegen/scope.d.ts +79 -0
- package/node_modules/ajv/dist/compile/codegen/scope.js +143 -0
- package/node_modules/ajv/dist/compile/codegen/scope.js.map +1 -0
- package/node_modules/ajv/dist/compile/errors.d.ts +13 -0
- package/node_modules/ajv/dist/compile/errors.js +123 -0
- package/node_modules/ajv/dist/compile/errors.js.map +1 -0
- package/node_modules/ajv/dist/compile/index.d.ts +80 -0
- package/node_modules/ajv/dist/compile/index.js +242 -0
- package/node_modules/ajv/dist/compile/index.js.map +1 -0
- package/node_modules/ajv/dist/compile/jtd/parse.d.ts +4 -0
- package/node_modules/ajv/dist/compile/jtd/parse.js +350 -0
- package/node_modules/ajv/dist/compile/jtd/parse.js.map +1 -0
- package/node_modules/ajv/dist/compile/jtd/serialize.d.ts +4 -0
- package/node_modules/ajv/dist/compile/jtd/serialize.js +236 -0
- package/node_modules/ajv/dist/compile/jtd/serialize.js.map +1 -0
- package/node_modules/ajv/dist/compile/jtd/types.d.ts +6 -0
- package/node_modules/ajv/dist/compile/jtd/types.js +14 -0
- package/node_modules/ajv/dist/compile/jtd/types.js.map +1 -0
- package/node_modules/ajv/dist/compile/names.d.ts +20 -0
- package/node_modules/ajv/dist/compile/names.js +28 -0
- package/node_modules/ajv/dist/compile/names.js.map +1 -0
- package/node_modules/ajv/dist/compile/ref_error.d.ts +6 -0
- package/node_modules/ajv/dist/compile/ref_error.js +12 -0
- package/node_modules/ajv/dist/compile/ref_error.js.map +1 -0
- package/node_modules/ajv/dist/compile/resolve.d.ts +12 -0
- package/node_modules/ajv/dist/compile/resolve.js +155 -0
- package/node_modules/ajv/dist/compile/resolve.js.map +1 -0
- package/node_modules/ajv/dist/compile/rules.d.ts +28 -0
- package/node_modules/ajv/dist/compile/rules.js +26 -0
- package/node_modules/ajv/dist/compile/rules.js.map +1 -0
- package/node_modules/ajv/dist/compile/util.d.ts +40 -0
- package/node_modules/ajv/dist/compile/util.js +178 -0
- package/node_modules/ajv/dist/compile/util.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/applicability.d.ts +6 -0
- package/node_modules/ajv/dist/compile/validate/applicability.js +19 -0
- package/node_modules/ajv/dist/compile/validate/applicability.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/boolSchema.d.ts +4 -0
- package/node_modules/ajv/dist/compile/validate/boolSchema.js +50 -0
- package/node_modules/ajv/dist/compile/validate/boolSchema.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/dataType.d.ts +17 -0
- package/node_modules/ajv/dist/compile/validate/dataType.js +203 -0
- package/node_modules/ajv/dist/compile/validate/dataType.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/defaults.d.ts +2 -0
- package/node_modules/ajv/dist/compile/validate/defaults.js +35 -0
- package/node_modules/ajv/dist/compile/validate/defaults.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/index.d.ts +42 -0
- package/node_modules/ajv/dist/compile/validate/index.js +520 -0
- package/node_modules/ajv/dist/compile/validate/index.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/keyword.d.ts +8 -0
- package/node_modules/ajv/dist/compile/validate/keyword.js +124 -0
- package/node_modules/ajv/dist/compile/validate/keyword.js.map +1 -0
- package/node_modules/ajv/dist/compile/validate/subschema.d.ts +47 -0
- package/node_modules/ajv/dist/compile/validate/subschema.js +81 -0
- package/node_modules/ajv/dist/compile/validate/subschema.js.map +1 -0
- package/node_modules/ajv/dist/core.d.ts +174 -0
- package/node_modules/ajv/dist/core.js +618 -0
- package/node_modules/ajv/dist/core.js.map +1 -0
- package/node_modules/ajv/dist/jtd.d.ts +47 -0
- package/node_modules/ajv/dist/jtd.js +72 -0
- package/node_modules/ajv/dist/jtd.js.map +1 -0
- package/node_modules/ajv/dist/refs/data.json +13 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/index.d.ts +2 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/index.js +28 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/index.js.map +1 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/applicator.json +53 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/content.json +17 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/core.json +57 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/format.json +14 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/meta-data.json +37 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/meta/validation.json +90 -0
- package/node_modules/ajv/dist/refs/json-schema-2019-09/schema.json +39 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/index.d.ts +2 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/index.js +30 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/index.js.map +1 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/applicator.json +48 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/content.json +17 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/core.json +51 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/format-annotation.json +14 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/meta-data.json +37 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/unevaluated.json +15 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/meta/validation.json +90 -0
- package/node_modules/ajv/dist/refs/json-schema-2020-12/schema.json +55 -0
- package/node_modules/ajv/dist/refs/json-schema-draft-06.json +137 -0
- package/node_modules/ajv/dist/refs/json-schema-draft-07.json +151 -0
- package/node_modules/ajv/dist/refs/json-schema-secure.json +88 -0
- package/node_modules/ajv/dist/refs/jtd-schema.d.ts +3 -0
- package/node_modules/ajv/dist/refs/jtd-schema.js +118 -0
- package/node_modules/ajv/dist/refs/jtd-schema.js.map +1 -0
- package/node_modules/ajv/dist/runtime/equal.d.ts +6 -0
- package/node_modules/ajv/dist/runtime/equal.js +7 -0
- package/node_modules/ajv/dist/runtime/equal.js.map +1 -0
- package/node_modules/ajv/dist/runtime/parseJson.d.ts +18 -0
- package/node_modules/ajv/dist/runtime/parseJson.js +185 -0
- package/node_modules/ajv/dist/runtime/parseJson.js.map +1 -0
- package/node_modules/ajv/dist/runtime/quote.d.ts +5 -0
- package/node_modules/ajv/dist/runtime/quote.js +30 -0
- package/node_modules/ajv/dist/runtime/quote.js.map +1 -0
- package/node_modules/ajv/dist/runtime/re2.d.ts +6 -0
- package/node_modules/ajv/dist/runtime/re2.js +6 -0
- package/node_modules/ajv/dist/runtime/re2.js.map +1 -0
- package/node_modules/ajv/dist/runtime/timestamp.d.ts +5 -0
- package/node_modules/ajv/dist/runtime/timestamp.js +42 -0
- package/node_modules/ajv/dist/runtime/timestamp.js.map +1 -0
- package/node_modules/ajv/dist/runtime/ucs2length.d.ts +5 -0
- package/node_modules/ajv/dist/runtime/ucs2length.js +24 -0
- package/node_modules/ajv/dist/runtime/ucs2length.js.map +1 -0
- package/node_modules/ajv/dist/runtime/uri.d.ts +6 -0
- package/node_modules/ajv/dist/runtime/uri.js +6 -0
- package/node_modules/ajv/dist/runtime/uri.js.map +1 -0
- package/node_modules/ajv/dist/runtime/validation_error.d.ts +7 -0
- package/node_modules/ajv/dist/runtime/validation_error.js +11 -0
- package/node_modules/ajv/dist/runtime/validation_error.js.map +1 -0
- package/node_modules/ajv/dist/standalone/index.d.ts +6 -0
- package/node_modules/ajv/dist/standalone/index.js +90 -0
- package/node_modules/ajv/dist/standalone/index.js.map +1 -0
- package/node_modules/ajv/dist/standalone/instance.d.ts +12 -0
- package/node_modules/ajv/dist/standalone/instance.js +35 -0
- package/node_modules/ajv/dist/standalone/instance.js.map +1 -0
- package/node_modules/ajv/dist/types/index.d.ts +183 -0
- package/node_modules/ajv/dist/types/index.js +3 -0
- package/node_modules/ajv/dist/types/index.js.map +1 -0
- package/node_modules/ajv/dist/types/json-schema.d.ts +125 -0
- package/node_modules/ajv/dist/types/json-schema.js +3 -0
- package/node_modules/ajv/dist/types/json-schema.js.map +1 -0
- package/node_modules/ajv/dist/types/jtd-schema.d.ts +174 -0
- package/node_modules/ajv/dist/types/jtd-schema.js +3 -0
- package/node_modules/ajv/dist/types/jtd-schema.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalItems.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalItems.js +49 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalItems.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js +106 -0
- package/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/allOf.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/allOf.js +23 -0
- package/node_modules/ajv/dist/vocabularies/applicator/allOf.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/anyOf.d.ts +4 -0
- package/node_modules/ajv/dist/vocabularies/applicator/anyOf.js +12 -0
- package/node_modules/ajv/dist/vocabularies/applicator/anyOf.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/contains.d.ts +7 -0
- package/node_modules/ajv/dist/vocabularies/applicator/contains.js +95 -0
- package/node_modules/ajv/dist/vocabularies/applicator/contains.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependencies.d.ts +21 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependencies.js +85 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependencies.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependentSchemas.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependentSchemas.js +11 -0
- package/node_modules/ajv/dist/vocabularies/applicator/dependentSchemas.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/if.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/applicator/if.js +66 -0
- package/node_modules/ajv/dist/vocabularies/applicator/if.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/index.d.ts +13 -0
- package/node_modules/ajv/dist/vocabularies/applicator/index.js +44 -0
- package/node_modules/ajv/dist/vocabularies/applicator/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items.js +52 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items2020.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items2020.js +30 -0
- package/node_modules/ajv/dist/vocabularies/applicator/items2020.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/not.d.ts +4 -0
- package/node_modules/ajv/dist/vocabularies/applicator/not.js +26 -0
- package/node_modules/ajv/dist/vocabularies/applicator/not.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/oneOf.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/applicator/oneOf.js +60 -0
- package/node_modules/ajv/dist/vocabularies/applicator/oneOf.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/patternProperties.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/patternProperties.js +75 -0
- package/node_modules/ajv/dist/vocabularies/applicator/patternProperties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/prefixItems.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/prefixItems.js +12 -0
- package/node_modules/ajv/dist/vocabularies/applicator/prefixItems.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/properties.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/properties.js +54 -0
- package/node_modules/ajv/dist/vocabularies/applicator/properties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/propertyNames.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/applicator/propertyNames.js +38 -0
- package/node_modules/ajv/dist/vocabularies/applicator/propertyNames.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/applicator/thenElse.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/applicator/thenElse.js +13 -0
- package/node_modules/ajv/dist/vocabularies/applicator/thenElse.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/code.d.ts +17 -0
- package/node_modules/ajv/dist/vocabularies/code.js +131 -0
- package/node_modules/ajv/dist/vocabularies/code.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/core/id.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/core/id.js +10 -0
- package/node_modules/ajv/dist/vocabularies/core/id.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/core/index.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/core/index.js +16 -0
- package/node_modules/ajv/dist/vocabularies/core/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/core/ref.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/core/ref.js +122 -0
- package/node_modules/ajv/dist/vocabularies/core/ref.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/index.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/index.js +104 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/types.d.ts +10 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/types.js +9 -0
- package/node_modules/ajv/dist/vocabularies/discriminator/types.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/draft2020.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/draft2020.js +23 -0
- package/node_modules/ajv/dist/vocabularies/draft2020.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/draft7.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/draft7.js +17 -0
- package/node_modules/ajv/dist/vocabularies/draft7.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicAnchor.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicAnchor.js +30 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicAnchor.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicRef.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicRef.js +51 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/dynamicRef.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/index.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/index.js +9 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveAnchor.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveAnchor.js +16 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveAnchor.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveRef.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveRef.js +10 -0
- package/node_modules/ajv/dist/vocabularies/dynamic/recursiveRef.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/errors.d.ts +9 -0
- package/node_modules/ajv/dist/vocabularies/errors.js +3 -0
- package/node_modules/ajv/dist/vocabularies/errors.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/format/format.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/format/format.js +92 -0
- package/node_modules/ajv/dist/vocabularies/format/format.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/format/index.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/format/index.js +6 -0
- package/node_modules/ajv/dist/vocabularies/format/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/discriminator.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/jtd/discriminator.js +71 -0
- package/node_modules/ajv/dist/vocabularies/jtd/discriminator.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/elements.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/jtd/elements.js +24 -0
- package/node_modules/ajv/dist/vocabularies/jtd/elements.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/enum.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/jtd/enum.js +43 -0
- package/node_modules/ajv/dist/vocabularies/jtd/enum.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/error.d.ts +9 -0
- package/node_modules/ajv/dist/vocabularies/jtd/error.js +20 -0
- package/node_modules/ajv/dist/vocabularies/jtd/error.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/index.d.ts +10 -0
- package/node_modules/ajv/dist/vocabularies/jtd/index.js +29 -0
- package/node_modules/ajv/dist/vocabularies/jtd/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/metadata.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/jtd/metadata.js +25 -0
- package/node_modules/ajv/dist/vocabularies/jtd/metadata.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/nullable.d.ts +4 -0
- package/node_modules/ajv/dist/vocabularies/jtd/nullable.js +22 -0
- package/node_modules/ajv/dist/vocabularies/jtd/nullable.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/optionalProperties.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/jtd/optionalProperties.js +15 -0
- package/node_modules/ajv/dist/vocabularies/jtd/optionalProperties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/properties.d.ts +22 -0
- package/node_modules/ajv/dist/vocabularies/jtd/properties.js +149 -0
- package/node_modules/ajv/dist/vocabularies/jtd/properties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/ref.d.ts +4 -0
- package/node_modules/ajv/dist/vocabularies/jtd/ref.js +67 -0
- package/node_modules/ajv/dist/vocabularies/jtd/ref.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/type.d.ts +10 -0
- package/node_modules/ajv/dist/vocabularies/jtd/type.js +69 -0
- package/node_modules/ajv/dist/vocabularies/jtd/type.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/union.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/jtd/union.js +12 -0
- package/node_modules/ajv/dist/vocabularies/jtd/union.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/jtd/values.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/jtd/values.js +51 -0
- package/node_modules/ajv/dist/vocabularies/jtd/values.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/metadata.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/metadata.js +18 -0
- package/node_modules/ajv/dist/vocabularies/metadata.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/next.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/next.js +8 -0
- package/node_modules/ajv/dist/vocabularies/next.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/index.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/index.js +7 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedItems.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedItems.js +40 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedItems.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedProperties.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedProperties.js +65 -0
- package/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedProperties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/const.d.ts +6 -0
- package/node_modules/ajv/dist/vocabularies/validation/const.js +25 -0
- package/node_modules/ajv/dist/vocabularies/validation/const.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/dependentRequired.d.ts +5 -0
- package/node_modules/ajv/dist/vocabularies/validation/dependentRequired.js +12 -0
- package/node_modules/ajv/dist/vocabularies/validation/dependentRequired.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/enum.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/validation/enum.js +48 -0
- package/node_modules/ajv/dist/vocabularies/validation/enum.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/index.d.ts +16 -0
- package/node_modules/ajv/dist/vocabularies/validation/index.js +33 -0
- package/node_modules/ajv/dist/vocabularies/validation/index.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitContains.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitContains.js +15 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitContains.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitItems.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitItems.js +24 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitItems.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitLength.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitLength.js +27 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitLength.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitNumber.d.ts +11 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitNumber.js +27 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitNumber.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitProperties.d.ts +3 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitProperties.js +24 -0
- package/node_modules/ajv/dist/vocabularies/validation/limitProperties.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/multipleOf.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/validation/multipleOf.js +26 -0
- package/node_modules/ajv/dist/vocabularies/validation/multipleOf.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/pattern.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/validation/pattern.js +33 -0
- package/node_modules/ajv/dist/vocabularies/validation/pattern.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/required.d.ts +8 -0
- package/node_modules/ajv/dist/vocabularies/validation/required.js +79 -0
- package/node_modules/ajv/dist/vocabularies/validation/required.js.map +1 -0
- package/node_modules/ajv/dist/vocabularies/validation/uniqueItems.d.ts +9 -0
- package/node_modules/ajv/dist/vocabularies/validation/uniqueItems.js +64 -0
- package/node_modules/ajv/dist/vocabularies/validation/uniqueItems.js.map +1 -0
- package/node_modules/ajv/lib/2019.ts +81 -0
- package/node_modules/ajv/lib/2020.ts +75 -0
- package/node_modules/ajv/lib/ajv.ts +70 -0
- package/node_modules/ajv/lib/compile/codegen/code.ts +169 -0
- package/node_modules/ajv/lib/compile/codegen/index.ts +852 -0
- package/node_modules/ajv/lib/compile/codegen/scope.ts +215 -0
- package/node_modules/ajv/lib/compile/errors.ts +184 -0
- package/node_modules/ajv/lib/compile/index.ts +324 -0
- package/node_modules/ajv/lib/compile/jtd/parse.ts +411 -0
- package/node_modules/ajv/lib/compile/jtd/serialize.ts +277 -0
- package/node_modules/ajv/lib/compile/jtd/types.ts +16 -0
- package/node_modules/ajv/lib/compile/names.ts +27 -0
- package/node_modules/ajv/lib/compile/ref_error.ts +13 -0
- package/node_modules/ajv/lib/compile/resolve.ts +149 -0
- package/node_modules/ajv/lib/compile/rules.ts +50 -0
- package/node_modules/ajv/lib/compile/util.ts +213 -0
- package/node_modules/ajv/lib/compile/validate/applicability.ts +22 -0
- package/node_modules/ajv/lib/compile/validate/boolSchema.ts +47 -0
- package/node_modules/ajv/lib/compile/validate/dataType.ts +230 -0
- package/node_modules/ajv/lib/compile/validate/defaults.ts +32 -0
- package/node_modules/ajv/lib/compile/validate/index.ts +582 -0
- package/node_modules/ajv/lib/compile/validate/keyword.ts +171 -0
- package/node_modules/ajv/lib/compile/validate/subschema.ts +135 -0
- package/node_modules/ajv/lib/core.ts +892 -0
- package/node_modules/ajv/lib/jtd.ts +132 -0
- package/node_modules/ajv/lib/refs/data.json +13 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/index.ts +28 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/applicator.json +53 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/content.json +17 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/core.json +57 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/format.json +14 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/meta-data.json +37 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/meta/validation.json +90 -0
- package/node_modules/ajv/lib/refs/json-schema-2019-09/schema.json +39 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/index.ts +30 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/applicator.json +48 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/content.json +17 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/core.json +51 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/format-annotation.json +14 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/meta-data.json +37 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/unevaluated.json +15 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/meta/validation.json +90 -0
- package/node_modules/ajv/lib/refs/json-schema-2020-12/schema.json +55 -0
- package/node_modules/ajv/lib/refs/json-schema-draft-06.json +137 -0
- package/node_modules/ajv/lib/refs/json-schema-draft-07.json +151 -0
- package/node_modules/ajv/lib/refs/json-schema-secure.json +88 -0
- package/node_modules/ajv/lib/refs/jtd-schema.ts +130 -0
- package/node_modules/ajv/lib/runtime/equal.ts +7 -0
- package/node_modules/ajv/lib/runtime/parseJson.ts +177 -0
- package/node_modules/ajv/lib/runtime/quote.ts +31 -0
- package/node_modules/ajv/lib/runtime/re2.ts +6 -0
- package/node_modules/ajv/lib/runtime/timestamp.ts +46 -0
- package/node_modules/ajv/lib/runtime/ucs2length.ts +20 -0
- package/node_modules/ajv/lib/runtime/uri.ts +6 -0
- package/node_modules/ajv/lib/runtime/validation_error.ts +13 -0
- package/node_modules/ajv/lib/standalone/index.ts +100 -0
- package/node_modules/ajv/lib/standalone/instance.ts +36 -0
- package/node_modules/ajv/lib/types/index.ts +244 -0
- package/node_modules/ajv/lib/types/json-schema.ts +187 -0
- package/node_modules/ajv/lib/types/jtd-schema.ts +273 -0
- package/node_modules/ajv/lib/vocabularies/applicator/additionalItems.ts +56 -0
- package/node_modules/ajv/lib/vocabularies/applicator/additionalProperties.ts +118 -0
- package/node_modules/ajv/lib/vocabularies/applicator/allOf.ts +22 -0
- package/node_modules/ajv/lib/vocabularies/applicator/anyOf.ts +14 -0
- package/node_modules/ajv/lib/vocabularies/applicator/contains.ts +109 -0
- package/node_modules/ajv/lib/vocabularies/applicator/dependencies.ts +112 -0
- package/node_modules/ajv/lib/vocabularies/applicator/dependentSchemas.ts +11 -0
- package/node_modules/ajv/lib/vocabularies/applicator/if.ts +80 -0
- package/node_modules/ajv/lib/vocabularies/applicator/index.ts +53 -0
- package/node_modules/ajv/lib/vocabularies/applicator/items.ts +59 -0
- package/node_modules/ajv/lib/vocabularies/applicator/items2020.ts +36 -0
- package/node_modules/ajv/lib/vocabularies/applicator/not.ts +38 -0
- package/node_modules/ajv/lib/vocabularies/applicator/oneOf.ts +82 -0
- package/node_modules/ajv/lib/vocabularies/applicator/patternProperties.ts +91 -0
- package/node_modules/ajv/lib/vocabularies/applicator/prefixItems.ts +12 -0
- package/node_modules/ajv/lib/vocabularies/applicator/properties.ts +57 -0
- package/node_modules/ajv/lib/vocabularies/applicator/propertyNames.ts +50 -0
- package/node_modules/ajv/lib/vocabularies/applicator/thenElse.ts +13 -0
- package/node_modules/ajv/lib/vocabularies/code.ts +168 -0
- package/node_modules/ajv/lib/vocabularies/core/id.ts +10 -0
- package/node_modules/ajv/lib/vocabularies/core/index.ts +16 -0
- package/node_modules/ajv/lib/vocabularies/core/ref.ts +129 -0
- package/node_modules/ajv/lib/vocabularies/discriminator/index.ts +113 -0
- package/node_modules/ajv/lib/vocabularies/discriminator/types.ts +12 -0
- package/node_modules/ajv/lib/vocabularies/draft2020.ts +23 -0
- package/node_modules/ajv/lib/vocabularies/draft7.ts +17 -0
- package/node_modules/ajv/lib/vocabularies/dynamic/dynamicAnchor.ts +31 -0
- package/node_modules/ajv/lib/vocabularies/dynamic/dynamicRef.ts +51 -0
- package/node_modules/ajv/lib/vocabularies/dynamic/index.ts +9 -0
- package/node_modules/ajv/lib/vocabularies/dynamic/recursiveAnchor.ts +14 -0
- package/node_modules/ajv/lib/vocabularies/dynamic/recursiveRef.ts +10 -0
- package/node_modules/ajv/lib/vocabularies/errors.ts +18 -0
- package/node_modules/ajv/lib/vocabularies/format/format.ts +120 -0
- package/node_modules/ajv/lib/vocabularies/format/index.ts +6 -0
- package/node_modules/ajv/lib/vocabularies/jtd/discriminator.ts +89 -0
- package/node_modules/ajv/lib/vocabularies/jtd/elements.ts +32 -0
- package/node_modules/ajv/lib/vocabularies/jtd/enum.ts +45 -0
- package/node_modules/ajv/lib/vocabularies/jtd/error.ts +23 -0
- package/node_modules/ajv/lib/vocabularies/jtd/index.ts +37 -0
- package/node_modules/ajv/lib/vocabularies/jtd/metadata.ts +24 -0
- package/node_modules/ajv/lib/vocabularies/jtd/nullable.ts +21 -0
- package/node_modules/ajv/lib/vocabularies/jtd/optionalProperties.ts +15 -0
- package/node_modules/ajv/lib/vocabularies/jtd/properties.ts +184 -0
- package/node_modules/ajv/lib/vocabularies/jtd/ref.ts +76 -0
- package/node_modules/ajv/lib/vocabularies/jtd/type.ts +75 -0
- package/node_modules/ajv/lib/vocabularies/jtd/union.ts +12 -0
- package/node_modules/ajv/lib/vocabularies/jtd/values.ts +58 -0
- package/node_modules/ajv/lib/vocabularies/metadata.ts +17 -0
- package/node_modules/ajv/lib/vocabularies/next.ts +8 -0
- package/node_modules/ajv/lib/vocabularies/unevaluated/index.ts +7 -0
- package/node_modules/ajv/lib/vocabularies/unevaluated/unevaluatedItems.ts +47 -0
- package/node_modules/ajv/lib/vocabularies/unevaluated/unevaluatedProperties.ts +85 -0
- package/node_modules/ajv/lib/vocabularies/validation/const.ts +28 -0
- package/node_modules/ajv/lib/vocabularies/validation/dependentRequired.ts +23 -0
- package/node_modules/ajv/lib/vocabularies/validation/enum.ts +54 -0
- package/node_modules/ajv/lib/vocabularies/validation/index.ts +49 -0
- package/node_modules/ajv/lib/vocabularies/validation/limitContains.ts +16 -0
- package/node_modules/ajv/lib/vocabularies/validation/limitItems.ts +26 -0
- package/node_modules/ajv/lib/vocabularies/validation/limitLength.ts +30 -0
- package/node_modules/ajv/lib/vocabularies/validation/limitNumber.ts +42 -0
- package/node_modules/ajv/lib/vocabularies/validation/limitProperties.ts +26 -0
- package/node_modules/ajv/lib/vocabularies/validation/multipleOf.ts +34 -0
- package/node_modules/ajv/lib/vocabularies/validation/pattern.ts +39 -0
- package/node_modules/ajv/lib/vocabularies/validation/required.ts +98 -0
- package/node_modules/ajv/lib/vocabularies/validation/uniqueItems.ts +79 -0
- package/node_modules/ajv/package.json +126 -0
- package/node_modules/ajv-formats/LICENSE +21 -0
- package/node_modules/ajv-formats/README.md +125 -0
- package/node_modules/ajv-formats/dist/formats.d.ts +9 -0
- package/node_modules/ajv-formats/dist/formats.js +208 -0
- package/node_modules/ajv-formats/dist/formats.js.map +1 -0
- package/node_modules/ajv-formats/dist/index.d.ts +15 -0
- package/node_modules/ajv-formats/dist/index.js +37 -0
- package/node_modules/ajv-formats/dist/index.js.map +1 -0
- package/node_modules/ajv-formats/dist/limit.d.ts +10 -0
- package/node_modules/ajv-formats/dist/limit.js +69 -0
- package/node_modules/ajv-formats/dist/limit.js.map +1 -0
- package/node_modules/ajv-formats/package.json +74 -0
- package/node_modules/ajv-formats/src/formats.ts +269 -0
- package/node_modules/ajv-formats/src/index.ts +62 -0
- package/node_modules/ajv-formats/src/limit.ts +99 -0
- package/node_modules/fast-deep-equal/LICENSE +21 -0
- package/node_modules/fast-deep-equal/README.md +96 -0
- package/node_modules/fast-deep-equal/es6/index.d.ts +2 -0
- package/node_modules/fast-deep-equal/es6/index.js +72 -0
- package/node_modules/fast-deep-equal/es6/react.d.ts +2 -0
- package/node_modules/fast-deep-equal/es6/react.js +79 -0
- package/node_modules/fast-deep-equal/index.d.ts +4 -0
- package/node_modules/fast-deep-equal/index.js +46 -0
- package/node_modules/fast-deep-equal/package.json +61 -0
- package/node_modules/fast-deep-equal/react.d.ts +2 -0
- package/node_modules/fast-deep-equal/react.js +53 -0
- package/node_modules/fast-uri/.gitattributes +2 -0
- package/node_modules/fast-uri/.github/dependabot.yml +13 -0
- package/node_modules/fast-uri/.github/workflows/ci.yml +106 -0
- package/node_modules/fast-uri/.github/workflows/lock-threads.yml +19 -0
- package/node_modules/fast-uri/.github/workflows/package-manager-ci.yml +24 -0
- package/node_modules/fast-uri/LICENSE +30 -0
- package/node_modules/fast-uri/README.md +152 -0
- package/node_modules/fast-uri/benchmark/benchmark.mjs +159 -0
- package/node_modules/fast-uri/benchmark/equal.mjs +51 -0
- package/node_modules/fast-uri/benchmark/non-simple-domain.mjs +22 -0
- package/node_modules/fast-uri/benchmark/package.json +17 -0
- package/node_modules/fast-uri/benchmark/string-array-to-hex-stripped.mjs +24 -0
- package/node_modules/fast-uri/benchmark/ws-is-secure.mjs +65 -0
- package/node_modules/fast-uri/eslint.config.js +6 -0
- package/node_modules/fast-uri/index.js +631 -0
- package/node_modules/fast-uri/lib/schemes.js +272 -0
- package/node_modules/fast-uri/lib/utils.js +747 -0
- package/node_modules/fast-uri/package.json +68 -0
- package/node_modules/fast-uri/test/ajv.test.js +43 -0
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +163 -0
- package/node_modules/fast-uri/test/equal.test.js +145 -0
- package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +503 -0
- package/node_modules/fast-uri/test/fixtures/uri-js-serialize.json +120 -0
- package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +124 -0
- package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
- package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
- package/node_modules/fast-uri/test/parse.test.js +327 -0
- package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
- package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
- package/node_modules/fast-uri/test/resolve.test.js +87 -0
- package/node_modules/fast-uri/test/rfc-3986.test.js +90 -0
- package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
- package/node_modules/fast-uri/test/security-normalization.test.js +178 -0
- package/node_modules/fast-uri/test/security.test.js +431 -0
- package/node_modules/fast-uri/test/serialize.test.js +151 -0
- package/node_modules/fast-uri/test/uri-js-compatibility.test.js +33 -0
- package/node_modules/fast-uri/test/uri-js.test.js +912 -0
- package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
- package/node_modules/fast-uri/test/util.test.js +38 -0
- package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
- package/node_modules/fast-uri/tsconfig.json +9 -0
- package/node_modules/fast-uri/types/index.d.ts +60 -0
- package/node_modules/fast-uri/types/index.test-d.ts +17 -0
- package/node_modules/json-schema-traverse/.eslintrc.yml +27 -0
- package/node_modules/json-schema-traverse/.github/FUNDING.yml +2 -0
- package/node_modules/json-schema-traverse/.github/workflows/build.yml +28 -0
- package/node_modules/json-schema-traverse/.github/workflows/publish.yml +27 -0
- package/node_modules/json-schema-traverse/LICENSE +21 -0
- package/node_modules/json-schema-traverse/README.md +95 -0
- package/node_modules/json-schema-traverse/index.d.ts +40 -0
- package/node_modules/json-schema-traverse/index.js +93 -0
- package/node_modules/json-schema-traverse/package.json +43 -0
- package/node_modules/json-schema-traverse/spec/.eslintrc.yml +6 -0
- package/node_modules/json-schema-traverse/spec/fixtures/schema.js +125 -0
- package/node_modules/json-schema-traverse/spec/index.spec.js +171 -0
- package/node_modules/require-from-string/index.js +34 -0
- package/node_modules/require-from-string/license +21 -0
- package/node_modules/require-from-string/package.json +28 -0
- package/node_modules/require-from-string/readme.md +56 -0
- package/package.json +49 -2
- package/packages/cli/dist/agent-spans.d.ts +238 -0
- package/packages/cli/dist/agent-spans.d.ts.map +1 -0
- package/packages/cli/dist/agent-spans.js +677 -0
- package/packages/cli/dist/agent-spans.js.map +1 -0
- package/packages/cli/dist/api.d.ts +127 -0
- package/packages/cli/dist/api.d.ts.map +1 -0
- package/packages/cli/dist/api.js +159 -0
- package/packages/cli/dist/api.js.map +1 -0
- package/packages/cli/dist/archive.d.ts +24 -0
- package/packages/cli/dist/archive.d.ts.map +1 -0
- package/packages/cli/dist/archive.js +230 -0
- package/packages/cli/dist/archive.js.map +1 -0
- package/packages/cli/dist/args.d.ts +57 -0
- package/packages/cli/dist/args.d.ts.map +1 -0
- package/packages/cli/dist/args.js +180 -0
- package/packages/cli/dist/args.js.map +1 -0
- package/packages/cli/dist/attach.d.ts +48 -0
- package/packages/cli/dist/attach.d.ts.map +1 -0
- package/packages/cli/dist/attach.js +153 -0
- package/packages/cli/dist/attach.js.map +1 -0
- package/packages/cli/dist/capture-limits.d.ts +7 -0
- package/packages/cli/dist/capture-limits.d.ts.map +1 -0
- package/packages/cli/dist/capture-limits.js +13 -0
- package/packages/cli/dist/capture-limits.js.map +1 -0
- package/packages/cli/dist/cli.d.ts +3 -0
- package/packages/cli/dist/cli.d.ts.map +1 -0
- package/packages/cli/dist/cli.js +4 -0
- package/packages/cli/dist/cli.js.map +1 -0
- package/packages/cli/dist/commands/attach.d.ts +49 -0
- package/packages/cli/dist/commands/attach.d.ts.map +1 -0
- package/packages/cli/dist/commands/attach.js +350 -0
- package/packages/cli/dist/commands/attach.js.map +1 -0
- package/packages/cli/dist/commands/compare.d.ts +27 -0
- package/packages/cli/dist/commands/compare.d.ts.map +1 -0
- package/packages/cli/dist/commands/compare.js +187 -0
- package/packages/cli/dist/commands/compare.js.map +1 -0
- package/packages/cli/dist/commands/doctor.d.ts +24 -0
- package/packages/cli/dist/commands/doctor.d.ts.map +1 -0
- package/packages/cli/dist/commands/doctor.js +402 -0
- package/packages/cli/dist/commands/doctor.js.map +1 -0
- package/packages/cli/dist/commands/gc.d.ts +24 -0
- package/packages/cli/dist/commands/gc.d.ts.map +1 -0
- package/packages/cli/dist/commands/gc.js +326 -0
- package/packages/cli/dist/commands/gc.js.map +1 -0
- package/packages/cli/dist/commands/inspect.d.ts +45 -0
- package/packages/cli/dist/commands/inspect.d.ts.map +1 -0
- package/packages/cli/dist/commands/inspect.js +375 -0
- package/packages/cli/dist/commands/inspect.js.map +1 -0
- package/packages/cli/dist/commands/quickstart.d.ts +48 -0
- package/packages/cli/dist/commands/quickstart.d.ts.map +1 -0
- package/packages/cli/dist/commands/quickstart.js +413 -0
- package/packages/cli/dist/commands/quickstart.js.map +1 -0
- package/packages/cli/dist/commands/record.d.ts +31 -0
- package/packages/cli/dist/commands/record.d.ts.map +1 -0
- package/packages/cli/dist/commands/record.js +958 -0
- package/packages/cli/dist/commands/record.js.map +1 -0
- package/packages/cli/dist/commands/replay.d.ts +184 -0
- package/packages/cli/dist/commands/replay.d.ts.map +1 -0
- package/packages/cli/dist/commands/replay.js +2014 -0
- package/packages/cli/dist/commands/replay.js.map +1 -0
- package/packages/cli/dist/commands/scrub.d.ts +34 -0
- package/packages/cli/dist/commands/scrub.d.ts.map +1 -0
- package/packages/cli/dist/commands/scrub.js +765 -0
- package/packages/cli/dist/commands/scrub.js.map +1 -0
- package/packages/cli/dist/commands/setup.d.ts +23 -0
- package/packages/cli/dist/commands/setup.d.ts.map +1 -0
- package/packages/cli/dist/commands/setup.js +239 -0
- package/packages/cli/dist/commands/setup.js.map +1 -0
- package/packages/cli/dist/commands/sync.d.ts +236 -0
- package/packages/cli/dist/commands/sync.d.ts.map +1 -0
- package/packages/cli/dist/commands/sync.js +1270 -0
- package/packages/cli/dist/commands/sync.js.map +1 -0
- package/packages/cli/dist/config.d.ts +69 -0
- package/packages/cli/dist/config.d.ts.map +1 -0
- package/packages/cli/dist/config.js +144 -0
- package/packages/cli/dist/config.js.map +1 -0
- package/packages/cli/dist/exchange-events.d.ts +80 -0
- package/packages/cli/dist/exchange-events.d.ts.map +1 -0
- package/packages/cli/dist/exchange-events.js +296 -0
- package/packages/cli/dist/exchange-events.js.map +1 -0
- package/packages/cli/dist/flags.d.ts +41 -0
- package/packages/cli/dist/flags.d.ts.map +1 -0
- package/packages/cli/dist/flags.js +292 -0
- package/packages/cli/dist/flags.js.map +1 -0
- package/packages/cli/dist/fs-events.d.ts +19 -0
- package/packages/cli/dist/fs-events.d.ts.map +1 -0
- package/packages/cli/dist/fs-events.js +89 -0
- package/packages/cli/dist/fs-events.js.map +1 -0
- package/packages/cli/dist/index.d.ts +18 -0
- package/packages/cli/dist/index.d.ts.map +1 -0
- package/packages/cli/dist/index.js +18 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/cli/dist/main.d.ts +2 -0
- package/packages/cli/dist/main.d.ts.map +1 -0
- package/packages/cli/dist/main.js +404 -0
- package/packages/cli/dist/main.js.map +1 -0
- package/packages/cli/dist/mcp-server.d.ts +44 -0
- package/packages/cli/dist/mcp-server.d.ts.map +1 -0
- package/packages/cli/dist/mcp-server.js +250 -0
- package/packages/cli/dist/mcp-server.js.map +1 -0
- package/packages/cli/dist/mcp.d.ts +126 -0
- package/packages/cli/dist/mcp.d.ts.map +1 -0
- package/packages/cli/dist/mcp.js +290 -0
- package/packages/cli/dist/mcp.js.map +1 -0
- package/packages/cli/dist/out.d.ts +107 -0
- package/packages/cli/dist/out.d.ts.map +1 -0
- package/packages/cli/dist/out.js +280 -0
- package/packages/cli/dist/out.js.map +1 -0
- package/packages/cli/dist/rasterize.d.ts +62 -0
- package/packages/cli/dist/rasterize.d.ts.map +1 -0
- package/packages/cli/dist/rasterize.js +154 -0
- package/packages/cli/dist/rasterize.js.map +1 -0
- package/packages/cli/dist/serial.d.ts +19 -0
- package/packages/cli/dist/serial.d.ts.map +1 -0
- package/packages/cli/dist/serial.js +34 -0
- package/packages/cli/dist/serial.js.map +1 -0
- package/packages/cli/dist/share-card.d.ts +73 -0
- package/packages/cli/dist/share-card.d.ts.map +1 -0
- package/packages/cli/dist/share-card.js +413 -0
- package/packages/cli/dist/share-card.js.map +1 -0
- package/packages/cli/dist/snapshot.d.ts +39 -0
- package/packages/cli/dist/snapshot.d.ts.map +1 -0
- package/packages/cli/dist/snapshot.js +43 -0
- package/packages/cli/dist/snapshot.js.map +1 -0
- package/packages/cli/dist/tls-capture.d.ts +135 -0
- package/packages/cli/dist/tls-capture.d.ts.map +1 -0
- package/packages/cli/dist/tls-capture.js +586 -0
- package/packages/cli/dist/tls-capture.js.map +1 -0
- package/packages/cli/dist/upstream.d.ts +29 -0
- package/packages/cli/dist/upstream.d.ts.map +1 -0
- package/packages/cli/dist/upstream.js +41 -0
- package/packages/cli/dist/upstream.js.map +1 -0
- package/packages/cli/dist/version.d.ts +2 -0
- package/packages/cli/dist/version.d.ts.map +1 -0
- package/packages/cli/dist/version.js +18 -0
- package/packages/cli/dist/version.js.map +1 -0
- package/packages/cli/package.json +11 -11
- package/.dockerignore +0 -11
- package/.gitattributes +0 -19
- package/.github/workflows/ci.yml +0 -146
- package/.grok-plugin/plugin.json +0 -12
- package/.mcp.json +0 -8
- package/.prettierignore +0 -4
- package/.prettierrc.json +0 -1
- package/CONTRIBUTING.md +0 -106
- package/Dockerfile +0 -30
- package/MAINTAINERS.md +0 -24
- package/RELEASING.md +0 -183
- package/SECURITY.md +0 -149
- package/capture/CAPTURE-RUNBOOK.md +0 -271
- package/capture/CURSOR-HTTP2.md +0 -226
- package/capture/README.md +0 -349
- package/capture/capture-run.gif +0 -0
- package/capture/capture.mjs +0 -1883
- package/capture/fable-capture.gif +0 -0
- package/capture/fable-capture.mp4 +0 -0
- package/capture/muse-shim.mjs +0 -114
- package/capture/render-run.mjs +0 -125
- package/capture/render.mjs +0 -228
- package/companion-kiokuko-dsh.patch +0 -7806
- package/docs/agenticreplay-acceptance.md +0 -135
- package/docs/architecture.md +0 -160
- package/docs/chain-card.png +0 -0
- package/docs/compare-card.png +0 -0
- package/docs/demo-cli.gif +0 -0
- package/docs/demo-viewer.gif +0 -0
- package/docs/fidelity.md +0 -16
- package/docs/good-first-issues.md +0 -78
- package/docs/graph-card.png +0 -0
- package/docs/how-to/compare-models-on-the-same-failure.md +0 -58
- package/docs/how-to/debug-a-failing-agent-run.md +0 -127
- package/docs/how-to/why-did-my-agent-delete-my-file.md +0 -92
- package/docs/i18n/README.ar.md +0 -597
- package/docs/i18n/README.de.md +0 -648
- package/docs/i18n/README.es.md +0 -642
- package/docs/i18n/README.fr.md +0 -649
- package/docs/i18n/README.ja.md +0 -608
- package/docs/i18n/README.ko.md +0 -598
- package/docs/i18n/README.zh-CN.md +0 -574
- package/docs/integrations.md +0 -628
- package/docs/launch-path.md +0 -215
- package/docs/media/README.md +0 -101
- package/docs/media/sync-transcript.txt +0 -18
- package/docs/media/transcript.txt +0 -29
- package/docs/opencode-capture.md +0 -137
- package/docs/plugins.md +0 -250
- package/docs/proposals/action-graph-and-reasoning.md +0 -354
- package/docs/sync-card.png +0 -0
- package/docs/validation.md +0 -52
- package/docs/viewer-timeline.png +0 -0
- package/examples/traces/README.md +0 -50
- package/examples/traces/run_9f2c14a03b71/blobs/1b/1b694f32b8c582ace6b35ad64050e532fb3ee3ecc1a2763a82cf42ad0f2a3dd0 +0 -10
- package/examples/traces/run_9f2c14a03b71/blobs/51/517b5b8ec6c3b13121dbaec61784e2a024247c7c4efd9ba068b582ee57bd2764 +0 -4
- package/examples/traces/run_9f2c14a03b71/blobs/5b/5bba1bd069013d86363f69c00c1ae77c84c4e113aeeb7431c8141af4fed76860 +0 -7
- package/examples/traces/run_9f2c14a03b71/blobs/84/84247e7b385fd5f99a6728a509838e52ef963af92f44ef6eccbed6910de1438d +0 -10
- package/examples/traces/run_9f2c14a03b71/blobs/ac/ac9b4be9bdf7fe63c7b5135e2d14c4c0745a48771e733804869790590455f8e8 +0 -7
- package/examples/traces/run_9f2c14a03b71/events.jsonl +0 -31
- package/examples/traces/run_9f2c14a03b71/manifest.json +0 -46
- package/examples/traces/run_9f2c14a03b71/redactions.json +0 -17
- package/llms.txt +0 -26
- package/packages/adapters/fixtures/harness/claude-code.json +0 -12
- package/packages/adapters/fixtures/harness/codex.json +0 -10
- package/packages/adapters/fixtures/harness/cursor.json +0 -10
- package/packages/adapters/fixtures/harness/exec.json +0 -10
- package/packages/adapters/fixtures/harness/generic-openai.json +0 -14
- package/packages/adapters/fixtures/harness/goose.json +0 -14
- package/packages/adapters/fixtures/harness/grok.json +0 -18
- package/packages/adapters/fixtures/harness/hermes.json +0 -10
- package/packages/adapters/fixtures/harness/indexrag.json +0 -21
- package/packages/adapters/fixtures/harness/kilo.json +0 -10
- package/packages/adapters/fixtures/harness/mcode.json +0 -10
- package/packages/adapters/fixtures/harness/mimo.json +0 -10
- package/packages/adapters/fixtures/harness/node.json +0 -22
- package/packages/adapters/fixtures/harness/openclaw.json +0 -21
- package/packages/adapters/fixtures/harness/opencode.json +0 -20
- package/packages/adapters/fixtures/harness/qwen.json +0 -20
- package/packages/adapters/fixtures/harness/zcode.json +0 -10
- package/packages/adapters/package.json +0 -29
- package/packages/adapters/src/claude-code.ts +0 -109
- package/packages/adapters/src/codex.ts +0 -135
- package/packages/adapters/src/contract.ts +0 -531
- package/packages/adapters/src/cursor.ts +0 -76
- package/packages/adapters/src/detect.ts +0 -132
- package/packages/adapters/src/env.ts +0 -118
- package/packages/adapters/src/exec.ts +0 -59
- package/packages/adapters/src/generic-openai.ts +0 -36
- package/packages/adapters/src/goose.ts +0 -87
- package/packages/adapters/src/grok.ts +0 -60
- package/packages/adapters/src/hermes.ts +0 -92
- package/packages/adapters/src/index.ts +0 -24
- package/packages/adapters/src/indexrag.ts +0 -254
- package/packages/adapters/src/kilo.ts +0 -39
- package/packages/adapters/src/mcode.ts +0 -392
- package/packages/adapters/src/mcp-config.ts +0 -84
- package/packages/adapters/src/mimo.ts +0 -44
- package/packages/adapters/src/node.ts +0 -71
- package/packages/adapters/src/openclaw.ts +0 -50
- package/packages/adapters/src/opencode-api-bases.ts +0 -200
- package/packages/adapters/src/opencode-capture.ts +0 -164
- package/packages/adapters/src/opencode-catalog.ts +0 -44
- package/packages/adapters/src/opencode-config.ts +0 -209
- package/packages/adapters/src/opencode.ts +0 -257
- package/packages/adapters/src/qwen.ts +0 -113
- package/packages/adapters/src/registry.ts +0 -121
- package/packages/adapters/src/scaffold.ts +0 -173
- package/packages/adapters/src/session.ts +0 -138
- package/packages/adapters/src/zcode.ts +0 -440
- package/packages/adapters/test/adapters.test.ts +0 -666
- package/packages/adapters/test/contract.test.ts +0 -601
- package/packages/adapters/test/exec-adapter.test.ts +0 -114
- package/packages/adapters/test/harness-versions.test.ts +0 -220
- package/packages/adapters/test/indexrag.test.ts +0 -192
- package/packages/adapters/test/mcode.test.ts +0 -678
- package/packages/adapters/test/mcp-config.test.ts +0 -118
- package/packages/adapters/test/named-agents.test.ts +0 -262
- package/packages/adapters/test/node-adapter.test.ts +0 -98
- package/packages/adapters/test/opencode-capture.test.ts +0 -137
- package/packages/adapters/test/opencode-catalog.test.ts +0 -178
- package/packages/adapters/test/opencode-config.test.ts +0 -63
- package/packages/adapters/test/scaffold.test.ts +0 -156
- package/packages/adapters/test/session.test.ts +0 -368
- package/packages/adapters/test/zcode.test.ts +0 -497
- package/packages/adapters/tsconfig.json +0 -16
- package/packages/cli/README.md +0 -92
- package/packages/cli/src/agent-spans.ts +0 -752
- package/packages/cli/src/api.ts +0 -275
- package/packages/cli/src/archive.ts +0 -264
- package/packages/cli/src/args.ts +0 -207
- package/packages/cli/src/attach.ts +0 -178
- package/packages/cli/src/capture-limits.ts +0 -21
- package/packages/cli/src/cli.ts +0 -4
- package/packages/cli/src/commands/attach.ts +0 -441
- package/packages/cli/src/commands/compare.ts +0 -218
- package/packages/cli/src/commands/doctor.ts +0 -447
- package/packages/cli/src/commands/gc.ts +0 -372
- package/packages/cli/src/commands/inspect.ts +0 -482
- package/packages/cli/src/commands/quickstart.ts +0 -479
- package/packages/cli/src/commands/record.ts +0 -1069
- package/packages/cli/src/commands/replay.ts +0 -2289
- package/packages/cli/src/commands/scrub.ts +0 -865
- package/packages/cli/src/commands/setup.ts +0 -294
- package/packages/cli/src/commands/sync.ts +0 -1429
- package/packages/cli/src/config.ts +0 -182
- package/packages/cli/src/exchange-events.ts +0 -369
- package/packages/cli/src/flags.ts +0 -316
- package/packages/cli/src/fs-events.ts +0 -103
- package/packages/cli/src/index.ts +0 -17
- package/packages/cli/src/main.ts +0 -419
- package/packages/cli/src/mcp-server.ts +0 -314
- package/packages/cli/src/mcp.ts +0 -350
- package/packages/cli/src/out.ts +0 -350
- package/packages/cli/src/rasterize.ts +0 -205
- package/packages/cli/src/serial.ts +0 -38
- package/packages/cli/src/share-card.ts +0 -514
- package/packages/cli/src/snapshot.ts +0 -80
- package/packages/cli/src/tls-capture.ts +0 -688
- package/packages/cli/src/upstream.ts +0 -75
- package/packages/cli/src/version.ts +0 -21
- package/packages/cli/test/agent-spans-drain.test.ts +0 -157
- package/packages/cli/test/agent-spans-race.test.ts +0 -97
- package/packages/cli/test/agent-spans.test.ts +0 -1032
- package/packages/cli/test/api.test.ts +0 -178
- package/packages/cli/test/archive.test.ts +0 -143
- package/packages/cli/test/args.test.ts +0 -164
- package/packages/cli/test/attach-command.test.ts +0 -356
- package/packages/cli/test/attach.test.ts +0 -198
- package/packages/cli/test/capture-oracle.test.ts +0 -160
- package/packages/cli/test/capture-warning.test.ts +0 -215
- package/packages/cli/test/chain-card.test.ts +0 -190
- package/packages/cli/test/claude-capture.test.ts +0 -242
- package/packages/cli/test/compare.test.ts +0 -329
- package/packages/cli/test/config-permission-failure.test.ts +0 -41
- package/packages/cli/test/config.test.ts +0 -239
- package/packages/cli/test/declared-inside-replay.test.ts +0 -170
- package/packages/cli/test/doctor.test.ts +0 -276
- package/packages/cli/test/e2e.test.ts +0 -1230
- package/packages/cli/test/exchange-events.test.ts +0 -345
- package/packages/cli/test/failure-lines.test.ts +0 -47
- package/packages/cli/test/fixtures/deaf-agent.mjs +0 -11
- package/packages/cli/test/fixtures/embedding-agent.mjs +0 -32
- package/packages/cli/test/fixtures/fake-agent.mjs +0 -114
- package/packages/cli/test/fixtures/fake-model.mjs +0 -105
- package/packages/cli/test/fixtures/gateway-agent.mjs +0 -20
- package/packages/cli/test/fixtures/ide-parent.mjs +0 -34
- package/packages/cli/test/fixtures/mcp-agent.mjs +0 -64
- package/packages/cli/test/fixtures/proxy-call.mjs +0 -105
- package/packages/cli/test/fixtures/responses-agent.mjs +0 -82
- package/packages/cli/test/fixtures/responses-model.mjs +0 -94
- package/packages/cli/test/fixtures/tls-agent.mjs +0 -35
- package/packages/cli/test/fixtures/vercel-agent.mjs +0 -81
- package/packages/cli/test/flag-values.test.ts +0 -162
- package/packages/cli/test/flags.test.ts +0 -313
- package/packages/cli/test/fork-provenance.test.ts +0 -224
- package/packages/cli/test/fork-tls.test.ts +0 -190
- package/packages/cli/test/gateway-e2e.test.ts +0 -110
- package/packages/cli/test/gc.test.ts +0 -531
- package/packages/cli/test/generated-esm.test.ts +0 -87
- package/packages/cli/test/graph-card.test.ts +0 -249
- package/packages/cli/test/graph-command.test.ts +0 -258
- package/packages/cli/test/grok-bot-e2e.test.ts +0 -349
- package/packages/cli/test/inspect.test.ts +0 -412
- package/packages/cli/test/intercept-failures.test.ts +0 -74
- package/packages/cli/test/json-only.test.ts +0 -88
- package/packages/cli/test/json-output.test.ts +0 -221
- package/packages/cli/test/list-gateway.test.ts +0 -770
- package/packages/cli/test/mcp-capture.test.ts +0 -498
- package/packages/cli/test/mcp-server.test.ts +0 -315
- package/packages/cli/test/nested-repo-replay.test.ts +0 -972
- package/packages/cli/test/no-credential-in-attrs.test.ts +0 -255
- package/packages/cli/test/opencode-capture.test.ts +0 -422
- package/packages/cli/test/opencode-catalog-capture.test.ts +0 -175
- package/packages/cli/test/out.test.ts +0 -491
- package/packages/cli/test/pinned-fetch.test.ts +0 -154
- package/packages/cli/test/prompt-scrub.test.ts +0 -132
- package/packages/cli/test/publish-order.test.ts +0 -87
- package/packages/cli/test/quickstart.test.ts +0 -579
- package/packages/cli/test/rasterize.test.ts +0 -86
- package/packages/cli/test/record-detection.test.ts +0 -156
- package/packages/cli/test/record-teardown.test.ts +0 -203
- package/packages/cli/test/replay-putback.test.ts +0 -242
- package/packages/cli/test/replay-spill.test.ts +0 -116
- package/packages/cli/test/replay-teardown.test.ts +0 -143
- package/packages/cli/test/replay-trace.test.ts +0 -199
- package/packages/cli/test/replay-transport.test.ts +0 -113
- package/packages/cli/test/reset-roots.test.ts +0 -67
- package/packages/cli/test/responses-e2e.test.ts +0 -119
- package/packages/cli/test/retrieval-context.test.ts +0 -168
- package/packages/cli/test/review-regressions.test.ts +0 -168
- package/packages/cli/test/route-decision.test.ts +0 -134
- package/packages/cli/test/run-dir-sidecars.test.ts +0 -779
- package/packages/cli/test/scrub.test.ts +0 -936
- package/packages/cli/test/serial.test.ts +0 -65
- package/packages/cli/test/setup.test.ts +0 -535
- package/packages/cli/test/share-card.test.ts +0 -135
- package/packages/cli/test/shell-capture.test.ts +0 -184
- package/packages/cli/test/shell-frames-drain.test.ts +0 -91
- package/packages/cli/test/snapshot-retry.test.ts +0 -54
- package/packages/cli/test/support-claims.test.ts +0 -127
- package/packages/cli/test/sync-credentials.test.ts +0 -177
- package/packages/cli/test/sync.test.ts +0 -1709
- package/packages/cli/test/tls-intercept.test.ts +0 -548
- package/packages/cli/test/upstream-visible.test.ts +0 -314
- package/packages/cli/test/vercel-sdk-e2e.test.ts +0 -105
- package/packages/cli/test/version.test.ts +0 -20
- package/packages/cli/tsconfig.json +0 -40
- package/packages/core/package.json +0 -26
- package/packages/core/src/blobs.ts +0 -109
- package/packages/core/src/fetch.ts +0 -48
- package/packages/core/src/graph.ts +0 -450
- package/packages/core/src/index.ts +0 -8
- package/packages/core/src/paths.ts +0 -180
- package/packages/core/src/private-files.ts +0 -394
- package/packages/core/src/reader.ts +0 -175
- package/packages/core/src/redaction.ts +0 -826
- package/packages/core/src/writer.ts +0 -467
- package/packages/core/test/blobs.test.ts +0 -170
- package/packages/core/test/capture-contract.test.ts +0 -179
- package/packages/core/test/data-uri-redaction.test.ts +0 -758
- package/packages/core/test/graph.test.ts +0 -520
- package/packages/core/test/integration.test.ts +0 -148
- package/packages/core/test/paths-permission-failure.test.ts +0 -53
- package/packages/core/test/paths.test.ts +0 -339
- package/packages/core/test/private-files-owner.test.ts +0 -77
- package/packages/core/test/private-files-scratch-race.test.ts +0 -62
- package/packages/core/test/private-files.test.ts +0 -251
- package/packages/core/test/reader.test.ts +0 -271
- package/packages/core/test/redaction.test.ts +0 -525
- package/packages/core/test/writer.test.ts +0 -531
- package/packages/core/tsconfig.json +0 -6
- package/packages/fs-capture/package.json +0 -25
- package/packages/fs-capture/src/capture.ts +0 -193
- package/packages/fs-capture/src/git.ts +0 -131
- package/packages/fs-capture/src/index.ts +0 -3
- package/packages/fs-capture/src/shadow.ts +0 -751
- package/packages/fs-capture/test/capture.test.ts +0 -241
- package/packages/fs-capture/test/git.test.ts +0 -118
- package/packages/fs-capture/test/helpers.ts +0 -28
- package/packages/fs-capture/test/shadow.test.ts +0 -1058
- package/packages/fs-capture/tsconfig.json +0 -6
- package/packages/mcp-shim/package.json +0 -26
- package/packages/mcp-shim/src/cli.ts +0 -372
- package/packages/mcp-shim/src/framing.ts +0 -106
- package/packages/mcp-shim/src/index.ts +0 -4
- package/packages/mcp-shim/src/mock.ts +0 -194
- package/packages/mcp-shim/src/shim.ts +0 -126
- package/packages/mcp-shim/test/cli.test.ts +0 -489
- package/packages/mcp-shim/test/framing.test.ts +0 -143
- package/packages/mcp-shim/test/mock.test.ts +0 -200
- package/packages/mcp-shim/test/shim.test.ts +0 -287
- package/packages/mcp-shim/tsconfig.json +0 -5
- package/packages/node-instrument/package.json +0 -23
- package/packages/node-instrument/src/capture.ts +0 -505
- package/packages/node-instrument/src/index.ts +0 -3
- package/packages/node-instrument/src/install.ts +0 -186
- package/packages/node-instrument/src/rewrite.ts +0 -66
- package/packages/node-instrument/test/capture.test.ts +0 -423
- package/packages/node-instrument/test/install.test.ts +0 -427
- package/packages/node-instrument/test/rewrite.test.ts +0 -85
- package/packages/node-instrument/tsconfig.json +0 -9
- package/packages/plugin-api/package.json +0 -22
- package/packages/plugin-api/src/canonical.ts +0 -73
- package/packages/plugin-api/src/index.ts +0 -2
- package/packages/plugin-api/src/plugins.ts +0 -265
- package/packages/plugin-api/test/canonical.test.ts +0 -58
- package/packages/plugin-api/tsconfig.json +0 -5
- package/packages/providers/package.json +0 -26
- package/packages/providers/src/index.ts +0 -34
- package/packages/providers/src/pricing.ts +0 -140
- package/packages/providers/src/translate/anthropic.ts +0 -620
- package/packages/providers/src/translate/openai-responses.ts +0 -638
- package/packages/providers/src/translate/openai.ts +0 -630
- package/packages/providers/src/translate/sse.ts +0 -99
- package/packages/providers/src/translate/util.ts +0 -111
- package/packages/providers/test/anthropic-translate.test.ts +0 -687
- package/packages/providers/test/openai-responses-translate.test.ts +0 -377
- package/packages/providers/test/openai-translate.test.ts +0 -884
- package/packages/providers/test/pricing.test.ts +0 -171
- package/packages/providers/tsconfig.json +0 -6
- package/packages/proxy/package.json +0 -28
- package/packages/proxy/src/ca.ts +0 -376
- package/packages/proxy/src/der.ts +0 -152
- package/packages/proxy/src/dialects.ts +0 -413
- package/packages/proxy/src/forward.ts +0 -64
- package/packages/proxy/src/index.ts +0 -8
- package/packages/proxy/src/intercept.ts +0 -1554
- package/packages/proxy/src/matching.ts +0 -1056
- package/packages/proxy/src/retrieval.ts +0 -290
- package/packages/proxy/src/server.ts +0 -2875
- package/packages/proxy/src/tls-hosts.ts +0 -205
- package/packages/proxy/test/beta-headers.test.ts +0 -39
- package/packages/proxy/test/ca.test.ts +0 -146
- package/packages/proxy/test/forward.test.ts +0 -306
- package/packages/proxy/test/hop-by-hop.test.ts +0 -118
- package/packages/proxy/test/image-matching.test.ts +0 -129
- package/packages/proxy/test/indexing-concurrency.test.ts +0 -224
- package/packages/proxy/test/lookahead.test.ts +0 -160
- package/packages/proxy/test/malformed-body.test.ts +0 -73
- package/packages/proxy/test/matching.test.ts +0 -822
- package/packages/proxy/test/passthrough.test.ts +0 -599
- package/packages/proxy/test/recorded-upstream.test.ts +0 -253
- package/packages/proxy/test/responses-dialect.test.ts +0 -239
- package/packages/proxy/test/retrieval.test.ts +0 -589
- package/packages/proxy/test/server.test.ts +0 -1281
- package/packages/proxy/test/tls-hosts.test.ts +0 -190
- package/packages/proxy/test/tls-intercept.test.ts +0 -1769
- package/packages/proxy/tsconfig.json +0 -22
- package/packages/schema/package.json +0 -28
- package/packages/schema/src/constants.ts +0 -73
- package/packages/schema/src/index.ts +0 -3
- package/packages/schema/src/types.ts +0 -103
- package/packages/schema/src/validate.ts +0 -60
- package/packages/schema/test/schema-parity.test.ts +0 -116
- package/packages/schema/tsconfig.json +0 -5
- package/packages/shell-shim/package.json +0 -26
- package/packages/shell-shim/src/index.ts +0 -3
- package/packages/shell-shim/src/install.ts +0 -406
- package/packages/shell-shim/src/resolve.ts +0 -98
- package/packages/shell-shim/src/runner-bin.ts +0 -4
- package/packages/shell-shim/src/runner.ts +0 -149
- package/packages/shell-shim/test/resolve.test.ts +0 -125
- package/packages/shell-shim/test/shim.test.ts +0 -548
- package/packages/shell-shim/test/transport-race.test.ts +0 -109
- package/packages/shell-shim/tsconfig.json +0 -13
- package/packages/viewer/package.json +0 -25
- package/packages/viewer/src/bundle.ts +0 -36
- package/packages/viewer/src/client/main.ts +0 -248
- package/packages/viewer/src/credit.ts +0 -24
- package/packages/viewer/src/css.ts +0 -409
- package/packages/viewer/src/export.ts +0 -38
- package/packages/viewer/src/html.ts +0 -356
- package/packages/viewer/src/index.ts +0 -16
- package/packages/viewer/src/render.ts +0 -791
- package/packages/viewer/src/serve.ts +0 -150
- package/packages/viewer/src/trace-dir.ts +0 -140
- package/packages/viewer/test/bundle.test.ts +0 -47
- package/packages/viewer/test/client.test.ts +0 -378
- package/packages/viewer/test/export.test.ts +0 -131
- package/packages/viewer/test/fixtures.ts +0 -69
- package/packages/viewer/test/html.test.ts +0 -453
- package/packages/viewer/test/playback.test.ts +0 -54
- package/packages/viewer/test/render.test.ts +0 -714
- package/packages/viewer/test/serve.test.ts +0 -125
- package/packages/viewer/tsconfig.json +0 -6
- package/prompt/AIDER/deepseek-v4-1-flash-system-prompt.md +0 -29
- package/prompt/CLAUDECODE/claude-fable-5-1-print-system-prompt.md +0 -127
- package/prompt/CLAUDECODE/claude-fable-5-1-system-prompt.md +0 -169
- package/prompt/CLAUDECODE/claude-opus-4-8-system-prompt.md +0 -131
- package/prompt/CLAUDECODE/claude-opus-5-system-prompt.md +0 -149
- package/prompt/CLINE/openai-gpt-4o-mini-system-prompt.md +0 -37
- package/prompt/CODEX/gpt-5-6-luna-system-prompt.md +0 -183
- package/prompt/CODEX/gpt-5-6-sol-system-prompt.md +0 -218
- package/prompt/CODEX/gpt-6-1-sol-system-prompt.md +0 -242
- package/prompt/CODEX/gpt-6-astra-system-prompt.md +0 -170
- package/prompt/CODEX/gpt-6-luna-system-prompt.md +0 -223
- package/prompt/CODEX/gpt-6-sol-system-prompt.md +0 -226
- package/prompt/CRUSH/deepseek-v4-1-flash-system-prompt.md +0 -472
- package/prompt/CURSOR/grok-4-5-high-system-prompt.md +0 -40
- package/prompt/DSH/deepseek-flash-system-prompt.md +0 -31
- package/prompt/GEMINICLI/gemini-3-5-flash-system-prompt.md +0 -168
- package/prompt/GOOSE/deepseek-v4-1-flash-system-prompt.md +0 -180
- package/prompt/HACKERAI/openai-gpt-4o-mini-system-prompt.md +0 -70
- package/prompt/HERMES/nemotron-3-5-lightning-free-system-prompt.md +0 -111
- package/prompt/KILOCODE/kilo-auto-free-system-prompt.md +0 -129
- package/prompt/MCODE/deepseek-deepseek-v4-flash-free-coding-system-prompt.md +0 -128
- package/prompt/MCODE/deepseek-deepseek-v4-flash-free-tui-system-prompt.md +0 -119
- package/prompt/MCODE/deepseek-deepseek-v4-flash-free-work-system-prompt.md +0 -140
- package/prompt/MIMOCODE/mimo-v2-5-pro-system-prompt.md +0 -411
- package/prompt/MIMOCODE/mimo-v2-5-system-prompt.md +0 -411
- package/prompt/MUSECODE/muse-spark-1-3-system-prompt.md +0 -78
- package/prompt/OPENCLAW/gpt-5-6-sol-system-prompt.md +0 -333
- package/prompt/OPENCODE/big-pickle-system-prompt.md +0 -114
- package/prompt/OPENCODE/gpt-5-6-sol-system-prompt.md +0 -126
- package/prompt/OPENCODE/ling-3-0-flash-fin-free-system-prompt.md +0 -114
- package/prompt/OPENCODE/mimo-v2-5-free-system-prompt.md +0 -114
- package/prompt/OPENCODE/muse-spark-1-2-contributor-free-system-prompt.md +0 -84
- package/prompt/OPENCODE/nemotron-3-5-lightning-free-system-prompt.md +0 -114
- package/prompt/OPENCODE/nemotron-3-ultra-free-system-prompt.md +0 -114
- package/prompt/PI/openai-gpt-4o-mini-system-prompt.md +0 -31
- package/prompt/QWENCODE/gpt-5-6-sol-system-prompt.md +0 -290
- package/prompt/ZCODE/glm-4-6-system-prompt.md +0 -91
- package/python/README.md +0 -132
- package/python/agenticreplay_trace/__init__.py +0 -58
- package/python/agenticreplay_trace/graph.py +0 -137
- package/python/agenticreplay_trace/models.py +0 -491
- package/python/agenticreplay_trace/py.typed +0 -0
- package/python/agenticreplay_trace/reader.py +0 -295
- package/python/conftest.py +0 -12
- package/python/examples/analyze.py +0 -114
- package/python/pyproject.toml +0 -45
- package/python/tests/conftest.py +0 -102
- package/python/tests/test_capture_contract.py +0 -24
- package/python/tests/test_conformance.py +0 -235
- package/python/tests/test_examples.py +0 -60
- package/python/tests/test_graph.py +0 -247
- package/python/tests/test_models.py +0 -342
- package/python/tests/test_reader.py +0 -423
- package/python-langgraph/README.md +0 -159
- package/python-langgraph/agenticreplay_langgraph/__init__.py +0 -21
- package/python-langgraph/agenticreplay_langgraph/handler.py +0 -317
- package/python-langgraph/agenticreplay_langgraph/hook.py +0 -168
- package/python-langgraph/pyproject.toml +0 -35
- package/python-langgraph/tests/test_handler.py +0 -370
- package/python-langgraph/tests/test_integration.py +0 -484
- package/python-openai-agents/README.md +0 -145
- package/python-openai-agents/agenticreplay_openai_agents/__init__.py +0 -11
- package/python-openai-agents/agenticreplay_openai_agents/processor.py +0 -331
- package/python-openai-agents/pyproject.toml +0 -34
- package/python-openai-agents/tests/test_processor.py +0 -457
- package/scripts/check-neutrality.mjs +0 -62
- package/scripts/codex-client-acceptance.mjs +0 -133
- package/scripts/conformance.mjs +0 -245
- package/scripts/fidelity.mjs +0 -170
- package/scripts/hermes-client-acceptance.mjs +0 -158
- package/scripts/host-client-acceptance.mjs +0 -732
- package/scripts/installed-smoke.mjs +0 -316
- package/scripts/publish-order.mjs +0 -96
- package/scripts/regenerate-quickstart.mjs +0 -79
- package/scripts/render-cards.mjs +0 -178
- package/scripts/render-demo.mjs +0 -139
- package/scripts/render-sync-card.mjs +0 -96
- package/scripts/set-version.mjs +0 -152
- package/scripts/set-version.test.ts +0 -220
- package/scripts/sync-server-json.mjs +0 -13
- package/scripts/update-opencode-api-bases.mjs +0 -29
- package/server.json +0 -28
- package/skills/agenticreplay-replay/SKILL.md +0 -211
- package/spec/agenticreplay-trace-v0.md +0 -223
- package/test/integrations/README.md +0 -133
- package/test/integrations/agents/ai_sdk_openai.mjs +0 -24
- package/test/integrations/agents/anthropic_sdk.py +0 -10
- package/test/integrations/agents/browser_use_agent.py +0 -24
- package/test/integrations/agents/crewai_agent.py +0 -44
- package/test/integrations/agents/crewai_model_names.py +0 -72
- package/test/integrations/agents/hardcoded_origin.mjs +0 -13
- package/test/integrations/agents/haystack_pipeline.py +0 -28
- package/test/integrations/agents/haystack_rag.py +0 -35
- package/test/integrations/agents/langgraph_agent.py +0 -54
- package/test/integrations/agents/langgraph_nodes.py +0 -62
- package/test/integrations/agents/litellm_agent.py +0 -11
- package/test/integrations/agents/llama_index_agent.py +0 -27
- package/test/integrations/agents/llama_index_model_names.py +0 -67
- package/test/integrations/agents/mastra_agent.mjs +0 -20
- package/test/integrations/agents/mcp_agent.py +0 -44
- package/test/integrations/agents/mcp_server.py +0 -20
- package/test/integrations/agents/openai_agents_handoff.py +0 -52
- package/test/integrations/agents/openai_agents_sdk.py +0 -29
- package/test/integrations/agents/openai_async.py +0 -17
- package/test/integrations/agents/openai_sdk.py +0 -10
- package/test/integrations/agents/openhands_agent.py +0 -34
- package/test/integrations/agents/rag_pipeline.py +0 -79
- package/test/integrations/agents/vision_agent.py +0 -63
- package/test/integrations/run.mjs +0 -719
- package/test/integrations/stub-origin.mjs +0 -229
- package/tsconfig.base.json +0 -20
- package/tsconfig.json +0 -41
- package/vitest.config.ts +0 -39
- package/vitest.setup.ts +0 -25
- /package/{packages → node_modules/@agenticreplay}/schema/schema/event.schema.json +0 -0
- /package/{packages → node_modules/@agenticreplay}/schema/schema/manifest.schema.json +0 -0
|
@@ -1,1769 +0,0 @@
|
|
|
1
|
-
import { X509Certificate } from 'node:crypto';
|
|
2
|
-
import { once } from 'node:events';
|
|
3
|
-
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
4
|
-
import { request as httpRequest, type IncomingMessage } from 'node:http';
|
|
5
|
-
import { createServer as createHttpsServer, type Server as HttpsServer } from 'node:https';
|
|
6
|
-
import type { AddressInfo, Socket } from 'node:net';
|
|
7
|
-
import { tmpdir } from 'node:os';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import {
|
|
10
|
-
connect as h2Connect,
|
|
11
|
-
createSecureServer as createHttp2Origin,
|
|
12
|
-
type Http2SecureServer,
|
|
13
|
-
type ClientHttp2Session,
|
|
14
|
-
} from 'node:http2';
|
|
15
|
-
import type { IncomingHttpHeaders } from 'node:http';
|
|
16
|
-
import { connect as tlsConnect } from 'node:tls';
|
|
17
|
-
import zlib from 'node:zlib';
|
|
18
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
19
|
-
import { RunCa } from '../src/ca.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* zstd landed in Node's `zlib` after the oldest runtime this CLI supports, so a named import can be
|
|
23
|
-
* `undefined` on supported runtimes and the test below would die on `zstdCompressSync is not a function` —
|
|
24
|
-
* a red build on every pull request, saying nothing about the change that triggered it.
|
|
25
|
-
*
|
|
26
|
-
* Looked up dynamically, the same way `decodeBody` looks up the other half of the pair, so
|
|
27
|
-
* the module still loads. Skipped rather than deleted: the behaviour is real on the runtimes that
|
|
28
|
-
* have zstd, and a skipped test names the runtime that is missing something where a deleted one
|
|
29
|
-
* would just be gone.
|
|
30
|
-
*/
|
|
31
|
-
const zstdCompressSync = (zlib as typeof zlib & { zstdCompressSync?: (input: Buffer) => Buffer })
|
|
32
|
-
.zstdCompressSync;
|
|
33
|
-
import { decodeBody } from '../src/intercept.js';
|
|
34
|
-
import {
|
|
35
|
-
createProxy,
|
|
36
|
-
type NetExchange,
|
|
37
|
-
type ProxyHandle,
|
|
38
|
-
type TunnelRecord,
|
|
39
|
-
} from '../src/server.js';
|
|
40
|
-
import type { RecordedExchange } from '../src/server.js';
|
|
41
|
-
import { defaultDialects } from '../src/server.js';
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The interception itself, driven the way a real agent drives it: an HTTP `CONNECT` to the proxy,
|
|
45
|
-
* a TLS handshake on the tunnel, and an HTTP request inside it.
|
|
46
|
-
*
|
|
47
|
-
* Two origins run throughout — one the run is allowed to decrypt, one it is not — and both are
|
|
48
|
-
* real HTTPS servers with their own certificates. That is what makes the negative case meaningful:
|
|
49
|
-
* the un-allowlisted origin is reached with *its own* certificate, over a connection agenticreplay could
|
|
50
|
-
* not read even if it wanted to.
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
/** Where the client is pointed and what it is willing to trust. */
|
|
54
|
-
interface ProxiedRequest {
|
|
55
|
-
proxyPort: number;
|
|
56
|
-
host: string;
|
|
57
|
-
port: number;
|
|
58
|
-
trust: string[];
|
|
59
|
-
method?: string;
|
|
60
|
-
path?: string;
|
|
61
|
-
body?: string | Buffer;
|
|
62
|
-
headers?: Record<string, string>;
|
|
63
|
-
onFirstChunk?: (chunk: string) => void;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface ProxiedResponse {
|
|
67
|
-
status: number;
|
|
68
|
-
body: string;
|
|
69
|
-
/** Who signed the certificate the client actually saw. The tell for "was this decrypted?". */
|
|
70
|
-
peerIssuer: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** CONNECT, then TLS over the tunnel, then one HTTP request — a proxy-aware client in 30 lines. */
|
|
74
|
-
/**
|
|
75
|
-
* A client that stops reading before the response is over.
|
|
76
|
-
*
|
|
77
|
-
* `through` resolves on `end`, which is the one thing this case never reaches. A harness reading a
|
|
78
|
-
* streaming reply only until it has its answer -- and one that gives up before the origin answers
|
|
79
|
-
* at all -- both leave the exchange half-finished, and half-finished is what has to be recorded.
|
|
80
|
-
* Returns whatever arrived before the client walked away.
|
|
81
|
-
*/
|
|
82
|
-
async function abandoned(
|
|
83
|
-
opts: ProxiedRequest & { leaveAfter: 'first-chunk' | 'request' },
|
|
84
|
-
): Promise<string> {
|
|
85
|
-
const target = `${opts.host}:${opts.port}`;
|
|
86
|
-
const tunnel = httpRequest({
|
|
87
|
-
host: '127.0.0.1',
|
|
88
|
-
port: opts.proxyPort,
|
|
89
|
-
method: 'CONNECT',
|
|
90
|
-
path: target,
|
|
91
|
-
headers: { host: target },
|
|
92
|
-
});
|
|
93
|
-
tunnel.end();
|
|
94
|
-
|
|
95
|
-
const [res, socket, head] = (await once(tunnel, 'connect')) as [IncomingMessage, Socket, Buffer];
|
|
96
|
-
if (res.statusCode !== 200) {
|
|
97
|
-
socket.destroy();
|
|
98
|
-
throw new Error(`CONNECT refused: ${res.statusCode}`);
|
|
99
|
-
}
|
|
100
|
-
if (head.length > 0) socket.unshift(head);
|
|
101
|
-
|
|
102
|
-
const secure = tlsConnect({ socket, ca: opts.trust, host: opts.host, port: opts.port });
|
|
103
|
-
await once(secure, 'secureConnect');
|
|
104
|
-
|
|
105
|
-
return await new Promise<string>((resolve) => {
|
|
106
|
-
let seen = '';
|
|
107
|
-
const req = httpRequest(
|
|
108
|
-
{
|
|
109
|
-
createConnection: () => secure,
|
|
110
|
-
host: opts.host,
|
|
111
|
-
port: opts.port,
|
|
112
|
-
method: opts.method ?? 'GET',
|
|
113
|
-
path: opts.path ?? '/',
|
|
114
|
-
headers: { host: target, ...opts.headers },
|
|
115
|
-
},
|
|
116
|
-
(response) => {
|
|
117
|
-
response.setEncoding('utf8');
|
|
118
|
-
response.on('data', (chunk: string) => {
|
|
119
|
-
seen += chunk;
|
|
120
|
-
if (opts.leaveAfter === 'first-chunk') {
|
|
121
|
-
secure.destroy();
|
|
122
|
-
resolve(seen);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
},
|
|
126
|
-
);
|
|
127
|
-
// No `error` rejection: tearing the socket down is the behaviour under test, so the errors it
|
|
128
|
-
// raises on this side are the expected consequence rather than a failure.
|
|
129
|
-
req.on('error', () => undefined);
|
|
130
|
-
if (opts.body !== undefined) req.write(opts.body);
|
|
131
|
-
req.end();
|
|
132
|
-
if (opts.leaveAfter === 'request') {
|
|
133
|
-
// Gone while the origin is still thinking. One beat first, so the request is on the wire
|
|
134
|
-
// before the socket goes -- that is what makes the recorded request body non-empty.
|
|
135
|
-
setTimeout(() => {
|
|
136
|
-
secure.destroy();
|
|
137
|
-
resolve(seen);
|
|
138
|
-
}, 150);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** Long enough for the proxy to notice the client left and file what it had. */
|
|
144
|
-
const settle = (): Promise<void> => new Promise((r) => setTimeout(r, 300));
|
|
145
|
-
|
|
146
|
-
async function through(opts: ProxiedRequest): Promise<ProxiedResponse> {
|
|
147
|
-
const target = `${opts.host}:${opts.port}`;
|
|
148
|
-
const tunnel = httpRequest({
|
|
149
|
-
host: '127.0.0.1',
|
|
150
|
-
port: opts.proxyPort,
|
|
151
|
-
method: 'CONNECT',
|
|
152
|
-
path: target,
|
|
153
|
-
headers: { host: target },
|
|
154
|
-
});
|
|
155
|
-
tunnel.end();
|
|
156
|
-
|
|
157
|
-
const [res, socket, head] = (await once(tunnel, 'connect')) as [IncomingMessage, Socket, Buffer];
|
|
158
|
-
if (res.statusCode !== 200) {
|
|
159
|
-
socket.destroy();
|
|
160
|
-
throw new Error(`CONNECT refused: ${res.statusCode}`);
|
|
161
|
-
}
|
|
162
|
-
if (head.length > 0) socket.unshift(head);
|
|
163
|
-
|
|
164
|
-
const secure = tlsConnect({ socket, ca: opts.trust, host: opts.host, port: opts.port });
|
|
165
|
-
try {
|
|
166
|
-
await once(secure, 'secureConnect');
|
|
167
|
-
} catch (err) {
|
|
168
|
-
secure.destroy();
|
|
169
|
-
throw err;
|
|
170
|
-
}
|
|
171
|
-
if (!secure.authorized) {
|
|
172
|
-
const reason = secure.authorizationError;
|
|
173
|
-
secure.destroy();
|
|
174
|
-
throw reason ?? new Error('unauthorized');
|
|
175
|
-
}
|
|
176
|
-
const peerIssuer = String(secure.getPeerCertificate().issuer.CN ?? '');
|
|
177
|
-
|
|
178
|
-
return await new Promise<ProxiedResponse>((resolve, reject) => {
|
|
179
|
-
const req = httpRequest(
|
|
180
|
-
{
|
|
181
|
-
createConnection: () => secure,
|
|
182
|
-
host: opts.host,
|
|
183
|
-
port: opts.port,
|
|
184
|
-
method: opts.method ?? 'GET',
|
|
185
|
-
path: opts.path ?? '/',
|
|
186
|
-
headers: { host: target, ...opts.headers },
|
|
187
|
-
},
|
|
188
|
-
(response) => {
|
|
189
|
-
let body = '';
|
|
190
|
-
let first = true;
|
|
191
|
-
response.setEncoding('utf8');
|
|
192
|
-
response.on('data', (chunk: string) => {
|
|
193
|
-
body += chunk;
|
|
194
|
-
if (first) {
|
|
195
|
-
first = false;
|
|
196
|
-
opts.onFirstChunk?.(chunk);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
response.on('end', () => {
|
|
200
|
-
secure.destroy();
|
|
201
|
-
resolve({ status: response.statusCode ?? 0, body, peerIssuer });
|
|
202
|
-
});
|
|
203
|
-
},
|
|
204
|
-
);
|
|
205
|
-
req.on('error', (err) => {
|
|
206
|
-
secure.destroy();
|
|
207
|
-
reject(err);
|
|
208
|
-
});
|
|
209
|
-
if (opts.body !== undefined) req.write(opts.body);
|
|
210
|
-
req.end();
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** The CN a client sees as the issuer of whatever certificate it was handed. */
|
|
215
|
-
function commonName(certPem: string): string {
|
|
216
|
-
return /CN=(.*)/.exec(new X509Certificate(certPem).subject)?.[1] ?? '';
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* The same idea as `startOrigin`, over HTTP/2.
|
|
221
|
-
*
|
|
222
|
-
* A separate helper rather than an option on the first one, because an h2 origin answers on
|
|
223
|
-
* `stream` rather than with a request/response pair, and because the interesting cases here are
|
|
224
|
-
* about *when* it answers: `delayMs` lets the origin reply after the client has already gone,
|
|
225
|
-
* which is the shape that used to take the proxy down.
|
|
226
|
-
*/
|
|
227
|
-
async function startH2Origin(
|
|
228
|
-
ca: RunCa,
|
|
229
|
-
opts: {
|
|
230
|
-
delayMs?: number;
|
|
231
|
-
onStream?: (headers: IncomingHttpHeaders) => void;
|
|
232
|
-
/** What to answer with, for a test that needs a body a dialect can read. */
|
|
233
|
-
answer?: () => { contentType: string; body: string | Buffer; encoding?: string };
|
|
234
|
-
} = {},
|
|
235
|
-
): Promise<{ port: number; hits: number; close: () => Promise<void> }> {
|
|
236
|
-
const issued = ca.issue('127.0.0.1');
|
|
237
|
-
const server: Http2SecureServer = createHttp2Origin({
|
|
238
|
-
key: issued.keyPem,
|
|
239
|
-
cert: issued.certPem,
|
|
240
|
-
});
|
|
241
|
-
const state = { hits: 0 };
|
|
242
|
-
// Tracked so `close` can force them down. `server.close()` waits for open sessions, and the
|
|
243
|
-
// proxy holds its upstream h2 session in a cache until the whole handle is closed -- so an
|
|
244
|
-
// origin waiting politely deadlocks the teardown.
|
|
245
|
-
const sessions = new Set<{ destroy: () => void }>();
|
|
246
|
-
server.on('session', (session) => {
|
|
247
|
-
sessions.add(session);
|
|
248
|
-
session.on('close', () => sessions.delete(session));
|
|
249
|
-
});
|
|
250
|
-
server.on('stream', (stream, headers) => {
|
|
251
|
-
state.hits += 1;
|
|
252
|
-
opts.onStream?.(headers);
|
|
253
|
-
stream.on('error', () => undefined);
|
|
254
|
-
stream.on('data', () => undefined);
|
|
255
|
-
const answer = (): void => {
|
|
256
|
-
if (stream.destroyed) return;
|
|
257
|
-
const chosen = opts.answer?.() ?? { contentType: 'text/plain', body: 'from-origin' };
|
|
258
|
-
stream.respond({
|
|
259
|
-
':status': 200,
|
|
260
|
-
'content-type': chosen.contentType,
|
|
261
|
-
...(chosen.encoding === undefined ? {} : { 'content-encoding': chosen.encoding }),
|
|
262
|
-
});
|
|
263
|
-
stream.end(chosen.body);
|
|
264
|
-
};
|
|
265
|
-
stream.on('end', () => {
|
|
266
|
-
if (opts.delayMs) setTimeout(answer, opts.delayMs);
|
|
267
|
-
else answer();
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
271
|
-
return {
|
|
272
|
-
port: (server.address() as AddressInfo).port,
|
|
273
|
-
get hits() {
|
|
274
|
-
return state.hits;
|
|
275
|
-
},
|
|
276
|
-
close: () =>
|
|
277
|
-
new Promise<void>((resolve) => {
|
|
278
|
-
for (const session of sessions) session.destroy();
|
|
279
|
-
sessions.clear();
|
|
280
|
-
server.close(() => resolve());
|
|
281
|
-
}),
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/** An h2 session to `host:port` through the proxy's CONNECT tunnel. */
|
|
286
|
-
async function h2Through(opts: {
|
|
287
|
-
proxyPort: number;
|
|
288
|
-
host: string;
|
|
289
|
-
port: number;
|
|
290
|
-
trust: string[];
|
|
291
|
-
}): Promise<ClientHttp2Session> {
|
|
292
|
-
const target = `${opts.host}:${opts.port}`;
|
|
293
|
-
const tunnel = httpRequest({
|
|
294
|
-
host: '127.0.0.1',
|
|
295
|
-
port: opts.proxyPort,
|
|
296
|
-
method: 'CONNECT',
|
|
297
|
-
path: target,
|
|
298
|
-
headers: { host: target },
|
|
299
|
-
});
|
|
300
|
-
tunnel.end();
|
|
301
|
-
const [res, socket, head] = (await once(tunnel, 'connect')) as [IncomingMessage, Socket, Buffer];
|
|
302
|
-
if (res.statusCode !== 200) {
|
|
303
|
-
socket.destroy();
|
|
304
|
-
throw new Error(`CONNECT refused: ${res.statusCode}`);
|
|
305
|
-
}
|
|
306
|
-
if (head.length > 0) socket.unshift(head);
|
|
307
|
-
// The TLS handshake is done here rather than left to `http2.connect`: given a
|
|
308
|
-
// `createConnection`, http2 uses that stream as the transport as-is and adds no encryption, so
|
|
309
|
-
// an unwrapped socket would speak cleartext h2 frames at a TLS server.
|
|
310
|
-
const secure = tlsConnect({
|
|
311
|
-
socket,
|
|
312
|
-
ca: opts.trust,
|
|
313
|
-
host: opts.host,
|
|
314
|
-
port: opts.port,
|
|
315
|
-
ALPNProtocols: ['h2'],
|
|
316
|
-
});
|
|
317
|
-
await once(secure, 'secureConnect');
|
|
318
|
-
const session = h2Connect(`https://${target}`, { createConnection: () => secure });
|
|
319
|
-
session.on('error', () => undefined);
|
|
320
|
-
await once(session, 'connect');
|
|
321
|
-
return session;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
type OriginHandler = Parameters<typeof createHttpsServer>[1];
|
|
325
|
-
|
|
326
|
-
async function startOrigin(
|
|
327
|
-
ca: RunCa,
|
|
328
|
-
handler: OriginHandler,
|
|
329
|
-
): Promise<{
|
|
330
|
-
port: number;
|
|
331
|
-
close: () => Promise<void>;
|
|
332
|
-
}> {
|
|
333
|
-
const issued = ca.issue('127.0.0.1');
|
|
334
|
-
const server: HttpsServer = createHttpsServer(
|
|
335
|
-
{ key: issued.keyPem, cert: issued.certPem },
|
|
336
|
-
handler,
|
|
337
|
-
);
|
|
338
|
-
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
339
|
-
return {
|
|
340
|
-
port: (server.address() as AddressInfo).port,
|
|
341
|
-
close: () => new Promise<void>((resolve) => void server.close(() => resolve())),
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* A body agenticreplay cannot decode is a body no dialect can read, and the run says only that nothing
|
|
347
|
-
* looked like a model call. Sending a gzipped request through a real intercepted host recorded
|
|
348
|
-
* `agenticreplay-base64:H4sIA...` and exactly that message, so these three are worth pinning: they need no
|
|
349
|
-
* runtime guard, unlike zstd, and gzip is the encoding an SDK is most likely to turn on.
|
|
350
|
-
*/
|
|
351
|
-
describe('decodeBody', () => {
|
|
352
|
-
const payload = JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hi' }] });
|
|
353
|
-
|
|
354
|
-
it('reads a gzipped body back as the JSON that went in', () => {
|
|
355
|
-
expect(decodeBody(zlib.gzipSync(Buffer.from(payload)), 'gzip')).toBe(payload);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
it('reads deflate and brotli too', () => {
|
|
359
|
-
expect(decodeBody(zlib.deflateSync(Buffer.from(payload)), 'deflate')).toBe(payload);
|
|
360
|
-
expect(decodeBody(zlib.brotliCompressSync(Buffer.from(payload)), 'br')).toBe(payload);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it('decodes layered encodings in reverse wire order', () => {
|
|
364
|
-
expect(decodeBody(zlib.gzipSync(Buffer.from(payload)), 'GZIP, identity')).toBe(payload);
|
|
365
|
-
const layered = zlib.deflateSync(zlib.gzipSync(Buffer.from(payload)));
|
|
366
|
-
expect(decodeBody(layered, 'gzip, deflate')).toBe(payload);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
it('rejects decompression that exceeds the configured output bound', () => {
|
|
370
|
-
expect(() => decodeBody(zlib.gzipSync(Buffer.from('x'.repeat(1024))), 'gzip', 32)).toThrow(
|
|
371
|
-
/larger than|capture limit/,
|
|
372
|
-
);
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it('leaves an unencoded body alone', () => {
|
|
376
|
-
expect(decodeBody(Buffer.from(payload), undefined)).toBe(payload);
|
|
377
|
-
expect(decodeBody(Buffer.from(payload), 'identity')).toBe(payload);
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
describe('TLS interception', () => {
|
|
382
|
-
let runDir: string;
|
|
383
|
-
let originDir: string;
|
|
384
|
-
/** The run's own CA — the one an intercepted client has to trust. */
|
|
385
|
-
let runCa: RunCa;
|
|
386
|
-
/** A stand-in for the public web's CAs, so the origins have credible certificates of their own. */
|
|
387
|
-
let originCa: RunCa;
|
|
388
|
-
let model: Awaited<ReturnType<typeof startOrigin>>;
|
|
389
|
-
let bank: Awaited<ReturnType<typeof startOrigin>>;
|
|
390
|
-
let proxy: ProxyHandle | undefined;
|
|
391
|
-
let netExchanges: NetExchange[];
|
|
392
|
-
let tunnels: TunnelRecord[];
|
|
393
|
-
let modelExchanges: RecordedExchange[];
|
|
394
|
-
let release: (() => void) | undefined;
|
|
395
|
-
/** What the origin actually received, so "forwarded" can be asserted without echoing it back. */
|
|
396
|
-
let originSawAuth: string | undefined;
|
|
397
|
-
/** The same, for the headers a provider attributes traffic by. */
|
|
398
|
-
let originSawAttribution: Record<string, string | undefined>;
|
|
399
|
-
/** Body of a `/v1/chat/completions` the origin received, for `--model` substitution. */
|
|
400
|
-
let originSawChatBody: string | undefined;
|
|
401
|
-
|
|
402
|
-
beforeEach(async () => {
|
|
403
|
-
runDir = await mkdtemp(join(tmpdir(), 'agenticreplay-mitm-run-'));
|
|
404
|
-
originDir = await mkdtemp(join(tmpdir(), 'agenticreplay-mitm-origin-'));
|
|
405
|
-
runCa = await RunCa.create({ runDir });
|
|
406
|
-
originCa = await RunCa.create({ runDir: originDir });
|
|
407
|
-
netExchanges = [];
|
|
408
|
-
tunnels = [];
|
|
409
|
-
modelExchanges = [];
|
|
410
|
-
originSawAuth = undefined;
|
|
411
|
-
originSawAttribution = {};
|
|
412
|
-
originSawChatBody = undefined;
|
|
413
|
-
|
|
414
|
-
model = await startOrigin(originCa, (req, res) => {
|
|
415
|
-
const chunks: Buffer[] = [];
|
|
416
|
-
req.on('data', (c: Buffer) => void chunks.push(c));
|
|
417
|
-
req.on('end', () => {
|
|
418
|
-
const body = Buffer.concat(chunks).toString('utf8');
|
|
419
|
-
if (req.url === '/die-mid-stream') {
|
|
420
|
-
// Headers, one chunk, then the connection goes without an end. This is a crashing
|
|
421
|
-
// origin or a network break, not a client that left -- and the difference is the whole
|
|
422
|
-
// point of the test below.
|
|
423
|
-
res.writeHead(200, { 'content-type': 'text/event-stream' });
|
|
424
|
-
res.write('data: first\n\n');
|
|
425
|
-
setTimeout(() => res.socket?.destroy(), 30);
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
if (req.url === '/not-modified') {
|
|
429
|
-
// What a cache revalidation answers, and RFC 7232 asks for the header fields a 200
|
|
430
|
-
// would have carried -- so `content-encoding` is here on a response with no body.
|
|
431
|
-
res.writeHead(304, { 'content-encoding': 'gzip', etag: '"abc"' });
|
|
432
|
-
res.end();
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if (req.url === '/repeated') {
|
|
436
|
-
res.writeHead(200, {
|
|
437
|
-
'content-type': 'application/json',
|
|
438
|
-
'x-repeated': ['one', 'two'],
|
|
439
|
-
'set-cookie': ['session=secret-a', 'session=secret-b'],
|
|
440
|
-
});
|
|
441
|
-
res.end('{"ok":true}');
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
if (req.url === '/stream-gzip') {
|
|
445
|
-
// A compressed stream, handed over in two writes so a client can leave mid-member. What
|
|
446
|
-
// agenticreplay keeps is then a prefix of a deflate stream, which cannot be inflated.
|
|
447
|
-
const whole = zlib.gzipSync(Buffer.from('data: first\n\ndata: second\n\n'));
|
|
448
|
-
res.writeHead(200, {
|
|
449
|
-
'content-type': 'text/event-stream',
|
|
450
|
-
'content-encoding': 'gzip',
|
|
451
|
-
});
|
|
452
|
-
res.write(whole.subarray(0, Math.floor(whole.length / 2)));
|
|
453
|
-
void new Promise<void>((resolve) => {
|
|
454
|
-
release = resolve;
|
|
455
|
-
}).then(() => {
|
|
456
|
-
res.write(whole.subarray(Math.floor(whole.length / 2)));
|
|
457
|
-
res.end();
|
|
458
|
-
});
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
if (req.headers['x-test-gzip'] !== undefined) {
|
|
462
|
-
// Compressed regardless of `accept-encoding`, which the interceptor strips from every
|
|
463
|
-
// request precisely so an origin that honours it answers in plaintext. This is the
|
|
464
|
-
// origin that does not: a gateway with compression forced on, or an edge handing back a
|
|
465
|
-
// pre-compressed error page.
|
|
466
|
-
const payload = JSON.stringify({
|
|
467
|
-
id: 'chatcmpl-1',
|
|
468
|
-
object: 'chat.completion',
|
|
469
|
-
model: 'gpt-5.2',
|
|
470
|
-
choices: [
|
|
471
|
-
{ index: 0, message: { role: 'assistant', content: 'hi' }, finish_reason: 'stop' },
|
|
472
|
-
],
|
|
473
|
-
usage: { prompt_tokens: 3, completion_tokens: 1, total_tokens: 4 },
|
|
474
|
-
});
|
|
475
|
-
// `lying` claims the encoding without applying it, which is what a gateway in front of
|
|
476
|
-
// an already-decompressing cache produces.
|
|
477
|
-
const out =
|
|
478
|
-
req.headers['x-test-gzip'] === 'lying'
|
|
479
|
-
? Buffer.from(payload)
|
|
480
|
-
: zlib.gzipSync(Buffer.from(payload));
|
|
481
|
-
res.writeHead(200, {
|
|
482
|
-
'content-type': 'application/json',
|
|
483
|
-
'content-encoding': 'gzip',
|
|
484
|
-
'content-length': String(out.length),
|
|
485
|
-
});
|
|
486
|
-
res.end(out);
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
if (req.url === '/stream') {
|
|
490
|
-
res.writeHead(200, { 'content-type': 'text/event-stream' });
|
|
491
|
-
res.write('data: first\n\n');
|
|
492
|
-
// Held until the client confirms it saw the first chunk. A proxy that buffered the
|
|
493
|
-
// whole response before forwarding a byte would deadlock here rather than pass.
|
|
494
|
-
void new Promise<void>((resolve) => {
|
|
495
|
-
release = resolve;
|
|
496
|
-
}).then(() => {
|
|
497
|
-
res.write('data: second\n\n');
|
|
498
|
-
res.end();
|
|
499
|
-
});
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
if (req.url === '/v1/chat/completions' && req.headers['x-test-hold'] !== undefined) {
|
|
503
|
-
// Held before a single response header is written, which is the state a client that
|
|
504
|
-
// gives up early leaves the exchange in: a request agenticreplay decrypted and a response that
|
|
505
|
-
// never began. Released in `afterEach` along with `/stream`.
|
|
506
|
-
void new Promise<void>((resolve) => {
|
|
507
|
-
release = resolve;
|
|
508
|
-
}).then(() => {
|
|
509
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
510
|
-
res.end('{}');
|
|
511
|
-
});
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
if (req.url === '/v1/chat/completions') {
|
|
515
|
-
originSawChatBody = body;
|
|
516
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
517
|
-
res.end(
|
|
518
|
-
JSON.stringify({
|
|
519
|
-
id: 'chatcmpl-1',
|
|
520
|
-
object: 'chat.completion',
|
|
521
|
-
model: 'gpt-5.2',
|
|
522
|
-
choices: [
|
|
523
|
-
{ index: 0, message: { role: 'assistant', content: 'hi' }, finish_reason: 'stop' },
|
|
524
|
-
],
|
|
525
|
-
usage: { prompt_tokens: 3, completion_tokens: 1, total_tokens: 4 },
|
|
526
|
-
}),
|
|
527
|
-
);
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
originSawAuth = req.headers.authorization;
|
|
531
|
-
originSawAttribution = {
|
|
532
|
-
'http-referer': req.headers['http-referer'] as string | undefined,
|
|
533
|
-
'x-title': req.headers['x-title'] as string | undefined,
|
|
534
|
-
};
|
|
535
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
536
|
-
res.end(JSON.stringify({ saw: body, path: req.url }));
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
bank = await startOrigin(originCa, (_req, res) => {
|
|
541
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
542
|
-
res.end(JSON.stringify({ balance: 'SUPER-SECRET-BALANCE-42' }));
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
afterEach(async () => {
|
|
547
|
-
release?.();
|
|
548
|
-
await proxy?.close();
|
|
549
|
-
proxy = undefined;
|
|
550
|
-
await model.close();
|
|
551
|
-
await bank.close();
|
|
552
|
-
await runCa.dispose();
|
|
553
|
-
await originCa.dispose();
|
|
554
|
-
await rm(runDir, { recursive: true, force: true });
|
|
555
|
-
await rm(originDir, { recursive: true, force: true });
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
async function startProxy(hosts: string[]): Promise<ProxyHandle> {
|
|
559
|
-
proxy = await createProxy({
|
|
560
|
-
mode: 'record',
|
|
561
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
562
|
-
tls: {
|
|
563
|
-
ca: runCa,
|
|
564
|
-
hosts,
|
|
565
|
-
// The origins here are signed by a CA no machine trusts, exactly as a corporate
|
|
566
|
-
// TLS-inspecting middlebox would be. Verification of the origin stays on either way.
|
|
567
|
-
trustedOriginCerts: [originCa.certPem],
|
|
568
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
569
|
-
onTunnel: (t) => void tunnels.push(t),
|
|
570
|
-
},
|
|
571
|
-
});
|
|
572
|
-
return proxy;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
it.each([
|
|
576
|
-
{
|
|
577
|
-
path: '/api/v2/chat/messages',
|
|
578
|
-
body: { model: 'gpt-5.2', messages: [{ role: 'user', content: 'hello' }] },
|
|
579
|
-
},
|
|
580
|
-
{ path: '/v3/conversations/messages', body: { text: 'hello', channel: 'fixture' } },
|
|
581
|
-
])('keeps intercepted $path traffic opaque', async ({ path, body }) => {
|
|
582
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
583
|
-
const rawBody = JSON.stringify(body);
|
|
584
|
-
const response = await through({
|
|
585
|
-
proxyPort: handle.port,
|
|
586
|
-
host: '127.0.0.1',
|
|
587
|
-
port: model.port,
|
|
588
|
-
trust: [runCa.certPem],
|
|
589
|
-
method: 'POST',
|
|
590
|
-
path,
|
|
591
|
-
body: rawBody,
|
|
592
|
-
headers: { 'content-type': 'application/json' },
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
expect(response.status).toBe(200);
|
|
596
|
-
expect(JSON.parse(response.body)).toEqual({ saw: rawBody, path });
|
|
597
|
-
expect(modelExchanges).toHaveLength(0);
|
|
598
|
-
expect(handle.exchanges()).toHaveLength(0);
|
|
599
|
-
expect(netExchanges).toHaveLength(1);
|
|
600
|
-
expect(netExchanges[0]).toMatchObject({ path, requestBody: rawBody, status: 200 });
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
it('marks an over-limit intercepted body incomplete while preserving the wire byte count', async () => {
|
|
604
|
-
const handle = await (async () => {
|
|
605
|
-
proxy = await createProxy({
|
|
606
|
-
mode: 'record',
|
|
607
|
-
maxCapturedBytes: 32,
|
|
608
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
609
|
-
tls: {
|
|
610
|
-
ca: runCa,
|
|
611
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
612
|
-
trustedOriginCerts: [originCa.certPem],
|
|
613
|
-
maxCapturedBytes: 32,
|
|
614
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
615
|
-
},
|
|
616
|
-
});
|
|
617
|
-
return proxy;
|
|
618
|
-
})();
|
|
619
|
-
const body = JSON.stringify({ unknown: 'x'.repeat(512) });
|
|
620
|
-
const response = await through({
|
|
621
|
-
proxyPort: handle.port,
|
|
622
|
-
host: '127.0.0.1',
|
|
623
|
-
port: model.port,
|
|
624
|
-
trust: [runCa.certPem],
|
|
625
|
-
method: 'POST',
|
|
626
|
-
path: '/api/v2/chat/messages',
|
|
627
|
-
body,
|
|
628
|
-
headers: { 'content-type': 'application/json' },
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
expect(response.status).toBe(200);
|
|
632
|
-
expect(netExchanges).toHaveLength(1);
|
|
633
|
-
expect(netExchanges[0]).toMatchObject({
|
|
634
|
-
requestBytes: Buffer.byteLength(body),
|
|
635
|
-
requestTruncated: true,
|
|
636
|
-
responseTruncated: true,
|
|
637
|
-
responseComplete: false,
|
|
638
|
-
});
|
|
639
|
-
expect(netExchanges[0]!.requestBody.length).toBeLessThan(body.length);
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
it('preserves repeated nonsecret response headers and excludes cookies', async () => {
|
|
643
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
644
|
-
const response = await through({
|
|
645
|
-
proxyPort: handle.port,
|
|
646
|
-
host: '127.0.0.1',
|
|
647
|
-
port: model.port,
|
|
648
|
-
trust: [runCa.certPem],
|
|
649
|
-
method: 'POST',
|
|
650
|
-
path: '/repeated',
|
|
651
|
-
body: '{}',
|
|
652
|
-
headers: { 'content-type': 'application/json' },
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
expect(response.status).toBe(200);
|
|
656
|
-
expect(netExchanges[0]!.responseHeaders['x-repeated']).toEqual(['one', 'two']);
|
|
657
|
-
expect(netExchanges[0]!.responseHeaders['set-cookie']).toBeUndefined();
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* HTTP/2, which reaches a different forwarder inside the interceptor.
|
|
662
|
-
*
|
|
663
|
-
* These exist because the h2 path was added without them and three failures followed from that:
|
|
664
|
-
* a replay that went live, a late origin response that killed the process, and an undecodable
|
|
665
|
-
* body that did the same. Each test below is one of those.
|
|
666
|
-
*/
|
|
667
|
-
describe('over HTTP/2', () => {
|
|
668
|
-
let h2Origin: Awaited<ReturnType<typeof startH2Origin>>;
|
|
669
|
-
|
|
670
|
-
afterEach(async () => {
|
|
671
|
-
await h2Origin?.close();
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
/** `createProxy` with a replay hook, which is what makes the origin off-limits. */
|
|
675
|
-
async function startReplayProxy(
|
|
676
|
-
hosts: string[],
|
|
677
|
-
reply: (path: string) => { status: number; headers?: Record<string, string>; body: string },
|
|
678
|
-
): Promise<ProxyHandle> {
|
|
679
|
-
proxy = await createProxy({
|
|
680
|
-
mode: 'record',
|
|
681
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
682
|
-
tls: {
|
|
683
|
-
ca: runCa,
|
|
684
|
-
hosts,
|
|
685
|
-
trustedOriginCerts: [originCa.certPem],
|
|
686
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
687
|
-
onRequest: async (req) => reply(req.path),
|
|
688
|
-
},
|
|
689
|
-
});
|
|
690
|
-
return proxy;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
it('decodes a compressed h2 response too, and stops claiming the encoding', async () => {
|
|
694
|
-
// The h2 forwarder builds its own header map and files its own exchange, so the property
|
|
695
|
-
// holds only where it is pinned. Asked on a path no dialect claims, because that is the
|
|
696
|
-
// exchange that keeps response headers to check.
|
|
697
|
-
h2Origin = await startH2Origin(originCa, {
|
|
698
|
-
answer: () => ({
|
|
699
|
-
contentType: 'application/json',
|
|
700
|
-
encoding: 'gzip',
|
|
701
|
-
body: zlib.gzipSync(Buffer.from('{"answer":"from the origin"}')),
|
|
702
|
-
}),
|
|
703
|
-
});
|
|
704
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
705
|
-
|
|
706
|
-
const session = await h2Through({
|
|
707
|
-
proxyPort: handle.port,
|
|
708
|
-
host: '127.0.0.1',
|
|
709
|
-
port: h2Origin.port,
|
|
710
|
-
trust: [runCa.certPem],
|
|
711
|
-
});
|
|
712
|
-
const request = session.request({ ':method': 'POST', ':path': '/not-a-model-endpoint' });
|
|
713
|
-
request.setEncoding('utf8');
|
|
714
|
-
request.on('data', () => undefined);
|
|
715
|
-
request.end('{}');
|
|
716
|
-
await once(request, 'close');
|
|
717
|
-
session.destroy();
|
|
718
|
-
|
|
719
|
-
expect(netExchanges).toHaveLength(1);
|
|
720
|
-
const exchange = netExchanges[0]!;
|
|
721
|
-
expect(exchange.responseBody).toBe('{"answer":"from the origin"}');
|
|
722
|
-
expect(exchange.responseDecodedFrom).toBe('gzip');
|
|
723
|
-
expect(exchange.responseHeaders['content-encoding']).toBeUndefined();
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
it('marks an over-limit h2 response incomplete', async () => {
|
|
727
|
-
h2Origin = await startH2Origin(originCa, {
|
|
728
|
-
answer: () => ({
|
|
729
|
-
contentType: 'application/json',
|
|
730
|
-
body: JSON.stringify({ answer: 'x'.repeat(512) }),
|
|
731
|
-
}),
|
|
732
|
-
});
|
|
733
|
-
const handle = await createProxy({
|
|
734
|
-
mode: 'record',
|
|
735
|
-
maxCapturedBytes: 32,
|
|
736
|
-
tls: {
|
|
737
|
-
ca: runCa,
|
|
738
|
-
hosts: [`127.0.0.1:${h2Origin.port}`],
|
|
739
|
-
trustedOriginCerts: [originCa.certPem],
|
|
740
|
-
maxCapturedBytes: 32,
|
|
741
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
742
|
-
},
|
|
743
|
-
});
|
|
744
|
-
proxy = handle;
|
|
745
|
-
|
|
746
|
-
const session = await h2Through({
|
|
747
|
-
proxyPort: handle.port,
|
|
748
|
-
host: '127.0.0.1',
|
|
749
|
-
port: h2Origin.port,
|
|
750
|
-
trust: [runCa.certPem],
|
|
751
|
-
});
|
|
752
|
-
const request = session.request({ ':method': 'POST', ':path': '/not-a-model-endpoint' });
|
|
753
|
-
request.on('data', () => undefined);
|
|
754
|
-
request.end('{}');
|
|
755
|
-
await once(request, 'close');
|
|
756
|
-
session.destroy();
|
|
757
|
-
|
|
758
|
-
expect(netExchanges).toHaveLength(1);
|
|
759
|
-
expect(netExchanges[0]!.responseTruncated).toBe(true);
|
|
760
|
-
expect(netExchanges[0]!.responseComplete).toBe(false);
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
it('carries the protocol onto a model exchange promoted from an h2 call', async () => {
|
|
764
|
-
// `alpn` has been recorded on `net.request` since the interceptor learned h2, and the
|
|
765
|
-
// reason given was that "did this run go through the h2 path" has to be answerable from the
|
|
766
|
-
// trace. On an intercepted run it was not: every model call a dialect claims is promoted,
|
|
767
|
-
// so no `net.*` event is left to carry the field, and promotion dropped it. Asked over h2
|
|
768
|
-
// because that is the answer worth having -- and because the HTTP/1.1 test client offers no
|
|
769
|
-
// ALPN at all, where absent is the honest value.
|
|
770
|
-
h2Origin = await startH2Origin(originCa, {
|
|
771
|
-
answer: () => ({
|
|
772
|
-
contentType: 'application/json',
|
|
773
|
-
body: JSON.stringify({
|
|
774
|
-
id: 'chatcmpl-1',
|
|
775
|
-
object: 'chat.completion',
|
|
776
|
-
model: 'gpt-5.2',
|
|
777
|
-
choices: [
|
|
778
|
-
{ index: 0, message: { role: 'assistant', content: 'hi' }, finish_reason: 'stop' },
|
|
779
|
-
],
|
|
780
|
-
usage: { prompt_tokens: 3, completion_tokens: 1, total_tokens: 4 },
|
|
781
|
-
}),
|
|
782
|
-
}),
|
|
783
|
-
});
|
|
784
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
785
|
-
|
|
786
|
-
const session = await h2Through({
|
|
787
|
-
proxyPort: handle.port,
|
|
788
|
-
host: '127.0.0.1',
|
|
789
|
-
port: h2Origin.port,
|
|
790
|
-
trust: [runCa.certPem],
|
|
791
|
-
});
|
|
792
|
-
const request = session.request({
|
|
793
|
-
':method': 'POST',
|
|
794
|
-
':path': '/v1/chat/completions',
|
|
795
|
-
'content-type': 'application/json',
|
|
796
|
-
});
|
|
797
|
-
request.setEncoding('utf8');
|
|
798
|
-
request.on('data', () => undefined);
|
|
799
|
-
request.end(
|
|
800
|
-
JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hi' }] }),
|
|
801
|
-
);
|
|
802
|
-
await once(request, 'close');
|
|
803
|
-
session.destroy();
|
|
804
|
-
|
|
805
|
-
expect(modelExchanges).toHaveLength(1);
|
|
806
|
-
expect(modelExchanges[0]!.alpn).toBe('h2');
|
|
807
|
-
expect(netExchanges).toHaveLength(1);
|
|
808
|
-
expect(netExchanges[0]!.modelDialect).toBe('openai');
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
/**
|
|
812
|
-
* The same guarantee over h2, which is the path that actually matters here: `openrouter.ai`
|
|
813
|
-
* negotiates h2, so every OpenRouter-attributed request reaches the interceptor through
|
|
814
|
-
* `forwardH2` rather than the HTTP/1.1 forwarder. The two forwarders build their header maps
|
|
815
|
-
* separately, so the property has to be pinned on both or it holds only where it was tested.
|
|
816
|
-
*/
|
|
817
|
-
it('forwards the app attribution headers untouched over h2 too', async () => {
|
|
818
|
-
const referer = 'https://github.com/askdkc/AgenticReplay';
|
|
819
|
-
const title = 'Some Coding Agent';
|
|
820
|
-
let seen: IncomingHttpHeaders = {};
|
|
821
|
-
h2Origin = await startH2Origin(originCa, { onStream: (h) => void (seen = h) });
|
|
822
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
823
|
-
|
|
824
|
-
const session = await h2Through({
|
|
825
|
-
proxyPort: handle.port,
|
|
826
|
-
host: '127.0.0.1',
|
|
827
|
-
port: h2Origin.port,
|
|
828
|
-
trust: [runCa.certPem],
|
|
829
|
-
});
|
|
830
|
-
const request = session.request({
|
|
831
|
-
':method': 'POST',
|
|
832
|
-
':path': '/v1/embeddings',
|
|
833
|
-
authorization: 'Bearer sk-live-abcdefghijklmnop',
|
|
834
|
-
'http-referer': referer,
|
|
835
|
-
'x-title': title,
|
|
836
|
-
});
|
|
837
|
-
request.on('error', () => undefined);
|
|
838
|
-
// The response has to be drained, or h2 flow control keeps the stream open and `close`
|
|
839
|
-
// never fires.
|
|
840
|
-
request.setEncoding('utf8');
|
|
841
|
-
request.on('data', () => undefined);
|
|
842
|
-
request.end('{}');
|
|
843
|
-
await once(request, 'close');
|
|
844
|
-
session.destroy();
|
|
845
|
-
|
|
846
|
-
expect(seen['http-referer']).toBe(referer);
|
|
847
|
-
expect(seen['x-title']).toBe(title);
|
|
848
|
-
const recorded = netExchanges.find((e) => e.path === '/v1/embeddings');
|
|
849
|
-
expect(recorded?.requestHeaders['http-referer']).toBe(referer);
|
|
850
|
-
expect(recorded?.requestHeaders['x-title']).toBe(title);
|
|
851
|
-
expect(recorded?.requestHeaders.authorization).toBeUndefined();
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
it('answers from the replay hook without opening a connection to the origin', async () => {
|
|
855
|
-
h2Origin = await startH2Origin(originCa);
|
|
856
|
-
const handle = await startReplayProxy([`127.0.0.1:${h2Origin.port}`], () => ({
|
|
857
|
-
status: 418,
|
|
858
|
-
headers: { 'content-type': 'text/plain' },
|
|
859
|
-
body: 'from-recording',
|
|
860
|
-
}));
|
|
861
|
-
|
|
862
|
-
const session = await h2Through({
|
|
863
|
-
proxyPort: handle.port,
|
|
864
|
-
host: '127.0.0.1',
|
|
865
|
-
port: h2Origin.port,
|
|
866
|
-
trust: [runCa.certPem],
|
|
867
|
-
});
|
|
868
|
-
const request = session.request({ ':method': 'POST', ':path': '/replay' });
|
|
869
|
-
let status = 0;
|
|
870
|
-
let body = '';
|
|
871
|
-
request.on('response', (h) => void (status = Number(h[':status'])));
|
|
872
|
-
request.setEncoding('utf8');
|
|
873
|
-
request.on('data', (c: string) => void (body += c));
|
|
874
|
-
request.end('hello');
|
|
875
|
-
await once(request, 'close');
|
|
876
|
-
session.destroy();
|
|
877
|
-
|
|
878
|
-
expect(status).toBe(418);
|
|
879
|
-
expect(body).toBe('from-recording');
|
|
880
|
-
// The point of the whole test: a strict replay must not reach the provider.
|
|
881
|
-
expect(h2Origin.hits).toBe(0);
|
|
882
|
-
});
|
|
883
|
-
|
|
884
|
-
it('survives an origin response that arrives after the client has gone', async () => {
|
|
885
|
-
let answered = false;
|
|
886
|
-
// Waited for rather than slept past. The assertion below is that the origin saw the stream,
|
|
887
|
-
// and the proxy has to complete a TLS handshake and open an h2 session upstream before it
|
|
888
|
-
// can — so a fixed 40ms was a bet on how long that takes. It came in under the wire on one
|
|
889
|
-
// CI runner and not on another, and `expected +0 to be 1` is what losing that bet looks
|
|
890
|
-
// like. Shortening the sleep to zero reproduces it three times out of three.
|
|
891
|
-
let sawStream = (): void => undefined;
|
|
892
|
-
const streamReached = new Promise<void>((resolve) => {
|
|
893
|
-
sawStream = resolve;
|
|
894
|
-
});
|
|
895
|
-
h2Origin = await startH2Origin(originCa, { delayMs: 250, onStream: () => sawStream() });
|
|
896
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
897
|
-
|
|
898
|
-
const session = await h2Through({
|
|
899
|
-
proxyPort: handle.port,
|
|
900
|
-
host: '127.0.0.1',
|
|
901
|
-
port: h2Origin.port,
|
|
902
|
-
trust: [runCa.certPem],
|
|
903
|
-
});
|
|
904
|
-
const request = session.request({ ':method': 'POST', ':path': '/abort' });
|
|
905
|
-
request.on('error', () => undefined);
|
|
906
|
-
request.end('hello');
|
|
907
|
-
await streamReached;
|
|
908
|
-
// The client gives up while the origin is still thinking. Responding on this stream
|
|
909
|
-
// afterwards raises ERR_HTTP2_INVALID_STREAM from inside an event callback, which used to
|
|
910
|
-
// be an uncaught exception and took the proxy process with it.
|
|
911
|
-
request.destroy();
|
|
912
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
913
|
-
answered = true;
|
|
914
|
-
session.destroy();
|
|
915
|
-
|
|
916
|
-
expect(answered).toBe(true);
|
|
917
|
-
expect(h2Origin.hits).toBe(1);
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
it('records an h2 exchange the client abandoned before the origin answered', async () => {
|
|
921
|
-
// The test above proves the proxy survives this. This one proves the run remembers it.
|
|
922
|
-
let sawStream = (): void => undefined;
|
|
923
|
-
const streamReached = new Promise<void>((resolve) => {
|
|
924
|
-
sawStream = resolve;
|
|
925
|
-
});
|
|
926
|
-
h2Origin = await startH2Origin(originCa, { delayMs: 250, onStream: () => sawStream() });
|
|
927
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
928
|
-
|
|
929
|
-
const session = await h2Through({
|
|
930
|
-
proxyPort: handle.port,
|
|
931
|
-
host: '127.0.0.1',
|
|
932
|
-
port: h2Origin.port,
|
|
933
|
-
trust: [runCa.certPem],
|
|
934
|
-
});
|
|
935
|
-
const request = session.request({ ':method': 'POST', ':path': '/abort' });
|
|
936
|
-
request.on('error', () => undefined);
|
|
937
|
-
request.end('hello');
|
|
938
|
-
await streamReached;
|
|
939
|
-
request.destroy();
|
|
940
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
941
|
-
session.destroy();
|
|
942
|
-
|
|
943
|
-
expect(netExchanges).toHaveLength(1);
|
|
944
|
-
expect(netExchanges[0]!.abandoned).toBe(true);
|
|
945
|
-
expect(netExchanges[0]!.alpn).toBe('h2');
|
|
946
|
-
// The request reached the origin, so the bytes the agent sent are the part worth keeping.
|
|
947
|
-
expect(netExchanges[0]!.requestBody).toBe('hello');
|
|
948
|
-
expect(netExchanges[0]!.status).toBe(0);
|
|
949
|
-
});
|
|
950
|
-
|
|
951
|
-
it('records an exchange whose request body it cannot decode', async () => {
|
|
952
|
-
h2Origin = await startH2Origin(originCa);
|
|
953
|
-
const handle = await startProxy([`127.0.0.1:${h2Origin.port}`]);
|
|
954
|
-
const failures: string[] = [];
|
|
955
|
-
// `onFailure` is the channel the opaque case reports on, and the proxy under test already
|
|
956
|
-
// has one wired by `startProxy`; this asserts the exchange, which is the load-bearing half.
|
|
957
|
-
|
|
958
|
-
const session = await h2Through({
|
|
959
|
-
proxyPort: handle.port,
|
|
960
|
-
host: '127.0.0.1',
|
|
961
|
-
port: h2Origin.port,
|
|
962
|
-
trust: [runCa.certPem],
|
|
963
|
-
});
|
|
964
|
-
const request = session.request({
|
|
965
|
-
':method': 'POST',
|
|
966
|
-
':path': '/v1/embeddings',
|
|
967
|
-
// Claims an encoding the body does not have. `decodeBody` throws either because
|
|
968
|
-
// the runtime has no zstd or because the stream is corrupt; both used to escape the
|
|
969
|
-
// `end` handler as an uncaught exception.
|
|
970
|
-
'content-encoding': 'zstd',
|
|
971
|
-
});
|
|
972
|
-
request.on('error', () => undefined);
|
|
973
|
-
request.setEncoding('utf8');
|
|
974
|
-
let body = '';
|
|
975
|
-
request.on('data', (c: string) => void (body += c));
|
|
976
|
-
request.end(Buffer.from('not zstd at all'));
|
|
977
|
-
await once(request, 'close');
|
|
978
|
-
session.destroy();
|
|
979
|
-
expect(failures).toHaveLength(0);
|
|
980
|
-
|
|
981
|
-
expect(body).toBe('from-origin');
|
|
982
|
-
const opaque = netExchanges.find((e) => e.path === '/v1/embeddings');
|
|
983
|
-
expect(opaque).toBeDefined();
|
|
984
|
-
expect(opaque?.alpn).toBe('h2');
|
|
985
|
-
expect(opaque?.status).toBe(200);
|
|
986
|
-
});
|
|
987
|
-
});
|
|
988
|
-
|
|
989
|
-
it('refuses CONNECT entirely when interception was not asked for', async () => {
|
|
990
|
-
proxy = await createProxy({ mode: 'record' });
|
|
991
|
-
await expect(
|
|
992
|
-
through({
|
|
993
|
-
proxyPort: proxy.port,
|
|
994
|
-
host: '127.0.0.1',
|
|
995
|
-
port: model.port,
|
|
996
|
-
trust: [runCa.certPem, originCa.certPem],
|
|
997
|
-
}),
|
|
998
|
-
).rejects.toThrow();
|
|
999
|
-
expect(netExchanges).toHaveLength(0);
|
|
1000
|
-
});
|
|
1001
|
-
|
|
1002
|
-
// `/v1/embeddings` throughout the opaque-capture tests, and the choice is load-bearing: these
|
|
1003
|
-
// assert what happens to traffic *no dialect recognises*, so the path has to be one agenticreplay has no
|
|
1004
|
-
// translator for. They were written against `/v1/responses`, which stopped being such a path the
|
|
1005
|
-
// day the Responses dialect landed — and then failed, correctly, by recording a model exchange.
|
|
1006
|
-
it('decrypts an allowlisted host and captures both halves of the exchange', async () => {
|
|
1007
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1008
|
-
|
|
1009
|
-
const response = await through({
|
|
1010
|
-
proxyPort: handle.port,
|
|
1011
|
-
host: '127.0.0.1',
|
|
1012
|
-
port: model.port,
|
|
1013
|
-
trust: [runCa.certPem],
|
|
1014
|
-
method: 'POST',
|
|
1015
|
-
path: '/v1/embeddings',
|
|
1016
|
-
body: JSON.stringify({ prompt: 'hello' }),
|
|
1017
|
-
headers: { 'content-type': 'application/json' },
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
expect(response.status).toBe(200);
|
|
1021
|
-
// The origin's real answer, relayed intact.
|
|
1022
|
-
expect(JSON.parse(response.body).saw).toBe(JSON.stringify({ prompt: 'hello' }));
|
|
1023
|
-
// Signed by the run CA, not by the origin's: this connection was terminated and re-encrypted.
|
|
1024
|
-
expect(response.peerIssuer).toBe(commonName(runCa.certPem));
|
|
1025
|
-
|
|
1026
|
-
expect(netExchanges).toHaveLength(1);
|
|
1027
|
-
const captured = netExchanges[0]!;
|
|
1028
|
-
expect(captured.host).toBe('127.0.0.1');
|
|
1029
|
-
expect(captured.port).toBe(model.port);
|
|
1030
|
-
expect(captured.method).toBe('POST');
|
|
1031
|
-
expect(captured.path).toBe('/v1/embeddings');
|
|
1032
|
-
expect(captured.requestBody).toBe(JSON.stringify({ prompt: 'hello' }));
|
|
1033
|
-
expect(captured.status).toBe(200);
|
|
1034
|
-
expect(JSON.parse(captured.responseBody).path).toBe('/v1/embeddings');
|
|
1035
|
-
expect(tunnels).toHaveLength(0);
|
|
1036
|
-
});
|
|
1037
|
-
|
|
1038
|
-
it('cannot be reached by a client that does not trust the run CA', async () => {
|
|
1039
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1040
|
-
// Interception is not invisible, and should not be: a client trusting only the real origin's
|
|
1041
|
-
// CA gets a handshake failure rather than a quietly rewritten connection.
|
|
1042
|
-
await expect(
|
|
1043
|
-
through({
|
|
1044
|
-
proxyPort: handle.port,
|
|
1045
|
-
host: '127.0.0.1',
|
|
1046
|
-
port: model.port,
|
|
1047
|
-
trust: [originCa.certPem],
|
|
1048
|
-
}),
|
|
1049
|
-
).rejects.toThrow();
|
|
1050
|
-
});
|
|
1051
|
-
|
|
1052
|
-
it('tunnels a host outside the allowlist without decrypting it', async () => {
|
|
1053
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1054
|
-
|
|
1055
|
-
const response = await through({
|
|
1056
|
-
proxyPort: handle.port,
|
|
1057
|
-
host: '127.0.0.1',
|
|
1058
|
-
port: bank.port,
|
|
1059
|
-
// Only the origin's CA. If agenticreplay had terminated this connection the handshake would fail.
|
|
1060
|
-
trust: [originCa.certPem],
|
|
1061
|
-
path: '/accounts',
|
|
1062
|
-
});
|
|
1063
|
-
|
|
1064
|
-
expect(response.status).toBe(200);
|
|
1065
|
-
expect(JSON.parse(response.body).balance).toBe('SUPER-SECRET-BALANCE-42');
|
|
1066
|
-
// The origin's own certificate reached the client untouched. AgenticReplay never held the plaintext.
|
|
1067
|
-
expect(response.peerIssuer).toBe(commonName(originCa.certPem));
|
|
1068
|
-
expect(response.peerIssuer).not.toBe(commonName(runCa.certPem));
|
|
1069
|
-
|
|
1070
|
-
expect(netExchanges).toHaveLength(0);
|
|
1071
|
-
// A tunnel's record is only complete when it closes — byte counts are the only thing there is
|
|
1072
|
-
// to say about it, and they are not final until then.
|
|
1073
|
-
await vi.waitFor(() => expect(tunnels).toHaveLength(1));
|
|
1074
|
-
const tunnel = tunnels[0]!;
|
|
1075
|
-
expect(tunnel.host).toBe('127.0.0.1');
|
|
1076
|
-
expect(tunnel.port).toBe(bank.port);
|
|
1077
|
-
expect(tunnel.bytesToClient).toBeGreaterThan(0);
|
|
1078
|
-
// What a tunnel records is an address and a byte count. Not a path, not a header, not a body.
|
|
1079
|
-
expect(JSON.stringify(tunnel)).not.toContain('SUPER-SECRET-BALANCE-42');
|
|
1080
|
-
expect(JSON.stringify(tunnel)).not.toContain('accounts');
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
it('records an intercepted model API call as both model and authoritative net evidence', async () => {
|
|
1084
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1085
|
-
|
|
1086
|
-
await through({
|
|
1087
|
-
proxyPort: handle.port,
|
|
1088
|
-
host: '127.0.0.1',
|
|
1089
|
-
port: model.port,
|
|
1090
|
-
trust: [runCa.certPem],
|
|
1091
|
-
method: 'POST',
|
|
1092
|
-
path: '/v1/chat/completions',
|
|
1093
|
-
body: JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hello' }] }),
|
|
1094
|
-
headers: { 'content-type': 'application/json' },
|
|
1095
|
-
});
|
|
1096
|
-
|
|
1097
|
-
// This is the payoff for a harness that ignores base-URL variables: its model traffic lands
|
|
1098
|
-
// in the trace as model traffic, indistinguishable from a run captured the ordinary way.
|
|
1099
|
-
expect(modelExchanges).toHaveLength(1);
|
|
1100
|
-
expect(modelExchanges[0]!.dialect).toBe('openai');
|
|
1101
|
-
expect(modelExchanges[0]!.canonicalRequest.model).toBe('gpt-5.2');
|
|
1102
|
-
expect(modelExchanges[0]!.status).toBe(200);
|
|
1103
|
-
expect(netExchanges).toHaveLength(1);
|
|
1104
|
-
expect(netExchanges[0]!.modelDialect).toBe('openai');
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
it('recognises a model API call whose endpoint carries a query string', async () => {
|
|
1108
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1109
|
-
|
|
1110
|
-
await through({
|
|
1111
|
-
proxyPort: handle.port,
|
|
1112
|
-
host: '127.0.0.1',
|
|
1113
|
-
port: model.port,
|
|
1114
|
-
trust: [runCa.certPem],
|
|
1115
|
-
method: 'POST',
|
|
1116
|
-
// What Azure OpenAI's endpoints look like, and they are not optional there.
|
|
1117
|
-
path: '/v1/chat/completions?api-version=2026-02-01',
|
|
1118
|
-
body: JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hello' }] }),
|
|
1119
|
-
headers: { 'content-type': 'application/json' },
|
|
1120
|
-
});
|
|
1121
|
-
|
|
1122
|
-
// Matching the raw path recorded this as net traffic: unreplayable, unforkable, and reported
|
|
1123
|
-
// as a path no dialect claims.
|
|
1124
|
-
expect(modelExchanges).toHaveLength(1);
|
|
1125
|
-
expect(modelExchanges[0]!.dialect).toBe('openai');
|
|
1126
|
-
expect(netExchanges).toHaveLength(1);
|
|
1127
|
-
expect(netExchanges[0]!.modelDialect).toBe('openai');
|
|
1128
|
-
// The query stays in the trace -- it is what the agent asked for; only the match ignores it.
|
|
1129
|
-
expect(modelExchanges[0]!.path).toBe('/v1/chat/completions?api-version=2026-02-01');
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
/**
|
|
1133
|
-
* A response body reaches the recording compressed only from an origin that ignores the
|
|
1134
|
-
* stripped `accept-encoding`. What made it worth fixing is that the fallback was silently wrong
|
|
1135
|
-
* rather than merely large: measured against such an origin, `agenticreplay replay` reported
|
|
1136
|
-
* `exact=1 divergences=0` over a response the agent could not read.
|
|
1137
|
-
*/
|
|
1138
|
-
describe('a response the origin compressed anyway', () => {
|
|
1139
|
-
it('records the body the client saw, and says what it took off to get there', async () => {
|
|
1140
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1141
|
-
await through({
|
|
1142
|
-
proxyPort: handle.port,
|
|
1143
|
-
host: '127.0.0.1',
|
|
1144
|
-
port: model.port,
|
|
1145
|
-
trust: [runCa.certPem],
|
|
1146
|
-
method: 'POST',
|
|
1147
|
-
path: '/v1/chat/completions',
|
|
1148
|
-
body: JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hello' }] }),
|
|
1149
|
-
headers: { 'content-type': 'application/json', 'x-test-gzip': '1' },
|
|
1150
|
-
});
|
|
1151
|
-
|
|
1152
|
-
expect(modelExchanges).toHaveLength(1);
|
|
1153
|
-
const exchange = modelExchanges[0]!;
|
|
1154
|
-
// Three failures from the one cause, each pinned here. No dialect can read a deflate
|
|
1155
|
-
// stream, so `usage` came out 0/0 on a call that reports 3/1 uncompressed; the recorded
|
|
1156
|
-
// body was base64 of the wire bytes, which is what a reader opens; and replay answers from
|
|
1157
|
-
// that body under a `content-type` it synthesises and never a `content-encoding`, so the
|
|
1158
|
-
// agent was handed the base64 text as the model's reply.
|
|
1159
|
-
expect(exchange.rawResponse).toContain('"content":"hi"');
|
|
1160
|
-
expect(exchange.rawResponse).not.toContain('agenticreplay-base64:');
|
|
1161
|
-
expect(exchange.usage?.input_tokens).toBe(3);
|
|
1162
|
-
expect(exchange.usage?.output_tokens).toBe(1);
|
|
1163
|
-
expect(exchange.responseDecodedFrom).toBe('gzip');
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
it('stops claiming an encoding the recorded body no longer has', async () => {
|
|
1167
|
-
// Asked on a path no dialect claims, because that is the exchange that keeps its response
|
|
1168
|
-
// headers. A promoted model exchange carries none at all, which is why `decoded_from` has
|
|
1169
|
-
// to travel separately.
|
|
1170
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1171
|
-
await through({
|
|
1172
|
-
proxyPort: handle.port,
|
|
1173
|
-
host: '127.0.0.1',
|
|
1174
|
-
port: model.port,
|
|
1175
|
-
trust: [runCa.certPem],
|
|
1176
|
-
method: 'POST',
|
|
1177
|
-
path: '/not-a-model-endpoint',
|
|
1178
|
-
body: '{}',
|
|
1179
|
-
headers: { 'content-type': 'application/json', 'x-test-gzip': '1' },
|
|
1180
|
-
});
|
|
1181
|
-
|
|
1182
|
-
expect(netExchanges).toHaveLength(1);
|
|
1183
|
-
const exchange = netExchanges[0]!;
|
|
1184
|
-
expect(exchange.responseBody).toContain('"content":"hi"');
|
|
1185
|
-
// `content-encoding: gzip` beside a decoded body is a claim the recording cannot support,
|
|
1186
|
-
// and a `content-length` counting compressed bytes is another. Neither fact is lost: the
|
|
1187
|
-
// wire size is what `responseBytes` has always been.
|
|
1188
|
-
expect(exchange.responseHeaders['content-encoding']).toBeUndefined();
|
|
1189
|
-
expect(exchange.responseHeaders['content-length']).toBeUndefined();
|
|
1190
|
-
expect(exchange.responseHeaders['content-type']).toBe('application/json');
|
|
1191
|
-
expect(exchange.responseDecodedFrom).toBe('gzip');
|
|
1192
|
-
expect(exchange.responseBytes).toBeLessThan(exchange.responseBody.length);
|
|
1193
|
-
});
|
|
1194
|
-
|
|
1195
|
-
it('keeps the wire bytes, and says why, when the claimed encoding is not there', async () => {
|
|
1196
|
-
const failures: string[] = [];
|
|
1197
|
-
const handle = await createProxy({
|
|
1198
|
-
mode: 'record',
|
|
1199
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
1200
|
-
tls: {
|
|
1201
|
-
ca: runCa,
|
|
1202
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1203
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1204
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1205
|
-
onFailure: (f) => void failures.push(f.reason),
|
|
1206
|
-
},
|
|
1207
|
-
});
|
|
1208
|
-
proxy = handle;
|
|
1209
|
-
await through({
|
|
1210
|
-
proxyPort: handle.port,
|
|
1211
|
-
host: '127.0.0.1',
|
|
1212
|
-
port: model.port,
|
|
1213
|
-
trust: [runCa.certPem],
|
|
1214
|
-
method: 'POST',
|
|
1215
|
-
path: '/not-a-model-endpoint',
|
|
1216
|
-
body: '{}',
|
|
1217
|
-
headers: { 'content-type': 'application/json', 'x-test-gzip': 'lying' },
|
|
1218
|
-
});
|
|
1219
|
-
|
|
1220
|
-
// Undecodable is not unrecordable. The bytes are kept exactly as they arrived and the
|
|
1221
|
-
// header set is left describing them, because in this case it still does.
|
|
1222
|
-
expect(netExchanges).toHaveLength(1);
|
|
1223
|
-
expect(netExchanges[0]!.responseDecodedFrom).toBeUndefined();
|
|
1224
|
-
expect(netExchanges[0]!.responseHeaders['content-encoding']).toBe('gzip');
|
|
1225
|
-
expect(failures.some((reason) => reason.startsWith('response body left opaque'))).toBe(true);
|
|
1226
|
-
});
|
|
1227
|
-
|
|
1228
|
-
it('says nothing about a response that carried no body at all', async () => {
|
|
1229
|
-
const failures: string[] = [];
|
|
1230
|
-
const handle = await createProxy({
|
|
1231
|
-
mode: 'record',
|
|
1232
|
-
tls: {
|
|
1233
|
-
ca: runCa,
|
|
1234
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1235
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1236
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1237
|
-
onFailure: (f) => void failures.push(f.reason),
|
|
1238
|
-
},
|
|
1239
|
-
});
|
|
1240
|
-
proxy = handle;
|
|
1241
|
-
await through({
|
|
1242
|
-
proxyPort: handle.port,
|
|
1243
|
-
host: '127.0.0.1',
|
|
1244
|
-
port: model.port,
|
|
1245
|
-
trust: [runCa.certPem],
|
|
1246
|
-
method: 'GET',
|
|
1247
|
-
path: '/not-modified',
|
|
1248
|
-
});
|
|
1249
|
-
|
|
1250
|
-
expect(netExchanges).toHaveLength(1);
|
|
1251
|
-
expect(netExchanges[0]!.status).toBe(304);
|
|
1252
|
-
expect(netExchanges[0]!.responseBody).toBe('');
|
|
1253
|
-
expect(netExchanges[0]!.responseDecodedFrom).toBeUndefined();
|
|
1254
|
-
// Every decoder throws "unexpected end of file" on an empty buffer, so attempting one here
|
|
1255
|
-
// reported an opaque body on a response that never had one.
|
|
1256
|
-
expect(failures).toEqual([]);
|
|
1257
|
-
// Nothing was decoded, so the header set still describes what arrived.
|
|
1258
|
-
expect(netExchanges[0]!.responseHeaders['content-encoding']).toBe('gzip');
|
|
1259
|
-
});
|
|
1260
|
-
|
|
1261
|
-
it('leaves a stream the client walked away from mid-member alone, and says nothing', async () => {
|
|
1262
|
-
// Half a deflate member cannot be inflated, so attempting it would report a failure on
|
|
1263
|
-
// every turn of a harness that stops reading once it has its answer -- and `abandoned`
|
|
1264
|
-
// already says the record is a prefix rather than the whole of it.
|
|
1265
|
-
const failures: string[] = [];
|
|
1266
|
-
const handle = await createProxy({
|
|
1267
|
-
mode: 'record',
|
|
1268
|
-
tls: {
|
|
1269
|
-
ca: runCa,
|
|
1270
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1271
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1272
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1273
|
-
onFailure: (f) => void failures.push(f.reason),
|
|
1274
|
-
},
|
|
1275
|
-
});
|
|
1276
|
-
proxy = handle;
|
|
1277
|
-
await abandoned({
|
|
1278
|
-
proxyPort: handle.port,
|
|
1279
|
-
host: '127.0.0.1',
|
|
1280
|
-
port: model.port,
|
|
1281
|
-
trust: [runCa.certPem],
|
|
1282
|
-
path: '/stream-gzip',
|
|
1283
|
-
leaveAfter: 'first-chunk',
|
|
1284
|
-
});
|
|
1285
|
-
// Filed from `res.on('close')`, which lands after the client's own promise settles. The
|
|
1286
|
-
// origin is left holding the rest of the member on purpose; `afterEach` releases it into a
|
|
1287
|
-
// socket that has already gone.
|
|
1288
|
-
await settle();
|
|
1289
|
-
|
|
1290
|
-
expect(netExchanges).toHaveLength(1);
|
|
1291
|
-
expect(netExchanges[0]!.abandoned).toBe(true);
|
|
1292
|
-
expect(netExchanges[0]!.responseDecodedFrom).toBeUndefined();
|
|
1293
|
-
expect(failures).toEqual([]);
|
|
1294
|
-
});
|
|
1295
|
-
});
|
|
1296
|
-
|
|
1297
|
-
it.skipIf(zstdCompressSync === undefined)(
|
|
1298
|
-
'replays a zstd-compressed Codex request inside intercepted TLS',
|
|
1299
|
-
async () => {
|
|
1300
|
-
const dialect = defaultDialects().find((candidate) => candidate.id === 'codex')!;
|
|
1301
|
-
const request = {
|
|
1302
|
-
model: 'gpt-5.6-luna',
|
|
1303
|
-
instructions: 'Answer briefly.',
|
|
1304
|
-
input: [
|
|
1305
|
-
{
|
|
1306
|
-
type: 'message',
|
|
1307
|
-
role: 'user',
|
|
1308
|
-
content: [{ type: 'input_text', text: 'say hello' }],
|
|
1309
|
-
},
|
|
1310
|
-
],
|
|
1311
|
-
stream: true,
|
|
1312
|
-
};
|
|
1313
|
-
const response =
|
|
1314
|
-
'event: response.created\n' +
|
|
1315
|
-
'data: ' +
|
|
1316
|
-
JSON.stringify({
|
|
1317
|
-
type: 'response.created',
|
|
1318
|
-
response: { id: 'resp_test', model: 'gpt-5.6-luna', status: 'in_progress' },
|
|
1319
|
-
}) +
|
|
1320
|
-
'\n\n' +
|
|
1321
|
-
'event: response.output_text.delta\n' +
|
|
1322
|
-
'data: ' +
|
|
1323
|
-
JSON.stringify({ type: 'response.output_text.delta', delta: 'CODEX_REPLAY_OK' }) +
|
|
1324
|
-
'\n\n' +
|
|
1325
|
-
'event: response.completed\n' +
|
|
1326
|
-
'data: ' +
|
|
1327
|
-
JSON.stringify({
|
|
1328
|
-
type: 'response.completed',
|
|
1329
|
-
response: {
|
|
1330
|
-
id: 'resp_test',
|
|
1331
|
-
model: 'gpt-5.6-luna',
|
|
1332
|
-
status: 'completed',
|
|
1333
|
-
usage: { input_tokens: 3, output_tokens: 1 },
|
|
1334
|
-
},
|
|
1335
|
-
}) +
|
|
1336
|
-
'\n\n';
|
|
1337
|
-
proxy = await createProxy({
|
|
1338
|
-
mode: 'replay',
|
|
1339
|
-
exchanges: [
|
|
1340
|
-
{
|
|
1341
|
-
seq: 0,
|
|
1342
|
-
dialect: 'codex',
|
|
1343
|
-
path: '/backend-api/codex/responses',
|
|
1344
|
-
rawRequest: JSON.stringify(request),
|
|
1345
|
-
rawResponse: response,
|
|
1346
|
-
status: 200,
|
|
1347
|
-
streamed: true,
|
|
1348
|
-
canonicalRequest: dialect.toCanonicalRequest(request),
|
|
1349
|
-
canonicalResponse: dialect.parseStream(response),
|
|
1350
|
-
},
|
|
1351
|
-
],
|
|
1352
|
-
tls: {
|
|
1353
|
-
ca: runCa,
|
|
1354
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1355
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1356
|
-
},
|
|
1357
|
-
});
|
|
1358
|
-
|
|
1359
|
-
const replayed = await through({
|
|
1360
|
-
proxyPort: proxy.port,
|
|
1361
|
-
host: '127.0.0.1',
|
|
1362
|
-
port: model.port,
|
|
1363
|
-
trust: [runCa.certPem],
|
|
1364
|
-
method: 'POST',
|
|
1365
|
-
path: '/backend-api/codex/responses',
|
|
1366
|
-
body: zstdCompressSync(Buffer.from(JSON.stringify(request))),
|
|
1367
|
-
headers: { 'content-type': 'application/json', 'content-encoding': 'zstd' },
|
|
1368
|
-
});
|
|
1369
|
-
|
|
1370
|
-
expect(replayed.status).toBe(200);
|
|
1371
|
-
expect(replayed.body).toBe(response);
|
|
1372
|
-
expect(proxy.stats().matchedExact).toBe(1);
|
|
1373
|
-
expect(proxy.stats().unmatched).toBe(0);
|
|
1374
|
-
expect(netExchanges).toHaveLength(0);
|
|
1375
|
-
},
|
|
1376
|
-
);
|
|
1377
|
-
|
|
1378
|
-
it('never records the credentials it forwards', async () => {
|
|
1379
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1380
|
-
|
|
1381
|
-
const response = await through({
|
|
1382
|
-
proxyPort: handle.port,
|
|
1383
|
-
host: '127.0.0.1',
|
|
1384
|
-
port: model.port,
|
|
1385
|
-
trust: [runCa.certPem],
|
|
1386
|
-
method: 'POST',
|
|
1387
|
-
path: '/v1/embeddings',
|
|
1388
|
-
body: '{}',
|
|
1389
|
-
headers: { authorization: 'Bearer sk-live-abcdefghijklmnop', 'x-api-key': 'secret-key' },
|
|
1390
|
-
});
|
|
1391
|
-
|
|
1392
|
-
expect(response.status).toBe(200);
|
|
1393
|
-
// Forwarded — an agent that cannot authenticate cannot run.
|
|
1394
|
-
expect(originSawAuth).toBe('Bearer sk-live-abcdefghijklmnop');
|
|
1395
|
-
// Not recorded, in any form.
|
|
1396
|
-
const recorded = JSON.stringify(netExchanges[0]);
|
|
1397
|
-
expect(recorded).not.toContain('sk-live-abcdefghijklmnop');
|
|
1398
|
-
expect(recorded).not.toContain('secret-key');
|
|
1399
|
-
expect(netExchanges[0]!.requestHeaders.authorization).toBeUndefined();
|
|
1400
|
-
});
|
|
1401
|
-
|
|
1402
|
-
/**
|
|
1403
|
-
* The mirror image of the credential test above: these two headers must survive, and must be
|
|
1404
|
-
* recorded.
|
|
1405
|
-
*
|
|
1406
|
-
* `HTTP-Referer` and `X-Title` are how a provider attributes a request to the app that made it —
|
|
1407
|
-
* OpenRouter builds its public app leaderboard from exactly these. A proxy that rewrote or
|
|
1408
|
-
* dropped them would re-attribute the agent's tokens to whoever ran the recording, silently
|
|
1409
|
-
* changing a third party's published ranking; that is not agenticreplay's to alter, and a debugger is the
|
|
1410
|
-
* last thing that should be editing attribution. Recording them, unlike recording a credential,
|
|
1411
|
-
* is the right call: they say which app produced the exchange, which is the one thing a trace
|
|
1412
|
-
* holding several agents' traffic cannot otherwise recover.
|
|
1413
|
-
*/
|
|
1414
|
-
it('forwards the app attribution headers untouched, and records them', async () => {
|
|
1415
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1416
|
-
const referer = 'https://github.com/askdkc/AgenticReplay';
|
|
1417
|
-
const title = 'Some Coding Agent';
|
|
1418
|
-
|
|
1419
|
-
const response = await through({
|
|
1420
|
-
proxyPort: handle.port,
|
|
1421
|
-
host: '127.0.0.1',
|
|
1422
|
-
port: model.port,
|
|
1423
|
-
trust: [runCa.certPem],
|
|
1424
|
-
method: 'POST',
|
|
1425
|
-
path: '/v1/embeddings',
|
|
1426
|
-
body: '{}',
|
|
1427
|
-
headers: {
|
|
1428
|
-
authorization: 'Bearer sk-live-abcdefghijklmnop',
|
|
1429
|
-
'http-referer': referer,
|
|
1430
|
-
'x-title': title,
|
|
1431
|
-
},
|
|
1432
|
-
});
|
|
1433
|
-
|
|
1434
|
-
expect(response.status).toBe(200);
|
|
1435
|
-
// Byte-identical at the origin: not re-cased, not re-written, not agenticreplay's own.
|
|
1436
|
-
expect(originSawAttribution['http-referer']).toBe(referer);
|
|
1437
|
-
expect(originSawAttribution['x-title']).toBe(title);
|
|
1438
|
-
// And present in the trace, which is what lets one recording separate two agents.
|
|
1439
|
-
expect(netExchanges[0]!.requestHeaders['http-referer']).toBe(referer);
|
|
1440
|
-
expect(netExchanges[0]!.requestHeaders['x-title']).toBe(title);
|
|
1441
|
-
// The credential rule still holds alongside them.
|
|
1442
|
-
expect(netExchanges[0]!.requestHeaders.authorization).toBeUndefined();
|
|
1443
|
-
});
|
|
1444
|
-
|
|
1445
|
-
it('never lets the run CA private key reach anything it records', async () => {
|
|
1446
|
-
// The property this whole feature stands on. The key exists so agenticreplay can impersonate a host to
|
|
1447
|
-
// the child; a copy of it in a trace someone attaches to an issue is a signing key handed to
|
|
1448
|
-
// whoever reads the issue. Nothing in the capture path has any reason to touch it, which is
|
|
1449
|
-
// exactly why this is worth asserting: it is the kind of invariant a later refactor breaks
|
|
1450
|
-
// silently, and there is no error to notice when it does.
|
|
1451
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1452
|
-
|
|
1453
|
-
await through({
|
|
1454
|
-
proxyPort: handle.port,
|
|
1455
|
-
host: '127.0.0.1',
|
|
1456
|
-
port: model.port,
|
|
1457
|
-
trust: [runCa.certPem],
|
|
1458
|
-
method: 'POST',
|
|
1459
|
-
path: '/v1/embeddings',
|
|
1460
|
-
body: '{"model":"gpt-5.2"}',
|
|
1461
|
-
});
|
|
1462
|
-
|
|
1463
|
-
// Read from disk, because `RunCa` does not expose the key at all — it is a private field, and
|
|
1464
|
-
// the file is the only place it exists. That is the stronger guarantee: the capture path
|
|
1465
|
-
// cannot reach the key even by mistake. This test defends the remaining route, which is
|
|
1466
|
-
// something copying the file's contents into a record.
|
|
1467
|
-
//
|
|
1468
|
-
// Both shapes it could take: the PEM as written, and its base64 body with the armour and
|
|
1469
|
-
// newlines stripped, which is how it would survive being embedded in JSON.
|
|
1470
|
-
const keyPem = await readFile(runCa.keyPath, 'utf8');
|
|
1471
|
-
const keyBody = keyPem.replace(/-----[A-Z ]+-----/g, '').replace(/\s+/g, '');
|
|
1472
|
-
expect(keyBody.length).toBeGreaterThan(64);
|
|
1473
|
-
|
|
1474
|
-
const everythingRecorded = JSON.stringify({
|
|
1475
|
-
net: netExchanges,
|
|
1476
|
-
tunnels,
|
|
1477
|
-
model: modelExchanges,
|
|
1478
|
-
});
|
|
1479
|
-
expect(everythingRecorded).not.toContain(keyPem);
|
|
1480
|
-
expect(everythingRecorded).not.toContain(keyBody);
|
|
1481
|
-
expect(everythingRecorded).not.toContain('PRIVATE KEY');
|
|
1482
|
-
// The certificate is public and may legitimately appear; the key must not. Assert the search
|
|
1483
|
-
// was capable of finding something, so a future refactor cannot make this pass by recording
|
|
1484
|
-
// nothing at all.
|
|
1485
|
-
expect(everythingRecorded.length).toBeGreaterThan(100);
|
|
1486
|
-
});
|
|
1487
|
-
|
|
1488
|
-
it('forwards a streaming response as it arrives rather than buffering it', async () => {
|
|
1489
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1490
|
-
|
|
1491
|
-
const response = await through({
|
|
1492
|
-
proxyPort: handle.port,
|
|
1493
|
-
host: '127.0.0.1',
|
|
1494
|
-
port: model.port,
|
|
1495
|
-
trust: [runCa.certPem],
|
|
1496
|
-
path: '/stream',
|
|
1497
|
-
onFirstChunk: (chunk) => {
|
|
1498
|
-
expect(chunk).toContain('first');
|
|
1499
|
-
// The origin is waiting on this. If the proxy had read the whole body first, nothing
|
|
1500
|
-
// would ever call it.
|
|
1501
|
-
release?.();
|
|
1502
|
-
},
|
|
1503
|
-
});
|
|
1504
|
-
|
|
1505
|
-
expect(response.body).toBe('data: first\n\ndata: second\n\n');
|
|
1506
|
-
expect(netExchanges[0]!.responseBody).toBe('data: first\n\ndata: second\n\n');
|
|
1507
|
-
});
|
|
1508
|
-
|
|
1509
|
-
/**
|
|
1510
|
-
* The failure that made Hermes look uncapturable.
|
|
1511
|
-
*
|
|
1512
|
-
* Recording used to happen only when the response reached `end`, so a client that stopped
|
|
1513
|
-
* reading a streaming reply the moment it had its answer left nothing behind -- and the run
|
|
1514
|
-
* reported `capture.empty` with "the agent never called the proxy", about a request agenticreplay had
|
|
1515
|
-
* decrypted and forwarded itself. The prefix is the evidence, and the prefix is what gets kept.
|
|
1516
|
-
*/
|
|
1517
|
-
it('records a streaming exchange the client walks away from mid-flight', async () => {
|
|
1518
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1519
|
-
|
|
1520
|
-
const seen = await abandoned({
|
|
1521
|
-
proxyPort: handle.port,
|
|
1522
|
-
host: '127.0.0.1',
|
|
1523
|
-
port: model.port,
|
|
1524
|
-
trust: [runCa.certPem],
|
|
1525
|
-
path: '/stream',
|
|
1526
|
-
leaveAfter: 'first-chunk',
|
|
1527
|
-
});
|
|
1528
|
-
expect(seen).toBe('data: first\n\n');
|
|
1529
|
-
// The origin is left holding the second chunk on purpose. Releasing it here would let
|
|
1530
|
-
// the response reach `end` and be filed the ordinary way, which is the path this test is
|
|
1531
|
-
// not about; `afterEach` releases it into a socket that has already gone.
|
|
1532
|
-
await settle();
|
|
1533
|
-
|
|
1534
|
-
expect(netExchanges).toHaveLength(1);
|
|
1535
|
-
const captured = netExchanges[0]!;
|
|
1536
|
-
expect(captured.abandoned).toBe(true);
|
|
1537
|
-
expect(captured.status).toBe(200);
|
|
1538
|
-
expect(captured.responseBody).toContain('first');
|
|
1539
|
-
// Not a capture-limit truncation: agenticreplay kept everything it was handed.
|
|
1540
|
-
expect(captured.responseTruncated).toBe(false);
|
|
1541
|
-
});
|
|
1542
|
-
|
|
1543
|
-
/**
|
|
1544
|
-
* An exchange with no response is evidence, not a model call.
|
|
1545
|
-
*
|
|
1546
|
-
* `onDecrypted` promotes a decrypted POST to a model exchange when a dialect claims the path,
|
|
1547
|
-
* and a call abandoned before the answer would satisfy that on the path alone. Promoting it puts
|
|
1548
|
-
* an entry in the replay set that can answer nothing and cannot be forked, so it is kept as
|
|
1549
|
-
* network traffic instead -- which is what it is.
|
|
1550
|
-
*/
|
|
1551
|
-
it('keeps a model call abandoned before the origin answered as network traffic', async () => {
|
|
1552
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1553
|
-
|
|
1554
|
-
await abandoned({
|
|
1555
|
-
proxyPort: handle.port,
|
|
1556
|
-
host: '127.0.0.1',
|
|
1557
|
-
port: model.port,
|
|
1558
|
-
trust: [runCa.certPem],
|
|
1559
|
-
method: 'POST',
|
|
1560
|
-
path: '/v1/chat/completions',
|
|
1561
|
-
body: JSON.stringify({ model: 'gpt-5.2', messages: [{ role: 'user', content: 'hello' }] }),
|
|
1562
|
-
headers: { 'content-type': 'application/json', 'x-test-hold': '1' },
|
|
1563
|
-
leaveAfter: 'request',
|
|
1564
|
-
});
|
|
1565
|
-
// Deliberately not released here: the point is an exchange whose response never began, and
|
|
1566
|
-
// letting the origin answer first would give it the status that makes it a model call.
|
|
1567
|
-
// `afterEach` releases it into a socket that has already gone.
|
|
1568
|
-
await settle();
|
|
1569
|
-
|
|
1570
|
-
expect(modelExchanges).toHaveLength(0);
|
|
1571
|
-
expect(netExchanges).toHaveLength(1);
|
|
1572
|
-
expect(netExchanges[0]!.abandoned).toBe(true);
|
|
1573
|
-
expect(netExchanges[0]!.status).toBe(0);
|
|
1574
|
-
expect(netExchanges[0]!.requestBody).toContain('gpt-5.2');
|
|
1575
|
-
});
|
|
1576
|
-
|
|
1577
|
-
/**
|
|
1578
|
-
* An origin that dies is not a client that left, and only one of the two may go unanswered.
|
|
1579
|
-
*
|
|
1580
|
-
* The client is still connected and waiting for the rest of a response agenticreplay already began
|
|
1581
|
-
* forwarding. Treating the origin's abort as abandonment settles the forward promise, so the
|
|
1582
|
-
* caller's `.catch` -- the only thing that ends the client's response -- never runs, and the
|
|
1583
|
-
* agent's in-flight call waits for a stream that will never continue. Recording it as
|
|
1584
|
-
* `abandoned` compounds it: the field means the agent stopped reading, and here it did not.
|
|
1585
|
-
*/
|
|
1586
|
-
it('answers the client when the origin dies mid-response rather than leaving it hanging', async () => {
|
|
1587
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1588
|
-
|
|
1589
|
-
const settled = await Promise.race([
|
|
1590
|
-
through({
|
|
1591
|
-
proxyPort: handle.port,
|
|
1592
|
-
host: '127.0.0.1',
|
|
1593
|
-
port: model.port,
|
|
1594
|
-
trust: [runCa.certPem],
|
|
1595
|
-
path: '/die-mid-stream',
|
|
1596
|
-
}).then(
|
|
1597
|
-
() => 'settled' as const,
|
|
1598
|
-
// A transport error is still an answer: the client stops waiting. Hanging is the failure.
|
|
1599
|
-
() => 'settled' as const,
|
|
1600
|
-
),
|
|
1601
|
-
new Promise<'hung'>((resolve) => setTimeout(() => resolve('hung'), 4_000)),
|
|
1602
|
-
]);
|
|
1603
|
-
expect(settled).toBe('settled');
|
|
1604
|
-
await settle();
|
|
1605
|
-
|
|
1606
|
-
expect(netExchanges).toHaveLength(1);
|
|
1607
|
-
const captured = netExchanges[0]!;
|
|
1608
|
-
// The prefix the origin did send is worth keeping.
|
|
1609
|
-
expect(captured.responseBody).toContain('first');
|
|
1610
|
-
expect(captured.status).toBe(200);
|
|
1611
|
-
// But not as the agent's doing. `abandoned` says the client stopped reading; it did not.
|
|
1612
|
-
expect(captured.abandoned).not.toBe(true);
|
|
1613
|
-
});
|
|
1614
|
-
|
|
1615
|
-
it('refuses an origin whose certificate it cannot verify instead of downgrading', async () => {
|
|
1616
|
-
// A CA the proxy was never told about — the shape of a real MITM sitting in front of the
|
|
1617
|
-
// origin. Interception must not become an excuse to stop checking.
|
|
1618
|
-
const strangerDir = await mkdtemp(join(tmpdir(), 'agenticreplay-mitm-stranger-'));
|
|
1619
|
-
const stranger = await RunCa.create({ runDir: strangerDir });
|
|
1620
|
-
const impostor = await startOrigin(stranger, (_req, res) => res.end('{}'));
|
|
1621
|
-
try {
|
|
1622
|
-
const handle = await startProxy([`127.0.0.1:${impostor.port}`]);
|
|
1623
|
-
const response = await through({
|
|
1624
|
-
proxyPort: handle.port,
|
|
1625
|
-
host: '127.0.0.1',
|
|
1626
|
-
port: impostor.port,
|
|
1627
|
-
trust: [runCa.certPem],
|
|
1628
|
-
});
|
|
1629
|
-
expect(response.status).toBe(502);
|
|
1630
|
-
expect(response.body).toContain('certificate');
|
|
1631
|
-
} finally {
|
|
1632
|
-
await impostor.close();
|
|
1633
|
-
await stranger.dispose();
|
|
1634
|
-
await rm(strangerDir, { recursive: true, force: true });
|
|
1635
|
-
}
|
|
1636
|
-
});
|
|
1637
|
-
|
|
1638
|
-
it('reports what it is intercepting, so a run can say so before it starts', async () => {
|
|
1639
|
-
const handle = await startProxy(['api.openai.com', '*.chatgpt.com']);
|
|
1640
|
-
expect(handle.tls?.hosts).toBe('api.openai.com, *.chatgpt.com');
|
|
1641
|
-
expect(handle.tls?.fingerprint).toBe(runCa.fingerprint);
|
|
1642
|
-
expect(handle.tls?.caCertPath).toBe(runCa.certPath);
|
|
1643
|
-
expect(handle.tls?.caBundlePath).toBe(runCa.bundlePath);
|
|
1644
|
-
});
|
|
1645
|
-
|
|
1646
|
-
it('counts what it decrypted and what it refused to', async () => {
|
|
1647
|
-
const handle = await startProxy([`127.0.0.1:${model.port}`]);
|
|
1648
|
-
await through({
|
|
1649
|
-
proxyPort: handle.port,
|
|
1650
|
-
host: '127.0.0.1',
|
|
1651
|
-
port: model.port,
|
|
1652
|
-
trust: [runCa.certPem],
|
|
1653
|
-
path: '/one',
|
|
1654
|
-
});
|
|
1655
|
-
await through({
|
|
1656
|
-
proxyPort: handle.port,
|
|
1657
|
-
host: '127.0.0.1',
|
|
1658
|
-
port: bank.port,
|
|
1659
|
-
trust: [originCa.certPem],
|
|
1660
|
-
path: '/two',
|
|
1661
|
-
});
|
|
1662
|
-
expect(handle.stats().intercepted).toBe(1);
|
|
1663
|
-
expect(handle.stats().tunnelled).toBe(1);
|
|
1664
|
-
});
|
|
1665
|
-
|
|
1666
|
-
/**
|
|
1667
|
-
* `--model` on a TLS-intercepted fork. Issue #49: the flag was accepted and echoed, then the
|
|
1668
|
-
* intercepted live path forwarded the recorded model unchanged, and `live=0` because `goLive`
|
|
1669
|
-
* never ran. Same-provider substitution has to rewrite the body and still talk to the CONNECT
|
|
1670
|
-
* target — that origin's credential cannot follow us to a vendor default.
|
|
1671
|
-
*/
|
|
1672
|
-
const interceptedChat = {
|
|
1673
|
-
model: 'grok-4',
|
|
1674
|
-
messages: [{ role: 'user', content: 'hello' }],
|
|
1675
|
-
};
|
|
1676
|
-
|
|
1677
|
-
async function postInterceptedChat(
|
|
1678
|
-
handle: ProxyHandle,
|
|
1679
|
-
body: typeof interceptedChat = interceptedChat,
|
|
1680
|
-
): Promise<ProxiedResponse> {
|
|
1681
|
-
return through({
|
|
1682
|
-
proxyPort: handle.port,
|
|
1683
|
-
host: '127.0.0.1',
|
|
1684
|
-
port: model.port,
|
|
1685
|
-
trust: [runCa.certPem],
|
|
1686
|
-
method: 'POST',
|
|
1687
|
-
path: '/v1/chat/completions',
|
|
1688
|
-
body: JSON.stringify(body),
|
|
1689
|
-
headers: { 'content-type': 'application/json' },
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
it('substitutes --model on a TLS-intercepted live call and counts it as live', async () => {
|
|
1694
|
-
const routes: Array<{ model: string; origin?: string }> = [];
|
|
1695
|
-
proxy = await createProxy({
|
|
1696
|
-
mode: 'hybrid',
|
|
1697
|
-
exchanges: [],
|
|
1698
|
-
forkAt: 0,
|
|
1699
|
-
forkModel: 'grok-4-fast',
|
|
1700
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
1701
|
-
onRoute: (d) => void routes.push(d),
|
|
1702
|
-
tls: {
|
|
1703
|
-
ca: runCa,
|
|
1704
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1705
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1706
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1707
|
-
},
|
|
1708
|
-
});
|
|
1709
|
-
|
|
1710
|
-
const response = await postInterceptedChat(proxy);
|
|
1711
|
-
expect(response.status).toBe(200);
|
|
1712
|
-
expect(JSON.parse(originSawChatBody ?? '{}').model).toBe('grok-4-fast');
|
|
1713
|
-
expect(proxy.stats().liveCalls).toBe(1);
|
|
1714
|
-
expect(modelExchanges[0]?.canonicalRequest.model).toBe('grok-4-fast');
|
|
1715
|
-
expect(routes).toEqual([
|
|
1716
|
-
expect.objectContaining({
|
|
1717
|
-
model: 'grok-4-fast',
|
|
1718
|
-
recorded: 'openai',
|
|
1719
|
-
target: 'openai',
|
|
1720
|
-
crossProvider: false,
|
|
1721
|
-
origin: `https://127.0.0.1:${model.port}`,
|
|
1722
|
-
}),
|
|
1723
|
-
]);
|
|
1724
|
-
});
|
|
1725
|
-
|
|
1726
|
-
it('counts a TLS-intercepted live call even when --model is unchanged', async () => {
|
|
1727
|
-
proxy = await createProxy({
|
|
1728
|
-
mode: 'hybrid',
|
|
1729
|
-
exchanges: [],
|
|
1730
|
-
forkAt: 0,
|
|
1731
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
1732
|
-
tls: {
|
|
1733
|
-
ca: runCa,
|
|
1734
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1735
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1736
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1737
|
-
},
|
|
1738
|
-
});
|
|
1739
|
-
|
|
1740
|
-
const response = await postInterceptedChat(proxy);
|
|
1741
|
-
expect(response.status).toBe(200);
|
|
1742
|
-
expect(JSON.parse(originSawChatBody ?? '{}').model).toBe('grok-4');
|
|
1743
|
-
expect(proxy.stats().liveCalls).toBe(1);
|
|
1744
|
-
expect(modelExchanges).toHaveLength(1);
|
|
1745
|
-
});
|
|
1746
|
-
|
|
1747
|
-
it('refuses a cross-provider --model on a TLS-intercepted fork instead of calling the old one', async () => {
|
|
1748
|
-
proxy = await createProxy({
|
|
1749
|
-
mode: 'hybrid',
|
|
1750
|
-
exchanges: [],
|
|
1751
|
-
forkAt: 0,
|
|
1752
|
-
forkModel: 'claude-haiku-4-5',
|
|
1753
|
-
onExchange: (e) => void modelExchanges.push(e),
|
|
1754
|
-
tls: {
|
|
1755
|
-
ca: runCa,
|
|
1756
|
-
hosts: [`127.0.0.1:${model.port}`],
|
|
1757
|
-
trustedOriginCerts: [originCa.certPem],
|
|
1758
|
-
onNetExchange: (e) => void netExchanges.push(e),
|
|
1759
|
-
},
|
|
1760
|
-
});
|
|
1761
|
-
|
|
1762
|
-
const response = await postInterceptedChat(proxy);
|
|
1763
|
-
expect(response.status).toBe(400);
|
|
1764
|
-
expect(response.body).toMatch(/claude-haiku-4-5/);
|
|
1765
|
-
expect(response.body).toMatch(/cannot leave the host/i);
|
|
1766
|
-
expect(originSawChatBody).toBeUndefined();
|
|
1767
|
-
expect(proxy.stats().liveCalls).toBe(0);
|
|
1768
|
-
});
|
|
1769
|
-
});
|