@kontourai/flow-agents 3.11.0 → 3.12.1
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/CHANGELOG.md +14 -0
- package/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/build/src/builder-flow-run-adapter.js +2 -0
- package/build/src/builder-flow-runtime.d.ts +5 -0
- package/build/src/builder-flow-runtime.js +90 -68
- package/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/build/src/builder-gate-action-envelope.js +368 -0
- package/build/src/cli/public-contracts.d.ts +139 -0
- package/build/src/cli/public-contracts.js +37 -0
- package/build/src/cli/workflow-sidecar.js +9 -13
- package/build/src/cli/workflow.d.ts +1 -0
- package/build/src/cli/workflow.js +49 -12
- package/build/src/continuation-driver.d.ts +40 -3
- package/build/src/continuation-driver.js +361 -412
- package/build/src/continuation-persistence.d.ts +4 -0
- package/build/src/continuation-persistence.js +296 -0
- package/build/src/continuation-validation.d.ts +9 -0
- package/build/src/continuation-validation.js +169 -0
- package/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/build/src/flow-kit/action-metadata.js +162 -0
- package/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/build/src/flow-kit/action-repository-validation.js +237 -0
- package/build/src/flow-kit/validate.d.ts +2 -14
- package/build/src/flow-kit/validate.js +18 -345
- package/build/src/index.d.ts +4 -2
- package/build/src/index.js +2 -1
- package/dist/base/build/package.json +1 -1
- package/dist/base/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/base/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/base/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/base/build/src/builder-flow-runtime.js +90 -68
- package/dist/base/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/base/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/base/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/base/build/src/cli/public-contracts.js +37 -0
- package/dist/base/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/base/build/src/cli/workflow.d.ts +1 -0
- package/dist/base/build/src/cli/workflow.js +49 -12
- package/dist/base/build/src/continuation-driver.d.ts +40 -3
- package/dist/base/build/src/continuation-driver.js +361 -412
- package/dist/base/build/src/continuation-persistence.d.ts +4 -0
- package/dist/base/build/src/continuation-persistence.js +296 -0
- package/dist/base/build/src/continuation-validation.d.ts +9 -0
- package/dist/base/build/src/continuation-validation.js +169 -0
- package/dist/base/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/base/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/base/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/base/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/base/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/base/build/src/flow-kit/validate.js +18 -345
- package/dist/base/build/src/index.d.ts +4 -2
- package/dist/base/build/src/index.js +2 -1
- package/dist/base/docs/migrations.md +5 -0
- package/dist/base/docs/public-workflow-cli.md +41 -5
- package/dist/base/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/base/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/base/evals/integration/test_bundle_install.sh +15 -15
- package/dist/base/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/base/install.sh +1 -1
- package/dist/base/kits/builder/kit.json +88 -14
- package/dist/claude-code/build/package.json +1 -1
- package/dist/claude-code/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/claude-code/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/claude-code/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/claude-code/build/src/builder-flow-runtime.js +90 -68
- package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/claude-code/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/claude-code/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/claude-code/build/src/cli/public-contracts.js +37 -0
- package/dist/claude-code/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/claude-code/build/src/cli/workflow.d.ts +1 -0
- package/dist/claude-code/build/src/cli/workflow.js +49 -12
- package/dist/claude-code/build/src/continuation-driver.d.ts +40 -3
- package/dist/claude-code/build/src/continuation-driver.js +361 -412
- package/dist/claude-code/build/src/continuation-persistence.d.ts +4 -0
- package/dist/claude-code/build/src/continuation-persistence.js +296 -0
- package/dist/claude-code/build/src/continuation-validation.d.ts +9 -0
- package/dist/claude-code/build/src/continuation-validation.js +169 -0
- package/dist/claude-code/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/claude-code/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/claude-code/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/claude-code/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/claude-code/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/claude-code/build/src/flow-kit/validate.js +18 -345
- package/dist/claude-code/build/src/index.d.ts +4 -2
- package/dist/claude-code/build/src/index.js +2 -1
- package/dist/claude-code/docs/migrations.md +5 -0
- package/dist/claude-code/docs/public-workflow-cli.md +41 -5
- package/dist/claude-code/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/claude-code/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/claude-code/evals/integration/test_bundle_install.sh +15 -15
- package/dist/claude-code/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/claude-code/install.sh +1 -1
- package/dist/claude-code/kits/builder/kit.json +88 -14
- package/dist/codex/build/package.json +1 -1
- package/dist/codex/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/codex/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/codex/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/codex/build/src/builder-flow-runtime.js +90 -68
- package/dist/codex/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/codex/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/codex/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/codex/build/src/cli/public-contracts.js +37 -0
- package/dist/codex/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/codex/build/src/cli/workflow.d.ts +1 -0
- package/dist/codex/build/src/cli/workflow.js +49 -12
- package/dist/codex/build/src/continuation-driver.d.ts +40 -3
- package/dist/codex/build/src/continuation-driver.js +361 -412
- package/dist/codex/build/src/continuation-persistence.d.ts +4 -0
- package/dist/codex/build/src/continuation-persistence.js +296 -0
- package/dist/codex/build/src/continuation-validation.d.ts +9 -0
- package/dist/codex/build/src/continuation-validation.js +169 -0
- package/dist/codex/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/codex/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/codex/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/codex/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/codex/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/codex/build/src/flow-kit/validate.js +18 -345
- package/dist/codex/build/src/index.d.ts +4 -2
- package/dist/codex/build/src/index.js +2 -1
- package/dist/codex/docs/migrations.md +5 -0
- package/dist/codex/docs/public-workflow-cli.md +41 -5
- package/dist/codex/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/codex/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/codex/evals/integration/test_bundle_install.sh +15 -15
- package/dist/codex/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/codex/install.sh +1 -1
- package/dist/codex/kits/builder/kit.json +88 -14
- package/dist/kiro/build/package.json +1 -1
- package/dist/kiro/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/kiro/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/kiro/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/kiro/build/src/builder-flow-runtime.js +90 -68
- package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/kiro/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/kiro/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/kiro/build/src/cli/public-contracts.js +37 -0
- package/dist/kiro/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/kiro/build/src/cli/workflow.d.ts +1 -0
- package/dist/kiro/build/src/cli/workflow.js +49 -12
- package/dist/kiro/build/src/continuation-driver.d.ts +40 -3
- package/dist/kiro/build/src/continuation-driver.js +361 -412
- package/dist/kiro/build/src/continuation-persistence.d.ts +4 -0
- package/dist/kiro/build/src/continuation-persistence.js +296 -0
- package/dist/kiro/build/src/continuation-validation.d.ts +9 -0
- package/dist/kiro/build/src/continuation-validation.js +169 -0
- package/dist/kiro/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/kiro/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/kiro/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/kiro/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/kiro/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/kiro/build/src/flow-kit/validate.js +18 -345
- package/dist/kiro/build/src/index.d.ts +4 -2
- package/dist/kiro/build/src/index.js +2 -1
- package/dist/kiro/docs/migrations.md +5 -0
- package/dist/kiro/docs/public-workflow-cli.md +41 -5
- package/dist/kiro/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/kiro/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/kiro/evals/integration/test_bundle_install.sh +15 -15
- package/dist/kiro/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/kiro/install.sh +1 -1
- package/dist/kiro/kits/builder/kit.json +88 -14
- package/dist/opencode/build/package.json +1 -1
- package/dist/opencode/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/opencode/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/opencode/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/opencode/build/src/builder-flow-runtime.js +90 -68
- package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/opencode/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/opencode/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/opencode/build/src/cli/public-contracts.js +37 -0
- package/dist/opencode/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/opencode/build/src/cli/workflow.d.ts +1 -0
- package/dist/opencode/build/src/cli/workflow.js +49 -12
- package/dist/opencode/build/src/continuation-driver.d.ts +40 -3
- package/dist/opencode/build/src/continuation-driver.js +361 -412
- package/dist/opencode/build/src/continuation-persistence.d.ts +4 -0
- package/dist/opencode/build/src/continuation-persistence.js +296 -0
- package/dist/opencode/build/src/continuation-validation.d.ts +9 -0
- package/dist/opencode/build/src/continuation-validation.js +169 -0
- package/dist/opencode/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/opencode/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/opencode/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/opencode/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/opencode/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/opencode/build/src/flow-kit/validate.js +18 -345
- package/dist/opencode/build/src/index.d.ts +4 -2
- package/dist/opencode/build/src/index.js +2 -1
- package/dist/opencode/docs/migrations.md +5 -0
- package/dist/opencode/docs/public-workflow-cli.md +41 -5
- package/dist/opencode/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/opencode/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/opencode/evals/integration/test_bundle_install.sh +15 -15
- package/dist/opencode/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/opencode/install.sh +1 -1
- package/dist/opencode/kits/builder/kit.json +88 -14
- package/dist/pi/build/package.json +1 -1
- package/dist/pi/build/src/builder-flow-run-adapter.d.ts +1 -0
- package/dist/pi/build/src/builder-flow-run-adapter.js +2 -0
- package/dist/pi/build/src/builder-flow-runtime.d.ts +5 -0
- package/dist/pi/build/src/builder-flow-runtime.js +90 -68
- package/dist/pi/build/src/builder-gate-action-envelope.d.ts +152 -0
- package/dist/pi/build/src/builder-gate-action-envelope.js +368 -0
- package/dist/pi/build/src/cli/public-contracts.d.ts +139 -0
- package/dist/pi/build/src/cli/public-contracts.js +37 -0
- package/dist/pi/build/src/cli/workflow-sidecar.js +9 -13
- package/dist/pi/build/src/cli/workflow.d.ts +1 -0
- package/dist/pi/build/src/cli/workflow.js +49 -12
- package/dist/pi/build/src/continuation-driver.d.ts +40 -3
- package/dist/pi/build/src/continuation-driver.js +361 -412
- package/dist/pi/build/src/continuation-persistence.d.ts +4 -0
- package/dist/pi/build/src/continuation-persistence.js +296 -0
- package/dist/pi/build/src/continuation-validation.d.ts +9 -0
- package/dist/pi/build/src/continuation-validation.js +169 -0
- package/dist/pi/build/src/flow-kit/action-metadata.d.ts +28 -0
- package/dist/pi/build/src/flow-kit/action-metadata.js +162 -0
- package/dist/pi/build/src/flow-kit/action-repository-validation.d.ts +16 -0
- package/dist/pi/build/src/flow-kit/action-repository-validation.js +237 -0
- package/dist/pi/build/src/flow-kit/validate.d.ts +2 -14
- package/dist/pi/build/src/flow-kit/validate.js +18 -345
- package/dist/pi/build/src/index.d.ts +4 -2
- package/dist/pi/build/src/index.js +2 -1
- package/dist/pi/docs/migrations.md +5 -0
- package/dist/pi/docs/public-workflow-cli.md +41 -5
- package/dist/pi/docs/spec/builder-flow-runtime.md +117 -0
- package/dist/pi/evals/integration/test_builder_step_producers.sh +60 -21
- package/dist/pi/evals/integration/test_bundle_install.sh +15 -15
- package/dist/pi/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/dist/pi/install.sh +1 -1
- package/dist/pi/kits/builder/kit.json +88 -14
- package/docs/migrations.md +5 -0
- package/docs/public-workflow-cli.md +41 -5
- package/docs/spec/builder-flow-runtime.md +117 -0
- package/evals/integration/test_builder_step_producers.sh +60 -21
- package/evals/integration/test_bundle_install.sh +15 -15
- package/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
- package/kits/builder/kit.json +88 -14
- package/package.json +1 -1
- package/src/builder-flow-run-adapter.ts +3 -0
- package/src/builder-flow-runtime.ts +73 -46
- package/src/builder-gate-action-envelope.ts +531 -0
- package/src/cli/builder-flow-runtime.test.mjs +289 -58
- package/src/cli/continuation-driver.test.mjs +542 -24
- package/src/cli/kit-metadata-security.test.mjs +161 -8
- package/src/cli/public-contracts.ts +41 -0
- package/src/cli/workflow-sidecar.ts +9 -13
- package/src/cli/workflow.ts +48 -12
- package/src/continuation-driver.ts +466 -378
- package/src/continuation-persistence.ts +228 -0
- package/src/continuation-validation.ts +137 -0
- package/src/flow-kit/action-metadata.ts +155 -0
- package/src/flow-kit/action-repository-validation.ts +192 -0
- package/src/flow-kit/validate.ts +19 -326
- package/src/index.ts +17 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { constants as fsConstants } from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { evaluateGate, expectationsForGate, openGates } from "@kontourai/flow";
|
|
6
|
+
import { parseKitFlowStepActions } from "./flow-kit/validate.js";
|
|
7
|
+
import { PUBLIC_OPERATION_CONTRACTS, WORKFLOW_CRITIQUE_STATUSES } from "./cli/public-contracts.js";
|
|
8
|
+
import { flowAgentsPackageRoot } from "./lib/package-version.js";
|
|
9
|
+
import { pinnedFlowAgentsCommand } from "./lib/pinned-cli-command.js";
|
|
10
|
+
const MAX_METADATA_BYTES = 1_048_576;
|
|
11
|
+
const MAX_ENVELOPE_BYTES = 65_536;
|
|
12
|
+
const MAX_SKILLS = 16;
|
|
13
|
+
const MAX_REQUIREMENTS = 32;
|
|
14
|
+
const MAX_ARTIFACTS = 32;
|
|
15
|
+
const MAX_CANONICAL_EVIDENCE = 256;
|
|
16
|
+
const MAX_OBSERVED_ARTIFACTS = 128;
|
|
17
|
+
const MAX_OBSERVED_ARTIFACT_BYTES = 8 * 1_048_576;
|
|
18
|
+
const CONTROL_ARTIFACTS = new Set(["state.json"]);
|
|
19
|
+
/** Derive bounded adapter context without trusting adapter telemetry. */
|
|
20
|
+
export function deriveBuilderGateActionEnvelope(input) {
|
|
21
|
+
const loaded = loadGateAction(input);
|
|
22
|
+
const derived = deriveFlowRequirements(input, loaded.action);
|
|
23
|
+
const envelope = assembleGateActionEnvelope(input, loaded, derived);
|
|
24
|
+
assertBoundedEnvelope(envelope);
|
|
25
|
+
return envelope;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Canonical progress is useful after a run becomes terminal, when no adapter
|
|
29
|
+
* action envelope may be emitted. Keep this deliberately separate from the
|
|
30
|
+
* request-only envelope so terminal snapshots cannot be mistaken for work.
|
|
31
|
+
*/
|
|
32
|
+
export function deriveBuilderGateActionProgressSnapshot(input) {
|
|
33
|
+
const { actions } = loadGateAction(input);
|
|
34
|
+
return {
|
|
35
|
+
current_step: input.run.state.current_step,
|
|
36
|
+
canonical_status: input.run.state.status,
|
|
37
|
+
canonical_evidence: canonicalEvidence(input.run.manifest),
|
|
38
|
+
observed_artifacts: observeBuilderArtifactsForProgress(input.sessionDir, actions.flatMap((entry) => entry.artifacts)),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function loadGateAction(input) {
|
|
42
|
+
const packageRoot = flowAgentsPackageRoot();
|
|
43
|
+
const packageMetadata = readBoundedJson(packageRoot, "package.json", "flow-agents package metadata");
|
|
44
|
+
if (typeof packageMetadata.version !== "string" || !packageMetadata.version)
|
|
45
|
+
throw new Error("flow-agents package metadata has no version");
|
|
46
|
+
const packageVersion = packageMetadata.version;
|
|
47
|
+
const kit = readBoundedJson(packageRoot, path.join("kits", "builder", "kit.json"), "Builder kit metadata");
|
|
48
|
+
const parsed = parseKitFlowStepActions(kit, "kits/builder/kit.json");
|
|
49
|
+
if (parsed.errors.length)
|
|
50
|
+
throw new Error(`Builder gate-action metadata is invalid: ${parsed.errors.join("; ")}`);
|
|
51
|
+
const actions = parsed.entries.filter((entry) => entry.flow_id === input.run.definitionId);
|
|
52
|
+
const selected = actions.filter((entry) => entry.step_id === input.run.state.current_step);
|
|
53
|
+
if (selected.length !== 1)
|
|
54
|
+
throw new Error(`Builder gate-action metadata must declare exactly one action for ${input.run.definitionId}/${input.run.state.current_step}`);
|
|
55
|
+
const action = selected[0];
|
|
56
|
+
const actionableArtifacts = action.artifacts.filter((artifact) => !isControlArtifact(artifact));
|
|
57
|
+
if (action.skills.length > MAX_SKILLS || action.artifacts.length > MAX_ARTIFACTS) {
|
|
58
|
+
throw new Error("Builder gate-action metadata exceeds the supported envelope bound");
|
|
59
|
+
}
|
|
60
|
+
return { packageRoot, packageVersion, kit, action, actions, actionableArtifacts };
|
|
61
|
+
}
|
|
62
|
+
function deriveFlowRequirements(input, action) {
|
|
63
|
+
const gates = openGates(input.definition, input.run.state);
|
|
64
|
+
const acceptedExceptions = [];
|
|
65
|
+
const requirements = gates.flatMap((gate) => {
|
|
66
|
+
const outcome = evaluateGate(input.definition, input.run.state, input.run.manifest, gate.id, input.run.config);
|
|
67
|
+
if (typeof outcome.accepted_exception_id === "string") {
|
|
68
|
+
acceptedExceptions.push({ gate_id: gate.id, exception_id: outcome.accepted_exception_id });
|
|
69
|
+
}
|
|
70
|
+
const matched = new Set((Array.isArray(outcome.matched_expectations) ? outcome.matched_expectations : [])
|
|
71
|
+
.flatMap((entry) => isRecord(entry) && typeof entry.expectation_id === "string" ? [entry.expectation_id] : []));
|
|
72
|
+
return expectationsForGate(gate, input.run.config)
|
|
73
|
+
.map((expectation) => requirementFromExpectation(gate.id, expectation, matched, typeof outcome.accepted_exception_id === "string"));
|
|
74
|
+
});
|
|
75
|
+
if (requirements.length > MAX_REQUIREMENTS)
|
|
76
|
+
throw new Error("Builder gate-action envelope requirements exceed the supported bound");
|
|
77
|
+
if (!sameSet(action.expectation_ids, requirements.map((requirement) => requirement.id))) {
|
|
78
|
+
throw new Error(`Builder gate-action metadata evidence does not exactly match canonical Flow requirements for ${input.run.definitionId}/${input.run.state.current_step}`);
|
|
79
|
+
}
|
|
80
|
+
const unresolved = requirements.filter((requirement) => requirement.status === "unresolved").map((requirement) => requirement.id);
|
|
81
|
+
const unresolvedRequired = requirements.filter((requirement) => requirement.required && requirement.status === "unresolved").map((requirement) => requirement.id);
|
|
82
|
+
return { gates, requirements, unresolved, unresolvedRequired, acceptedExceptions };
|
|
83
|
+
}
|
|
84
|
+
function assembleGateActionEnvelope(input, loaded, derived) {
|
|
85
|
+
const { packageRoot, packageVersion, kit, action, actions, actionableArtifacts } = loaded;
|
|
86
|
+
const { gates, requirements, unresolved, unresolvedRequired, acceptedExceptions } = derived;
|
|
87
|
+
const sessionDir = path.resolve(input.sessionDir);
|
|
88
|
+
const sessionArgument = sessionPathForPublicCommand(input.projectRoot, sessionDir);
|
|
89
|
+
const statusCommand = pinnedFlowAgentsCommand(packageVersion, ["workflow", "status", "--session-dir", sessionArgument, "--json"]);
|
|
90
|
+
const requiredArtifacts = action.artifact_bindings
|
|
91
|
+
.filter((binding) => !isControlArtifact(binding.artifact) && binding.expectation_ids.some((id) => unresolvedRequired.includes(id)))
|
|
92
|
+
.map((binding) => binding.artifact);
|
|
93
|
+
const envelope = {
|
|
94
|
+
schema_version: "2.0",
|
|
95
|
+
flow: {
|
|
96
|
+
run_id: input.run.runId,
|
|
97
|
+
definition_id: input.run.definitionId,
|
|
98
|
+
definition_version: input.run.definitionVersion,
|
|
99
|
+
status: input.run.state.status,
|
|
100
|
+
current_step: input.run.state.current_step,
|
|
101
|
+
gate_ids: gates.map((gate) => gate.id),
|
|
102
|
+
},
|
|
103
|
+
gate: { requirements, unresolved_requirement_ids: unresolved, accepted_exceptions: acceptedExceptions },
|
|
104
|
+
action: envelopeAction(action, actionableArtifacts, kit, packageRoot, packageVersion),
|
|
105
|
+
public_interfaces: {
|
|
106
|
+
status: { command: statusCommand },
|
|
107
|
+
mutations: action.expectation_bindings.map((binding) => publicMutation(binding, sessionArgument, packageVersion)),
|
|
108
|
+
},
|
|
109
|
+
stop_condition: envelopeStopCondition(input, gates, action, requiredArtifacts, unresolvedRequired),
|
|
110
|
+
progress: {
|
|
111
|
+
canonical_evidence: canonicalEvidence(input.run.manifest),
|
|
112
|
+
observed_artifacts: observeBuilderArtifactsForProgress(sessionDir, actions.flatMap((entry) => entry.artifacts)),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
return envelope;
|
|
116
|
+
}
|
|
117
|
+
function envelopeAction(action, artifacts, kit, packageRoot, packageVersion) {
|
|
118
|
+
return {
|
|
119
|
+
skills: action.skills.map((skill) => skillIdentity(kit, packageRoot, packageVersion, skill)),
|
|
120
|
+
operations: [...action.operations],
|
|
121
|
+
declared_artifacts: [...artifacts],
|
|
122
|
+
declared_evidence: [...action.expectation_ids],
|
|
123
|
+
implementation_allowed: action.implementation_allowed,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function envelopeStopCondition(input, gates, action, artifactRefs, unresolvedEvidenceIds) {
|
|
127
|
+
const operation = action.operations[0];
|
|
128
|
+
const protocol = operation ? PUBLIC_OPERATION_CONTRACTS[operation] : undefined;
|
|
129
|
+
return {
|
|
130
|
+
kind: "one_turn",
|
|
131
|
+
scope: { run_id: input.run.runId, current_step: input.run.state.current_step, gate_ids: gates.map((gate) => gate.id), current_gate_only: true },
|
|
132
|
+
required: { skill_ids: unresolvedEvidenceIds.length > 0 ? action.skills : [], artifact_refs: artifactRefs, unresolved_evidence_ids: unresolvedEvidenceIds },
|
|
133
|
+
sequence: ["activate_required_skills", "produce_declared_artifacts", "record_bound_evidence", "synchronize_canonical_flow", "return_adapter_result"],
|
|
134
|
+
after: "return_adapter_result",
|
|
135
|
+
synchronize_canonical_flow: true,
|
|
136
|
+
adapter_evidence_is_gate_evidence: false,
|
|
137
|
+
...(protocol?.availability.status === "external_capability_required" ? {
|
|
138
|
+
external_capability: {
|
|
139
|
+
status: "waiting",
|
|
140
|
+
operation: protocol.operation,
|
|
141
|
+
capability: protocol.capability,
|
|
142
|
+
completion: "external_verification_required",
|
|
143
|
+
},
|
|
144
|
+
} : {}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function gateActionProgressSnapshot(envelope) {
|
|
148
|
+
return {
|
|
149
|
+
current_step: envelope.flow.current_step,
|
|
150
|
+
canonical_status: envelope.flow.status,
|
|
151
|
+
canonical_evidence: [...envelope.progress.canonical_evidence],
|
|
152
|
+
observed_artifacts: [...envelope.progress.observed_artifacts],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export function withGateActionPriorProgress(envelope, priorTurn) {
|
|
156
|
+
const copy = structuredClone(envelope);
|
|
157
|
+
copy.progress.prior_turn = structuredClone(priorTurn);
|
|
158
|
+
assertBoundedEnvelope(copy);
|
|
159
|
+
return copy;
|
|
160
|
+
}
|
|
161
|
+
function publicMutation(binding, sessionArgument, packageVersion) {
|
|
162
|
+
if (binding.interface === "operation") {
|
|
163
|
+
const operation = binding.operation;
|
|
164
|
+
const protocol = PUBLIC_OPERATION_CONTRACTS[operation];
|
|
165
|
+
if (!protocol)
|
|
166
|
+
throw new Error(`Builder gate-action operation '${operation}' has no canonical public protocol`);
|
|
167
|
+
return {
|
|
168
|
+
expectation_id: binding.expectation_id,
|
|
169
|
+
interface: "operation",
|
|
170
|
+
operation,
|
|
171
|
+
protocol: structuredClone(protocol),
|
|
172
|
+
completion: {
|
|
173
|
+
status: "external_verification_required",
|
|
174
|
+
executable_by_flow_agents: false,
|
|
175
|
+
gate_evidence_interface: null,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (binding.interface === "workflow.critique") {
|
|
180
|
+
return {
|
|
181
|
+
expectation_id: binding.expectation_id,
|
|
182
|
+
interface: binding.interface,
|
|
183
|
+
package: { name: "@kontourai/flow-agents", version: packageVersion },
|
|
184
|
+
command: "flow-agents",
|
|
185
|
+
argv: ["workflow", "critique", "--session-dir", sessionArgument, "--json"],
|
|
186
|
+
parameters: [
|
|
187
|
+
{ name: "id", flag: "--id", required: false },
|
|
188
|
+
{ name: "verdict", flag: "--verdict", required: true, allowed_values: [...WORKFLOW_CRITIQUE_STATUSES] },
|
|
189
|
+
{ name: "summary", flag: "--summary", required: true },
|
|
190
|
+
{ name: "lane_json", flag: "--lane-json", required: true, repeatable: true },
|
|
191
|
+
{ name: "artifact_ref", flag: "--artifact-ref", required: false, repeatable: true, required_when: { parameter: "verdict", equals: "pass" } },
|
|
192
|
+
{ name: "finding_json", flag: "--finding-json", required: false, repeatable: true },
|
|
193
|
+
{ name: "timestamp", flag: "--timestamp", required: false },
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return workflowEvidenceMutation(binding.expectation_id, sessionArgument, packageVersion);
|
|
198
|
+
}
|
|
199
|
+
function workflowEvidenceMutation(expectationId, sessionArgument, packageVersion) {
|
|
200
|
+
return {
|
|
201
|
+
expectation_id: expectationId,
|
|
202
|
+
interface: "workflow.evidence",
|
|
203
|
+
package: { name: "@kontourai/flow-agents", version: packageVersion },
|
|
204
|
+
command: "flow-agents",
|
|
205
|
+
argv: ["workflow", "evidence", "--session-dir", sessionArgument, "--expectation", expectationId, "--json"],
|
|
206
|
+
parameters: [
|
|
207
|
+
{ name: "status", flag: "--status", required: true, allowed_values: ["pass", "fail", "not_verified"] },
|
|
208
|
+
{ name: "summary", flag: "--summary", required: true },
|
|
209
|
+
{ name: "evidence_ref_json", flag: "--evidence-ref-json", required: true, repeatable: true },
|
|
210
|
+
{ name: "route_reason", flag: "--route-reason", required: false },
|
|
211
|
+
{ name: "criterion_json", flag: "--criterion-json", required: false, repeatable: true },
|
|
212
|
+
{ name: "accepted_gap_reason", flag: "--accepted-gap-reason", required: false },
|
|
213
|
+
{ name: "waived_by", flag: "--waived-by", required: false },
|
|
214
|
+
{ name: "command", flag: "--command", required: false, repeatable: true },
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function requirementFromExpectation(gateId, expectation, satisfied, acceptedException) {
|
|
219
|
+
const record = expectation;
|
|
220
|
+
const claim = isRecord(record.bundle_claim) ? record.bundle_claim : null;
|
|
221
|
+
if (typeof record.id !== "string" || typeof record.description !== "string" || !claim || typeof claim.claimType !== "string") {
|
|
222
|
+
throw new Error("canonical Flow gate contains malformed expectation metadata");
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
id: record.id,
|
|
226
|
+
gate_id: gateId,
|
|
227
|
+
required: record.required === true,
|
|
228
|
+
description: record.description,
|
|
229
|
+
claim_type: claim.claimType,
|
|
230
|
+
subject_type: typeof claim.subjectType === "string" ? claim.subjectType : null,
|
|
231
|
+
status: satisfied.has(record.id) ? "satisfied" : acceptedException ? "accepted_exception" : "unresolved",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function skillIdentity(kit, packageRoot, version, skill) {
|
|
235
|
+
const skills = Array.isArray(kit.skills) ? kit.skills : [];
|
|
236
|
+
const entry = skills.find((candidate) => isRecord(candidate) && candidate.id === `builder.${skill}`);
|
|
237
|
+
if (!entry || typeof entry.path !== "string")
|
|
238
|
+
throw new Error(`Builder gate-action skill '${skill}' has no installed skill source`);
|
|
239
|
+
const kitRoot = path.join(packageRoot, "kits", "builder");
|
|
240
|
+
const source = readStableRegularFile(kitRoot, entry.path, `Builder skill '${skill}'`, MAX_METADATA_BYTES);
|
|
241
|
+
if (!source)
|
|
242
|
+
throw new Error(`Builder skill '${skill}' has no installed skill source`);
|
|
243
|
+
return {
|
|
244
|
+
id: skill,
|
|
245
|
+
package: { name: "@kontourai/flow-agents", version },
|
|
246
|
+
path: path.relative(fs.realpathSync(packageRoot), source.path).split(path.sep).join("/"),
|
|
247
|
+
sha256: createHash("sha256").update(source.bytes).digest("hex"),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function canonicalEvidence(manifest) {
|
|
251
|
+
const ids = (Array.isArray(manifest.evidence) ? manifest.evidence : []).flatMap((entry) => {
|
|
252
|
+
if (!isRecord(entry) || entry.superseded_by || typeof entry.gate_id !== "string")
|
|
253
|
+
return [];
|
|
254
|
+
const identity = typeof entry.sha256 === "string" ? entry.sha256 : typeof entry.id === "string" ? entry.id : null;
|
|
255
|
+
return identity ? [`${entry.gate_id}:${identity}`] : [];
|
|
256
|
+
});
|
|
257
|
+
const unique = [...new Set(ids)].sort();
|
|
258
|
+
if (unique.length > MAX_CANONICAL_EVIDENCE)
|
|
259
|
+
throw new Error("canonical Flow evidence exceeds the supported envelope bound");
|
|
260
|
+
return unique;
|
|
261
|
+
}
|
|
262
|
+
export function observeBuilderArtifactsForProgress(sessionDir, artifacts) {
|
|
263
|
+
const observed = [];
|
|
264
|
+
const candidates = [...new Set(artifacts)].filter((artifact) => !artifact.includes("#") && !isControlArtifact(artifact));
|
|
265
|
+
if (candidates.length > MAX_OBSERVED_ARTIFACTS)
|
|
266
|
+
throw new Error(`Builder artifact progress exceeds ${MAX_OBSERVED_ARTIFACTS} unique files`);
|
|
267
|
+
const aggregateBudget = { remaining: MAX_OBSERVED_ARTIFACT_BYTES };
|
|
268
|
+
for (const artifact of candidates) {
|
|
269
|
+
const relative = artifact.replaceAll("<slug>", path.basename(sessionDir));
|
|
270
|
+
const file = readStableRegularFile(sessionDir, relative, `Builder artifact '${artifact}'`, MAX_METADATA_BYTES, false, aggregateBudget);
|
|
271
|
+
observed.push(file
|
|
272
|
+
? `${artifact}:${createHash("sha256").update(file.bytes).digest("hex")}`
|
|
273
|
+
: `${artifact}:absent`);
|
|
274
|
+
}
|
|
275
|
+
return observed.sort();
|
|
276
|
+
}
|
|
277
|
+
function isControlArtifact(artifact) {
|
|
278
|
+
return CONTROL_ARTIFACTS.has(path.posix.normalize(artifact.replaceAll("\\", "/")));
|
|
279
|
+
}
|
|
280
|
+
function readBoundedJson(root, candidate, label) {
|
|
281
|
+
const file = readStableRegularFile(root, candidate, label, MAX_METADATA_BYTES);
|
|
282
|
+
if (!file)
|
|
283
|
+
throw new Error(`${label} is missing`);
|
|
284
|
+
const value = JSON.parse(file.bytes.toString("utf8"));
|
|
285
|
+
if (!isRecord(value))
|
|
286
|
+
throw new Error(`${label} must be a JSON object`);
|
|
287
|
+
return value;
|
|
288
|
+
}
|
|
289
|
+
function readStableRegularFile(root, candidate, label, maxBytes, required = true, aggregateBudget) {
|
|
290
|
+
if (path.isAbsolute(candidate) || candidate.includes("\0"))
|
|
291
|
+
throw new Error(`${label} must be a relative path`);
|
|
292
|
+
const canonicalRoot = fs.realpathSync(root);
|
|
293
|
+
const resolved = path.resolve(canonicalRoot, candidate);
|
|
294
|
+
const relative = path.relative(canonicalRoot, resolved);
|
|
295
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
296
|
+
throw new Error(`${label} must remain within its package or session`);
|
|
297
|
+
}
|
|
298
|
+
let fd;
|
|
299
|
+
try {
|
|
300
|
+
const canonicalParentBefore = fs.realpathSync(path.dirname(resolved));
|
|
301
|
+
assertWithinRoot(canonicalRoot, canonicalParentBefore, label);
|
|
302
|
+
const parentBefore = fs.statSync(canonicalParentBefore);
|
|
303
|
+
if (!parentBefore.isDirectory())
|
|
304
|
+
throw new Error(`${label} parent must be a directory`);
|
|
305
|
+
if (typeof fsConstants.O_NOFOLLOW !== "number")
|
|
306
|
+
throw new Error(`${label} cannot be read safely because O_NOFOLLOW is unavailable`);
|
|
307
|
+
fd = fs.openSync(resolved, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
308
|
+
const before = fs.fstatSync(fd);
|
|
309
|
+
if (!before.isFile() || before.size > maxBytes)
|
|
310
|
+
throw new Error(`${label} must be a bounded regular file`);
|
|
311
|
+
if (aggregateBudget && before.size > aggregateBudget.remaining)
|
|
312
|
+
throw new Error(`Builder artifact progress exceeds ${MAX_OBSERVED_ARTIFACT_BYTES} aggregate bytes`);
|
|
313
|
+
if (aggregateBudget)
|
|
314
|
+
aggregateBudget.remaining -= before.size;
|
|
315
|
+
const pathBefore = fs.lstatSync(resolved);
|
|
316
|
+
if (pathBefore.isSymbolicLink() || !sameIdentity(before, pathBefore))
|
|
317
|
+
throw new Error(`${label} changed identity while opening`);
|
|
318
|
+
const bytes = fs.readFileSync(fd);
|
|
319
|
+
const after = fs.fstatSync(fd);
|
|
320
|
+
if (!sameIdentity(before, after) || before.size !== after.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs || bytes.length !== after.size) {
|
|
321
|
+
throw new Error(`${label} changed while reading`);
|
|
322
|
+
}
|
|
323
|
+
const pathAfter = fs.lstatSync(resolved);
|
|
324
|
+
if (pathAfter.isSymbolicLink() || !sameIdentity(after, pathAfter))
|
|
325
|
+
throw new Error(`${label} changed identity while reading`);
|
|
326
|
+
const canonicalParentAfter = fs.realpathSync(path.dirname(resolved));
|
|
327
|
+
const parentAfter = fs.statSync(canonicalParentAfter);
|
|
328
|
+
if (canonicalParentAfter !== canonicalParentBefore || !sameIdentity(parentBefore, parentAfter))
|
|
329
|
+
throw new Error(`${label} parent changed identity while reading`);
|
|
330
|
+
assertWithinRoot(canonicalRoot, canonicalParentAfter, label);
|
|
331
|
+
return { path: resolved, bytes };
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
if (!required && error.code === "ENOENT")
|
|
335
|
+
return null;
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
if (fd !== undefined)
|
|
340
|
+
fs.closeSync(fd);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function assertWithinRoot(root, candidate, label) {
|
|
344
|
+
const relative = path.relative(root, candidate);
|
|
345
|
+
if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
346
|
+
throw new Error(`${label} must remain within its package or session`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function sameIdentity(left, right) {
|
|
350
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
351
|
+
}
|
|
352
|
+
function sessionPathForPublicCommand(projectRoot, sessionDir) {
|
|
353
|
+
const relative = path.relative(path.resolve(projectRoot), sessionDir);
|
|
354
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
355
|
+
throw new Error("Builder session must remain within the project root for public commands");
|
|
356
|
+
}
|
|
357
|
+
return relative;
|
|
358
|
+
}
|
|
359
|
+
function assertBoundedEnvelope(envelope) {
|
|
360
|
+
if (Buffer.byteLength(JSON.stringify(envelope), "utf8") > MAX_ENVELOPE_BYTES)
|
|
361
|
+
throw new Error("Builder gate-action envelope exceeds 65536 bytes");
|
|
362
|
+
}
|
|
363
|
+
function sameSet(left, right) {
|
|
364
|
+
return left.length === right.length && new Set(left).size === left.length && left.every((entry) => right.includes(entry));
|
|
365
|
+
}
|
|
366
|
+
function isRecord(value) {
|
|
367
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
368
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export declare const WORKFLOW_CRITIQUE_STATUSES: readonly ["pass", "fail", "not_verified"];
|
|
2
|
+
export declare const PUBLISH_CHANGE_OPERATION: "publish-change";
|
|
3
|
+
export declare const PUBLISH_CHANGE_OPERATION_PROTOCOL: {
|
|
4
|
+
readonly schema_version: "1.0";
|
|
5
|
+
readonly operation: "publish-change";
|
|
6
|
+
readonly kind: "provider_capability";
|
|
7
|
+
readonly capability: "pull_request.create";
|
|
8
|
+
readonly parameters: readonly [{
|
|
9
|
+
readonly name: "title";
|
|
10
|
+
readonly required: true;
|
|
11
|
+
readonly type: "string";
|
|
12
|
+
readonly max_length: 512;
|
|
13
|
+
}, {
|
|
14
|
+
readonly name: "body";
|
|
15
|
+
readonly required: true;
|
|
16
|
+
readonly type: "string";
|
|
17
|
+
readonly max_length: 65536;
|
|
18
|
+
}, {
|
|
19
|
+
readonly name: "head_ref";
|
|
20
|
+
readonly required: true;
|
|
21
|
+
readonly type: "string";
|
|
22
|
+
readonly max_length: 255;
|
|
23
|
+
}, {
|
|
24
|
+
readonly name: "base_ref";
|
|
25
|
+
readonly required: true;
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
readonly max_length: 255;
|
|
28
|
+
}, {
|
|
29
|
+
readonly name: "draft";
|
|
30
|
+
readonly required: false;
|
|
31
|
+
readonly type: "boolean";
|
|
32
|
+
}];
|
|
33
|
+
readonly result: {
|
|
34
|
+
readonly required: readonly ["provider", "repository", "number", "url", "head_ref", "base_ref"];
|
|
35
|
+
readonly properties: {
|
|
36
|
+
readonly provider: {
|
|
37
|
+
readonly type: "string";
|
|
38
|
+
readonly max_length: 128;
|
|
39
|
+
};
|
|
40
|
+
readonly repository: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
readonly max_length: 1024;
|
|
43
|
+
};
|
|
44
|
+
readonly number: {
|
|
45
|
+
readonly type: "integer";
|
|
46
|
+
readonly minimum: 1;
|
|
47
|
+
};
|
|
48
|
+
readonly url: {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
readonly max_length: 8192;
|
|
51
|
+
};
|
|
52
|
+
readonly head_ref: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly max_length: 255;
|
|
55
|
+
};
|
|
56
|
+
readonly base_ref: {
|
|
57
|
+
readonly type: "string";
|
|
58
|
+
readonly max_length: 255;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
readonly url_protocols: readonly ["https:"];
|
|
62
|
+
readonly persist_as: "publish-change.result.json";
|
|
63
|
+
};
|
|
64
|
+
readonly availability: {
|
|
65
|
+
readonly status: "external_capability_required";
|
|
66
|
+
readonly executable_by_flow_agents: false;
|
|
67
|
+
readonly completion_verification: "authenticated_change_provider_required";
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export declare const PUBLIC_OPERATION_CONTRACTS: {
|
|
71
|
+
readonly "publish-change": {
|
|
72
|
+
readonly schema_version: "1.0";
|
|
73
|
+
readonly operation: "publish-change";
|
|
74
|
+
readonly kind: "provider_capability";
|
|
75
|
+
readonly capability: "pull_request.create";
|
|
76
|
+
readonly parameters: readonly [{
|
|
77
|
+
readonly name: "title";
|
|
78
|
+
readonly required: true;
|
|
79
|
+
readonly type: "string";
|
|
80
|
+
readonly max_length: 512;
|
|
81
|
+
}, {
|
|
82
|
+
readonly name: "body";
|
|
83
|
+
readonly required: true;
|
|
84
|
+
readonly type: "string";
|
|
85
|
+
readonly max_length: 65536;
|
|
86
|
+
}, {
|
|
87
|
+
readonly name: "head_ref";
|
|
88
|
+
readonly required: true;
|
|
89
|
+
readonly type: "string";
|
|
90
|
+
readonly max_length: 255;
|
|
91
|
+
}, {
|
|
92
|
+
readonly name: "base_ref";
|
|
93
|
+
readonly required: true;
|
|
94
|
+
readonly type: "string";
|
|
95
|
+
readonly max_length: 255;
|
|
96
|
+
}, {
|
|
97
|
+
readonly name: "draft";
|
|
98
|
+
readonly required: false;
|
|
99
|
+
readonly type: "boolean";
|
|
100
|
+
}];
|
|
101
|
+
readonly result: {
|
|
102
|
+
readonly required: readonly ["provider", "repository", "number", "url", "head_ref", "base_ref"];
|
|
103
|
+
readonly properties: {
|
|
104
|
+
readonly provider: {
|
|
105
|
+
readonly type: "string";
|
|
106
|
+
readonly max_length: 128;
|
|
107
|
+
};
|
|
108
|
+
readonly repository: {
|
|
109
|
+
readonly type: "string";
|
|
110
|
+
readonly max_length: 1024;
|
|
111
|
+
};
|
|
112
|
+
readonly number: {
|
|
113
|
+
readonly type: "integer";
|
|
114
|
+
readonly minimum: 1;
|
|
115
|
+
};
|
|
116
|
+
readonly url: {
|
|
117
|
+
readonly type: "string";
|
|
118
|
+
readonly max_length: 8192;
|
|
119
|
+
};
|
|
120
|
+
readonly head_ref: {
|
|
121
|
+
readonly type: "string";
|
|
122
|
+
readonly max_length: 255;
|
|
123
|
+
};
|
|
124
|
+
readonly base_ref: {
|
|
125
|
+
readonly type: "string";
|
|
126
|
+
readonly max_length: 255;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
readonly url_protocols: readonly ["https:"];
|
|
130
|
+
readonly persist_as: "publish-change.result.json";
|
|
131
|
+
};
|
|
132
|
+
readonly availability: {
|
|
133
|
+
readonly status: "external_capability_required";
|
|
134
|
+
readonly executable_by_flow_agents: false;
|
|
135
|
+
readonly completion_verification: "authenticated_change_provider_required";
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
export declare const PUBLIC_OPERATION_IDS: Set<string>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const WORKFLOW_CRITIQUE_STATUSES = ["pass", "fail", "not_verified"];
|
|
2
|
+
export const PUBLISH_CHANGE_OPERATION = "publish-change";
|
|
3
|
+
export const PUBLISH_CHANGE_OPERATION_PROTOCOL = {
|
|
4
|
+
schema_version: "1.0",
|
|
5
|
+
operation: PUBLISH_CHANGE_OPERATION,
|
|
6
|
+
kind: "provider_capability",
|
|
7
|
+
capability: "pull_request.create",
|
|
8
|
+
parameters: [
|
|
9
|
+
{ name: "title", required: true, type: "string", max_length: 512 },
|
|
10
|
+
{ name: "body", required: true, type: "string", max_length: 65_536 },
|
|
11
|
+
{ name: "head_ref", required: true, type: "string", max_length: 255 },
|
|
12
|
+
{ name: "base_ref", required: true, type: "string", max_length: 255 },
|
|
13
|
+
{ name: "draft", required: false, type: "boolean" },
|
|
14
|
+
],
|
|
15
|
+
result: {
|
|
16
|
+
required: ["provider", "repository", "number", "url", "head_ref", "base_ref"],
|
|
17
|
+
properties: {
|
|
18
|
+
provider: { type: "string", max_length: 128 },
|
|
19
|
+
repository: { type: "string", max_length: 1_024 },
|
|
20
|
+
number: { type: "integer", minimum: 1 },
|
|
21
|
+
url: { type: "string", max_length: 8_192 },
|
|
22
|
+
head_ref: { type: "string", max_length: 255 },
|
|
23
|
+
base_ref: { type: "string", max_length: 255 },
|
|
24
|
+
},
|
|
25
|
+
url_protocols: ["https:"],
|
|
26
|
+
persist_as: "publish-change.result.json",
|
|
27
|
+
},
|
|
28
|
+
availability: {
|
|
29
|
+
status: "external_capability_required",
|
|
30
|
+
executable_by_flow_agents: false,
|
|
31
|
+
completion_verification: "authenticated_change_provider_required",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export const PUBLIC_OPERATION_CONTRACTS = {
|
|
35
|
+
[PUBLISH_CHANGE_OPERATION]: PUBLISH_CHANGE_OPERATION_PROTOCOL,
|
|
36
|
+
};
|
|
37
|
+
export const PUBLIC_OPERATION_IDS = new Set(Object.keys(PUBLIC_OPERATION_CONTRACTS));
|
|
@@ -14,6 +14,7 @@ import { flowAgentsPackageRoot, flowAgentsPackageVersion } from "../lib/package-
|
|
|
14
14
|
import { pinnedFlowAgentsCommand } from "../lib/pinned-cli-command.js";
|
|
15
15
|
import { runObservedCommand } from "../lib/observed-command.js";
|
|
16
16
|
import { captureReviewWorkspaceSnapshot, startBuilderFlowSession, syncBuilderFlowSession } from "../builder-flow-runtime.js";
|
|
17
|
+
import { WORKFLOW_CRITIQUE_STATUSES } from "./public-contracts.js";
|
|
17
18
|
// #291 Wave 1 Task 1.1 exports: ensure-session's ownership guard reuses the EXACT same
|
|
18
19
|
// assignment ⋈ liveness join / claim / supersede logic #290 already ships for the
|
|
19
20
|
// `assignment-provider` CLI, rather than reimplementing a second, parallel join (static ESM
|
|
@@ -2514,24 +2515,19 @@ function expectedGateProducer(flowId, stepId, expectationId) {
|
|
|
2514
2515
|
const action = actions.find((candidate) => candidate.flow_id === flowId && candidate.step_id === stepId);
|
|
2515
2516
|
if (!action)
|
|
2516
2517
|
die(`record-gate-claim cannot derive a producer for unknown Flow step ${flowId}/${stepId}`);
|
|
2518
|
+
const binding = Array.isArray(action.expectation_bindings)
|
|
2519
|
+
? action.expectation_bindings.find((candidate) => candidate && typeof candidate === "object" && !Array.isArray(candidate) && candidate.expectation_id === expectationId)
|
|
2520
|
+
: undefined;
|
|
2521
|
+
if (binding?.interface === "operation") {
|
|
2522
|
+
const operation = typeof binding.operation === "string" ? binding.operation : "the declared external operation";
|
|
2523
|
+
die(`record-gate-claim cannot satisfy operation-bound expectation ${expectationId}; ${operation} requires authenticated external ChangeProvider completion`);
|
|
2524
|
+
}
|
|
2517
2525
|
const skills = Array.isArray(action.skills) ? action.skills.filter((value) => typeof value === "string") : [];
|
|
2518
2526
|
const roles = Array.isArray(manifest.skill_roles) ? manifest.skill_roles : [];
|
|
2519
2527
|
const owners = roles.filter((role) => typeof role.skill_id === "string"
|
|
2520
2528
|
&& Array.isArray(role.step_ids) && role.step_ids.includes(stepId)
|
|
2521
2529
|
&& Array.isArray(role.expectation_ids) && role.expectation_ids.includes(expectationId)
|
|
2522
2530
|
&& skills.includes(role.skill_id.replace(/^builder\./, "")));
|
|
2523
|
-
if (owners.length === 0) {
|
|
2524
|
-
const operations = Array.isArray(action.operations) ? action.operations.filter((value) => typeof value === "string") : [];
|
|
2525
|
-
const operationExpectations = Array.isArray(action.expectation_ids) ? action.expectation_ids : [];
|
|
2526
|
-
if (operations.length === 1 && operationExpectations.includes(expectationId)) {
|
|
2527
|
-
const artifacts = Array.isArray(action.artifacts) ? action.artifacts.filter((value) => typeof value === "string") : [];
|
|
2528
|
-
return {
|
|
2529
|
-
id: `operation:${operations[0]}`,
|
|
2530
|
-
artifactPatterns: artifacts.filter((value) => !value.includes("#")),
|
|
2531
|
-
selfProducedTrustSlices: artifacts.filter((value) => value.startsWith("trust.bundle#")).map((value) => value.slice("trust.bundle#".length)),
|
|
2532
|
-
};
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
2531
|
if (owners.length !== 1)
|
|
2536
2532
|
die(`record-gate-claim cannot derive exactly one producer for ${flowId}/${stepId}/${expectationId}`);
|
|
2537
2533
|
const owner = owners[0];
|
|
@@ -2820,7 +2816,7 @@ function completePassingCriteria(existing, raw, observedCommands, verifiedAt) {
|
|
|
2820
2816
|
return { ...expectedById.get(ids[index]), status: "pass", evidence_refs: refs, identity_version: 2, verified_at: verifiedAt };
|
|
2821
2817
|
});
|
|
2822
2818
|
}
|
|
2823
|
-
const critiqueStatuses = new Set(
|
|
2819
|
+
const critiqueStatuses = new Set(WORKFLOW_CRITIQUE_STATUSES);
|
|
2824
2820
|
const safeCritiqueId = /^[a-z][a-z0-9_-]*$/;
|
|
2825
2821
|
function normalizeCritiqueLanes(raw) {
|
|
2826
2822
|
if (raw.length === 0)
|