@kontourai/flow-agents 3.6.0 → 3.8.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 +19 -0
- package/build/src/builder-flow-run-adapter.d.ts +22 -2
- package/build/src/builder-flow-run-adapter.js +93 -28
- package/build/src/builder-flow-runtime.d.ts +8 -3
- package/build/src/builder-flow-runtime.js +407 -51
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +80 -14
- package/build/src/cli/builder-run.js +14 -18
- package/build/src/cli/workflow-sidecar.d.ts +28 -4
- package/build/src/cli/workflow-sidecar.js +825 -103
- package/build/src/cli/workflow.js +301 -43
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.js +5 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/tools/build-universal-bundles.js +53 -3
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +78 -9
- package/docs/context-map.md +22 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/getting-started.md +9 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +75 -40
- package/docs/workflow-usage-guide.md +109 -42
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +52 -41
- package/evals/integration/test_builder_step_producers.sh +330 -6
- package/evals/integration/test_bundle_install.sh +318 -65
- package/evals/integration/test_bundle_lifecycle.sh +4 -6
- package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
- package/evals/integration/test_current_json_per_actor.sh +12 -0
- package/evals/integration/test_dual_emit_flow_step.sh +62 -43
- package/evals/integration/test_flowdef_session_activation.sh +145 -25
- package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
- package/evals/integration/test_gate_lockdown.sh +3 -5
- package/evals/integration/test_goal_fit_hook.sh +60 -2
- package/evals/integration/test_install_merge.sh +18 -8
- package/evals/integration/test_liveness_verdict.sh +14 -17
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
- package/evals/integration/test_public_workflow_cli.sh +334 -14
- package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
- package/evals/integration/test_sidecar_field_preservation.sh +36 -11
- package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
- package/evals/integration/test_workflow_steering_hook.sh +15 -38
- package/evals/run.sh +2 -0
- package/evals/static/test_builder_skill_coherence.sh +247 -0
- package/evals/static/test_library_exports.sh +5 -2
- package/evals/static/test_universal_bundles.sh +44 -1
- package/evals/static/test_workflow_skills.sh +13 -325
- package/kits/builder/flows/build.flow.json +22 -0
- package/kits/builder/flows/shape.flow.json +9 -9
- package/kits/builder/kit.json +70 -16
- package/kits/builder/skills/builder-shape/SKILL.md +75 -75
- package/kits/builder/skills/continue-work/SKILL.md +45 -106
- package/kits/builder/skills/deliver/SKILL.md +96 -442
- package/kits/builder/skills/design-probe/SKILL.md +40 -139
- package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
- package/kits/builder/skills/execute-plan/SKILL.md +54 -125
- package/kits/builder/skills/fix-bug/SKILL.md +42 -132
- package/kits/builder/skills/gate-review/SKILL.md +60 -211
- package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
- package/kits/builder/skills/learning-review/SKILL.md +63 -170
- package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
- package/kits/builder/skills/plan-work/SKILL.md +51 -185
- package/kits/builder/skills/pull-work/SKILL.md +136 -485
- package/kits/builder/skills/release-readiness/SKILL.md +66 -107
- package/kits/builder/skills/review-work/SKILL.md +89 -176
- package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
- package/kits/builder/skills/verify-work/SKILL.md +101 -113
- package/package.json +2 -2
- package/packaging/README.md +1 -1
- package/scripts/README.md +1 -1
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/scripts/install-codex-home.sh +63 -23
- package/scripts/install-owned-files.js +18 -2
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +426 -64
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +75 -14
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +436 -18
- package/src/cli/builder-run.ts +3 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +746 -103
- package/src/cli/workflow.ts +288 -41
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +6 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/tools/build-universal-bundles.ts +51 -3
- package/src/tools/generate-context-map.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.8.0](https://github.com/kontourai/flow-agents/compare/v3.7.0...v3.8.0) (2026-07-12)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **packaging:** install portable skills under .agents ([#551](https://github.com/kontourai/flow-agents/issues/551)) ([12f12e3](https://github.com/kontourai/flow-agents/commit/12f12e3d0a32b398e47a9ac01604179c58bf14ba))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
* **builder:** make gate evidence sync visit-safe ([#558](https://github.com/kontourai/flow-agents/issues/558)) ([1c0e8dc](https://github.com/kontourai/flow-agents/commit/1c0e8dcea6bdfd7d54484f950b2432fcf727b0ea))
|
|
14
|
+
|
|
15
|
+
## [3.7.0](https://github.com/kontourai/flow-agents/compare/v3.6.0...v3.7.0) (2026-07-12)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **builder:** align kit skills with canonical Flow ([#552](https://github.com/kontourai/flow-agents/issues/552)) ([2d672ed](https://github.com/kontourai/flow-agents/commit/2d672ede2dc16f96ef2d5186a3f0b6fc1c9d162f))
|
|
21
|
+
|
|
3
22
|
## [3.6.0](https://github.com/kontourai/flow-agents/compare/v3.5.0...v3.6.0) (2026-07-11)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type FlowEvidenceEntry, type FlowLifecycleRequest, type FlowRunState, type GateOutcome, type JsonObject } from "@kontourai/flow";
|
|
2
2
|
export declare const BUILDER_BUILD_FLOW_ID = "builder.build";
|
|
3
3
|
export declare const BUILDER_BUILD_FLOW_RELATIVE_PATH = "kits/builder/flows/build.flow.json";
|
|
4
|
+
export declare const BUILDER_SHAPE_FLOW_ID = "builder.shape";
|
|
5
|
+
export declare const BUILDER_SHAPE_FLOW_RELATIVE_PATH = "kits/builder/flows/shape.flow.json";
|
|
6
|
+
export type BuilderFlowId = typeof BUILDER_BUILD_FLOW_ID | typeof BUILDER_SHAPE_FLOW_ID;
|
|
4
7
|
export interface BuilderBuildTrustBundleEvidenceInput {
|
|
5
8
|
gate: string;
|
|
6
9
|
/**
|
|
@@ -8,6 +11,8 @@ export interface BuilderBuildTrustBundleEvidenceInput {
|
|
|
8
11
|
* Callers must not pass raw user-controlled paths to this local runtime API.
|
|
9
12
|
*/
|
|
10
13
|
file: string;
|
|
14
|
+
/** SHA-256 of the immutable snapshot validated by Flow Agents before Flow attaches it. */
|
|
15
|
+
expectedSha256?: string;
|
|
11
16
|
status?: "passed" | "failed";
|
|
12
17
|
producer?: string;
|
|
13
18
|
authorityTrace?: string;
|
|
@@ -28,6 +33,9 @@ export interface StartBuilderBuildRunInput {
|
|
|
28
33
|
cwd?: string;
|
|
29
34
|
runId?: string;
|
|
30
35
|
}
|
|
36
|
+
export interface StartBuilderFlowRunInput extends StartBuilderBuildRunInput {
|
|
37
|
+
flowId: BuilderFlowId;
|
|
38
|
+
}
|
|
31
39
|
export interface EvaluateBuilderBuildRunInput {
|
|
32
40
|
runId: string;
|
|
33
41
|
/**
|
|
@@ -45,8 +53,8 @@ export interface ChangeBuilderBuildRunLifecycleInput extends LoadBuilderBuildRun
|
|
|
45
53
|
request: FlowLifecycleRequest;
|
|
46
54
|
at?: string;
|
|
47
55
|
}
|
|
48
|
-
export interface
|
|
49
|
-
definitionId:
|
|
56
|
+
export interface BuilderFlowRunResult {
|
|
57
|
+
definitionId: BuilderFlowId;
|
|
50
58
|
definitionVersion: string;
|
|
51
59
|
runId: string;
|
|
52
60
|
dir: string;
|
|
@@ -56,6 +64,9 @@ export interface BuilderBuildRunResult {
|
|
|
56
64
|
manifest: JsonObject;
|
|
57
65
|
freshnessTransitions: JsonObject[];
|
|
58
66
|
}
|
|
67
|
+
export interface BuilderBuildRunResult extends Omit<BuilderFlowRunResult, "definitionId"> {
|
|
68
|
+
definitionId: typeof BUILDER_BUILD_FLOW_ID;
|
|
69
|
+
}
|
|
59
70
|
export type BuilderBuildRunIdentityMismatch = "definition-id" | "definition-version" | "definition-content";
|
|
60
71
|
export declare class BuilderBuildRunInputError extends Error {
|
|
61
72
|
readonly code: "BUILDER_BUILD_RUN_INVALID_INPUT";
|
|
@@ -80,10 +91,19 @@ export declare class BuilderBuildRunIdentityError extends Error {
|
|
|
80
91
|
}
|
|
81
92
|
export declare function resolveBuilderBuildFlowDefinitionPath(startDir?: string): string;
|
|
82
93
|
export declare function startBuilderBuildRun(input: StartBuilderBuildRunInput): Promise<BuilderBuildRunResult>;
|
|
94
|
+
export declare function resolveBuilderFlowDefinitionPath(flowId: BuilderFlowId, startDir?: string): string;
|
|
95
|
+
export declare function startBuilderFlowRun(input: StartBuilderFlowRunInput): Promise<BuilderFlowRunResult>;
|
|
83
96
|
export declare function evaluateBuilderBuildRun(input: EvaluateBuilderBuildRunInput): Promise<BuilderBuildRunResult>;
|
|
97
|
+
export declare function evaluateBuilderFlowRun(input: EvaluateBuilderBuildRunInput): Promise<BuilderFlowRunResult>;
|
|
84
98
|
export declare function loadBuilderBuildRun(input: LoadBuilderBuildRunInput): Promise<BuilderBuildRunResult>;
|
|
99
|
+
export declare function loadBuilderFlowRun(input: LoadBuilderBuildRunInput): Promise<BuilderFlowRunResult>;
|
|
85
100
|
export declare function pauseBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult>;
|
|
86
101
|
export declare function resumeBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult>;
|
|
87
102
|
export declare function cancelBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult & {
|
|
88
103
|
idempotent: boolean;
|
|
89
104
|
}>;
|
|
105
|
+
export declare function pauseBuilderFlowRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderFlowRunResult>;
|
|
106
|
+
export declare function resumeBuilderFlowRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderFlowRunResult>;
|
|
107
|
+
export declare function cancelBuilderFlowRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderFlowRunResult & {
|
|
108
|
+
idempotent: boolean;
|
|
109
|
+
}>;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { isDeepStrictEqual } from "node:util";
|
|
6
|
-
import { attachEvidence, cancelRun, evaluateRun, expectationsForGate, loadRun, normalizeTrustBundle, openGates, pauseRun,
|
|
6
|
+
import { attachEvidence, cancelRun, evaluateRun, expectationsForGate, loadRun, normalizeTrustBundle, openGates, pauseRun, resumeRun, startRun, validateDefinition, } from "@kontourai/flow";
|
|
7
7
|
import { resolveEffectiveFlowDefinition } from "./lib/flow-resolver.js";
|
|
8
8
|
export const BUILDER_BUILD_FLOW_ID = "builder.build";
|
|
9
9
|
export const BUILDER_BUILD_FLOW_RELATIVE_PATH = "kits/builder/flows/build.flow.json";
|
|
10
|
+
export const BUILDER_SHAPE_FLOW_ID = "builder.shape";
|
|
11
|
+
export const BUILDER_SHAPE_FLOW_RELATIVE_PATH = "kits/builder/flows/shape.flow.json";
|
|
10
12
|
export class BuilderBuildRunInputError extends Error {
|
|
11
13
|
code = "BUILDER_BUILD_RUN_INVALID_INPUT";
|
|
12
14
|
field;
|
|
@@ -36,18 +38,25 @@ export class BuilderBuildRunIdentityError extends Error {
|
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
export function resolveBuilderBuildFlowDefinitionPath(startDir = moduleDirectory()) {
|
|
39
|
-
|
|
40
|
-
return path.join(root, BUILDER_BUILD_FLOW_RELATIVE_PATH);
|
|
41
|
+
return resolveBuilderFlowDefinitionPath(BUILDER_BUILD_FLOW_ID, startDir);
|
|
41
42
|
}
|
|
42
43
|
export async function startBuilderBuildRun(input) {
|
|
44
|
+
const result = await startBuilderFlowRun({ ...input, flowId: BUILDER_BUILD_FLOW_ID });
|
|
45
|
+
return asBuilderBuildResult(result, input.runId ?? result.runId);
|
|
46
|
+
}
|
|
47
|
+
export function resolveBuilderFlowDefinitionPath(flowId, startDir = moduleDirectory()) {
|
|
48
|
+
const root = findPackageRoot(startDir);
|
|
49
|
+
return path.join(root, flowRelativePath(flowId));
|
|
50
|
+
}
|
|
51
|
+
export async function startBuilderFlowRun(input) {
|
|
43
52
|
assertRuntimeInput(input, ["evidence", "now", "gate"]);
|
|
44
53
|
if (!isNonEmptyString(input.subject)) {
|
|
45
54
|
throw new BuilderBuildRunInputError("subject", "must be a non-empty string");
|
|
46
55
|
}
|
|
47
56
|
const cwd = input.cwd ?? process.cwd();
|
|
48
|
-
const definitionPath =
|
|
49
|
-
const definition = await
|
|
50
|
-
const runtimeDefinitionPath = materializeRuntimeDefinition(cwd, definition);
|
|
57
|
+
const definitionPath = resolveBuilderFlowDefinitionPath(input.flowId);
|
|
58
|
+
const definition = await loadShippedBuilderFlowDefinition(input.flowId, definitionPath);
|
|
59
|
+
const runtimeDefinitionPath = materializeRuntimeDefinition(cwd, input.flowId, definition);
|
|
51
60
|
const started = await startRun(runtimeDefinitionPath, {
|
|
52
61
|
cwd,
|
|
53
62
|
runId: input.runId,
|
|
@@ -56,25 +65,39 @@ export async function startBuilderBuildRun(input) {
|
|
|
56
65
|
subject: input.subject,
|
|
57
66
|
},
|
|
58
67
|
});
|
|
59
|
-
const run = await
|
|
68
|
+
const run = await loadCanonicalBuilderFlowRun(started.runId, cwd, definition);
|
|
60
69
|
return resultFromRun(run, started.runId);
|
|
61
70
|
}
|
|
62
71
|
export async function evaluateBuilderBuildRun(input) {
|
|
72
|
+
const result = await evaluateBuilderFlowRun(input);
|
|
73
|
+
return asBuilderBuildResult(result, input.runId);
|
|
74
|
+
}
|
|
75
|
+
export async function evaluateBuilderFlowRun(input) {
|
|
63
76
|
assertRuntimeInput(input, ["now", "gate"]);
|
|
64
77
|
if (Array.isArray(input.evidence)) {
|
|
65
78
|
throw new BuilderBuildRunInputError("evidence", "must be zero or one evidence object, not an array");
|
|
66
79
|
}
|
|
67
80
|
const cwd = input.cwd ?? process.cwd();
|
|
68
81
|
const run = await loadRun(input.runId, cwd);
|
|
69
|
-
const definition = await
|
|
82
|
+
const definition = await loadShippedBuilderFlowDefinitionForRun(input.runId, run.definition);
|
|
70
83
|
assertCanonicalDefinition(input.runId, definition, run.definition);
|
|
71
84
|
let attachedEvidence = [];
|
|
72
85
|
if (input.evidence !== undefined) {
|
|
73
86
|
const evidence = validateEvidenceInput(input.evidence);
|
|
74
87
|
assertCurrentOpenGate(run.definition, run.state, evidence.gate);
|
|
75
|
-
const
|
|
88
|
+
const source = path.resolve(cwd, evidence.file);
|
|
89
|
+
const bytes = readFileSync(source);
|
|
90
|
+
const validatedSha256 = createHash("sha256").update(bytes).digest("hex");
|
|
91
|
+
if (evidence.expectedSha256 && evidence.expectedSha256 !== validatedSha256) {
|
|
92
|
+
throw new BuilderBuildRunInputError("evidence.expectedSha256", "does not match the bytes presented for validation");
|
|
93
|
+
}
|
|
94
|
+
const normalized = normalizeTrustBundle(JSON.parse(bytes.toString("utf8")));
|
|
76
95
|
assertBundleSubjects(normalized.bundle, run.state.subject, openGates(run.definition, run.state)[0]);
|
|
77
|
-
|
|
96
|
+
const attached = await attachEvidence(input.runId, trustBundleAttachOptions(cwd, evidence, validatedSha256));
|
|
97
|
+
if (attached.sha256 !== validatedSha256) {
|
|
98
|
+
throw new BuilderBuildRunInputError("evidence.file", "changed after validation before Flow attachment");
|
|
99
|
+
}
|
|
100
|
+
attachedEvidence = [attached];
|
|
78
101
|
}
|
|
79
102
|
const evaluated = await evaluateRun(input.runId, { cwd });
|
|
80
103
|
return {
|
|
@@ -90,35 +113,51 @@ export async function evaluateBuilderBuildRun(input) {
|
|
|
90
113
|
};
|
|
91
114
|
}
|
|
92
115
|
export async function loadBuilderBuildRun(input) {
|
|
116
|
+
const result = await loadBuilderFlowRun(input);
|
|
117
|
+
return asBuilderBuildResult(result, input.runId);
|
|
118
|
+
}
|
|
119
|
+
export async function loadBuilderFlowRun(input) {
|
|
93
120
|
assertRuntimeInput(input, ["evidence", "now", "gate"]);
|
|
94
121
|
const cwd = input.cwd ?? process.cwd();
|
|
95
122
|
const run = await loadRun(input.runId, cwd);
|
|
96
|
-
const definition = await
|
|
123
|
+
const definition = await loadShippedBuilderFlowDefinitionForRun(input.runId, run.definition);
|
|
97
124
|
assertCanonicalDefinition(input.runId, definition, run.definition);
|
|
98
125
|
return resultFromRun(run, input.runId);
|
|
99
126
|
}
|
|
100
127
|
export async function pauseBuilderBuildRun(input) {
|
|
101
|
-
|
|
128
|
+
const result = await pauseBuilderFlowRun(input);
|
|
129
|
+
return asBuilderBuildResult(result, input.runId);
|
|
102
130
|
}
|
|
103
131
|
export async function resumeBuilderBuildRun(input) {
|
|
104
|
-
|
|
132
|
+
const result = await resumeBuilderFlowRun(input);
|
|
133
|
+
return asBuilderBuildResult(result, input.runId);
|
|
105
134
|
}
|
|
106
135
|
export async function cancelBuilderBuildRun(input) {
|
|
107
|
-
const changed = await
|
|
136
|
+
const changed = await changeBuilderFlowRunLifecycleResult(input, cancelRun);
|
|
137
|
+
return { ...asBuilderBuildResult(resultFromRun(changed, input.runId), input.runId), idempotent: changed.idempotent };
|
|
138
|
+
}
|
|
139
|
+
export async function pauseBuilderFlowRun(input) {
|
|
140
|
+
return changeBuilderFlowRunLifecycle(input, pauseRun);
|
|
141
|
+
}
|
|
142
|
+
export async function resumeBuilderFlowRun(input) {
|
|
143
|
+
return changeBuilderFlowRunLifecycle(input, resumeRun);
|
|
144
|
+
}
|
|
145
|
+
export async function cancelBuilderFlowRun(input) {
|
|
146
|
+
const changed = await changeBuilderFlowRunLifecycleResult(input, cancelRun);
|
|
108
147
|
return { ...resultFromRun(changed, input.runId), idempotent: changed.idempotent };
|
|
109
148
|
}
|
|
110
|
-
async function
|
|
111
|
-
const changed = await
|
|
149
|
+
async function changeBuilderFlowRunLifecycle(input, operation) {
|
|
150
|
+
const changed = await changeBuilderFlowRunLifecycleResult(input, operation);
|
|
112
151
|
return resultFromRun(changed, input.runId);
|
|
113
152
|
}
|
|
114
|
-
async function
|
|
153
|
+
async function changeBuilderFlowRunLifecycleResult(input, operation) {
|
|
115
154
|
assertRuntimeInput(input, []);
|
|
116
155
|
if (!isRecord(input.request))
|
|
117
156
|
throw new BuilderBuildRunInputError("request", "must be a lifecycle request object");
|
|
118
157
|
const cwd = input.cwd ?? process.cwd();
|
|
119
|
-
const before = await
|
|
158
|
+
const before = await loadBuilderFlowRun({ runId: input.runId, cwd });
|
|
120
159
|
const changed = await operation(input.runId, { cwd, ...input.request, ...(input.at ? { at: input.at } : {}) });
|
|
121
|
-
const definition = await
|
|
160
|
+
const definition = await loadShippedBuilderFlowDefinitionForRun(input.runId, changed.definition);
|
|
122
161
|
assertCanonicalDefinition(input.runId, definition, changed.definition);
|
|
123
162
|
if (changed.state.subject !== before.state.subject) {
|
|
124
163
|
throw new BuilderBuildRunInputError("flow_run.state.subject", "changed during lifecycle transition");
|
|
@@ -138,33 +177,55 @@ function resultFromRun(run, runId) {
|
|
|
138
177
|
freshnessTransitions: [],
|
|
139
178
|
};
|
|
140
179
|
}
|
|
141
|
-
async function
|
|
180
|
+
async function loadCanonicalBuilderFlowRun(runId, cwd, definition) {
|
|
142
181
|
const run = await loadRun(runId, cwd);
|
|
143
182
|
assertCanonicalDefinition(runId, definition, run.definition);
|
|
144
183
|
return run;
|
|
145
184
|
}
|
|
146
|
-
async function
|
|
185
|
+
async function loadShippedBuilderFlowDefinition(flowId, definitionPath) {
|
|
147
186
|
const packageRoot = findPackageRoot(path.dirname(definitionPath));
|
|
148
|
-
const effective = resolveEffectiveFlowDefinition(
|
|
187
|
+
const effective = resolveEffectiveFlowDefinition(flowId, packageRoot, { allowOverride: false });
|
|
149
188
|
if (!effective) {
|
|
150
189
|
throw new BuilderBuildRunInputError("definition", "could not compile the shipped uses_flow composition");
|
|
151
190
|
}
|
|
152
191
|
const definition = validateDefinition(effective);
|
|
153
|
-
if (definition.id !==
|
|
154
|
-
throw new BuilderBuildRunInputError("definition", `expected shipped definition id ${
|
|
192
|
+
if (definition.id !== flowId) {
|
|
193
|
+
throw new BuilderBuildRunInputError("definition", `expected shipped definition id ${flowId}`);
|
|
155
194
|
}
|
|
156
195
|
return definition;
|
|
157
196
|
}
|
|
158
|
-
function
|
|
197
|
+
async function loadShippedBuilderFlowDefinitionForRun(runId, actualDefinition) {
|
|
198
|
+
const flowId = actualDefinition.id;
|
|
199
|
+
if (!isBuilderFlowId(flowId)) {
|
|
200
|
+
throw new BuilderBuildRunIdentityError(runId, { id: BUILDER_BUILD_FLOW_ID, version: "unknown" }, actualDefinition, "definition-id");
|
|
201
|
+
}
|
|
202
|
+
return loadShippedBuilderFlowDefinition(flowId, resolveBuilderFlowDefinitionPath(flowId));
|
|
203
|
+
}
|
|
204
|
+
function materializeRuntimeDefinition(cwd, flowId, definition) {
|
|
159
205
|
const content = `${JSON.stringify(definition, null, 2)}\n`;
|
|
160
206
|
const digest = createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
161
207
|
const directory = path.join(cwd, ".kontourai", "flow-agents", "runtime-definitions");
|
|
162
208
|
mkdirSync(directory, { recursive: true });
|
|
163
|
-
const file = path.join(directory,
|
|
209
|
+
const file = path.join(directory, `${flowId.replace(".", "-")}-${digest}.flow.json`);
|
|
164
210
|
if (!existsSync(file))
|
|
165
211
|
writeFileSync(file, content);
|
|
166
212
|
return file;
|
|
167
213
|
}
|
|
214
|
+
function flowRelativePath(flowId) {
|
|
215
|
+
return flowId === BUILDER_BUILD_FLOW_ID ? BUILDER_BUILD_FLOW_RELATIVE_PATH : BUILDER_SHAPE_FLOW_RELATIVE_PATH;
|
|
216
|
+
}
|
|
217
|
+
function isBuilderFlowId(value) {
|
|
218
|
+
return value === BUILDER_BUILD_FLOW_ID || value === BUILDER_SHAPE_FLOW_ID;
|
|
219
|
+
}
|
|
220
|
+
function assertExpectedFlow(runId, actual, expected) {
|
|
221
|
+
if (actual === expected)
|
|
222
|
+
return;
|
|
223
|
+
throw new BuilderBuildRunIdentityError(runId, { id: expected, version: "unknown" }, { id: actual, version: "unknown" }, "definition-id");
|
|
224
|
+
}
|
|
225
|
+
function asBuilderBuildResult(result, runId) {
|
|
226
|
+
assertExpectedFlow(runId, result.definitionId, BUILDER_BUILD_FLOW_ID);
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
168
229
|
function assertCanonicalDefinition(runId, expectedDefinition, actualDefinition) {
|
|
169
230
|
if (isDeepStrictEqual(actualDefinition, expectedDefinition))
|
|
170
231
|
return;
|
|
@@ -195,6 +256,9 @@ function validateEvidenceInput(evidence) {
|
|
|
195
256
|
if (!isNonEmptyString(evidence.file)) {
|
|
196
257
|
throw new BuilderBuildRunInputError("evidence.file", "must be a non-empty string");
|
|
197
258
|
}
|
|
259
|
+
if (evidence.expectedSha256 !== undefined && (!isNonEmptyString(evidence.expectedSha256) || !/^[a-f0-9]{64}$/i.test(evidence.expectedSha256))) {
|
|
260
|
+
throw new BuilderBuildRunInputError("evidence.expectedSha256", "must be a SHA-256 hex digest");
|
|
261
|
+
}
|
|
198
262
|
if (evidence.status !== undefined && evidence.status !== "passed" && evidence.status !== "failed") {
|
|
199
263
|
throw new BuilderBuildRunInputError("evidence.status", "must be passed or failed");
|
|
200
264
|
}
|
|
@@ -227,11 +291,12 @@ function assertBundleSubjects(bundle, subject, gate) {
|
|
|
227
291
|
}
|
|
228
292
|
}
|
|
229
293
|
}
|
|
230
|
-
function trustBundleAttachOptions(cwd, evidence) {
|
|
294
|
+
function trustBundleAttachOptions(cwd, evidence, expectedSha256) {
|
|
231
295
|
return {
|
|
232
296
|
cwd,
|
|
233
297
|
gate: evidence.gate,
|
|
234
298
|
file: evidence.file,
|
|
299
|
+
expectedSha256,
|
|
235
300
|
kind: "trust.bundle",
|
|
236
301
|
bundle: true,
|
|
237
302
|
...(evidence.status ? { status: evidence.status } : {}),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type BuilderFlowId, type BuilderFlowRunResult } from "./builder-flow-run-adapter.js";
|
|
2
2
|
type AnyRecord = Record<string, any>;
|
|
3
3
|
export interface BuilderFlowSessionInput {
|
|
4
4
|
sessionDir: string;
|
|
5
|
+
flowId?: BuilderFlowId;
|
|
5
6
|
}
|
|
6
7
|
export interface BuilderFlowAuthorizedLifecycleInput extends BuilderFlowSessionInput {
|
|
7
8
|
authorizationFile: string;
|
|
@@ -12,13 +13,14 @@ export interface BuilderFlowAgentLifecycleInput extends BuilderFlowSessionInput
|
|
|
12
13
|
export interface BuilderFlowSessionResult {
|
|
13
14
|
sessionDir: string;
|
|
14
15
|
projectRoot: string;
|
|
15
|
-
run:
|
|
16
|
+
run: BuilderFlowRunResult;
|
|
16
17
|
projection: AnyRecord;
|
|
17
18
|
attached: boolean;
|
|
18
19
|
}
|
|
19
20
|
export declare function startBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
|
|
20
21
|
export declare function syncBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
|
|
21
22
|
export declare function recoverBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
|
|
23
|
+
export declare function inspectBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
|
|
22
24
|
export declare function pauseBuilderFlowSession(input: BuilderFlowAgentLifecycleInput): Promise<BuilderFlowSessionResult>;
|
|
23
25
|
export declare function resumeBuilderFlowSession(input: BuilderFlowAgentLifecycleInput): Promise<BuilderFlowSessionResult>;
|
|
24
26
|
export declare function cancelBuilderFlowSession(input: BuilderFlowAuthorizedLifecycleInput): Promise<BuilderFlowSessionResult & {
|
|
@@ -31,5 +33,8 @@ export declare function releaseBuilderFlowAssignment(input: BuilderFlowAgentLife
|
|
|
31
33
|
export declare function archiveBuilderFlowSession(input: BuilderFlowAuthorizedLifecycleInput): Promise<BuilderFlowSessionResult & {
|
|
32
34
|
archiveDir: string;
|
|
33
35
|
}>;
|
|
34
|
-
export declare function
|
|
36
|
+
export declare function captureReviewWorkspaceSnapshot(projectRoot: string, reviewedFiles: Array<{
|
|
37
|
+
file: string;
|
|
38
|
+
sha256: string;
|
|
39
|
+
}>): AnyRecord;
|
|
35
40
|
export {};
|