@kontourai/flow-agents 1.0.0 → 1.1.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/.github/workflows/ci.yml +110 -0
- package/CHANGELOG.md +24 -0
- package/build/src/cli/console-learning-projection.js +19 -2
- package/build/src/cli/effective-backlog-settings.js +18 -2
- package/build/src/cli/fixture-retirement-audit.js +19 -2
- package/build/src/cli/flow-kit.js +135 -5
- package/build/src/cli/init.js +19 -2
- package/build/src/cli/promote-workflow-artifact.js +19 -2
- package/build/src/cli/publish-change-helper.js +19 -2
- package/build/src/cli/pull-work-provider.js +19 -2
- package/build/src/cli/runtime-adapter.js +20 -2
- package/build/src/cli/usage-feedback.js +19 -2
- package/build/src/cli/utterance-check.js +19 -2
- package/build/src/cli/validate-hook-influence.js +19 -2
- package/build/src/cli/validate-source-tree.js +19 -2
- package/build/src/cli/veritas-governance.js +19 -2
- package/build/src/cli/workflow-artifact-cleanup-audit.js +19 -2
- package/build/src/runtime-adapters.js +56 -25
- package/build/src/tools/build-universal-bundles.js +19 -2
- package/build/src/tools/generate-context-map.js +19 -2
- package/build/src/tools/validate-package.js +19 -2
- package/build/src/tools/validate-source-tree.js +20 -3
- package/context/scripts/telemetry/console-presets.sh +1 -1
- package/docs/fixture-ownership.md +1 -1
- package/docs/kit-authoring-guide.md +20 -3
- package/evals/ci/run-baseline.sh +55 -8
- package/evals/integration/test_activate_npx_context.sh +134 -0
- package/evals/integration/test_flow_kit_install_git.sh +163 -0
- package/evals/integration/test_runtime_adapter_activation.sh +138 -17
- package/evals/run.sh +2 -0
- package/evals/static/test_console_presets.sh +49 -0
- package/package.json +1 -1
- package/scripts/telemetry/console-presets.sh +1 -1
- package/src/cli/console-learning-projection.ts +7 -1
- package/src/cli/effective-backlog-settings.ts +6 -1
- package/src/cli/fixture-retirement-audit.ts +7 -1
- package/src/cli/flow-kit.ts +123 -4
- package/src/cli/init.ts +7 -1
- package/src/cli/promote-workflow-artifact.ts +7 -1
- package/src/cli/publish-change-helper.ts +7 -1
- package/src/cli/pull-work-provider.ts +7 -1
- package/src/cli/runtime-adapter.ts +8 -1
- package/src/cli/usage-feedback.ts +7 -1
- package/src/cli/utterance-check.ts +7 -1
- package/src/cli/validate-hook-influence.ts +7 -1
- package/src/cli/validate-source-tree.ts +7 -1
- package/src/cli/veritas-governance.ts +7 -1
- package/src/cli/workflow-artifact-cleanup-audit.ts +7 -1
- package/src/runtime-adapters.ts +55 -27
- package/src/tools/build-universal-bundles.ts +7 -1
- package/src/tools/generate-context-map.ts +7 -1
- package/src/tools/validate-package.ts +7 -1
- package/src/tools/validate-source-tree.ts +8 -2
|
@@ -27,5 +27,22 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
27
27
|
console.log("Source tree validation passed");
|
|
28
28
|
return 0;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
31
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS).
|
|
32
|
+
import * as _fsVST from "node:fs";
|
|
33
|
+
import { fileURLToPath as _ftpVST } from "node:url";
|
|
34
|
+
const _selfVST = (() => { try {
|
|
35
|
+
return _fsVST.realpathSync(_ftpVST(import.meta.url));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return _ftpVST(import.meta.url);
|
|
39
|
+
} })();
|
|
40
|
+
const _argv1VST = (() => { try {
|
|
41
|
+
return _fsVST.realpathSync(process.argv[1]);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return process.argv[1];
|
|
45
|
+
} })();
|
|
46
|
+
if (_selfVST === _argv1VST) {
|
|
47
|
+
process.exitCode = main();
|
|
48
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { spawnSync } from "node:child_process";
|
|
4
5
|
import { flagBool, flagString, parseArgs } from "../lib/args.js";
|
|
@@ -258,5 +259,21 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
258
259
|
const options = parseEvidenceOptions(argv);
|
|
259
260
|
return options ? runEvidence(options) : 2;
|
|
260
261
|
}
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
263
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
264
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
265
|
+
const _selfRealPath = (() => { try {
|
|
266
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return fileURLToPath(import.meta.url);
|
|
270
|
+
} })();
|
|
271
|
+
const _argv1RealPath = (() => { try {
|
|
272
|
+
return fs.realpathSync(process.argv[1]);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return process.argv[1];
|
|
276
|
+
} })();
|
|
277
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
278
|
+
process.exitCode = main();
|
|
279
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
import { flagBool, flagString, parseArgs } from "../lib/args.js";
|
|
4
5
|
const ACTIVE_STATUSES = new Set([
|
|
@@ -268,5 +269,21 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
268
269
|
printText(result);
|
|
269
270
|
return 0;
|
|
270
271
|
}
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
273
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
274
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
275
|
+
const _selfRealPath = (() => { try {
|
|
276
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return fileURLToPath(import.meta.url);
|
|
280
|
+
} })();
|
|
281
|
+
const _argv1RealPath = (() => { try {
|
|
282
|
+
return fs.realpathSync(process.argv[1]);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return process.argv[1];
|
|
286
|
+
} })();
|
|
287
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
288
|
+
process.exitCode = main();
|
|
289
|
+
}
|
|
@@ -74,7 +74,7 @@ export function readKitInventory(sourceRoot, dest) {
|
|
|
74
74
|
const assets = [];
|
|
75
75
|
const catalogPath = path.join(sourceRoot, "kits", "catalog.json");
|
|
76
76
|
if (!fs.existsSync(catalogPath))
|
|
77
|
-
|
|
77
|
+
warnings.push(`${catalogPath}: built-in Kit Catalog not found; skipping built-in kits (this is normal when running outside a flow-agents checkout)`);
|
|
78
78
|
else {
|
|
79
79
|
const catalog = readJson(catalogPath);
|
|
80
80
|
const kits = catalog.kits;
|
|
@@ -118,31 +118,48 @@ export function readKitInventory(sourceRoot, dest) {
|
|
|
118
118
|
function safeSegment(value) {
|
|
119
119
|
return value.replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^[.-]+|[.-]+$/g, "") || "asset";
|
|
120
120
|
}
|
|
121
|
+
// Asset classes that are directly activated (copied to the runtime directory) by both adapters.
|
|
122
|
+
// flows: gate definitions read by the adapter's flow-routing layer.
|
|
123
|
+
// skills: agent guidance markdown copied to skills/<kit-id>/ for agent discovery.
|
|
124
|
+
// docs: documentation markdown copied to docs/<kit-id>/ for agent reference.
|
|
125
|
+
const ACTIVATED_ASSET_CLASSES = new Set(["flows", "skills", "docs"]);
|
|
121
126
|
export function activateCodexLocal(sourceRoot, dest) {
|
|
122
127
|
const inventory = readKitInventory(sourceRoot, dest);
|
|
123
128
|
const runtimeDir = path.join(dest, ".flow-agents", "runtime", "codex");
|
|
124
129
|
const generated = [];
|
|
125
130
|
const skipped = [];
|
|
126
131
|
for (const asset of inventory.assets) {
|
|
127
|
-
if (asset.asset_class
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
if (asset.asset_class === "flows") {
|
|
133
|
+
if (!asset.asset_id) {
|
|
134
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: null, reason: "flow asset is missing an id" });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
|
|
138
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
139
|
+
fs.copyFileSync(asset.source_path, output);
|
|
140
|
+
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id, source_path: asset.source_path.split(path.sep).join("/") });
|
|
130
141
|
}
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
else if (asset.asset_class === "skills" || asset.asset_class === "docs") {
|
|
143
|
+
// Copy skills and docs to runtime/<adapter>/<class>/<kit-id>/<filename> so the
|
|
144
|
+
// agent's guidance index (AGENTS.md) can reference them and they are co-located
|
|
145
|
+
// with flow definitions for the same kit.
|
|
146
|
+
const filename = path.basename(asset.source_path);
|
|
147
|
+
const output = path.join(runtimeDir, asset.asset_class, safeSegment(asset.kit_id), filename);
|
|
148
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
149
|
+
fs.copyFileSync(asset.source_path, output);
|
|
150
|
+
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id ?? "", source_path: asset.source_path.split(path.sep).join("/") });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: asset.asset_id, reason: "asset class is not activated by codex-local" });
|
|
134
154
|
}
|
|
135
|
-
const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
|
|
136
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
137
|
-
fs.copyFileSync(asset.source_path, output);
|
|
138
|
-
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id, source_path: asset.source_path.split(path.sep).join("/") });
|
|
139
155
|
}
|
|
140
156
|
fs.mkdirSync(runtimeDir, { recursive: true });
|
|
141
|
-
const
|
|
157
|
+
const supportedClasses = Array.from(ACTIVATED_ASSET_CLASSES);
|
|
158
|
+
const manifest = { schema_version: "1.0", adapter: "codex-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
142
159
|
const manifestPath = path.join(runtimeDir, "activation.json");
|
|
143
160
|
writeJson(manifestPath, manifest);
|
|
144
161
|
generated.push({ asset_class: "activation-manifest", path: relPath(dest, manifestPath), kit_id: "runtime", asset_id: "codex-local.activation", source_path: manifestPath.split(path.sep).join("/") });
|
|
145
|
-
return { selected_adapter: "codex-local", supported_asset_classes:
|
|
162
|
+
return { selected_adapter: "codex-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
146
163
|
}
|
|
147
164
|
// Decision Q3 (Issue #32): Option (a) — new adapter id "strands-local" rather than
|
|
148
165
|
// loading kit flows inside FlowAgentsHooks. Rationale: activation is a workspace-prep
|
|
@@ -154,27 +171,41 @@ export function activateStrandsLocal(sourceRoot, dest) {
|
|
|
154
171
|
const inventory = readKitInventory(sourceRoot, dest);
|
|
155
172
|
// Runtime flows land at .flow-agents/runtime/strands/flows/<kit-id>/<asset-id>.flow.json
|
|
156
173
|
// so the Strands steering context can glob for *.flow.json under this path.
|
|
174
|
+
// Runtime skills land at .flow-agents/runtime/strands/skills/<kit-id>/<filename> and
|
|
175
|
+
// docs at .flow-agents/runtime/strands/docs/<kit-id>/<filename> for system-prompt injection.
|
|
157
176
|
const runtimeDir = path.join(dest, ".flow-agents", "runtime", "strands");
|
|
158
177
|
const generated = [];
|
|
159
178
|
const skipped = [];
|
|
160
179
|
for (const asset of inventory.assets) {
|
|
161
|
-
if (asset.asset_class
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
if (asset.asset_class === "flows") {
|
|
181
|
+
if (!asset.asset_id) {
|
|
182
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: null, reason: "flow asset is missing an id" });
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
|
|
186
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
187
|
+
fs.copyFileSync(asset.source_path, output);
|
|
188
|
+
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id, source_path: asset.source_path.split(path.sep).join("/") });
|
|
164
189
|
}
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
190
|
+
else if (asset.asset_class === "skills" || asset.asset_class === "docs") {
|
|
191
|
+
// Mirror the codex-local layout: strands/<class>/<kit-id>/<filename>.
|
|
192
|
+
// The Strands system-prompt injection layer can glob for all *.md files under
|
|
193
|
+
// .flow-agents/runtime/strands/skills/ to include agent guidance in the context.
|
|
194
|
+
const filename = path.basename(asset.source_path);
|
|
195
|
+
const output = path.join(runtimeDir, asset.asset_class, safeSegment(asset.kit_id), filename);
|
|
196
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
197
|
+
fs.copyFileSync(asset.source_path, output);
|
|
198
|
+
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id ?? "", source_path: asset.source_path.split(path.sep).join("/") });
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: asset.asset_id, reason: "asset class is not activated by strands-local" });
|
|
168
202
|
}
|
|
169
|
-
const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
|
|
170
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
171
|
-
fs.copyFileSync(asset.source_path, output);
|
|
172
|
-
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id, source_path: asset.source_path.split(path.sep).join("/") });
|
|
173
203
|
}
|
|
174
204
|
fs.mkdirSync(runtimeDir, { recursive: true });
|
|
175
|
-
const
|
|
205
|
+
const supportedClasses = Array.from(ACTIVATED_ASSET_CLASSES);
|
|
206
|
+
const manifest = { schema_version: "1.0", adapter: "strands-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
176
207
|
const manifestPath = path.join(runtimeDir, "activation.json");
|
|
177
208
|
writeJson(manifestPath, manifest);
|
|
178
209
|
generated.push({ asset_class: "activation-manifest", path: relPath(dest, manifestPath), kit_id: "runtime", asset_id: "strands-local.activation", source_path: manifestPath.split(path.sep).join("/") });
|
|
179
|
-
return { selected_adapter: "strands-local", supported_asset_classes:
|
|
210
|
+
return { selected_adapter: "strands-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
180
211
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { loadJson, readText, root, walkFiles, writeText } from "./common.js";
|
|
5
6
|
const dist = process.env.FLOW_AGENTS_DIST_DIR ? path.resolve(process.env.FLOW_AGENTS_DIST_DIR) : path.join(root, "dist");
|
|
@@ -678,5 +679,21 @@ export function main() {
|
|
|
678
679
|
}
|
|
679
680
|
return 0;
|
|
680
681
|
}
|
|
681
|
-
|
|
682
|
-
|
|
682
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
683
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
684
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
685
|
+
const _selfRealPath = (() => { try {
|
|
686
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
687
|
+
}
|
|
688
|
+
catch {
|
|
689
|
+
return fileURLToPath(import.meta.url);
|
|
690
|
+
} })();
|
|
691
|
+
const _argv1RealPath = (() => { try {
|
|
692
|
+
return fs.realpathSync(process.argv[1]);
|
|
693
|
+
}
|
|
694
|
+
catch {
|
|
695
|
+
return process.argv[1];
|
|
696
|
+
} })();
|
|
697
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
698
|
+
process.exitCode = main();
|
|
699
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { exists, loadJson, markdownTable, oneLine, readText, rel, root, writeText } from "./common.js";
|
|
5
6
|
const defaultOutput = path.join(root, "docs/context-map.md");
|
|
@@ -194,5 +195,21 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
194
195
|
console.log(`Wrote ${rel(output)}`);
|
|
195
196
|
return 0;
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
-
|
|
198
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
199
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
200
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
201
|
+
const _selfRealPath = (() => { try {
|
|
202
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return fileURLToPath(import.meta.url);
|
|
206
|
+
} })();
|
|
207
|
+
const _argv1RealPath = (() => { try {
|
|
208
|
+
return fs.realpathSync(process.argv[1]);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return process.argv[1];
|
|
212
|
+
} })();
|
|
213
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
214
|
+
process.exitCode = main();
|
|
215
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
export function main(argv = process.argv.slice(2)) {
|
|
5
6
|
const [prefixArg, localFlag] = argv;
|
|
@@ -60,5 +61,21 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
60
61
|
console.log(errors === 0 ? "Result: PASS" : `Result: FAIL (${errors} error(s))`);
|
|
61
62
|
return errors === 0 ? 0 : 1;
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
65
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
66
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
67
|
+
const _selfRealPath = (() => { try {
|
|
68
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return fileURLToPath(import.meta.url);
|
|
72
|
+
} })();
|
|
73
|
+
const _argv1RealPath = (() => { try {
|
|
74
|
+
return fs.realpathSync(process.argv[1]);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return process.argv[1];
|
|
78
|
+
} })();
|
|
79
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
80
|
+
process.exitCode = main();
|
|
81
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { spawnSync } from "node:child_process";
|
|
5
6
|
import { loadJson, readText, rel, root, walkFiles } from "./common.js";
|
|
@@ -84,7 +85,7 @@ const fixtureOwnerPolicies = new Map([
|
|
|
84
85
|
["evals/fixtures/backlog-provider-settings", { owners: ["evals/integration/test_effective_backlog_settings.sh"], classification: "settings precedence fixtures" }],
|
|
85
86
|
["evals/fixtures/builder-kit-workflow-state", { owners: ["evals/static/test_workflow_skills.sh"], classification: "Builder Kit workflow-state fixtures" }],
|
|
86
87
|
["evals/fixtures/console-learning-projection", { owners: ["evals/integration/test_console_learning_projection.sh"], classification: "console learning projection fixtures" }],
|
|
87
|
-
["evals/fixtures/flow-kit-repository", { owners: ["evals/integration/test_flow_kit_repository.sh", "evals/integration/test_local_flow_kit_install.sh", "evals/integration/test_runtime_adapter_activation.sh", "evals/static/test_workflow_skills.sh"], classification: "Flow Kit repository contract fixtures" }],
|
|
88
|
+
["evals/fixtures/flow-kit-repository", { owners: ["evals/integration/test_flow_kit_repository.sh", "evals/integration/test_local_flow_kit_install.sh", "evals/integration/test_runtime_adapter_activation.sh", "evals/integration/test_activate_npx_context.sh", "evals/integration/test_flow_kit_install_git.sh", "evals/static/test_workflow_skills.sh"], classification: "Flow Kit repository contract fixtures" }],
|
|
88
89
|
["evals/fixtures/kit-conformance-levels", { owners: ["evals/integration/test_kit_conformance_levels.sh"], classification: "K-level conformance and consumer-target derivation fixtures" }],
|
|
89
90
|
["evals/fixtures/hook-influence", { owners: ["evals/integration/test_hook_influence_cases.sh", "evals/static/test_workflow_skills.sh", "scripts/validate-hook-influence-cases.js"], classification: "hook influence behavioral cases" }],
|
|
90
91
|
["evals/fixtures/pull-work-provider", { owners: ["evals/integration/test_pull_work_provider.sh"], classification: "work item provider normalization fixtures" }],
|
|
@@ -624,5 +625,21 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
624
625
|
console.log("Source tree validation passed.");
|
|
625
626
|
return 0;
|
|
626
627
|
}
|
|
627
|
-
|
|
628
|
-
|
|
628
|
+
// Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
|
|
629
|
+
// Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
|
|
630
|
+
// entry-point guard fires correctly when the module is loaded directly as a script.
|
|
631
|
+
const _selfRealPath = (() => { try {
|
|
632
|
+
return fs.realpathSync(fileURLToPath(import.meta.url));
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
return fileURLToPath(import.meta.url);
|
|
636
|
+
} })();
|
|
637
|
+
const _argv1RealPath = (() => { try {
|
|
638
|
+
return fs.realpathSync(process.argv[1]);
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
return process.argv[1];
|
|
642
|
+
} })();
|
|
643
|
+
if (_selfRealPath === _argv1RealPath) {
|
|
644
|
+
process.exitCode = main();
|
|
645
|
+
}
|
|
@@ -6,7 +6,7 @@ flow_agents_local_kontour_console_url() {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
flow_agents_kontour_cloud_console_url() {
|
|
9
|
-
printf '%s\n' "${FLOW_AGENTS_KONTOUR_CLOUD_CONSOLE_URL:-https://console.kontourai.
|
|
9
|
+
printf '%s\n' "${FLOW_AGENTS_KONTOUR_CLOUD_CONSOLE_URL:-https://console.kontourai.io}"
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
flow_agents_kontour_hosted_console_url() {
|
|
@@ -16,7 +16,7 @@ run `npm run validate:source --` and `npm run fixture:retirement-audit --`.
|
|
|
16
16
|
| `evals/fixtures/backlog-provider-settings` | settings precedence fixtures | `evals/integration/test_effective_backlog_settings.sh` | Keep while backlog provider settings resolution supports global defaults and project overrides. |
|
|
17
17
|
| `evals/fixtures/builder-kit-workflow-state` | Builder Kit workflow-state fixtures | `evals/static/test_workflow_skills.sh` | Keep while Builder Kit state contract and resume behavior are documented in workflow skill contracts. |
|
|
18
18
|
| `evals/fixtures/console-learning-projection` | console learning projection fixtures | `evals/integration/test_console_learning_projection.sh` | Keep while learning projection supports correction and open-route examples. |
|
|
19
|
-
| `evals/fixtures/flow-kit-repository` | Flow Kit repository contract fixtures | `evals/integration/test_flow_kit_repository.sh`, `evals/integration/test_local_flow_kit_install.sh`, `evals/integration/test_runtime_adapter_activation.sh`, `evals/static/test_workflow_skills.sh` | Keep valid and invalid cases paired with the Flow Kit repository contract. |
|
|
19
|
+
| `evals/fixtures/flow-kit-repository` | Flow Kit repository contract fixtures | `evals/integration/test_flow_kit_repository.sh`, `evals/integration/test_local_flow_kit_install.sh`, `evals/integration/test_runtime_adapter_activation.sh`, `evals/integration/test_activate_npx_context.sh`, `evals/integration/test_flow_kit_install_git.sh`, `evals/static/test_workflow_skills.sh` | Keep valid and invalid cases paired with the Flow Kit repository contract. |
|
|
20
20
|
| `evals/fixtures/kit-conformance-levels` | K-level conformance and consumer-target derivation fixtures | `evals/integration/test_kit_conformance_levels.sh` | Keep while K-level derivation, degradation invariant, and consumer-target badge rules are tested. |
|
|
21
21
|
| `evals/fixtures/hook-influence` | hook influence behavioral cases | `evals/integration/test_hook_influence_cases.sh`, `evals/static/test_workflow_skills.sh`, `scripts/validate-hook-influence-cases.js` | Keep while hook influence cases define agent guidance behavior. |
|
|
22
22
|
| `evals/fixtures/pull-work-provider` | work item provider normalization fixtures | `evals/integration/test_pull_work_provider.sh` | Keep while provider normalization preserves blockers, artifact refs, board membership, and freshness metadata. |
|
|
@@ -12,7 +12,7 @@ This guide walks you from an empty directory to a validated, locally installed k
|
|
|
12
12
|
|
|
13
13
|
- **Kit** — a directory with a root `kit.json` manifest and the assets it declares. The manifest is the contract; Flow Agents validates it before anything is copied.
|
|
14
14
|
- **Flow Definition** — a `.flow.json` file that declares steps, gates, and expected evidence. Validation of the Flow Definition semantics belongs to [Kontour Flow](https://kontourai.github.io/flow/); the kit contract delegates to it.
|
|
15
|
-
- **Activation** — the step that reads the installed kit and writes runtime-local files into your workspace.
|
|
15
|
+
- **Activation** — the step that reads the installed kit and writes runtime-local files into your workspace. Both `codex-local` and `strands-local` adapters activate Flow Definitions, skills, and docs. See the Activate section for the full asset-class table.
|
|
16
16
|
|
|
17
17
|
## Directory layout
|
|
18
18
|
|
|
@@ -54,7 +54,7 @@ Required fields:
|
|
|
54
54
|
| `name` | Non-empty display name |
|
|
55
55
|
| `flows` | Non-empty list; each entry must have `id` and `path` |
|
|
56
56
|
|
|
57
|
-
Optional fields: `product_name`, `description`, `skills`, `docs`, `adapters`, `evals`, `assets`. Optional fields list relative asset paths or objects with `id`, `path`, and optional `description`.
|
|
57
|
+
Optional fields: `product_name`, `description`, `skills`, `docs`, `adapters`, `evals`, `assets`. Optional fields list relative asset paths or objects with `id`, `path`, and optional `description`. `skills` and `docs` assets are activated by both adapters alongside flows. `adapters`, `evals`, and `assets` appear in diagnostics as `skipped_assets` (see the Activate section for the full per-adapter table).
|
|
58
58
|
|
|
59
59
|
## Minimal flow file
|
|
60
60
|
|
|
@@ -140,7 +140,24 @@ After installing, run activate to write runtime-local files into the workspace:
|
|
|
140
140
|
npx @kontourai/flow-agents flow-kit activate --dest /path/to/workspace --format json
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
The `codex-local` adapter is selected automatically.
|
|
143
|
+
The `codex-local` adapter is selected automatically. To activate for Strands, pass `--adapter strands-local`.
|
|
144
|
+
|
|
145
|
+
### What each adapter activates
|
|
146
|
+
|
|
147
|
+
Each adapter copies declared assets into `.flow-agents/runtime/<adapter>/` and produces an `activation.json` manifest. The table below shows which asset classes are activated today:
|
|
148
|
+
|
|
149
|
+
| Asset class | `codex-local` | `strands-local` | Notes |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| `flows` | Activated — `.flow-agents/runtime/codex/flows/<kit-id>/<asset-id>.flow.json` | Activated — `.flow-agents/runtime/strands/flows/<kit-id>/<asset-id>.flow.json` | Gate definitions read by each adapter's flow-routing layer. |
|
|
152
|
+
| `skills` | Activated — `.flow-agents/runtime/codex/skills/<kit-id>/<filename>` | Activated — `.flow-agents/runtime/strands/skills/<kit-id>/<filename>` | Agent guidance markdown. For codex-local, reference these paths from AGENTS.md. For strands-local, the Strands steering layer can glob for `*.md` under `skills/` during system-prompt injection. |
|
|
153
|
+
| `docs` | Activated — `.flow-agents/runtime/codex/docs/<kit-id>/<filename>` | Activated — `.flow-agents/runtime/strands/docs/<kit-id>/<filename>` | Documentation assets. Co-located with skill files for easy reference. |
|
|
154
|
+
| `adapters` | `skipped_assets` | `skipped_assets` | Framework or runtime adapter code — not copied by the activation layer. |
|
|
155
|
+
| `evals` | `skipped_assets` | `skipped_assets` | Evaluation suites — not run or copied during activation. |
|
|
156
|
+
| `assets` | `skipped_assets` | `skipped_assets` | General supporting assets — not copied during activation. |
|
|
157
|
+
|
|
158
|
+
Assets in `skipped_assets` are recorded in `activation.json` for diagnostics but are not an error. They are not activated because no activation path is defined for those classes in the current adapters.
|
|
159
|
+
|
|
160
|
+
Flows with a missing `id` field in `kit.json` are also placed in `skipped_assets` with an explicit reason.
|
|
144
161
|
|
|
145
162
|
When installing through `npx @kontourai/flow-agents init` with the Codex runtime, pass `--activate-kits` to run activation as part of init:
|
|
146
163
|
|
package/evals/ci/run-baseline.sh
CHANGED
|
@@ -26,6 +26,24 @@ CHECKS=(
|
|
|
26
26
|
"Flow Kit repository integration|bash evals/integration/test_flow_kit_repository.sh"
|
|
27
27
|
"Runtime adapter activation integration|bash evals/integration/test_runtime_adapter_activation.sh"
|
|
28
28
|
"Bundle install integration|bash evals/integration/test_bundle_install.sh"
|
|
29
|
+
"Bundle lifecycle integration|bash evals/integration/test_bundle_lifecycle.sh"
|
|
30
|
+
"Activate npx context integration|bash evals/integration/test_activate_npx_context.sh"
|
|
31
|
+
"Kit conformance levels integration|bash evals/integration/test_kit_conformance_levels.sh"
|
|
32
|
+
"Local Flow Kit install integration|bash evals/integration/test_local_flow_kit_install.sh"
|
|
33
|
+
"Flow Kit install-git integration|bash evals/integration/test_flow_kit_install_git.sh"
|
|
34
|
+
"Console learning projection integration|bash evals/integration/test_console_learning_projection.sh"
|
|
35
|
+
"Context map integration|bash evals/integration/test_context_map.sh"
|
|
36
|
+
"Effective backlog settings integration|bash evals/integration/test_effective_backlog_settings.sh"
|
|
37
|
+
"Flow agents statusline integration|bash evals/integration/test_flow_agents_statusline.sh"
|
|
38
|
+
"Telemetry contract integration|bash evals/integration/test_telemetry.sh"
|
|
39
|
+
"Telemetry doctor integration|bash evals/integration/test_telemetry_doctor.sh"
|
|
40
|
+
"Utterance check integration|bash evals/integration/test_utterance_check.sh"
|
|
41
|
+
"Pull work provider integration|bash evals/integration/test_pull_work_provider.sh"
|
|
42
|
+
"Usage feedback import integration|bash evals/integration/test_usage_feedback_import.sh"
|
|
43
|
+
"Usage feedback outcomes integration|bash evals/integration/test_usage_feedback_outcomes.sh"
|
|
44
|
+
"Usage feedback report integration|bash evals/integration/test_usage_feedback_report.sh"
|
|
45
|
+
"Usage feedback dashboard integration|bash evals/integration/test_usage_feedback_dashboard.sh"
|
|
46
|
+
"Usage feedback global integration|bash evals/integration/test_usage_feedback_global.sh"
|
|
29
47
|
)
|
|
30
48
|
|
|
31
49
|
LANE_SOURCE_AND_STATIC=(
|
|
@@ -51,6 +69,27 @@ LANE_RUNTIME_AND_KIT=(
|
|
|
51
69
|
"Flow Kit repository integration"
|
|
52
70
|
"Runtime adapter activation integration"
|
|
53
71
|
"Bundle install integration"
|
|
72
|
+
"Bundle lifecycle integration"
|
|
73
|
+
"Activate npx context integration"
|
|
74
|
+
"Kit conformance levels integration"
|
|
75
|
+
"Local Flow Kit install integration"
|
|
76
|
+
"Flow Kit install-git integration"
|
|
77
|
+
# QUARANTINED (#74): passes on macOS, fails on Linux CI — not gating until triaged
|
|
78
|
+
"Context map integration"
|
|
79
|
+
"Effective backlog settings integration"
|
|
80
|
+
"Flow agents statusline integration"
|
|
81
|
+
"Telemetry contract integration"
|
|
82
|
+
"Telemetry doctor integration"
|
|
83
|
+
"Utterance check integration"
|
|
84
|
+
"Pull work provider integration"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
LANE_USAGE_FEEDBACK=(
|
|
88
|
+
"Usage feedback import integration"
|
|
89
|
+
"Usage feedback outcomes integration"
|
|
90
|
+
"Usage feedback report integration"
|
|
91
|
+
"Usage feedback dashboard integration"
|
|
92
|
+
"Usage feedback global integration"
|
|
54
93
|
)
|
|
55
94
|
|
|
56
95
|
slugify() {
|
|
@@ -78,6 +117,9 @@ lane_labels() {
|
|
|
78
117
|
runtime-and-kit)
|
|
79
118
|
printf '%s\n' "${LANE_RUNTIME_AND_KIT[@]}"
|
|
80
119
|
;;
|
|
120
|
+
usage-feedback)
|
|
121
|
+
printf '%s\n' "${LANE_USAGE_FEEDBACK[@]}"
|
|
122
|
+
;;
|
|
81
123
|
*)
|
|
82
124
|
echo "Unknown CI baseline lane: $(active_lane)" >&2
|
|
83
125
|
return 1
|
|
@@ -120,14 +162,19 @@ find_check() {
|
|
|
120
162
|
}
|
|
121
163
|
|
|
122
164
|
find_active_check() {
|
|
165
|
+
# Look up the check by id-or-label without streaming active_checks through a
|
|
166
|
+
# process substitution. Streaming and returning early from the consumer loop
|
|
167
|
+
# causes a SIGPIPE on the producer printf when pipefail is set, printing a
|
|
168
|
+
# spurious "write error: Broken pipe" on Linux even though every check passed.
|
|
169
|
+
# Instead: resolve via the pure-bash find_check, then confirm the label is
|
|
170
|
+
# present in the active lane.
|
|
123
171
|
local requested="$1"
|
|
124
|
-
local row id label
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
done < <(active_checks)
|
|
172
|
+
local row id label line
|
|
173
|
+
row="$(find_check "$requested")" || return 1
|
|
174
|
+
IFS=$'\t' read -r id label _ <<<"$row"
|
|
175
|
+
while IFS= read -r line; do
|
|
176
|
+
[[ "$line" == "$label" ]] && { printf '%s\n' "$row"; return 0; }
|
|
177
|
+
done <<<"$(lane_labels)"
|
|
131
178
|
return 1
|
|
132
179
|
}
|
|
133
180
|
|
|
@@ -265,7 +312,7 @@ case "${1:-}" in
|
|
|
265
312
|
;;
|
|
266
313
|
--lane)
|
|
267
314
|
if [[ -z "${2:-}" ]]; then
|
|
268
|
-
echo "Usage: $0 --lane <source-and-static|workflow-contracts|runtime-and-kit>" >&2
|
|
315
|
+
echo "Usage: $0 --lane <source-and-static|workflow-contracts|runtime-and-kit|usage-feedback>" >&2
|
|
269
316
|
exit 2
|
|
270
317
|
fi
|
|
271
318
|
FLOW_AGENTS_CI_LANE="$2"
|