@kontourai/flow-agents 3.5.0 → 3.7.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.
Files changed (111) hide show
  1. package/.github/workflows/ci.yml +4 -0
  2. package/CHANGELOG.md +15 -0
  3. package/build/src/builder-flow-run-adapter.d.ts +32 -3
  4. package/build/src/builder-flow-run-adapter.js +113 -20
  5. package/build/src/builder-flow-runtime.d.ts +26 -3
  6. package/build/src/builder-flow-runtime.js +502 -49
  7. package/build/src/builder-lifecycle-authority.d.ts +35 -0
  8. package/build/src/builder-lifecycle-authority.js +219 -0
  9. package/build/src/cli/assignment-provider.d.ts +14 -7
  10. package/build/src/cli/assignment-provider.js +128 -65
  11. package/build/src/cli/builder-run.js +46 -9
  12. package/build/src/cli/workflow-artifact-cleanup-audit.js +3 -0
  13. package/build/src/cli/workflow-sidecar.d.ts +30 -3
  14. package/build/src/cli/workflow-sidecar.js +825 -99
  15. package/build/src/cli/workflow.d.ts +2 -0
  16. package/build/src/cli/workflow.js +769 -0
  17. package/build/src/cli.js +2 -0
  18. package/build/src/flow-kit/validate.d.ts +17 -0
  19. package/build/src/flow-kit/validate.js +340 -2
  20. package/build/src/index.d.ts +4 -0
  21. package/build/src/index.js +7 -5
  22. package/build/src/lib/observed-command.d.ts +7 -0
  23. package/build/src/lib/observed-command.js +100 -0
  24. package/build/src/lib/package-version.d.ts +2 -0
  25. package/build/src/lib/package-version.js +13 -0
  26. package/build/src/lib/pinned-cli-command.d.ts +6 -0
  27. package/build/src/lib/pinned-cli-command.js +21 -0
  28. package/build/src/tools/generate-context-map.js +5 -3
  29. package/context/contracts/artifact-contract.md +1 -1
  30. package/context/scripts/hooks/config-protection.js +8 -1
  31. package/context/scripts/hooks/lib/config-protection-remedies.js +3 -0
  32. package/context/scripts/hooks/lib/kit-catalog.js +1 -1
  33. package/context/scripts/hooks/stop-goal-fit.js +79 -10
  34. package/docs/context-map.md +24 -20
  35. package/docs/developer-architecture.md +1 -1
  36. package/docs/public-workflow-cli.md +132 -0
  37. package/docs/skills-map.md +51 -27
  38. package/docs/spec/builder-flow-runtime.md +78 -40
  39. package/docs/workflow-usage-guide.md +110 -38
  40. package/evals/ci/run-baseline.sh +2 -0
  41. package/evals/fixtures/hook-influence/cases.json +2 -2
  42. package/evals/integration/test_builder_entry_enforcement.sh +57 -45
  43. package/evals/integration/test_builder_step_producers.sh +297 -6
  44. package/evals/integration/test_bundle_install.sh +258 -55
  45. package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
  46. package/evals/integration/test_current_json_per_actor.sh +12 -0
  47. package/evals/integration/test_dual_emit_flow_step.sh +62 -43
  48. package/evals/integration/test_flowdef_session_activation.sh +145 -25
  49. package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
  50. package/evals/integration/test_gate_lockdown.sh +3 -5
  51. package/evals/integration/test_goal_fit_hook.sh +60 -2
  52. package/evals/integration/test_liveness_verdict.sh +14 -17
  53. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
  54. package/evals/integration/test_public_workflow_cli.sh +573 -0
  55. package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
  56. package/evals/integration/test_sidecar_field_preservation.sh +36 -11
  57. package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
  58. package/evals/integration/test_workflow_steering_hook.sh +15 -38
  59. package/evals/run.sh +2 -0
  60. package/evals/static/test_builder_skill_coherence.sh +247 -0
  61. package/evals/static/test_library_exports.sh +5 -2
  62. package/evals/static/test_workflow_skills.sh +13 -325
  63. package/kits/builder/flows/build.flow.json +22 -0
  64. package/kits/builder/flows/shape.flow.json +9 -9
  65. package/kits/builder/kit.json +70 -16
  66. package/kits/builder/skills/builder-shape/SKILL.md +75 -75
  67. package/kits/builder/skills/continue-work/SKILL.md +45 -106
  68. package/kits/builder/skills/deliver/SKILL.md +96 -442
  69. package/kits/builder/skills/design-probe/SKILL.md +40 -139
  70. package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
  71. package/kits/builder/skills/execute-plan/SKILL.md +54 -125
  72. package/kits/builder/skills/fix-bug/SKILL.md +42 -132
  73. package/kits/builder/skills/gate-review/SKILL.md +60 -211
  74. package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
  75. package/kits/builder/skills/learning-review/SKILL.md +63 -170
  76. package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
  77. package/kits/builder/skills/plan-work/SKILL.md +51 -185
  78. package/kits/builder/skills/pull-work/SKILL.md +136 -485
  79. package/kits/builder/skills/release-readiness/SKILL.md +66 -107
  80. package/kits/builder/skills/review-work/SKILL.md +89 -176
  81. package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
  82. package/kits/builder/skills/verify-work/SKILL.md +101 -113
  83. package/package.json +2 -2
  84. package/schemas/builder-lifecycle-authorization.schema.json +57 -0
  85. package/schemas/lifecycle-authority-keys.schema.json +25 -0
  86. package/schemas/workflow-state.schema.json +1 -1
  87. package/scripts/hooks/config-protection.js +8 -1
  88. package/scripts/hooks/lib/config-protection-remedies.js +3 -0
  89. package/scripts/hooks/lib/kit-catalog.js +1 -1
  90. package/scripts/hooks/stop-goal-fit.js +79 -10
  91. package/src/builder-flow-run-adapter.ts +156 -23
  92. package/src/builder-flow-runtime.ts +535 -53
  93. package/src/builder-lifecycle-authority.ts +218 -0
  94. package/src/cli/assignment-provider-lock.test.mjs +83 -0
  95. package/src/cli/assignment-provider.ts +91 -22
  96. package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
  97. package/src/cli/builder-flow-runtime.test.mjs +597 -8
  98. package/src/cli/builder-run.ts +54 -9
  99. package/src/cli/kit-metadata-security.test.mjs +232 -6
  100. package/src/cli/public-api.test.mjs +15 -0
  101. package/src/cli/workflow-artifact-cleanup-audit.ts +3 -0
  102. package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
  103. package/src/cli/workflow-sidecar.ts +748 -99
  104. package/src/cli/workflow.ts +708 -0
  105. package/src/cli.ts +2 -0
  106. package/src/flow-kit/validate.ts +320 -2
  107. package/src/index.ts +20 -5
  108. package/src/lib/observed-command.ts +96 -0
  109. package/src/lib/package-version.ts +15 -0
  110. package/src/lib/pinned-cli-command.ts +23 -0
  111. package/src/tools/generate-context-map.ts +5 -3
