@kontourai/flow-agents 3.11.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -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 +151 -0
- package/build/src/builder-gate-action-envelope.js +367 -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 +139 -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 +151 -0
- package/dist/base/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/claude-code/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/codex/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/kiro/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/opencode/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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 +151 -0
- package/dist/pi/build/src/builder-gate-action-envelope.js +367 -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 +139 -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/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/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 +529 -0
- package/src/cli/builder-flow-runtime.test.mjs +287 -58
- package/src/cli/continuation-driver.test.mjs +527 -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 +107 -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,237 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { sameStringSet } from "./action-metadata.js";
|
|
4
|
+
const MAX_FLOW_DEFINITION_BYTES = 1_048_576;
|
|
5
|
+
export function validateActionRepositoryMetadata(input) {
|
|
6
|
+
const errors = [];
|
|
7
|
+
validateDeclaredSkills(input.manifest, input.skillRoles, input.manifestPath, errors);
|
|
8
|
+
const flows = loadFlowMetadata(input.kitDir, input.manifest, input.manifestPath, errors);
|
|
9
|
+
const resolve = effectiveStepResolver(flows);
|
|
10
|
+
validateRoleReferences(input.skillRoles, flows, resolve, input.manifestPath, errors);
|
|
11
|
+
const owners = seedSkillOwners(input.skillRoles, resolve);
|
|
12
|
+
validateActions(input.actions, input.skillRoles, flows, resolve, owners, input.manifest, input.manifestPath, errors);
|
|
13
|
+
validateOwnerCardinality(flows, owners, input.manifestPath, errors);
|
|
14
|
+
return errors;
|
|
15
|
+
}
|
|
16
|
+
function validateDeclaredSkills(manifest, roles, manifestPath, errors) {
|
|
17
|
+
const declared = new Set(Array.isArray(manifest.skills) ? manifest.skills.flatMap((entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string" ? [entry.id] : []) : []);
|
|
18
|
+
const bound = new Set(roles.map((entry) => entry.skill_id));
|
|
19
|
+
for (const id of declared)
|
|
20
|
+
if (!bound.has(id))
|
|
21
|
+
errors.push(`${manifestPath}: skill_roles is missing declared skill '${id}'`);
|
|
22
|
+
for (const id of bound)
|
|
23
|
+
if (!declared.has(id))
|
|
24
|
+
errors.push(`${manifestPath}: skill_roles references undeclared skill '${id}'`);
|
|
25
|
+
}
|
|
26
|
+
function loadFlowMetadata(kitDir, manifest, manifestPath, errors) {
|
|
27
|
+
const flows = new Map();
|
|
28
|
+
if (!Array.isArray(manifest.flows))
|
|
29
|
+
return flows;
|
|
30
|
+
for (const entry of manifest.flows) {
|
|
31
|
+
if (typeof entry !== "object" || entry === null)
|
|
32
|
+
continue;
|
|
33
|
+
const flow = entry;
|
|
34
|
+
if (typeof flow.id !== "string" || typeof flow.path !== "string")
|
|
35
|
+
continue;
|
|
36
|
+
const safe = readSafeFlowDefinition(kitDir, flow.path);
|
|
37
|
+
if (!safe.definition) {
|
|
38
|
+
errors.push(`${manifestPath}: flows '${flow.id}' ${safe.error}`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const definition = safe.definition;
|
|
42
|
+
const steps = Array.isArray(definition.steps) ? definition.steps.filter(isRecord) : [];
|
|
43
|
+
const stepIds = new Set(steps.flatMap((step) => typeof step.id === "string" ? [step.id] : []));
|
|
44
|
+
const usesFlowByStep = new Map(steps.flatMap((step) => typeof step.id === "string" && typeof step.uses_flow === "string" ? [[step.id, step.uses_flow]] : []));
|
|
45
|
+
flows.set(flow.id, { steps: stepIds, usesFlowByStep, expectationsByStep: expectationsByStep(definition), exports: new Set(Array.isArray(definition.exports) ? definition.exports.filter((value) => typeof value === "string" && value.length > 0) : []) });
|
|
46
|
+
}
|
|
47
|
+
return flows;
|
|
48
|
+
}
|
|
49
|
+
function expectationsByStep(definition) {
|
|
50
|
+
const result = new Map();
|
|
51
|
+
if (!isRecord(definition.gates))
|
|
52
|
+
return result;
|
|
53
|
+
for (const gate of Object.values(definition.gates)) {
|
|
54
|
+
if (!isRecord(gate) || typeof gate.step !== "string" || !Array.isArray(gate.expects))
|
|
55
|
+
continue;
|
|
56
|
+
const expectations = result.get(gate.step) ?? new Map();
|
|
57
|
+
for (const value of gate.expects) {
|
|
58
|
+
if (!isRecord(value) || typeof value.id !== "string")
|
|
59
|
+
continue;
|
|
60
|
+
const exportKeys = new Set([value.id]);
|
|
61
|
+
if (isRecord(value.bundle_claim) && typeof value.bundle_claim.claimType === "string")
|
|
62
|
+
exportKeys.add(value.bundle_claim.claimType);
|
|
63
|
+
expectations.set(value.id, { id: value.id, exportKeys });
|
|
64
|
+
}
|
|
65
|
+
result.set(gate.step, expectations);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function effectiveStepResolver(flows) {
|
|
70
|
+
const resolve = (flowId, stepId, seen = new Set()) => {
|
|
71
|
+
const cycleKey = `${flowId}\0${stepId}`;
|
|
72
|
+
if (seen.has(cycleKey))
|
|
73
|
+
return undefined;
|
|
74
|
+
seen.add(cycleKey);
|
|
75
|
+
const flow = flows.get(flowId);
|
|
76
|
+
if (!flow)
|
|
77
|
+
return undefined;
|
|
78
|
+
const direct = flow.expectationsByStep.get(stepId);
|
|
79
|
+
if (direct)
|
|
80
|
+
return { sourceFlowId: flowId, stepId, expectations: direct, flowIds: new Set([flowId]) };
|
|
81
|
+
const childFlowId = flow.usesFlowByStep.get(stepId);
|
|
82
|
+
if (!childFlowId)
|
|
83
|
+
return { sourceFlowId: flowId, stepId, expectations: new Map(), flowIds: new Set([flowId]) };
|
|
84
|
+
const child = resolve(childFlowId, stepId, seen);
|
|
85
|
+
const childFlow = flows.get(childFlowId);
|
|
86
|
+
if (!child || !childFlow || [...child.expectations.values()].some((expectation) => ![...expectation.exportKeys].some((key) => childFlow.exports.has(key))))
|
|
87
|
+
return undefined;
|
|
88
|
+
child.flowIds.add(flowId);
|
|
89
|
+
return child;
|
|
90
|
+
};
|
|
91
|
+
return resolve;
|
|
92
|
+
}
|
|
93
|
+
function validateRoleReferences(roles, flows, resolve, manifestPath, errors) {
|
|
94
|
+
for (const row of roles) {
|
|
95
|
+
if (!row.flow_id)
|
|
96
|
+
continue;
|
|
97
|
+
const flow = flows.get(row.flow_id);
|
|
98
|
+
if (!flow) {
|
|
99
|
+
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' references unknown flow '${row.flow_id}'`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const stepId of row.step_ids)
|
|
103
|
+
if (!flow.steps.has(stepId))
|
|
104
|
+
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' references unknown step '${row.flow_id}/${stepId}'`);
|
|
105
|
+
const allowed = new Set(row.step_ids.flatMap((stepId) => [...(resolve(row.flow_id, stepId)?.expectations.keys() ?? [])]));
|
|
106
|
+
for (const expectationId of row.expectation_ids)
|
|
107
|
+
if (!allowed.has(expectationId))
|
|
108
|
+
errors.push(`${manifestPath}: skill_roles '${row.skill_id}' expectation '${expectationId}' is not owned by its bound step(s)`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function seedSkillOwners(roles, resolve) {
|
|
112
|
+
const owners = new Map();
|
|
113
|
+
for (const row of roles) {
|
|
114
|
+
if (row.role !== "step" || !row.flow_id)
|
|
115
|
+
continue;
|
|
116
|
+
for (const stepId of row.step_ids) {
|
|
117
|
+
const effective = resolve(row.flow_id, stepId);
|
|
118
|
+
if (!effective)
|
|
119
|
+
continue;
|
|
120
|
+
for (const expectationId of row.expectation_ids)
|
|
121
|
+
if (effective.expectations.has(expectationId)) {
|
|
122
|
+
const key = `${effective.sourceFlowId}\0${effective.stepId}\0${expectationId}`;
|
|
123
|
+
owners.set(key, [...(owners.get(key) ?? []), `skill:${row.skill_id}`]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return owners;
|
|
128
|
+
}
|
|
129
|
+
function validateActions(actions, roles, flows, resolve, owners, manifest, manifestPath, errors) {
|
|
130
|
+
const roleByShortId = new Map(roles.map((entry) => [entry.skill_id.replace(`${String(manifest.id)}.`, ""), entry]));
|
|
131
|
+
for (const action of actions) {
|
|
132
|
+
const flow = flows.get(action.flow_id);
|
|
133
|
+
if (!flow || !flow.steps.has(action.step_id)) {
|
|
134
|
+
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' references an unknown flow step`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const effective = resolve(action.flow_id, action.step_id);
|
|
138
|
+
if (!effective) {
|
|
139
|
+
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' cannot resolve its composed Flow step`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
for (const id of action.expectation_ids)
|
|
143
|
+
if (!effective.expectations.has(id))
|
|
144
|
+
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' operation expectation '${id}' is not owned by its resolved Flow step`);
|
|
145
|
+
if (!sameStringSet(action.expectation_ids, [...effective.expectations.keys()]))
|
|
146
|
+
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' expectation_ids must exactly equal its resolved Flow expectation set`);
|
|
147
|
+
for (const skill of action.skills) {
|
|
148
|
+
const row = roleByShortId.get(skill);
|
|
149
|
+
if (!row || row.role !== "step" || !row.flow_id || !effective.flowIds.has(row.flow_id) || !row.step_ids.includes(action.step_id))
|
|
150
|
+
errors.push(`${manifestPath}: flow_step_actions '${action.flow_id}/${action.step_id}' skill '${skill}' must match one step-role binding`);
|
|
151
|
+
}
|
|
152
|
+
for (const expectationId of effective.expectations.keys()) {
|
|
153
|
+
const binding = action.expectation_bindings.find((entry) => entry.expectation_id === expectationId);
|
|
154
|
+
if (binding?.interface !== "operation")
|
|
155
|
+
continue;
|
|
156
|
+
const key = `${effective.sourceFlowId}\0${effective.stepId}\0${expectationId}`;
|
|
157
|
+
owners.set(key, [...(owners.get(key) ?? []), `operation:${action.flow_id}/${action.step_id}`]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function validateOwnerCardinality(flows, owners, manifestPath, errors) {
|
|
162
|
+
for (const [flowId, flow] of flows)
|
|
163
|
+
for (const [stepId, expectations] of flow.expectationsByStep)
|
|
164
|
+
for (const expectationId of expectations.keys()) {
|
|
165
|
+
const found = owners.get(`${flowId}\0${stepId}\0${expectationId}`) ?? [];
|
|
166
|
+
if (found.length !== 1)
|
|
167
|
+
errors.push(`${manifestPath}: flow expectation '${flowId}/${stepId}/${expectationId}' must have exactly one producer owner; found ${found.length}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function readSafeFlowDefinition(kitDir, relativePath) {
|
|
171
|
+
const root = path.resolve(kitDir);
|
|
172
|
+
if (path.isAbsolute(relativePath))
|
|
173
|
+
return { error: "path must be relative" };
|
|
174
|
+
const lexical = path.resolve(root, relativePath);
|
|
175
|
+
if (lexical === root || !lexical.startsWith(`${root}${path.sep}`))
|
|
176
|
+
return { error: "path must stay inside the kit directory" };
|
|
177
|
+
let fd;
|
|
178
|
+
try {
|
|
179
|
+
const realRoot = fs.realpathSync(root);
|
|
180
|
+
const initial = lstatSafePath(realRoot, relativePath);
|
|
181
|
+
if (!initial.file || !initial.stat)
|
|
182
|
+
return { error: initial.error };
|
|
183
|
+
if (!initial.stat.isFile())
|
|
184
|
+
return { error: "path must reference a regular file" };
|
|
185
|
+
if (initial.stat.size > MAX_FLOW_DEFINITION_BYTES)
|
|
186
|
+
return { error: `file exceeds ${MAX_FLOW_DEFINITION_BYTES} bytes` };
|
|
187
|
+
if (typeof fs.constants.O_NOFOLLOW !== "number")
|
|
188
|
+
return { error: "O_NOFOLLOW is unavailable" };
|
|
189
|
+
fd = fs.openSync(initial.file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
190
|
+
const opened = fs.fstatSync(fd);
|
|
191
|
+
if (!opened.isFile() || !sameIdentity(initial.stat, opened))
|
|
192
|
+
return { error: "flow definition identity changed while opening" };
|
|
193
|
+
const verified = lstatSafePath(realRoot, relativePath);
|
|
194
|
+
if (!verified.stat || !sameIdentity(opened, verified.stat))
|
|
195
|
+
return { error: "flow definition identity changed while opening" };
|
|
196
|
+
const bytes = Buffer.alloc(opened.size);
|
|
197
|
+
let offset = 0;
|
|
198
|
+
while (offset < bytes.length) {
|
|
199
|
+
const read = fs.readSync(fd, bytes, offset, bytes.length - offset, offset);
|
|
200
|
+
if (read === 0)
|
|
201
|
+
break;
|
|
202
|
+
offset += read;
|
|
203
|
+
}
|
|
204
|
+
const after = fs.fstatSync(fd);
|
|
205
|
+
if (offset !== opened.size || after.size !== opened.size || !sameIdentity(opened, after))
|
|
206
|
+
return { error: "file changed while being read" };
|
|
207
|
+
return { definition: JSON.parse(bytes.toString("utf8")) };
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
if (error.code === "ELOOP")
|
|
211
|
+
return { error: "path must not reference a symbolic link" };
|
|
212
|
+
return { error: `path is not readable: ${error.message}` };
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
if (fd !== undefined)
|
|
216
|
+
fs.closeSync(fd);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function lstatSafePath(root, relativePath) {
|
|
220
|
+
const parts = relativePath.split(path.sep);
|
|
221
|
+
let current = root;
|
|
222
|
+
for (const [index, part] of parts.entries()) {
|
|
223
|
+
if (!part || part === "." || part === "..")
|
|
224
|
+
return { error: "path must stay inside the kit directory" };
|
|
225
|
+
current = path.join(current, part);
|
|
226
|
+
const stat = fs.lstatSync(current);
|
|
227
|
+
if (stat.isSymbolicLink())
|
|
228
|
+
return { error: "path must not traverse a symbolic link" };
|
|
229
|
+
if (index < parts.length - 1 && !stat.isDirectory())
|
|
230
|
+
return { error: "path component must be a directory" };
|
|
231
|
+
if (index === parts.length - 1)
|
|
232
|
+
return { file: current, stat };
|
|
233
|
+
}
|
|
234
|
+
return { error: "path must reference a regular file" };
|
|
235
|
+
}
|
|
236
|
+
function sameIdentity(left, right) { return left.dev === right.dev && left.ino === right.ino; }
|
|
237
|
+
function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { isObservableBuilderArtifactRef, isSafeBuilderArtifactRef, parseKitFlowStepActions } from "./action-metadata.js";
|
|
2
|
+
export type { KitFlowStepActionEntry, KitFlowStepArtifactBinding, KitFlowStepExpectationBinding } from "./action-metadata.js";
|
|
1
3
|
export interface KitDependencyEntry {
|
|
2
4
|
kit_id: string;
|
|
3
5
|
reason?: string;
|
|
@@ -23,16 +25,6 @@ export interface KitHookInfluenceExpectationEntry {
|
|
|
23
25
|
must_include_guidance: string[];
|
|
24
26
|
must_include_actions: string[];
|
|
25
27
|
}
|
|
26
|
-
export interface KitFlowStepActionEntry {
|
|
27
|
-
flow_id: string;
|
|
28
|
-
step_id: string;
|
|
29
|
-
skills: string[];
|
|
30
|
-
operations: string[];
|
|
31
|
-
/** Gate expectations produced by this action's explicit operation(s). */
|
|
32
|
-
expectation_ids?: string[];
|
|
33
|
-
/** Durable artifacts produced by an operation-only action. */
|
|
34
|
-
artifacts: string[];
|
|
35
|
-
}
|
|
36
28
|
export type KitSkillRole = "entrypoint" | "profile" | "step" | "shared-primitive" | "extension";
|
|
37
29
|
export interface KitSkillRoleEntry {
|
|
38
30
|
skill_id: string;
|
|
@@ -69,10 +61,6 @@ export declare function parseKitHookInfluenceExpectations(manifest: Record<strin
|
|
|
69
61
|
entries: KitHookInfluenceExpectationEntry[];
|
|
70
62
|
errors: string[];
|
|
71
63
|
};
|
|
72
|
-
export declare function parseKitFlowStepActions(manifest: Record<string, unknown>, manifestPath: string): {
|
|
73
|
-
entries: KitFlowStepActionEntry[];
|
|
74
|
-
errors: string[];
|
|
75
|
-
};
|
|
76
64
|
export declare function parseKitSkillRoles(manifest: Record<string, unknown>, manifestPath: string): {
|
|
77
65
|
entries: KitSkillRoleEntry[];
|
|
78
66
|
errors: string[];
|