@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
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { readJson } from "../lib/fs.js";
|
|
4
|
+
import { parseKitFlowStepActions, workflowTriggerIdentifier } from "./action-metadata.js";
|
|
5
|
+
import { validateActionRepositoryMetadata } from "./action-repository-validation.js";
|
|
6
|
+
export { isObservableBuilderArtifactRef, isSafeBuilderArtifactRef, parseKitFlowStepActions } from "./action-metadata.js";
|
|
4
7
|
// Extension-only asset classes: validated by Flow Agents. Flows are validated by @kontourai/flow.
|
|
5
8
|
const EXTENSION_ASSET_CLASSES = ["skills", "docs", "adapters", "evals", "assets"];
|
|
6
9
|
// Core container fields owned by kontourai/flow (flow-kit-container.schema.json).
|
|
@@ -15,88 +18,6 @@ const AGENT_EXTENSION_CLASSES = new Set(["skills", "docs", "adapters", "evals",
|
|
|
15
18
|
// and first_party is legacy catalog/marketplace metadata. It does not grant runtime
|
|
16
19
|
// capability or steering privilege.
|
|
17
20
|
const KNOWN_METADATA_FIELDS = new Set(["dependencies", "workflow_triggers", "hook_influence_expectations", "flow_step_actions", "skill_roles", "first_party"]);
|
|
18
|
-
const MAX_FLOW_DEFINITION_BYTES = 1024 * 1024;
|
|
19
|
-
function sameFileIdentity(left, right) {
|
|
20
|
-
return left.dev === right.dev && left.ino === right.ino;
|
|
21
|
-
}
|
|
22
|
-
function lstatSafePath(root, relativePath) {
|
|
23
|
-
const parts = relativePath.split(path.sep);
|
|
24
|
-
let current = root;
|
|
25
|
-
for (const [index, part] of parts.entries()) {
|
|
26
|
-
if (!part || part === "." || part === "..")
|
|
27
|
-
return { error: "path must stay inside the kit directory" };
|
|
28
|
-
current = path.join(current, part);
|
|
29
|
-
const stat = fs.lstatSync(current);
|
|
30
|
-
if (stat.isSymbolicLink())
|
|
31
|
-
return { error: "path must not traverse a symbolic link" };
|
|
32
|
-
if (index < parts.length - 1 && !stat.isDirectory())
|
|
33
|
-
return { error: "path component must be a directory" };
|
|
34
|
-
if (index === parts.length - 1)
|
|
35
|
-
return { file: current, stat };
|
|
36
|
-
}
|
|
37
|
-
return { error: "path must reference a regular file" };
|
|
38
|
-
}
|
|
39
|
-
function readSafeFlowDefinition(kitDir, relativePath) {
|
|
40
|
-
const root = path.resolve(kitDir);
|
|
41
|
-
if (path.isAbsolute(relativePath))
|
|
42
|
-
return { error: "path must be relative" };
|
|
43
|
-
const lexicalFile = path.resolve(root, relativePath);
|
|
44
|
-
if (lexicalFile === root || !lexicalFile.startsWith(`${root}${path.sep}`))
|
|
45
|
-
return { error: "path must stay inside the kit directory" };
|
|
46
|
-
let rootDescriptor;
|
|
47
|
-
let descriptor;
|
|
48
|
-
try {
|
|
49
|
-
const realRoot = fs.realpathSync.native(root);
|
|
50
|
-
rootDescriptor = fs.openSync(realRoot, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY);
|
|
51
|
-
const rootIdentity = fs.fstatSync(rootDescriptor);
|
|
52
|
-
if (!rootIdentity.isDirectory() || !sameFileIdentity(rootIdentity, fs.lstatSync(realRoot)))
|
|
53
|
-
return { error: "kit directory identity changed while opening flow definition" };
|
|
54
|
-
const initialPath = lstatSafePath(realRoot, relativePath);
|
|
55
|
-
if (!initialPath.file || !initialPath.stat)
|
|
56
|
-
return { error: initialPath.error };
|
|
57
|
-
if (!initialPath.stat.isFile())
|
|
58
|
-
return { error: "path must reference a regular file" };
|
|
59
|
-
if (initialPath.stat.size > MAX_FLOW_DEFINITION_BYTES)
|
|
60
|
-
return { error: `file exceeds ${MAX_FLOW_DEFINITION_BYTES} bytes` };
|
|
61
|
-
// O_NOFOLLOW protects the terminal component. Identity checks before and after
|
|
62
|
-
// opening make a race on any intermediate component fail closed on macOS/Node,
|
|
63
|
-
// where openat-style traversal from a directory descriptor is not exposed.
|
|
64
|
-
descriptor = fs.openSync(initialPath.file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
65
|
-
const stat = fs.fstatSync(descriptor);
|
|
66
|
-
if (!stat.isFile())
|
|
67
|
-
return { error: "path must reference a regular file" };
|
|
68
|
-
if (!sameFileIdentity(initialPath.stat, stat))
|
|
69
|
-
return { error: "flow definition identity changed while opening" };
|
|
70
|
-
if (stat.size > MAX_FLOW_DEFINITION_BYTES)
|
|
71
|
-
return { error: `file exceeds ${MAX_FLOW_DEFINITION_BYTES} bytes` };
|
|
72
|
-
const verifiedPath = lstatSafePath(realRoot, relativePath);
|
|
73
|
-
if (!verifiedPath.stat || !sameFileIdentity(stat, verifiedPath.stat))
|
|
74
|
-
return { error: "flow definition identity changed while opening" };
|
|
75
|
-
const buffer = Buffer.alloc(stat.size);
|
|
76
|
-
let offset = 0;
|
|
77
|
-
while (offset < buffer.length) {
|
|
78
|
-
const read = fs.readSync(descriptor, buffer, offset, buffer.length - offset, offset);
|
|
79
|
-
if (read === 0)
|
|
80
|
-
break;
|
|
81
|
-
offset += read;
|
|
82
|
-
}
|
|
83
|
-
const finalStat = fs.fstatSync(descriptor);
|
|
84
|
-
if (offset !== stat.size || finalStat.size !== stat.size || !sameFileIdentity(stat, finalStat))
|
|
85
|
-
return { error: "file changed while being read" };
|
|
86
|
-
return { definition: JSON.parse(buffer.toString("utf8")) };
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (error.code === "ELOOP")
|
|
90
|
-
return { error: "path must not reference a symbolic link" };
|
|
91
|
-
return { error: `path is not readable: ${error.message}` };
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
if (descriptor !== undefined)
|
|
95
|
-
fs.closeSync(descriptor);
|
|
96
|
-
if (rootDescriptor !== undefined)
|
|
97
|
-
fs.closeSync(rootDescriptor);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
21
|
/**
|
|
101
22
|
* Parse and shape-validate a kit manifest's `dependencies` field (Flow Agents
|
|
102
23
|
* extension-layer metadata; see docs/adr/0019-kit-dependency-ownership.md).
|
|
@@ -155,10 +76,6 @@ export function parseKitDependencies(manifest, manifestPath) {
|
|
|
155
76
|
function nonEmptyStringList(value) {
|
|
156
77
|
return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && item.trim().length > 0);
|
|
157
78
|
}
|
|
158
|
-
const WORKFLOW_TRIGGER_IDENTIFIER_RE = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
|
|
159
|
-
function workflowTriggerIdentifier(value) {
|
|
160
|
-
return typeof value === "string" && WORKFLOW_TRIGGER_IDENTIFIER_RE.test(value);
|
|
161
|
-
}
|
|
162
79
|
function optionalWorkflowTriggerIdentifier(value) {
|
|
163
80
|
return value === undefined || workflowTriggerIdentifier(value);
|
|
164
81
|
}
|
|
@@ -304,76 +221,6 @@ export function parseKitHookInfluenceExpectations(manifest, manifestPath) {
|
|
|
304
221
|
});
|
|
305
222
|
return { entries, errors };
|
|
306
223
|
}
|
|
307
|
-
export function parseKitFlowStepActions(manifest, manifestPath) {
|
|
308
|
-
const entries = [];
|
|
309
|
-
const errors = [];
|
|
310
|
-
const raw = manifest.flow_step_actions;
|
|
311
|
-
if (raw === undefined)
|
|
312
|
-
return { entries, errors };
|
|
313
|
-
if (!Array.isArray(raw)) {
|
|
314
|
-
errors.push(`${manifestPath}: .flow_step_actions must be a list`);
|
|
315
|
-
return { entries, errors };
|
|
316
|
-
}
|
|
317
|
-
const seen = new Set();
|
|
318
|
-
raw.forEach((entry, index) => {
|
|
319
|
-
if (typeof entry !== "object" || entry === null) {
|
|
320
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}] must be an object`);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
const record = entry;
|
|
324
|
-
if (!workflowTriggerIdentifier(record.flow_id)) {
|
|
325
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].flow_id must be a Flow identifier`);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (!workflowTriggerIdentifier(record.step_id)) {
|
|
329
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].step_id must be a step identifier`);
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
const skills = record.skills;
|
|
333
|
-
const operations = record.operations ?? [];
|
|
334
|
-
const expectationIds = record.expectation_ids;
|
|
335
|
-
const artifacts = record.artifacts ?? [];
|
|
336
|
-
if (!Array.isArray(skills) || !skills.every(workflowTriggerIdentifier)) {
|
|
337
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].skills must be an identifier list`);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
if (new Set(skills).size !== skills.length) {
|
|
341
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].skills must not contain duplicates`);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
if (!Array.isArray(operations) || !operations.every(workflowTriggerIdentifier)) {
|
|
345
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].operations must be an identifier list when present`);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
if (new Set(operations).size !== operations.length) {
|
|
349
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].operations must not contain duplicates`);
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (expectationIds !== undefined && (!Array.isArray(expectationIds) || !expectationIds.every(workflowTriggerIdentifier) || new Set(expectationIds).size !== expectationIds.length)) {
|
|
353
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].expectation_ids must be a unique identifier list when present`);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
if (!Array.isArray(artifacts) || !artifacts.every((artifact) => typeof artifact === "string" && artifact.trim().length > 0) || new Set(artifacts).size !== artifacts.length) {
|
|
357
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}].artifacts must be a unique non-empty string list when present`);
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
const key = `${record.flow_id}/${record.step_id}`;
|
|
361
|
-
if (seen.has(key)) {
|
|
362
|
-
errors.push(`${manifestPath}: flow_step_actions[${index}] duplicates '${key}'`);
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
seen.add(key);
|
|
366
|
-
entries.push({
|
|
367
|
-
flow_id: record.flow_id,
|
|
368
|
-
step_id: record.step_id,
|
|
369
|
-
skills: skills,
|
|
370
|
-
operations: operations,
|
|
371
|
-
artifacts: artifacts,
|
|
372
|
-
...(Array.isArray(expectationIds) ? { expectation_ids: expectationIds } : {}),
|
|
373
|
-
});
|
|
374
|
-
});
|
|
375
|
-
return { entries, errors };
|
|
376
|
-
}
|
|
377
224
|
export function parseKitSkillRoles(manifest, manifestPath) {
|
|
378
225
|
const entries = [];
|
|
379
226
|
const errors = [];
|
|
@@ -556,15 +403,15 @@ export async function validateKitRepository(kitDir) {
|
|
|
556
403
|
errors.push(`${manifestPath}: invalid JSON: ${error.message}`);
|
|
557
404
|
return errors;
|
|
558
405
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
406
|
+
errors.push(...await delegateCoreContainerValidation(kitDir, manifest));
|
|
407
|
+
errors.push(...validateExtensionAssets(kitDir, manifestPath, manifest));
|
|
408
|
+
errors.push(...validateAgentMetadata(kitDir, manifestPath, manifest));
|
|
409
|
+
if (manifest.first_party !== undefined && typeof manifest.first_party !== "boolean")
|
|
410
|
+
errors.push(`${manifestPath}: .first_party must be a boolean when present`);
|
|
411
|
+
return errors;
|
|
412
|
+
}
|
|
413
|
+
function validateExtensionAssets(kitDir, manifestPath, manifest) {
|
|
414
|
+
const errors = [];
|
|
568
415
|
for (const section of EXTENSION_ASSET_CLASSES) {
|
|
569
416
|
const entries = manifest[section];
|
|
570
417
|
if (entries === undefined)
|
|
@@ -606,9 +453,10 @@ export async function validateKitRepository(kitDir) {
|
|
|
606
453
|
}
|
|
607
454
|
});
|
|
608
455
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
456
|
+
return errors;
|
|
457
|
+
}
|
|
458
|
+
function validateAgentMetadata(kitDir, manifestPath, manifest) {
|
|
459
|
+
const errors = [];
|
|
612
460
|
const depResult = parseKitDependencies(manifest, manifestPath);
|
|
613
461
|
for (const err of depResult.errors)
|
|
614
462
|
errors.push(err);
|
|
@@ -624,183 +472,8 @@ export async function validateKitRepository(kitDir) {
|
|
|
624
472
|
const skillRoleResult = parseKitSkillRoles(manifest, manifestPath);
|
|
625
473
|
for (const err of skillRoleResult.errors)
|
|
626
474
|
errors.push(err);
|
|
627
|
-
if (manifest.skill_roles !== undefined && skillRoleResult.errors.length === 0) {
|
|
628
|
-
|
|
629
|
-
? manifest.skills.flatMap((entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string" ? [entry.id] : [])
|
|
630
|
-
: []);
|
|
631
|
-
const roleSkillIds = new Set(skillRoleResult.entries.map((entry) => entry.skill_id));
|
|
632
|
-
for (const id of declaredSkillIds)
|
|
633
|
-
if (!roleSkillIds.has(id))
|
|
634
|
-
errors.push(`${manifestPath}: skill_roles is missing declared skill '${id}'`);
|
|
635
|
-
for (const id of roleSkillIds)
|
|
636
|
-
if (!declaredSkillIds.has(id))
|
|
637
|
-
errors.push(`${manifestPath}: skill_roles references undeclared skill '${id}'`);
|
|
638
|
-
const flows = new Map();
|
|
639
|
-
if (Array.isArray(manifest.flows)) {
|
|
640
|
-
for (const entry of manifest.flows) {
|
|
641
|
-
if (typeof entry !== "object" || entry === null)
|
|
642
|
-
continue;
|
|
643
|
-
const flow = entry;
|
|
644
|
-
if (typeof flow.id !== "string" || typeof flow.path !== "string")
|
|
645
|
-
continue;
|
|
646
|
-
const safeDefinition = readSafeFlowDefinition(kitDir, flow.path);
|
|
647
|
-
if (!safeDefinition.definition) {
|
|
648
|
-
errors.push(`${manifestPath}: flows '${flow.id}' ${safeDefinition.error}`);
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
try {
|
|
652
|
-
const definition = safeDefinition.definition;
|
|
653
|
-
const steps = new Set(Array.isArray(definition.steps) ? definition.steps.flatMap((step) => typeof step === "object" && step !== null && typeof step.id === "string" ? [step.id] : []) : []);
|
|
654
|
-
const usesFlowByStep = new Map();
|
|
655
|
-
if (Array.isArray(definition.steps)) {
|
|
656
|
-
for (const step of definition.steps) {
|
|
657
|
-
if (typeof step !== "object" || step === null)
|
|
658
|
-
continue;
|
|
659
|
-
const stepRecord = step;
|
|
660
|
-
if (typeof stepRecord.id === "string" && typeof stepRecord.uses_flow === "string")
|
|
661
|
-
usesFlowByStep.set(stepRecord.id, stepRecord.uses_flow);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
const expectationsByStep = new Map();
|
|
665
|
-
if (typeof definition.gates === "object" && definition.gates !== null) {
|
|
666
|
-
for (const gate of Object.values(definition.gates)) {
|
|
667
|
-
if (typeof gate !== "object" || gate === null)
|
|
668
|
-
continue;
|
|
669
|
-
const gateRecord = gate;
|
|
670
|
-
if (typeof gateRecord.step !== "string" || !Array.isArray(gateRecord.expects))
|
|
671
|
-
continue;
|
|
672
|
-
const expectations = expectationsByStep.get(gateRecord.step) ?? new Map();
|
|
673
|
-
for (const expectation of gateRecord.expects) {
|
|
674
|
-
if (typeof expectation !== "object" || expectation === null)
|
|
675
|
-
continue;
|
|
676
|
-
const expectationRecord = expectation;
|
|
677
|
-
if (typeof expectationRecord.id !== "string")
|
|
678
|
-
continue;
|
|
679
|
-
const exportKeys = new Set([expectationRecord.id]);
|
|
680
|
-
const claimType = expectationRecord.bundle_claim?.claimType;
|
|
681
|
-
if (typeof claimType === "string")
|
|
682
|
-
exportKeys.add(claimType);
|
|
683
|
-
expectations.set(expectationRecord.id, { id: expectationRecord.id, exportKeys });
|
|
684
|
-
}
|
|
685
|
-
expectationsByStep.set(gateRecord.step, expectations);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
flows.set(flow.id, {
|
|
689
|
-
steps,
|
|
690
|
-
expectationsByStep,
|
|
691
|
-
usesFlowByStep,
|
|
692
|
-
exports: new Set(Array.isArray(definition.exports) ? definition.exports.filter((entry) => typeof entry === "string" && entry.length > 0) : []),
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
catch {
|
|
696
|
-
// Core Flow validation reports missing or malformed definitions.
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
const resolveEffectiveFlowStep = (flowId, stepId, seen = new Set()) => {
|
|
701
|
-
const cycleKey = `${flowId}\u0000${stepId}`;
|
|
702
|
-
if (seen.has(cycleKey))
|
|
703
|
-
return undefined;
|
|
704
|
-
seen.add(cycleKey);
|
|
705
|
-
const flow = flows.get(flowId);
|
|
706
|
-
if (!flow)
|
|
707
|
-
return undefined;
|
|
708
|
-
const direct = flow.expectationsByStep.get(stepId);
|
|
709
|
-
if (direct)
|
|
710
|
-
return { sourceFlowId: flowId, stepId, expectations: direct, flowIds: new Set([flowId]) };
|
|
711
|
-
const childFlowId = flow.usesFlowByStep.get(stepId);
|
|
712
|
-
if (!childFlowId)
|
|
713
|
-
return { sourceFlowId: flowId, stepId, expectations: new Map(), flowIds: new Set([flowId]) };
|
|
714
|
-
const child = resolveEffectiveFlowStep(childFlowId, stepId, seen);
|
|
715
|
-
const childFlow = flows.get(childFlowId);
|
|
716
|
-
if (!child || !childFlow || [...child.expectations.values()].some((expectation) => ![...expectation.exportKeys].some((key) => childFlow.exports.has(key))))
|
|
717
|
-
return undefined;
|
|
718
|
-
child.flowIds.add(flowId);
|
|
719
|
-
return child;
|
|
720
|
-
};
|
|
721
|
-
for (const row of skillRoleResult.entries) {
|
|
722
|
-
if (!row.flow_id)
|
|
723
|
-
continue;
|
|
724
|
-
const flow = flows.get(row.flow_id);
|
|
725
|
-
if (!flow) {
|
|
726
|
-
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' references unknown flow '${row.flow_id}'`);
|
|
727
|
-
continue;
|
|
728
|
-
}
|
|
729
|
-
for (const stepId of row.step_ids)
|
|
730
|
-
if (!flow.steps.has(stepId))
|
|
731
|
-
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' references unknown step '${row.flow_id}/${stepId}'`);
|
|
732
|
-
const allowedExpectations = new Set(row.step_ids.flatMap((stepId) => [...(resolveEffectiveFlowStep(row.flow_id, stepId)?.expectations.keys() ?? [])]));
|
|
733
|
-
for (const expectationId of row.expectation_ids)
|
|
734
|
-
if (!allowedExpectations.has(expectationId))
|
|
735
|
-
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' expectation '${expectationId}' is not owned by its bound step(s)`);
|
|
736
|
-
}
|
|
737
|
-
const roleByShortId = new Map(skillRoleResult.entries.map((entry) => [entry.skill_id.replace(`${String(manifest.id)}.`, ""), entry]));
|
|
738
|
-
const producerOwners = new Map();
|
|
739
|
-
for (const row of skillRoleResult.entries) {
|
|
740
|
-
if (row.role !== "step" || !row.flow_id)
|
|
741
|
-
continue;
|
|
742
|
-
for (const stepId of row.step_ids) {
|
|
743
|
-
const effectiveStep = resolveEffectiveFlowStep(row.flow_id, stepId);
|
|
744
|
-
if (!effectiveStep)
|
|
745
|
-
continue;
|
|
746
|
-
for (const expectationId of row.expectation_ids) {
|
|
747
|
-
if (!effectiveStep.expectations.has(expectationId))
|
|
748
|
-
continue;
|
|
749
|
-
const key = `${effectiveStep.sourceFlowId}\u0000${effectiveStep.stepId}\u0000${expectationId}`;
|
|
750
|
-
producerOwners.set(key, [...(producerOwners.get(key) ?? []), `skill:${row.skill_id}`]);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
for (const action of flowStepActionResult.entries) {
|
|
755
|
-
const containingFlow = flows.get(action.flow_id);
|
|
756
|
-
if (!containingFlow || !containingFlow.steps.has(action.step_id)) {
|
|
757
|
-
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' references an unknown flow step`);
|
|
758
|
-
continue;
|
|
759
|
-
}
|
|
760
|
-
const effectiveStep = resolveEffectiveFlowStep(action.flow_id, action.step_id);
|
|
761
|
-
if (!effectiveStep) {
|
|
762
|
-
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' cannot resolve its composed Flow step`);
|
|
763
|
-
continue;
|
|
764
|
-
}
|
|
765
|
-
const expectedAtStep = effectiveStep.expectations;
|
|
766
|
-
for (const expectationId of action.expectation_ids ?? []) {
|
|
767
|
-
if (!expectedAtStep.has(expectationId))
|
|
768
|
-
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' operation expectation '${expectationId}' is not owned by its resolved Flow step`);
|
|
769
|
-
}
|
|
770
|
-
if (action.skills.length === 0 && action.operations.length > 0 && expectedAtStep.size > 0 && !(action.expectation_ids?.length)) {
|
|
771
|
-
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' operation-only action must explicitly declare expectation_ids`);
|
|
772
|
-
}
|
|
773
|
-
const actionRows = [];
|
|
774
|
-
for (const skill of action.skills) {
|
|
775
|
-
const row = roleByShortId.get(skill);
|
|
776
|
-
if (!row || row.role !== "step" || !row.flow_id || !effectiveStep.flowIds.has(row.flow_id) || !row.step_ids.includes(action.step_id)) {
|
|
777
|
-
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' skill '${skill}' must match one step-role binding`);
|
|
778
|
-
}
|
|
779
|
-
else {
|
|
780
|
-
actionRows.push(row);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
for (const expectationId of expectedAtStep.keys()) {
|
|
784
|
-
const key = `${effectiveStep.sourceFlowId}\u0000${effectiveStep.stepId}\u0000${expectationId}`;
|
|
785
|
-
const owners = producerOwners.get(key) ?? [];
|
|
786
|
-
if (action.operations.length > 0 && action.expectation_ids?.includes(expectationId))
|
|
787
|
-
owners.push(`operation:${action.flow_id}/${action.step_id}`);
|
|
788
|
-
producerOwners.set(key, owners);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
for (const [flowId, flow] of flows) {
|
|
792
|
-
for (const [stepId, expectations] of flow.expectationsByStep) {
|
|
793
|
-
for (const expectationId of expectations.keys()) {
|
|
794
|
-
const owners = producerOwners.get(`${flowId}\u0000${stepId}\u0000${expectationId}`) ?? [];
|
|
795
|
-
if (owners.length !== 1) {
|
|
796
|
-
errors.push(`${manifestPath}: flow expectation '${flowId}/${stepId}/${expectationId}' must have exactly one producer owner; found ${owners.length}`);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
if (manifest.first_party !== undefined && typeof manifest.first_party !== "boolean") {
|
|
803
|
-
errors.push(`${manifestPath}: .first_party must be a boolean when present`);
|
|
475
|
+
if ((manifest.skill_roles !== undefined || manifest.flow_step_actions !== undefined) && skillRoleResult.errors.length === 0) {
|
|
476
|
+
errors.push(...validateActionRepositoryMetadata({ kitDir, manifestPath, manifest, actions: flowStepActionResult.entries, skillRoles: skillRoleResult.entries }));
|
|
804
477
|
}
|
|
805
478
|
return errors;
|
|
806
479
|
}
|
|
@@ -2,8 +2,10 @@ export { BUILDER_BUILD_FLOW_ID, BUILDER_BUILD_FLOW_RELATIVE_PATH, BuilderBuildRu
|
|
|
2
2
|
export type { BuilderBuildRunResult, BuilderBuildRunIdentityMismatch, BuilderBuildTrustBundleEvidenceInput, EvaluateBuilderBuildRunInput, LoadBuilderBuildRunInput, StartBuilderBuildRunInput, } from "./builder-flow-run-adapter.js";
|
|
3
3
|
export { archiveBuilderFlowSession, cancelBuilderFlowSession, pauseBuilderFlowSession, recoverBuilderFlowSession, releaseBuilderFlowAssignment, resumeBuilderFlowSession, startBuilderFlowSession, syncBuilderFlowSession, } from "./builder-flow-runtime.js";
|
|
4
4
|
export type { BuilderFlowAgentLifecycleInput, BuilderFlowAuthorizedLifecycleInput, BuilderFlowSessionInput, BuilderFlowSessionResult } from "./builder-flow-runtime.js";
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
5
|
+
export { deriveBuilderGateActionEnvelope, gateActionProgressSnapshot, withGateActionPriorProgress, } from "./builder-gate-action-envelope.js";
|
|
6
|
+
export type { BuilderGateActionEnvelopeInput, GateActionEnvelope, GateActionInterfaceParameter, GateActionPriorProgress, GateActionProgressSnapshot, GateActionPublicMutation, } from "./builder-gate-action-envelope.js";
|
|
7
|
+
export { ContinuationAdapterTimeoutError, MAX_CONTINUATION_ADAPTER_EVIDENCE_BYTES, MAX_CONTINUATION_TURN_RESULT_BYTES, createFileContinuationStore, driveBuilderFlowSession, runContinuationDriver, withContinuationDriverLock, } from "./continuation-driver.js";
|
|
8
|
+
export type { ContinuationBarrier, ContinuationAcceptedTurn, ContinuationDriverEvent, ContinuationDriverLockLease, ContinuationDriverOutcome, ContinuationDriverState, ContinuationRuntimePort, ContinuationSnapshot, ContinuationStateStore, ContinuationTurnAuthority, ContinuationTurnContext, ContinuationTurnRequest, ContinuationTurnResult, DriveBuilderFlowSessionInput, RunContinuationDriverInput, } from "./continuation-driver.js";
|
|
7
9
|
export { builderLifecycleAuthorizationPayload, loadBuilderLifecycleAuthorization } from "./builder-lifecycle-authority.js";
|
|
8
10
|
export type { BuilderLifecycleAuthorization } from "./builder-lifecycle-authority.js";
|
|
9
11
|
export { defaultArtifactRootForRead, defaultCodexHome, defaultTelemetryDirForRead, defaultTelemetryDirsForRead, durableFlowAgentsRoot, durableInstallRecordPath, DURABLE_FLOW_AGENTS_DIR, FLOW_AGENTS_RUNTIME_DIR, FLOW_AGENTS_RUNTIME_SUBDIR, firstExistingPath, flowAgentsArtifactRoot, KONTOURAI_DIR, legacyTelemetryDataDir, LEGACY_TELEMETRY_DIR, telemetryDataDir, } from "./lib/local-artifact-root.js";
|
|
@@ -15,7 +15,8 @@ import * as path from "node:path";
|
|
|
15
15
|
import { loadJson as _loadJson, writeJson as _writeJson } from "./cli/workflow-sidecar.js";
|
|
16
16
|
export { BUILDER_BUILD_FLOW_ID, BUILDER_BUILD_FLOW_RELATIVE_PATH, BuilderBuildRunInputError, BuilderBuildRunIdentityError, evaluateBuilderBuildRun, loadBuilderBuildRun, resolveBuilderBuildFlowDefinitionPath, startBuilderBuildRun, } from "./builder-flow-run-adapter.js";
|
|
17
17
|
export { archiveBuilderFlowSession, cancelBuilderFlowSession, pauseBuilderFlowSession, recoverBuilderFlowSession, releaseBuilderFlowAssignment, resumeBuilderFlowSession, startBuilderFlowSession, syncBuilderFlowSession, } from "./builder-flow-runtime.js";
|
|
18
|
-
export {
|
|
18
|
+
export { deriveBuilderGateActionEnvelope, gateActionProgressSnapshot, withGateActionPriorProgress, } from "./builder-gate-action-envelope.js";
|
|
19
|
+
export { ContinuationAdapterTimeoutError, MAX_CONTINUATION_ADAPTER_EVIDENCE_BYTES, MAX_CONTINUATION_TURN_RESULT_BYTES, createFileContinuationStore, driveBuilderFlowSession, runContinuationDriver, withContinuationDriverLock, } from "./continuation-driver.js";
|
|
19
20
|
// Pure serialization contract used by external lifecycle authorities when
|
|
20
21
|
// signing requests. This does not load, create, or mutate a Flow run.
|
|
21
22
|
export { builderLifecycleAuthorizationPayload, loadBuilderLifecycleAuthorization } from "./builder-lifecycle-authority.js";
|
|
@@ -6,6 +6,11 @@ title: Migrations
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
- Gate-action envelopes now use `schema_version: "2.0"`. Each entry in
|
|
10
|
+
`gate.requirements` includes its originating `gate_id`, allowing consumers to
|
|
11
|
+
verify accepted exceptions without private Flow-definition knowledge. There
|
|
12
|
+
is no legacy envelope fallback; adapters that validate or project the public
|
|
13
|
+
envelope must require version 2.0 and the new binding.
|
|
9
14
|
- Workflow runtime artifacts now live under `.kontourai/flow-agents/` instead
|
|
10
15
|
of earlier runtime roots such as `.flow-agents/` or `.agents/flow-agents/`.
|
|
11
16
|
Move any local session directories, sidecars, or `current.json` pointers you
|
|
@@ -90,9 +90,10 @@ Critique derives reviewer identity from the calling runtime actor. An active
|
|
|
90
90
|
implementation assignment is required, and its actor cannot review its own
|
|
91
91
|
work; the delegated reviewer invokes the command directly under a distinct
|
|
92
92
|
identity. The public interface does not accept a caller-selected reviewer
|
|
93
|
-
label. Every critique includes an explicit
|
|
94
|
-
|
|
95
|
-
require every lane to pass; reviewed
|
|
93
|
+
label. Every critique includes an explicit `pass`, `fail`, or `not_verified`
|
|
94
|
+
verdict and at least one substantive `--lane-json`. Passing critiques additionally
|
|
95
|
+
require local reviewed `--artifact-ref` values and every lane to pass; reviewed
|
|
96
|
+
files and the workspace snapshot are
|
|
96
97
|
hashed into the stored review target so later implementation changes invalidate
|
|
97
98
|
stale clean critiques.
|
|
98
99
|
|
|
@@ -173,7 +174,13 @@ flow_agents workflow drive \
|
|
|
173
174
|
Driver state and its append-only event stream live under
|
|
174
175
|
`.kontourai/flow-agents/<slug>/continuation-driver/`. The mission turn count survives reinvocation;
|
|
175
176
|
subsequent invocations must use the same `--max-turns` value. The request contains the
|
|
176
|
-
canonical run id, definition id, current step, projected `next_action`, iteration, and budget.
|
|
177
|
+
canonical run id, definition id, current step, projected `next_action`, iteration, and budget. Builder
|
|
178
|
+
turns additionally carry one bounded top-level `gate_action_envelope` with immutable skill identities,
|
|
179
|
+
declared artifacts/evidence, requirement satisfaction and unresolved ids, typed public
|
|
180
|
+
`workflow.evidence`/`workflow.critique` argv or product-operation bindings, one-turn stop semantics,
|
|
181
|
+
product-declared implementation policy, and prior canonical progress/stagnation. Parameter values are
|
|
182
|
+
appended as separate argv entries; adapters must not perform string substitution into a shell command. The
|
|
183
|
+
envelope is request-only and is not duplicated in projected `next_action` or durable `state.json`. It
|
|
177
184
|
does not mutate or replace the runtime system prompt. Adapter errors are recorded as failed turns
|
|
178
185
|
and fail open to canonical resynchronization and the next bounded turn; they cannot bypass the
|
|
179
186
|
persisted mission budget. The Builder Flow projection supplies the canonical continue/wait/done/failed
|
|
@@ -188,6 +195,15 @@ state rollback or deletion is rejected when its append-only event history proves
|
|
|
188
195
|
started. These local coordination records detect accidental or in-process rollback; they are not a
|
|
189
196
|
cryptographic boundary against a process that can rewrite the entire artifact directory.
|
|
190
197
|
|
|
198
|
+
An operation mutation is a structured product protocol, not necessarily a directly executable CLI
|
|
199
|
+
command. In particular, `publish-change` identifies the provider capability `pull_request.create`,
|
|
200
|
+
its bounded parameters, the required provider result, and `publish-change.result.json` as its dedicated
|
|
201
|
+
result artifact. This release has no authenticated ChangeProvider executor. The operation therefore
|
|
202
|
+
reports `external_capability_required` and `external_verification_required`, exposes no completion
|
|
203
|
+
mutation, and parks the continuation. A locally authored result is not provider evidence. The installed
|
|
204
|
+
`flow-agents publish-change` helper renders and validates publish artifacts and provider checks; it does
|
|
205
|
+
not create a pull request and must not be treated as the operation executor.
|
|
206
|
+
|
|
191
207
|
Immediately before spawning an adapter turn, the driver writes a transient, schema-versioned
|
|
192
208
|
`active-turn.json` beside its mission state and passes a raw 32-byte turn secret plus the path-safe,
|
|
193
209
|
signed run id in `FLOW_AGENTS_CONTINUATION_TURN_SECRET` and
|
|
@@ -230,7 +246,27 @@ The event stream records `turn_completed`, `gate_not_advanced`, `turn_failed`, a
|
|
|
230
246
|
outcome. Failed turns carry
|
|
231
247
|
`failure_kind` of `timeout` or `adapter_error`; a completed adapter turn whose canonical run remains
|
|
232
248
|
active at the same current step records `gate_not_advanced`. These events describe driver execution only and do not
|
|
233
|
-
change canonical Flow state.
|
|
249
|
+
change canonical Flow state. Adapter-returned `evidence` is not interpreted as gate evidence; only
|
|
250
|
+
the public `workflow evidence` path can attach evidence for Flow evaluation. Same-step canonical
|
|
251
|
+
evidence or declared-artifact hash changes are recorded as progress, while repeated no-progress turns are
|
|
252
|
+
classified as possible stagnation and then stagnant without fabricating a gate outcome.
|
|
253
|
+
Progress uses run-wide canonical evidence/artifact manifests and resumes
|
|
254
|
+
from the durable `last_progress` baseline after interruption or reinvocation. Kit metadata, skill source,
|
|
255
|
+
and observed artifact reads are bounded descriptor-stable regular-file reads that reject symlinks and
|
|
256
|
+
identity changes.
|
|
257
|
+
Request-facing declared and required artifacts exclude control `state.json`, even where legacy kit
|
|
258
|
+
ownership metadata retains it.
|
|
259
|
+
Kit validation and envelope construction both cap an action at 16 skills and a flow at 128 distinct
|
|
260
|
+
observable file artifacts, excluding virtual trust-bundle refs and control artifacts consistently.
|
|
261
|
+
Synchronization measures an interrupted, waiting, terminal, or callback-failed turn before clearing
|
|
262
|
+
its recovery marker. Evidence-free canonical gate evaluation is limited to accepted exceptions and
|
|
263
|
+
gates whose effective expectations are all optional; ordinary missing-required gates remain unevaluated.
|
|
264
|
+
Signed drives reserve aggregate attestation capacity before adapter execution when another bounded
|
|
265
|
+
signed result cannot fit.
|
|
266
|
+
The complete serialized adapter result is capped at 74,000 bytes, and preflight reserves that exact
|
|
267
|
+
maximum plus the actual request and JSON structure. Accepted request/result pairs and measured progress
|
|
268
|
+
are journaled durably before the active marker is cleared. Restart idempotently completes missing audit
|
|
269
|
+
writes, and signed attestation fails closed when persisted accepted events lack journal coverage.
|
|
234
270
|
|
|
235
271
|
## Compatibility Doctor
|
|
236
272
|
|
|
@@ -153,6 +153,123 @@ composed steps that have no legacy sidecar phase (`merge-ready-ci` and `learn`).
|
|
|
153
153
|
Both the legacy `current.json` pointer and every matching per-actor pointer are
|
|
154
154
|
updated from that canonical step; `phase_map` is presentation metadata, not the
|
|
155
155
|
authority for pointer navigation.
|
|
156
|
+
|
|
157
|
+
### Gate-Action Envelope
|
|
158
|
+
|
|
159
|
+
Every active Builder continuation request includes a bounded
|
|
160
|
+
`gate_action_envelope` with schema version `1.0`. Flow Agents derives it from
|
|
161
|
+
the persisted canonical Flow run and effective Flow Definition, then joins it
|
|
162
|
+
to the installed Builder Kit's validated `flow_step_actions` record. It is an
|
|
163
|
+
execution context, not a second gate evaluator: Flow remains the only authority
|
|
164
|
+
that evaluates requirements, advances steps, routes back, or consumes attempt
|
|
165
|
+
budget.
|
|
166
|
+
|
|
167
|
+
The envelope provides the current gate ids and claim shapes, including each
|
|
168
|
+
expectation's required flag and `satisfied`, `accepted_exception`, or `unresolved`
|
|
169
|
+
status. Accepted exceptions are identified separately. Flow Agents evaluates
|
|
170
|
+
these statuses with the run's effective Flow config, including gate overrides,
|
|
171
|
+
so waived, satisfied, and optional work is never mislabeled as required. Skill
|
|
172
|
+
identities bind package, version, stable package-relative source
|
|
173
|
+
path, and SHA-256, so durable attestations never retain a stale absolute install path.
|
|
174
|
+
Requirement status comes from Flow's canonical gate evaluation and therefore
|
|
175
|
+
uses the expectation's trust-bundle selector, Surface-derived claim status,
|
|
176
|
+
supersession, freshness, and current gate visit; `expectation_ids` labels alone
|
|
177
|
+
never mark a requirement satisfied.
|
|
178
|
+
Declared operations, artifacts, and evidence expectation ids come from product
|
|
179
|
+
metadata. `implementation_allowed` is also product metadata; the shipped Builder
|
|
180
|
+
Kit declares it true only for `builder.build/execute`.
|
|
181
|
+
|
|
182
|
+
The read-only status interface is an exact version-pinned command. Mutation
|
|
183
|
+
interfaces are typed per expectation: `workflow.evidence`, `workflow.critique`,
|
|
184
|
+
or a named product operation such as `publish-change`. Evidence and critique
|
|
185
|
+
interfaces expose fixed argv plus typed required parameters and allowed values;
|
|
186
|
+
they do not publish shell strings with substitution placeholders. Consumers add
|
|
187
|
+
parameter values as distinct argv entries.
|
|
188
|
+
|
|
189
|
+
`publish-change` is a provider-capability protocol, not a claim that the local
|
|
190
|
+
`flow-agents publish-change` helper opens a pull request. Its envelope binds the
|
|
191
|
+
exact `pull_request.create` capability, bounded structured inputs, the required
|
|
192
|
+
provider result, and the dedicated session-relative
|
|
193
|
+
`publish-change.result.json` artifact. No authenticated ChangeProvider executor
|
|
194
|
+
ships in this issue, so the operation is explicitly unavailable locally and has
|
|
195
|
+
an `external_verification_required` completion state. It exposes no
|
|
196
|
+
`record_completion` mutation, a self-authored result cannot satisfy
|
|
197
|
+
`pull-request-opened`, and the projection waits instead of scheduling repeated
|
|
198
|
+
adapter turns. The protocol remains the future provider contract. The local
|
|
199
|
+
publish-change helper only renders and validates publish artifacts and provider
|
|
200
|
+
checks; it is not the provider action executor.
|
|
201
|
+
|
|
202
|
+
`flow_step_actions` must explicitly declare `artifacts`, `artifact_bindings`,
|
|
203
|
+
`expectation_ids`, `expectation_bindings`, and `implementation_allowed`, including
|
|
204
|
+
empty lists for terminal actions. Expectation ids must exactly equal the resolved
|
|
205
|
+
Flow expectation set. Artifact bindings map each artifact to its owning
|
|
206
|
+
expectations, allowing optional artifacts to remain declared without appearing
|
|
207
|
+
under `stop_condition.required`. Operation bindings must resolve through the
|
|
208
|
+
canonical public operation catalog, not merely a self-declared string. Artifact
|
|
209
|
+
refs are either lexically safe session-relative paths or validated
|
|
210
|
+
`trust.bundle#<safe-id>` virtual refs; absolute paths, traversal, and arbitrary
|
|
211
|
+
fragments fail closed. Malformed,
|
|
212
|
+
unknown-field, duplicate, oversized, unmatched, symlinked, or otherwise
|
|
213
|
+
unbounded action metadata fails closed before an adapter is launched. The
|
|
214
|
+
runtime verifies every named skill against the installed Builder package and
|
|
215
|
+
binds its contents by SHA-256. Kit JSON, skill source, and artifact identity/hash
|
|
216
|
+
reads open the final path once with `O_NOFOLLOW`, bound size from `fstat`, read
|
|
217
|
+
through that descriptor, and recheck descriptor/path identity after the read.
|
|
218
|
+
Run-wide artifact observation deduplicates refs and enforces count plus aggregate
|
|
219
|
+
byte/hash budgets before reading file contents. Product validation and runtime
|
|
220
|
+
both cap each action at 16 skills and each flow at 128 distinct observable file
|
|
221
|
+
artifacts; virtual trust-bundle refs and control artifacts are excluded using the
|
|
222
|
+
same classification in both layers.
|
|
223
|
+
|
|
224
|
+
After every successful or failed adapter turn, Flow Agents synchronizes the
|
|
225
|
+
canonical run and records a delta: step advancement, newly attached canonical
|
|
226
|
+
evidence, changed hashes of declared artifacts (`artifact_changes`), or no
|
|
227
|
+
progress. Evidence identities and the artifact manifest are run-wide rather
|
|
228
|
+
than selected-step scoped, so the evidence/artifact that advances a gate remains
|
|
229
|
+
attributable and files already present for later steps are part of the baseline.
|
|
230
|
+
Control `state.json` is excluded from both request-facing declared/required
|
|
231
|
+
artifacts and artifact progress. Legacy kit ownership metadata may retain it,
|
|
232
|
+
but the envelope never instructs an adapter to produce Flow Agents control
|
|
233
|
+
state or observes its own hash. Repeated
|
|
234
|
+
no-progress deltas are classified as `possible` and then `stagnant`; they never
|
|
235
|
+
invent evidence, auto-pass a gate, or change Flow state. A same-step evidence
|
|
236
|
+
attachment is recorded as progress even though the legacy `gate_not_advanced`
|
|
237
|
+
event remains for compatibility. Adapter-returned `evidence` remains optional
|
|
238
|
+
adapter telemetry only and is never gate evidence.
|
|
239
|
+
|
|
240
|
+
The durable `last_progress` snapshot is the recovery baseline. A durable active
|
|
241
|
+
turn phase and pre-turn snapshot identify an adapter turn interrupted before its
|
|
242
|
+
post-turn measurement. Reinvocation compares freshly synchronized canonical
|
|
243
|
+
state with that snapshot, counts an unchanged started turn as no progress exactly
|
|
244
|
+
once, records any delta, and clears the recovery marker. Synchronization and this
|
|
245
|
+
reconciliation occur before waiting or terminal disposition handling, so the
|
|
246
|
+
turn's audit and progress survive either outcome. Accepted turns, wait turns, and
|
|
247
|
+
callback failures are likewise synchronized and measured before their durable
|
|
248
|
+
turn marker is cleared. Signed workflow drives preflight the aggregate attestation
|
|
249
|
+
capacity before launching an adapter when another bounded signed result cannot fit.
|
|
250
|
+
Accepted request/result pairs and their measured progress are first stored in a
|
|
251
|
+
durable idempotent journal while the active turn remains in `measured` phase.
|
|
252
|
+
Only after journal and completion-event persistence does the driver clear that
|
|
253
|
+
marker. Restart completes either write exactly once. Signed attestations reload
|
|
254
|
+
the journal and fail closed if an accepted event lacks request/result coverage.
|
|
255
|
+
The complete serialized turn result is capped at 74,000 bytes; signed preflight
|
|
256
|
+
reserves that exact maximum in addition to the actual request and JSON structure.
|
|
257
|
+
The authoritative envelope
|
|
258
|
+
exists only at top-level in the turn request; projected `next_action` and durable
|
|
259
|
+
`state.json` do not contain a duplicate.
|
|
260
|
+
|
|
261
|
+
Canonical synchronization normally waits for attached bundle evidence before
|
|
262
|
+
evaluating a gate. It may evaluate an evidence-free gate only when the run's
|
|
263
|
+
effective config proves the gate can pass without new evidence: an accepted
|
|
264
|
+
exception applies, or every effective expectation is optional. This advances
|
|
265
|
+
those gates without prematurely evaluating ordinary missing-required gates, and
|
|
266
|
+
once the run advances no obsolete action skill remains required.
|
|
267
|
+
|
|
268
|
+
The envelope and its prior-turn delta are additive fields of
|
|
269
|
+
`ContinuationTurnRequest` schema `1.0`; adapters that only consume the existing
|
|
270
|
+
request fields remain compatible. When `workflow drive` produces its optional
|
|
271
|
+
signed request/result attestation, the exact request object (including the
|
|
272
|
+
envelope) is included in the signed payload without transformation.
|
|
156
273
|
# Builder Lifecycle Authority
|
|
157
274
|
|
|
158
275
|
The canonical Flow run owns pause, resume, and cancellation. The current assignment actor may
|