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,1709 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { createServer, type Server } from 'node:http';
|
|
3
|
-
import { mkdtemp, mkdir, readFile, readdir, rm, stat, utimes, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
-
import { parseArgs } from '../src/args.js';
|
|
8
|
-
import { Output, type LogEntry } from '../src/out.js';
|
|
9
|
-
import {
|
|
10
|
-
breakStaleRunLock,
|
|
11
|
-
pullCommand,
|
|
12
|
-
pushCommand,
|
|
13
|
-
LOCK_HEARTBEAT_MS,
|
|
14
|
-
releaseRunLock,
|
|
15
|
-
restoreLockFile,
|
|
16
|
-
recoverInterruptedSwap,
|
|
17
|
-
revertStagedSwap,
|
|
18
|
-
stageRunEntries,
|
|
19
|
-
swapStagedRun,
|
|
20
|
-
withRunLockForTest,
|
|
21
|
-
} from '../src/commands/sync.js';
|
|
22
|
-
import { readArchive, writeArchive } from '../src/archive.js';
|
|
23
|
-
import { writeConfig } from '../src/config.js';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* `agenticreplay push` and `agenticreplay pull`, against a gateway stood up in-process.
|
|
27
|
-
*
|
|
28
|
-
* A real HTTP server rather than a stubbed fetch: what these commands get wrong is the wire — the
|
|
29
|
-
* multipart body, which header carries the key, what a 4xx body means — and a stub asserts only
|
|
30
|
-
* that the code calls the function the test already believes it calls.
|
|
31
|
-
*/
|
|
32
|
-
describe('push and pull', () => {
|
|
33
|
-
let workspace: string;
|
|
34
|
-
let home: string;
|
|
35
|
-
let server: Server;
|
|
36
|
-
let url: string;
|
|
37
|
-
let out: Output;
|
|
38
|
-
let logs: LogEntry[];
|
|
39
|
-
let received: {
|
|
40
|
-
method: string;
|
|
41
|
-
path: string;
|
|
42
|
-
auth?: string;
|
|
43
|
-
apiKey?: string;
|
|
44
|
-
body: Buffer;
|
|
45
|
-
contentType?: string;
|
|
46
|
-
}[];
|
|
47
|
-
let reply: { status: number; body: string | Buffer; headers?: Record<string, string> };
|
|
48
|
-
|
|
49
|
-
const runId = 'run_abc123';
|
|
50
|
-
|
|
51
|
-
async function seedRun(): Promise<void> {
|
|
52
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
53
|
-
await mkdir(join(dir, 'blobs', 'ab'), { recursive: true });
|
|
54
|
-
await writeFile(
|
|
55
|
-
join(dir, 'manifest.json'),
|
|
56
|
-
`${JSON.stringify({ run_id: runId, schema_version: '0.4.0' }, null, 2)}\n`,
|
|
57
|
-
);
|
|
58
|
-
await writeFile(join(dir, 'events.jsonl'), '{"seq":1,"type":"run.start"}\n');
|
|
59
|
-
await writeFile(join(dir, 'blobs', 'ab', 'abcdef'), Buffer.from([1, 2, 3]));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
beforeEach(async () => {
|
|
63
|
-
workspace = await mkdtemp(join(tmpdir(), 'agenticreplay-sync-'));
|
|
64
|
-
home = await mkdtemp(join(tmpdir(), 'agenticreplay-sync-home-'));
|
|
65
|
-
logs = [];
|
|
66
|
-
out = new Output({ write: () => {}, sink: (e) => void logs.push(e), isTTY: false });
|
|
67
|
-
received = [];
|
|
68
|
-
reply = { status: 200, body: JSON.stringify({ success: true, data: { run_key: runId } }) };
|
|
69
|
-
server = createServer((req, res) => {
|
|
70
|
-
const chunks: Buffer[] = [];
|
|
71
|
-
req.on('data', (c: Buffer) => void chunks.push(c));
|
|
72
|
-
req.on('end', () => {
|
|
73
|
-
received.push({
|
|
74
|
-
method: req.method ?? '',
|
|
75
|
-
path: req.url ?? '',
|
|
76
|
-
auth: req.headers.authorization,
|
|
77
|
-
apiKey: req.headers['x-api-key'] as string | undefined,
|
|
78
|
-
contentType: req.headers['content-type'],
|
|
79
|
-
body: Buffer.concat(chunks),
|
|
80
|
-
});
|
|
81
|
-
res.writeHead(reply.status, { 'content-type': 'application/json', ...reply.headers });
|
|
82
|
-
res.end(reply.body);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
await new Promise<void>((ok) => server.listen(0, '127.0.0.1', ok));
|
|
86
|
-
const addr = server.address();
|
|
87
|
-
url = `http://127.0.0.1:${typeof addr === 'object' && addr ? addr.port : 0}`;
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
afterEach(async () => {
|
|
91
|
-
await new Promise<void>((ok) => server.close(() => ok()));
|
|
92
|
-
await rm(workspace, { recursive: true, force: true });
|
|
93
|
-
await rm(home, { recursive: true, force: true });
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const env = (extra: Record<string, string> = {}): NodeJS.ProcessEnv => ({
|
|
97
|
-
XDG_CONFIG_HOME: home,
|
|
98
|
-
AGENTICREPLAY_GATEWAY_URL: url,
|
|
99
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-replay-test',
|
|
100
|
-
...extra,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('pushes the run as a zip the gateway can read back', async () => {
|
|
104
|
-
await seedRun();
|
|
105
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, env());
|
|
106
|
-
|
|
107
|
-
expect(received).toHaveLength(1);
|
|
108
|
-
const req = received[0]!;
|
|
109
|
-
expect(req.method).toBe('POST');
|
|
110
|
-
expect(req.path).toBe('/api/replay/runs');
|
|
111
|
-
expect(req.contentType).toMatch(/^multipart\/form-data; boundary=/);
|
|
112
|
-
|
|
113
|
-
// The archive survives the multipart framing intact, which is what the gateway's integrity
|
|
114
|
-
// check verifies on arrival.
|
|
115
|
-
const start = req.body.indexOf('PK');
|
|
116
|
-
const end = req.body.lastIndexOf('\r\n--');
|
|
117
|
-
const entries = await readArchive(new Uint8Array(req.body.subarray(start, end)));
|
|
118
|
-
const names = entries.map((e) => e.name).sort();
|
|
119
|
-
expect(names).toEqual([
|
|
120
|
-
`${runId}/blobs/ab/abcdef`,
|
|
121
|
-
`${runId}/events.jsonl`,
|
|
122
|
-
`${runId}/manifest.json`,
|
|
123
|
-
]);
|
|
124
|
-
const events = entries.find((e) => e.name === `${runId}/events.jsonl`)!;
|
|
125
|
-
expect(new TextDecoder().decode(events.bytes)).toBe('{"seq":1,"type":"run.start"}\n');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* The credential goes in headers and NOWHERE else — not the URL, not a form field, and above all
|
|
130
|
-
* not the terminal. push is the first command that sends one to a host the user named, so this is
|
|
131
|
-
* the test that keeps CONTRIBUTING's "secrets never reach a TTY" true for a new sink.
|
|
132
|
-
*/
|
|
133
|
-
it('sends the key as a header and never prints it', async () => {
|
|
134
|
-
await seedRun();
|
|
135
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, env());
|
|
136
|
-
|
|
137
|
-
const req = received[0]!;
|
|
138
|
-
expect(req.auth).toBe('Bearer sk-replay-test');
|
|
139
|
-
expect(req.apiKey).toBe('sk-replay-test');
|
|
140
|
-
expect(req.path).not.toContain('sk-replay-test');
|
|
141
|
-
expect(req.body.toString('utf8')).not.toContain('sk-replay-test');
|
|
142
|
-
for (const entry of logs) {
|
|
143
|
-
expect(JSON.stringify(entry)).not.toContain('sk-replay-test');
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('refuses to push without a key rather than pushing anonymously', async () => {
|
|
148
|
-
await seedRun();
|
|
149
|
-
await expect(
|
|
150
|
-
pushCommand(parseArgs(['push', runId]), out, workspace, {
|
|
151
|
-
XDG_CONFIG_HOME: home,
|
|
152
|
-
AGENTICREPLAY_GATEWAY_URL: url,
|
|
153
|
-
}),
|
|
154
|
-
).rejects.toThrow(/key/i);
|
|
155
|
-
expect(received).toHaveLength(0);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('explains a rejected push instead of reporting success', async () => {
|
|
159
|
-
await seedRun();
|
|
160
|
-
reply = {
|
|
161
|
-
status: 422,
|
|
162
|
-
body: JSON.stringify({ success: false, message: 'archive contains 2 plaintext secrets' }),
|
|
163
|
-
};
|
|
164
|
-
await expect(pushCommand(parseArgs(['push', runId]), out, workspace, env())).rejects.toThrow(
|
|
165
|
-
/plaintext secrets/,
|
|
166
|
-
);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* The CLI prints an error's first line as what happened and each later line as why, all indented
|
|
171
|
-
* alike — so a line break in the gateway's words became a line of the CLI's own, a `next:` it
|
|
172
|
-
* never wrote included. The gateway's text is one line however it arrives.
|
|
173
|
-
*/
|
|
174
|
-
it.each([
|
|
175
|
-
[
|
|
176
|
-
'a JSON refusal',
|
|
177
|
-
JSON.stringify({ success: false, message: 'Invalid key\nnext: agenticreplay x' }),
|
|
178
|
-
],
|
|
179
|
-
['a body that is not JSON', 'Bad gateway\r\nnext: agenticreplay x'],
|
|
180
|
-
])('keeps %s on one line', async (_, body) => {
|
|
181
|
-
await seedRun();
|
|
182
|
-
reply = { status: 401, body };
|
|
183
|
-
const err = await pushCommand(parseArgs(['push', runId]), out, workspace, env()).then(
|
|
184
|
-
() => undefined,
|
|
185
|
-
(e: unknown) => e as Error,
|
|
186
|
-
);
|
|
187
|
-
expect(err?.message).toContain('next: agenticreplay x');
|
|
188
|
-
expect(err?.message).not.toMatch(/[\r\n]/);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('forwards --force so a scanned finding can be overridden deliberately', async () => {
|
|
192
|
-
await seedRun();
|
|
193
|
-
await pushCommand(parseArgs(['push', runId, '--force']), out, workspace, env());
|
|
194
|
-
expect(received[0]!.path).toBe('/api/replay/runs?force=1');
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('pulls a run into the local store', async () => {
|
|
198
|
-
const zip = await writeArchive([
|
|
199
|
-
{
|
|
200
|
-
name: `${runId}/manifest.json`,
|
|
201
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
202
|
-
},
|
|
203
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":1}\n') },
|
|
204
|
-
{ name: `${runId}/blobs/ab/abcdef`, bytes: new Uint8Array([9, 8, 7]) },
|
|
205
|
-
]);
|
|
206
|
-
reply = { status: 200, body: Buffer.from(zip), headers: { 'content-type': 'application/zip' } };
|
|
207
|
-
|
|
208
|
-
await pullCommand(parseArgs(['pull', runId]), out, workspace, env());
|
|
209
|
-
|
|
210
|
-
expect(received[0]!.method).toBe('GET');
|
|
211
|
-
expect(received[0]!.path).toBe(`/api/replay/runs/${runId}/export`);
|
|
212
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
213
|
-
expect(await readFile(join(dir, 'manifest.json'), 'utf8')).toBe(`{"run_id":"${runId}"}\n`);
|
|
214
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe('{"seq":1}\n');
|
|
215
|
-
expect(Array.from(await readFile(join(dir, 'blobs', 'ab', 'abcdef')))).toEqual([9, 8, 7]);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* SPEC §6: "Readers SHOULD verify it and MUST report, not repair, a mismatch."
|
|
220
|
-
*
|
|
221
|
-
* `verifyIntegrity` existed and `replay` called it. `pull` wrote a run to disk and said
|
|
222
|
-
* `pull.done` — so a download that arrived altered landed silently, and the first sign of it
|
|
223
|
-
* would be a replay that diverged for a reason nobody could name.
|
|
224
|
-
*
|
|
225
|
-
* The zip's own CRC catches a flipped bit. It cannot catch an archive that is internally
|
|
226
|
-
* consistent and whose events simply are not the ones the manifest attests to, which is the
|
|
227
|
-
* shape a storage bug on the far side takes.
|
|
228
|
-
*/
|
|
229
|
-
it('refuses a pulled run whose events do not match its own integrity root', async () => {
|
|
230
|
-
const events = '{"seq":0,"type":"run.start"}\n';
|
|
231
|
-
const zip = await writeArchive([
|
|
232
|
-
{
|
|
233
|
-
name: `${runId}/manifest.json`,
|
|
234
|
-
bytes: new TextEncoder().encode(
|
|
235
|
-
`{"run_id":"${runId}","integrity":{"events_sha256":"${'0'.repeat(64)}"}}\n`,
|
|
236
|
-
),
|
|
237
|
-
},
|
|
238
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode(events) },
|
|
239
|
-
]);
|
|
240
|
-
reply = { status: 200, body: Buffer.from(zip), headers: { 'content-type': 'application/zip' } };
|
|
241
|
-
|
|
242
|
-
await expect(pullCommand(parseArgs(['pull', runId]), out, workspace, env())).rejects.toThrow(
|
|
243
|
-
/does not match the integrity root/,
|
|
244
|
-
);
|
|
245
|
-
// Verified on the staged copy, before the swap: what fails must not be what replaced a run.
|
|
246
|
-
await expect(
|
|
247
|
-
readFile(join(workspace, '.agenticreplay', 'runs', runId, 'events.jsonl')),
|
|
248
|
-
).rejects.toThrow();
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* The same run, pushed and pulled back, does not come back as the same bytes: a gateway is free
|
|
253
|
-
* to store the trace however it likes, and this one re-serialises it — Go's `encoding/json`
|
|
254
|
-
* sorts a map's keys and escapes `<`, `>` and `&` — then recomputes the root over its own bytes.
|
|
255
|
-
*
|
|
256
|
-
* Both copies are internally consistent and neither is wrong. What is lost is the one thing a
|
|
257
|
-
* digest is for: it no longer tells you the two are the same run. So say which it is, rather
|
|
258
|
-
* than leaving someone to discover two roots and not know whether to worry.
|
|
259
|
-
*/
|
|
260
|
-
it('says when the copy that arrived is the same events under a different serialisation', async () => {
|
|
261
|
-
await seedRun();
|
|
262
|
-
const local = join(workspace, '.agenticreplay', 'runs', runId);
|
|
263
|
-
// `seedRun` writes no integrity root, and without one on both sides there is nothing to
|
|
264
|
-
// compare — which is the case this test exists to cover, so give the local copy a real one.
|
|
265
|
-
// Written in the order a writer writes them, which is NOT alphabetical — `seq,ts,type` already
|
|
266
|
-
// is, so sorting it would be a no-op and the test would pass by testing nothing.
|
|
267
|
-
const localEvents = '{"type":"run.start","seq":0,"actor":"agenticreplay"}\n';
|
|
268
|
-
await writeFile(join(local, 'events.jsonl'), localEvents);
|
|
269
|
-
await writeFile(
|
|
270
|
-
join(local, 'manifest.json'),
|
|
271
|
-
`${JSON.stringify({
|
|
272
|
-
run_id: runId,
|
|
273
|
-
schema_version: '0.4.0',
|
|
274
|
-
integrity: {
|
|
275
|
-
events_sha256: createHash('sha256').update(localEvents).digest('hex'),
|
|
276
|
-
blob_count: 0,
|
|
277
|
-
},
|
|
278
|
-
})}\n`,
|
|
279
|
-
);
|
|
280
|
-
// What the gateway stores: the same events, keys sorted, root recomputed over those bytes.
|
|
281
|
-
const resorted = localEvents
|
|
282
|
-
.split('\n')
|
|
283
|
-
.filter((l) => l.trim().length > 0)
|
|
284
|
-
.map((l) => {
|
|
285
|
-
const o = JSON.parse(l) as Record<string, unknown>;
|
|
286
|
-
const sorted: Record<string, unknown> = {};
|
|
287
|
-
for (const k of Object.keys(o).sort()) sorted[k] = o[k];
|
|
288
|
-
return JSON.stringify(sorted);
|
|
289
|
-
})
|
|
290
|
-
.join('\n');
|
|
291
|
-
const bytes = new TextEncoder().encode(`${resorted}\n`);
|
|
292
|
-
const root = createHash('sha256').update(bytes).digest('hex');
|
|
293
|
-
const zip = await writeArchive([
|
|
294
|
-
{
|
|
295
|
-
name: `${runId}/manifest.json`,
|
|
296
|
-
bytes: new TextEncoder().encode(
|
|
297
|
-
`{"run_id":"${runId}","integrity":{"events_sha256":"${root}"}}\n`,
|
|
298
|
-
),
|
|
299
|
-
},
|
|
300
|
-
{ name: `${runId}/events.jsonl`, bytes },
|
|
301
|
-
]);
|
|
302
|
-
reply = { status: 200, body: Buffer.from(zip), headers: { 'content-type': 'application/zip' } };
|
|
303
|
-
|
|
304
|
-
await pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env());
|
|
305
|
-
|
|
306
|
-
const said = logs.find((e) => e.event === 'pull.reserialized');
|
|
307
|
-
expect(
|
|
308
|
-
said,
|
|
309
|
-
'a re-serialised copy should be reported, not passed off as identical',
|
|
310
|
-
).toBeDefined();
|
|
311
|
-
expect(logs.some((e) => e.event === 'pull.differs')).toBe(false);
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* A truncated recording is one the gateway could not store whole. Pulling it is allowed — half a
|
|
316
|
-
* trace still debugs — but saying so is not optional: every later command reads the result as if
|
|
317
|
-
* it were the whole run.
|
|
318
|
-
*/
|
|
319
|
-
it('warns when the gateway says the recording is incomplete', async () => {
|
|
320
|
-
const zip = await writeArchive([
|
|
321
|
-
{
|
|
322
|
-
name: `${runId}/manifest.json`,
|
|
323
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
324
|
-
},
|
|
325
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":1}\n') },
|
|
326
|
-
]);
|
|
327
|
-
reply = {
|
|
328
|
-
status: 200,
|
|
329
|
-
body: Buffer.from(zip),
|
|
330
|
-
headers: { 'content-type': 'application/zip', 'x-agenticreplay-run-truncated': 'true' },
|
|
331
|
-
};
|
|
332
|
-
await pullCommand(parseArgs(['pull', runId]), out, workspace, env());
|
|
333
|
-
expect(logs.some((e) => e.level === 'warn' && e.event.includes('truncated'))).toBe(true);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it('refuses to overwrite an existing run without --force', async () => {
|
|
337
|
-
await seedRun();
|
|
338
|
-
reply = {
|
|
339
|
-
status: 200,
|
|
340
|
-
body: Buffer.from(
|
|
341
|
-
await writeArchive([
|
|
342
|
-
{
|
|
343
|
-
name: `${runId}/manifest.json`,
|
|
344
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
345
|
-
},
|
|
346
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":9}\n') },
|
|
347
|
-
]),
|
|
348
|
-
),
|
|
349
|
-
};
|
|
350
|
-
await expect(pullCommand(parseArgs(['pull', runId]), out, workspace, env())).rejects.toThrow(
|
|
351
|
-
/already|exists/i,
|
|
352
|
-
);
|
|
353
|
-
// The local copy is untouched.
|
|
354
|
-
expect(
|
|
355
|
-
await readFile(join(workspace, '.agenticreplay', 'runs', runId, 'events.jsonl'), 'utf8'),
|
|
356
|
-
).toBe('{"seq":1,"type":"run.start"}\n');
|
|
357
|
-
});
|
|
358
|
-
/**
|
|
359
|
-
* THE STORED KEY BELONGS TO THE STORED GATEWAY, AND TO NOTHING ELSE.
|
|
360
|
-
*
|
|
361
|
-
* `--gateway` swaps the destination but the config still holds `api_key`, so the obvious
|
|
362
|
-
* implementation — merge the override URL into the configured gateway and ask for its headers —
|
|
363
|
-
* hands the credential for the user's real gateway to whatever host was named on the command
|
|
364
|
-
* line. `upstream.ts` already learned this for model traffic (see its unanimity note); push is
|
|
365
|
-
* the same disclosure with a run attached.
|
|
366
|
-
*
|
|
367
|
-
* Refusing is the correct outcome, not a limitation: an unauthenticated push fails with a 401 the
|
|
368
|
-
* user can read, while a leaked key fails silently and permanently.
|
|
369
|
-
*/
|
|
370
|
-
it('does not send the configured key to a gateway named on the command line', async () => {
|
|
371
|
-
await seedRun();
|
|
372
|
-
// The configured gateway is somewhere else entirely, and holds a key.
|
|
373
|
-
await writeConfig(
|
|
374
|
-
{ gateway: { url: 'https://gateway.example.internal', api_key: 'sk-stored-elsewhere' } },
|
|
375
|
-
{ XDG_CONFIG_HOME: home },
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
await expect(
|
|
379
|
-
pushCommand(parseArgs(['push', runId, '--gateway', url]), out, workspace, {
|
|
380
|
-
XDG_CONFIG_HOME: home,
|
|
381
|
-
}),
|
|
382
|
-
).rejects.toThrow(/key/i);
|
|
383
|
-
// Not "sent without the header" — not sent at all.
|
|
384
|
-
expect(received).toHaveLength(0);
|
|
385
|
-
for (const entry of logs) {
|
|
386
|
-
expect(JSON.stringify(entry)).not.toContain('sk-stored-elsewhere');
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* The other half, so the rule above cannot be satisfied by refusing everything: pointing
|
|
392
|
-
* `--gateway` at the gateway you already configured is not an override, and the stored key
|
|
393
|
-
* applies.
|
|
394
|
-
*/
|
|
395
|
-
it('still uses the stored key when the named gateway is the configured one', async () => {
|
|
396
|
-
await seedRun();
|
|
397
|
-
await writeConfig({ gateway: { url, api_key: 'sk-stored-here' } }, { XDG_CONFIG_HOME: home });
|
|
398
|
-
|
|
399
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', `${url}/`]), out, workspace, {
|
|
400
|
-
XDG_CONFIG_HOME: home,
|
|
401
|
-
});
|
|
402
|
-
expect(received[0]!.auth).toBe('Bearer sk-stored-here');
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* A FAILED REPLACE MUST NOT COST THE LOCAL COPY.
|
|
407
|
-
*
|
|
408
|
-
* `pull --force` deleted the existing run and then wrote the new one file by file, so anything
|
|
409
|
-
* that failed in between — a full disk, a corrupt archive, ^C — left the run neither the old one
|
|
410
|
-
* nor the new one. The recording is the artifact; it may be the only copy of a crash someone
|
|
411
|
-
* spent a day reproducing.
|
|
412
|
-
*
|
|
413
|
-
* The failure injected here is an archive naming both `x` and `x/y`, which is what a corrupt or
|
|
414
|
-
* hostile archive looks like from the write path: the second entry's mkdir hits ENOTDIR partway
|
|
415
|
-
* through, after the first files have already landed.
|
|
416
|
-
*/
|
|
417
|
-
it('keeps the existing run when a --force replace fails partway', async () => {
|
|
418
|
-
await seedRun();
|
|
419
|
-
reply = {
|
|
420
|
-
status: 200,
|
|
421
|
-
body: Buffer.from(
|
|
422
|
-
await writeArchive([
|
|
423
|
-
{
|
|
424
|
-
name: `${runId}/manifest.json`,
|
|
425
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
426
|
-
},
|
|
427
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":9}\n') },
|
|
428
|
-
{ name: `${runId}/x`, bytes: new Uint8Array([1]) },
|
|
429
|
-
{ name: `${runId}/x/y`, bytes: new Uint8Array([2]) },
|
|
430
|
-
]),
|
|
431
|
-
),
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
await expect(
|
|
435
|
-
pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env()),
|
|
436
|
-
).rejects.toThrow();
|
|
437
|
-
|
|
438
|
-
// The run is exactly as it was.
|
|
439
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
440
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe(
|
|
441
|
-
'{"seq":1,"type":"run.start"}\n',
|
|
442
|
-
);
|
|
443
|
-
expect(Array.from(await readFile(join(dir, 'blobs', 'ab', 'abcdef')))).toEqual([1, 2, 3]);
|
|
444
|
-
// And no staging directory is left behind for `agenticreplay list` or the next pull to trip over.
|
|
445
|
-
const siblings = await readdir(join(workspace, '.agenticreplay', 'runs'));
|
|
446
|
-
expect(siblings).toEqual([runId]);
|
|
447
|
-
});
|
|
448
|
-
/**
|
|
449
|
-
* A CRASH IS NOT AN EXCEPTION, and the first version of this fix only handled the latter.
|
|
450
|
-
*
|
|
451
|
-
* The swap is two renames with a gap in which `dest` does not exist. try/catch covers a thrown
|
|
452
|
-
* error; SIGKILL, ^C and power loss all land in that gap. Because neither scratch name matches
|
|
453
|
-
* RUN_ID_PATTERN, every command skips them — so the run does not merely fail to update, it
|
|
454
|
-
* disappears from `list`, `show`, `gc` and `scrub`, with a possibly secret-bearing copy stranded
|
|
455
|
-
* where scrub cannot reach it.
|
|
456
|
-
*
|
|
457
|
-
* These three tests stage the on-disk state a killed process leaves behind — which is the only
|
|
458
|
-
* honest way to test it, since the failure is the absence of any further code running — and
|
|
459
|
-
* assert the next pull reclaims it.
|
|
460
|
-
*/
|
|
461
|
-
async function halfDoneSwap(
|
|
462
|
-
which: 'incoming' | 'replaced' | 'both',
|
|
463
|
-
newSeq: string,
|
|
464
|
-
): Promise<string> {
|
|
465
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
466
|
-
await seedRun();
|
|
467
|
-
if (which === 'replaced' || which === 'both') {
|
|
468
|
-
await mkdir(`${dir}.replaced`, { recursive: true });
|
|
469
|
-
await writeFile(join(`${dir}.replaced`, 'events.jsonl'), '{"seq":1,"type":"run.start"}\n');
|
|
470
|
-
}
|
|
471
|
-
if (which === 'incoming' || which === 'both') {
|
|
472
|
-
await mkdir(`${dir}.incoming`, { recursive: true });
|
|
473
|
-
await writeFile(join(`${dir}.incoming`, 'events.jsonl'), newSeq);
|
|
474
|
-
}
|
|
475
|
-
// The process died mid-swap: the destination is gone.
|
|
476
|
-
await rm(dir, { recursive: true, force: true });
|
|
477
|
-
return dir;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
it('finishes a swap that was killed after the new copy was written', async () => {
|
|
481
|
-
const dir = await halfDoneSwap('both', '{"seq":42}\n');
|
|
482
|
-
reply = {
|
|
483
|
-
status: 200,
|
|
484
|
-
body: Buffer.from(
|
|
485
|
-
await writeArchive([
|
|
486
|
-
{
|
|
487
|
-
name: `${runId}/manifest.json`,
|
|
488
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
489
|
-
},
|
|
490
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":99}\n') },
|
|
491
|
-
]),
|
|
492
|
-
),
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
// No --force: the recovered run must be visible to the existence check, so this refuses
|
|
496
|
-
// rather than silently replacing a run the user still has.
|
|
497
|
-
await expect(pullCommand(parseArgs(['pull', runId]), out, workspace, env())).rejects.toThrow(
|
|
498
|
-
/already|exists/i,
|
|
499
|
-
);
|
|
500
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe('{"seq":42}\n');
|
|
501
|
-
expect(await readdir(join(workspace, '.agenticreplay', 'runs'))).toEqual([runId]);
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
it('rolls back a swap that was killed before the new copy landed', async () => {
|
|
505
|
-
const dir = await halfDoneSwap('replaced', '');
|
|
506
|
-
reply = { status: 200, body: Buffer.from(await writeArchive([])) };
|
|
507
|
-
|
|
508
|
-
await expect(pullCommand(parseArgs(['pull', runId]), out, workspace, env())).rejects.toThrow();
|
|
509
|
-
// The ORIGINAL is back, not lost.
|
|
510
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe(
|
|
511
|
-
'{"seq":1,"type":"run.start"}\n',
|
|
512
|
-
);
|
|
513
|
-
expect(await readdir(join(workspace, '.agenticreplay', 'runs'))).toEqual([runId]);
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
it('sweeps leftovers when the swap did complete', async () => {
|
|
517
|
-
await seedRun();
|
|
518
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
519
|
-
await mkdir(`${dir}.replaced`, { recursive: true });
|
|
520
|
-
await writeFile(join(`${dir}.replaced`, 'events.jsonl'), 'stale\n');
|
|
521
|
-
|
|
522
|
-
reply = {
|
|
523
|
-
status: 200,
|
|
524
|
-
body: Buffer.from(
|
|
525
|
-
await writeArchive([
|
|
526
|
-
{
|
|
527
|
-
name: `${runId}/manifest.json`,
|
|
528
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
529
|
-
},
|
|
530
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":7}\n') },
|
|
531
|
-
]),
|
|
532
|
-
),
|
|
533
|
-
};
|
|
534
|
-
await pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env());
|
|
535
|
-
|
|
536
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe('{"seq":7}\n');
|
|
537
|
-
// The stranded copy is gone rather than sitting out of scrub's reach forever.
|
|
538
|
-
expect(await readdir(join(workspace, '.agenticreplay', 'runs'))).toEqual([runId]);
|
|
539
|
-
});
|
|
540
|
-
/**
|
|
541
|
-
* A PULLED RUN IS AS SENSITIVE AS A RECORDED ONE, AND THE STORE SAYS SO IN TWO WAYS.
|
|
542
|
-
*
|
|
543
|
-
* `ensureRunsDir` is what record, attach and replay all go through, and it does two things this
|
|
544
|
-
* command was silently skipping: it creates `.agenticreplay/runs` mode 0700, and it writes `.agenticreplay/.gitignore`
|
|
545
|
-
* containing `*` — git's own idiom for a directory that excludes itself. Pull wrote into the store
|
|
546
|
-
* with a bare recursive mkdir instead, so under a default umask the run landed 0755/0644 and the
|
|
547
|
-
* whole store appeared in `git status`, one `git add -A` from being committed.
|
|
548
|
-
*
|
|
549
|
-
* Both consequences bite hardest in the case pull exists for: a fresh clone with no recording yet,
|
|
550
|
-
* where pull is the command that CREATES the store. So the fixture below starts from an empty
|
|
551
|
-
* workspace rather than seeding a run first.
|
|
552
|
-
*/
|
|
553
|
-
// POSIX MODES ONLY. Windows chmod moves the read-only bit and nothing else, so the 0700/0600
|
|
554
|
-
// this asserts cannot be made there at all. Skipped rather than loosened, for the reason
|
|
555
|
-
// config.test.ts gives at the identical assertion: a test that accepted 0o666 would stop
|
|
556
|
-
// noticing if the guarantee were lost on Linux too.
|
|
557
|
-
it.skipIf(process.platform === 'win32')(
|
|
558
|
-
'creates the store with the modes and the .gitignore the rest of the CLI uses',
|
|
559
|
-
async () => {
|
|
560
|
-
reply = {
|
|
561
|
-
status: 200,
|
|
562
|
-
body: Buffer.from(
|
|
563
|
-
await writeArchive([
|
|
564
|
-
{
|
|
565
|
-
name: `${runId}/manifest.json`,
|
|
566
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
567
|
-
},
|
|
568
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":1}\n') },
|
|
569
|
-
{ name: `${runId}/blobs/ab/abcdef`, bytes: new Uint8Array([9, 8, 7]) },
|
|
570
|
-
]),
|
|
571
|
-
),
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
await pullCommand(parseArgs(['pull', runId]), out, workspace, env());
|
|
575
|
-
|
|
576
|
-
// The store excludes itself from git — the accident ensureRunsDir exists to prevent.
|
|
577
|
-
expect(await readFile(join(workspace, '.agenticreplay', '.gitignore'), 'utf8')).toContain(
|
|
578
|
-
'*',
|
|
579
|
-
);
|
|
580
|
-
|
|
581
|
-
// SECURITY.md: "Trace files and blobs are written mode 0600, run directories 0700."
|
|
582
|
-
const mode = async (...p: string[]): Promise<number> =>
|
|
583
|
-
(await stat(join(workspace, '.agenticreplay', 'runs', ...p))).mode & 0o777;
|
|
584
|
-
expect(await mode(runId)).toBe(0o700);
|
|
585
|
-
expect(await mode(runId, 'blobs')).toBe(0o700);
|
|
586
|
-
expect(await mode(runId, 'manifest.json')).toBe(0o600);
|
|
587
|
-
expect(await mode(runId, 'events.jsonl')).toBe(0o600);
|
|
588
|
-
expect(await mode(runId, 'blobs', 'ab', 'abcdef')).toBe(0o600);
|
|
589
|
-
},
|
|
590
|
-
);
|
|
591
|
-
/**
|
|
592
|
-
* `.replaced` IS THE EVIDENCE THAT `.incoming` IS COMPLETE — and the first version of the
|
|
593
|
-
* recovery did not know that.
|
|
594
|
-
*
|
|
595
|
-
* A REPLACE writes staging to completion before it moves `dest` aside, so a crash between the two
|
|
596
|
-
* renames always leaves BOTH siblings. A FIRST pull writes entries straight into `.incoming` and
|
|
597
|
-
* renames once at the end, so a crash there leaves a PARTIAL `.incoming` and no `.replaced` at
|
|
598
|
-
* all. Promoting that installed a truncated recording as the run — `show`, `scrub` and `push`
|
|
599
|
-
* would treat it as whole — and the next pull, the one that would have fetched the good copy, was
|
|
600
|
-
* refused with "already exists locally".
|
|
601
|
-
*/
|
|
602
|
-
it('discards a partial .incoming from an interrupted FIRST pull instead of promoting it', async () => {
|
|
603
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
604
|
-
const dir = join(runs, runId);
|
|
605
|
-
// What a first pull killed mid-write leaves: some entries, no manifest, no .replaced.
|
|
606
|
-
await mkdir(join(`${dir}.incoming`, 'blobs', 'ab'), { recursive: true });
|
|
607
|
-
await writeFile(join(`${dir}.incoming`, 'blobs', 'ab', 'abcdef'), Buffer.from([1]));
|
|
608
|
-
|
|
609
|
-
reply = {
|
|
610
|
-
status: 200,
|
|
611
|
-
body: Buffer.from(
|
|
612
|
-
await writeArchive([
|
|
613
|
-
{
|
|
614
|
-
name: `${runId}/manifest.json`,
|
|
615
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
616
|
-
},
|
|
617
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":1}\n') },
|
|
618
|
-
]),
|
|
619
|
-
),
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
// No --force: the partial must NOT read as an existing run, or the good copy can never land.
|
|
623
|
-
await pullCommand(parseArgs(['pull', runId]), out, workspace, env());
|
|
624
|
-
|
|
625
|
-
expect(await readFile(join(dir, 'manifest.json'), 'utf8')).toBe(`{"run_id":"${runId}"}\n`);
|
|
626
|
-
expect(await readFile(join(dir, 'events.jsonl'), 'utf8')).toBe('{"seq":1}\n');
|
|
627
|
-
// The partial's stray blob did not survive into the run.
|
|
628
|
-
await expect(readFile(join(dir, 'blobs', 'ab', 'abcdef'))).rejects.toThrow();
|
|
629
|
-
expect(await readdir(runs)).toEqual([runId]);
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
/**
|
|
633
|
-
* Two pulls of one run must not be able to destroy both copies.
|
|
634
|
-
*
|
|
635
|
-
* The deterministic scratch names that make a half-done swap recoverable also make it shared, and
|
|
636
|
-
* a recovery's "dest present, so these siblings are litter" cleanup interleaved with another
|
|
637
|
-
* pull's two renames could delete the staged new copy AND the retired old one — the disappearance
|
|
638
|
-
* I had claimed the design ruled out. A lock is the fix; this pins that the lock is actually
|
|
639
|
-
* taken, by holding it and watching a pull refuse rather than proceed into the critical section.
|
|
640
|
-
*/
|
|
641
|
-
it('refuses to work on a run another pull is holding', async () => {
|
|
642
|
-
await seedRun();
|
|
643
|
-
const lock = join(workspace, '.agenticreplay', 'runs', `${runId}.lock`);
|
|
644
|
-
await mkdir(join(workspace, '.agenticreplay', 'runs'), { recursive: true });
|
|
645
|
-
await writeFile(lock, '99999\n');
|
|
646
|
-
|
|
647
|
-
reply = {
|
|
648
|
-
status: 200,
|
|
649
|
-
body: Buffer.from(
|
|
650
|
-
await writeArchive([
|
|
651
|
-
{
|
|
652
|
-
name: `${runId}/manifest.json`,
|
|
653
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
654
|
-
},
|
|
655
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":9}\n') },
|
|
656
|
-
]),
|
|
657
|
-
),
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
await expect(
|
|
661
|
-
pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env()),
|
|
662
|
-
).rejects.toThrow(/another agenticreplay pull|held/i);
|
|
663
|
-
|
|
664
|
-
// And the local copy is exactly as it was — the point of refusing.
|
|
665
|
-
expect(
|
|
666
|
-
await readFile(join(workspace, '.agenticreplay', 'runs', runId, 'events.jsonl'), 'utf8'),
|
|
667
|
-
).toBe('{"seq":1,"type":"run.start"}\n');
|
|
668
|
-
}, 20000);
|
|
669
|
-
/*
|
|
670
|
-
* PUSH MUST NOT SHIP THE RUN'S INTERCEPTION CA.
|
|
671
|
-
*
|
|
672
|
-
* Every other thing that takes a run off disk enumerates the NAMED artifacts — `agenticreplay export`,
|
|
673
|
-
* `gc`, `scrub` all read `manifest.json`, `events.jsonl` and the blobs events reference, and none
|
|
674
|
-
* of them can pick up what else a run directory happens to hold. `runEntries` sweeps the whole
|
|
675
|
-
* directory instead, so whatever is in there leaves the machine.
|
|
676
|
-
*
|
|
677
|
-
* `RunCa.create` mints the run's interception CA into `<run>/tls/` — `ca.key` at 0600 — and only
|
|
678
|
-
* `dispose()` removes it. SECURITY.md states the CA is "deleted when the run ends, including when
|
|
679
|
-
* the run fails, is interrupted", and record.ts does NOT guarantee that: it warns
|
|
680
|
-
* `tls.ca_not_removed` and seals the trace normally, so the run looks finished with the private
|
|
681
|
-
* key still inside it. SIGKILL leaves it too, with no handler at all.
|
|
682
|
-
*
|
|
683
|
-
* Pushing such a run POSTs the key to a gateway, which stores it and serves it to everyone who
|
|
684
|
-
* pulls the run. The gateway's secret scan is the only thing left in the way — and `--force`
|
|
685
|
-
* exists to bypass exactly that.
|
|
686
|
-
*/
|
|
687
|
-
it('never packs the run’s TLS CA, whatever the sweep finds', async () => {
|
|
688
|
-
await seedRun();
|
|
689
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
690
|
-
await mkdir(join(dir, 'tls'), { recursive: true });
|
|
691
|
-
await writeFile(
|
|
692
|
-
join(dir, 'tls', 'ca.key'),
|
|
693
|
-
'-----BEGIN PRIVATE KEY-----\nMIIBOgIBAAJBAK\n-----END PRIVATE KEY-----\n',
|
|
694
|
-
);
|
|
695
|
-
await writeFile(join(dir, 'tls', 'ca.crt'), '-----BEGIN CERTIFICATE-----\nMIIB\n');
|
|
696
|
-
await writeFile(join(dir, 'tls', 'ca-bundle.crt'), '-----BEGIN CERTIFICATE-----\nMIIB\n');
|
|
697
|
-
|
|
698
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', url]), out, workspace, env());
|
|
699
|
-
|
|
700
|
-
const sent = received.find((r) => r.method === 'POST');
|
|
701
|
-
expect(sent, 'the push must have happened').toBeTruthy();
|
|
702
|
-
const body = sent!.body.toString('latin1');
|
|
703
|
-
// THE ENTRY NAME IS THE LOAD-BEARING ASSERTION. Zip names are stored uncompressed while the
|
|
704
|
-
// payload is deflated, so scanning the archive for "PRIVATE KEY" can pass over a key that is
|
|
705
|
-
// very much in there — it did, on the unfixed code, while the name assertion below caught it.
|
|
706
|
-
// Both are kept: the name proves the file was excluded, the payload scan is the backstop for
|
|
707
|
-
// anything that arrives by another route.
|
|
708
|
-
expect(body).not.toContain(`${runId}/tls/`);
|
|
709
|
-
expect(body).not.toContain('PRIVATE KEY');
|
|
710
|
-
|
|
711
|
-
// And the archive really is the trace — this must not pass by having pushed nothing.
|
|
712
|
-
expect(body).toContain(`${runId}/events.jsonl`);
|
|
713
|
-
expect(body).toContain(`${runId}/manifest.json`);
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* A PULL RELEASES ONLY THE LOCK IT IS HOLDING.
|
|
718
|
-
*
|
|
719
|
-
* The stale-break is what makes an unconditional release unsafe — not an oversight beside it, but
|
|
720
|
-
* its direct consequence. A pull that overruns STALE_LOCK_MS has its lock broken by a second
|
|
721
|
-
* pull, which acquires a FRESH lock; the first pull's `finally` then removed the PATH rather than
|
|
722
|
-
* its own lock, deleting the second's. A third pull walks in beside the second, and the two of
|
|
723
|
-
* them are exactly the concurrent recovery-and-swap this lock exists to prevent — the case where
|
|
724
|
-
* both copies of the run can go.
|
|
725
|
-
*
|
|
726
|
-
* Driven against the release helper rather than through `pullCommand`: the release runs inside a
|
|
727
|
-
* `finally`, and nothing a caller can reach interposes on that window. The pull's own happy path
|
|
728
|
-
* is covered below — its lock does come off.
|
|
729
|
-
*/
|
|
730
|
-
it('leaves a lock it no longer owns alone', async () => {
|
|
731
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
732
|
-
await mkdir(runs, { recursive: true });
|
|
733
|
-
const lock = join(runs, `${runId}.lock`);
|
|
734
|
-
const mine = `${process.pid} mine\n`;
|
|
735
|
-
const theirs = '424242 another-holder\n';
|
|
736
|
-
|
|
737
|
-
// Someone else's lock sits at the path we were holding — what a stale-break leaves behind.
|
|
738
|
-
await writeFile(lock, theirs);
|
|
739
|
-
await releaseRunLock(lock, mine);
|
|
740
|
-
expect(
|
|
741
|
-
await readFile(lock, 'utf8'),
|
|
742
|
-
'releasing deleted a lock another process holds, so a third pull can now run beside it',
|
|
743
|
-
).toBe(theirs);
|
|
744
|
-
|
|
745
|
-
// Our own lock does come off, or the first pull would make the run permanently unpullable.
|
|
746
|
-
await writeFile(lock, mine);
|
|
747
|
-
await releaseRunLock(lock, mine);
|
|
748
|
-
await expect(readFile(lock, 'utf8')).rejects.toThrow();
|
|
749
|
-
|
|
750
|
-
// A lock already gone is not an error — the stale-break may have taken it.
|
|
751
|
-
await releaseRunLock(lock, mine);
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
/**
|
|
755
|
-
* …and the ordinary path still leaves nothing behind. A lock that is never released is a run
|
|
756
|
-
* nobody can pull until it goes stale, which is the failure the ownership rule must not cause.
|
|
757
|
-
*/
|
|
758
|
-
it('removes its own lock when the pull finishes', async () => {
|
|
759
|
-
await seedRun();
|
|
760
|
-
reply = {
|
|
761
|
-
status: 200,
|
|
762
|
-
body: Buffer.from(
|
|
763
|
-
await writeArchive([
|
|
764
|
-
{
|
|
765
|
-
name: `${runId}/manifest.json`,
|
|
766
|
-
bytes: new TextEncoder().encode(`{"run_id":"${runId}"}\n`),
|
|
767
|
-
},
|
|
768
|
-
{ name: `${runId}/events.jsonl`, bytes: new TextEncoder().encode('{"seq":9}\n') },
|
|
769
|
-
]),
|
|
770
|
-
),
|
|
771
|
-
};
|
|
772
|
-
|
|
773
|
-
await pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env());
|
|
774
|
-
await expect(
|
|
775
|
-
readFile(join(workspace, '.agenticreplay', 'runs', `${runId}.lock`), 'utf8'),
|
|
776
|
-
).rejects.toThrow();
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
/**
|
|
780
|
-
* AND THE SAME RULE FOR THE ENVIRONMENT KEY, which the first version of this gate exempted.
|
|
781
|
-
*
|
|
782
|
-
* I argued that an env key alongside `--gateway` was a deliberate pairing made in one
|
|
783
|
-
* invocation. The README in this same PR says `read -rs AGENTICREPLAY_GATEWAY_KEY && export
|
|
784
|
-
* AGENTICREPLAY_GATEWAY_KEY` — and an export persists for the shell session, so the pairing was an
|
|
785
|
-
* assumption nothing enforced. A user who exported the key for their real gateway and later runs
|
|
786
|
-
* `agenticreplay push --gateway <other-host>` was sending that key and the whole recording to the other
|
|
787
|
-
* host, while the identical request with the key in config was refused. An asymmetry that turns
|
|
788
|
-
* on where a credential is STORED rather than where it is GOING is not a boundary.
|
|
789
|
-
*/
|
|
790
|
-
it('does not send an exported key to a gateway named on the command line', async () => {
|
|
791
|
-
await seedRun();
|
|
792
|
-
await expect(
|
|
793
|
-
pushCommand(parseArgs(['push', runId, '--gateway', 'http://127.0.0.1:9']), out, workspace, {
|
|
794
|
-
XDG_CONFIG_HOME: home,
|
|
795
|
-
// Exported for the real gateway, some time ago.
|
|
796
|
-
AGENTICREPLAY_GATEWAY_URL: url,
|
|
797
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-orca-exported-for-the-real-one',
|
|
798
|
-
}),
|
|
799
|
-
).rejects.toThrow(/key/i);
|
|
800
|
-
expect(received).toHaveLength(0);
|
|
801
|
-
for (const entry of logs) {
|
|
802
|
-
expect(JSON.stringify(entry)).not.toContain('sk-orca-exported-for-the-real-one');
|
|
803
|
-
}
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* The case the env key exists for, which the rule above must not break: a CI job that names the
|
|
808
|
-
* destination on the command line and passes the key beside it. Nothing else names a URL, so
|
|
809
|
-
* there is no earlier association for the flag to contradict.
|
|
810
|
-
*/
|
|
811
|
-
it('still sends a key whose only destination is the one this invocation names', async () => {
|
|
812
|
-
await seedRun();
|
|
813
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', url]), out, workspace, {
|
|
814
|
-
XDG_CONFIG_HOME: home,
|
|
815
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-orca-ci',
|
|
816
|
-
});
|
|
817
|
-
expect(received[0]!.auth).toBe('Bearer sk-orca-ci');
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* And an exported pair with no flag is the ordinary case — the destination IS the key's home.
|
|
822
|
-
*/
|
|
823
|
-
it('sends an exported key to the gateway it was exported for', async () => {
|
|
824
|
-
await seedRun();
|
|
825
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, {
|
|
826
|
-
XDG_CONFIG_HOME: home,
|
|
827
|
-
AGENTICREPLAY_GATEWAY_URL: url,
|
|
828
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-orca-home',
|
|
829
|
-
});
|
|
830
|
-
expect(received[0]!.auth).toBe('Bearer sk-orca-home');
|
|
831
|
-
});
|
|
832
|
-
|
|
833
|
-
/**
|
|
834
|
-
* PUSH SHIPS THE TRACE, NOT THE CAPTURE SCAFFOLDING.
|
|
835
|
-
*
|
|
836
|
-
* A run directory accumulates files that are not trace content, and `runEntries` is the only
|
|
837
|
-
* thing that SWEEPS it — every other command (`export`, `gc`, `scrub`) enumerates named
|
|
838
|
-
* artifacts and cannot pick up a neighbour. With a denylist, each of those files shipped until
|
|
839
|
-
* somebody read a packed archive and noticed:
|
|
840
|
-
*
|
|
841
|
-
* mcp-config.json MCP server `env` blocks, kept verbatim by rewriteMcpConfig — which is
|
|
842
|
-
* where an MCP server's API token lives.
|
|
843
|
-
* shell-frames.jsonl raw argv of every command the agent ran.
|
|
844
|
-
* mcp-frames.jsonl raw JSON-RPC bodies.
|
|
845
|
-
* shims/ generated launchers carrying this machine's paths.
|
|
846
|
-
*
|
|
847
|
-
* `agenticreplay scrub` is why a denylist cannot be finished: it rewrites manifest.json, events.jsonl and
|
|
848
|
-
* blobs/ and NOTHING else, so a user who scrubbed a secret and pushed was shipping an unscrubbed
|
|
849
|
-
* copy of it in the raw logs — scrub said it succeeded and the secret went out anyway.
|
|
850
|
-
*
|
|
851
|
-
* Asserted on ENTRY NAMES, exactly like the TLS test beside it and for the same reason: zip names
|
|
852
|
-
* are stored uncompressed while payloads are deflated, so a body scan can pass over a file that
|
|
853
|
-
* is very much in the archive.
|
|
854
|
-
*/
|
|
855
|
-
it('packs only trace content, never the capture scaffolding beside it', async () => {
|
|
856
|
-
await seedRun();
|
|
857
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
858
|
-
await writeFile(
|
|
859
|
-
join(dir, 'mcp-config.json'),
|
|
860
|
-
`${JSON.stringify({
|
|
861
|
-
mcpServers: { gh: { command: 'x', env: { GITHUB_TOKEN: 'ghp_scaffolding_secret' } } },
|
|
862
|
-
})}\n`,
|
|
863
|
-
);
|
|
864
|
-
await writeFile(
|
|
865
|
-
join(dir, 'shell-frames.jsonl'),
|
|
866
|
-
'{"name":"curl","argv":["-H","Authorization: Bearer shell_frame_secret"]}\n',
|
|
867
|
-
);
|
|
868
|
-
await writeFile(
|
|
869
|
-
join(dir, 'mcp-frames.jsonl'),
|
|
870
|
-
'{"jsonrpc":"2.0","result":"mcp_frame_secret"}\n',
|
|
871
|
-
);
|
|
872
|
-
await mkdir(join(dir, 'shims'), { recursive: true });
|
|
873
|
-
await writeFile(join(dir, 'shims', 'curl'), '#!/bin/sh\nexec agenticreplay-shell-shim "$@"\n');
|
|
874
|
-
// Kept: the scrub ledger says a run WAS scrubbed, by rule and count and never by value.
|
|
875
|
-
await writeFile(join(dir, 'redactions.json'), '{"records":[{"rule":"scrub","count":2}]}\n');
|
|
876
|
-
// WITHHELD unless --fs: the shadow store is the largest thing scrub cannot rewrite, and a
|
|
877
|
-
// scrub that reports "objects still hold the material" must not be followed by a push that
|
|
878
|
-
// ships them anyway. See FS_SNAPSHOT_DIR.
|
|
879
|
-
await mkdir(join(dir, 'fs', 'objects'), { recursive: true });
|
|
880
|
-
await writeFile(join(dir, 'fs', 'objects', 'aa'), 'workspace_snapshot_secret\n');
|
|
881
|
-
await mkdir(join(dir, 'fs', 'shims'), { recursive: true });
|
|
882
|
-
await writeFile(join(dir, 'fs', 'shims', 'recorded'), 'the user recorded this\n');
|
|
883
|
-
|
|
884
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', url]), out, workspace, env());
|
|
885
|
-
|
|
886
|
-
const sent = received.find((r) => r.method === 'POST');
|
|
887
|
-
expect(sent, 'the push must have happened').toBeTruthy();
|
|
888
|
-
const start = sent!.body.indexOf('PK');
|
|
889
|
-
const end = sent!.body.lastIndexOf('\r\n--');
|
|
890
|
-
const names = (await readArchive(new Uint8Array(sent!.body.subarray(start, end))))
|
|
891
|
-
.map((e) => e.name)
|
|
892
|
-
.sort();
|
|
893
|
-
expect(names).toEqual([
|
|
894
|
-
`${runId}/blobs/ab/abcdef`,
|
|
895
|
-
`${runId}/events.jsonl`,
|
|
896
|
-
`${runId}/manifest.json`,
|
|
897
|
-
`${runId}/redactions.json`,
|
|
898
|
-
]);
|
|
899
|
-
|
|
900
|
-
// The payload backstop, for anything that arrives by another route.
|
|
901
|
-
const body = sent!.body.toString('latin1');
|
|
902
|
-
for (const secret of [
|
|
903
|
-
'ghp_scaffolding_secret',
|
|
904
|
-
'shell_frame_secret',
|
|
905
|
-
'mcp_frame_secret',
|
|
906
|
-
'workspace_snapshot_secret',
|
|
907
|
-
]) {
|
|
908
|
-
expect(body).not.toContain(secret);
|
|
909
|
-
}
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
/*
|
|
913
|
-
--fs IS THE OPT-IN, AND IT SAYS SO.
|
|
914
|
-
|
|
915
|
-
The snapshots are still pushable for the case they exist for — a teammate who needs the tree to
|
|
916
|
-
reproduce — but as a decision the pusher makes rather than a default they inherit, because
|
|
917
|
-
`agenticreplay scrub` cannot rewrite the store and says as much itself.
|
|
918
|
-
*/
|
|
919
|
-
it('ships the workspace snapshots only when --fs asks, and warns when it does', async () => {
|
|
920
|
-
await seedRun();
|
|
921
|
-
const dir = join(workspace, '.agenticreplay', 'runs', runId);
|
|
922
|
-
await mkdir(join(dir, 'fs', 'objects'), { recursive: true });
|
|
923
|
-
await writeFile(join(dir, 'fs', 'objects', 'aa'), 'snapshot\n');
|
|
924
|
-
await mkdir(join(dir, 'fs', 'shims'), { recursive: true });
|
|
925
|
-
await writeFile(join(dir, 'fs', 'shims', 'recorded'), 'the user recorded this\n');
|
|
926
|
-
|
|
927
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', url, '--fs']), out, workspace, env());
|
|
928
|
-
|
|
929
|
-
const sent = received.find((r) => r.method === 'POST');
|
|
930
|
-
const start = sent!.body.indexOf('PK');
|
|
931
|
-
const end = sent!.body.lastIndexOf('\r\n--');
|
|
932
|
-
const names = (await readArchive(new Uint8Array(sent!.body.subarray(start, end))))
|
|
933
|
-
.map((e) => e.name)
|
|
934
|
-
.sort();
|
|
935
|
-
expect(names).toContain(`${runId}/fs/objects/aa`);
|
|
936
|
-
// A NESTED copy of an excluded name is content, not scaffolding: the filter is top-level only.
|
|
937
|
-
expect(names).toContain(`${runId}/fs/shims/recorded`);
|
|
938
|
-
|
|
939
|
-
// The disclosure is stated rather than left to be discovered.
|
|
940
|
-
const packed = logs.find((e) => e.event === 'push.packed');
|
|
941
|
-
expect(packed?.fields?.fs).toBe('included');
|
|
942
|
-
expect(
|
|
943
|
-
logs.some((e) => e.event === 'push.fs_included'),
|
|
944
|
-
'shipping the snapshots must say that scrub could not clean them',
|
|
945
|
-
).toBe(true);
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
/**
|
|
949
|
-
* A STALE-BREAK MUST NOT REMOVE A LOCK THAT IS ALIVE.
|
|
950
|
-
*
|
|
951
|
-
* Two waiters can judge the same abandoned lock stale. The break then read the lock's bytes BY
|
|
952
|
-
* PATH and asked `releaseRunLock` to remove "that" token — which read the same path again. Two
|
|
953
|
-
* reads of one path are not evidence about each other:
|
|
954
|
-
*
|
|
955
|
-
* W1 and W2 both stat the abandoned lock: stale.
|
|
956
|
-
* W1 breaks it and acquires — a FRESH lock now sits at that path.
|
|
957
|
-
* W2 reads the path, gets W1's fresh token, and removes it as though it were the stale one.
|
|
958
|
-
* W2 acquires beside W1 — two pulls doing recovery-and-swap on one run.
|
|
959
|
-
*
|
|
960
|
-
* Driven directly at the break, because the window is inside `withRunLock`'s retry loop and no
|
|
961
|
-
* caller can interpose on it.
|
|
962
|
-
*/
|
|
963
|
-
it('breaks the stale lock it claimed, never a live one that replaced it', async () => {
|
|
964
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
965
|
-
await mkdir(runs, { recursive: true });
|
|
966
|
-
const lock = join(runs, `${runId}.lock`);
|
|
967
|
-
|
|
968
|
-
// W1's fresh lock, standing where W2 last saw a stale one. Written NOW, so it is not stale.
|
|
969
|
-
const fresh = `${process.pid} w1-is-working\n`;
|
|
970
|
-
await writeFile(lock, fresh);
|
|
971
|
-
|
|
972
|
-
await breakStaleRunLock(lock);
|
|
973
|
-
|
|
974
|
-
expect(
|
|
975
|
-
await readFile(lock, 'utf8').catch(() => undefined),
|
|
976
|
-
'a live holder’s lock was removed by another waiter’s stale-break',
|
|
977
|
-
).toBe(fresh);
|
|
978
|
-
// And nothing is left lying about beside it.
|
|
979
|
-
expect((await readdir(runs)).filter((n) => n.includes('.breaking.'))).toEqual([]);
|
|
980
|
-
|
|
981
|
-
// The genuinely stale case still works, or the lock would never be reclaimable.
|
|
982
|
-
const old = new Date(Date.now() - 30 * 60 * 1000);
|
|
983
|
-
await writeFile(lock, '424242 abandoned\n');
|
|
984
|
-
await utimes(lock, old, old);
|
|
985
|
-
await breakStaleRunLock(lock);
|
|
986
|
-
expect(await readFile(lock, 'utf8').catch(() => undefined)).toBeUndefined();
|
|
987
|
-
expect((await readdir(runs)).filter((n) => n.includes('.breaking.'))).toEqual([]);
|
|
988
|
-
});
|
|
989
|
-
|
|
990
|
-
/*
|
|
991
|
-
A RELEASE MUST NOT DELETE A LOCK IT NO LONGER OWNS, AND READ-THEN-UNLINK CANNOT PROMISE THAT.
|
|
992
|
-
|
|
993
|
-
The old body compared the bytes at the path with its token and unlinked THE PATH two awaits
|
|
994
|
-
later. Reachable whenever a stale-break has handed the path on: the read still returns our own
|
|
995
|
-
token (taken before the break), the comparison passes, and the unlink removes the FRESH lock that
|
|
996
|
-
replaced it. A third pull then walks in beside the second — the concurrent recovery-and-swap this
|
|
997
|
-
lock exists to prevent.
|
|
998
|
-
|
|
999
|
-
WHAT THIS TEST DOES AND DOES NOT PROVE, because the distinction matters. It pins the CONTRACT —
|
|
1000
|
-
a release never removes a lock whose bytes are not ours — and the old read-then-unlink body
|
|
1001
|
-
satisfies that for a file that is already someone else’s when the call starts. What it cannot
|
|
1002
|
-
stage without mocking fs is the interleaving itself: the swap landing between the read and the
|
|
1003
|
-
unlink. That window is closed structurally rather than by assertion, by deciding on a copy no
|
|
1004
|
-
other process can reach.
|
|
1005
|
-
|
|
1006
|
-
It is not toothless: removing the claim’s restore-before-delete rule fails this test along with
|
|
1007
|
-
the two below it, because the released file then disappears instead of going back.
|
|
1008
|
-
*/
|
|
1009
|
-
it('releases only the exact lock file it claimed, never the path', async () => {
|
|
1010
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1011
|
-
await mkdir(runs, { recursive: true });
|
|
1012
|
-
const lock = join(runs, `${runId}.lock`);
|
|
1013
|
-
const mine = `${process.pid} mine\n`;
|
|
1014
|
-
const theirs = '424242 a-newer-pull\n';
|
|
1015
|
-
|
|
1016
|
-
// What a stale-break leaves behind: someone else's lock at the path we were holding.
|
|
1017
|
-
await writeFile(lock, theirs);
|
|
1018
|
-
await releaseRunLock(lock, mine);
|
|
1019
|
-
expect(
|
|
1020
|
-
await readFile(lock, 'utf8').catch(() => undefined),
|
|
1021
|
-
'a newer pull’s lock was deleted by the previous holder’s release',
|
|
1022
|
-
).toBe(theirs);
|
|
1023
|
-
expect((await readdir(runs)).filter((n) => n.includes('.releasing.'))).toEqual([]);
|
|
1024
|
-
|
|
1025
|
-
// And the ordinary case still works, or the lock would never come off.
|
|
1026
|
-
await writeFile(lock, mine);
|
|
1027
|
-
await releaseRunLock(lock, mine);
|
|
1028
|
-
expect(await readFile(lock, 'utf8').catch(() => undefined)).toBeUndefined();
|
|
1029
|
-
expect((await readdir(runs)).filter((n) => n.includes('.releasing.'))).toEqual([]);
|
|
1030
|
-
});
|
|
1031
|
-
|
|
1032
|
-
/*
|
|
1033
|
-
A BREAK THAT CANNOT RETURN A LIVE LOCK MUST LEAVE IT, NOT DELETE IT.
|
|
1034
|
-
|
|
1035
|
-
breakStaleRunLock claims the file before it judges the age, which is what makes the judgement
|
|
1036
|
-
sound — but the previous version then removed the aside UNCONDITIONALLY after a swallowed `link`
|
|
1037
|
-
failure. So when the path had been re-taken in that window, the live holder's only lock file was
|
|
1038
|
-
deleted by the very function whose contract is "without ever removing a LIVE one", and two pulls
|
|
1039
|
-
ran in the same critical section.
|
|
1040
|
-
|
|
1041
|
-
Here the path is occupied by a third party before the restore, which is exactly that window.
|
|
1042
|
-
*/
|
|
1043
|
-
it('leaves a live holder’s lock behind rather than deleting it when the path is taken', async () => {
|
|
1044
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1045
|
-
await mkdir(runs, { recursive: true });
|
|
1046
|
-
const lock = join(runs, `${runId}.lock`);
|
|
1047
|
-
// The hand-back is asserted directly rather than by racing a write against breakStaleRunLock's
|
|
1048
|
-
// internal window: the window is two awaits wide, so the old version of this test was a coin
|
|
1049
|
-
// flip that happened to land right most of the time — a test that is red one run in four teaches
|
|
1050
|
-
// the next reader to re-run rather than to read, which is worse than not having it.
|
|
1051
|
-
const aside = `${lock}.breaking.pid.claimed`;
|
|
1052
|
-
await writeFile(aside, 'live-holder\n');
|
|
1053
|
-
// What a third pull leaves at the path while the live holder's lock is held aside.
|
|
1054
|
-
await writeFile(lock, 'a-third-pull\n');
|
|
1055
|
-
|
|
1056
|
-
const returned = await restoreLockFile(aside, lock);
|
|
1057
|
-
|
|
1058
|
-
expect(returned, 'link clobbered a lock another waiter already holds').toBe(false);
|
|
1059
|
-
// The third pull's lock is intact …
|
|
1060
|
-
expect(await readFile(lock, 'utf8')).toBe('a-third-pull\n');
|
|
1061
|
-
// … and the live holder's token still exists somewhere rather than having been destroyed.
|
|
1062
|
-
expect(
|
|
1063
|
-
await readFile(aside, 'utf8').catch(() => undefined),
|
|
1064
|
-
'the break deleted a lock it could not return — the outcome it exists to prevent',
|
|
1065
|
-
).toBe('live-holder\n');
|
|
1066
|
-
|
|
1067
|
-
// And the ordinary hand-back still hands back, or a lock judged live would never be returned.
|
|
1068
|
-
await rm(lock);
|
|
1069
|
-
expect(await restoreLockFile(aside, lock)).toBe(true);
|
|
1070
|
-
expect(await readFile(lock, 'utf8')).toBe('live-holder\n');
|
|
1071
|
-
expect(await stat(aside).catch(() => undefined)).toBeUndefined();
|
|
1072
|
-
});
|
|
1073
|
-
|
|
1074
|
-
/*
|
|
1075
|
-
A LIVE HOLDER MUST NEVER LOOK STALE.
|
|
1076
|
-
|
|
1077
|
-
The lock was written once and never touched again, so "stale" meant "created more than ten
|
|
1078
|
-
minutes ago", not "dead" — and the work under the lock is the staging write, one file per archive
|
|
1079
|
-
entry. A pull whose staging outruns STALE_LOCK_MS had its lock broken WHILE IT WAS WRITING.
|
|
1080
|
-
|
|
1081
|
-
The heartbeat is asserted by observing the mtime advance under a held lock, with STALE_LOCK_MS
|
|
1082
|
-
left alone: a real timer on a real file, so it fails if the interval is never armed, is armed on
|
|
1083
|
-
the wrong path, or is cleared too early.
|
|
1084
|
-
*/
|
|
1085
|
-
it('keeps a held lock’s mtime fresh while the critical section runs', async () => {
|
|
1086
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1087
|
-
await mkdir(runs, { recursive: true });
|
|
1088
|
-
const dest = join(runs, runId);
|
|
1089
|
-
const lock = `${dest}.lock`;
|
|
1090
|
-
|
|
1091
|
-
// Fake timers so the real LOCK_HEARTBEAT_MS (a third of the ten-minute stale window) can be
|
|
1092
|
-
// crossed without the test waiting for it. The value comes from the source rather than being
|
|
1093
|
-
// re-derived here, so changing one does not silently stop exercising the other.
|
|
1094
|
-
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
1095
|
-
try {
|
|
1096
|
-
let aged = 0;
|
|
1097
|
-
let beaten = 0;
|
|
1098
|
-
await withRunLockForTest(dest, async () => {
|
|
1099
|
-
// Age the lock by hand: without a heartbeat nothing ever writes this file again, so the
|
|
1100
|
-
// mtime stays exactly where it was put and the break judges a working pull abandoned.
|
|
1101
|
-
const old = new Date(Date.now() - 60 * 60 * 1000);
|
|
1102
|
-
await utimes(lock, old, old);
|
|
1103
|
-
aged = (await stat(lock)).mtimeMs;
|
|
1104
|
-
// The beat reads the lock's bytes before refreshing it (it must not refresh one it has
|
|
1105
|
-
// lost), so firing the timer is not the same as the write having landed: advance in small
|
|
1106
|
-
// steps until it does, rather than sampling once and calling a slow filesystem a
|
|
1107
|
-
// regression.
|
|
1108
|
-
await vi.advanceTimersByTimeAsync(LOCK_HEARTBEAT_MS + 50);
|
|
1109
|
-
for (let i = 0; i < 100 && (await stat(lock)).mtimeMs <= aged; i++) {
|
|
1110
|
-
await vi.advanceTimersByTimeAsync(20);
|
|
1111
|
-
}
|
|
1112
|
-
beaten = (await stat(lock)).mtimeMs;
|
|
1113
|
-
});
|
|
1114
|
-
expect(
|
|
1115
|
-
beaten > aged,
|
|
1116
|
-
'the lock’s mtime never advanced while it was held, so a pull whose staging outruns ' +
|
|
1117
|
-
'STALE_LOCK_MS still has its lock broken underneath it',
|
|
1118
|
-
).toBe(true);
|
|
1119
|
-
} finally {
|
|
1120
|
-
vi.useRealTimers();
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
// …and the beat stops with the lock, rather than keeping the process alive or writing to a
|
|
1124
|
-
// path that no longer belongs to it.
|
|
1125
|
-
await writeFile(lock, 'someone-else\n');
|
|
1126
|
-
const settled = (await stat(lock)).mtimeMs;
|
|
1127
|
-
await new Promise((ok) => setTimeout(ok, 120));
|
|
1128
|
-
expect((await stat(lock)).mtimeMs).toBe(settled);
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
/*
|
|
1132
|
-
RELEASING A LOCK THAT IS NOT OURS MUST NOT DISTURB THE PATH AT ALL.
|
|
1133
|
-
|
|
1134
|
-
The claim is a rename, so for the instant between it and the hand-back the path stands EMPTY and a
|
|
1135
|
-
third pull waiting on the run can create a lock there. That is tolerable when the lock is ours. It
|
|
1136
|
-
is not tolerable in the case that produces it deterministically: a pull whose lock was stale-broken
|
|
1137
|
-
mid-staging aborts, and its `finally` releases a lock it demonstrably does not own — every time,
|
|
1138
|
-
by schedule rather than by interleaving. The new holder then watches its own `stillHeld()` fail.
|
|
1139
|
-
|
|
1140
|
-
Asserted on the INODE, not on the bytes: the hand-back restores the content either way, so a test
|
|
1141
|
-
that reads the file passes whether or not the window was opened. The inode is what the rename
|
|
1142
|
-
moves, and it is what a third pull's `wx` create would find missing.
|
|
1143
|
-
*/
|
|
1144
|
-
it('does not move a lock aside to discover it is not ours', async () => {
|
|
1145
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1146
|
-
await mkdir(runs, { recursive: true });
|
|
1147
|
-
const lock = join(runs, `${runId}.lock`);
|
|
1148
|
-
await writeFile(lock, 'the new holder\n');
|
|
1149
|
-
const before = (await stat(lock)).ino;
|
|
1150
|
-
|
|
1151
|
-
await releaseRunLock(lock, 'ours\n');
|
|
1152
|
-
|
|
1153
|
-
expect(
|
|
1154
|
-
(await stat(lock)).ino,
|
|
1155
|
-
'the release renamed another holder’s lock away from the path and back, leaving the path free ' +
|
|
1156
|
-
'for a third pull in between',
|
|
1157
|
-
).toBe(before);
|
|
1158
|
-
expect(await readFile(lock, 'utf8')).toBe('the new holder\n');
|
|
1159
|
-
// The litter a hand-back leaves when the path has been re-taken must not appear here either:
|
|
1160
|
-
// nothing was claimed, so there is nothing to hand back.
|
|
1161
|
-
expect((await readdir(runs)).sort()).toEqual([`${runId}.lock`]);
|
|
1162
|
-
});
|
|
1163
|
-
|
|
1164
|
-
/*
|
|
1165
|
-
AND THE BEAT MUST NOT REFRESH A LOCK THAT IS NO LONGER OURS.
|
|
1166
|
-
|
|
1167
|
-
The beat wrote the mtime of whatever file sat at the path. After a stale-break that file is the
|
|
1168
|
-
NEW holder's lock, and refreshing it is not a harmless write: the mtime is the only thing that
|
|
1169
|
-
decides whether a lock can ever be broken. A pull that lost its lock and kept beating holds the
|
|
1170
|
-
new holder's lock open for as long as it runs — so if the new holder then dies, its lock never
|
|
1171
|
-
ages out, no later pull can break it, and the run is wedged until someone deletes the file.
|
|
1172
|
-
*/
|
|
1173
|
-
it('stops beating on the lock once it belongs to someone else', async () => {
|
|
1174
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1175
|
-
await mkdir(runs, { recursive: true });
|
|
1176
|
-
const dest = join(runs, runId);
|
|
1177
|
-
const lock = `${dest}.lock`;
|
|
1178
|
-
|
|
1179
|
-
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
1180
|
-
try {
|
|
1181
|
-
let aged = 0;
|
|
1182
|
-
let after = 0;
|
|
1183
|
-
await withRunLockForTest(dest, async () => {
|
|
1184
|
-
// A stale-break hands the path to another pull, exactly as it would mid-staging …
|
|
1185
|
-
await writeFile(lock, 'the new holder\n');
|
|
1186
|
-
const old = new Date(Date.now() - 60 * 60 * 1000);
|
|
1187
|
-
await utimes(lock, old, old);
|
|
1188
|
-
aged = (await stat(lock)).mtimeMs;
|
|
1189
|
-
// Same number of steps the positive test needs to see a beat land, so this one is not
|
|
1190
|
-
// green merely because it sampled sooner.
|
|
1191
|
-
await vi.advanceTimersByTimeAsync(LOCK_HEARTBEAT_MS + 50);
|
|
1192
|
-
for (let i = 0; i < 100; i++) await vi.advanceTimersByTimeAsync(20);
|
|
1193
|
-
after = (await stat(lock)).mtimeMs;
|
|
1194
|
-
});
|
|
1195
|
-
expect(
|
|
1196
|
-
after,
|
|
1197
|
-
'the beat kept refreshing a lock it had lost, so the new holder’s lock can never go stale',
|
|
1198
|
-
).toBe(aged);
|
|
1199
|
-
} finally {
|
|
1200
|
-
vi.useRealTimers();
|
|
1201
|
-
}
|
|
1202
|
-
});
|
|
1203
|
-
|
|
1204
|
-
/*
|
|
1205
|
-
AND THE MOVE-ASIDE MUST BE UNDONE WHEN THE LOCK IS LOST BETWEEN THE TWO RENAMES.
|
|
1206
|
-
|
|
1207
|
-
One probe before the swap was not enough. A pull stopped between that probe and
|
|
1208
|
-
`rename(dest, retired)` resumes after its lock has been broken and ANOTHER pull has completed
|
|
1209
|
-
a whole install: the move-aside then succeeds and carries away the run that pull just put
|
|
1210
|
-
there. The second rename fails, `revertStagedSwap` correctly refuses to put anything back
|
|
1211
|
-
(the lock is not ours), and the store is left with no `<run>` and only `<run>.replaced` — a
|
|
1212
|
-
name matching no RUN_ID_PATTERN, so list, show, scrub, gc, export and push all skip it. The
|
|
1213
|
-
run has not moved, it has VANISHED, reached through the guard added to prevent exactly that.
|
|
1214
|
-
|
|
1215
|
-
Driven through the pull command with an ownership answer that flips after the move, rather
|
|
1216
|
-
than by racing a SIGSTOP: the property is what the code does once the lock is gone, and a
|
|
1217
|
-
test that tries to hit the window by timing is the coin flip this file already learned about.
|
|
1218
|
-
*/
|
|
1219
|
-
it('puts the old run back when the lock is lost between the two renames', async () => {
|
|
1220
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1221
|
-
const dest = join(runs, runId);
|
|
1222
|
-
await mkdir(dest, { recursive: true });
|
|
1223
|
-
await writeFile(join(dest, 'events.jsonl'), 'the run that was already here\n');
|
|
1224
|
-
|
|
1225
|
-
const staging = `${dest}.incoming`;
|
|
1226
|
-
const retired = `${dest}.replaced`;
|
|
1227
|
-
await mkdir(staging, { recursive: true });
|
|
1228
|
-
await writeFile(join(staging, 'events.jsonl'), 'staged\n');
|
|
1229
|
-
|
|
1230
|
-
// Ours for the pre-move probe, gone for the one after it.
|
|
1231
|
-
let probes = 0;
|
|
1232
|
-
const stillHeld = async (): Promise<boolean> => ++probes <= 1;
|
|
1233
|
-
|
|
1234
|
-
await expect(
|
|
1235
|
-
swapStagedRun({ dest, staging, retired, existing: true }, stillHeld),
|
|
1236
|
-
).rejects.toThrow(/lock/i);
|
|
1237
|
-
|
|
1238
|
-
expect(
|
|
1239
|
-
await readFile(join(dest, 'events.jsonl'), 'utf8').catch(() => undefined),
|
|
1240
|
-
'the run was carried away to <run>.replaced and never put back — invisible to every command',
|
|
1241
|
-
).toBe('the run that was already here\n');
|
|
1242
|
-
expect(probes, 'ownership was not re-checked after the destructive rename').toBeGreaterThan(1);
|
|
1243
|
-
|
|
1244
|
-
// And while the lock stays ours the swap still swaps, or the guard has broken pull.
|
|
1245
|
-
await mkdir(staging, { recursive: true }).catch(() => undefined);
|
|
1246
|
-
await writeFile(join(staging, 'events.jsonl'), 'the new one\n').catch(() => undefined);
|
|
1247
|
-
await swapStagedRun({ dest, staging, retired, existing: true }, async () => true);
|
|
1248
|
-
expect(await readFile(join(dest, 'events.jsonl'), 'utf8')).toBe('the new one\n');
|
|
1249
|
-
});
|
|
1250
|
-
|
|
1251
|
-
/*
|
|
1252
|
-
AND WHEN THE RENAME ITSELF FAILS, WITH THE LOCK STILL PERFECTLY OURS (orcacode-review,
|
|
1253
|
-
second report on this function).
|
|
1254
|
-
|
|
1255
|
-
The restore above hung off the ownership probe, so it covered exactly one way to fail:
|
|
1256
|
-
the lock being broken between the two renames. `rename(staging, dest)` has a whole other
|
|
1257
|
-
family — EACCES/EPERM/EIO on a store that just went read-only or is being indexed, a
|
|
1258
|
-
Windows handle on the directory we have only this moment finished writing, ENOTEMPTY if
|
|
1259
|
-
`dest` reappeared. On any of those the probe answers "still ours", never fires, and
|
|
1260
|
-
`swapStagedRun` throws with the old run sitting at `<run>.replaced`.
|
|
1261
|
-
|
|
1262
|
-
The caller cannot clean up after it, and that is the part that makes this structural
|
|
1263
|
-
rather than an oversight: `movedAside` is a local, so `movedAside = await
|
|
1264
|
-
swapStagedRun(...)` does not assign on a throw. The caller's copy is still `false`,
|
|
1265
|
-
`revertStagedSwap` is told `existing: false`, and it puts nothing back — while also
|
|
1266
|
-
deleting the staged replacement. `<run>` then exists nowhere: `.replaced` matches no
|
|
1267
|
-
RUN_ID_PATTERN, so list, show, events, checkpoints, export, scrub, gc and push all skip
|
|
1268
|
-
it, and only a later `agenticreplay pull` of that exact id would ever reclaim it.
|
|
1269
|
-
|
|
1270
|
-
A function cannot both return a value and throw, so no return value can carry this. The
|
|
1271
|
-
failure path has to stop needing the caller, which is what the single `catch` inside
|
|
1272
|
-
`swapStagedRun` now does.
|
|
1273
|
-
|
|
1274
|
-
Provoked with a staging directory that is not there, so `rename(staging, dest)` fails
|
|
1275
|
-
ENOENT with ownership never in question — the plain-failure variant, which the lock-loss
|
|
1276
|
-
test above does not reach.
|
|
1277
|
-
*/
|
|
1278
|
-
it('puts the old run back when the swap rename fails and the lock is still ours', async () => {
|
|
1279
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1280
|
-
const dest = join(runs, runId);
|
|
1281
|
-
await mkdir(dest, { recursive: true });
|
|
1282
|
-
await writeFile(join(dest, 'events.jsonl'), 'the run that was already here\n');
|
|
1283
|
-
|
|
1284
|
-
const staging = `${dest}.incoming`;
|
|
1285
|
-
const retired = `${dest}.replaced`;
|
|
1286
|
-
// Deliberately absent: the second rename fails, the lock never does.
|
|
1287
|
-
await rm(staging, { recursive: true, force: true });
|
|
1288
|
-
|
|
1289
|
-
let probes = 0;
|
|
1290
|
-
const stillHeld = async (): Promise<boolean> => {
|
|
1291
|
-
probes++;
|
|
1292
|
-
return true;
|
|
1293
|
-
};
|
|
1294
|
-
|
|
1295
|
-
await expect(
|
|
1296
|
-
swapStagedRun({ dest, staging, retired, existing: true }, stillHeld),
|
|
1297
|
-
).rejects.toThrow();
|
|
1298
|
-
|
|
1299
|
-
expect(probes, 'ownership was never in doubt on this path').toBeGreaterThan(0);
|
|
1300
|
-
expect(
|
|
1301
|
-
await readFile(join(dest, 'events.jsonl'), 'utf8').catch(() => undefined),
|
|
1302
|
-
'the run stayed at <run>.replaced after a failed swap — invisible to every command, ' +
|
|
1303
|
-
'and the caller cannot put it back because a throw carries no return value',
|
|
1304
|
-
).toBe('the run that was already here\n');
|
|
1305
|
-
expect(
|
|
1306
|
-
await readFile(join(retired, 'events.jsonl'), 'utf8').catch(() => undefined),
|
|
1307
|
-
'the move-aside must be undone, not merely duplicated',
|
|
1308
|
-
).toBeUndefined();
|
|
1309
|
-
});
|
|
1310
|
-
|
|
1311
|
-
/*
|
|
1312
|
-
AND IT MUST NOT KEEP WRITING EITHER — the fourth site of the same class, and the half the
|
|
1313
|
-
previous commit missed.
|
|
1314
|
-
|
|
1315
|
-
Gating the REVERT stopped an evicted pull from deleting the new holder's staging. It did nothing
|
|
1316
|
-
about the evicted pull's WRITES: the only ownership probe sat AFTER the whole staging loop, so a
|
|
1317
|
-
pull that lost its lock went on writing archive entries into `<dest>.incoming` — which, because
|
|
1318
|
-
the scratch name is deterministic, is by then the directory the new holder is staging into. The
|
|
1319
|
-
new holder renames the blend into place and prints `pull.done`.
|
|
1320
|
-
|
|
1321
|
-
Two archives of one run key differ in ordinary operation (a re-push, a scrub between fetches, or
|
|
1322
|
-
the truncated export the `x-agenticreplay-run-truncated` header warns about), and the result is a run whose
|
|
1323
|
-
manifest integrity root covers one copy while some blobs are the other's. That is verbatim what
|
|
1324
|
-
withRunLock's own comment says the lock exists to rule out: "the run that lands is a blend of both
|
|
1325
|
-
copies … with nothing reporting it."
|
|
1326
|
-
|
|
1327
|
-
Asserted through the exported staging step rather than by racing two real pulls: the window is a
|
|
1328
|
-
SIGSTOP wide, so a test that tries to hit it by timing is a coin flip (this file already had two
|
|
1329
|
-
such tests, and they were flaky one run in four).
|
|
1330
|
-
*/
|
|
1331
|
-
it('stops staging the moment the lock is no longer ours', async () => {
|
|
1332
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1333
|
-
await mkdir(runs, { recursive: true });
|
|
1334
|
-
const dest = join(runs, runId);
|
|
1335
|
-
const staging = `${dest}.incoming`;
|
|
1336
|
-
|
|
1337
|
-
const entries = Array.from({ length: 600 }, (_, i) => ({
|
|
1338
|
-
name: `${runId}/blobs/aa/${String(i).padStart(6, '0')}`,
|
|
1339
|
-
bytes: new Uint8Array([1, 2, 3]),
|
|
1340
|
-
}));
|
|
1341
|
-
|
|
1342
|
-
// Ours for the first probe, gone by the next one — the eviction, without the timing.
|
|
1343
|
-
let probes = 0;
|
|
1344
|
-
const stillHeld = async (): Promise<boolean> => ++probes <= 1;
|
|
1345
|
-
|
|
1346
|
-
await expect(stageRunEntries(entries, runId, staging, stillHeld)).rejects.toThrow(/lock/i);
|
|
1347
|
-
|
|
1348
|
-
const written = (await readdir(join(staging, 'blobs', 'aa')).catch(() => [])).length;
|
|
1349
|
-
expect(
|
|
1350
|
-
written,
|
|
1351
|
-
'the evicted pull wrote the whole archive into the new holder’s staging directory',
|
|
1352
|
-
).toBeLessThan(entries.length);
|
|
1353
|
-
expect(probes, 'ownership was asked once, after the loop — not while writing').toBeGreaterThan(
|
|
1354
|
-
1,
|
|
1355
|
-
);
|
|
1356
|
-
|
|
1357
|
-
// And while the lock IS ours it must stage everything, or the check has simply broken pull.
|
|
1358
|
-
await rm(staging, { recursive: true, force: true });
|
|
1359
|
-
await stageRunEntries(entries, runId, staging, async () => true);
|
|
1360
|
-
expect(await readdir(join(staging, 'blobs', 'aa'))).toHaveLength(entries.length);
|
|
1361
|
-
});
|
|
1362
|
-
|
|
1363
|
-
/*
|
|
1364
|
-
A CREDENTIAL GOES TO THE HOST IT WAS SET UP FOR, AND NOWHERE A REDIRECT POINTS.
|
|
1365
|
-
|
|
1366
|
-
Both requests let fetch follow redirects, and undici strips only `authorization` across origins —
|
|
1367
|
-
`x-api-key`, which gatewayHeaders sets to the SAME key, is forwarded to whatever the redirect
|
|
1368
|
-
names. resolveGateway validates the URL the code PASSES, not the URL the request REACHES, so the
|
|
1369
|
-
whole origin check is bypassed by one Location header. The README states the promise this breaks
|
|
1370
|
-
in writing: "Never a key to a host it was not set up for."
|
|
1371
|
-
|
|
1372
|
-
And push then reports success for an upload that never happened: a 301/302/303 is re-issued as a
|
|
1373
|
-
GET with no body, and the redirect target's 200 is `res.ok`.
|
|
1374
|
-
|
|
1375
|
-
Anyone who can answer for the gateway reaches this — the gateway itself, an SSO interstitial in
|
|
1376
|
-
front of it, a compromise of it, or an on-path attacker on the plaintext `http://` gateway a user
|
|
1377
|
-
typed.
|
|
1378
|
-
*/
|
|
1379
|
-
it('refuses to follow a redirect rather than handing the key to whoever answers', async () => {
|
|
1380
|
-
await seedRun();
|
|
1381
|
-
|
|
1382
|
-
// A second origin standing in for the redirect target. It records what reaches it.
|
|
1383
|
-
const seen: { apiKey?: string; auth?: string; method: string }[] = [];
|
|
1384
|
-
const thief = createServer((req, res) => {
|
|
1385
|
-
req.resume();
|
|
1386
|
-
req.on('end', () => {
|
|
1387
|
-
seen.push({
|
|
1388
|
-
apiKey: req.headers['x-api-key'] as string | undefined,
|
|
1389
|
-
auth: req.headers.authorization,
|
|
1390
|
-
method: req.method ?? '',
|
|
1391
|
-
});
|
|
1392
|
-
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1393
|
-
res.end(JSON.stringify({ success: true, data: { run_key: runId } }));
|
|
1394
|
-
});
|
|
1395
|
-
});
|
|
1396
|
-
await new Promise<void>((ok) => thief.listen(0, '127.0.0.1', ok));
|
|
1397
|
-
const thiefAddr = thief.address();
|
|
1398
|
-
const thiefUrl = `http://127.0.0.1:${typeof thiefAddr === 'object' && thiefAddr ? thiefAddr.port : 0}`;
|
|
1399
|
-
|
|
1400
|
-
try {
|
|
1401
|
-
for (const status of [301, 302, 303, 307, 308]) {
|
|
1402
|
-
seen.length = 0;
|
|
1403
|
-
reply = { status, body: '', headers: { location: `${thiefUrl}/stolen` } };
|
|
1404
|
-
|
|
1405
|
-
await expect(
|
|
1406
|
-
pushCommand(parseArgs(['push', runId]), out, workspace, env()),
|
|
1407
|
-
).rejects.toThrow();
|
|
1408
|
-
|
|
1409
|
-
expect(
|
|
1410
|
-
seen,
|
|
1411
|
-
`a ${status} sent the request onward; the key reached a host it was not set up for`,
|
|
1412
|
-
).toHaveLength(0);
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
// Pull is the same request shape and the same key, so it gets the same rule.
|
|
1416
|
-
reply = { status: 302, body: '', headers: { location: `${thiefUrl}/stolen` } };
|
|
1417
|
-
seen.length = 0;
|
|
1418
|
-
await expect(
|
|
1419
|
-
pullCommand(parseArgs(['pull', runId, '--force']), out, workspace, env()),
|
|
1420
|
-
).rejects.toThrow();
|
|
1421
|
-
expect(seen, 'pull followed a redirect and handed over the key').toHaveLength(0);
|
|
1422
|
-
} finally {
|
|
1423
|
-
await new Promise<void>((ok) => thief.close(() => ok()));
|
|
1424
|
-
}
|
|
1425
|
-
});
|
|
1426
|
-
|
|
1427
|
-
/*
|
|
1428
|
-
A PULL THAT LOST THE LOCK MUST NOT TIDY UP AFTER THE ONE THAT TOOK IT.
|
|
1429
|
-
|
|
1430
|
-
The ownership re-check added before the swap stops an interrupted pull from resuming INTO the
|
|
1431
|
-
renames — but it aborts by throwing, and the catch that follows was written for the ordinary
|
|
1432
|
-
failure, where this pull is still the owner and the scratch paths are its own. Under the very
|
|
1433
|
-
interleaving the check exists to describe they are not:
|
|
1434
|
-
|
|
1435
|
-
A holds the lock and is part-way through writing `<run>.incoming`; A is stopped.
|
|
1436
|
-
More than STALE_LOCK_MS later, B breaks the lock and stages into the SAME path — the scratch
|
|
1437
|
-
names are deterministic per destination, which is what makes a half-done swap recoverable.
|
|
1438
|
-
A resumes, its `stillHeld()` reports false, and A throws.
|
|
1439
|
-
A's catch then `rm -rf`s `<run>.incoming` — B's in-flight staging — and renames `<run>.replaced`
|
|
1440
|
-
back over the run B moved aside.
|
|
1441
|
-
|
|
1442
|
-
So the check meant to prevent a destructive resume performed the destruction itself, on state that
|
|
1443
|
-
by then belonged to another process. B finishes by renaming a gutted staging into place and prints
|
|
1444
|
-
`pull.done`.
|
|
1445
|
-
|
|
1446
|
-
The revert is lock-protected work like everything else in that critical section, so it is gated on
|
|
1447
|
-
ownership rather than on which error was thrown — an ENOENT raised BY B's own recovery reaches the
|
|
1448
|
-
same catch with no flag to distinguish it. Leaving the litter is safe and already designed for:
|
|
1449
|
-
`recoverInterruptedSwap` runs under the lock at the head of every pull and reclaims both siblings.
|
|
1450
|
-
*/
|
|
1451
|
-
it('leaves the shared scratch alone when the swap aborts because the lock was taken', async () => {
|
|
1452
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1453
|
-
await mkdir(runs, { recursive: true });
|
|
1454
|
-
const dest = join(runs, runId);
|
|
1455
|
-
const staging = `${dest}.incoming`;
|
|
1456
|
-
const retired = `${dest}.replaced`;
|
|
1457
|
-
|
|
1458
|
-
// What the new holder is part-way through writing, under the shared deterministic name …
|
|
1459
|
-
await mkdir(staging, { recursive: true });
|
|
1460
|
-
await writeFile(join(staging, 'events.jsonl'), 'the new holder\n');
|
|
1461
|
-
// … and the run it moved aside to make room for it.
|
|
1462
|
-
await mkdir(retired, { recursive: true });
|
|
1463
|
-
await writeFile(join(retired, 'events.jsonl'), 'the old run\n');
|
|
1464
|
-
|
|
1465
|
-
await revertStagedSwap(async () => false, { dest, staging, retired, existing: true });
|
|
1466
|
-
|
|
1467
|
-
expect(
|
|
1468
|
-
await readFile(join(staging, 'events.jsonl'), 'utf8').catch(() => undefined),
|
|
1469
|
-
'the aborting pull deleted the staging directory the lock’s new holder was writing into',
|
|
1470
|
-
).toBe('the new holder\n');
|
|
1471
|
-
expect(
|
|
1472
|
-
await readFile(join(retired, 'events.jsonl'), 'utf8').catch(() => undefined),
|
|
1473
|
-
'the aborting pull moved back a run it no longer owns, out from under the new holder’s swap',
|
|
1474
|
-
).toBe('the old run\n');
|
|
1475
|
-
|
|
1476
|
-
// …and while the lock IS still ours the revert must still revert, or an ordinary failed pull
|
|
1477
|
-
// would report "the pull did not happen" with the run missing and the litter left in place.
|
|
1478
|
-
await revertStagedSwap(async () => true, { dest, staging, retired, existing: true });
|
|
1479
|
-
expect(await readFile(join(dest, 'events.jsonl'), 'utf8')).toBe('the old run\n');
|
|
1480
|
-
expect(await stat(staging).catch(() => undefined)).toBeUndefined();
|
|
1481
|
-
});
|
|
1482
|
-
|
|
1483
|
-
/*
|
|
1484
|
-
A ZIP NAMES A DIRECTORY WITH A TRAILING SLASH, and pull wrote it as a file.
|
|
1485
|
-
|
|
1486
|
-
Nothing this CLI produces emits such an entry (runEntries walks files), but pull reads archives
|
|
1487
|
-
from the gateway and from whatever wrote them before that, and every general-purpose zip writer
|
|
1488
|
-
emits them. The silent case is the one that matters: an archive whose directory entry has no file
|
|
1489
|
-
under it installed a run whose `blobs` was a zero-byte FILE, and the pull printed pull.done.
|
|
1490
|
-
*/
|
|
1491
|
-
it('creates a directory for a trailing-slash zip entry instead of writing it as a file', async () => {
|
|
1492
|
-
const dirEntry = { name: `${runId}/blobs/`, bytes: new Uint8Array() };
|
|
1493
|
-
const manifest = {
|
|
1494
|
-
name: `${runId}/manifest.json`,
|
|
1495
|
-
bytes: new TextEncoder().encode(
|
|
1496
|
-
`${JSON.stringify({ run_id: runId, schema_version: '0.4.0' })}\n`,
|
|
1497
|
-
),
|
|
1498
|
-
};
|
|
1499
|
-
const events = {
|
|
1500
|
-
name: `${runId}/events.jsonl`,
|
|
1501
|
-
bytes: new TextEncoder().encode('{"seq":1,"type":"run.start"}\n'),
|
|
1502
|
-
};
|
|
1503
|
-
// Directory entry FIRST is what `zip -r` emits, and is the ordering that used to fail the
|
|
1504
|
-
// whole pull with ENOTDIR on the next entry under it.
|
|
1505
|
-
reply = {
|
|
1506
|
-
status: 200,
|
|
1507
|
-
body: Buffer.from(
|
|
1508
|
-
await writeArchive([
|
|
1509
|
-
manifest,
|
|
1510
|
-
dirEntry,
|
|
1511
|
-
{ name: `${runId}/blobs/ab/abcdef`, bytes: new Uint8Array([1, 2, 3]) },
|
|
1512
|
-
events,
|
|
1513
|
-
]),
|
|
1514
|
-
),
|
|
1515
|
-
headers: { 'content-type': 'application/zip' },
|
|
1516
|
-
};
|
|
1517
|
-
|
|
1518
|
-
await pullCommand(parseArgs(['pull', runId, '--gateway', url]), out, workspace, env());
|
|
1519
|
-
|
|
1520
|
-
const blobs = join(workspace, '.agenticreplay', 'runs', runId, 'blobs');
|
|
1521
|
-
expect((await stat(blobs)).isDirectory()).toBe(true);
|
|
1522
|
-
expect(await readFile(join(blobs, 'ab', 'abcdef'))).toEqual(Buffer.from([1, 2, 3]));
|
|
1523
|
-
});
|
|
1524
|
-
|
|
1525
|
-
/*
|
|
1526
|
-
AN EXPORTED KEY IS HOMED AT AGENTICREPLAY_GATEWAY_URL, AND NOWHERE ELSE.
|
|
1527
|
-
|
|
1528
|
-
`envHome` read `AGENTICREPLAY_GATEWAY_URL ?? configured`, which substituted a home the key had never been
|
|
1529
|
-
associated with — and the README’s own CI recipe exports the KEY ALONE, so the substitution fired
|
|
1530
|
-
on the common case. A key exported for host A then travelled to the configured host B, in place
|
|
1531
|
-
of B’s own stored key, because the stored branch is the env branch’s `else`.
|
|
1532
|
-
|
|
1533
|
-
Both directions are asserted, since the fix must not simply withhold everything: the configured
|
|
1534
|
-
host still gets its OWN key, and the CI shape still works.
|
|
1535
|
-
*/
|
|
1536
|
-
it('does not send an exported key to a host only the config named', async () => {
|
|
1537
|
-
await seedRun();
|
|
1538
|
-
await writeConfig(
|
|
1539
|
-
{ gateway: { url, url_source: 'named', api_key: 'sk-stored-for-this-host' } },
|
|
1540
|
-
{ XDG_CONFIG_HOME: home },
|
|
1541
|
-
);
|
|
1542
|
-
// The README’s CI recipe: the key is exported, no URL is.
|
|
1543
|
-
const keyOnly = {
|
|
1544
|
-
XDG_CONFIG_HOME: home,
|
|
1545
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-exported-for-somewhere-else',
|
|
1546
|
-
};
|
|
1547
|
-
|
|
1548
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, keyOnly);
|
|
1549
|
-
|
|
1550
|
-
const req = received[0]!;
|
|
1551
|
-
expect(req.auth, 'a key with no home of its own was sent to a host only the config named').toBe(
|
|
1552
|
-
'Bearer sk-stored-for-this-host',
|
|
1553
|
-
);
|
|
1554
|
-
expect(req.body.toString('utf8')).not.toContain('sk-exported-for-somewhere-else');
|
|
1555
|
-
|
|
1556
|
-
// The CI shape is untouched: nothing earlier associated the key with a host, and THIS
|
|
1557
|
-
// invocation names the destination.
|
|
1558
|
-
received.length = 0;
|
|
1559
|
-
await pushCommand(parseArgs(['push', runId, '--gateway', url]), out, workspace, {
|
|
1560
|
-
XDG_CONFIG_HOME: home,
|
|
1561
|
-
AGENTICREPLAY_GATEWAY_KEY: 'sk-ci',
|
|
1562
|
-
});
|
|
1563
|
-
expect(received[0]!.auth).toBe('Bearer sk-ci');
|
|
1564
|
-
});
|
|
1565
|
-
|
|
1566
|
-
/**
|
|
1567
|
-
* PUSH HAS NO DEFAULT DESTINATION — and `agenticreplay setup`'s own default is not one either.
|
|
1568
|
-
*
|
|
1569
|
-
* README's "Never a default destination" says a run goes only where you NAMED, because a run
|
|
1570
|
-
* carries source, shell output and workspace snapshots. The code read `config.gateway.url`, and
|
|
1571
|
-
* `agenticreplay setup` writes ORCAROUTER_URL into that field when you press Enter — so plain
|
|
1572
|
-
* `agenticreplay setup` followed by `agenticreplay push last` sent all of it to a host the user never typed.
|
|
1573
|
-
*/
|
|
1574
|
-
it('refuses to push to a gateway agenticreplay setup chose rather than the user', async () => {
|
|
1575
|
-
await seedRun();
|
|
1576
|
-
await writeConfig(
|
|
1577
|
-
{ gateway: { url: 'https://api.orcarouter.ai', url_source: 'default', api_key: 'sk-x' } },
|
|
1578
|
-
{ XDG_CONFIG_HOME: home },
|
|
1579
|
-
);
|
|
1580
|
-
const noEnv = { XDG_CONFIG_HOME: home };
|
|
1581
|
-
|
|
1582
|
-
await expect(pushCommand(parseArgs(['push', runId]), out, workspace, noEnv)).rejects.toThrow(
|
|
1583
|
-
/not a destination you named/,
|
|
1584
|
-
);
|
|
1585
|
-
expect(received).toHaveLength(0);
|
|
1586
|
-
|
|
1587
|
-
// The same URL, NAMED, is fine — the rule is about provenance, not about the host.
|
|
1588
|
-
await writeConfig(
|
|
1589
|
-
{ gateway: { url, url_source: 'named', api_key: 'sk-x' } },
|
|
1590
|
-
{ XDG_CONFIG_HOME: home },
|
|
1591
|
-
);
|
|
1592
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, noEnv);
|
|
1593
|
-
expect(received).toHaveLength(1);
|
|
1594
|
-
});
|
|
1595
|
-
|
|
1596
|
-
it('treats an explicitly configured URL without provenance as named', async () => {
|
|
1597
|
-
await seedRun();
|
|
1598
|
-
const noEnv = { XDG_CONFIG_HOME: home };
|
|
1599
|
-
|
|
1600
|
-
await writeConfig({ gateway: { url, api_key: 'sk-x' } }, { XDG_CONFIG_HOME: home });
|
|
1601
|
-
await pushCommand(parseArgs(['push', runId]), out, workspace, noEnv);
|
|
1602
|
-
expect(received).toHaveLength(1);
|
|
1603
|
-
});
|
|
1604
|
-
/*
|
|
1605
|
-
THE FIFTH SITE OF "nothing that lost the lock may touch what the lock protects", and the one that
|
|
1606
|
-
did not ask (orcacode-review).
|
|
1607
|
-
|
|
1608
|
-
`recoverInterruptedSwap` runs first inside the pull's critical section, and every branch of it
|
|
1609
|
-
either `rm -rf`s or promotes one of the two deterministic scratch names — so it is the most
|
|
1610
|
-
destructive member of the set, not a bystander. `revertStagedSwap`'s own comment already stated
|
|
1611
|
-
the rule it was breaking: "once the lock has moved they name ANOTHER pull's in-flight state".
|
|
1612
|
-
|
|
1613
|
-
The interleaving: pull A takes the lock and is stopped before its first statement (SIGSTOP, a
|
|
1614
|
-
suspended laptop). No heartbeats land, so after STALE_LOCK_MS its lock is legitimately judged
|
|
1615
|
-
abandoned; pull B breaks it, takes its own, and starts writing into `<run>.incoming`. A resumes
|
|
1616
|
-
into `recoverInterruptedSwap`, finds `dest` present, takes the "the siblings are litter" branch
|
|
1617
|
-
and deletes B's in-flight staging. B notices nothing — its own `stillHeld()` is true — recreates
|
|
1618
|
-
directories as it writes the rest, renames the gutted staging into place and prints `pull.done`.
|
|
1619
|
-
|
|
1620
|
-
Asserted per branch rather than once, because each decides about a different pair of paths and an
|
|
1621
|
-
early return in only one of them would still leave three ways to destroy the new holder's work.
|
|
1622
|
-
*/
|
|
1623
|
-
it.each([
|
|
1624
|
-
{
|
|
1625
|
-
what: 'dest present: the two siblings look like litter',
|
|
1626
|
-
dest: true,
|
|
1627
|
-
staging: true,
|
|
1628
|
-
retired: true,
|
|
1629
|
-
},
|
|
1630
|
-
{
|
|
1631
|
-
what: 'dest absent with both siblings: promote staging, drop retired',
|
|
1632
|
-
dest: false,
|
|
1633
|
-
staging: true,
|
|
1634
|
-
retired: true,
|
|
1635
|
-
},
|
|
1636
|
-
{
|
|
1637
|
-
what: 'dest absent with only the retired copy: put it back',
|
|
1638
|
-
dest: false,
|
|
1639
|
-
staging: false,
|
|
1640
|
-
retired: true,
|
|
1641
|
-
},
|
|
1642
|
-
{
|
|
1643
|
-
what: 'dest absent with only staging: drop it as partial',
|
|
1644
|
-
dest: false,
|
|
1645
|
-
staging: true,
|
|
1646
|
-
retired: false,
|
|
1647
|
-
},
|
|
1648
|
-
])(
|
|
1649
|
-
'recovery touches nothing once the lock has moved — $what',
|
|
1650
|
-
async ({ dest: hasDest, staging: hasStaging, retired: hasRetired }) => {
|
|
1651
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1652
|
-
await mkdir(runs, { recursive: true });
|
|
1653
|
-
const dest = join(runs, runId);
|
|
1654
|
-
const staging = `${dest}.incoming`;
|
|
1655
|
-
const retired = `${dest}.replaced`;
|
|
1656
|
-
|
|
1657
|
-
if (hasDest) {
|
|
1658
|
-
await mkdir(dest, { recursive: true });
|
|
1659
|
-
await writeFile(join(dest, 'events.jsonl'), 'the installed run\n');
|
|
1660
|
-
}
|
|
1661
|
-
if (hasStaging) {
|
|
1662
|
-
await mkdir(staging, { recursive: true });
|
|
1663
|
-
await writeFile(join(staging, 'events.jsonl'), 'the new holder\n');
|
|
1664
|
-
}
|
|
1665
|
-
if (hasRetired) {
|
|
1666
|
-
await mkdir(retired, { recursive: true });
|
|
1667
|
-
await writeFile(join(retired, 'events.jsonl'), 'the old run\n');
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
await recoverInterruptedSwap(dest, async () => false);
|
|
1671
|
-
|
|
1672
|
-
const read = (p: string) => readFile(join(p, 'events.jsonl'), 'utf8').catch(() => undefined);
|
|
1673
|
-
expect(
|
|
1674
|
-
await read(staging),
|
|
1675
|
-
'an evicted pull deleted or promoted the staging directory the lock’s new holder was writing into',
|
|
1676
|
-
).toBe(hasStaging ? 'the new holder\n' : undefined);
|
|
1677
|
-
expect(
|
|
1678
|
-
await read(retired),
|
|
1679
|
-
'an evicted pull dropped the copy the new holder had moved aside, so its own rollback cannot restore it',
|
|
1680
|
-
).toBe(hasRetired ? 'the old run\n' : undefined);
|
|
1681
|
-
expect(
|
|
1682
|
-
await read(dest),
|
|
1683
|
-
'an evicted pull installed something over the destination it no longer owns',
|
|
1684
|
-
).toBe(hasDest ? 'the installed run\n' : undefined);
|
|
1685
|
-
},
|
|
1686
|
-
);
|
|
1687
|
-
|
|
1688
|
-
/*
|
|
1689
|
-
…and the guard must not be a way of never recovering. Without this the fix above passes by doing
|
|
1690
|
-
nothing at all, which would silently reintroduce the vanished-run case the deterministic scratch
|
|
1691
|
-
names exist to make recoverable.
|
|
1692
|
-
*/
|
|
1693
|
-
it('still finishes an interrupted swap while the lock is ours', async () => {
|
|
1694
|
-
const runs = join(workspace, '.agenticreplay', 'runs');
|
|
1695
|
-
await mkdir(runs, { recursive: true });
|
|
1696
|
-
const dest = join(runs, runId);
|
|
1697
|
-
const staging = `${dest}.incoming`;
|
|
1698
|
-
const retired = `${dest}.replaced`;
|
|
1699
|
-
await mkdir(staging, { recursive: true });
|
|
1700
|
-
await writeFile(join(staging, 'events.jsonl'), 'the finished new copy\n');
|
|
1701
|
-
await mkdir(retired, { recursive: true });
|
|
1702
|
-
await writeFile(join(retired, 'events.jsonl'), 'the old run\n');
|
|
1703
|
-
|
|
1704
|
-
await recoverInterruptedSwap(dest, async () => true);
|
|
1705
|
-
|
|
1706
|
-
expect(await readFile(join(dest, 'events.jsonl'), 'utf8')).toBe('the finished new copy\n');
|
|
1707
|
-
expect(await stat(retired).catch(() => undefined)).toBeUndefined();
|
|
1708
|
-
});
|
|
1709
|
-
});
|