@kontourai/flow-agents 1.0.1 → 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.
Files changed (46) hide show
  1. package/.github/workflows/ci.yml +110 -0
  2. package/CHANGELOG.md +16 -0
  3. package/build/src/cli/console-learning-projection.js +19 -2
  4. package/build/src/cli/effective-backlog-settings.js +18 -2
  5. package/build/src/cli/fixture-retirement-audit.js +19 -2
  6. package/build/src/cli/init.js +19 -2
  7. package/build/src/cli/promote-workflow-artifact.js +19 -2
  8. package/build/src/cli/publish-change-helper.js +19 -2
  9. package/build/src/cli/pull-work-provider.js +19 -2
  10. package/build/src/cli/runtime-adapter.js +20 -2
  11. package/build/src/cli/usage-feedback.js +19 -2
  12. package/build/src/cli/utterance-check.js +19 -2
  13. package/build/src/cli/validate-hook-influence.js +19 -2
  14. package/build/src/cli/veritas-governance.js +19 -2
  15. package/build/src/cli/workflow-artifact-cleanup-audit.js +19 -2
  16. package/build/src/runtime-adapters.js +55 -24
  17. package/build/src/tools/build-universal-bundles.js +19 -2
  18. package/build/src/tools/generate-context-map.js +19 -2
  19. package/build/src/tools/validate-package.js +19 -2
  20. package/build/src/tools/validate-source-tree.js +19 -2
  21. package/context/scripts/telemetry/console-presets.sh +1 -1
  22. package/docs/kit-authoring-guide.md +20 -3
  23. package/evals/ci/run-baseline.sh +55 -8
  24. package/evals/integration/test_runtime_adapter_activation.sh +138 -17
  25. package/evals/run.sh +2 -0
  26. package/evals/static/test_console_presets.sh +49 -0
  27. package/package.json +1 -1
  28. package/scripts/telemetry/console-presets.sh +1 -1
  29. package/src/cli/console-learning-projection.ts +7 -1
  30. package/src/cli/effective-backlog-settings.ts +6 -1
  31. package/src/cli/fixture-retirement-audit.ts +7 -1
  32. package/src/cli/init.ts +7 -1
  33. package/src/cli/promote-workflow-artifact.ts +7 -1
  34. package/src/cli/publish-change-helper.ts +7 -1
  35. package/src/cli/pull-work-provider.ts +7 -1
  36. package/src/cli/runtime-adapter.ts +8 -1
  37. package/src/cli/usage-feedback.ts +7 -1
  38. package/src/cli/utterance-check.ts +7 -1
  39. package/src/cli/validate-hook-influence.ts +7 -1
  40. package/src/cli/veritas-governance.ts +7 -1
  41. package/src/cli/workflow-artifact-cleanup-audit.ts +7 -1
  42. package/src/runtime-adapters.ts +54 -26
  43. package/src/tools/build-universal-bundles.ts +7 -1
  44. package/src/tools/generate-context-map.ts +7 -1
  45. package/src/tools/validate-package.ts +7 -1
  46. package/src/tools/validate-source-tree.ts +7 -1
package/src/cli/init.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
+ import { fileURLToPath } from "node:url";
3
4
  import * as os from "node:os";
4
5
  import * as path from "node:path";
5
6
  import { createInterface } from "node:readline/promises";
@@ -458,4 +459,9 @@ export async function mainDogfood(argv = process.argv.slice(2)): Promise<number>
458
459
  }
459
460
  }
460
461
 
461
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(await main());
462
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
463
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
464
+ // entry-point guard fires correctly when the module is loaded directly as a script.
465
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
466
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
467
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = await main(); }
@@ -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 { parseArgs, flagString } from "../lib/args.js";
4
5
  import { isoNow, relPath } from "../lib/fs.js";
@@ -61,4 +62,9 @@ export function main(argv = process.argv.slice(2)): number {
61
62
  return 0;
62
63
  }
