@kontourai/flow-agents 2.2.0 → 2.4.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/CODEOWNERS +8 -0
- package/.github/workflows/ci.yml +32 -0
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +46 -0
- package/CONTEXT.md +14 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +22 -6
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +792 -69
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +23 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +38 -7
- package/context/contracts/builder-kit-workflow-state-contract.md +3 -2
- package/context/contracts/decision-registry-contract.md +263 -0
- package/context/contracts/delivery-contract.md +1 -1
- package/context/contracts/planning-contract.md +2 -1
- package/context/contracts/review-contract.md +5 -3
- package/context/contracts/verification-contract.md +9 -1
- package/context/contracts/work-item-contract.md +1 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +283 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +9 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +14 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +3 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +1 -1
- package/docs/workflow-usage-guide.md +254 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +65 -1
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +2 -2
- package/evals/integration/test_pull_work_liveness_preflight.sh +386 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +4 -4
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +2 -2
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +151 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +723 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +22 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +56 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +13 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +80 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +8 -4
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +436 -79
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +22 -6
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +795 -71
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +23 -1
package/build/src/cli/kit.js
CHANGED
|
@@ -6,12 +6,17 @@ import * as path from "node:path";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { parseArgs, flagBool, flagString } from "../lib/args.js";
|
|
8
8
|
import { assertPathContained, copyDir, isoNow, readJson, walkFiles, writeJson } from "../lib/fs.js";
|
|
9
|
-
import { assertKitRepository, deriveKitTargets } from "../flow-kit/validate.js";
|
|
9
|
+
import { assertKitRepository, deriveKitTargets, parseKitDependencies } from "../flow-kit/validate.js";
|
|
10
10
|
import { activateCodexLocal, activateStrandsLocal } from "../runtime-adapters.js";
|
|
11
|
+
import { defaultCodexHome } from "../lib/local-artifact-root.js";
|
|
11
12
|
const REGISTRY_REL = path.join("kits", "local", "installed-kits.json");
|
|
12
13
|
const REPOSITORIES_REL = path.join("kits", "local", "repositories");
|
|
13
14
|
function registryPath(dest) { return path.join(dest, REGISTRY_REL); }
|
|
14
15
|
function installedPath(dest, kitId) { return path.join(dest, REPOSITORIES_REL, kitId); }
|
|
16
|
+
function resolveDest(flags) {
|
|
17
|
+
const explicit = flagString(flags, "dest");
|
|
18
|
+
return path.resolve(explicit ?? defaultCodexHome());
|
|
19
|
+
}
|
|
15
20
|
function loadRegistry(dest) {
|
|
16
21
|
const file = registryPath(dest);
|
|
17
22
|
if (!fs.existsSync(file))
|
|
@@ -19,6 +24,28 @@ function loadRegistry(dest) {
|
|
|
19
24
|
const data = readJson(file);
|
|
20
25
|
return { schema_version: data.schema_version ?? "1.0", kits: Array.isArray(data.kits) ? data.kits.filter((item) => typeof item === "object" && item !== null) : [] };
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Emit a non-blocking warning for each declared kit dependency that is not present
|
|
29
|
+
* in the destination's LOCAL registry.
|
|
30
|
+
*
|
|
31
|
+
* Scope limitation (v1, accepted): this check only sees the local installed-kits
|
|
32
|
+
* registry at `dest`, NOT the built-in Kit Catalog. A dependency satisfied solely by
|
|
33
|
+
* a built-in catalog kit will still warn here. Presence is enforced authoritatively
|
|
34
|
+
* (hard error) at activation time against the full discovered inventory
|
|
35
|
+
* (built-in catalog + local registry) — see src/runtime-adapters.ts.
|
|
36
|
+
*/
|
|
37
|
+
function warnUninstalledDependencies(manifest, manifestPath, dest) {
|
|
38
|
+
const { entries } = parseKitDependencies(manifest, manifestPath);
|
|
39
|
+
if (!entries.length)
|
|
40
|
+
return;
|
|
41
|
+
const installed = new Set(loadRegistry(dest).kits.map((entry) => String(entry.id ?? "")));
|
|
42
|
+
const kitId = String(manifest.id);
|
|
43
|
+
for (const dep of entries) {
|
|
44
|
+
if (!installed.has(dep.kit_id)) {
|
|
45
|
+
console.log(`warning: kit '${kitId}' declares a dependency on '${dep.kit_id}'${dep.reason ? ` (${dep.reason})` : ""} which is not installed at ${dest}; install it first with 'flow-agents kit install <source>' or activation will fail`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
22
49
|
function contentHash(root) {
|
|
23
50
|
const hash = crypto.createHash("sha256");
|
|
24
51
|
for (const file of walkFiles(root)) {
|
|
@@ -73,7 +100,7 @@ async function install(argv) {
|
|
|
73
100
|
}
|
|
74
101
|
async function installLocalSource(source, argv) {
|
|
75
102
|
const args = parseArgs(argv);
|
|
76
|
-
const dest =
|
|
103
|
+
const dest = resolveDest(args.flags);
|
|
77
104
|
let manifest;
|
|
78
105
|
try {
|
|
79
106
|
manifest = await assertKitRepository(source);
|
|
@@ -85,10 +112,12 @@ async function installLocalSource(source, argv) {
|
|
|
85
112
|
return 1;
|
|
86
113
|
}
|
|
87
114
|
const kitId = String(manifest.id);
|
|
115
|
+
warnUninstalledDependencies(manifest, path.join(source, "kit.json"), dest);
|
|
88
116
|
const hash = contentHash(source);
|
|
89
117
|
const registry = loadRegistry(dest);
|
|
90
118
|
const existing = registry.kits.find((entry) => entry.id === kitId);
|
|
91
119
|
const target = installedPath(dest, kitId);
|
|
120
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
92
121
|
assertPathContained(dest, target);
|
|
93
122
|
const sourceText = source;
|
|
94
123
|
if (existing && existing.source !== sourceText && !flagBool(args.flags, "update")) {
|
|
@@ -127,7 +156,7 @@ async function installGitSource(rawUrl, argv) {
|
|
|
127
156
|
}
|
|
128
157
|
if (!ref)
|
|
129
158
|
ref = flagString(args.flags, "ref") ?? null;
|
|
130
|
-
const dest =
|
|
159
|
+
const dest = resolveDest(args.flags);
|
|
131
160
|
const force = flagBool(args.flags, "force") ?? false;
|
|
132
161
|
const update = flagBool(args.flags, "update") ?? false;
|
|
133
162
|
// Shallow-clone into a temporary directory.
|
|
@@ -161,10 +190,12 @@ async function installGitSource(rawUrl, argv) {
|
|
|
161
190
|
}
|
|
162
191
|
// Delegate to the shared install logic (copy + registry update).
|
|
163
192
|
const kitId = String(manifest.id);
|
|
193
|
+
warnUninstalledDependencies(manifest, path.join(tmpBase, "kit.json"), dest);
|
|
164
194
|
const hash = kitContentHash(tmpBase);
|
|
165
195
|
const registry = loadRegistry(dest);
|
|
166
196
|
const existing = registry.kits.find((entry) => entry.id === kitId);
|
|
167
197
|
const target = installedPath(dest, kitId);
|
|
198
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
168
199
|
assertPathContained(dest, target);
|
|
169
200
|
const sourceText = repoUrl + (ref ? `#${ref}` : "");
|
|
170
201
|
if (existing && existing.source !== sourceText && !update) {
|
|
@@ -197,7 +228,7 @@ async function installGitSource(rawUrl, argv) {
|
|
|
197
228
|
}
|
|
198
229
|
function list(argv) {
|
|
199
230
|
const args = parseArgs(argv);
|
|
200
|
-
const dest =
|
|
231
|
+
const dest = resolveDest(args.flags);
|
|
201
232
|
const entries = loadRegistry(dest).kits;
|
|
202
233
|
if (!entries.length) {
|
|
203
234
|
console.log("No local Flow Kits installed.");
|
|
@@ -210,7 +241,7 @@ function list(argv) {
|
|
|
210
241
|
}
|
|
211
242
|
function status(argv) {
|
|
212
243
|
const args = parseArgs(argv);
|
|
213
|
-
const dest =
|
|
244
|
+
const dest = resolveDest(args.flags);
|
|
214
245
|
let entries = loadRegistry(dest).kits;
|
|
215
246
|
const kitId = args.positionals[0];
|
|
216
247
|
if (kitId) {
|
|
@@ -233,7 +264,7 @@ function status(argv) {
|
|
|
233
264
|
const AVAILABLE_ADAPTERS = ["codex-local", "strands-local"];
|
|
234
265
|
function activate(argv) {
|
|
235
266
|
const args = parseArgs(argv);
|
|
236
|
-
const dest =
|
|
267
|
+
const dest = resolveDest(args.flags);
|
|
237
268
|
const sourceRoot = path.resolve(flagString(args.flags, "source-root", path.resolve(path.dirname(process.argv[1]), "..")) ?? ".");
|
|
238
269
|
const adapter = flagString(args.flags, "adapter");
|
|
239
270
|
if (adapter && !AVAILABLE_ADAPTERS.includes(adapter)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { parseArgs, flagList, flagString } from "../lib/args.js";
|
|
4
|
-
const FLOW_ARTIFACT_PATTERN = /(?<path>\.flow-agents\/[^\s`'")]+)/g;
|
|
4
|
+
const FLOW_ARTIFACT_PATTERN = /(?<path>\.kontourai\/flow-agents\/[^\s`'")]+)/g;
|
|
5
5
|
const GITHUB_ISSUE_PATTERN = /(?:(?<owner>[A-Za-z0-9_.-]+)\/(?<repo>[A-Za-z0-9_.-]+))?#(?<number>\d+)/g;
|
|
6
6
|
const GITHUB_URL_PATTERN = /https:\/\/github\.com\/(?<owner>[^/\s]+)\/(?<repo>[^/\s]+)\/(?:issues|pull)\/(?<number>\d+)/g;
|
|
7
7
|
const BLOCKER_PATTERN = /\b(?:blocked by|depends on|waiting on|requires|should follow|coordinate with)\b[:\s-]*(?<refs>[^\n]+)/gi;
|
|
@@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { parseArgs, flagBool, flagList, flagString } from "../lib/args.js";
|
|
6
|
-
import { defaultArtifactRootForRead, defaultTelemetryDirForRead, defaultTelemetryDirsForRead, telemetryDataDir, flowAgentsArtifactRoot
|
|
6
|
+
import { defaultArtifactRootForRead, defaultTelemetryDirForRead, defaultTelemetryDirsForRead, telemetryDataDir, flowAgentsArtifactRoot } from "../lib/local-artifact-root.js";
|
|
7
7
|
const VALID_RESULTS = new Set(["success", "partial", "failure", "not_verified"]);
|
|
8
8
|
function telemetryDir(flags) {
|
|
9
9
|
const explicit = flagString(flags, "telemetry-dir") ?? process.env.TELEMETRY_DATA_DIR;
|
|
@@ -152,7 +152,7 @@ function syncArtifacts(argv) {
|
|
|
152
152
|
const dir = telemetryDir(flags);
|
|
153
153
|
ensureSafeDir(dir);
|
|
154
154
|
const artifacts = flagList(flags, "artifact-dir");
|
|
155
|
-
const records = (artifacts.length ? artifacts : [flowAgentsArtifactRoot()
|
|
155
|
+
const records = (artifacts.length ? artifacts : [flowAgentsArtifactRoot()]).flatMap((item) => fs.existsSync(item) ? artifactOutcomes(item, flags) : []);
|
|
156
156
|
writeJsonlUpsert(path.join(dir, "outcomes.jsonl"), records, "outcome_id");
|
|
157
157
|
if (!flagBool(flags, "quiet"))
|
|
158
158
|
console.log(`synced ${records.length} artifact outcome(s) to ${path.join(dir, "outcomes.jsonl")}`);
|
|
@@ -382,7 +382,7 @@ function discoverProjects(root) {
|
|
|
382
382
|
if (!fs.existsSync(root))
|
|
383
383
|
return [];
|
|
384
384
|
const candidates = [root, ...fs.readdirSync(root).map((name) => path.join(root, name))];
|
|
385
|
-
return candidates.filter((candidate) => fs.existsSync(flowAgentsArtifactRoot(candidate))
|
|
385
|
+
return candidates.filter((candidate) => fs.existsSync(flowAgentsArtifactRoot(candidate))).map((repoRoot) => {
|
|
386
386
|
const name = path.basename(repoRoot);
|
|
387
387
|
return { name, repo: name, repo_root: repoRoot, artifact_dir: defaultArtifactRootForRead(repoRoot), input_telemetry_dir: defaultTelemetryDirForRead(repoRoot), runtime: "codex", skill_ids: [] };
|
|
388
388
|
});
|
|
@@ -7,6 +7,7 @@ const validEvents = new Set(["UserPromptSubmit", "PostToolUse", "Stop"]);
|
|
|
7
7
|
const requiredCases = {
|
|
8
8
|
"dev-builder-build-requires-pickup-probe-before-plan": { description: "missing pickup Probe before plan", tier: "design-target", must_include: ["design-probe", "accepted gaps", "provider_state", "conflict_risks"], agent_must_do: ["route decision_gap back to design-probe/pickup Probe"] },
|
|
9
9
|
"dev-builder-review-before-verify-after-execute": { description: "review-before-verify after execute", tier: "adapter", event: "PostToolUse", must_include: ["Next: review", "then verify", "report only"], agent_must_do: ["review-work for report-only critique before verify-work", "not count critique.json as verification evidence"] },
|
|
10
|
+
"dev-builder-route-fresh-coding-prompt": { description: "fresh coding prompt routes into Builder workflow", tier: "adapter", event: "UserPromptSubmit", must_include: ["BUILDER WORKFLOW ROUTE", "activate `deliver`", "--flow-id builder.build", "plan-work -> execute-plan -> review-work -> verify-work", "publish/release-readiness and learning-review"], agent_must_do: ["activate Builder Kit delivery workflow before source edits", "use deliver by default for coding/build work", "do not bypass plan-work -> execute-plan -> review-work -> verify-work", "publish, release readiness, and learning feedback"] },
|
|
10
11
|
"dev-verify-fail-preserves-trace-before-rework": { description: "verify failure route-back with preserved FAIL evidence", tier: "design-target", must_include: ["If verdict=FAIL: record the FAIL artifact"], agent_must_do: ["write the FAIL artifact before routing back", "route to plan"] },
|
|
11
12
|
"codex-claude-strict-stop-adapter-contract": { description: "Goal Fit stop adapter behavior", tier: "adapter", hook: "stop-goal-fit", event: "Stop", must_include: ["Goal Fit warning"], agent_must_do: ["treat strict Stop guidance as a blocker"] },
|
|
12
13
|
"codex-live-context-gap": { description: "Codex documented runtime gap", tier: "documented-runtime-gap", must_include: ["STATE:", "not_verified"], agent_must_do: ["record NOT_VERIFIED for live influence"] },
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
// Resolve bundled JSON Schemas relative to this compiled script's own package
|
|
6
|
+
// location (build/src/cli/validate-workflow-artifacts.js -> ../../../schemas), NOT
|
|
7
|
+
// process.cwd(), so `flow-agents-validate-artifacts` works from any repo (the artifact
|
|
8
|
+
// paths to validate are still taken from argv/cwd). Mirrors the package-relative pattern
|
|
9
|
+
// used for liveness-read.js in workflow-sidecar.ts.
|
|
10
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
5
11
|
const statusRe = /\[(PASS|FAIL|NOT_VERIFIED|SKIP|PARTIAL)\]/i;
|
|
6
12
|
const dateTimeRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
7
13
|
const sidecarSchemas = {
|
|
@@ -311,11 +317,12 @@ function readJson(file) {
|
|
|
311
317
|
}
|
|
312
318
|
function validateSidecar(file) {
|
|
313
319
|
const { value, issues } = readJson(file);
|
|
320
|
+
const warnings = [];
|
|
314
321
|
if (value === undefined)
|
|
315
|
-
return issues;
|
|
322
|
+
return { issues, warnings };
|
|
316
323
|
const schemaFile = sidecarSchemas[path.basename(file)];
|
|
317
324
|
if (schemaFile) {
|
|
318
|
-
const schema = JSON.parse(readText(path.join(
|
|
325
|
+
const schema = JSON.parse(readText(path.join(packageRoot, schemaFile)));
|
|
319
326
|
validateSchemaValue(file, value, schema, path.basename(file), issues, schema);
|
|
320
327
|
}
|
|
321
328
|
if (path.basename(file) === "evidence.json") {
|
|
@@ -359,7 +366,10 @@ function validateSidecar(file) {
|
|
|
359
366
|
issues.push({ path: file, message: "deploy decision requires post_deploy_checks to be planned or pass" });
|
|
360
367
|
}
|
|
361
368
|
}
|
|
362
|
-
|
|
369
|
+
if (path.basename(file) === "state.json" && value && typeof value === "object" && !Array.isArray(value) && !("branch" in value)) {
|
|
370
|
+
warnings.push({ path: file, message: "state.json has no branch field (legacy/pre-#289 session) — re-run `ensure-session` to backfill agent/<actor>/<slug>." });
|
|
371
|
+
}
|
|
372
|
+
return { issues, warnings };
|
|
363
373
|
}
|
|
364
374
|
function validateLearningCorrections(file, status, records, issues) {
|
|
365
375
|
records.forEach((record, index) => {
|
|
@@ -486,12 +496,18 @@ function main() {
|
|
|
486
496
|
const markdown = artifactPaths(pathsIn);
|
|
487
497
|
const sidecars = sidecarPaths(pathsIn);
|
|
488
498
|
const issues = [];
|
|
499
|
+
const warnings = [];
|
|
489
500
|
if (!skipMarkdown)
|
|
490
501
|
for (const file of markdown)
|
|
491
502
|
issues.push(...validateArtifact(file));
|
|
492
|
-
for (const file of sidecars)
|
|
493
|
-
|
|
503
|
+
for (const file of sidecars) {
|
|
504
|
+
const result = validateSidecar(file);
|
|
505
|
+
issues.push(...result.issues);
|
|
506
|
+
warnings.push(...result.warnings);
|
|
507
|
+
}
|
|
494
508
|
issues.push(...validateSidecarGroup(pathsIn, markdown, requireSidecars, requireCritique));
|
|
509
|
+
for (const w of warnings)
|
|
510
|
+
console.error(`WARN ${w.path}: ${w.message}`);
|
|
495
511
|
if (issues.length) {
|
|
496
512
|
for (const issue of issues)
|
|
497
513
|
console.error(`${issue.path}: ${issue.message}`);
|
|
@@ -16,7 +16,7 @@ const ACTIVE_STATUSES = new Set([
|
|
|
16
16
|
const KNOWN_LEARNING_STATUSES = new Set(["pending", "learned", "followup_required", "blocked"]);
|
|
17
17
|
const KNOWN_LEARNING_ROUTE_TARGETS = new Set(["rule", "skill", "power", "agent", "eval", "doc", "backlog", "knowledge", "none"]);
|
|
18
18
|
const KNOWN_LEARNING_ROUTE_STATUSES = new Set(["completed", "open", "deferred", "accepted", "rejected"]);
|
|
19
|
-
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history"]);
|
|
19
|
+
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history", "liveness"]);
|
|
20
20
|
const MAX_SIDECAR_BYTES = 1024 * 1024;
|
|
21
21
|
function printHelp() {
|
|
22
22
|
console.log("Usage: flow-agents workflow-artifact-cleanup-audit [--artifact-root <path>] [--json]");
|
|
@@ -24,7 +24,7 @@ function printHelp() {
|
|
|
24
24
|
console.log("Read-only dry-run audit for local workflow artifact directories.");
|
|
25
25
|
console.log("");
|
|
26
26
|
console.log("Options:");
|
|
27
|
-
console.log(" --artifact-root <path> Local artifact root to scan (default: .kontourai/flow-agents
|
|
27
|
+
console.log(" --artifact-root <path> Local artifact root to scan (default: .kontourai/flow-agents)");
|
|
28
28
|
console.log(" --json Print stable JSON buckets instead of text");
|
|
29
29
|
console.log(" --help Show this help");
|
|
30
30
|
console.log("");
|
|
@@ -148,6 +148,34 @@ function invalidItem(slug, workflowPath, reason) {
|
|
|
148
148
|
reasons: [reason],
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
|
+
// Promote-then-archive gate (issue #312). A delivered session's durable residue
|
|
152
|
+
// (decisions, vocabulary, learnings, doc updates) must be PROMOTED before the session
|
|
153
|
+
// is archived. Promotion is recorded as a session-local promotion claim in the session
|
|
154
|
+
// trust.bundle (workflow-sidecar promote), detectable here via claim.metadata.promotion
|
|
155
|
+
// — no new manifest entry required. A delivered/accepted session that reached a terminal
|
|
156
|
+
// shape WITHOUT that claim is a cleanup_candidate (blocked from archive) with a remedy
|
|
157
|
+
// naming the promote step. Already-`archived` sessions are past the gate and are never
|
|
158
|
+
// re-flagged (issue #312 non-goal: do not backfill already-archived sessions).
|
|
159
|
+
const PROMOTE_REMEDY = "run `flow-agents workflow-sidecar promote <dir> --evidence-path <durable-doc> ...`" +
|
|
160
|
+
" (or `promote --none --reason \"<why nothing durable>\"`) to record the promotion claim before archiving";
|
|
161
|
+
function hasPromotionClaim(workflowDir) {
|
|
162
|
+
const bundlePath = path.join(workflowDir, "trust.bundle");
|
|
163
|
+
if (!fs.existsSync(bundlePath))
|
|
164
|
+
return false;
|
|
165
|
+
const parsed = readJson(bundlePath, "trust.bundle");
|
|
166
|
+
if (!parsed.ok)
|
|
167
|
+
return false;
|
|
168
|
+
const bundle = objectValue(parsed.value);
|
|
169
|
+
if (!bundle || !Array.isArray(bundle.claims))
|
|
170
|
+
return false;
|
|
171
|
+
return bundle.claims.some((entry) => {
|
|
172
|
+
const claim = objectValue(entry);
|
|
173
|
+
if (!claim)
|
|
174
|
+
return false;
|
|
175
|
+
const meta = objectValue(claim.metadata);
|
|
176
|
+
return meta !== null && objectValue(meta.promotion) !== null;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
151
179
|
function classifyWorkflow(slug, workflowPath) {
|
|
152
180
|
const statePath = path.join(workflowPath, "state.json");
|
|
153
181
|
if (!fs.existsSync(statePath))
|
|
@@ -185,9 +213,15 @@ function classifyWorkflow(slug, workflowPath) {
|
|
|
185
213
|
return { ...base, classification: "cleanup_candidate", reasons: ["verified workflow has next_action.status done"] };
|
|
186
214
|
}
|
|
187
215
|
if (["delivered", "accepted", "archived"].includes(status) && phase === "done") {
|
|
216
|
+
if (status !== "archived" && !hasPromotionClaim(workflowPath)) {
|
|
217
|
+
return { ...base, classification: "cleanup_candidate", reasons: [`${status} workflow reached phase done without a promotion claim; ${PROMOTE_REMEDY}`] };
|
|
218
|
+
}
|
|
188
219
|
return { ...base, classification: "terminal_done", reasons: [`${status} workflow is in phase done`] };
|
|
189
220
|
}
|
|
190
221
|
if ((status === "accepted" || status === "archived") && learning.reasons.length === 0) {
|
|
222
|
+
if (status !== "archived" && !hasPromotionClaim(workflowPath)) {
|
|
223
|
+
return { ...base, classification: "cleanup_candidate", reasons: [`${status} workflow has closed learning routing but no promotion claim; ${PROMOTE_REMEDY}`] };
|
|
224
|
+
}
|
|
191
225
|
return { ...base, classification: "terminal_done", reasons: [`${status} workflow has no open learning routing`] };
|
|
192
226
|
}
|
|
193
227
|
return { ...base, classification: "invalid", reasons: [`unrecognized lifecycle shape: status=${status}, phase=${phase}, next_action.status=${nextStatus ?? "missing"}`] };
|
|
@@ -80,7 +80,7 @@ type SurfaceModule = {
|
|
|
80
80
|
status: string;
|
|
81
81
|
policyId: string | undefined;
|
|
82
82
|
};
|
|
83
|
-
generateClaimId: (subjectId: string,
|
|
83
|
+
generateClaimId: (subjectId: string, facet: string, fieldOrBehavior: string) => string;
|
|
84
84
|
statusFunctionVersion: string;
|
|
85
85
|
resolveInquiry: (bundle: Record<string, unknown>, inquiry: SurfaceInquiry, options?: {
|
|
86
86
|
now?: Date;
|
|
@@ -208,10 +208,17 @@ export declare function sealTrustCheckpoint(dir: string, slug: string, sealedAt:
|
|
|
208
208
|
* trust.checkpoint.intoto.json / trust.checkpoint.sig.json from the
|
|
209
209
|
* session artifact dir to <repoRoot>/delivery/.
|
|
210
210
|
*
|
|
211
|
-
* Fail-soft: if trust.bundle is absent, returns without throwing.
|
|
211
|
+
* Fail-soft on a missing bundle: if trust.bundle is absent, returns without throwing.
|
|
212
|
+
* Fail-CLOSED on repo-root resolution: repoRoot must be a real, resolved kits/ ancestor
|
|
213
|
+
* (see findRepoRootFromDirStrict) — null (no ancestor found) skips the publish with a
|
|
214
|
+
* visible warning instead of writing to whatever process.cwd() happens to be. This
|
|
215
|
+
* prevents a scratch/test session dir (no kits/ ancestor) from silently clobbering an
|
|
216
|
+
* unrelated real repo's delivery/trust.bundle when invoked with that repo as cwd (see
|
|
217
|
+
* evals/integration/test_checkpoint_signing.sh TEST 2 and the WS5 session findings at
|
|
218
|
+
* .kontourai/flow-agents/ws5-governance-kit-slice1 for the root cause this fixes).
|
|
212
219
|
* Idempotent: overwrites on re-delivery.
|
|
213
220
|
*/
|
|
214
|
-
export declare function publishDelivery(dir: string, repoRoot: string): Promise<void>;
|
|
221
|
+
export declare function publishDelivery(dir: string, repoRoot: string | null): Promise<void>;
|
|
215
222
|
export declare function validateLearningCorrection(record: AnyObj): void;
|
|
216
223
|
export declare function normalizeLearning(raw: AnyObj, timestamp: string): AnyObj;
|
|
217
224
|
/** Shape of a claim from the trust.bundle */
|
|
@@ -219,7 +226,7 @@ export interface TrustClaim {
|
|
|
219
226
|
id: string;
|
|
220
227
|
subjectType: string;
|
|
221
228
|
subjectId: string;
|
|
222
|
-
|
|
229
|
+
facet?: string;
|
|
223
230
|
claimType: string;
|
|
224
231
|
fieldOrBehavior: string;
|
|
225
232
|
value: string;
|
|
@@ -236,7 +243,7 @@ export interface BundleFile {
|
|
|
236
243
|
events: AnyObj[];
|
|
237
244
|
policies: AnyObj[];
|
|
238
245
|
}
|
|
239
|
-
/** The gate block signal read from .flow-agents/.goal-fit-block-streak.json */
|
|
246
|
+
/** The gate block signal read from .kontourai/flow-agents/.goal-fit-block-streak.json */
|
|
240
247
|
export interface GateBlockSignal {
|
|
241
248
|
/** True when the streak file exists AND count >= 1 */
|
|
242
249
|
blocked: boolean;
|
|
@@ -251,13 +258,13 @@ export interface GateBlockSignal {
|
|
|
251
258
|
*/
|
|
252
259
|
export type GateCalibration = "correct" | "false_block" | "missed_block";
|
|
253
260
|
/**
|
|
254
|
-
* Read the gate block signal from .flow-agents/.goal-fit-block-streak.json
|
|
261
|
+
* Read the gate block signal from .kontourai/flow-agents/.goal-fit-block-streak.json
|
|
255
262
|
* (written by scripts/hooks/stop-goal-fit.js when block mode fires).
|
|
256
263
|
* The file sits at <artifact-root>/.goal-fit-block-streak.json — one level
|
|
257
264
|
* above the session artifact dir. Fail-open: returns { blocked: false } when
|
|
258
265
|
* the file is absent or unreadable.
|
|
259
266
|
*
|
|
260
|
-
* @param artifactRoot The
|
|
267
|
+
* @param artifactRoot The runtime artifact root dir (parent of session slug dir).
|
|
261
268
|
*/
|
|
262
269
|
export declare function readGateBlockSignal(artifactRoot: string): GateBlockSignal;
|
|
263
270
|
/**
|