@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,74 @@
|
|
|
1
|
+
// The single public entry: investigateBug (ADR-0009 D2/D6/D10/D11). A deterministic linear pipeline
|
|
2
|
+
// (NOT the harness loop): intake precondition -> parse failure evidence -> build context -> [prompt
|
|
3
|
+
// -> model -> parse -> validate -> scope-guard] (bounded retries) -> [investigation-only |
|
|
4
|
+
// rejected | dry-run | apply -> verify] -> report. It composes #3-#7 UNCHANGED and emits redacted
|
|
5
|
+
// progress events. The model loop, verify stage, and report stages live in sibling files to keep
|
|
6
|
+
// each under the LOC limit; this file owns the stage sequencing, the intake precondition (return
|
|
7
|
+
// `rejected` with no model call when no evidence is present), and the single top-level catch
|
|
8
|
+
// boundary that maps a CancelledError to a "cancelled" report and any other IO failure to a
|
|
9
|
+
// redacted "failed" report.
|
|
10
|
+
import { CancelledError } from "../../gateway/errors.js";
|
|
11
|
+
import { detectWorkspace } from "../../workspace/index.js";
|
|
12
|
+
import { nodeWorkspaceFs } from "../../workspace/fs.js";
|
|
13
|
+
import { buildBugContext } from "./context.js";
|
|
14
|
+
import { computeBugFingerprint } from "./emit.js";
|
|
15
|
+
import { parseFailureEvidence } from "./failure-parse.js";
|
|
16
|
+
import { runBugModelLoop } from "./model-loop.js";
|
|
17
|
+
import { cancelledReport, emitCompleted, failedReport, finishPipeline, insufficientInputReport, } from "./stages.js";
|
|
18
|
+
import { buildBugRunState, EMPTY_BUG_LOOP } from "./internal.js";
|
|
19
|
+
// Intake precondition (D2): at least one evidence field must be present, else there is nothing to
|
|
20
|
+
// investigate and we reject WITHOUT calling the model.
|
|
21
|
+
function hasEvidence(report) {
|
|
22
|
+
return (nonEmpty(report.description) ||
|
|
23
|
+
nonEmpty(report.failingOutput) ||
|
|
24
|
+
nonEmpty(report.stackTrace) ||
|
|
25
|
+
(report.targetFiles?.some((file) => nonEmpty(file)) ?? false));
|
|
26
|
+
}
|
|
27
|
+
function nonEmpty(value) {
|
|
28
|
+
return value !== undefined && value.trim().length > 0;
|
|
29
|
+
}
|
|
30
|
+
async function runPipeline(state) {
|
|
31
|
+
const report = state.input.report;
|
|
32
|
+
state.emitter.emit({
|
|
33
|
+
type: "bug:started",
|
|
34
|
+
workflowId: "bug-investigation",
|
|
35
|
+
modelId: state.input.modelId,
|
|
36
|
+
applyEnabled: state.input.apply === true,
|
|
37
|
+
limits: state.limits,
|
|
38
|
+
});
|
|
39
|
+
if (!hasEvidence(report)) {
|
|
40
|
+
return insufficientInputReport(state);
|
|
41
|
+
}
|
|
42
|
+
const fs = state.deps.fs ?? nodeWorkspaceFs;
|
|
43
|
+
const workspace = detectWorkspace(state.input.workspaceRoot, fs);
|
|
44
|
+
const evidence = parseFailureEvidence(report);
|
|
45
|
+
state.emitter.emit({
|
|
46
|
+
type: "bug:failure:parsed",
|
|
47
|
+
frameCount: evidence.frames.length,
|
|
48
|
+
messageCount: evidence.messages.length,
|
|
49
|
+
});
|
|
50
|
+
const pack = buildBugContext(workspace, report.description, evidence, state.limits, { fs });
|
|
51
|
+
state.emitter.emit({
|
|
52
|
+
type: "bug:context:selected",
|
|
53
|
+
entryCount: pack.selected.length,
|
|
54
|
+
usedBytes: pack.usedBytes,
|
|
55
|
+
budgetBytes: pack.budgetBytes,
|
|
56
|
+
droppedForBudget: pack.droppedForBudget,
|
|
57
|
+
});
|
|
58
|
+
const loop = await runBugModelLoop(state, workspace, report, evidence, pack);
|
|
59
|
+
return finishPipeline(state, workspace, loop, evidence);
|
|
60
|
+
}
|
|
61
|
+
export async function investigateBug(input, deps) {
|
|
62
|
+
const state = buildBugRunState(input, deps, computeBugFingerprint(input.report, input.modelId));
|
|
63
|
+
let report;
|
|
64
|
+
try {
|
|
65
|
+
report = await runPipeline(state);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
report =
|
|
69
|
+
error instanceof CancelledError
|
|
70
|
+
? cancelledReport(state, EMPTY_BUG_LOOP, undefined, { frames: [], messages: [] })
|
|
71
|
+
: failedReport(state, error);
|
|
72
|
+
}
|
|
73
|
+
return emitCompleted(state, report);
|
|
74
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface WorkflowInputSpec {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly type: "string" | "boolean" | "string[]" | "object";
|
|
4
|
+
readonly required: boolean;
|
|
5
|
+
readonly description: string;
|
|
6
|
+
readonly defaultValue?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface WorkflowDescriptor<TLimits = object> {
|
|
9
|
+
readonly workflowId: string;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly description: string;
|
|
12
|
+
readonly inputs: readonly WorkflowInputSpec[];
|
|
13
|
+
readonly defaultLimits: TLimits;
|
|
14
|
+
readonly modelSelectionOptions: {
|
|
15
|
+
readonly arbitrary: boolean;
|
|
16
|
+
readonly preferredCostClass: "low" | "medium" | "high";
|
|
17
|
+
};
|
|
18
|
+
readonly supportsDryRun: boolean;
|
|
19
|
+
readonly supportsApply: boolean;
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Shared UI workflow-descriptor interfaces (ADR-0009 D12). Extracted from the unit-test
|
|
2
|
+
// workflow's descriptor so BOTH workflows depend on this common base and NEITHER depends on the
|
|
3
|
+
// other — a clean dependency direction for the workflows layer. Pure types, no runtime logic.
|
|
4
|
+
// Each workflow exports its own concrete `*_WORKFLOW_DESCRIPTOR: WorkflowDescriptor<TLimits>`
|
|
5
|
+
// value; issue #13 reads those values to render the workflow UI without the implementation.
|
|
6
|
+
// `TLimits` is the workflow's own frozen limits shape so each descriptor keeps precise typing on
|
|
7
|
+
// `defaultLimits` (it defaults to `object` for callers that handle descriptors generically).
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ContextPack, type WorkspaceInfo } from "../../workspace/index.js";
|
|
2
|
+
import { type WorkspaceFs } from "../../workspace/fs.js";
|
|
3
|
+
import type { UnitTestWorkflowInput, WorkflowLimits } from "./types.js";
|
|
4
|
+
export interface TestGenContextDeps {
|
|
5
|
+
readonly fs?: WorkspaceFs | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildTestGenContext(workspace: WorkspaceInfo, input: UnitTestWorkflowInput, limits: WorkflowLimits, deps?: TestGenContextDeps): ContextPack;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Context assembly for the generation call (ADR-0008 D1). Delegates to #5 buildContextPack so the
|
|
2
|
+
// target file, nearby test files, manifests/config, and type definitions are selected, ranked, and
|
|
3
|
+
// excerpted under a byte budget — every excerpt already redacted by #5 at the IO boundary. Pure
|
|
4
|
+
// except for the WorkspaceFs seam threaded into buildContextPack. The `task` hint is a forward-
|
|
5
|
+
// compatible natural-language description of the target for a future embedding ranker; the Wave-1
|
|
6
|
+
// lexical strategy tolerates it.
|
|
7
|
+
import { buildContextPack, DEFAULT_DISCOVERY_OPTIONS, lexicalRetrievalStrategy, SELECTION_REASON_PRIORITY, } from "../../workspace/index.js";
|
|
8
|
+
import { nodeWorkspaceFs } from "../../workspace/fs.js";
|
|
9
|
+
function toPosix(path) {
|
|
10
|
+
return path.split("\\").join("/");
|
|
11
|
+
}
|
|
12
|
+
function underDir(path, dir) {
|
|
13
|
+
const normalized = toPosix(dir);
|
|
14
|
+
return path === normalized || path.startsWith(`${normalized}/`);
|
|
15
|
+
}
|
|
16
|
+
function basename(path) {
|
|
17
|
+
const normalized = toPosix(path);
|
|
18
|
+
const idx = normalized.lastIndexOf("/");
|
|
19
|
+
return idx === -1 ? normalized : normalized.slice(idx + 1);
|
|
20
|
+
}
|
|
21
|
+
function stem(path) {
|
|
22
|
+
const base = basename(path);
|
|
23
|
+
const idx = base.lastIndexOf(".");
|
|
24
|
+
return idx <= 0 ? base : base.slice(0, idx);
|
|
25
|
+
}
|
|
26
|
+
function testStem(path) {
|
|
27
|
+
const parts = stem(path).split(".");
|
|
28
|
+
const marker = parts.findIndex((part) => part === "test" || part === "spec");
|
|
29
|
+
return marker === -1 ? parts.join(".") : parts.slice(0, marker).join(".");
|
|
30
|
+
}
|
|
31
|
+
function targetPaths(target) {
|
|
32
|
+
if (target.kind === "file") {
|
|
33
|
+
return [toPosix(target.filePath)];
|
|
34
|
+
}
|
|
35
|
+
if (target.kind === "changedFiles") {
|
|
36
|
+
return target.filePaths.map(toPosix);
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
function moduleDir(target) {
|
|
41
|
+
return target.kind === "module" ? toPosix(target.moduleDir) : undefined;
|
|
42
|
+
}
|
|
43
|
+
function isRequestedTarget(path, input) {
|
|
44
|
+
const module = moduleDir(input.target);
|
|
45
|
+
return (targetPaths(input.target).includes(path) || (module !== undefined && underDir(path, module)));
|
|
46
|
+
}
|
|
47
|
+
function isTestCandidate(path, workspace, selectionReason) {
|
|
48
|
+
return (selectionReason === "test" ||
|
|
49
|
+
workspace.testDirs.some((testDir) => underDir(path, testDir)) ||
|
|
50
|
+
stem(path)
|
|
51
|
+
.split(".")
|
|
52
|
+
.some((part) => part === "test" || part === "spec"));
|
|
53
|
+
}
|
|
54
|
+
function isNearbyTest(path, workspace, input, selectionReason) {
|
|
55
|
+
if (!isTestCandidate(path, workspace, selectionReason)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const targets = targetPaths(input.target);
|
|
59
|
+
if (targets.length === 0) {
|
|
60
|
+
const module = moduleDir(input.target);
|
|
61
|
+
return module !== undefined && path.includes(basename(module));
|
|
62
|
+
}
|
|
63
|
+
const candidateStem = testStem(path);
|
|
64
|
+
return targets.some((target) => candidateStem === stem(target));
|
|
65
|
+
}
|
|
66
|
+
function priorityIndex(reason) {
|
|
67
|
+
return SELECTION_REASON_PRIORITY.indexOf(reason);
|
|
68
|
+
}
|
|
69
|
+
function issue8Priority(ranked, workspace, input) {
|
|
70
|
+
const path = toPosix(ranked.file.relativePath);
|
|
71
|
+
if (isRequestedTarget(path, input)) {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
if (isNearbyTest(path, workspace, input, ranked.selectionReason)) {
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
function isSupportContext(ranked) {
|
|
80
|
+
return ranked.selectionReason === "manifest" || ranked.selectionReason === "config";
|
|
81
|
+
}
|
|
82
|
+
function focusedContext(ranked, workspace, input) {
|
|
83
|
+
const focused = ranked.filter((item) => issue8Priority(item, workspace, input) < 2 || isSupportContext(item));
|
|
84
|
+
return focused.length === 0 ? ranked : focused;
|
|
85
|
+
}
|
|
86
|
+
function createUnitTestRetrievalStrategy(workspace, input) {
|
|
87
|
+
return {
|
|
88
|
+
rank: (files, task) => {
|
|
89
|
+
const ranked = focusedContext(lexicalRetrievalStrategy.rank(files, task), workspace, input);
|
|
90
|
+
return [...ranked].sort((a, b) => {
|
|
91
|
+
const byIssue8 = issue8Priority(a, workspace, input) - issue8Priority(b, workspace, input);
|
|
92
|
+
if (byIssue8 !== 0) {
|
|
93
|
+
return byIssue8;
|
|
94
|
+
}
|
|
95
|
+
const byReason = priorityIndex(a.selectionReason) - priorityIndex(b.selectionReason);
|
|
96
|
+
if (byReason !== 0) {
|
|
97
|
+
return byReason;
|
|
98
|
+
}
|
|
99
|
+
return a.file.relativePath.localeCompare(b.file.relativePath);
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function taskHint(target) {
|
|
105
|
+
if (target.kind === "file") {
|
|
106
|
+
return target.targetFunction === undefined
|
|
107
|
+
? `unit tests for ${target.filePath}`
|
|
108
|
+
: `unit tests for ${target.targetFunction} in ${target.filePath}`;
|
|
109
|
+
}
|
|
110
|
+
if (target.kind === "module") {
|
|
111
|
+
return `unit tests for module ${target.moduleDir}`;
|
|
112
|
+
}
|
|
113
|
+
return `unit tests for ${target.filePaths.join(", ")}`;
|
|
114
|
+
}
|
|
115
|
+
export function buildTestGenContext(workspace, input, limits, deps = {}) {
|
|
116
|
+
const request = {
|
|
117
|
+
task: taskHint(input.target),
|
|
118
|
+
budgetBytes: limits.contextBudgetBytes,
|
|
119
|
+
maxBytesPerFile: limits.maxBytesPerFile,
|
|
120
|
+
discovery: DEFAULT_DISCOVERY_OPTIONS,
|
|
121
|
+
};
|
|
122
|
+
// buildContextPack defaults to the lexical strategy, but ContextPackDeps requires the field; pass
|
|
123
|
+
// the #5 barrel default explicitly so we hand a complete deps object without reaching past #5.
|
|
124
|
+
const packDeps = {
|
|
125
|
+
fs: deps.fs ?? nodeWorkspaceFs,
|
|
126
|
+
strategy: createUnitTestRetrievalStrategy(workspace, input),
|
|
127
|
+
};
|
|
128
|
+
return buildContextPack(workspace, request, packDeps);
|
|
129
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ContextPack, WorkspaceInfo } from "../../workspace/index.js";
|
|
2
|
+
import type { TestConventions } from "./types.js";
|
|
3
|
+
export declare function isTestPath(workspace: WorkspaceInfo, relPath: string): boolean;
|
|
4
|
+
export declare function detectConventions(workspace: WorkspaceInfo, pack: ContextPack): TestConventions;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Convention detection (ADR-0008 D7) and the production-code guard predicate (D6). Pure except
|
|
2
|
+
// for the WorkspaceInfo/ContextPack values handed in (no IO, no clock, no RNG). ALL path and
|
|
3
|
+
// naming predicates use plain string ops (split('.'), startsWith, equality) — zero regex — so
|
|
4
|
+
// there is no ReDoS surface (CodeQL js/polynomial-redos, steering note F).
|
|
5
|
+
import { basename, dirname, extname } from "node:path";
|
|
6
|
+
const MAX_ASSERTION_SAMPLES = 2;
|
|
7
|
+
const TEST_SEGMENTS = ["test", "spec"];
|
|
8
|
+
// Normalises a path to forward slashes so dir/segment checks are platform-independent.
|
|
9
|
+
function toPosix(path) {
|
|
10
|
+
return path.split("\\").join("/");
|
|
11
|
+
}
|
|
12
|
+
// True when the basename (without its final extension) contains "test" or "spec" as a
|
|
13
|
+
// dot-separated segment. `foo.test.ts` -> ["foo","test"] -> pass; `testUtils.ts` ->
|
|
14
|
+
// ["testUtils"] -> FAIL (prefix, not a segment); `foo.spec.utils.ts` -> ["foo","spec","utils"] -> pass.
|
|
15
|
+
function basenameMarksTest(path) {
|
|
16
|
+
const ext = extname(path);
|
|
17
|
+
const stem = basename(path, ext);
|
|
18
|
+
const segments = stem.split(".");
|
|
19
|
+
return segments.some((segment) => TEST_SEGMENTS.includes(segment));
|
|
20
|
+
}
|
|
21
|
+
// True when the path's directory equals or sits under one of the configured testDirs.
|
|
22
|
+
function underTestDir(testDirs, posixPath) {
|
|
23
|
+
const dir = dirname(posixPath);
|
|
24
|
+
return testDirs.some((rawTestDir) => {
|
|
25
|
+
const testDir = toPosix(rawTestDir);
|
|
26
|
+
return dir === testDir || dir.startsWith(`${testDir}/`) || posixPath.startsWith(`${testDir}/`);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
// A path containing a `..` segment or an absolute leading slash is traversal: it can resolve to a
|
|
30
|
+
// production file OUTSIDE the apparent test directory. `tests/../src/auth.ts` lexically starts with
|
|
31
|
+
// `tests/`, but #6 resolveWithinWorkspace collapses it to the in-workspace `src/auth.ts` and writes
|
|
32
|
+
// THAT. A legitimately generated test path is always a clean workspace-relative path, so we reject
|
|
33
|
+
// traversal fail-closed before any test/testDir check (security fix: D6 bypass via path traversal).
|
|
34
|
+
function isTraversal(posixPath) {
|
|
35
|
+
return posixPath.startsWith("/") || posixPath.split("/").includes("..");
|
|
36
|
+
}
|
|
37
|
+
// The production-code guard predicate (D6): a path passes if its basename marks it a test file OR
|
|
38
|
+
// it lies under a detected testDir. Used to reject any patch that touches a non-test path before
|
|
39
|
+
// renderDryRun/applyPatch — the second barrier against prompt-injected source modification. Any
|
|
40
|
+
// traversal/absolute path is rejected outright so the guarded path matches the path #6 would write.
|
|
41
|
+
export function isTestPath(workspace, relPath) {
|
|
42
|
+
const posixPath = toPosix(relPath);
|
|
43
|
+
if (isTraversal(posixPath)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return basenameMarksTest(posixPath) || underTestDir(workspace.testDirs, posixPath);
|
|
47
|
+
}
|
|
48
|
+
// The set of test excerpts already selected by #5 (redacted, bounded), capped to MAX_ASSERTION_SAMPLES.
|
|
49
|
+
function sampleAssertionStyle(pack) {
|
|
50
|
+
return pack.selected
|
|
51
|
+
.filter((entry) => entry.selectionReason === "test")
|
|
52
|
+
.slice(0, MAX_ASSERTION_SAMPLES)
|
|
53
|
+
.map((entry) => entry.excerpt);
|
|
54
|
+
}
|
|
55
|
+
// Whether any selected pack entry is a sibling test (a test file whose directory matches a
|
|
56
|
+
// non-test source path's directory). We approximate "sibling" as a test-marked path NOT under a
|
|
57
|
+
// configured testDir, and "mirrored" as a test-marked path under a testDir.
|
|
58
|
+
function hasSiblingTest(workspace, pack) {
|
|
59
|
+
return pack.selected.some((entry) => basenameMarksTest(toPosix(entry.path)) &&
|
|
60
|
+
!underTestDir(workspace.testDirs, toPosix(entry.path)));
|
|
61
|
+
}
|
|
62
|
+
function hasMirroredTest(workspace, pack) {
|
|
63
|
+
return pack.selected.some((entry) => basenameMarksTest(toPosix(entry.path)) &&
|
|
64
|
+
underTestDir(workspace.testDirs, toPosix(entry.path)));
|
|
65
|
+
}
|
|
66
|
+
function deriveNamingStyle(workspace, pack) {
|
|
67
|
+
if (hasSiblingTest(workspace, pack)) {
|
|
68
|
+
return "sibling";
|
|
69
|
+
}
|
|
70
|
+
if (workspace.testDirs.length > 0 && hasMirroredTest(workspace, pack)) {
|
|
71
|
+
return "mirrored";
|
|
72
|
+
}
|
|
73
|
+
// testDirs present but no observed test sample: default to mirrored (the conventional placement
|
|
74
|
+
// under tests/). Only when there is neither a testDir nor a sample is the style unknown.
|
|
75
|
+
if (workspace.testDirs.length > 0) {
|
|
76
|
+
return "mirrored";
|
|
77
|
+
}
|
|
78
|
+
return "unknown";
|
|
79
|
+
}
|
|
80
|
+
export function detectConventions(workspace, pack) {
|
|
81
|
+
return {
|
|
82
|
+
framework: workspace.testFramework,
|
|
83
|
+
testDirs: workspace.testDirs,
|
|
84
|
+
fileNamingStyle: deriveNamingStyle(workspace, pack),
|
|
85
|
+
assertionStyleSamples: sampleAssertionStyle(pack),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type WorkflowLimits } from "./types.js";
|
|
2
|
+
import type { WorkflowDescriptor } from "../descriptor.js";
|
|
3
|
+
export type { WorkflowDescriptor, WorkflowInputSpec } from "../descriptor.js";
|
|
4
|
+
export declare const UNIT_TEST_WORKFLOW_DESCRIPTOR: WorkflowDescriptor<WorkflowLimits>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// The static UI workflow descriptor (ADR-0008 D10). Issue #13 reads this to render the workflow
|
|
2
|
+
// UI without knowing the implementation. Frozen and JSON-serializable. The descriptor interfaces
|
|
3
|
+
// are the shared base (ADR-0009 D12) — re-exported here so #8's existing import surface (the
|
|
4
|
+
// unit-tests barrel) is unchanged; both workflows depend on the base and neither on the other.
|
|
5
|
+
import { DEFAULT_WORKFLOW_LIMITS } from "./types.js";
|
|
6
|
+
export const UNIT_TEST_WORKFLOW_DESCRIPTOR = {
|
|
7
|
+
workflowId: "unit-test-generation",
|
|
8
|
+
name: "Unit Test Generation",
|
|
9
|
+
description: "Generates a reviewable unit-test patch for a target TypeScript file, function, or module. " +
|
|
10
|
+
"Detects the project's test framework and naming conventions. Dry-run by default; " +
|
|
11
|
+
"pass apply:true to write the tests and run verification.",
|
|
12
|
+
inputs: [
|
|
13
|
+
{
|
|
14
|
+
name: "target",
|
|
15
|
+
type: "object",
|
|
16
|
+
required: true,
|
|
17
|
+
description: "Target: { kind: 'file', filePath } | { kind: 'module', moduleDir } | { kind: 'changedFiles', filePaths }",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "apply",
|
|
21
|
+
type: "boolean",
|
|
22
|
+
required: false,
|
|
23
|
+
description: "Write tests to disk and run verification",
|
|
24
|
+
defaultValue: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "modelId",
|
|
28
|
+
type: "string",
|
|
29
|
+
required: true,
|
|
30
|
+
description: "Model ID registered in gateway config",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "limits",
|
|
34
|
+
type: "object",
|
|
35
|
+
required: false,
|
|
36
|
+
description: "Partial<WorkflowLimits> overrides",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
defaultLimits: DEFAULT_WORKFLOW_LIMITS,
|
|
40
|
+
modelSelectionOptions: { arbitrary: true, preferredCostClass: "medium" },
|
|
41
|
+
supportsDryRun: true,
|
|
42
|
+
supportsApply: true,
|
|
43
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { UnitTestTarget } from "./types.js";
|
|
2
|
+
import type { WorkflowEvent, WorkflowEventSink } from "./events.js";
|
|
3
|
+
export declare function computeFingerprint(target: UnitTestTarget, modelId: string): string;
|
|
4
|
+
type EnvelopeFields = "schemaVersion" | "runId" | "fingerprint" | "seq" | "ts";
|
|
5
|
+
export type WorkflowEventBody = {
|
|
6
|
+
[E in WorkflowEvent as E["type"]]: Omit<E, EnvelopeFields>;
|
|
7
|
+
}[WorkflowEvent["type"]];
|
|
8
|
+
export interface EventEmitter {
|
|
9
|
+
readonly emit: (body: WorkflowEventBody) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createEventEmitter(sink: WorkflowEventSink, runId: string, fingerprint: string, now: () => number): EventEmitter;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Event emission helper for the workflow (ADR-0008 D4). Owns the monotonic seq counter and stamps
|
|
2
|
+
// every event with the shared envelope ({ schemaVersion, runId, fingerprint, seq, ts }). The
|
|
3
|
+
// fingerprint is SHA-256(workflowId + canonical(target) + modelId) truncated to 16 hex chars — the
|
|
4
|
+
// same shape as the harness fingerprinter — reusing `canonicalise` from the harness barrel so two
|
|
5
|
+
// structurally equal targets fingerprint identically regardless of key order. Sensitive fields are
|
|
6
|
+
// redacted by the CALLER before handing the event here (this helper does not inspect payloads).
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { canonicalise } from "../../harness/index.js";
|
|
9
|
+
const FINGERPRINT_HEX_CHARS = 16;
|
|
10
|
+
export function computeFingerprint(target, modelId) {
|
|
11
|
+
const canonical = canonicalise({ workflowId: "unit-test-generation", target, modelId });
|
|
12
|
+
return createHash("sha256")
|
|
13
|
+
.update(canonical, "utf8")
|
|
14
|
+
.digest("hex")
|
|
15
|
+
.slice(0, FINGERPRINT_HEX_CHARS);
|
|
16
|
+
}
|
|
17
|
+
export function createEventEmitter(sink, runId, fingerprint, now) {
|
|
18
|
+
let seq = 0;
|
|
19
|
+
return {
|
|
20
|
+
emit: (body) => {
|
|
21
|
+
seq += 1;
|
|
22
|
+
// The body is a complete discriminated-union member minus the envelope; re-attaching the
|
|
23
|
+
// envelope yields a valid WorkflowEvent. The cast is over the union, not a widening to any.
|
|
24
|
+
const event = {
|
|
25
|
+
schemaVersion: "1",
|
|
26
|
+
runId,
|
|
27
|
+
fingerprint,
|
|
28
|
+
seq,
|
|
29
|
+
ts: now(),
|
|
30
|
+
...body,
|
|
31
|
+
};
|
|
32
|
+
sink.emit(event);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { TestFramework } from "../../workspace/index.js";
|
|
2
|
+
import type { VerificationStatus } from "../../verification/index.js";
|
|
3
|
+
import type { FileNamingStyle, WorkflowLimits, WorkflowStatus } from "./types.js";
|
|
4
|
+
interface BaseWorkflowEvent {
|
|
5
|
+
readonly schemaVersion: "1";
|
|
6
|
+
readonly runId: string;
|
|
7
|
+
readonly fingerprint: string;
|
|
8
|
+
readonly seq: number;
|
|
9
|
+
readonly ts: number;
|
|
10
|
+
}
|
|
11
|
+
export interface WorkflowStartedEvent extends BaseWorkflowEvent {
|
|
12
|
+
readonly type: "workflow:started";
|
|
13
|
+
readonly workflowId: "unit-test-generation";
|
|
14
|
+
readonly modelId: string;
|
|
15
|
+
readonly applyEnabled: boolean;
|
|
16
|
+
readonly limits: WorkflowLimits;
|
|
17
|
+
}
|
|
18
|
+
export interface ConventionsDetectedEvent extends BaseWorkflowEvent {
|
|
19
|
+
readonly type: "conventions:detected";
|
|
20
|
+
readonly framework: TestFramework;
|
|
21
|
+
readonly testDirs: readonly string[];
|
|
22
|
+
readonly fileNamingStyle: FileNamingStyle;
|
|
23
|
+
}
|
|
24
|
+
export interface ContextSelectedEvent extends BaseWorkflowEvent {
|
|
25
|
+
readonly type: "context:selected";
|
|
26
|
+
readonly entryCount: number;
|
|
27
|
+
readonly usedBytes: number;
|
|
28
|
+
readonly budgetBytes: number;
|
|
29
|
+
readonly droppedForBudget: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ModelCallStartedEvent extends BaseWorkflowEvent {
|
|
32
|
+
readonly type: "workflow:model:call:started";
|
|
33
|
+
readonly attempt: number;
|
|
34
|
+
readonly contextBytes: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ModelCallCompletedEvent extends BaseWorkflowEvent {
|
|
37
|
+
readonly type: "workflow:model:call:completed";
|
|
38
|
+
readonly attempt: number;
|
|
39
|
+
readonly finishReason: string;
|
|
40
|
+
readonly promptTokens: number;
|
|
41
|
+
readonly completionTokens: number;
|
|
42
|
+
readonly latencyMs: number;
|
|
43
|
+
}
|
|
44
|
+
export interface PatchValidatedEvent extends BaseWorkflowEvent {
|
|
45
|
+
readonly type: "patch:validated";
|
|
46
|
+
readonly ok: boolean;
|
|
47
|
+
readonly patchBytes: number;
|
|
48
|
+
readonly filesChanged: number;
|
|
49
|
+
readonly rejectionCode?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
export interface PatchAppliedEvent extends BaseWorkflowEvent {
|
|
52
|
+
readonly type: "workflow:patch:applied";
|
|
53
|
+
readonly changedFiles: number;
|
|
54
|
+
readonly created: number;
|
|
55
|
+
readonly deleted: number;
|
|
56
|
+
}
|
|
57
|
+
export interface VerificationResultEvent extends BaseWorkflowEvent {
|
|
58
|
+
readonly type: "workflow:verification:result";
|
|
59
|
+
readonly overallStatus: VerificationStatus;
|
|
60
|
+
readonly stepCount: number;
|
|
61
|
+
readonly passedCount: number;
|
|
62
|
+
readonly durationMs: number;
|
|
63
|
+
}
|
|
64
|
+
export interface WorkflowCompletedEvent extends BaseWorkflowEvent {
|
|
65
|
+
readonly type: "workflow:completed";
|
|
66
|
+
readonly status: WorkflowStatus;
|
|
67
|
+
readonly durationMs: number;
|
|
68
|
+
}
|
|
69
|
+
export interface WorkflowFailedEvent extends BaseWorkflowEvent {
|
|
70
|
+
readonly type: "workflow:failed";
|
|
71
|
+
readonly errorCode: string;
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}
|
|
74
|
+
export type WorkflowEvent = WorkflowStartedEvent | ConventionsDetectedEvent | ContextSelectedEvent | ModelCallStartedEvent | ModelCallCompletedEvent | PatchValidatedEvent | PatchAppliedEvent | VerificationResultEvent | WorkflowCompletedEvent | WorkflowFailedEvent;
|
|
75
|
+
export interface WorkflowEventSink {
|
|
76
|
+
readonly emit: (event: WorkflowEvent) => void;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// The WorkflowEvent discriminated union and its BaseWorkflowEvent envelope (ADR-0008 D4). The
|
|
2
|
+
// envelope reuses the harness BaseEvent field shape ({ schemaVersion, runId, fingerprint, seq,
|
|
3
|
+
// ts }) by structural convention — NOT a TypeScript import — so the #10 audit ledger and #13 UI
|
|
4
|
+
// can narrow workflow events with the same envelope logic they apply to HarnessEvent. This union
|
|
5
|
+
// is SEPARATE from HarnessEvent because the workflow does not pass through the harness state
|
|
6
|
+
// machine. No runtime logic lives here. Every SENSITIVE field is redacted before emit.
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { generateUnitTests } from "./workflow.js";
|
|
2
|
+
export { assembleReport, renderMarkdownReport, type ReportParts } from "./report.js";
|
|
3
|
+
export { UNIT_TEST_WORKFLOW_DESCRIPTOR, type WorkflowDescriptor, type WorkflowInputSpec, } from "./descriptor.js";
|
|
4
|
+
export { detectConventions, isTestPath } from "./conventions.js";
|
|
5
|
+
export { DEFAULT_WORKFLOW_LIMITS, type AddedTestFile, type FileNamingStyle, type TestConventions, type UnitTestTarget, type UnitTestWorkflowDeps, type UnitTestWorkflowInput, type UnitTestWorkflowReport, type WorkflowLimits, type WorkflowStatus, } from "./types.js";
|
|
6
|
+
export type { ConventionsDetectedEvent, ContextSelectedEvent, ModelCallCompletedEvent, ModelCallStartedEvent, PatchAppliedEvent, PatchValidatedEvent, VerificationResultEvent, WorkflowCompletedEvent, WorkflowEvent, WorkflowEventSink, WorkflowFailedEvent, WorkflowStartedEvent, } from "./events.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Public barrel for the unit-test generation workflow (ADR-0008 D1). Re-exports the single entry
|
|
2
|
+
// (generateUnitTests), the static UI descriptor, the Markdown renderer, the WorkflowEvent family,
|
|
3
|
+
// and all public types. Internal pipeline modules (internal, model-loop, verify-stage, stages,
|
|
4
|
+
// emit, parse, context, prompt) are NOT re-exported — they are implementation detail. Explicit
|
|
5
|
+
// named re-exports, `type` keyword for type-only, double quotes, `.js`.
|
|
6
|
+
export { generateUnitTests } from "./workflow.js";
|
|
7
|
+
export { assembleReport, renderMarkdownReport } from "./report.js";
|
|
8
|
+
export { UNIT_TEST_WORKFLOW_DESCRIPTOR, } from "./descriptor.js";
|
|
9
|
+
export { detectConventions, isTestPath } from "./conventions.js";
|
|
10
|
+
export { DEFAULT_WORKFLOW_LIMITS, } from "./types.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PatchValidation } from "../../tools/index.js";
|
|
2
|
+
import { type EventEmitter } from "./emit.js";
|
|
3
|
+
import { type UnitTestWorkflowDeps, type UnitTestWorkflowInput, type WorkflowLimits } from "./types.js";
|
|
4
|
+
import type { WorkflowEventSink } from "./events.js";
|
|
5
|
+
export declare const NO_OP_SINK: WorkflowEventSink;
|
|
6
|
+
export interface WorkflowProgress {
|
|
7
|
+
modelCallCount: number;
|
|
8
|
+
patchRetryCount: number;
|
|
9
|
+
}
|
|
10
|
+
export interface RunState {
|
|
11
|
+
readonly input: UnitTestWorkflowInput;
|
|
12
|
+
readonly deps: UnitTestWorkflowDeps;
|
|
13
|
+
readonly limits: WorkflowLimits;
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
readonly now: () => number;
|
|
16
|
+
readonly emitter: EventEmitter;
|
|
17
|
+
readonly startedAt: number;
|
|
18
|
+
readonly progress: WorkflowProgress;
|
|
19
|
+
}
|
|
20
|
+
export interface AcceptedPatch {
|
|
21
|
+
readonly diff: string;
|
|
22
|
+
readonly validation: PatchValidation;
|
|
23
|
+
readonly coveredBehavior: string | undefined;
|
|
24
|
+
readonly knownGaps: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
export interface ModelLoopResult {
|
|
27
|
+
readonly accepted: AcceptedPatch | undefined;
|
|
28
|
+
readonly modelCallCount: number;
|
|
29
|
+
readonly patchRetryCount: number;
|
|
30
|
+
readonly lastRejectionCode: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
export declare const EMPTY_LOOP: ModelLoopResult;
|
|
33
|
+
export declare function resolveLimits(input: UnitTestWorkflowInput): WorkflowLimits;
|
|
34
|
+
export declare function buildRunState(input: UnitTestWorkflowInput, deps: UnitTestWorkflowDeps, fingerprint: string): RunState;
|
|
35
|
+
export declare function nextActionsFor(applied: boolean, files: readonly string[]): readonly string[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Shared internal types and small pure helpers used across the workflow pipeline stages (the
|
|
2
|
+
// model loop, the verify stage, and the report stages). Kept private to the module — none of these
|
|
3
|
+
// are re-exported from index.ts. Splitting them out keeps each pipeline file under the LOC limit
|
|
4
|
+
// while leaving a single source of truth for the resolved RunState and the loop result shape.
|
|
5
|
+
import { createEventEmitter } from "./emit.js";
|
|
6
|
+
import { DEFAULT_WORKFLOW_LIMITS, } from "./types.js";
|
|
7
|
+
// A no-op sink used when the caller injects none. emit is synchronous (ADR-0004 EventSink contract).
|
|
8
|
+
export const NO_OP_SINK = { emit: () => undefined };
|
|
9
|
+
// The zero-progress loop used to assemble a cancelled/failed report before the model loop ran.
|
|
10
|
+
export const EMPTY_LOOP = {
|
|
11
|
+
accepted: undefined,
|
|
12
|
+
modelCallCount: 0,
|
|
13
|
+
patchRetryCount: 0,
|
|
14
|
+
lastRejectionCode: undefined,
|
|
15
|
+
};
|
|
16
|
+
export function resolveLimits(input) {
|
|
17
|
+
return { ...DEFAULT_WORKFLOW_LIMITS, ...input.limits };
|
|
18
|
+
}
|
|
19
|
+
export function buildRunState(input, deps, fingerprint) {
|
|
20
|
+
const now = deps.now ?? Date.now;
|
|
21
|
+
const idSource = deps.idSource ?? (() => crypto.randomUUID());
|
|
22
|
+
return {
|
|
23
|
+
input,
|
|
24
|
+
deps,
|
|
25
|
+
limits: resolveLimits(input),
|
|
26
|
+
signal: deps.signal ?? new AbortController().signal,
|
|
27
|
+
now,
|
|
28
|
+
emitter: createEventEmitter(deps.sink ?? NO_OP_SINK, idSource(), fingerprint, now),
|
|
29
|
+
startedAt: now(),
|
|
30
|
+
progress: { modelCallCount: 0, patchRetryCount: 0 },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// UI-renderable next actions for the report. Pure.
|
|
34
|
+
export function nextActionsFor(applied, files) {
|
|
35
|
+
const first = files[0] ?? "the generated test file";
|
|
36
|
+
if (applied) {
|
|
37
|
+
return [`Review the generated tests in ${first}`, "Run `keiko verify` to confirm they pass"];
|
|
38
|
+
}
|
|
39
|
+
return [
|
|
40
|
+
`Review the proposed tests for ${first}`,
|
|
41
|
+
"Re-run with --apply to write the tests and verify",
|
|
42
|
+
];
|
|
43
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ContextPack, WorkspaceInfo } from "../../workspace/index.js";
|
|
2
|
+
import type { ModelLoopResult, RunState } from "./internal.js";
|
|
3
|
+
import type { TestConventions } from "./types.js";
|
|
4
|
+
export declare function runModelLoop(state: RunState, workspace: WorkspaceInfo, conventions: TestConventions, pack: ContextPack): Promise<ModelLoopResult>;
|