@oscharko-dev/keiko 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +7 -0
- package/README.md +621 -0
- package/TRADEMARKS.md +41 -0
- package/dist/audit/aggregate.d.ts +5 -0
- package/dist/audit/aggregate.js +25 -0
- package/dist/audit/build.d.ts +2 -0
- package/dist/audit/build.js +224 -0
- package/dist/audit/errors.d.ts +25 -0
- package/dist/audit/errors.js +39 -0
- package/dist/audit/index-api.d.ts +14 -0
- package/dist/audit/index-api.js +131 -0
- package/dist/audit/index.d.ts +12 -0
- package/dist/audit/index.js +17 -0
- package/dist/audit/persist.d.ts +8 -0
- package/dist/audit/persist.js +40 -0
- package/dist/audit/redaction.d.ts +3 -0
- package/dist/audit/redaction.js +61 -0
- package/dist/audit/report.d.ts +18 -0
- package/dist/audit/report.js +50 -0
- package/dist/audit/retention.d.ts +3 -0
- package/dist/audit/retention.js +95 -0
- package/dist/audit/runid.d.ts +1 -0
- package/dist/audit/runid.js +29 -0
- package/dist/audit/side-file.d.ts +12 -0
- package/dist/audit/side-file.js +82 -0
- package/dist/audit/store.d.ts +12 -0
- package/dist/audit/store.js +198 -0
- package/dist/audit/types.d.ts +188 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit/workflow-evidence.d.ts +27 -0
- package/dist/audit/workflow-evidence.js +145 -0
- package/dist/cli/context.d.ts +2 -0
- package/dist/cli/context.js +102 -0
- package/dist/cli/evaluate.d.ts +7 -0
- package/dist/cli/evaluate.js +207 -0
- package/dist/cli/evidence.d.ts +8 -0
- package/dist/cli/evidence.js +88 -0
- package/dist/cli/gateway-config.d.ts +10 -0
- package/dist/cli/gateway-config.js +12 -0
- package/dist/cli/gen-tests.d.ts +7 -0
- package/dist/cli/gen-tests.js +208 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/investigate.d.ts +8 -0
- package/dist/cli/investigate.js +242 -0
- package/dist/cli/models.d.ts +3 -0
- package/dist/cli/models.js +64 -0
- package/dist/cli/run.d.ts +7 -0
- package/dist/cli/run.js +187 -0
- package/dist/cli/runner.d.ts +6 -0
- package/dist/cli/runner.js +83 -0
- package/dist/cli/ui.d.ts +31 -0
- package/dist/cli/ui.js +240 -0
- package/dist/cli/verify.d.ts +2 -0
- package/dist/cli/verify.js +103 -0
- package/dist/evaluations/fixtures/bug-investigation/happy-path.d.ts +2 -0
- package/dist/evaluations/fixtures/bug-investigation/happy-path.js +66 -0
- package/dist/evaluations/fixtures/bug-investigation/investigation-only.d.ts +2 -0
- package/dist/evaluations/fixtures/bug-investigation/investigation-only.js +39 -0
- package/dist/evaluations/fixtures/bug-investigation/unsafe-action.d.ts +2 -0
- package/dist/evaluations/fixtures/bug-investigation/unsafe-action.js +37 -0
- package/dist/evaluations/fixtures/index.d.ts +7 -0
- package/dist/evaluations/fixtures/index.js +35 -0
- package/dist/evaluations/fixtures/support.d.ts +5 -0
- package/dist/evaluations/fixtures/support.js +42 -0
- package/dist/evaluations/fixtures/unit-tests/happy-path.d.ts +2 -0
- package/dist/evaluations/fixtures/unit-tests/happy-path.js +40 -0
- package/dist/evaluations/fixtures/unit-tests/retry-then-accept.d.ts +2 -0
- package/dist/evaluations/fixtures/unit-tests/retry-then-accept.js +39 -0
- package/dist/evaluations/fixtures/unit-tests/unsafe-action.d.ts +2 -0
- package/dist/evaluations/fixtures/unit-tests/unsafe-action.js +32 -0
- package/dist/evaluations/index.d.ts +12 -0
- package/dist/evaluations/index.js +12 -0
- package/dist/evaluations/manifest-check.d.ts +1 -0
- package/dist/evaluations/manifest-check.js +48 -0
- package/dist/evaluations/model-provider.d.ts +12 -0
- package/dist/evaluations/model-provider.js +26 -0
- package/dist/evaluations/render.d.ts +2 -0
- package/dist/evaluations/render.js +59 -0
- package/dist/evaluations/runner-support.d.ts +27 -0
- package/dist/evaluations/runner-support.js +163 -0
- package/dist/evaluations/runner.d.ts +20 -0
- package/dist/evaluations/runner.js +174 -0
- package/dist/evaluations/scorer.d.ts +14 -0
- package/dist/evaluations/scorer.js +131 -0
- package/dist/evaluations/scripted-model.d.ts +6 -0
- package/dist/evaluations/scripted-model.js +26 -0
- package/dist/evaluations/surface-parity.d.ts +2 -0
- package/dist/evaluations/surface-parity.js +184 -0
- package/dist/evaluations/types.d.ts +74 -0
- package/dist/evaluations/types.js +16 -0
- package/dist/gateway/capabilities.d.ts +11 -0
- package/dist/gateway/capabilities.data.d.ts +2 -0
- package/dist/gateway/capabilities.data.js +203 -0
- package/dist/gateway/capabilities.js +41 -0
- package/dist/gateway/config.d.ts +15 -0
- package/dist/gateway/config.js +154 -0
- package/dist/gateway/errors.d.ts +72 -0
- package/dist/gateway/errors.js +82 -0
- package/dist/gateway/gateway.d.ts +19 -0
- package/dist/gateway/gateway.js +94 -0
- package/dist/gateway/index.d.ts +10 -0
- package/dist/gateway/index.js +11 -0
- package/dist/gateway/model-selection.d.ts +9 -0
- package/dist/gateway/model-selection.js +36 -0
- package/dist/gateway/normalize.d.ts +7 -0
- package/dist/gateway/normalize.js +93 -0
- package/dist/gateway/openai-adapter.d.ts +20 -0
- package/dist/gateway/openai-adapter.js +263 -0
- package/dist/gateway/redaction.d.ts +1 -0
- package/dist/gateway/redaction.js +51 -0
- package/dist/gateway/resilience.d.ts +24 -0
- package/dist/gateway/resilience.js +166 -0
- package/dist/gateway/types.d.ts +108 -0
- package/dist/gateway/types.js +2 -0
- package/dist/harness/adapters.d.ts +23 -0
- package/dist/harness/adapters.js +38 -0
- package/dist/harness/context.d.ts +33 -0
- package/dist/harness/context.js +21 -0
- package/dist/harness/emitter.d.ts +15 -0
- package/dist/harness/emitter.js +72 -0
- package/dist/harness/errors.d.ts +21 -0
- package/dist/harness/errors.js +39 -0
- package/dist/harness/executor.d.ts +3 -0
- package/dist/harness/executor.js +211 -0
- package/dist/harness/fingerprint.d.ts +6 -0
- package/dist/harness/fingerprint.js +43 -0
- package/dist/harness/index.d.ts +9 -0
- package/dist/harness/index.js +13 -0
- package/dist/harness/loop.d.ts +3 -0
- package/dist/harness/loop.js +159 -0
- package/dist/harness/patcher.d.ts +4 -0
- package/dist/harness/patcher.js +49 -0
- package/dist/harness/planner.d.ts +3 -0
- package/dist/harness/planner.js +21 -0
- package/dist/harness/ports.d.ts +61 -0
- package/dist/harness/ports.js +4 -0
- package/dist/harness/session.d.ts +25 -0
- package/dist/harness/session.js +116 -0
- package/dist/harness/sinks.d.ts +30 -0
- package/dist/harness/sinks.js +72 -0
- package/dist/harness/tasks/explain-plan.d.ts +3 -0
- package/dist/harness/tasks/explain-plan.js +29 -0
- package/dist/harness/tasks/generate-unit-tests.d.ts +3 -0
- package/dist/harness/tasks/generate-unit-tests.js +28 -0
- package/dist/harness/tasks/investigate-bug.d.ts +3 -0
- package/dist/harness/tasks/investigate-bug.js +31 -0
- package/dist/harness/tasks/policy.d.ts +11 -0
- package/dist/harness/tasks/policy.js +22 -0
- package/dist/harness/tasks/verify.d.ts +3 -0
- package/dist/harness/tasks/verify.js +16 -0
- package/dist/harness/types.d.ts +270 -0
- package/dist/harness/types.js +33 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +36 -0
- package/dist/sdk/index.d.ts +9 -0
- package/dist/sdk/index.js +37 -0
- package/dist/sdk/run-agent.d.ts +16 -0
- package/dist/sdk/run-agent.js +56 -0
- package/dist/tools/browser/cdp-client.d.ts +35 -0
- package/dist/tools/browser/cdp-client.js +218 -0
- package/dist/tools/browser/errors.d.ts +25 -0
- package/dist/tools/browser/errors.js +55 -0
- package/dist/tools/browser/index.d.ts +5 -0
- package/dist/tools/browser/index.js +6 -0
- package/dist/tools/browser/session.d.ts +44 -0
- package/dist/tools/browser/session.js +748 -0
- package/dist/tools/browser/types.d.ts +48 -0
- package/dist/tools/browser/types.js +2 -0
- package/dist/tools/browser/validators.d.ts +5 -0
- package/dist/tools/browser/validators.js +97 -0
- package/dist/tools/errors.d.ts +59 -0
- package/dist/tools/errors.js +94 -0
- package/dist/tools/exec.d.ts +42 -0
- package/dist/tools/exec.js +327 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/patch-content.d.ts +10 -0
- package/dist/tools/patch-content.js +126 -0
- package/dist/tools/patch-normalize.d.ts +1 -0
- package/dist/tools/patch-normalize.js +80 -0
- package/dist/tools/patch-parse.d.ts +8 -0
- package/dist/tools/patch-parse.js +201 -0
- package/dist/tools/patch.d.ts +18 -0
- package/dist/tools/patch.js +403 -0
- package/dist/tools/registry.d.ts +36 -0
- package/dist/tools/registry.js +231 -0
- package/dist/tools/sandbox.d.ts +8 -0
- package/dist/tools/sandbox.js +121 -0
- package/dist/tools/schemas.d.ts +2 -0
- package/dist/tools/schemas.js +51 -0
- package/dist/tools/terminal-policy.d.ts +9 -0
- package/dist/tools/terminal-policy.js +313 -0
- package/dist/tools/types.d.ts +99 -0
- package/dist/tools/types.js +103 -0
- package/dist/tools/writer.d.ts +7 -0
- package/dist/tools/writer.js +20 -0
- package/dist/ui/browser.d.ts +10 -0
- package/dist/ui/browser.js +231 -0
- package/dist/ui/chat-handlers.d.ts +4 -0
- package/dist/ui/chat-handlers.js +281 -0
- package/dist/ui/csp-hashes.json +17 -0
- package/dist/ui/csp.d.ts +2 -0
- package/dist/ui/csp.js +66 -0
- package/dist/ui/deps.d.ts +34 -0
- package/dist/ui/deps.js +137 -0
- package/dist/ui/evidence.d.ts +27 -0
- package/dist/ui/evidence.js +142 -0
- package/dist/ui/files-deny.d.ts +2 -0
- package/dist/ui/files-deny.js +12 -0
- package/dist/ui/files.d.ts +65 -0
- package/dist/ui/files.js +492 -0
- package/dist/ui/headers.d.ts +2 -0
- package/dist/ui/headers.js +21 -0
- package/dist/ui/host-check.d.ts +2 -0
- package/dist/ui/host-check.js +58 -0
- package/dist/ui/index.d.ts +20 -0
- package/dist/ui/index.js +23 -0
- package/dist/ui/load-csp.d.ts +1 -0
- package/dist/ui/load-csp.js +28 -0
- package/dist/ui/read-handlers.d.ts +8 -0
- package/dist/ui/read-handlers.js +247 -0
- package/dist/ui/routes.d.ts +36 -0
- package/dist/ui/routes.js +129 -0
- package/dist/ui/run-engine.d.ts +20 -0
- package/dist/ui/run-engine.js +345 -0
- package/dist/ui/run-handlers.d.ts +8 -0
- package/dist/ui/run-handlers.js +431 -0
- package/dist/ui/run-request.d.ts +13 -0
- package/dist/ui/run-request.js +219 -0
- package/dist/ui/runs.d.ts +43 -0
- package/dist/ui/runs.js +92 -0
- package/dist/ui/server.d.ts +11 -0
- package/dist/ui/server.js +143 -0
- package/dist/ui/sink.d.ts +27 -0
- package/dist/ui/sink.js +80 -0
- package/dist/ui/sse.d.ts +7 -0
- package/dist/ui/sse.js +27 -0
- package/dist/ui/static/404.html +1 -0
- package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_buildManifest.js +1 -0
- package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_ssgManifest.js +1 -0
- package/dist/ui/static/_next/static/chunks/255-d47fd57964443afe.js +1 -0
- package/dist/ui/static/_next/static/chunks/4-be1fef693af8e088.js +1 -0
- package/dist/ui/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
- package/dist/ui/static/_next/static/chunks/app/_not-found/page-75825b09bcecad97.js +1 -0
- package/dist/ui/static/_next/static/chunks/app/launch/page-9c86a13c29884245.js +1 -0
- package/dist/ui/static/_next/static/chunks/app/layout-bdea63fe87947d50.js +1 -0
- package/dist/ui/static/_next/static/chunks/app/page-4168c12c68b7a853.js +1 -0
- package/dist/ui/static/_next/static/chunks/framework-a6e0b7e30f98059a.js +1 -0
- package/dist/ui/static/_next/static/chunks/main-778a50aebff02192.js +1 -0
- package/dist/ui/static/_next/static/chunks/main-app-30679af7240d63e9.js +1 -0
- package/dist/ui/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
- package/dist/ui/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
- package/dist/ui/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/ui/static/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
- package/dist/ui/static/_next/static/css/be7cb54d5c5673b6.css +1 -0
- package/dist/ui/static/assets/editors/goland.svg +35 -0
- package/dist/ui/static/assets/editors/intellij.svg +39 -0
- package/dist/ui/static/assets/editors/pycharm.svg +58 -0
- package/dist/ui/static/assets/editors/rustrover.svg +19 -0
- package/dist/ui/static/assets/editors/vscode.svg +1 -0
- package/dist/ui/static/assets/editors/webstorm.svg +21 -0
- package/dist/ui/static/assets/icons/anthropic.svg +1 -0
- package/dist/ui/static/assets/icons/brave.svg +1 -0
- package/dist/ui/static/assets/icons/css3.svg +1 -0
- package/dist/ui/static/assets/icons/docker.svg +1 -0
- package/dist/ui/static/assets/icons/git.svg +1 -0
- package/dist/ui/static/assets/icons/github.svg +1 -0
- package/dist/ui/static/assets/icons/go.svg +1 -0
- package/dist/ui/static/assets/icons/gradle.svg +1 -0
- package/dist/ui/static/assets/icons/grafana.svg +1 -0
- package/dist/ui/static/assets/icons/graphql.svg +1 -0
- package/dist/ui/static/assets/icons/html5.svg +1 -0
- package/dist/ui/static/assets/icons/image.svg +1 -0
- package/dist/ui/static/assets/icons/java.svg +1 -0
- package/dist/ui/static/assets/icons/javascript.svg +1 -0
- package/dist/ui/static/assets/icons/json.svg +1 -0
- package/dist/ui/static/assets/icons/kafka.svg +1 -0
- package/dist/ui/static/assets/icons/kubernetes.svg +1 -0
- package/dist/ui/static/assets/icons/linear.svg +1 -0
- package/dist/ui/static/assets/icons/markdown.svg +1 -0
- package/dist/ui/static/assets/icons/nginx.svg +1 -0
- package/dist/ui/static/assets/icons/nodejs.svg +1 -0
- package/dist/ui/static/assets/icons/notion.svg +1 -0
- package/dist/ui/static/assets/icons/openai.svg +1 -0
- package/dist/ui/static/assets/icons/playwright.svg +1 -0
- package/dist/ui/static/assets/icons/postgresql.svg +1 -0
- package/dist/ui/static/assets/icons/prometheus.svg +1 -0
- package/dist/ui/static/assets/icons/properties.svg +1 -0
- package/dist/ui/static/assets/icons/puppeteer.svg +1 -0
- package/dist/ui/static/assets/icons/python.svg +1 -0
- package/dist/ui/static/assets/icons/react.svg +1 -0
- package/dist/ui/static/assets/icons/redis.svg +1 -0
- package/dist/ui/static/assets/icons/rust.svg +1 -0
- package/dist/ui/static/assets/icons/sentry.svg +1 -0
- package/dist/ui/static/assets/icons/slack.svg +1 -0
- package/dist/ui/static/assets/icons/spring.svg +1 -0
- package/dist/ui/static/assets/icons/typescript.svg +1 -0
- package/dist/ui/static/assets/icons/upstash.svg +1 -0
- package/dist/ui/static/assets/icons/yaml.svg +1 -0
- package/dist/ui/static/assets/keiko-logo.svg +10 -0
- package/dist/ui/static/index.html +1 -0
- package/dist/ui/static/index.txt +19 -0
- package/dist/ui/static/keiko-logo.svg +10 -0
- package/dist/ui/static/launch.html +1 -0
- package/dist/ui/static/launch.txt +19 -0
- package/dist/ui/static.d.ts +3 -0
- package/dist/ui/static.js +72 -0
- package/dist/ui/store/chats.d.ts +14 -0
- package/dist/ui/store/chats.js +110 -0
- package/dist/ui/store/db.d.ts +6 -0
- package/dist/ui/store/db.js +182 -0
- package/dist/ui/store/errors.d.ts +12 -0
- package/dist/ui/store/errors.js +30 -0
- package/dist/ui/store/index.d.ts +6 -0
- package/dist/ui/store/index.js +6 -0
- package/dist/ui/store/messages.d.ts +5 -0
- package/dist/ui/store/messages.js +137 -0
- package/dist/ui/store/paths.d.ts +4 -0
- package/dist/ui/store/paths.js +69 -0
- package/dist/ui/store/projects.d.ts +7 -0
- package/dist/ui/store/projects.js +61 -0
- package/dist/ui/store/schema.d.ts +3 -0
- package/dist/ui/store/schema.js +77 -0
- package/dist/ui/store/types.d.ts +80 -0
- package/dist/ui/store/types.js +3 -0
- package/dist/ui/store/validation.d.ts +4 -0
- package/dist/ui/store/validation.js +72 -0
- package/dist/ui/store-handlers.d.ts +16 -0
- package/dist/ui/store-handlers.js +465 -0
- package/dist/ui/terminal-errors.d.ts +21 -0
- package/dist/ui/terminal-errors.js +45 -0
- package/dist/ui/terminal-evidence.d.ts +20 -0
- package/dist/ui/terminal-evidence.js +65 -0
- package/dist/ui/terminal-routes.d.ts +9 -0
- package/dist/ui/terminal-routes.js +219 -0
- package/dist/ui/terminal.d.ts +67 -0
- package/dist/ui/terminal.js +835 -0
- package/dist/verification/classify.d.ts +10 -0
- package/dist/verification/classify.js +53 -0
- package/dist/verification/detect.d.ts +4 -0
- package/dist/verification/detect.js +81 -0
- package/dist/verification/errors.d.ts +11 -0
- package/dist/verification/errors.js +21 -0
- package/dist/verification/index.d.ts +17 -0
- package/dist/verification/index.js +13 -0
- package/dist/verification/limits.d.ts +3 -0
- package/dist/verification/limits.js +40 -0
- package/dist/verification/monitor.d.ts +4 -0
- package/dist/verification/monitor.js +58 -0
- package/dist/verification/orchestrator.d.ts +16 -0
- package/dist/verification/orchestrator.js +363 -0
- package/dist/verification/plan.d.ts +9 -0
- package/dist/verification/plan.js +125 -0
- package/dist/verification/summary.d.ts +40 -0
- package/dist/verification/summary.js +67 -0
- package/dist/verification/types.d.ts +63 -0
- package/dist/verification/types.js +13 -0
- package/dist/workflows/bug-investigation/context.d.ts +7 -0
- package/dist/workflows/bug-investigation/context.js +119 -0
- package/dist/workflows/bug-investigation/descriptor.d.ts +3 -0
- package/dist/workflows/bug-investigation/descriptor.js +46 -0
- package/dist/workflows/bug-investigation/emit.d.ts +12 -0
- package/dist/workflows/bug-investigation/emit.js +35 -0
- package/dist/workflows/bug-investigation/events.d.ts +81 -0
- package/dist/workflows/bug-investigation/events.js +9 -0
- package/dist/workflows/bug-investigation/failure-parse.d.ts +3 -0
- package/dist/workflows/bug-investigation/failure-parse.js +154 -0
- package/dist/workflows/bug-investigation/guard.d.ts +2 -0
- package/dist/workflows/bug-investigation/guard.js +69 -0
- package/dist/workflows/bug-investigation/index.d.ts +7 -0
- package/dist/workflows/bug-investigation/index.js +13 -0
- package/dist/workflows/bug-investigation/internal.d.ts +37 -0
- package/dist/workflows/bug-investigation/internal.js +64 -0
- package/dist/workflows/bug-investigation/model-loop.d.ts +4 -0
- package/dist/workflows/bug-investigation/model-loop.js +223 -0
- package/dist/workflows/bug-investigation/parse.d.ts +3 -0
- package/dist/workflows/bug-investigation/parse.js +123 -0
- package/dist/workflows/bug-investigation/prompt.d.ts +4 -0
- package/dist/workflows/bug-investigation/prompt.js +107 -0
- package/dist/workflows/bug-investigation/report.d.ts +23 -0
- package/dist/workflows/bug-investigation/report.js +151 -0
- package/dist/workflows/bug-investigation/stages.d.ts +13 -0
- package/dist/workflows/bug-investigation/stages.js +242 -0
- package/dist/workflows/bug-investigation/types.d.ts +91 -0
- package/dist/workflows/bug-investigation/types.js +14 -0
- package/dist/workflows/bug-investigation/verify-stage.d.ts +10 -0
- package/dist/workflows/bug-investigation/verify-stage.js +91 -0
- package/dist/workflows/bug-investigation/workflow.d.ts +2 -0
- package/dist/workflows/bug-investigation/workflow.js +74 -0
- package/dist/workflows/descriptor.d.ts +20 -0
- package/dist/workflows/descriptor.js +8 -0
- package/dist/workflows/index.d.ts +3 -0
- package/dist/workflows/index.js +2 -0
- package/dist/workflows/unit-tests/context.d.ts +7 -0
- package/dist/workflows/unit-tests/context.js +129 -0
- package/dist/workflows/unit-tests/conventions.d.ts +4 -0
- package/dist/workflows/unit-tests/conventions.js +87 -0
- package/dist/workflows/unit-tests/descriptor.d.ts +4 -0
- package/dist/workflows/unit-tests/descriptor.js +43 -0
- package/dist/workflows/unit-tests/emit.d.ts +12 -0
- package/dist/workflows/unit-tests/emit.js +35 -0
- package/dist/workflows/unit-tests/events.d.ts +78 -0
- package/dist/workflows/unit-tests/events.js +7 -0
- package/dist/workflows/unit-tests/index.d.ts +6 -0
- package/dist/workflows/unit-tests/index.js +10 -0
- package/dist/workflows/unit-tests/internal.d.ts +35 -0
- package/dist/workflows/unit-tests/internal.js +43 -0
- package/dist/workflows/unit-tests/model-loop.d.ts +4 -0
- package/dist/workflows/unit-tests/model-loop.js +95 -0
- package/dist/workflows/unit-tests/parse.d.ts +6 -0
- package/dist/workflows/unit-tests/parse.js +68 -0
- package/dist/workflows/unit-tests/prompt.d.ts +4 -0
- package/dist/workflows/unit-tests/prompt.js +71 -0
- package/dist/workflows/unit-tests/report.d.ts +21 -0
- package/dist/workflows/unit-tests/report.js +90 -0
- package/dist/workflows/unit-tests/stages.d.ts +9 -0
- package/dist/workflows/unit-tests/stages.js +155 -0
- package/dist/workflows/unit-tests/types.d.ts +70 -0
- package/dist/workflows/unit-tests/types.js +11 -0
- package/dist/workflows/unit-tests/verify-stage.d.ts +9 -0
- package/dist/workflows/unit-tests/verify-stage.js +56 -0
- package/dist/workflows/unit-tests/workflow.d.ts +2 -0
- package/dist/workflows/unit-tests/workflow.js +58 -0
- package/dist/workspace/contextPack.d.ts +9 -0
- package/dist/workspace/contextPack.js +94 -0
- package/dist/workspace/detect.d.ts +3 -0
- package/dist/workspace/detect.js +135 -0
- package/dist/workspace/discovery.d.ts +9 -0
- package/dist/workspace/discovery.js +167 -0
- package/dist/workspace/errors.d.ts +39 -0
- package/dist/workspace/errors.js +66 -0
- package/dist/workspace/fs.d.ts +21 -0
- package/dist/workspace/fs.js +36 -0
- package/dist/workspace/ignore.d.ts +14 -0
- package/dist/workspace/ignore.js +176 -0
- package/dist/workspace/index.d.ts +11 -0
- package/dist/workspace/index.js +13 -0
- package/dist/workspace/paths.d.ts +2 -0
- package/dist/workspace/paths.js +38 -0
- package/dist/workspace/realpath.d.ts +7 -0
- package/dist/workspace/realpath.js +72 -0
- package/dist/workspace/retrieval.d.ts +9 -0
- package/dist/workspace/retrieval.js +74 -0
- package/dist/workspace/summary.d.ts +3 -0
- package/dist/workspace/summary.js +54 -0
- package/dist/workspace/types.d.ts +103 -0
- package/dist/workspace/types.js +27 -0
- package/package.json +58 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Final-report payload + renderer (ADR-0010 D9). buildEvidenceReport produces a structured,
|
|
2
|
+
// JSON-serializable summary of a persisted manifest; renderEvidenceReport renders it for the CLI.
|
|
3
|
+
// Both are PURE (no IO). knownLimitations is static text stating the Wave-1 evidence bounds
|
|
4
|
+
// (no tamper-evidence, no encryption at rest, per-run cost attribution) so a reviewer reads the
|
|
5
|
+
// honest trust boundary alongside the evidence.
|
|
6
|
+
const KNOWN_LIMITATIONS = [
|
|
7
|
+
"Evidence files are developer-writable: no tamper-evidence or immutability (out of scope).",
|
|
8
|
+
"Evidence is stored as plaintext JSON: no encryption at rest; redaction removes known shapes only.",
|
|
9
|
+
"Cost attribution is per-run (the declared model's class), not per model call.",
|
|
10
|
+
];
|
|
11
|
+
function statusFromHarnessResults(results) {
|
|
12
|
+
if (results === undefined || results.length === 0) {
|
|
13
|
+
return "not-run";
|
|
14
|
+
}
|
|
15
|
+
return results.every((result) => result.passed) ? "passed" : "failed";
|
|
16
|
+
}
|
|
17
|
+
function verificationStatus(manifest) {
|
|
18
|
+
return (manifest.verification?.overallStatus ?? statusFromHarnessResults(manifest.verificationResults));
|
|
19
|
+
}
|
|
20
|
+
export function buildEvidenceReport(manifest, location) {
|
|
21
|
+
return {
|
|
22
|
+
evidenceLocation: location,
|
|
23
|
+
runId: manifest.run.runId,
|
|
24
|
+
fingerprint: manifest.run.fingerprint,
|
|
25
|
+
taskType: manifest.run.taskType,
|
|
26
|
+
outcome: manifest.run.outcome,
|
|
27
|
+
changedFiles: manifest.patch?.changedFiles ?? 0,
|
|
28
|
+
usageTotals: manifest.usageTotals,
|
|
29
|
+
costClass: manifest.model.costClass,
|
|
30
|
+
verificationStatus: verificationStatus(manifest),
|
|
31
|
+
knownLimitations: KNOWN_LIMITATIONS,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function renderEvidenceReport(report) {
|
|
35
|
+
const { usageTotals: u } = report;
|
|
36
|
+
const lines = [
|
|
37
|
+
`Evidence: ${report.evidenceLocation}`,
|
|
38
|
+
` run ${report.runId} (fingerprint ${report.fingerprint})`,
|
|
39
|
+
` task ${report.taskType}`,
|
|
40
|
+
` outcome ${report.outcome}`,
|
|
41
|
+
` changed files ${String(report.changedFiles)}`,
|
|
42
|
+
` usage ${String(u.promptTokens)} prompt / ${String(u.completionTokens)} completion tokens, ` +
|
|
43
|
+
`${String(u.requestCount)} request(s), ${String(u.totalLatencyMs)}ms`,
|
|
44
|
+
` cost class ${report.costClass}`,
|
|
45
|
+
` verification ${report.verificationStatus}`,
|
|
46
|
+
" known limitations:",
|
|
47
|
+
...report.knownLimitations.map((limitation) => ` - ${limitation}`),
|
|
48
|
+
];
|
|
49
|
+
return `${lines.join("\n")}\n`;
|
|
50
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Retention and rotation (ADR-0010 D6). The single most dangerous operation in the layer, so it is
|
|
2
|
+
// the most tightly bounded: it deletes ONLY ledger-created `<runId>.json` files (every runId the
|
|
3
|
+
// store enumerates already passed assertValidRunId), inside the contained base dir, via
|
|
4
|
+
// EvidenceStore.delete. It computes the delete set then deletes that set (no recursion). "Oldest" is
|
|
5
|
+
// read from each manifest's finishedAt header — never filesystem mtime, which a developer touch
|
|
6
|
+
// could perturb. When disabled, deletion is a no-op. An unparseable manifest is left untouched
|
|
7
|
+
// rather than risking deletion of a file we cannot read a header from.
|
|
8
|
+
function readHeader(json) {
|
|
9
|
+
try {
|
|
10
|
+
const parsed = JSON.parse(json);
|
|
11
|
+
const finishedAt = parsed.run?.finishedAt;
|
|
12
|
+
if (typeof finishedAt !== "number") {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return { finishedAt, bytes: Buffer.byteLength(json, "utf8") };
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Newest-first ordering by finishedAt; ties broken by runId so the order is deterministic.
|
|
22
|
+
function collectCandidates(store) {
|
|
23
|
+
const candidates = [];
|
|
24
|
+
for (const runId of store.list()) {
|
|
25
|
+
const json = store.get(runId);
|
|
26
|
+
if (json === undefined) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const header = readHeader(json);
|
|
30
|
+
if (header === undefined) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
candidates.push({ runId, finishedAt: header.finishedAt, bytes: header.bytes });
|
|
34
|
+
}
|
|
35
|
+
candidates.sort((a, b) => b.finishedAt - a.finishedAt || a.runId.localeCompare(b.runId));
|
|
36
|
+
return candidates;
|
|
37
|
+
}
|
|
38
|
+
function beyondMaxRuns(sorted, maxRuns) {
|
|
39
|
+
return sorted.slice(Math.max(maxRuns, 0)).map((c) => c.runId);
|
|
40
|
+
}
|
|
41
|
+
function olderThanAge(sorted, maxAgeMs) {
|
|
42
|
+
const newest = sorted[0]?.finishedAt;
|
|
43
|
+
if (newest === undefined) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const cutoff = newest - maxAgeMs;
|
|
47
|
+
return sorted.filter((c) => c.finishedAt < cutoff).map((c) => c.runId);
|
|
48
|
+
}
|
|
49
|
+
function overByteCap(sorted, maxTotalBytes) {
|
|
50
|
+
const doomed = [];
|
|
51
|
+
let running = 0;
|
|
52
|
+
// Walk newest-first, keeping manifests until the cap is reached; the rest (oldest) are deleted.
|
|
53
|
+
// The newest manifest (index 0) is ALWAYS kept even if it alone exceeds the cap — retention must
|
|
54
|
+
// never delete the just-written run, and "delete oldest until under the cap" cannot apply to a
|
|
55
|
+
// single most-recent file.
|
|
56
|
+
for (let i = 0; i < sorted.length; i += 1) {
|
|
57
|
+
const candidate = sorted[i];
|
|
58
|
+
if (candidate === undefined) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
running += candidate.bytes;
|
|
62
|
+
if (i > 0 && running > maxTotalBytes) {
|
|
63
|
+
doomed.push(candidate.runId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return doomed;
|
|
67
|
+
}
|
|
68
|
+
function computeDeleteSet(sorted, policy) {
|
|
69
|
+
const doomed = new Set();
|
|
70
|
+
if (policy.maxRuns !== undefined) {
|
|
71
|
+
for (const id of beyondMaxRuns(sorted, policy.maxRuns)) {
|
|
72
|
+
doomed.add(id);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (policy.maxAgeMs !== undefined) {
|
|
76
|
+
for (const id of olderThanAge(sorted, policy.maxAgeMs)) {
|
|
77
|
+
doomed.add(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (policy.maxTotalBytes !== undefined) {
|
|
81
|
+
for (const id of overByteCap(sorted, policy.maxTotalBytes)) {
|
|
82
|
+
doomed.add(id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return doomed;
|
|
86
|
+
}
|
|
87
|
+
export function applyRetention(store, policy) {
|
|
88
|
+
if (policy.disabled === true) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const sorted = collectCandidates(store);
|
|
92
|
+
for (const runId of computeDeleteSet(sorted, policy)) {
|
|
93
|
+
store.delete(runId);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function assertValidRunId(runId: string): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// PURE, bounded runId validation (ADR-0010 D4 iii). The manifest filename is ALWAYS derived from a
|
|
2
|
+
// validated runId, so a malicious runId cannot escape the contained base dir or overwrite an
|
|
3
|
+
// arbitrary file. We accept only a bounded [A-Za-z0-9._-] character set with a length cap and reject
|
|
4
|
+
// a leading dot (no dotfiles, no `..`). NO REGEX is used (D3 no-new-regex rule) — validation is a
|
|
5
|
+
// per-character class check, which is also trivially linear-time.
|
|
6
|
+
import { InvalidRunIdError } from "./errors.js";
|
|
7
|
+
const MAX_RUN_ID_LENGTH = 256;
|
|
8
|
+
// Inclusive ASCII code-point ranges for the allowed class, plus the three allowed punctuation
|
|
9
|
+
// characters. A leading dot is rejected separately so `.` is allowed only in non-leading position.
|
|
10
|
+
function isAllowedChar(code) {
|
|
11
|
+
const isDigit = code >= 48 && code <= 57; // 0-9
|
|
12
|
+
const isUpper = code >= 65 && code <= 90; // A-Z
|
|
13
|
+
const isLower = code >= 97 && code <= 122; // a-z
|
|
14
|
+
const isPunct = code === 46 || code === 95 || code === 45; // . _ -
|
|
15
|
+
return isDigit || isUpper || isLower || isPunct;
|
|
16
|
+
}
|
|
17
|
+
export function assertValidRunId(runId) {
|
|
18
|
+
if (runId.length === 0 || runId.length > MAX_RUN_ID_LENGTH) {
|
|
19
|
+
throw new InvalidRunIdError(`invalid runId length: ${String(runId.length)}`);
|
|
20
|
+
}
|
|
21
|
+
if (runId.startsWith(".")) {
|
|
22
|
+
throw new InvalidRunIdError("runId must not start with a dot");
|
|
23
|
+
}
|
|
24
|
+
for (let i = 0; i < runId.length; i += 1) {
|
|
25
|
+
if (!isAllowedChar(runId.charCodeAt(i))) {
|
|
26
|
+
throw new InvalidRunIdError("runId contains a disallowed character");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type WorkspaceFs } from "../workspace/fs.js";
|
|
2
|
+
export interface SideFileWriteResult {
|
|
3
|
+
readonly relativePath: string;
|
|
4
|
+
readonly sha256: string;
|
|
5
|
+
readonly bytes: number;
|
|
6
|
+
readonly absolutePath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SideFileWriterOptions {
|
|
9
|
+
readonly fs?: WorkspaceFs;
|
|
10
|
+
readonly randomSuffix?: () => string;
|
|
11
|
+
}
|
|
12
|
+
export declare function writeSideFile(baseDir: string, runId: string, name: string, data: Buffer, options?: SideFileWriterOptions): SideFileWriteResult;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// ADR-0017 D5 — side-file writer for binary evidence (e.g. screenshots) that does NOT fit the
|
|
2
|
+
// text-only EvidenceManifest JSON. Atomic O_EXCL temp + rename, realpath-contained against the
|
|
3
|
+
// per-run subdirectory of evidenceDir, SHA-256 computed over the raw bytes. Reuses the workspace
|
|
4
|
+
// realpath-containment primitive — no new path-safety mechanism is introduced. `evidenceSchemaVersion`
|
|
5
|
+
// stays "1" (additive manifest field consumed by callers).
|
|
6
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
+
import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { nodeWorkspaceFs } from "../workspace/fs.js";
|
|
10
|
+
import { resolveWithinWorkspace } from "../workspace/paths.js";
|
|
11
|
+
import { assertContainedRealPath } from "../workspace/realpath.js";
|
|
12
|
+
import { assertValidRunId } from "./runid.js";
|
|
13
|
+
import { EvidenceWriteError } from "./errors.js";
|
|
14
|
+
const MAX_NAME_LENGTH = 128;
|
|
15
|
+
// Validates a side-file basename. The set is intentionally narrower than runId's: a name segment
|
|
16
|
+
// is a single non-empty path component with no separators, no leading dot, no `..`, length cap. No
|
|
17
|
+
// regex — character-class check stays linear-time.
|
|
18
|
+
function assertValidName(name) {
|
|
19
|
+
if (name.length === 0 || name.length > MAX_NAME_LENGTH) {
|
|
20
|
+
throw new EvidenceWriteError("side-file name length is invalid");
|
|
21
|
+
}
|
|
22
|
+
if (name.startsWith(".")) {
|
|
23
|
+
throw new EvidenceWriteError("side-file name must not start with a dot");
|
|
24
|
+
}
|
|
25
|
+
for (let i = 0; i < name.length; i += 1) {
|
|
26
|
+
if (!isAllowedNameChar(name.charCodeAt(i))) {
|
|
27
|
+
throw new EvidenceWriteError("side-file name contains a disallowed character");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function isAllowedNameChar(code) {
|
|
32
|
+
const isDigit = code >= 48 && code <= 57;
|
|
33
|
+
const isUpper = code >= 65 && code <= 90;
|
|
34
|
+
const isLower = code >= 97 && code <= 122;
|
|
35
|
+
const isPunct = code === 46 || code === 95 || code === 45;
|
|
36
|
+
return isDigit || isUpper || isLower || isPunct;
|
|
37
|
+
}
|
|
38
|
+
function ensureDir(absolute) {
|
|
39
|
+
try {
|
|
40
|
+
mkdirSync(absolute, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new EvidenceWriteError(`cannot create evidence subdirectory: ${error instanceof Error ? error.message : "unknown"}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function atomicWriteBytes(target, data, randomSuffix) {
|
|
47
|
+
const temp = `${target}.${randomSuffix()}.tmp`;
|
|
48
|
+
try {
|
|
49
|
+
// O_EXCL ("wx") refuses to open through a pre-planted symlink at the temp path. The randomUUID
|
|
50
|
+
// suffix never collides so "wx" never spuriously fails.
|
|
51
|
+
writeFileSync(temp, data, { flag: "wx" });
|
|
52
|
+
renameSync(temp, target);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
rmSync(temp, { force: true });
|
|
56
|
+
throw new EvidenceWriteError(`side-file write failed: ${error instanceof Error ? error.message : "unknown"}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Writes a binary side-file under `<baseDir>/<runId>/<name>` atomically. Containment is enforced
|
|
60
|
+
// by realpath-resolving the per-run directory after creation, then checking the final lexical path
|
|
61
|
+
// against that real root via assertContainedRealPath. Returns the relative path to embed in the
|
|
62
|
+
// manifest plus the SHA-256 of the raw bytes (tamper-evidence).
|
|
63
|
+
export function writeSideFile(baseDir, runId, name, data, options = {}) {
|
|
64
|
+
assertValidRunId(runId);
|
|
65
|
+
assertValidName(name);
|
|
66
|
+
const fs = options.fs ?? nodeWorkspaceFs;
|
|
67
|
+
const randomSuffix = options.randomSuffix ?? randomUUID;
|
|
68
|
+
ensureDir(baseDir);
|
|
69
|
+
const runDir = join(baseDir, runId);
|
|
70
|
+
ensureDir(runDir);
|
|
71
|
+
const realRunDir = fs.realPath(runDir);
|
|
72
|
+
const lexicalTarget = resolveWithinWorkspace(realRunDir, name);
|
|
73
|
+
const absoluteTarget = assertContainedRealPath(fs, realRunDir, lexicalTarget, name);
|
|
74
|
+
const sha256 = createHash("sha256").update(data).digest("hex");
|
|
75
|
+
atomicWriteBytes(absoluteTarget, data, randomSuffix);
|
|
76
|
+
return {
|
|
77
|
+
relativePath: name,
|
|
78
|
+
sha256,
|
|
79
|
+
bytes: data.length,
|
|
80
|
+
absolutePath: absoluteTarget,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type WorkspaceFs } from "../workspace/fs.js";
|
|
2
|
+
export declare const DEFAULT_EVIDENCE_DIR = "./.keiko/evidence";
|
|
3
|
+
export declare function resolveEvidenceDir(explicit: string | undefined, env: Readonly<Record<string, string | undefined>> | undefined): string;
|
|
4
|
+
export interface EvidenceStore {
|
|
5
|
+
readonly put: (runId: string, json: string) => string;
|
|
6
|
+
readonly list: () => readonly string[];
|
|
7
|
+
readonly get: (runId: string) => string | undefined;
|
|
8
|
+
readonly location?: ((runId: string) => string) | undefined;
|
|
9
|
+
readonly delete: (runId: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createInMemoryEvidenceStore(): EvidenceStore;
|
|
12
|
+
export declare function createNodeEvidenceStore(baseDir: string, fs?: WorkspaceFs, randomSuffix?: () => string): EvidenceStore;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// The EvidenceStore PORT + node adapter (ADR-0010 D4). A single manifest-record-typed port
|
|
2
|
+
// (read+write+list+delete) keeps all real IO in one auditable place and makes the layer testable
|
|
3
|
+
// with an in-memory store. We deliberately introduce a new port rather than reuse the #6
|
|
4
|
+
// WorkspaceWriter, which has no read/list capability that D5 requires.
|
|
5
|
+
//
|
|
6
|
+
// Safety: the node adapter realpath-contains its base dir once at construction (reusing the #5/#6
|
|
7
|
+
// primitives), every filename is derived from a VALIDATED runId (assertValidRunId), and the
|
|
8
|
+
// resolved child path is re-checked to remain inside the contained base dir before any write,
|
|
9
|
+
// read, or delete. Writes are atomic (temp + rename, same dir = same filesystem). list() returns
|
|
10
|
+
// only real `<runId>.json` files and never follows a symlink (lstat skip).
|
|
11
|
+
import { readdirSync, readFileSync, lstatSync, mkdirSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
import { join, resolve } from "node:path";
|
|
14
|
+
import { nodeWorkspaceFs } from "../workspace/fs.js";
|
|
15
|
+
import { resolveWithinWorkspace } from "../workspace/paths.js";
|
|
16
|
+
import { assertContainedRealPath } from "../workspace/realpath.js";
|
|
17
|
+
import { EvidenceReadError, EvidenceWriteError } from "./errors.js";
|
|
18
|
+
import { assertValidRunId } from "./runid.js";
|
|
19
|
+
const MANIFEST_SUFFIX = ".json";
|
|
20
|
+
// The workspace-relative default evidence base dir (ADR-0010 D4): predictable, local, .gitignored.
|
|
21
|
+
export const DEFAULT_EVIDENCE_DIR = "./.keiko/evidence";
|
|
22
|
+
// Single source of the output-location precedence (ADR-0010 D4): an explicit value (CLI
|
|
23
|
+
// --evidence-dir) wins over the KEIKO_EVIDENCE_DIR env var, which wins over the default. Shared by
|
|
24
|
+
// the CLI run command and the SDK persistEvidence default so both resolve identically.
|
|
25
|
+
export function resolveEvidenceDir(explicit, env) {
|
|
26
|
+
return explicit ?? env?.KEIKO_EVIDENCE_DIR ?? DEFAULT_EVIDENCE_DIR;
|
|
27
|
+
}
|
|
28
|
+
// ─── In-memory store (tests) ──────────────────────────────────────────────────────
|
|
29
|
+
export function createInMemoryEvidenceStore() {
|
|
30
|
+
const data = new Map();
|
|
31
|
+
return {
|
|
32
|
+
put: (runId, json) => {
|
|
33
|
+
assertValidRunId(runId);
|
|
34
|
+
data.set(runId, json);
|
|
35
|
+
return `${runId}${MANIFEST_SUFFIX}`;
|
|
36
|
+
},
|
|
37
|
+
list: () => [...data.keys()].sort(),
|
|
38
|
+
get: (runId) => {
|
|
39
|
+
assertValidRunId(runId);
|
|
40
|
+
return data.get(runId);
|
|
41
|
+
},
|
|
42
|
+
location: (runId) => {
|
|
43
|
+
assertValidRunId(runId);
|
|
44
|
+
return `${runId}${MANIFEST_SUFFIX}`;
|
|
45
|
+
},
|
|
46
|
+
delete: (runId) => {
|
|
47
|
+
assertValidRunId(runId);
|
|
48
|
+
data.delete(runId);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// ─── Node adapter ──────────────────────────────────────────────────────────────────
|
|
53
|
+
// Resolves the base dir, creates it if absent, then realpath-contains it against itself so the
|
|
54
|
+
// returned path is the canonical (symlink-followed) base every child path is checked against.
|
|
55
|
+
function prepareBaseDir(baseDir, fs) {
|
|
56
|
+
try {
|
|
57
|
+
mkdirSync(baseDir, { recursive: true });
|
|
58
|
+
return fs.realPath(baseDir);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new EvidenceWriteError(`cannot create evidence directory: ${error instanceof Error ? error.message : "unknown"}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function existingBaseDir(baseDir, fs) {
|
|
65
|
+
if (!fs.exists(baseDir)) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return fs.realPath(baseDir);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
throw new EvidenceReadError(`cannot read evidence directory: ${error instanceof Error ? error.message : "unknown"}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Returns the realpath-contained absolute path of <runId>.json inside the base dir, or throws if it
|
|
76
|
+
// would escape. The runId is validated first so no separator/`..`/NUL can reach the join.
|
|
77
|
+
function containedManifestPath(runId, realBase, fs) {
|
|
78
|
+
assertValidRunId(runId);
|
|
79
|
+
const lexical = resolveWithinWorkspace(realBase, `${runId}${MANIFEST_SUFFIX}`);
|
|
80
|
+
return assertContainedRealPath(fs, realBase, lexical, `${runId}${MANIFEST_SUFFIX}`);
|
|
81
|
+
}
|
|
82
|
+
function isManifestName(name) {
|
|
83
|
+
if (!name.endsWith(MANIFEST_SUFFIX)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const runId = name.slice(0, name.length - MANIFEST_SUFFIX.length);
|
|
87
|
+
try {
|
|
88
|
+
assertValidRunId(runId);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function isSingleLinkRegularFile(path, fs) {
|
|
96
|
+
try {
|
|
97
|
+
const stat = fs.stat(path);
|
|
98
|
+
return stat.isFile && (stat.hardLinkCount ?? 1) <= 1;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw new EvidenceReadError(`cannot inspect evidence manifest: ${error instanceof Error ? error.message : "unknown"}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function listManifestRunIds(realBase, fs) {
|
|
105
|
+
const runIds = [];
|
|
106
|
+
try {
|
|
107
|
+
for (const entry of readdirSync(realBase, { withFileTypes: true })) {
|
|
108
|
+
// Never follow a symlink: only count entries the ledger itself wrote as regular files.
|
|
109
|
+
if (entry.isSymbolicLink() ||
|
|
110
|
+
!entry.isFile() ||
|
|
111
|
+
!isManifestName(entry.name) ||
|
|
112
|
+
!isSingleLinkRegularFile(join(realBase, entry.name), fs)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
runIds.push(entry.name.slice(0, entry.name.length - MANIFEST_SUFFIX.length));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new EvidenceReadError(`cannot list evidence manifests: ${error instanceof Error ? error.message : "unknown"}`);
|
|
120
|
+
}
|
|
121
|
+
return runIds.sort();
|
|
122
|
+
}
|
|
123
|
+
function atomicWrite(target, json, randomSuffix) {
|
|
124
|
+
const temp = `${target}.${randomSuffix()}.tmp`;
|
|
125
|
+
try {
|
|
126
|
+
// O_EXCL ("wx"): refuse to open through a pre-planted symlink at the temp path, closing the
|
|
127
|
+
// temp-vs-final containment asymmetry (the final target is realpath-contained, the temp was
|
|
128
|
+
// not). A randomUUID suffix never collides, so "wx" never spuriously fails.
|
|
129
|
+
writeFileSync(temp, json, { encoding: "utf8", flag: "wx" });
|
|
130
|
+
renameSync(temp, target);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
rmSync(temp, { force: true });
|
|
134
|
+
throw new EvidenceWriteError(`evidence write failed: ${error instanceof Error ? error.message : "unknown"}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function reportLocation(baseDir, fs, runId) {
|
|
138
|
+
assertValidRunId(runId);
|
|
139
|
+
const realBase = existingBaseDir(baseDir, fs);
|
|
140
|
+
return realBase === undefined
|
|
141
|
+
? join(resolve(baseDir), `${runId}${MANIFEST_SUFFIX}`)
|
|
142
|
+
: containedManifestPath(runId, realBase, fs);
|
|
143
|
+
}
|
|
144
|
+
function putManifest(baseDir, fs, randomSuffix, runId, json) {
|
|
145
|
+
const realBase = prepareBaseDir(baseDir, fs);
|
|
146
|
+
const target = containedManifestPath(runId, realBase, fs);
|
|
147
|
+
atomicWrite(target, json, randomSuffix);
|
|
148
|
+
return target;
|
|
149
|
+
}
|
|
150
|
+
function listManifests(baseDir, fs) {
|
|
151
|
+
const realBase = existingBaseDir(baseDir, fs);
|
|
152
|
+
return realBase === undefined ? [] : listManifestRunIds(realBase, fs);
|
|
153
|
+
}
|
|
154
|
+
function getManifest(baseDir, fs, runId) {
|
|
155
|
+
assertValidRunId(runId);
|
|
156
|
+
const realBase = existingBaseDir(baseDir, fs);
|
|
157
|
+
if (realBase === undefined) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const target = join(realBase, `${runId}${MANIFEST_SUFFIX}`);
|
|
161
|
+
try {
|
|
162
|
+
if (lstatSync(target, { throwIfNoEntry: false })?.isFile() !== true) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
if (!isSingleLinkRegularFile(target, fs)) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
return readFileSync(target, "utf8");
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw new EvidenceReadError(`cannot read evidence manifest: ${error instanceof Error ? error.message : "unknown"}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function deleteManifest(baseDir, fs, runId) {
|
|
175
|
+
const realBase = existingBaseDir(baseDir, fs);
|
|
176
|
+
if (realBase === undefined) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const target = containedManifestPath(runId, realBase, fs);
|
|
180
|
+
if (lstatSync(target, { throwIfNoEntry: false })?.isFile() !== true) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!isSingleLinkRegularFile(target, fs)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
rmSync(target, { force: true });
|
|
187
|
+
}
|
|
188
|
+
export function createNodeEvidenceStore(baseDir, fs = nodeWorkspaceFs, randomSuffix = randomUUID) {
|
|
189
|
+
return {
|
|
190
|
+
put: (runId, json) => putManifest(baseDir, fs, randomSuffix, runId, json),
|
|
191
|
+
list: () => listManifests(baseDir, fs),
|
|
192
|
+
get: (runId) => getManifest(baseDir, fs, runId),
|
|
193
|
+
location: (runId) => reportLocation(baseDir, fs, runId),
|
|
194
|
+
delete: (runId) => {
|
|
195
|
+
deleteManifest(baseDir, fs, runId);
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { CostClass } from "../gateway/types.js";
|
|
2
|
+
import type { HarnessCode, HarnessStateName, RunManifest, RunOutcome, RunResult, TaskType } from "../harness/types.js";
|
|
3
|
+
import type { AuditSummary } from "../workspace/types.js";
|
|
4
|
+
import type { VerificationAuditSummary } from "../verification/summary.js";
|
|
5
|
+
import type { EvidenceStore } from "./store.js";
|
|
6
|
+
export declare const EVIDENCE_SCHEMA_VERSION: "1";
|
|
7
|
+
export interface EvidenceRunIdentity {
|
|
8
|
+
readonly runId: string;
|
|
9
|
+
readonly fingerprint: string;
|
|
10
|
+
readonly harnessVersion: string;
|
|
11
|
+
readonly taskType: EvidenceTaskType;
|
|
12
|
+
readonly outcome: RunOutcome;
|
|
13
|
+
readonly startedAt: number;
|
|
14
|
+
readonly finishedAt: number;
|
|
15
|
+
readonly durationMs: number;
|
|
16
|
+
}
|
|
17
|
+
export interface EvidenceModel {
|
|
18
|
+
readonly modelId: string;
|
|
19
|
+
readonly costClass: CostClass | "unknown";
|
|
20
|
+
}
|
|
21
|
+
export interface EvidenceUsageTotals {
|
|
22
|
+
readonly promptTokens: number;
|
|
23
|
+
readonly completionTokens: number;
|
|
24
|
+
readonly requestCount: number;
|
|
25
|
+
readonly totalLatencyMs: number;
|
|
26
|
+
}
|
|
27
|
+
export interface EvidenceStateTransition {
|
|
28
|
+
readonly seq: number;
|
|
29
|
+
readonly ts: number;
|
|
30
|
+
readonly from: HarnessStateName;
|
|
31
|
+
readonly to: HarnessStateName;
|
|
32
|
+
readonly reason: string;
|
|
33
|
+
}
|
|
34
|
+
export interface EvidenceToolCall {
|
|
35
|
+
readonly seq: number;
|
|
36
|
+
readonly ts: number;
|
|
37
|
+
readonly toolName: string;
|
|
38
|
+
readonly toolCallId: string;
|
|
39
|
+
readonly outcome: "completed" | "failed";
|
|
40
|
+
readonly durationMs?: number | undefined;
|
|
41
|
+
readonly errorCode?: string | undefined;
|
|
42
|
+
}
|
|
43
|
+
export interface EvidenceCommandExecution {
|
|
44
|
+
readonly seq: number;
|
|
45
|
+
readonly ts: number;
|
|
46
|
+
readonly executable: string;
|
|
47
|
+
readonly argCount: number;
|
|
48
|
+
readonly exitCode: number | null;
|
|
49
|
+
readonly timedOut: boolean;
|
|
50
|
+
readonly durationMs: number;
|
|
51
|
+
}
|
|
52
|
+
export interface EvidenceSandboxConfiguration {
|
|
53
|
+
readonly seq: number;
|
|
54
|
+
readonly ts: number;
|
|
55
|
+
readonly envAllowlist: readonly string[];
|
|
56
|
+
readonly network: "inherit" | "none";
|
|
57
|
+
readonly maxOutputBytes: number;
|
|
58
|
+
readonly timeoutMs: number;
|
|
59
|
+
readonly terminationGraceMs: number;
|
|
60
|
+
readonly cwdRequested: boolean;
|
|
61
|
+
}
|
|
62
|
+
export interface EvidenceVerificationResult {
|
|
63
|
+
readonly seq: number;
|
|
64
|
+
readonly ts: number;
|
|
65
|
+
readonly passed: boolean;
|
|
66
|
+
readonly detail: string;
|
|
67
|
+
}
|
|
68
|
+
export interface EvidencePatch {
|
|
69
|
+
readonly proposed: boolean;
|
|
70
|
+
readonly applied: boolean;
|
|
71
|
+
readonly targetFileCount: number;
|
|
72
|
+
readonly patchBytes: number;
|
|
73
|
+
readonly changedFiles: number;
|
|
74
|
+
readonly created: number;
|
|
75
|
+
readonly deleted: number;
|
|
76
|
+
readonly redactedDiff?: string | undefined;
|
|
77
|
+
}
|
|
78
|
+
export interface EvidenceReasoningEntry {
|
|
79
|
+
readonly seq: number;
|
|
80
|
+
readonly ts: number;
|
|
81
|
+
readonly phase: HarnessStateName;
|
|
82
|
+
readonly rationale: string;
|
|
83
|
+
readonly modelResponse?: string | undefined;
|
|
84
|
+
}
|
|
85
|
+
export interface EvidenceFailure {
|
|
86
|
+
readonly category: HarnessCode;
|
|
87
|
+
readonly message: string;
|
|
88
|
+
}
|
|
89
|
+
export type EvidenceTaskType = TaskType | "browser-capture" | "terminal-execution";
|
|
90
|
+
export interface EvidenceBrowserViewportPx {
|
|
91
|
+
readonly width: number;
|
|
92
|
+
readonly height: number;
|
|
93
|
+
}
|
|
94
|
+
export type EvidenceBrowserEventType = "browser:session-opened" | "browser:navigated" | "browser:screenshot-captured" | "browser:page-content-captured" | "browser:session-closed" | "browser:trust-warning" | "browser:error";
|
|
95
|
+
export interface EvidenceBrowserEvent {
|
|
96
|
+
readonly schemaVersion: "1";
|
|
97
|
+
readonly type: EvidenceBrowserEventType;
|
|
98
|
+
readonly sessionId: string;
|
|
99
|
+
readonly seq: number;
|
|
100
|
+
readonly ts: number;
|
|
101
|
+
readonly originOnly?: string | undefined;
|
|
102
|
+
readonly httpStatus?: number | null | undefined;
|
|
103
|
+
readonly captureSeq?: number | undefined;
|
|
104
|
+
readonly persisted?: boolean | undefined;
|
|
105
|
+
readonly viewportPx?: EvidenceBrowserViewportPx | undefined;
|
|
106
|
+
readonly path?: string | undefined;
|
|
107
|
+
readonly sha256?: string | undefined;
|
|
108
|
+
readonly bytes?: number | undefined;
|
|
109
|
+
readonly byteLength?: number | undefined;
|
|
110
|
+
readonly reason?: string | undefined;
|
|
111
|
+
readonly warning?: string | undefined;
|
|
112
|
+
readonly code?: string | undefined;
|
|
113
|
+
readonly message?: string | undefined;
|
|
114
|
+
}
|
|
115
|
+
export interface EvidenceBrowserScreenshot {
|
|
116
|
+
readonly seq: number;
|
|
117
|
+
readonly path: string;
|
|
118
|
+
readonly sha256: string;
|
|
119
|
+
readonly bytes: number;
|
|
120
|
+
readonly capturedAt: number;
|
|
121
|
+
readonly viewportPx: EvidenceBrowserViewportPx;
|
|
122
|
+
}
|
|
123
|
+
export interface EvidenceBrowserContentCapture {
|
|
124
|
+
readonly seq: number;
|
|
125
|
+
readonly byteLength: number;
|
|
126
|
+
readonly capturedAt: number;
|
|
127
|
+
readonly redactedHtml: string;
|
|
128
|
+
}
|
|
129
|
+
export interface EvidenceBrowserCapture {
|
|
130
|
+
readonly sessionId: string;
|
|
131
|
+
readonly cdpPort: number;
|
|
132
|
+
readonly targetId: string;
|
|
133
|
+
readonly status: "open" | "closed";
|
|
134
|
+
readonly startedAt: number;
|
|
135
|
+
readonly closedAt?: number | undefined;
|
|
136
|
+
readonly closeReason?: string | undefined;
|
|
137
|
+
readonly lastOriginOnly?: string | undefined;
|
|
138
|
+
readonly events: readonly EvidenceBrowserEvent[];
|
|
139
|
+
readonly screenshots?: readonly EvidenceBrowserScreenshot[] | undefined;
|
|
140
|
+
readonly contentCaptures?: readonly EvidenceBrowserContentCapture[] | undefined;
|
|
141
|
+
}
|
|
142
|
+
export interface EvidenceManifest {
|
|
143
|
+
readonly evidenceSchemaVersion: "1";
|
|
144
|
+
readonly run: EvidenceRunIdentity;
|
|
145
|
+
readonly model: EvidenceModel;
|
|
146
|
+
readonly usageTotals: EvidenceUsageTotals;
|
|
147
|
+
readonly context?: AuditSummary | undefined;
|
|
148
|
+
readonly stateTransitions: readonly EvidenceStateTransition[];
|
|
149
|
+
readonly toolCalls: readonly EvidenceToolCall[];
|
|
150
|
+
readonly commandExecutions: readonly EvidenceCommandExecution[];
|
|
151
|
+
readonly sandboxConfigurations?: readonly EvidenceSandboxConfiguration[] | undefined;
|
|
152
|
+
readonly verificationResults?: readonly EvidenceVerificationResult[] | undefined;
|
|
153
|
+
readonly patch?: EvidencePatch | undefined;
|
|
154
|
+
readonly verification?: VerificationAuditSummary | undefined;
|
|
155
|
+
readonly failure?: EvidenceFailure | undefined;
|
|
156
|
+
readonly reasoning?: readonly EvidenceReasoningEntry[] | undefined;
|
|
157
|
+
readonly browser?: EvidenceBrowserCapture | undefined;
|
|
158
|
+
}
|
|
159
|
+
export interface AuditRedactionConfig {
|
|
160
|
+
readonly additionalSecrets?: readonly string[] | undefined;
|
|
161
|
+
readonly redactEnvValues?: readonly string[] | undefined;
|
|
162
|
+
readonly sensitiveLiterals?: readonly string[] | undefined;
|
|
163
|
+
}
|
|
164
|
+
export interface RetentionPolicy {
|
|
165
|
+
readonly maxRuns?: number | undefined;
|
|
166
|
+
readonly maxAgeMs?: number | undefined;
|
|
167
|
+
readonly maxTotalBytes?: number | undefined;
|
|
168
|
+
readonly disabled?: boolean | undefined;
|
|
169
|
+
}
|
|
170
|
+
export declare const DEFAULT_RETENTION: RetentionPolicy;
|
|
171
|
+
export interface BuildOptions {
|
|
172
|
+
readonly includeReasoning?: boolean | undefined;
|
|
173
|
+
readonly includeDiff?: boolean | undefined;
|
|
174
|
+
}
|
|
175
|
+
export interface EvidenceBuildInput {
|
|
176
|
+
readonly result: RunResult;
|
|
177
|
+
readonly manifest: RunManifest;
|
|
178
|
+
readonly context?: AuditSummary | undefined;
|
|
179
|
+
readonly verification?: VerificationAuditSummary | undefined;
|
|
180
|
+
readonly redaction?: AuditRedactionConfig | undefined;
|
|
181
|
+
readonly options?: BuildOptions | undefined;
|
|
182
|
+
}
|
|
183
|
+
export interface EvidenceDeps {
|
|
184
|
+
readonly env?: Readonly<Record<string, string | undefined>> | undefined;
|
|
185
|
+
readonly store?: EvidenceStore | undefined;
|
|
186
|
+
readonly randomSuffix?: (() => string) | undefined;
|
|
187
|
+
readonly now?: (() => number) | undefined;
|
|
188
|
+
}
|