devcontour-harness 0.1.0-alpha.5 → 0.1.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -2
- package/docs/compatibility-versions.md +56 -0
- package/docs/compatibility.md +2 -2
- package/docs/connectors.md +323 -0
- package/docs/contracts.md +33 -5
- package/docs/integrations/hindsight.md +148 -0
- package/docs/quickstart.md +1 -1
- package/docs/release-notes/0.1.0-alpha.6.md +238 -0
- package/docs/release-notes/0.1.0-alpha.7.md +71 -0
- package/docs/review-probes.md +199 -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 +77 -24
- package/examples/README.md +1 -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/lib/agents/cli-adapter.js +10 -1
- package/lib/agents/inspect.d.ts +56 -2
- package/lib/agents/inspect.js +264 -14
- package/lib/agents/review-probe.d.ts +229 -7
- package/lib/agents/review-probe.js +830 -72
- package/lib/agents/schemas.d.ts +3 -1
- package/lib/agents/schemas.js +7 -3
- package/lib/cli.js +167 -7
- package/lib/contracts/cli.d.ts +820 -11
- package/lib/contracts/cli.js +243 -4
- package/lib/contracts/errors.d.ts +3 -1
- package/lib/contracts/errors.js +2 -0
- package/lib/contracts/events.d.ts +37 -5
- package/lib/contracts/events.js +9 -0
- package/lib/contracts/execution.d.ts +389 -15
- package/lib/contracts/execution.js +76 -4
- package/lib/contracts/failure.js +5 -0
- package/lib/contracts/index.d.ts +1 -0
- package/lib/contracts/index.js +1 -0
- package/lib/contracts/policy.d.ts +15 -0
- package/lib/contracts/policy.js +10 -0
- package/lib/contracts/ports.d.ts +50 -0
- package/lib/contracts/profiles.d.ts +14 -0
- package/lib/contracts/profiles.js +4 -0
- package/lib/contracts/published.d.ts +279 -8
- package/lib/contracts/result.d.ts +171 -0
- package/lib/contracts/result.js +39 -1
- package/lib/contracts/review.d.ts +231 -0
- package/lib/contracts/review.js +326 -2
- package/lib/contracts/toolchain.d.ts +96 -0
- package/lib/contracts/toolchain.js +89 -0
- package/lib/control/doctor.d.ts +16 -1
- package/lib/control/doctor.js +45 -3
- package/lib/control/harness.d.ts +52 -6
- package/lib/control/harness.js +28 -1
- package/lib/control/recovery.d.ts +3 -1
- package/lib/control/review.js +23 -11
- package/lib/engine/budget.d.ts +3 -3
- package/lib/engine/classify.js +1 -0
- package/lib/engine/engine.d.ts +67 -17
- package/lib/engine/prompt.d.ts +29 -1
- package/lib/engine/prompt.js +57 -0
- package/lib/engine/property-recovery.js +2 -0
- package/lib/engine/result.js +52 -0
- package/lib/engine/reuse.js +6 -1
- package/lib/engine/runner.d.ts +25 -0
- package/lib/engine/runner.js +500 -123
- package/lib/environment/lifecycle.js +6 -0
- package/lib/environment/live-calls.js +3 -2
- package/lib/environment/os-tools.d.ts +16 -0
- package/lib/environment/os-tools.js +35 -0
- package/lib/environment/process.d.ts +8 -0
- package/lib/environment/process.js +13 -6
- 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/profiles/resolve.d.ts +5 -1
- package/lib/profiles/resolve.js +31 -0
- package/lib/storage/document.d.ts +116 -16
- 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/verification/acceptance.d.ts +16 -0
- package/lib/verification/acceptance.js +16 -0
- package/lib/verification/gates.d.ts +38 -0
- package/lib/verification/gates.js +108 -26
- package/package.json +22 -1
- package/profiles/go-gotestsum.json +21 -0
- package/profiles/npm-ci.json +22 -0
- package/profiles/pnpm-frozen.json +24 -0
- package/profiles/python-uv.json +26 -0
- package/schemas/execution-document.schema.json +345 -4
- package/schemas/execution-policy.schema.json +48 -0
- package/schemas/result-envelope.schema.json +213 -1
- package/schemas/run-event.schema.json +93 -0
- package/schemas/run-result.schema.json +207 -0
- package/schemas/stack-profile.schema.json +43 -0
- package/templates/controller-mode/AGENTS.controller.md +58 -0
- package/templates/controller-mode/README.md +44 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { redactor } from "../../environment/redaction.js";
|
|
2
|
+
/** Абсолютные пути (POSIX и Windows) заменяются — они не ссылки для другого компьютера. */
|
|
3
|
+
const PATHS = /(?<![\w.:/\\])(?:[A-Za-z]:\\|\/)(?:[\w.@+-]+[\\/])+[\w.@+-]*/g;
|
|
4
|
+
export const stripPaths = (text) => text.replace(PATHS, '[локальный путь]');
|
|
5
|
+
const shortSha = (sha) => (sha ? sha.slice(0, 12) : '—');
|
|
6
|
+
export function summaryText(input) {
|
|
7
|
+
const r = input.result;
|
|
8
|
+
const redact = input.redact ?? redactor([]);
|
|
9
|
+
const gates = [...new Map(r.evidence.map((e) => [`${e.gate}/${e.phase}`, e])).values()]
|
|
10
|
+
.filter((e) => e.kind !== 'review')
|
|
11
|
+
.map((e) => {
|
|
12
|
+
const tests = e.tests
|
|
13
|
+
? ` (${e.tests.filter((t) => t.status === 'passed').length}/${e.tests.length} тестов)`
|
|
14
|
+
: '';
|
|
15
|
+
return `- ${e.gate} [${e.phase}]: ${e.passed ? 'passed' : 'failed'}${tests} @ ${shortSha(e.sha)}`;
|
|
16
|
+
});
|
|
17
|
+
const reviews = r.evidence.filter((e) => e.kind === 'review');
|
|
18
|
+
const lines = [
|
|
19
|
+
input.marker,
|
|
20
|
+
input.historical
|
|
21
|
+
? `**devcontour-harness: исторический результат** — относится к прежней постановке (снимок ${input.snapshot.revision.slice(0, 12)}), **не подтверждает текущие критерии и не закрывает задачу**.`
|
|
22
|
+
: `**devcontour-harness: ${r.outcome}** — ${input.task.key}`,
|
|
23
|
+
'',
|
|
24
|
+
`- Попытка: ${r.runId} (№ ${r.attempt}), репозиторий ${r.repositoryId}, target ${r.targetRef}`,
|
|
25
|
+
r.outcome === 'accepted'
|
|
26
|
+
? `- SHA: base ${shortSha(r.shas.base)}, candidate ${r.shas.candidate}, integration/result ${r.shas.result}`
|
|
27
|
+
: `- SHA: candidate ${shortSha(r.shas.candidate)}, integration ${shortSha(r.shas.integration)}`,
|
|
28
|
+
...(r.outcome !== 'accepted'
|
|
29
|
+
? [`- Причина: ${r.stopReason.code}: ${r.stopReason.message.slice(0, 500)}`]
|
|
30
|
+
: []),
|
|
31
|
+
`- Снимок постановки: ${input.task.identity} @ ${input.snapshot.revision} (CAS ${input.snapshot.casRevision})`,
|
|
32
|
+
'',
|
|
33
|
+
'**Gates**',
|
|
34
|
+
...(gates.length ? gates : ['- нет записей']),
|
|
35
|
+
...(reviews.length
|
|
36
|
+
? [
|
|
37
|
+
`- независимое ревью: ${reviews.map((e) => `${e.phase} ${e.passed ? 'approved' : 'rejected'}`).join(', ')}`,
|
|
38
|
+
]
|
|
39
|
+
: []),
|
|
40
|
+
'',
|
|
41
|
+
'**Критерии**',
|
|
42
|
+
...(input.criteria.length
|
|
43
|
+
? input.criteria.map((c) => `- ${c.title}: ${c.outcome}` +
|
|
44
|
+
(c.gate ? ` ← ${c.gate}${c.testId ? '/' + c.testId : ''}` : '') +
|
|
45
|
+
(c.reason ? ` (${c.reason})` : ''))
|
|
46
|
+
: ['- нет критериев']),
|
|
47
|
+
'',
|
|
48
|
+
`Завершение: ${input.completion}`,
|
|
49
|
+
...(r.limitations.length
|
|
50
|
+
? ['', '**Ограничения**', ...r.limitations.slice(0, 10).map((l) => '- ' + l)]
|
|
51
|
+
: []),
|
|
52
|
+
];
|
|
53
|
+
const body = stripPaths(redact(lines.join('\n'))).slice(0, 8000);
|
|
54
|
+
const title = stripPaths(redact(input.historical
|
|
55
|
+
? `devcontour-harness: исторический результат ${input.task.key}`
|
|
56
|
+
: `devcontour-harness: ${r.outcome} ${input.task.key}`)).slice(0, 200);
|
|
57
|
+
// Маркер не маскируется и не обрезается: по нему выполняется read-back.
|
|
58
|
+
return { title, body: body.startsWith(input.marker) ? body : input.marker + '\n' + body };
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Отдельный процесс набора проверки коннектора (fixture, не рабочий путь):
|
|
3
|
+
* доставка, reconcile или начало истории попытки над тем же каталогом
|
|
4
|
+
* состояния, с точками отказа. Crash — `process.exit(75)` в заданной точке.
|
|
5
|
+
* Итог — одна строка JSON в stdout.
|
|
6
|
+
*
|
|
7
|
+
* Запуск: `node --import tsx testing-worker.ts <spec.json>`.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { executionPolicySchema } from "../../contracts/index.js";
|
|
11
|
+
import { Harness } from "../../control/harness.js";
|
|
12
|
+
import { parseConfig } from "./config.js";
|
|
13
|
+
import { Connector, openConnector } from "./commands.js";
|
|
14
|
+
import { FakeRelayTransport, FileBarrier, faultyTransport, fileBackend, } from "./fake.js";
|
|
15
|
+
import { createTransportFor } from "./registry.js";
|
|
16
|
+
import { forbiddenAdapters } from "./testing.js";
|
|
17
|
+
const spec = JSON.parse(readFileSync(process.argv[2], 'utf8'));
|
|
18
|
+
const print = (value) => process.stdout.write(JSON.stringify(value) + '\n');
|
|
19
|
+
try {
|
|
20
|
+
const loaded = parseConfig(spec.config, spec.baseDir);
|
|
21
|
+
const inner = spec.transport.kind === 'fake'
|
|
22
|
+
? new FakeRelayTransport(fileBackend(spec.transport.file), {
|
|
23
|
+
provider: spec.transport.provider,
|
|
24
|
+
actor: spec.transport.actor,
|
|
25
|
+
})
|
|
26
|
+
: await createTransportFor(loaded);
|
|
27
|
+
const rules = (spec.faults ?? []).map(({ barrier, ...f }) => ({
|
|
28
|
+
...f,
|
|
29
|
+
...(barrier ? { barrier: new FileBarrier(barrier.dir, barrier.name, 60_000) } : {}),
|
|
30
|
+
}));
|
|
31
|
+
const writes = {};
|
|
32
|
+
const connector = await openConnector(loaded, {
|
|
33
|
+
stateDir: spec.state,
|
|
34
|
+
transport: faultyTransport(inner, rules),
|
|
35
|
+
...(spec.owner ? { owner: spec.owner } : {}),
|
|
36
|
+
onStoreWrite: (what) => {
|
|
37
|
+
writes[what] = (writes[what] ?? 0) + 1;
|
|
38
|
+
if (spec.crashOnStoreWrite?.what === what && writes[what] === spec.crashOnStoreWrite.nth)
|
|
39
|
+
process.exit(75);
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
if (spec.action === 'begin-attempt') {
|
|
43
|
+
const a = spec.attempt;
|
|
44
|
+
await connector.history.beginAttempt(a.work, a.attempt, a.baseSha);
|
|
45
|
+
print({ ok: true });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const h = Harness.open({
|
|
49
|
+
stateDir: spec.state,
|
|
50
|
+
policy: executionPolicySchema.parse(spec.policy),
|
|
51
|
+
baseDir: spec.repo,
|
|
52
|
+
adapters: forbiddenAdapters(spec.forbidden),
|
|
53
|
+
hooks: connector.hooks(),
|
|
54
|
+
resourceDatabase: spec.resources,
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
if (spec.action === 'deliver') {
|
|
58
|
+
const envelope = await h.deliver(spec.workId, connector.sink);
|
|
59
|
+
print({ ok: true, result: envelope });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const result = await connector.reconcile(h, spec.operation, Connector.decision(spec.decision));
|
|
63
|
+
print({ ok: true, result });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
h.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
connector.close();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
print({
|
|
74
|
+
ok: false,
|
|
75
|
+
error: {
|
|
76
|
+
code: error.code,
|
|
77
|
+
message: error instanceof Error ? error.message : String(error),
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
process.exitCode = 3;
|
|
81
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { type ExecutionPolicy, type RuntimeAdapter, type RuntimeName, type RuntimeRequest } from '../../contracts/index.ts';
|
|
2
|
+
import { Harness } from '../../control/harness.ts';
|
|
3
|
+
import { type ConnectorConfigInput, type CriterionMapping, type LoadedConfig } from './config.ts';
|
|
4
|
+
import { Connector } from './commands.ts';
|
|
5
|
+
import { type FaultRule } from './fake.ts';
|
|
6
|
+
import type { ProviderId, RelayTransport, TaskColumn } from './transport.ts';
|
|
7
|
+
export { FakeAdmin, FakeRelayTransport, FileBarrier, LocalBarrier, emptyFakeState, faultyTransport, fileBackend, memoryBackend, type Barrier, type FakeBackend, type FakeState, type FaultAction, type FaultRule, } from './fake.ts';
|
|
8
|
+
/** Действия другого участника прямо в backend (постановка задач, правки, перехват). */
|
|
9
|
+
export interface SuiteAdmin {
|
|
10
|
+
createTask(input: {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
column?: TaskColumn;
|
|
14
|
+
criteria?: {
|
|
15
|
+
title: string;
|
|
16
|
+
summary?: string;
|
|
17
|
+
}[];
|
|
18
|
+
dependencies?: string[];
|
|
19
|
+
parentId?: string;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
id: string;
|
|
22
|
+
key: string;
|
|
23
|
+
criteria: string[];
|
|
24
|
+
}>;
|
|
25
|
+
updateTask(id: string, patch: {
|
|
26
|
+
title?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
updateCriterion(id: string, criterionId: string, title: string): Promise<void>;
|
|
30
|
+
completeCriterion(id: string, criterionId: string, completed?: boolean): Promise<void>;
|
|
31
|
+
addDocument(taskId: string, doc: {
|
|
32
|
+
name: string;
|
|
33
|
+
body: string;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
id: string;
|
|
36
|
+
}>;
|
|
37
|
+
updateDocument(id: string, body: string): Promise<void>;
|
|
38
|
+
addDependency(id: string, dependsOn: string): Promise<void>;
|
|
39
|
+
/** Перемещение с done guards backend (как у человека). */
|
|
40
|
+
move(id: string, column: TaskColumn): Promise<void>;
|
|
41
|
+
/** Комментарий другого участника (может содержать любой текст, включая маркер). */
|
|
42
|
+
comment(id: string, body: string): Promise<void>;
|
|
43
|
+
/** Перехват открытой сессии истории другим владельцем. */
|
|
44
|
+
takeover(sessionId: string): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/** Как воссоздать транспорт в другом процессе (`testing-worker.ts`). */
|
|
47
|
+
export type WorkerTransport =
|
|
48
|
+
/** Подделка над общим файлом состояния. */
|
|
49
|
+
{
|
|
50
|
+
kind: 'fake';
|
|
51
|
+
file: string;
|
|
52
|
+
provider: ProviderId;
|
|
53
|
+
actor: string;
|
|
54
|
+
}
|
|
55
|
+
/** Настоящий адаптер по конфигурации коннектора (`createTransportFor`). */
|
|
56
|
+
| {
|
|
57
|
+
kind: 'config';
|
|
58
|
+
};
|
|
59
|
+
export interface SuiteProject {
|
|
60
|
+
provider: ProviderId;
|
|
61
|
+
projectId: string;
|
|
62
|
+
actor: string;
|
|
63
|
+
/** Поле `relay` конфигурации коннектора (без projectId/actor). */
|
|
64
|
+
relay: Record<string, unknown>;
|
|
65
|
+
/** Новый экземпляр транспорта этого проекта. */
|
|
66
|
+
transport(): RelayTransport;
|
|
67
|
+
worker: WorkerTransport;
|
|
68
|
+
admin: SuiteAdmin;
|
|
69
|
+
cleanup(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
/** Backend набора: каждый вызов `project()` — новый изолированный проект. */
|
|
72
|
+
export interface SuiteBackend {
|
|
73
|
+
name: string;
|
|
74
|
+
project(): Promise<SuiteProject>;
|
|
75
|
+
}
|
|
76
|
+
/** Backend набора на подделке; состояние каждого проекта — в своём файле SQLite. */
|
|
77
|
+
export declare function fakeSuiteBackend(provider?: ProviderId): SuiteBackend;
|
|
78
|
+
export declare const fixtureGreet = "exports.greet = (name) => 'Hello, ' + name + '!';\n";
|
|
79
|
+
export interface RuntimeCalls {
|
|
80
|
+
writer: number;
|
|
81
|
+
reviewer: number;
|
|
82
|
+
plan: number;
|
|
83
|
+
}
|
|
84
|
+
export interface FixtureBehaviour {
|
|
85
|
+
writer?: 'implement' | 'incomplete';
|
|
86
|
+
reviewer?: 'approve' | 'reject';
|
|
87
|
+
/** Вызывается при каждом вызове writer до ответа (проверка порядка, отмена). */
|
|
88
|
+
onWriter?: (request: RuntimeRequest) => void | Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
/** Runtime fixture в процессе: writer пишет greet, reviewer одобряет или отклоняет. */
|
|
91
|
+
export declare function fixtureAdapters(calls: RuntimeCalls, behaviour?: FixtureBehaviour): Partial<Record<RuntimeName, RuntimeAdapter>>;
|
|
92
|
+
/** Runtime, который не должен вызываться (доставка, reconcile): вызов — отказ и запись. */
|
|
93
|
+
export declare function forbiddenAdapters(file: string): Partial<Record<RuntimeName, RuntimeAdapter>>;
|
|
94
|
+
export declare function suitePolicy(repo: string, patch?: Partial<Record<string, unknown>>): ExecutionPolicy;
|
|
95
|
+
export interface ScenarioOptions extends FixtureBehaviour {
|
|
96
|
+
criteria?: {
|
|
97
|
+
title: string;
|
|
98
|
+
}[];
|
|
99
|
+
mapping?: (Partial<CriterionMapping> & {
|
|
100
|
+
gate: string;
|
|
101
|
+
})[];
|
|
102
|
+
config?: (config: ConnectorConfigInput & Record<string, unknown>) => void;
|
|
103
|
+
maxAttempts?: number;
|
|
104
|
+
approvalMode?: 'agent' | 'operator';
|
|
105
|
+
description?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface Opened {
|
|
108
|
+
connector: Connector;
|
|
109
|
+
h: Harness;
|
|
110
|
+
transport: RelayTransport & {
|
|
111
|
+
calls: Record<string, number>;
|
|
112
|
+
};
|
|
113
|
+
close(): void;
|
|
114
|
+
}
|
|
115
|
+
export interface WorkerSpec {
|
|
116
|
+
action: 'deliver' | 'reconcile' | 'begin-attempt';
|
|
117
|
+
workId?: string;
|
|
118
|
+
operation?: string;
|
|
119
|
+
decision?: string;
|
|
120
|
+
faults?: (Omit<FaultRule, 'barrier' | 'after'> & {
|
|
121
|
+
barrier?: {
|
|
122
|
+
dir: string;
|
|
123
|
+
name: string;
|
|
124
|
+
};
|
|
125
|
+
})[];
|
|
126
|
+
crashOnStoreWrite?: {
|
|
127
|
+
what: string;
|
|
128
|
+
nth: number;
|
|
129
|
+
};
|
|
130
|
+
owner?: string;
|
|
131
|
+
attempt?: {
|
|
132
|
+
work: unknown;
|
|
133
|
+
attempt: unknown;
|
|
134
|
+
baseSha: string;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
export interface WorkerResult {
|
|
138
|
+
code: number | null;
|
|
139
|
+
output?: {
|
|
140
|
+
ok: boolean;
|
|
141
|
+
result?: unknown;
|
|
142
|
+
error?: {
|
|
143
|
+
code?: string;
|
|
144
|
+
message: string;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
stderr: string;
|
|
148
|
+
}
|
|
149
|
+
export interface Scenario {
|
|
150
|
+
project: SuiteProject;
|
|
151
|
+
task: {
|
|
152
|
+
id: string;
|
|
153
|
+
key: string;
|
|
154
|
+
criteria: string[];
|
|
155
|
+
};
|
|
156
|
+
root: string;
|
|
157
|
+
repo: string;
|
|
158
|
+
state: string;
|
|
159
|
+
policy: ExecutionPolicy;
|
|
160
|
+
calls: RuntimeCalls;
|
|
161
|
+
config: ConnectorConfigInput & Record<string, unknown>;
|
|
162
|
+
loaded(): LoadedConfig;
|
|
163
|
+
workId: string;
|
|
164
|
+
open(o?: {
|
|
165
|
+
faults?: FaultRule[];
|
|
166
|
+
onStoreWrite?: (what: string) => void;
|
|
167
|
+
transport?: RelayTransport;
|
|
168
|
+
behaviour?: FixtureBehaviour;
|
|
169
|
+
secrets?: string[];
|
|
170
|
+
}): Promise<Opened>;
|
|
171
|
+
/** Снимок и `run --source` (ревью плана, исполнение, доставка). */
|
|
172
|
+
snapshotAndRun(o?: Parameters<Scenario['open']>[0]): Promise<{
|
|
173
|
+
opened: Opened;
|
|
174
|
+
run: Awaited<ReturnType<Connector['run']>>;
|
|
175
|
+
}>;
|
|
176
|
+
/** Снимок и исполнение без доставки (результат принят локально). */
|
|
177
|
+
runOnly(o?: Parameters<Scenario['open']>[0]): Promise<Opened>;
|
|
178
|
+
target(): string;
|
|
179
|
+
worker(spec: WorkerSpec, timeoutMs?: number): Promise<WorkerResult>;
|
|
180
|
+
/** Дождаться истечения lease упавшего владельца (перехват — только после срока). */
|
|
181
|
+
waitLeases(): Promise<void>;
|
|
182
|
+
cleanup(): Promise<void>;
|
|
183
|
+
}
|
|
184
|
+
export declare function scenario(backend: SuiteBackend, o?: ScenarioOptions): Promise<Scenario>;
|
|
185
|
+
/** Комментарии harness у задачи (по маркеру) — счёт у получателя, не локальных вызовов. */
|
|
186
|
+
export declare function harnessComments(t: RelayTransport, taskId: string): Promise<import("./transport.ts").CommentRecord[]>;
|
|
187
|
+
export declare function markerCount(t: RelayTransport, taskId: string, marker: string): Promise<number>;
|
|
188
|
+
/** Все чекпоинты сессий истории поручения у получателя. */
|
|
189
|
+
export declare function historyCheckpoints(opened: Opened, workId: string): Promise<{
|
|
190
|
+
session: string;
|
|
191
|
+
kind: string;
|
|
192
|
+
title: string;
|
|
193
|
+
body: string;
|
|
194
|
+
}[]>;
|
|
195
|
+
export interface SuiteOptions {
|
|
196
|
+
/** Предел одного теста, мс. */
|
|
197
|
+
timeoutMs?: number;
|
|
198
|
+
/** Выполнить только тесты с этими ID (`W02`, `D03`…). */
|
|
199
|
+
only?: string[];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Общий контрактный набор коннектора для backend. Имена тестов содержат ID
|
|
203
|
+
* условий приёмки и имя backend.
|
|
204
|
+
*/
|
|
205
|
+
export declare function connectorSuite(backend: SuiteBackend, options?: SuiteOptions): void;
|