@@ -266,6 +266,10 @@ jobs:
266
266
  continue-on-error: true
267
267
  run: bash evals/ci/run-baseline.sh --check bundle-install-integration
268
268
 
269
+ - name: Public workflow CLI integration
270
+ continue-on-error: true
271
+ run: bash evals/ci/run-baseline.sh --check public-workflow-cli-integration
272
+
269
273
  - name: Bundle lifecycle integration
270
274
  continue-on-error: true
271
275
  run: bash evals/ci/run-baseline.sh --check bundle-lifecycle-integration
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.7.0](https://github.com/kontourai/flow-agents/compare/v3.6.0...v3.7.0) (2026-07-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * **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))
9
+
10
+ ## [3.6.0](https://github.com/kontourai/flow-agents/compare/v3.5.0...v3.6.0) (2026-07-11)
11
+
12
+
13
+ ### Features
14
+
15
+ * **builder:** add authority-aware lifecycle controls ([#546](https://github.com/kontourai/flow-agents/issues/546)) ([5164902](https://github.com/kontourai/flow-agents/commit/51649020bc9a90dd77907f2aabdd9fb593f43504))
16
+ * **cli:** add public workflow command ([#548](https://github.com/kontourai/flow-agents/issues/548)) ([2dad479](https://github.com/kontourai/flow-agents/commit/2dad47974819100ecb850fa0bec645e911d168f8))
17
+
3
18
  ## [3.5.0](https://github.com/kontourai/flow-agents/compare/v3.4.3...v3.5.0) (2026-07-10)
4
19
 
5
20
 
@@ -1,6 +1,9 @@
1
- import { type FlowEvidenceEntry, type FlowRunState, type GateOutcome, type JsonObject } from "@kontourai/flow";
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
  /**
@@ -41,8 +49,12 @@ export interface LoadBuilderBuildRunInput {
41
49
  runId: string;
42
50
  cwd?: string;
43
51
  }
44
- export interface BuilderBuildRunResult {
45
- definitionId: typeof BUILDER_BUILD_FLOW_ID;
52
+ export interface ChangeBuilderBuildRunLifecycleInput extends LoadBuilderBuildRunInput {
53
+ request: FlowLifecycleRequest;
54
+ at?: string;
55
+ }
56
+ export interface BuilderFlowRunResult {
57
+ definitionId: BuilderFlowId;
46
58
  definitionVersion: string;
47
59
  runId: string;
48
60
  dir: string;
@@ -52,6 +64,9 @@ export interface BuilderBuildRunResult {
52
64
  manifest: JsonObject;
53
65
  freshnessTransitions: JsonObject[];
54
66
  }
67
+ export interface BuilderBuildRunResult extends Omit<BuilderFlowRunResult, "definitionId"> {
68
+ definitionId: typeof BUILDER_BUILD_FLOW_ID;
69
+ }
55
70
  export type BuilderBuildRunIdentityMismatch = "definition-id" | "definition-version" | "definition-content";
56
71
  export declare class BuilderBuildRunInputError extends Error {
57
72
  readonly code: "BUILDER_BUILD_RUN_INVALID_INPUT";
@@ -76,5 +91,19 @@ export declare class BuilderBuildRunIdentityError extends Error {
76
91
  }
77
92
  export declare function resolveBuilderBuildFlowDefinitionPath(startDir?: string): string;
78
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>;
79
96
  export declare function evaluateBuilderBuildRun(input: EvaluateBuilderBuildRunInput): Promise<BuilderBuildRunResult>;
97
+ export declare function evaluateBuilderFlowRun(input: EvaluateBuilderBuildRunInput): Promise<BuilderFlowRunResult>;
80
98
  export declare function loadBuilderBuildRun(input: LoadBuilderBuildRunInput): Promise<BuilderBuildRunResult>;
99
+ export declare function loadBuilderFlowRun(input: LoadBuilderBuildRunInput): Promise<BuilderFlowRunResult>;
100
+ export declare function pauseBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult>;
101
+ export declare function resumeBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult>;
102
+ export declare function cancelBuilderBuildRun(input: ChangeBuilderBuildRunLifecycleInput): Promise<BuilderBuildRunResult & {
103
+ idempotent: boolean;
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, evaluateRun, expectationsForGate, loadRun, normalizeTrustBundle, openGates, readJson, startRun, validateDefinition, } from "@kontourai/flow";
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
- const root = findPackageRoot(startDir);
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 = resolveBuilderBuildFlowDefinitionPath();
49
- const definition = await loadShippedBuilderBuildDefinition(definitionPath);
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 loadCanonicalBuilderBuildRun(started.runId, cwd, definition);
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 loadShippedBuilderBuildDefinition(resolveBuilderBuildFlowDefinitionPath());
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 normalized = normalizeTrustBundle(await readJson(path.resolve(cwd, evidence.file)));
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
- attachedEvidence = [await attachEvidence(input.runId, trustBundleAttachOptions(cwd, evidence))];
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,13 +113,57 @@ 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 loadShippedBuilderBuildDefinition(resolveBuilderBuildFlowDefinitionPath());
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
  }
127
+ export async function pauseBuilderBuildRun(input) {
128
+ const result = await pauseBuilderFlowRun(input);
129
+ return asBuilderBuildResult(result, input.runId);
130
+ }
131
+ export async function resumeBuilderBuildRun(input) {
132
+ const result = await resumeBuilderFlowRun(input);
133
+ return asBuilderBuildResult(result, input.runId);
134
+ }
135
+ export async function cancelBuilderBuildRun(input) {
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);
147
+ return { ...resultFromRun(changed, input.runId), idempotent: changed.idempotent };
148
+ }
149
+ async function changeBuilderFlowRunLifecycle(input, operation) {
150
+ const changed = await changeBuilderFlowRunLifecycleResult(input, operation);
151
+ return resultFromRun(changed, input.runId);
152
+ }
153
+ async function changeBuilderFlowRunLifecycleResult(input, operation) {
154
+ assertRuntimeInput(input, []);
155
+ if (!isRecord(input.request))
156
+ throw new BuilderBuildRunInputError("request", "must be a lifecycle request object");
157
+ const cwd = input.cwd ?? process.cwd();
158
+ const before = await loadBuilderFlowRun({ runId: input.runId, cwd });
159
+ const changed = await operation(input.runId, { cwd, ...input.request, ...(input.at ? { at: input.at } : {}) });
160
+ const definition = await loadShippedBuilderFlowDefinitionForRun(input.runId, changed.definition);
161
+ assertCanonicalDefinition(input.runId, definition, changed.definition);
162
+ if (changed.state.subject !== before.state.subject) {
163
+ throw new BuilderBuildRunInputError("flow_run.state.subject", "changed during lifecycle transition");
164
+ }
165
+ return changed;
166
+ }
100
167
  function resultFromRun(run, runId) {
101
168
  return {
102
169
  definitionId: run.definition.id,
@@ -110,33 +177,55 @@ function resultFromRun(run, runId) {
110
177
  freshnessTransitions: [],
111
178
  };
112
179
  }
113
- async function loadCanonicalBuilderBuildRun(runId, cwd, definition) {
180
+ async function loadCanonicalBuilderFlowRun(runId, cwd, definition) {
114
181
  const run = await loadRun(runId, cwd);
115
182
  assertCanonicalDefinition(runId, definition, run.definition);
116
183
  return run;
117
184
  }
118
- async function loadShippedBuilderBuildDefinition(definitionPath) {
185
+ async function loadShippedBuilderFlowDefinition(flowId, definitionPath) {
119
186
  const packageRoot = findPackageRoot(path.dirname(definitionPath));
120
- const effective = resolveEffectiveFlowDefinition(BUILDER_BUILD_FLOW_ID, packageRoot, { allowOverride: false });
187
+ const effective = resolveEffectiveFlowDefinition(flowId, packageRoot, { allowOverride: false });
121
188
  if (!effective) {
122
189
  throw new BuilderBuildRunInputError("definition", "could not compile the shipped uses_flow composition");
123
190
  }
124
191
  const definition = validateDefinition(effective);
125
- if (definition.id !== BUILDER_BUILD_FLOW_ID) {
126
- throw new BuilderBuildRunInputError("definition", `expected shipped definition id ${BUILDER_BUILD_FLOW_ID}`);
192
+ if (definition.id !== flowId) {
193
+ throw new BuilderBuildRunInputError("definition", `expected shipped definition id ${flowId}`);
127
194
  }
128
195
  return definition;
129
196
  }
130
- function materializeRuntimeDefinition(cwd, definition) {
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) {
131
205
  const content = `${JSON.stringify(definition, null, 2)}\n`;
132
206
  const digest = createHash("sha256").update(content).digest("hex").slice(0, 16);
133
207
  const directory = path.join(cwd, ".kontourai", "flow-agents", "runtime-definitions");
134
208
  mkdirSync(directory, { recursive: true });
135
- const file = path.join(directory, `builder-build-${digest}.flow.json`);
209
+ const file = path.join(directory, `${flowId.replace(".", "-")}-${digest}.flow.json`);
136
210
  if (!existsSync(file))
137
211
  writeFileSync(file, content);
138
212
  return file;
139
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
+ }
140
229
  function assertCanonicalDefinition(runId, expectedDefinition, actualDefinition) {
141
230
  if (isDeepStrictEqual(actualDefinition, expectedDefinition))
142
231
  return;
@@ -167,6 +256,9 @@ function validateEvidenceInput(evidence) {
167
256
  if (!isNonEmptyString(evidence.file)) {
168
257
  throw new BuilderBuildRunInputError("evidence.file", "must be a non-empty string");
169
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
+ }
170
262
  if (evidence.status !== undefined && evidence.status !== "passed" && evidence.status !== "failed") {
171
263
  throw new BuilderBuildRunInputError("evidence.status", "must be passed or failed");
172
264
  }
@@ -199,11 +291,12 @@ function assertBundleSubjects(bundle, subject, gate) {
199
291
  }
200
292
  }
201
293
  }
202
- function trustBundleAttachOptions(cwd, evidence) {
294
+ function trustBundleAttachOptions(cwd, evidence, expectedSha256) {
203
295
  return {
204
296
  cwd,
205
297
  gate: evidence.gate,
206
298
  file: evidence.file,
299
+ expectedSha256,
207
300
  kind: "trust.bundle",
208
301
  bundle: true,
209
302
  ...(evidence.status ? { status: evidence.status } : {}),
@@ -1,17 +1,40 @@
1
- import { type BuilderBuildRunResult } from "./builder-flow-run-adapter.js";
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;
6
+ }
7
+ export interface BuilderFlowAuthorizedLifecycleInput extends BuilderFlowSessionInput {
8
+ authorizationFile: string;
9
+ }
10
+ export interface BuilderFlowAgentLifecycleInput extends BuilderFlowSessionInput {
11
+ reason: string;
5
12
  }
6
13
  export interface BuilderFlowSessionResult {
7
14
  sessionDir: string;
8
15
  projectRoot: string;
9
- run: BuilderBuildRunResult;
16
+ run: BuilderFlowRunResult;
10
17
  projection: AnyRecord;
11
18
  attached: boolean;
12
19
  }
13
20
  export declare function startBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
14
21
  export declare function syncBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
15
22
  export declare function recoverBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
16
- export declare function syncBuilderFlowSessionIfPresent(sessionDir: string): Promise<BuilderFlowSessionResult | null>;
23
+ export declare function inspectBuilderFlowSession(input: BuilderFlowSessionInput): Promise<BuilderFlowSessionResult>;
24
+ export declare function pauseBuilderFlowSession(input: BuilderFlowAgentLifecycleInput): Promise<BuilderFlowSessionResult>;
25
+ export declare function resumeBuilderFlowSession(input: BuilderFlowAgentLifecycleInput): Promise<BuilderFlowSessionResult>;
26
+ export declare function cancelBuilderFlowSession(input: BuilderFlowAuthorizedLifecycleInput): Promise<BuilderFlowSessionResult & {
27
+ assignmentReleased: boolean;
28
+ idempotent: boolean;
29
+ }>;
30
+ export declare function releaseBuilderFlowAssignment(input: BuilderFlowAgentLifecycleInput): Promise<BuilderFlowSessionResult & {
31
+ assignmentReleased: boolean;
32
+ }>;
33
+ export declare function archiveBuilderFlowSession(input: BuilderFlowAuthorizedLifecycleInput): Promise<BuilderFlowSessionResult & {
34
+ archiveDir: string;
35
+ }>;
36
+ export declare function captureReviewWorkspaceSnapshot(projectRoot: string, reviewedFiles: Array<{
37
+ file: string;
38
+ sha256: string;
39
+ }>): AnyRecord;
17
40
  export {};