@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,363 @@
|
|
|
1
|
+
// The verification orchestrator (ADR-0007 D2–D5). Runs each plan step sequentially through the
|
|
2
|
+
// UNCHANGED #6 runCommand, applying per-command resource limits, honest appliedLimits, memory
|
|
3
|
+
// monitoring via a SpawnFn wrapper + ResourceMonitor seam (never modifying src/tools), cross-step
|
|
4
|
+
// cancellation, and a redacted output digest. Error handling lives only at this IO boundary; the
|
|
5
|
+
// classification it feeds is pure.
|
|
6
|
+
import { redact } from "../gateway/redaction.js";
|
|
7
|
+
import { DEFAULT_COMMAND_RULES, DEFAULT_SANDBOX_POLICY, nodeSpawnFn, runCommand, } from "../tools/index.js";
|
|
8
|
+
import { nodeWorkspaceFs } from "../workspace/fs.js";
|
|
9
|
+
import { classifyOutcome } from "./classify.js";
|
|
10
|
+
import { classifyScripts } from "./detect.js";
|
|
11
|
+
import { buildAppliedLimits } from "./limits.js";
|
|
12
|
+
import { nodeResourceMonitor } from "./monitor.js";
|
|
13
|
+
// Verification runs deterministic repository gates selected by Keiko, not arbitrary model-issued
|
|
14
|
+
// run_command calls. Keep the model-facing defaults read-only while allowing the verification
|
|
15
|
+
// orchestrator to invoke npm scripts and framework-targeted npx runs through the same #6 boundary.
|
|
16
|
+
export const VERIFICATION_COMMAND_RULES = Object.freeze([
|
|
17
|
+
{
|
|
18
|
+
executable: "npm",
|
|
19
|
+
allowedSubcommands: Object.freeze(["test", "run"]),
|
|
20
|
+
denyFlags: Object.freeze(["-c", "--call"]),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
executable: "npx",
|
|
24
|
+
allowedSubcommands: Object.freeze(["vitest", "jest"]),
|
|
25
|
+
denyFlags: Object.freeze(["-c", "--call"]),
|
|
26
|
+
},
|
|
27
|
+
...DEFAULT_COMMAND_RULES,
|
|
28
|
+
]);
|
|
29
|
+
const ALL_STATUSES = [
|
|
30
|
+
"passed",
|
|
31
|
+
"failed",
|
|
32
|
+
"skipped",
|
|
33
|
+
"denied",
|
|
34
|
+
"timed-out",
|
|
35
|
+
"cancelled",
|
|
36
|
+
"resource-exceeded",
|
|
37
|
+
];
|
|
38
|
+
// Maps a step's resource limits onto a #6 SandboxPolicy: wall-time and output-size are enforced by
|
|
39
|
+
// runCommand; network is passed through (documented-not-enforced). Memory is NOT a SandboxPolicy
|
|
40
|
+
// field — it is handled by the SpawnFn-wrapper monitor, so it does not appear here.
|
|
41
|
+
function policyForStep(limits) {
|
|
42
|
+
return {
|
|
43
|
+
...DEFAULT_SANDBOX_POLICY,
|
|
44
|
+
maxOutputBytes: limits.maxOutputBytes,
|
|
45
|
+
defaultTimeoutMs: limits.wallTimeMs,
|
|
46
|
+
network: limits.network,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Data-minimal output metadata. #6 already redacts/caps each stream, but regulated CLI/SDK
|
|
50
|
+
// summaries should not echo arbitrary repository logs or customer data by default.
|
|
51
|
+
function outputDigest(result) {
|
|
52
|
+
if (result === undefined) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
const combined = `${result.stdout}${result.stderr}`;
|
|
56
|
+
if (combined.length === 0) {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
if (result.truncated) {
|
|
60
|
+
return "command output exceeded the configured output-size limit and was omitted";
|
|
61
|
+
}
|
|
62
|
+
const bytes = Buffer.byteLength(combined, "utf8");
|
|
63
|
+
return `command output captured (${String(bytes)} bytes) and omitted from summary`;
|
|
64
|
+
}
|
|
65
|
+
// Derives which single dimension tripped, so exactly one appliedLimits row is breached:true.
|
|
66
|
+
function breachedDimension(status, abortReason, result) {
|
|
67
|
+
if (abortReason === "memory") {
|
|
68
|
+
return "memory";
|
|
69
|
+
}
|
|
70
|
+
if (status === "timed-out") {
|
|
71
|
+
return "wall-time";
|
|
72
|
+
}
|
|
73
|
+
if (status === "resource-exceeded" && result?.truncated === true) {
|
|
74
|
+
return "output-size";
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
function deniedResult(step, reason) {
|
|
79
|
+
return {
|
|
80
|
+
kind: step.kind,
|
|
81
|
+
scriptName: step.scriptName,
|
|
82
|
+
command: step.command,
|
|
83
|
+
args: step.args,
|
|
84
|
+
status: "denied",
|
|
85
|
+
exitCode: null,
|
|
86
|
+
signal: null,
|
|
87
|
+
durationMs: 0,
|
|
88
|
+
truncated: false,
|
|
89
|
+
redacted: true,
|
|
90
|
+
outputSummary: "",
|
|
91
|
+
appliedLimits: buildAppliedLimits(step.limits, undefined),
|
|
92
|
+
detail: redact(reason),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function isGeneratedSkipShape(step) {
|
|
96
|
+
return (step.kind !== "targeted-test" &&
|
|
97
|
+
step.skipReason !== undefined &&
|
|
98
|
+
step.scriptName === undefined &&
|
|
99
|
+
step.command === "npm" &&
|
|
100
|
+
step.args.length === 2 &&
|
|
101
|
+
step.args[0] === "run" &&
|
|
102
|
+
step.args[1] === step.kind);
|
|
103
|
+
}
|
|
104
|
+
function hasWindowsDrivePrefix(value) {
|
|
105
|
+
return value.length >= 2 && value[1] === ":";
|
|
106
|
+
}
|
|
107
|
+
function isGeneratedTargetPath(value) {
|
|
108
|
+
if (value.length === 0 ||
|
|
109
|
+
value.startsWith("-") ||
|
|
110
|
+
value.startsWith("/") ||
|
|
111
|
+
value.includes("\u0000") ||
|
|
112
|
+
hasWindowsDrivePrefix(value)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return value
|
|
116
|
+
.split("\\")
|
|
117
|
+
.join("/")
|
|
118
|
+
.split("/")
|
|
119
|
+
.every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
120
|
+
}
|
|
121
|
+
function scriptNameMatchesKind(step) {
|
|
122
|
+
if (step.kind === "targeted-test" || step.scriptName === undefined) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return classifyScripts({ [step.scriptName]: "" })[step.kind] === step.scriptName;
|
|
126
|
+
}
|
|
127
|
+
function isValidTargetedStep(step) {
|
|
128
|
+
if (step.scriptName !== undefined || step.command !== "npx" || step.args.length < 2) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (step.args[0] === "vitest") {
|
|
132
|
+
return (step.args[1] === "run" &&
|
|
133
|
+
step.args.length >= 3 &&
|
|
134
|
+
step.args.slice(2).every(isGeneratedTargetPath));
|
|
135
|
+
}
|
|
136
|
+
if (step.args[0] === "jest") {
|
|
137
|
+
return step.args.length >= 2 && step.args.slice(1).every(isGeneratedTargetPath);
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
function isValidTestStep(step) {
|
|
142
|
+
if (step.kind === "test") {
|
|
143
|
+
if (step.scriptName === "test") {
|
|
144
|
+
return step.args.length === 1 && step.args[0] === "test";
|
|
145
|
+
}
|
|
146
|
+
return (scriptNameMatchesKind(step) &&
|
|
147
|
+
step.args.length === 2 &&
|
|
148
|
+
step.args[0] === "run" &&
|
|
149
|
+
step.args[1] === step.scriptName);
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
function isValidScriptStep(step) {
|
|
154
|
+
if (step.command !== "npm") {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (step.kind === "test") {
|
|
158
|
+
return isValidTestStep(step);
|
|
159
|
+
}
|
|
160
|
+
if (!scriptNameMatchesKind(step)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return step.args.length === 2 && step.args[0] === "run" && step.args[1] === step.scriptName;
|
|
164
|
+
}
|
|
165
|
+
function isValidVerificationStep(step) {
|
|
166
|
+
if (isGeneratedSkipShape(step)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return step.kind === "targeted-test" ? isValidTargetedStep(step) : isValidScriptStep(step);
|
|
170
|
+
}
|
|
171
|
+
// Runs one command step through #6, wrapping the base SpawnFn with the memory monitor and owning
|
|
172
|
+
// the AbortController. The monitor's unwatch runs in `finally` on EVERY settle path (resolve,
|
|
173
|
+
// reject, denied-before-spawn where stop is never set, or a throwing await), so the sampling
|
|
174
|
+
// interval can never leak (ADR-0007 D3).
|
|
175
|
+
async function runStep(step, deps, baseSpawn, monitor) {
|
|
176
|
+
const now = deps.now ?? Date.now;
|
|
177
|
+
const startedAt = now();
|
|
178
|
+
let abortReason;
|
|
179
|
+
const ac = new AbortController();
|
|
180
|
+
const onHarnessAbort = () => {
|
|
181
|
+
abortReason ??= "harness";
|
|
182
|
+
ac.abort();
|
|
183
|
+
};
|
|
184
|
+
deps.signal?.addEventListener("abort", onHarnessAbort, { once: true });
|
|
185
|
+
let stop;
|
|
186
|
+
const spawn = (cmd, args, opts) => {
|
|
187
|
+
const child = baseSpawn(cmd, args, opts);
|
|
188
|
+
stop = monitor.watch(child.pid, step.limits.maxMemoryBytes, () => {
|
|
189
|
+
abortReason ??= "memory";
|
|
190
|
+
ac.abort();
|
|
191
|
+
});
|
|
192
|
+
return child;
|
|
193
|
+
};
|
|
194
|
+
try {
|
|
195
|
+
const result = await runCommand({
|
|
196
|
+
command: step.command,
|
|
197
|
+
args: step.args,
|
|
198
|
+
cwd: undefined,
|
|
199
|
+
timeoutMs: step.limits.wallTimeMs,
|
|
200
|
+
signal: ac.signal,
|
|
201
|
+
}, buildRunDeps(deps, step, spawn));
|
|
202
|
+
return { result, error: undefined, abortReason, durationMs: result.durationMs };
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
return { result: undefined, error, abortReason, durationMs: now() - startedAt };
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
stop?.();
|
|
209
|
+
deps.signal?.removeEventListener("abort", onHarnessAbort);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function buildRunDeps(deps, step, spawn) {
|
|
213
|
+
return {
|
|
214
|
+
workspace: deps.workspace,
|
|
215
|
+
policy: policyForStep(step.limits),
|
|
216
|
+
commandRules: VERIFICATION_COMMAND_RULES,
|
|
217
|
+
spawn,
|
|
218
|
+
processEnv: deps.processEnv ?? process.env,
|
|
219
|
+
now: deps.now ?? Date.now,
|
|
220
|
+
fs: deps.fs ?? nodeWorkspaceFs,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function skippedResult(step) {
|
|
224
|
+
return {
|
|
225
|
+
kind: step.kind,
|
|
226
|
+
scriptName: step.scriptName,
|
|
227
|
+
command: step.command,
|
|
228
|
+
args: step.args,
|
|
229
|
+
status: "skipped",
|
|
230
|
+
exitCode: null,
|
|
231
|
+
signal: null,
|
|
232
|
+
durationMs: 0,
|
|
233
|
+
truncated: false,
|
|
234
|
+
redacted: true,
|
|
235
|
+
outputSummary: "",
|
|
236
|
+
appliedLimits: buildAppliedLimits(step.limits, undefined),
|
|
237
|
+
detail: redact(step.skipReason ?? "skipped"),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function cancelledResult(step) {
|
|
241
|
+
return {
|
|
242
|
+
kind: step.kind,
|
|
243
|
+
scriptName: step.scriptName,
|
|
244
|
+
command: step.command,
|
|
245
|
+
args: step.args,
|
|
246
|
+
status: "cancelled",
|
|
247
|
+
exitCode: null,
|
|
248
|
+
signal: null,
|
|
249
|
+
durationMs: 0,
|
|
250
|
+
truncated: false,
|
|
251
|
+
redacted: true,
|
|
252
|
+
outputSummary: "",
|
|
253
|
+
appliedLimits: buildAppliedLimits(step.limits, undefined),
|
|
254
|
+
detail: "cancelled before execution",
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function toResult(step, run) {
|
|
258
|
+
const status = classifyOutcome({
|
|
259
|
+
skipped: false,
|
|
260
|
+
result: run.result,
|
|
261
|
+
error: run.error,
|
|
262
|
+
abortReason: run.abortReason,
|
|
263
|
+
});
|
|
264
|
+
const breached = breachedDimension(status, run.abortReason, run.result);
|
|
265
|
+
return {
|
|
266
|
+
kind: step.kind,
|
|
267
|
+
scriptName: step.scriptName,
|
|
268
|
+
command: step.command,
|
|
269
|
+
args: step.args,
|
|
270
|
+
status,
|
|
271
|
+
exitCode: run.result?.exitCode ?? null,
|
|
272
|
+
signal: run.result?.signal ?? null,
|
|
273
|
+
durationMs: run.result?.durationMs ?? run.durationMs,
|
|
274
|
+
truncated: run.result?.truncated ?? false,
|
|
275
|
+
redacted: true,
|
|
276
|
+
outputSummary: outputDigest(run.result),
|
|
277
|
+
appliedLimits: buildAppliedLimits(step.limits, breached),
|
|
278
|
+
detail: detailFor(status, run),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function detailFor(status, run) {
|
|
282
|
+
if (run.abortReason === "memory") {
|
|
283
|
+
return "memory ceiling exceeded";
|
|
284
|
+
}
|
|
285
|
+
// For denied/failed paths the rejection message (already a redacted Error from #6 for denied)
|
|
286
|
+
// is re-redacted here as defence in depth before it reaches the report.
|
|
287
|
+
if ((status === "denied" || status === "failed") && run.error instanceof Error) {
|
|
288
|
+
return redact(run.error.message);
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
function overallStatus(results, cancelled) {
|
|
293
|
+
if (cancelled) {
|
|
294
|
+
return "cancelled";
|
|
295
|
+
}
|
|
296
|
+
const allOk = results.every((r) => r.status === "passed" || r.status === "skipped");
|
|
297
|
+
return allOk ? "passed" : "failed";
|
|
298
|
+
}
|
|
299
|
+
function countByStatus(results) {
|
|
300
|
+
const counts = Object.fromEntries(ALL_STATUSES.map((s) => [s, 0]));
|
|
301
|
+
for (const r of results) {
|
|
302
|
+
counts[r.status] += 1;
|
|
303
|
+
}
|
|
304
|
+
return counts;
|
|
305
|
+
}
|
|
306
|
+
function finishReport(workspaceRoot, results, cancelled, startedAtMs, now) {
|
|
307
|
+
return {
|
|
308
|
+
workspaceRoot,
|
|
309
|
+
results,
|
|
310
|
+
overallStatus: overallStatus(results, cancelled),
|
|
311
|
+
startedAtMs,
|
|
312
|
+
durationMs: now() - startedAtMs,
|
|
313
|
+
counts: countByStatus(results),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function rootMismatchReport(plan, workspaceRoot, startedAtMs, now) {
|
|
317
|
+
const results = plan.steps.map((step) => deniedResult(step, "verification plan rejected: workspace root mismatch"));
|
|
318
|
+
return finishReport(workspaceRoot, results, false, startedAtMs, now);
|
|
319
|
+
}
|
|
320
|
+
function preExecutionResult(step, cancelled, signal) {
|
|
321
|
+
if (!isValidVerificationStep(step)) {
|
|
322
|
+
return {
|
|
323
|
+
result: deniedResult(step, "verification plan rejected: unsupported step shape"),
|
|
324
|
+
cancelled,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
if (cancelled) {
|
|
328
|
+
return { result: cancelledResult(step), cancelled };
|
|
329
|
+
}
|
|
330
|
+
if (step.skipReason !== undefined) {
|
|
331
|
+
return { result: skippedResult(step), cancelled };
|
|
332
|
+
}
|
|
333
|
+
if (signal?.aborted === true) {
|
|
334
|
+
return { result: cancelledResult(step), cancelled: true };
|
|
335
|
+
}
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
async function runPlanSteps(plan, deps, baseSpawn, monitor) {
|
|
339
|
+
const results = [];
|
|
340
|
+
let cancelled = false;
|
|
341
|
+
for (const step of plan.steps) {
|
|
342
|
+
const early = preExecutionResult(step, cancelled, deps.signal);
|
|
343
|
+
if (early !== undefined) {
|
|
344
|
+
results.push(early.result);
|
|
345
|
+
cancelled = early.cancelled;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const result = toResult(step, await runStep(step, deps, baseSpawn, monitor));
|
|
349
|
+
results.push(result);
|
|
350
|
+
cancelled ||= result.status === "cancelled";
|
|
351
|
+
}
|
|
352
|
+
return { results, cancelled };
|
|
353
|
+
}
|
|
354
|
+
export async function runVerification(plan, deps) {
|
|
355
|
+
const now = deps.now ?? Date.now;
|
|
356
|
+
const startedAtMs = now();
|
|
357
|
+
const workspaceRoot = deps.workspace.root;
|
|
358
|
+
if (plan.workspaceRoot !== workspaceRoot) {
|
|
359
|
+
return rootMismatchReport(plan, workspaceRoot, startedAtMs, now);
|
|
360
|
+
}
|
|
361
|
+
const { results, cancelled } = await runPlanSteps(plan, deps, deps.spawn ?? nodeSpawnFn, deps.monitor ?? nodeResourceMonitor);
|
|
362
|
+
return finishReport(workspaceRoot, results, cancelled, startedAtMs, now);
|
|
363
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type WorkspaceFs, type WorkspaceInfo } from "../workspace/index.js";
|
|
2
|
+
import { type ScriptCatalog, type VerificationKind, type VerificationPlan, type VerificationResourceLimits, type VerificationStep } from "./types.js";
|
|
3
|
+
export interface PlanOptions {
|
|
4
|
+
readonly only?: readonly VerificationKind[] | undefined;
|
|
5
|
+
readonly limits?: Partial<VerificationResourceLimits> | undefined;
|
|
6
|
+
readonly changedFiles?: readonly string[] | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveTargetedTests(workspace: WorkspaceInfo, changedFiles: readonly string[], fs?: WorkspaceFs, limits?: VerificationResourceLimits): readonly VerificationStep[];
|
|
9
|
+
export declare function buildVerificationPlan(workspace: WorkspaceInfo, catalog: ScriptCatalog, options?: PlanOptions, fs?: WorkspaceFs): VerificationPlan;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Plan construction: turns a detected ScriptCatalog into an ordered VerificationPlan, and resolves
|
|
2
|
+
// targeted-test steps from a changed-file set. All path handling goes through the workspace
|
|
3
|
+
// boundary (resolveWithinWorkspace + WorkspaceFs.exists); no raw node:fs. Candidate test-path
|
|
4
|
+
// derivation uses plain string ops (no regex), so there is no ReDoS surface.
|
|
5
|
+
import { basename, dirname, extname, join, relative } from "node:path";
|
|
6
|
+
import { resolveWithinWorkspace, } from "../workspace/index.js";
|
|
7
|
+
import { nodeWorkspaceFs } from "../workspace/fs.js";
|
|
8
|
+
import { DEFAULT_VERIFICATION_LIMITS, } from "./types.js";
|
|
9
|
+
// The script-backed kinds, in run order. `targeted-test` is synthesised, not script-backed.
|
|
10
|
+
const SCRIPT_KINDS = [
|
|
11
|
+
"typecheck",
|
|
12
|
+
"lint",
|
|
13
|
+
"test",
|
|
14
|
+
"build",
|
|
15
|
+
];
|
|
16
|
+
function resolveLimits(overrides) {
|
|
17
|
+
return { ...DEFAULT_VERIFICATION_LIMITS, ...overrides };
|
|
18
|
+
}
|
|
19
|
+
function scriptStep(kind, scriptName, limits) {
|
|
20
|
+
if (scriptName === undefined) {
|
|
21
|
+
return {
|
|
22
|
+
kind,
|
|
23
|
+
scriptName: undefined,
|
|
24
|
+
command: "npm",
|
|
25
|
+
args: ["run", kind],
|
|
26
|
+
limits,
|
|
27
|
+
skipReason: `no ${kind} script detected in package.json`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// `npm test` has a dedicated subcommand; every other kind runs via `npm run <script>`.
|
|
31
|
+
const args = scriptName === "test" ? ["test"] : ["run", scriptName];
|
|
32
|
+
return { kind, scriptName, command: "npm", args, limits };
|
|
33
|
+
}
|
|
34
|
+
function wants(only, kind) {
|
|
35
|
+
return only === undefined || only.includes(kind);
|
|
36
|
+
}
|
|
37
|
+
// Derives candidate test paths for a changed source file: a sibling `X.test.ts`/`X.spec.ts`
|
|
38
|
+
// (and .tsx/.js/.jsx variants), and the same basename mirrored under each configured testDir.
|
|
39
|
+
function candidateTestPaths(workspace, file) {
|
|
40
|
+
const ext = extname(file);
|
|
41
|
+
if (ext === "") {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const dir = dirname(file);
|
|
45
|
+
const stem = basename(file, ext);
|
|
46
|
+
const suffixes = [".test", ".spec"];
|
|
47
|
+
const siblings = suffixes.map((s) => join(dir, `${stem}${s}${ext}`));
|
|
48
|
+
const sourceSubdir = sourceRelativeDir(workspace, file);
|
|
49
|
+
const mirrored = workspace.testDirs.flatMap((testDir) => suffixes.map((s) => join(testDir, sourceSubdir, `${stem}${s}${ext}`)));
|
|
50
|
+
return [...siblings, ...mirrored];
|
|
51
|
+
}
|
|
52
|
+
function sourceRelativeDir(workspace, file) {
|
|
53
|
+
const dir = dirname(file);
|
|
54
|
+
for (const sourceDir of workspace.sourceDirs) {
|
|
55
|
+
const rel = relative(sourceDir, dir);
|
|
56
|
+
if (rel === "") {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
if (!rel.startsWith("..") && !rel.startsWith("/") && !rel.includes(":")) {
|
|
60
|
+
return rel;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return dir === "." ? "" : dir;
|
|
64
|
+
}
|
|
65
|
+
function existsInWorkspace(workspace, fs, relPath) {
|
|
66
|
+
try {
|
|
67
|
+
const abs = resolveWithinWorkspace(workspace.root, relPath);
|
|
68
|
+
return fs.exists(abs);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// A path that escapes the workspace is simply not a resolvable target; skip it.
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Builds the framework-appropriate invocation that runs ONLY the given test files. vitest and jest
|
|
76
|
+
// both accept positional file paths. Returns undefined for an unknown framework, so no targeted
|
|
77
|
+
// step is added rather than guessing. The `npx <runner> ...` shape passes the #6 allowlist.
|
|
78
|
+
function targetedInvocation(workspace, files) {
|
|
79
|
+
if (workspace.testFramework === "vitest") {
|
|
80
|
+
return { command: "npx", args: ["vitest", "run", ...files] };
|
|
81
|
+
}
|
|
82
|
+
if (workspace.testFramework === "jest") {
|
|
83
|
+
return { command: "npx", args: ["jest", ...files] };
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
export function resolveTargetedTests(workspace, changedFiles, fs = nodeWorkspaceFs, limits = DEFAULT_VERIFICATION_LIMITS) {
|
|
88
|
+
const resolved = [];
|
|
89
|
+
for (const file of changedFiles) {
|
|
90
|
+
for (const candidate of candidateTestPaths(workspace, file)) {
|
|
91
|
+
if (existsInWorkspace(workspace, fs, candidate) && !resolved.includes(candidate)) {
|
|
92
|
+
resolved.push(candidate);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (resolved.length === 0) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
const invocation = targetedInvocation(workspace, resolved);
|
|
100
|
+
if (invocation === undefined) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
return [
|
|
104
|
+
{
|
|
105
|
+
kind: "targeted-test",
|
|
106
|
+
scriptName: undefined,
|
|
107
|
+
command: invocation.command,
|
|
108
|
+
args: invocation.args,
|
|
109
|
+
limits,
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
export function buildVerificationPlan(workspace, catalog, options = {}, fs = nodeWorkspaceFs) {
|
|
114
|
+
const limits = resolveLimits(options.limits);
|
|
115
|
+
const steps = [];
|
|
116
|
+
for (const kind of SCRIPT_KINDS) {
|
|
117
|
+
if (wants(options.only, kind)) {
|
|
118
|
+
steps.push(scriptStep(kind, catalog.mapping[kind], limits));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (wants(options.only, "targeted-test") && options.changedFiles !== undefined) {
|
|
122
|
+
steps.push(...resolveTargetedTests(workspace, options.changedFiles, fs, limits));
|
|
123
|
+
}
|
|
124
|
+
return { workspaceRoot: workspace.root, steps };
|
|
125
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ResourceLimitDecision, VerificationReport, VerificationResult, VerificationStatus } from "./types.js";
|
|
2
|
+
export interface VerificationResultSummary {
|
|
3
|
+
readonly kind: VerificationResult["kind"];
|
|
4
|
+
readonly scriptName: string | undefined;
|
|
5
|
+
readonly command: string;
|
|
6
|
+
readonly status: VerificationStatus;
|
|
7
|
+
readonly exitCode: number | null;
|
|
8
|
+
readonly durationMs: number;
|
|
9
|
+
readonly truncated: boolean;
|
|
10
|
+
readonly outputSummary: string;
|
|
11
|
+
readonly appliedLimits: readonly ResourceLimitDecision[];
|
|
12
|
+
readonly detail: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface VerificationSummary {
|
|
15
|
+
readonly workspaceRoot: string;
|
|
16
|
+
readonly overallStatus: VerificationStatus;
|
|
17
|
+
readonly durationMs: number;
|
|
18
|
+
readonly counts: Readonly<Record<VerificationStatus, number>>;
|
|
19
|
+
readonly results: readonly VerificationResultSummary[];
|
|
20
|
+
}
|
|
21
|
+
export interface AuditResultEntry {
|
|
22
|
+
readonly kind: VerificationResult["kind"];
|
|
23
|
+
readonly scriptName: string | undefined;
|
|
24
|
+
readonly command: string;
|
|
25
|
+
readonly status: VerificationStatus;
|
|
26
|
+
readonly exitCode: number | null;
|
|
27
|
+
readonly durationMs: number;
|
|
28
|
+
readonly truncated: boolean;
|
|
29
|
+
readonly appliedLimits: readonly ResourceLimitDecision[];
|
|
30
|
+
}
|
|
31
|
+
export interface VerificationAuditSummary {
|
|
32
|
+
readonly workspaceRoot: string;
|
|
33
|
+
readonly overallStatus: VerificationStatus;
|
|
34
|
+
readonly durationMs: number;
|
|
35
|
+
readonly counts: Readonly<Record<VerificationStatus, number>>;
|
|
36
|
+
readonly results: readonly AuditResultEntry[];
|
|
37
|
+
}
|
|
38
|
+
export declare function buildVerificationSummary(report: VerificationReport): VerificationSummary;
|
|
39
|
+
export declare function summarizeForAudit(report: VerificationReport): VerificationAuditSummary;
|
|
40
|
+
export declare function renderMarkdownSummary(report: VerificationReport): string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// The render surfaces over a VerificationReport (ADR-0007). buildVerificationSummary is the
|
|
2
|
+
// structured CLI/SDK view (keeps the redacted output digest); summarizeForAudit is the audit-ledger
|
|
3
|
+
// projection that EXCLUDES raw output text (mirroring ADR-0005 audit excerpt-exclusion), keeping
|
|
4
|
+
// only status/exit/duration/appliedLimits/counts; renderMarkdownSummary is a PR/issue table. Every
|
|
5
|
+
// composed string is run through redact() so nothing a summary emits can leak a secret. Pure — no IO.
|
|
6
|
+
import { redact } from "../gateway/redaction.js";
|
|
7
|
+
export function buildVerificationSummary(report) {
|
|
8
|
+
return {
|
|
9
|
+
workspaceRoot: report.workspaceRoot,
|
|
10
|
+
overallStatus: report.overallStatus,
|
|
11
|
+
durationMs: report.durationMs,
|
|
12
|
+
counts: report.counts,
|
|
13
|
+
results: report.results.map((r) => ({
|
|
14
|
+
kind: r.kind,
|
|
15
|
+
scriptName: r.scriptName,
|
|
16
|
+
command: redact(`${r.command} ${r.args.join(" ")}`.trim()),
|
|
17
|
+
status: r.status,
|
|
18
|
+
exitCode: r.exitCode,
|
|
19
|
+
durationMs: r.durationMs,
|
|
20
|
+
truncated: r.truncated,
|
|
21
|
+
// r.outputSummary is already redacted at the orchestrator; re-redact as defence in depth.
|
|
22
|
+
outputSummary: redact(r.outputSummary),
|
|
23
|
+
appliedLimits: r.appliedLimits,
|
|
24
|
+
detail: r.detail === undefined ? undefined : redact(r.detail),
|
|
25
|
+
})),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function summarizeForAudit(report) {
|
|
29
|
+
return {
|
|
30
|
+
workspaceRoot: report.workspaceRoot,
|
|
31
|
+
overallStatus: report.overallStatus,
|
|
32
|
+
durationMs: report.durationMs,
|
|
33
|
+
counts: report.counts,
|
|
34
|
+
results: report.results.map((r) => ({
|
|
35
|
+
kind: r.kind,
|
|
36
|
+
scriptName: r.scriptName,
|
|
37
|
+
command: redact(`${r.command} ${r.args.join(" ")}`.trim()),
|
|
38
|
+
status: r.status,
|
|
39
|
+
exitCode: r.exitCode,
|
|
40
|
+
durationMs: r.durationMs,
|
|
41
|
+
truncated: r.truncated,
|
|
42
|
+
appliedLimits: r.appliedLimits,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function statusMark(status) {
|
|
47
|
+
if (status === "passed") {
|
|
48
|
+
return "pass";
|
|
49
|
+
}
|
|
50
|
+
if (status === "skipped") {
|
|
51
|
+
return "skip";
|
|
52
|
+
}
|
|
53
|
+
return "FAIL";
|
|
54
|
+
}
|
|
55
|
+
function markdownRow(result) {
|
|
56
|
+
const cmd = redact(`${result.command} ${result.args.join(" ")}`.trim());
|
|
57
|
+
const detail = result.detail === undefined ? "" : redact(result.detail);
|
|
58
|
+
const exit = result.exitCode === null ? "—" : String(result.exitCode);
|
|
59
|
+
return `| ${result.kind} | ${result.status} | ${exit} | ${String(result.durationMs)} | \`${cmd}\` | ${detail} |`;
|
|
60
|
+
}
|
|
61
|
+
// A PR/issue Markdown table. Every cell that can carry command-derived text is redacted.
|
|
62
|
+
export function renderMarkdownSummary(report) {
|
|
63
|
+
const header = `### Verification: ${statusMark(report.overallStatus)} (${report.overallStatus})`;
|
|
64
|
+
const tableHead = "| Kind | Status | Exit | ms | Command | Detail |\n| --- | --- | --- | --- | --- | --- |";
|
|
65
|
+
const rows = report.results.map(markdownRow).join("\n");
|
|
66
|
+
return `${header}\n\n${tableHead}\n${rows}\n`;
|
|
67
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { NetworkPolicy } from "../tools/types.js";
|
|
2
|
+
export type VerificationKind = "test" | "targeted-test" | "typecheck" | "lint" | "build";
|
|
3
|
+
export type VerificationStatus = "passed" | "failed" | "skipped" | "denied" | "timed-out" | "cancelled" | "resource-exceeded";
|
|
4
|
+
export type ResourceDimension = "wall-time" | "output-size" | "memory" | "network";
|
|
5
|
+
export interface ResourceLimitDecision {
|
|
6
|
+
readonly dimension: ResourceDimension;
|
|
7
|
+
readonly limit: number | string;
|
|
8
|
+
readonly enforced: boolean;
|
|
9
|
+
readonly note?: string | undefined;
|
|
10
|
+
readonly breached?: boolean | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface VerificationResourceLimits {
|
|
13
|
+
readonly wallTimeMs: number;
|
|
14
|
+
readonly maxOutputBytes: number;
|
|
15
|
+
readonly maxMemoryBytes: number | undefined;
|
|
16
|
+
readonly network: NetworkPolicy;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_VERIFICATION_LIMITS: VerificationResourceLimits;
|
|
19
|
+
export interface VerificationStep {
|
|
20
|
+
readonly kind: VerificationKind;
|
|
21
|
+
readonly scriptName: string | undefined;
|
|
22
|
+
readonly command: string;
|
|
23
|
+
readonly args: readonly string[];
|
|
24
|
+
readonly limits: VerificationResourceLimits;
|
|
25
|
+
readonly skipReason?: string | undefined;
|
|
26
|
+
}
|
|
27
|
+
export interface VerificationPlan {
|
|
28
|
+
readonly workspaceRoot: string;
|
|
29
|
+
readonly steps: readonly VerificationStep[];
|
|
30
|
+
}
|
|
31
|
+
export interface VerificationResult {
|
|
32
|
+
readonly kind: VerificationKind;
|
|
33
|
+
readonly scriptName: string | undefined;
|
|
34
|
+
readonly command: string;
|
|
35
|
+
readonly args: readonly string[];
|
|
36
|
+
readonly status: VerificationStatus;
|
|
37
|
+
readonly exitCode: number | null;
|
|
38
|
+
readonly signal: string | null;
|
|
39
|
+
readonly durationMs: number;
|
|
40
|
+
readonly truncated: boolean;
|
|
41
|
+
readonly redacted: boolean;
|
|
42
|
+
readonly outputSummary: string;
|
|
43
|
+
readonly appliedLimits: readonly ResourceLimitDecision[];
|
|
44
|
+
readonly detail?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
export interface VerificationReport {
|
|
47
|
+
readonly workspaceRoot: string;
|
|
48
|
+
readonly results: readonly VerificationResult[];
|
|
49
|
+
readonly overallStatus: VerificationStatus;
|
|
50
|
+
readonly startedAtMs: number;
|
|
51
|
+
readonly durationMs: number;
|
|
52
|
+
readonly counts: Readonly<Record<VerificationStatus, number>>;
|
|
53
|
+
}
|
|
54
|
+
export interface ScriptCatalog {
|
|
55
|
+
readonly scripts: Readonly<Record<string, string>>;
|
|
56
|
+
readonly mapping: ScriptMapping;
|
|
57
|
+
}
|
|
58
|
+
export interface ScriptMapping {
|
|
59
|
+
readonly test: string | undefined;
|
|
60
|
+
readonly typecheck: string | undefined;
|
|
61
|
+
readonly lint: string | undefined;
|
|
62
|
+
readonly build: string | undefined;
|
|
63
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// All verification-layer interfaces and the frozen default limits. No runtime logic lives here
|
|
2
|
+
// beyond the frozen constant tables the type layer exposes as values, mirroring the
|
|
3
|
+
// ADR-0003/0004/0005/0006 `types.ts` precedent. `readonly` everywhere; optional props are
|
|
4
|
+
// `| undefined` because exactOptionalPropertyTypes is on. Every shape is plain JSON-serializable
|
|
5
|
+
// so the #10 audit ledger can persist a VerificationReport without ad-hoc parsing.
|
|
6
|
+
// Wave-1 defaults. maxMemoryBytes is undefined by default: memory enforcement is opt-in and
|
|
7
|
+
// Linux-only (ADR-0007 D2/D3). network defaults to the no-network posture, documented-not-enforced.
|
|
8
|
+
export const DEFAULT_VERIFICATION_LIMITS = {
|
|
9
|
+
wallTimeMs: 120_000,
|
|
10
|
+
maxOutputBytes: 1_048_576,
|
|
11
|
+
maxMemoryBytes: undefined,
|
|
12
|
+
network: "none",
|
|
13
|
+
};
|