devcontour-harness 0.0.0-stage → 0.1.0-alpha.6
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 +21 -0
- package/README.md +183 -2
- package/docs/architecture.md +473 -0
- package/docs/compatibility-versions.md +56 -0
- package/docs/compatibility.md +192 -0
- package/docs/connectors.md +323 -0
- package/docs/contracts.md +603 -0
- package/docs/integrations/hindsight.md +148 -0
- package/docs/quickstart.md +182 -0
- package/docs/release-notes/0.1.0-alpha.6.md +238 -0
- package/docs/review-probes.md +120 -0
- package/docs/review-protocol.md +251 -0
- package/docs/toolchains.md +167 -0
- package/docs/turbo-starter.md +269 -0
- package/docs/upgrade.md +202 -0
- package/examples/README.md +27 -0
- package/examples/external-connector/README.md +19 -0
- package/examples/external-connector/connector.mjs +55 -0
- package/examples/files-only/README.md +28 -0
- package/examples/files-only/context/norms/rules.md +4 -0
- package/examples/files-only/graph.json +23 -0
- package/examples/files-only/policy.json +30 -0
- package/examples/one-vendor/README.md +19 -0
- package/examples/one-vendor/policy.json +27 -0
- package/examples/single-task/README.md +18 -0
- package/examples/single-task/graph.json +27 -0
- package/examples/single-task/policy-same-vendor.json +55 -0
- package/examples/single-task/policy.json +52 -0
- package/examples/single-task/src/.gitkeep +0 -0
- package/examples/single-task/test/run.js +19 -0
- package/examples/toolchains/README.md +32 -0
- package/examples/toolchains/go/bad/label/label.go +9 -0
- package/examples/toolchains/go/good/label/label.go +9 -0
- package/examples/toolchains/go/policy.json +79 -0
- package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/go/repo/_gitignore +1 -0
- package/examples/toolchains/go/repo/go.mod +5 -0
- package/examples/toolchains/go/repo/go.sum +2 -0
- package/examples/toolchains/go/repo/label/label.go +9 -0
- package/examples/toolchains/go/repo/label/label_test.go +27 -0
- package/examples/toolchains/go/repo/label/version.go +9 -0
- package/examples/toolchains/go/task.json +25 -0
- package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/policy.json +126 -0
- package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
- package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-go/task.json +25 -0
- package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/policy.json +121 -0
- package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
- package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
- package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
- package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
- package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-python/task.json +25 -0
- package/examples/toolchains/npm/bad/src/label.js +4 -0
- package/examples/toolchains/npm/good/src/label.js +4 -0
- package/examples/toolchains/npm/policy.json +82 -0
- package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/npm/repo/_gitignore +4 -0
- package/examples/toolchains/npm/repo/package-lock.json +22 -0
- package/examples/toolchains/npm/repo/package.json +13 -0
- package/examples/toolchains/npm/repo/src/label.js +4 -0
- package/examples/toolchains/npm/repo/test/label.test.js +13 -0
- package/examples/toolchains/npm/task.json +25 -0
- package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/policy.json +85 -0
- package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/pnpm/repo/_gitignore +4 -0
- package/examples/toolchains/pnpm/repo/package.json +10 -0
- package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
- package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
- package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/pnpm/task.json +25 -0
- package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/policy.json +80 -0
- package/examples/toolchains/python/repo/.python-version +1 -0
- package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/python/repo/_gitignore +5 -0
- package/examples/toolchains/python/repo/pyproject.toml +19 -0
- package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/repo/tests/test_label.py +13 -0
- package/examples/toolchains/python/repo/uv.lock +108 -0
- package/examples/toolchains/python/task.json +25 -0
- package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/policy.json +110 -0
- package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/turbo/repo/_gitignore +4 -0
- package/examples/toolchains/turbo/repo/package.json +13 -0
- package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
- package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
- package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/turbo/repo/turbo.json +7 -0
- package/examples/toolchains/turbo/task.json +25 -0
- package/examples/turbo-starter/README.md +16 -0
- package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
- package/examples/turbo-starter/changes/issued-at.patch +130 -0
- package/examples/turbo-starter/cleanup.mjs +58 -0
- package/examples/turbo-starter/graph.json +32 -0
- package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
- package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
- package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
- package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
- package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
- package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
- package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
- package/examples/turbo-starter/harness/env/backend.env.template +7 -0
- package/examples/turbo-starter/harness/env/compose.env.template +6 -0
- package/examples/turbo-starter/policy.json +109 -0
- package/examples/turbo-starter/policy.lifecycle.json +114 -0
- package/examples/turbo-starter/setup.mjs +352 -0
- package/examples/two-vendors/policy.json +30 -0
- package/lib/agents/cli-adapter.d.ts +48 -0
- package/lib/agents/cli-adapter.js +386 -0
- package/lib/agents/inspect.d.ts +6 -0
- package/lib/agents/inspect.js +46 -0
- package/lib/agents/probe-server.d.ts +2 -0
- package/lib/agents/probe-server.js +13 -0
- package/lib/agents/review-probe.d.ts +295 -0
- package/lib/agents/review-probe.js +872 -0
- package/lib/agents/runtime-events.d.ts +11 -0
- package/lib/agents/runtime-events.js +21 -0
- package/lib/agents/schemas.d.ts +217 -0
- package/lib/agents/schemas.js +124 -0
- package/lib/agents/usage.d.ts +8 -0
- package/lib/agents/usage.js +83 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.js +491 -0
- package/lib/connectors/files.d.ts +108 -0
- package/lib/connectors/files.js +133 -0
- package/lib/contracts/checks.d.ts +307 -0
- package/lib/contracts/checks.js +181 -0
- package/lib/contracts/cli.d.ts +3895 -0
- package/lib/contracts/cli.js +664 -0
- package/lib/contracts/context.d.ts +135 -0
- package/lib/contracts/context.js +129 -0
- package/lib/contracts/digest.d.ts +9 -0
- package/lib/contracts/digest.js +22 -0
- package/lib/contracts/errors.d.ts +81 -0
- package/lib/contracts/errors.js +70 -0
- package/lib/contracts/events.d.ts +827 -0
- package/lib/contracts/events.js +258 -0
- package/lib/contracts/execution.d.ts +3216 -0
- package/lib/contracts/execution.js +872 -0
- package/lib/contracts/failure.d.ts +67 -0
- package/lib/contracts/failure.js +127 -0
- package/lib/contracts/index.d.ts +18 -0
- package/lib/contracts/index.js +18 -0
- package/lib/contracts/policy.d.ts +1080 -0
- package/lib/contracts/policy.js +544 -0
- package/lib/contracts/ports.d.ts +417 -0
- package/lib/contracts/ports.js +1 -0
- package/lib/contracts/primitives.d.ts +63 -0
- package/lib/contracts/primitives.js +73 -0
- package/lib/contracts/profiles.d.ts +336 -0
- package/lib/contracts/profiles.js +109 -0
- package/lib/contracts/published.d.ts +3237 -0
- package/lib/contracts/published.js +34 -0
- package/lib/contracts/result.d.ts +1280 -0
- package/lib/contracts/result.js +311 -0
- package/lib/contracts/review.d.ts +441 -0
- package/lib/contracts/review.js +477 -0
- package/lib/contracts/toolchain.d.ts +96 -0
- package/lib/contracts/toolchain.js +89 -0
- package/lib/contracts/version.d.ts +17 -0
- package/lib/contracts/version.js +17 -0
- package/lib/contracts/work.d.ts +173 -0
- package/lib/contracts/work.js +178 -0
- package/lib/control/base-move.d.ts +44 -0
- package/lib/control/base-move.js +90 -0
- package/lib/control/doctor.d.ts +50 -0
- package/lib/control/doctor.js +113 -0
- package/lib/control/harness.d.ts +1125 -0
- package/lib/control/harness.js +741 -0
- package/lib/control/provenance.d.ts +17 -0
- package/lib/control/provenance.js +25 -0
- package/lib/control/recovery.d.ts +237 -0
- package/lib/control/recovery.js +236 -0
- package/lib/control/review.d.ts +62 -0
- package/lib/control/review.js +178 -0
- package/lib/control/workflow.d.ts +247 -0
- package/lib/control/workflow.js +259 -0
- package/lib/engine/budget.d.ts +345 -0
- package/lib/engine/budget.js +278 -0
- package/lib/engine/classify.d.ts +8 -0
- package/lib/engine/classify.js +32 -0
- package/lib/engine/engine.d.ts +1527 -0
- package/lib/engine/engine.js +2259 -0
- package/lib/engine/failure.d.ts +1 -0
- package/lib/engine/failure.js +3 -0
- package/lib/engine/joint-runner.d.ts +257 -0
- package/lib/engine/joint-runner.js +254 -0
- package/lib/engine/measured.d.ts +15 -0
- package/lib/engine/measured.js +82 -0
- package/lib/engine/prompt.d.ts +66 -0
- package/lib/engine/prompt.js +131 -0
- package/lib/engine/property-recovery.d.ts +50 -0
- package/lib/engine/property-recovery.js +171 -0
- package/lib/engine/repair.d.ts +33 -0
- package/lib/engine/repair.js +82 -0
- package/lib/engine/result.d.ts +9 -0
- package/lib/engine/result.js +218 -0
- package/lib/engine/reuse.d.ts +80 -0
- package/lib/engine/reuse.js +102 -0
- package/lib/engine/runner.d.ts +360 -0
- package/lib/engine/runner.js +1836 -0
- package/lib/engine/standalone.d.ts +6 -0
- package/lib/engine/standalone.js +48 -0
- package/lib/engine/usage.d.ts +87 -0
- package/lib/engine/usage.js +165 -0
- package/lib/environment/isolation.d.ts +110 -0
- package/lib/environment/isolation.js +238 -0
- package/lib/environment/lifecycle.d.ts +40 -0
- package/lib/environment/lifecycle.js +197 -0
- package/lib/environment/live-calls.d.ts +14 -0
- package/lib/environment/live-calls.js +73 -0
- package/lib/environment/os-tools.d.ts +16 -0
- package/lib/environment/os-tools.js +35 -0
- package/lib/environment/process.d.ts +32 -0
- package/lib/environment/process.js +369 -0
- package/lib/environment/redaction.d.ts +22 -0
- package/lib/environment/redaction.js +102 -0
- package/lib/environment/resources.d.ts +31 -0
- package/lib/environment/resources.js +120 -0
- package/lib/index.d.ts +65 -0
- package/lib/index.js +67 -0
- package/lib/integrations/connector/commands.d.ts +358 -0
- package/lib/integrations/connector/commands.js +428 -0
- package/lib/integrations/connector/config.d.ts +215 -0
- package/lib/integrations/connector/config.js +214 -0
- package/lib/integrations/connector/delivery.d.ts +107 -0
- package/lib/integrations/connector/delivery.js +591 -0
- package/lib/integrations/connector/fake.d.ts +291 -0
- package/lib/integrations/connector/fake.js +786 -0
- package/lib/integrations/connector/history.d.ts +124 -0
- package/lib/integrations/connector/history.js +497 -0
- package/lib/integrations/connector/index.d.ts +16 -0
- package/lib/integrations/connector/index.js +16 -0
- package/lib/integrations/connector/redact.d.ts +19 -0
- package/lib/integrations/connector/redact.js +91 -0
- package/lib/integrations/connector/registry.d.ts +15 -0
- package/lib/integrations/connector/registry.js +43 -0
- package/lib/integrations/connector/snapshot.d.ts +131 -0
- package/lib/integrations/connector/snapshot.js +422 -0
- package/lib/integrations/connector/source.d.ts +37 -0
- package/lib/integrations/connector/source.js +73 -0
- package/lib/integrations/connector/steps.d.ts +71 -0
- package/lib/integrations/connector/steps.js +188 -0
- package/lib/integrations/connector/store.d.ts +140 -0
- package/lib/integrations/connector/store.js +277 -0
- package/lib/integrations/connector/summary.d.ts +38 -0
- package/lib/integrations/connector/summary.js +59 -0
- package/lib/integrations/connector/testing-worker.d.ts +1 -0
- package/lib/integrations/connector/testing-worker.js +81 -0
- package/lib/integrations/connector/testing.d.ts +205 -0
- package/lib/integrations/connector/testing.js +1615 -0
- package/lib/integrations/connector/transport.d.ts +240 -0
- package/lib/integrations/connector/transport.js +28 -0
- package/lib/integrations/memory/context.d.ts +120 -0
- package/lib/integrations/memory/context.js +239 -0
- package/lib/integrations/memory/index.d.ts +8 -0
- package/lib/integrations/memory/index.js +8 -0
- package/lib/integrations/memory/provider.d.ts +79 -0
- package/lib/integrations/memory/provider.js +22 -0
- package/lib/integrations/memory/sink.d.ts +56 -0
- package/lib/integrations/memory/sink.js +116 -0
- package/lib/integrations/memory/testing.d.ts +44 -0
- package/lib/integrations/memory/testing.js +61 -0
- package/lib/integrations/relay-v1/index.d.ts +122 -0
- package/lib/integrations/relay-v1/index.js +860 -0
- package/lib/integrations/relay-v2/index.d.ts +145 -0
- package/lib/integrations/relay-v2/index.js +752 -0
- package/lib/integrations/relay-v2/process.d.ts +32 -0
- package/lib/integrations/relay-v2/process.js +112 -0
- package/lib/integrations/relay-v2/protocol.d.ts +172 -0
- package/lib/integrations/relay-v2/protocol.js +142 -0
- package/lib/package.d.ts +2 -0
- package/lib/package.js +3 -0
- package/lib/profiles/resolve.d.ts +190 -0
- package/lib/profiles/resolve.js +273 -0
- package/lib/storage/document.d.ts +1234 -0
- package/lib/storage/document.js +80 -0
- package/lib/storage/sqlite.d.ts +35 -0
- package/lib/storage/sqlite.js +260 -0
- package/lib/testing/index.d.ts +5 -0
- package/lib/testing/index.js +5 -0
- package/lib/testing/store-contract.d.ts +8 -0
- package/lib/testing/store-contract.js +167 -0
- package/lib/toolchains/index.d.ts +9 -0
- package/lib/toolchains/index.js +9 -0
- package/lib/toolchains/inspect.d.ts +105 -0
- package/lib/toolchains/inspect.js +831 -0
- package/lib/toolchains/manifests.d.ts +67 -0
- package/lib/toolchains/manifests.js +238 -0
- package/lib/toolchains/probe.d.ts +28 -0
- package/lib/toolchains/probe.js +54 -0
- package/lib/toolchains/recipes.d.ts +33 -0
- package/lib/toolchains/recipes.js +51 -0
- package/lib/validate.d.ts +36 -0
- package/lib/validate.js +175 -0
- package/lib/verification/acceptance.d.ts +284 -0
- package/lib/verification/acceptance.js +670 -0
- package/lib/verification/checks.d.ts +72 -0
- package/lib/verification/checks.js +190 -0
- package/lib/verification/confirm.d.ts +125 -0
- package/lib/verification/confirm.js +411 -0
- package/lib/verification/corpus.d.ts +1303 -0
- package/lib/verification/corpus.js +744 -0
- package/lib/verification/dependencies.d.ts +66 -0
- package/lib/verification/dependencies.js +144 -0
- package/lib/verification/gates.d.ts +160 -0
- package/lib/verification/gates.js +600 -0
- package/lib/verification/joint.d.ts +63 -0
- package/lib/verification/joint.js +121 -0
- package/lib/verification/proof.d.ts +54 -0
- package/lib/verification/proof.js +96 -0
- package/lib/verification/property.d.ts +86 -0
- package/lib/verification/property.js +214 -0
- package/lib/verification/requirements.d.ts +25 -0
- package/lib/verification/requirements.js +69 -0
- package/lib/verification/self-check.d.ts +29 -0
- package/lib/verification/self-check.js +99 -0
- package/lib/verification/spike.d.ts +79 -0
- package/lib/verification/spike.js +124 -0
- package/package.json +100 -4
- package/profiles/expo-mobile.json +15 -0
- package/profiles/go-api.json +15 -0
- package/profiles/go-gotestsum.json +21 -0
- package/profiles/mobile-maestro.json +29 -0
- package/profiles/nest-api.json +26 -0
- package/profiles/next-product.json +72 -0
- package/profiles/node-checks.json +77 -0
- package/profiles/npm-ci.json +22 -0
- package/profiles/pnpm-frozen.json +24 -0
- package/profiles/python-api.json +32 -0
- package/profiles/python-uv.json +26 -0
- package/profiles/react-native.json +50 -0
- package/profiles/react-vite-admin.json +71 -0
- package/schemas/context-snapshot.schema.json +231 -0
- package/schemas/contract-document.schema.json +385 -0
- package/schemas/execution-document.schema.json +3695 -0
- package/schemas/execution-policy.schema.json +2196 -0
- package/schemas/joint-verification.schema.json +617 -0
- package/schemas/result-envelope.schema.json +1652 -0
- package/schemas/review-record.schema.json +177 -0
- package/schemas/run-event.schema.json +2458 -0
- package/schemas/run-result.schema.json +1570 -0
- package/schemas/stack-profile.schema.json +535 -0
- package/schemas/work-graph.schema.json +381 -0
- package/schemas/work-order.schema.json +256 -0
- package/skills/harness/SKILL.md +64 -0
- package/templates/AGENTS.md +13 -0
- package/templates/controller-mode/AGENTS.controller.md +58 -0
- package/templates/controller-mode/README.md +44 -0
- package/templates/graph.json +22 -0
- package/templates/policy.json +28 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { HarnessError, relativePathSchema, sha256 } from "../contracts/index.js";
|
|
3
|
+
/** Требование заканчивается на следующем заголовке уровня 1–2; примеры в fenced-блоках не считаются. */
|
|
4
|
+
export function parseRequirements(markdown) {
|
|
5
|
+
if (Buffer.byteLength(markdown) > 1_000_000)
|
|
6
|
+
throw new HarnessError('INVALID_INPUT', 'Источник требований превышает 1 MB');
|
|
7
|
+
const found = [];
|
|
8
|
+
let current;
|
|
9
|
+
let fence;
|
|
10
|
+
const finish = () => {
|
|
11
|
+
if (!current)
|
|
12
|
+
return;
|
|
13
|
+
const text = current.lines.join('\n').trim();
|
|
14
|
+
if (text.length > 12000)
|
|
15
|
+
throw new HarnessError('INVALID_INPUT', 'Разбейте требование: ' + current.id);
|
|
16
|
+
if (found.some((r) => r.id === current.id))
|
|
17
|
+
throw new HarnessError('INVALID_INPUT', 'Повтор ID: ' + current.id);
|
|
18
|
+
found.push({ id: current.id, text, digest: sha256(text) });
|
|
19
|
+
current = undefined;
|
|
20
|
+
};
|
|
21
|
+
for (const line of markdown.replaceAll('\r\n', '\n').split('\n')) {
|
|
22
|
+
const delimiter = line.match(/^\s{0,3}(`{3,}|~{3,})/)?.[1];
|
|
23
|
+
if (delimiter) {
|
|
24
|
+
if (!fence)
|
|
25
|
+
fence = delimiter;
|
|
26
|
+
else if (delimiter[0] === fence[0] && delimiter.length >= fence.length)
|
|
27
|
+
fence = undefined;
|
|
28
|
+
current?.lines.push(line);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (!fence && /^#{1,2}\s/.test(line)) {
|
|
32
|
+
finish();
|
|
33
|
+
const id = line.match(/^## (REQ-[A-Za-z0-9_-]{1,64})(?:\s|:|$)/)?.[1];
|
|
34
|
+
if (id)
|
|
35
|
+
current = { id, lines: [] };
|
|
36
|
+
}
|
|
37
|
+
current?.lines.push(line);
|
|
38
|
+
}
|
|
39
|
+
finish();
|
|
40
|
+
return found;
|
|
41
|
+
}
|
|
42
|
+
/** Требования источника на коммите: файл обязан быть обычным Git-файлом. */
|
|
43
|
+
export function requirementSnapshot(cwd, source, ref = 'HEAD') {
|
|
44
|
+
relativePathSchema.parse(source);
|
|
45
|
+
if (!/^(HEAD|[a-f0-9]{40,64})$/.test(ref))
|
|
46
|
+
throw new HarnessError('INVALID_INPUT', 'Нужен HEAD или точный SHA');
|
|
47
|
+
const git = (...args) => execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 1_100_000 }).trimEnd();
|
|
48
|
+
const sha = git('rev-parse', '--verify', ref + '^{commit}');
|
|
49
|
+
if (!/^100(644|755) blob /.test(git('ls-tree', sha, '--', source)))
|
|
50
|
+
throw new HarnessError('NOT_READY', 'Источник требований должен быть обычным Git-файлом: ' + source);
|
|
51
|
+
return { source, sha, requirements: parseRequirements(git('show', `${sha}:${source}`)) };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Совпадают ли закреплённые требования поручения с источником на `ref`.
|
|
55
|
+
* Изменённое или удалённое требование — отказ: исполнение по устаревшей
|
|
56
|
+
* постановке не продолжается.
|
|
57
|
+
*/
|
|
58
|
+
export function assertRequirements(order, cwd, ref = 'HEAD') {
|
|
59
|
+
const snapshots = new Map();
|
|
60
|
+
const stale = order.requirements.filter((link) => {
|
|
61
|
+
if (!snapshots.has(link.source))
|
|
62
|
+
snapshots.set(link.source, requirementSnapshot(cwd, link.source, ref));
|
|
63
|
+
return (snapshots.get(link.source).requirements.find((r) => r.id === link.id)?.digest !== link.digest);
|
|
64
|
+
});
|
|
65
|
+
if (stale.length)
|
|
66
|
+
throw new HarnessError('APPROVAL_STALE', 'Требования изменились или удалены: ' + stale.map((r) => r.id).join(', '));
|
|
67
|
+
}
|
|
68
|
+
/** Псевдо-gate актуальности требований: обязателен в обеих фазах, если у поручения есть требования. */
|
|
69
|
+
export const REQUIREMENT_GATE = 'requirement-source';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ContractDocument, GatePolicy, WorkOrder } from '../contracts/index.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Самопроверка исполнителя: тот же закреплённый checker, полный корпус
|
|
4
|
+
* закреплённой версии, генератор с воспроизводимым seed и селектор свойств
|
|
5
|
+
* поручения. Проверяется рабочий, незакоммиченный код — результат
|
|
6
|
+
* диагностический и не заменяет evidence controller на commit SHA: gates
|
|
7
|
+
* исполняются всегда, с самопроверкой или без неё.
|
|
8
|
+
*/
|
|
9
|
+
export interface SelfCheckPlan {
|
|
10
|
+
command: string[];
|
|
11
|
+
corpus?: string;
|
|
12
|
+
cases: number;
|
|
13
|
+
seed: number;
|
|
14
|
+
properties: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function writeSelfCheck(input: {
|
|
17
|
+
order: Pick<WorkOrder, 'id' | 'properties'>;
|
|
18
|
+
contracts: ContractDocument[];
|
|
19
|
+
gates: GatePolicy[];
|
|
20
|
+
dir: string;
|
|
21
|
+
seed: number;
|
|
22
|
+
/** Канонический файл закреплённой версии корпуса и число её случаев. */
|
|
23
|
+
corpus?: {
|
|
24
|
+
content: string;
|
|
25
|
+
cases: number;
|
|
26
|
+
};
|
|
27
|
+
}): Promise<SelfCheckPlan | undefined>;
|
|
28
|
+
/** Строка запроса исполнителю о самопроверке. */
|
|
29
|
+
export declare function selfCheckNote(plan: SelfCheckPlan): string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { obligationOf } from "./checks.js";
|
|
4
|
+
export async function writeSelfCheck(input) {
|
|
5
|
+
const gates = new Map();
|
|
6
|
+
for (const id of input.order.properties ?? []) {
|
|
7
|
+
const found = obligationOf(input.contracts, id);
|
|
8
|
+
const gate = found && input.gates.find((g) => g.id === found.gate && g.property);
|
|
9
|
+
if (!gate)
|
|
10
|
+
continue;
|
|
11
|
+
const entry = gates.get(gate.id) ?? {
|
|
12
|
+
command: gate.command,
|
|
13
|
+
...(gate.cwd ? { cwd: gate.cwd } : {}),
|
|
14
|
+
properties: [],
|
|
15
|
+
};
|
|
16
|
+
entry.properties.push(id);
|
|
17
|
+
gates.set(gate.id, entry);
|
|
18
|
+
}
|
|
19
|
+
if (!gates.size)
|
|
20
|
+
return undefined;
|
|
21
|
+
await mkdir(input.dir, { recursive: true });
|
|
22
|
+
const corpus = input.corpus ? join(input.dir, 'corpus.json') : undefined;
|
|
23
|
+
if (input.corpus)
|
|
24
|
+
await writeFile(corpus, input.corpus.content);
|
|
25
|
+
const plan = {
|
|
26
|
+
work: input.order.id,
|
|
27
|
+
seed: input.seed,
|
|
28
|
+
corpus: corpus ?? null,
|
|
29
|
+
gates: [...gates].map(([id, g]) => ({ id, ...g })),
|
|
30
|
+
};
|
|
31
|
+
const script = join(input.dir, 'selfcheck.mjs');
|
|
32
|
+
await writeFile(script, selfCheckSource(plan));
|
|
33
|
+
return {
|
|
34
|
+
command: [process.execPath, script],
|
|
35
|
+
...(corpus ? { corpus } : {}),
|
|
36
|
+
cases: input.corpus?.cases ?? 0,
|
|
37
|
+
seed: input.seed,
|
|
38
|
+
properties: [...gates.values()].flatMap((g) => g.properties),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Строка запроса исполнителю о самопроверке. */
|
|
42
|
+
export function selfCheckNote(plan) {
|
|
43
|
+
return `Self-check: run \`${plan.command.join(' ')}\` from the worktree root before returning. It runs the pinned checker on your working tree with ${plan.cases} mandatory corpus cases, the generator with seed ${plan.seed} and your properties (${plan.properties.join(', ')}). A non-zero exit names the property, the exact input and the reason. It is diagnostic: the controller still runs the gates on your commit.`;
|
|
44
|
+
}
|
|
45
|
+
function selfCheckSource(plan) {
|
|
46
|
+
return `// Самопроверка исполнителя: закреплённый checker, полный корпус, seed и
|
|
47
|
+
// свойства поручения. Диагностика рабочего кода: controller всё равно
|
|
48
|
+
// исполняет gates на commit SHA. Ненулевой код — свойство, точный вход и причина.
|
|
49
|
+
import { spawnSync } from 'node:child_process';
|
|
50
|
+
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
51
|
+
import { tmpdir } from 'node:os';
|
|
52
|
+
import { join } from 'node:path';
|
|
53
|
+
const plan = ${JSON.stringify(plan, null, 2)};
|
|
54
|
+
const both = (name, value) => ({ ['DEVCONTOUR_' + name]: value, ['HARNESS_' + name]: value });
|
|
55
|
+
let failed = 0;
|
|
56
|
+
for (const gate of plan.gates) {
|
|
57
|
+
const scratch = mkdtempSync(join(tmpdir(), 'harness-self-'));
|
|
58
|
+
const report = join(scratch, 'property.json');
|
|
59
|
+
const result = spawnSync(gate.command[0], gate.command.slice(1), {
|
|
60
|
+
cwd: gate.cwd ? join(process.cwd(), gate.cwd) : process.cwd(),
|
|
61
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
62
|
+
env: {
|
|
63
|
+
...process.env,
|
|
64
|
+
...both('SEED', String(plan.seed)),
|
|
65
|
+
...both('PROPERTIES', gate.properties.join(',')),
|
|
66
|
+
...(plan.corpus ? both('CORPUS', plan.corpus) : {}),
|
|
67
|
+
...both('PROPERTY_REPORT', report),
|
|
68
|
+
...both('REPORT_PATH', join(scratch, 'junit.xml')),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
let parsed;
|
|
72
|
+
try {
|
|
73
|
+
parsed = JSON.parse(readFileSync(report, 'utf8'));
|
|
74
|
+
} catch {}
|
|
75
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
76
|
+
if (!parsed) {
|
|
77
|
+
failed++;
|
|
78
|
+
console.log('FAIL ' + gate.id + ': отчёт свойств не записан (код выхода ' + result.status + ')');
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
for (const p of parsed.properties) {
|
|
82
|
+
if (p.status === 'passed') continue;
|
|
83
|
+
failed++;
|
|
84
|
+
const c = p.counterexample;
|
|
85
|
+
const input = c ? (c.reduced ?? c.original) : p.current;
|
|
86
|
+
const reason = p.error ?? (c ? 'ожидалось ' + JSON.stringify(c.expected) + ', получено ' + JSON.stringify(c.actual) : 'не завершилось');
|
|
87
|
+
console.log('FAIL ' + p.testId + (c && c.case ? ' [случай корпуса ' + c.case + ']' : '') + ': input=' + JSON.stringify(input) + ' — ' + reason);
|
|
88
|
+
}
|
|
89
|
+
for (const f of parsed.corpus?.failed ?? [])
|
|
90
|
+
console.log('CORPUS ' + f.property + ' [' + f.id + ']: ожидалось ' + JSON.stringify(f.expected) + ', получено ' + JSON.stringify(f.actual));
|
|
91
|
+
if (result.status && !parsed.properties.some((p) => p.status !== 'passed')) {
|
|
92
|
+
failed++;
|
|
93
|
+
console.log('FAIL ' + gate.id + ': код выхода ' + result.status);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
console.log(failed ? 'self-check: ' + failed + ' failing (seed ' + plan.seed + ')' : 'self-check: all properties hold (seed ' + plan.seed + '); diagnostic only — the controller runs the gates on your commit');
|
|
97
|
+
process.exit(failed ? 1 : 0);
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type ExecutionPolicy, type ExecutionView, type Spike } from '../contracts/index.ts';
|
|
2
|
+
import type { Engine } from '../engine/engine.ts';
|
|
3
|
+
/** Что нужно эксперименту от controller. */
|
|
4
|
+
export interface SpikeContext {
|
|
5
|
+
engine: Engine;
|
|
6
|
+
policy: ExecutionPolicy;
|
|
7
|
+
stateDir: string;
|
|
8
|
+
repoPath(repo: ExecutionPolicy['repositories'][number]): string;
|
|
9
|
+
/** Закрытое проверке и открытое внутри него. */
|
|
10
|
+
boundary(): {
|
|
11
|
+
hidden: string[];
|
|
12
|
+
readable: string[];
|
|
13
|
+
};
|
|
14
|
+
environment?: NodeJS.ProcessEnv;
|
|
15
|
+
}
|
|
16
|
+
/** Эксперимент репозитория по ID или undefined. */
|
|
17
|
+
export declare function spikeOf(view: ExecutionView, repositoryId: string, id: string): {
|
|
18
|
+
id: string;
|
|
19
|
+
repositoryId: string;
|
|
20
|
+
sha: string;
|
|
21
|
+
command: string[];
|
|
22
|
+
seed: number;
|
|
23
|
+
sizes: number[];
|
|
24
|
+
timeoutMs: number;
|
|
25
|
+
question: string;
|
|
26
|
+
results: {
|
|
27
|
+
size: number;
|
|
28
|
+
ms: number;
|
|
29
|
+
outcome: "error" | "ok" | "timeout";
|
|
30
|
+
exitCode: number;
|
|
31
|
+
}[];
|
|
32
|
+
outcome: "failed" | "feasible" | "inconclusive";
|
|
33
|
+
limits: string;
|
|
34
|
+
environment: {
|
|
35
|
+
platform: string;
|
|
36
|
+
arch: string;
|
|
37
|
+
node: string;
|
|
38
|
+
cpus: number;
|
|
39
|
+
isolation: string;
|
|
40
|
+
};
|
|
41
|
+
at: string;
|
|
42
|
+
digest: string;
|
|
43
|
+
} | undefined;
|
|
44
|
+
/** Эксперименты репозитория. */
|
|
45
|
+
export declare function spikesOf(view: ExecutionView, repositoryId?: string): {
|
|
46
|
+
id: string;
|
|
47
|
+
repositoryId: string;
|
|
48
|
+
sha: string;
|
|
49
|
+
command: string[];
|
|
50
|
+
seed: number;
|
|
51
|
+
sizes: number[];
|
|
52
|
+
timeoutMs: number;
|
|
53
|
+
question: string;
|
|
54
|
+
results: {
|
|
55
|
+
size: number;
|
|
56
|
+
ms: number;
|
|
57
|
+
outcome: "error" | "ok" | "timeout";
|
|
58
|
+
exitCode: number;
|
|
59
|
+
}[];
|
|
60
|
+
outcome: "failed" | "feasible" | "inconclusive";
|
|
61
|
+
limits: string;
|
|
62
|
+
environment: {
|
|
63
|
+
platform: string;
|
|
64
|
+
arch: string;
|
|
65
|
+
node: string;
|
|
66
|
+
cpus: number;
|
|
67
|
+
isolation: string;
|
|
68
|
+
};
|
|
69
|
+
at: string;
|
|
70
|
+
digest: string;
|
|
71
|
+
}[];
|
|
72
|
+
/**
|
|
73
|
+
* Ограниченный эксперимент выполнимости: команда на закреплённом SHA в
|
|
74
|
+
* отдельном worktree, для каждого размера — под той же изоляцией, что gates,
|
|
75
|
+
* с пределом времени. После таймаута большие размеры не запускаются: они
|
|
76
|
+
* ничего не добавят к выводу. Результат с версиями среды и пределами вывода
|
|
77
|
+
* сохраняется под digest; ссылка тяжёлого обязательства закрепляет этот digest.
|
|
78
|
+
*/
|
|
79
|
+
export declare function runSpike(ctx: SpikeContext, raw: unknown): Promise<Spike>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
import { arch, cpus, platform } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { HarnessError, digestOf, spikeInputSchema, spikeSchema, } from "../contracts/index.js";
|
|
6
|
+
import { git } from "../environment/process.js";
|
|
7
|
+
import { executionEnvironment } from "../environment/lifecycle.js";
|
|
8
|
+
import { redactDeep, redactError } from "../environment/redaction.js";
|
|
9
|
+
import { runCheck } from "./gates.js";
|
|
10
|
+
/** Эксперимент репозитория по ID или undefined. */
|
|
11
|
+
export function spikeOf(view, repositoryId, id) {
|
|
12
|
+
return view.local('spikes', repositoryId, id);
|
|
13
|
+
}
|
|
14
|
+
/** Эксперименты репозитория. */
|
|
15
|
+
export function spikesOf(view, repositoryId) {
|
|
16
|
+
return view.locals('spikes', repositoryId).map((x) => x.value);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Ограниченный эксперимент выполнимости: команда на закреплённом SHA в
|
|
20
|
+
* отдельном worktree, для каждого размера — под той же изоляцией, что gates,
|
|
21
|
+
* с пределом времени. После таймаута большие размеры не запускаются: они
|
|
22
|
+
* ничего не добавят к выводу. Результат с версиями среды и пределами вывода
|
|
23
|
+
* сохраняется под digest; ссылка тяжёлого обязательства закрепляет этот digest.
|
|
24
|
+
*/
|
|
25
|
+
export async function runSpike(ctx, raw) {
|
|
26
|
+
const input = spikeInputSchema.parse(raw);
|
|
27
|
+
const repo = input.repositoryId
|
|
28
|
+
? ctx.policy.repositories.find((r) => r.id === input.repositoryId)
|
|
29
|
+
: ctx.policy.repositories[0];
|
|
30
|
+
if (!repo)
|
|
31
|
+
throw new HarnessError('NOT_FOUND', 'Репозиторий не объявлен: ' + input.repositoryId);
|
|
32
|
+
// Окружение и его маска — до любой работы: недостающий секрет — отказ без
|
|
33
|
+
// worktree и записи, а известные значения не попадают в сохраняемую запись.
|
|
34
|
+
const environmentOf = (size) => executionEnvironment([ctx.policy.environment, repo.environment], { DEVCONTOUR_SPIKE_SIZE: String(size), DEVCONTOUR_SEED: String(input.seed) }, ctx.environment ?? process.env);
|
|
35
|
+
let redact;
|
|
36
|
+
try {
|
|
37
|
+
redact = environmentOf(input.sizes[0]).redact;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new HarnessError('RUNTIME_UNAVAILABLE', 'Окружение эксперимента: ' + (error instanceof Error ? error.message : String(error)));
|
|
41
|
+
}
|
|
42
|
+
const path = ctx.repoPath(repo);
|
|
43
|
+
const sha = input.sha ?? (await git(path, 'rev-parse', 'HEAD'));
|
|
44
|
+
await git(path, 'cat-file', '-e', `${sha}^{commit}`).catch(() => {
|
|
45
|
+
throw new HarnessError('NOT_FOUND', `Commit ${sha} недоступен в ${repo.id}`);
|
|
46
|
+
});
|
|
47
|
+
const id = 'SP-' + randomUUID();
|
|
48
|
+
const root = join(ctx.stateDir, 'spikes');
|
|
49
|
+
const dir = join(root, id);
|
|
50
|
+
await mkdir(root, { recursive: true });
|
|
51
|
+
await git(path, 'worktree', 'add', '--detach', dir, sha);
|
|
52
|
+
const results = [];
|
|
53
|
+
try {
|
|
54
|
+
const boundary = ctx.boundary();
|
|
55
|
+
for (const size of input.sizes) {
|
|
56
|
+
const environment = environmentOf(size);
|
|
57
|
+
const started = Date.now();
|
|
58
|
+
const result = await runCheck({ config: ctx.policy }, {
|
|
59
|
+
argv: input.command,
|
|
60
|
+
cwd: dir,
|
|
61
|
+
env: environment.env,
|
|
62
|
+
redact: environment.redact,
|
|
63
|
+
timeoutMs: input.timeoutMs,
|
|
64
|
+
signal: AbortSignal.timeout(input.timeoutMs + 60000),
|
|
65
|
+
write: [dir],
|
|
66
|
+
readable: boundary.readable,
|
|
67
|
+
controller: boundary.hidden,
|
|
68
|
+
settingsDir: join(root, `${id}-settings`),
|
|
69
|
+
});
|
|
70
|
+
results.push({
|
|
71
|
+
size,
|
|
72
|
+
ms: Date.now() - started,
|
|
73
|
+
outcome: result.timedOut ? 'timeout' : result.code === 0 ? 'ok' : 'error',
|
|
74
|
+
exitCode: result.code,
|
|
75
|
+
});
|
|
76
|
+
if (result.timedOut)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
// Класс и код отказа сохраняются, известные значения — ни в одном поле.
|
|
82
|
+
throw redactError(error, redact);
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
await git(path, 'worktree', 'remove', '--force', dir).catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
const outcome = results.some((r) => r.outcome === 'timeout')
|
|
88
|
+
? 'inconclusive'
|
|
89
|
+
: results.some((r) => r.outcome === 'error')
|
|
90
|
+
? 'failed'
|
|
91
|
+
: 'feasible';
|
|
92
|
+
const timeout = results.find((r) => r.outcome === 'timeout');
|
|
93
|
+
const limits = outcome === 'inconclusive'
|
|
94
|
+
? `Таймаут ${input.timeoutMs} мс на размере ${timeout.size}: для этого способа и бюджета вывод не сделан. Это не доказательство невыполнимости или трудности и не основание менять требование.`
|
|
95
|
+
: outcome === 'failed'
|
|
96
|
+
? 'Команда эксперимента завершилась ошибкой: вывод о выполнимости не сделан.'
|
|
97
|
+
: `Успех на размерах ${input.sizes.join(', ')} с seed ${input.seed} в указанной среде. Не доказывает верхней границы на любом входе и других размерах.`;
|
|
98
|
+
const record = {
|
|
99
|
+
id,
|
|
100
|
+
repositoryId: repo.id,
|
|
101
|
+
sha,
|
|
102
|
+
command: input.command,
|
|
103
|
+
seed: input.seed,
|
|
104
|
+
sizes: input.sizes,
|
|
105
|
+
timeoutMs: input.timeoutMs,
|
|
106
|
+
question: input.question,
|
|
107
|
+
results,
|
|
108
|
+
outcome,
|
|
109
|
+
limits,
|
|
110
|
+
environment: {
|
|
111
|
+
platform: platform(),
|
|
112
|
+
arch: arch(),
|
|
113
|
+
node: process.version,
|
|
114
|
+
cpus: cpus().length,
|
|
115
|
+
isolation: ctx.policy.isolation.mode,
|
|
116
|
+
},
|
|
117
|
+
at: new Date().toISOString(),
|
|
118
|
+
};
|
|
119
|
+
// Сохраняется и возвращается маскированная форма; digest — от неё.
|
|
120
|
+
const safe = redactDeep(record, redact);
|
|
121
|
+
const spike = spikeSchema.parse({ ...safe, digest: digestOf(safe) });
|
|
122
|
+
ctx.engine.host.store.transact('checks.spike', (tx) => tx.putLocal('spikes', repo.id, id, spike));
|
|
123
|
+
return spike;
|
|
124
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,102 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devcontour-harness",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
|
+
"description": "Headless execution harness: work graph, isolated attempts, gates, independent reviews and accepted results.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/step1ov/devcontour-harness.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/step1ov/devcontour-harness#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/step1ov/devcontour-harness/issues"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=24.3.0"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"harness": "lib/cli.js"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./lib/index.d.ts",
|
|
24
|
+
"default": "./lib/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./contracts": {
|
|
27
|
+
"types": "./lib/contracts/index.d.ts",
|
|
28
|
+
"default": "./lib/contracts/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json",
|
|
31
|
+
"./schemas/*": "./schemas/*",
|
|
32
|
+
"./testing": {
|
|
33
|
+
"types": "./lib/testing/index.d.ts",
|
|
34
|
+
"default": "./lib/testing/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./toolchains": {
|
|
37
|
+
"types": "./lib/toolchains/index.d.ts",
|
|
38
|
+
"default": "./lib/toolchains/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./integrations/connector": {
|
|
41
|
+
"types": "./lib/integrations/connector/index.d.ts",
|
|
42
|
+
"default": "./lib/integrations/connector/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./integrations/relay-v1": {
|
|
45
|
+
"types": "./lib/integrations/relay-v1/index.d.ts",
|
|
46
|
+
"default": "./lib/integrations/relay-v1/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./integrations/relay-v2": {
|
|
49
|
+
"types": "./lib/integrations/relay-v2/index.d.ts",
|
|
50
|
+
"default": "./lib/integrations/relay-v2/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./integrations/memory": {
|
|
53
|
+
"types": "./lib/integrations/memory/index.d.ts",
|
|
54
|
+
"default": "./lib/integrations/memory/index.js"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"files": [
|
|
58
|
+
"lib",
|
|
59
|
+
"schemas",
|
|
60
|
+
"docs",
|
|
61
|
+
"examples",
|
|
62
|
+
"profiles",
|
|
63
|
+
"skills",
|
|
64
|
+
"templates",
|
|
65
|
+
"LICENSE",
|
|
66
|
+
"README.md"
|
|
67
|
+
],
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public",
|
|
70
|
+
"tag": "alpha",
|
|
71
|
+
"registry": "https://registry.npmjs.org/"
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"typecheck": "tsc --noEmit",
|
|
75
|
+
"build": "node scripts/clean.mjs && tsc -p tsconfig.build.json",
|
|
76
|
+
"prepack": "npm run schemas:check && npm run build",
|
|
77
|
+
"schemas": "node --import tsx scripts/build-schemas.ts",
|
|
78
|
+
"schemas:check": "node --import tsx scripts/build-schemas.ts --check",
|
|
79
|
+
"lint": "eslint .",
|
|
80
|
+
"test": "node scripts/test.mjs",
|
|
81
|
+
"test:integration": "node --import tsx --test --test-concurrency=1 --test-timeout=1800000 tests/integration/*.test.ts",
|
|
82
|
+
"test:package": "npm run build && node scripts/smoke-package.mjs",
|
|
83
|
+
"check": "npm run lint && npm run typecheck && npm run schemas:check && npm run build && npm test && node scripts/smoke-package.mjs",
|
|
84
|
+
"format": "prettier --write .",
|
|
85
|
+
"format:check": "prettier --check .",
|
|
86
|
+
"check:install": "node scripts/install-check.mjs"
|
|
87
|
+
},
|
|
88
|
+
"dependencies": {
|
|
89
|
+
"@anthropic-ai/sandbox-runtime": "0.0.77",
|
|
90
|
+
"fast-xml-parser": "5.11.1",
|
|
91
|
+
"zod": "4.6.5"
|
|
92
|
+
},
|
|
93
|
+
"devDependencies": {
|
|
94
|
+
"@types/node": "24.13.5",
|
|
95
|
+
"ajv": "8.20.0",
|
|
96
|
+
"eslint": "10.10.0",
|
|
97
|
+
"prettier": "3.9.7",
|
|
98
|
+
"tsx": "4.23.13",
|
|
99
|
+
"typescript": "6.0.3",
|
|
100
|
+
"typescript-eslint": "8.70.0"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "go-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"capabilities": ["go", "openapi", "integration-tests"],
|
|
5
|
+
"gates": [
|
|
6
|
+
{ "id": "vet", "kind": "check", "command": ["go", "vet", "./..."], "timeoutMs": 120000 },
|
|
7
|
+
{
|
|
8
|
+
"id": "acceptance",
|
|
9
|
+
"kind": "test",
|
|
10
|
+
"command": ["gotestsum", "--junitfile", ".reports/junit.xml", "--", "-race", "./..."],
|
|
11
|
+
"timeoutMs": 240000,
|
|
12
|
+
"report": { "type": "junit", "path": ".reports/junit.xml" }
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "go-gotestsum",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"capabilities": ["go", "unit-tests"],
|
|
5
|
+
"protectedPaths": ["go.mod", "go.sum"],
|
|
6
|
+
"toolchain": {
|
|
7
|
+
"tools": { "gotestsum": "1.12.3" }
|
|
8
|
+
},
|
|
9
|
+
"prepare": [{ "id": "install", "command": ["go", "mod", "download"], "timeoutMs": 600000 }],
|
|
10
|
+
"gates": [
|
|
11
|
+
{ "id": "vet", "kind": "check", "command": ["go", "vet", "./..."], "timeoutMs": 240000 },
|
|
12
|
+
{
|
|
13
|
+
"id": "acceptance",
|
|
14
|
+
"kind": "test",
|
|
15
|
+
"command": ["gotestsum", "--junitfile", ".reports/junit.xml", "--", "-count=1", "./..."],
|
|
16
|
+
"timeoutMs": 240000,
|
|
17
|
+
"dependsOn": ["vet"],
|
|
18
|
+
"report": { "type": "junit", "path": ".reports/junit.xml" }
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mobile-maestro",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"capabilities": ["mobile", "maestro", "device-lease-required"],
|
|
5
|
+
"concurrency": 1,
|
|
6
|
+
"gates": [
|
|
7
|
+
{
|
|
8
|
+
"id": "build-and-install",
|
|
9
|
+
"kind": "check",
|
|
10
|
+
"command": ["npm", "run", "mobile:devcontour:prepare"],
|
|
11
|
+
"timeoutMs": 600000
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "mobile-acceptance",
|
|
15
|
+
"kind": "test",
|
|
16
|
+
"command": [
|
|
17
|
+
"maestro",
|
|
18
|
+
"test",
|
|
19
|
+
".maestro/",
|
|
20
|
+
"--format",
|
|
21
|
+
"junit",
|
|
22
|
+
"--output",
|
|
23
|
+
".reports/junit.xml"
|
|
24
|
+
],
|
|
25
|
+
"timeoutMs": 600000,
|
|
26
|
+
"report": { "type": "junit", "path": ".reports/junit.xml" }
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "nest-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"extends": ["node-checks"],
|
|
5
|
+
"capabilities": ["nestjs", "api", "integration-tests"],
|
|
6
|
+
"gates": [
|
|
7
|
+
{
|
|
8
|
+
"id": "build",
|
|
9
|
+
"kind": "check",
|
|
10
|
+
"command": ["npm", "run", "build"],
|
|
11
|
+
"timeoutMs": 240000,
|
|
12
|
+
"dependsOn": ["typecheck"]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "api-acceptance",
|
|
16
|
+
"kind": "test",
|
|
17
|
+
"command": ["npm", "run", "test:devcontour:integration"],
|
|
18
|
+
"timeoutMs": 240000,
|
|
19
|
+
"dependsOn": ["build"],
|
|
20
|
+
"report": {
|
|
21
|
+
"type": "junit",
|
|
22
|
+
"path": ".reports/integration.xml"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|