63
64
 
64
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
65
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
66
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
67
+ // entry-point guard fires correctly when the module is loaded directly as a script.
68
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
69
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
70
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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 { parseArgs, flagString } from "../lib/args.js";
4
5
  import { readJson } from "../lib/fs.js";
@@ -140,4 +141,9 @@ export function main(argv = process.argv.slice(2)): number {
140
141
  }
141
142
  }
142
143
 
143
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
144
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
145
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
146
+ // entry-point guard fires correctly when the module is loaded directly as a script.
147
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
148
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
149
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import { fileURLToPath } from "node:url";
2
3
  import { parseArgs, flagList, flagString } from "../lib/args.js";
3
4
 
4
5
  const FLOW_ARTIFACT_PATTERN = /(?<path>\.flow-agents\/[^\s`'")]+)/g;
@@ -478,4 +479,9 @@ export function main(argv = process.argv.slice(2)): number {
478
479
  return 0;
479
480
  }
480
481
 
481
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
482
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
483
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
484
+ // entry-point guard fires correctly when the module is loaded directly as a script.
485
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
486
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
487
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -1,3 +1,5 @@
1
+ import * as fs from "node:fs";
2
+ import { fileURLToPath } from "node:url";
1
3
  import * as path from "node:path";
2
4
  import { parseArgs, flagString } from "../lib/args.js";
3
5
  import { activateCodexLocal, activateStrandsLocal } from "../runtime-adapters.js";
@@ -26,4 +28,9 @@ export function main(argv = process.argv.slice(2)): number {
26
28
  return Array.isArray(result.errors) && result.errors.length ? 1 : 0;
27
29
  }
28
30
 
29
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
31
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
32
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
33
+ // entry-point guard fires correctly when the module is loaded directly as a script.
34
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
35
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
36
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import { fileURLToPath } from "node:url";
2
3
  import * as os from "node:os";
3
4
  import * as path from "node:path";
4
5
  import { parseArgs, flagBool, flagList, flagString } from "../lib/args.js";
@@ -415,4 +416,9 @@ export function main(argv = process.argv.slice(2)): number {
415
416
  }
416
417
  }
417
418
 
418
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
419
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
420
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
421
+ // entry-point guard fires correctly when the module is loaded directly as a script.
422
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
423
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
424
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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
 
@@ -321,4 +322,9 @@ export async function main(argv = process.argv.slice(2)): Promise<number> {
321
322
  return runCheck(rest);
322
323
  }
323
324
 
324
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(await main());
325
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
326
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
327
+ // entry-point guard fires correctly when the module is loaded directly as a script.
328
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
329
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
330
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = await main(); }
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import { fileURLToPath } from "node:url";
2
3
 
3
4
  const validTiers = new Set(["adapter", "design-target", "installed-command", "live-acceptance", "documented-runtime-gap"]);
4
5
  const validRuntimes = new Set(["codex", "claude-code", "kiro-cli"]);
@@ -116,4 +117,9 @@ export function main(argv = process.argv.slice(2)): number {
116
117
  }
117
118
  }
118
119
 
119
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
120
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
121
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
122
+ // entry-point guard fires correctly when the module is loaded directly as a script.
123
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
124
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
125
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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";
@@ -319,4 +320,9 @@ export function main(argv = process.argv.slice(2)): number {
319
320
  return options ? runEvidence(options) : 2;
320
321
  }
321
322
 
322
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
323
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
324
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
325
+ // entry-point guard fires correctly when the module is loaded directly as a script.
326
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
327
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
328
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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
 
@@ -278,4 +279,9 @@ export function main(argv = process.argv.slice(2)): number {
278
279
  return 0;
279
280
  }
280
281
 
281
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
282
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
283
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
284
+ // entry-point guard fires correctly when the module is loaded directly as a script.
285
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
286
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
287
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -126,31 +126,47 @@ function safeSegment(value: string): string {
126
126
  return value.replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^[.-]+|[.-]+$/g, "") || "asset";
127
127
  }
128
128
 
129
+ // Asset classes that are directly activated (copied to the runtime directory) by both adapters.
130
+ // flows: gate definitions read by the adapter's flow-routing layer.
131
+ // skills: agent guidance markdown copied to skills/<kit-id>/ for agent discovery.
132
+ // docs: documentation markdown copied to docs/<kit-id>/ for agent reference.
133
+ const ACTIVATED_ASSET_CLASSES = new Set(["flows", "skills", "docs"]);
134
+
129
135
  export function activateCodexLocal(sourceRoot: string, dest: string): Record<string, unknown> {
130
136
  const inventory = readKitInventory(sourceRoot, dest);
131
137
  const runtimeDir = path.join(dest, ".flow-agents", "runtime", "codex");
132
138
  const generated: Record<string, string>[] = [];
133
139
  const skipped: Record<string, string | null>[] = [];
134
140
  for (const asset of inventory.assets) {
135
- if (asset.asset_class !== "flows") {
136
- 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 diagnostic-only for codex-local" });
137
- continue;
138
- }
139
- if (!asset.asset_id) {
140
- 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" });
141
- continue;
141
+ if (asset.asset_class === "flows") {
142
+ if (!asset.asset_id) {
143
+ 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" });
144
+ continue;
145
+ }
146
+ const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
147
+ fs.mkdirSync(path.dirname(output), { recursive: true });
148
+ fs.copyFileSync(asset.source_path, output);
149
+ 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("/") });
150
+ } else if (asset.asset_class === "skills" || asset.asset_class === "docs") {
151
+ // Copy skills and docs to runtime/<adapter>/<class>/<kit-id>/<filename> so the
152
+ // agent's guidance index (AGENTS.md) can reference them and they are co-located
153
+ // with flow definitions for the same kit.
154
+ const filename = path.basename(asset.source_path);
155
+ const output = path.join(runtimeDir, asset.asset_class, safeSegment(asset.kit_id), filename);
156
+ fs.mkdirSync(path.dirname(output), { recursive: true });
157
+ fs.copyFileSync(asset.source_path, output);
158
+ 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("/") });
159
+ } else {
160
+ 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" });
142
161
  }
143
- const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
144
- fs.mkdirSync(path.dirname(output), { recursive: true });
145
- fs.copyFileSync(asset.source_path, output);
146
- 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("/") });
147
162
  }
148
163
  fs.mkdirSync(runtimeDir, { recursive: true });
149
- const manifest = { schema_version: "1.0", adapter: "codex-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
164
+ const supportedClasses = Array.from(ACTIVATED_ASSET_CLASSES);
165
+ 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 };
150
166
  const manifestPath = path.join(runtimeDir, "activation.json");
151
167
  writeJson(manifestPath, manifest);
152
168
  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("/") });
153
- return { selected_adapter: "codex-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
169
+ return { selected_adapter: "codex-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
154
170
  }
155
171
 
156
172
  // Decision Q3 (Issue #32): Option (a) — new adapter id "strands-local" rather than
@@ -163,27 +179,39 @@ export function activateStrandsLocal(sourceRoot: string, dest: string): Record<s
163
179
  const inventory = readKitInventory(sourceRoot, dest);
164
180
  // Runtime flows land at .flow-agents/runtime/strands/flows/<kit-id>/<asset-id>.flow.json
165
181
  // so the Strands steering context can glob for *.flow.json under this path.
182
+ // Runtime skills land at .flow-agents/runtime/strands/skills/<kit-id>/<filename> and
183
+ // docs at .flow-agents/runtime/strands/docs/<kit-id>/<filename> for system-prompt injection.
166
184
  const runtimeDir = path.join(dest, ".flow-agents", "runtime", "strands");
167
185
  const generated: Record<string, string>[] = [];
168
186
  const skipped: Record<string, string | null>[] = [];
169
187
  for (const asset of inventory.assets) {
170
- if (asset.asset_class !== "flows") {
171
- 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 diagnostic-only for strands-local" });
172
- continue;
173
- }
174
- if (!asset.asset_id) {
175
- 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" });
176
- continue;
188
+ if (asset.asset_class === "flows") {
189
+ if (!asset.asset_id) {
190
+ 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" });
191
+ continue;
192
+ }
193
+ const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
194
+ fs.mkdirSync(path.dirname(output), { recursive: true });
195
+ fs.copyFileSync(asset.source_path, output);
196
+ 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("/") });
197
+ } else if (asset.asset_class === "skills" || asset.asset_class === "docs") {
198
+ // Mirror the codex-local layout: strands/<class>/<kit-id>/<filename>.
199
+ // The Strands system-prompt injection layer can glob for all *.md files under
200
+ // .flow-agents/runtime/strands/skills/ to include agent guidance in the context.
201
+ const filename = path.basename(asset.source_path);
202
+ const output = path.join(runtimeDir, asset.asset_class, safeSegment(asset.kit_id), filename);
203
+ fs.mkdirSync(path.dirname(output), { recursive: true });
204
+ fs.copyFileSync(asset.source_path, output);
205
+ 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("/") });
206
+ } else {
207
+ 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" });
177
208
  }
178
- const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
179
- fs.mkdirSync(path.dirname(output), { recursive: true });
180
- fs.copyFileSync(asset.source_path, output);
181
- 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("/") });
182
209
  }
183
210
  fs.mkdirSync(runtimeDir, { recursive: true });
184
- const manifest = { schema_version: "1.0", adapter: "strands-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
211
+ const supportedClasses = Array.from(ACTIVATED_ASSET_CLASSES);
212
+ 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 };
185
213
  const manifestPath = path.join(runtimeDir, "activation.json");
186
214
  writeJson(manifestPath, manifest);
187
215
  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("/") });
188
- return { selected_adapter: "strands-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
216
+ return { selected_adapter: "strands-local", supported_asset_classes: supportedClasses, generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
189
217
  }
@@ -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
 
@@ -646,4 +647,9 @@ export function main(): number {
646
647
  }
647
648
  return 0;
648
649
  }
649
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
650
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
651
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
652
+ // entry-point guard fires correctly when the module is loaded directly as a script.
653
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
654
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
655
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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
 
@@ -196,4 +197,9 @@ export function main(argv = process.argv.slice(2)): number {
196
197
  return 0;
197
198
  }
198
199
 
199
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
200
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
201
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
202
+ // entry-point guard fires correctly when the module is loaded directly as a script.
203
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
204
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
205
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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
 
5
6
  export function main(argv = process.argv.slice(2)): number {
@@ -54,4 +55,9 @@ export function main(argv = process.argv.slice(2)): number {
54
55
  console.log(errors === 0 ? "Result: PASS" : `Result: FAIL (${errors} error(s))`);
55
56
  return errors === 0 ? 0 : 1;
56
57
  }
57
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
58
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
59
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
60
+ // entry-point guard fires correctly when the module is loaded directly as a script.
61
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
62
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
63
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }
@@ -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";
@@ -491,4 +492,9 @@ export function main(argv = process.argv.slice(2)): number {
491
492
  console.log("Source tree validation passed.");
492
493
  return 0;
493
494
  }
494
- if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
495
+ // Use process.exitCode (not process.exit) to allow stdout to be flushed before exit.
496
+ // Resolve real paths to handle symlinks (e.g. /tmp -> /private/tmp on macOS) so the
497
+ // entry-point guard fires correctly when the module is loaded directly as a script.
498
+ const _selfRealPath = (() => { try { return fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return fileURLToPath(import.meta.url); } })();
499
+ const _argv1RealPath = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
500
+ if (_selfRealPath === _argv1RealPath) { process.exitCode = main(); }