@kontourai/flow-agents 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/build/src/builder-flow-runtime.js +118 -17
- package/build/src/cli/assignment-provider.js +13 -1
- package/build/src/cli/continuation-adapter.d.ts +24 -0
- package/build/src/cli/continuation-adapter.js +225 -0
- package/build/src/cli/workflow-sidecar.js +29 -11
- package/build/src/cli/workflow.js +67 -11
- package/build/src/continuation-driver.d.ts +92 -0
- package/build/src/continuation-driver.js +444 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/tools/build-universal-bundles.js +53 -3
- package/docs/getting-started.md +9 -1
- package/docs/public-workflow-cli.md +54 -0
- package/docs/spec/builder-flow-runtime.md +36 -2
- package/docs/workflow-usage-guide.md +7 -0
- package/evals/integration/test_builder_step_producers.sh +37 -4
- package/evals/integration/test_bundle_install.sh +108 -4
- package/evals/integration/test_bundle_lifecycle.sh +4 -6
- package/evals/integration/test_install_merge.sh +18 -8
- package/evals/integration/test_public_workflow_cli.sh +11 -5
- package/evals/static/test_universal_bundles.sh +44 -1
- package/package.json +4 -4
- package/packaging/README.md +1 -1
- package/scripts/README.md +1 -1
- package/scripts/install-codex-home.sh +63 -23
- package/scripts/install-owned-files.js +18 -2
- package/src/builder-flow-runtime.ts +108 -10
- package/src/cli/assignment-provider.ts +13 -1
- package/src/cli/builder-flow-runtime.test.mjs +378 -20
- package/src/cli/continuation-adapter.ts +239 -0
- package/src/cli/continuation-driver.test.mjs +564 -0
- package/src/cli/workflow-sidecar.ts +27 -11
- package/src/cli/workflow.ts +68 -11
- package/src/continuation-driver.ts +532 -0
- package/src/index.ts +20 -0
- package/src/tools/build-universal-bundles.ts +51 -3
|
@@ -663,6 +663,13 @@ the read-only `workflow status` projection without attaching evidence or advanci
|
|
|
663
663
|
[`docs/spec/builder-flow-runtime.md`](spec/builder-flow-runtime.md) for the ownership,
|
|
664
664
|
trust-binding, route-back, and artifact-root contract.
|
|
665
665
|
|
|
666
|
+
For unattended runtime re-entry, the active assignment actor may use `workflow drive` with an
|
|
667
|
+
explicit runtime adapter argv file. The driver repeats the same public projection/evidence cycle,
|
|
668
|
+
persists its mission turn budget, and parks on adapter-declared PID or deadline barriers instead of
|
|
669
|
+
spending turns while external work is incomplete. Adapter completion never advances a gate by
|
|
670
|
+
self-report; only trust evidence accepted by canonical Flow can change the current step. See
|
|
671
|
+
[`docs/public-workflow-cli.md`](public-workflow-cli.md#bounded-continuation-driver) for the protocol.
|
|
672
|
+
|
|
666
673
|
If the same Builder slice is interrupted, inspect its canonical status. Resume
|
|
667
674
|
only when the public status reports a paused run:
|
|
668
675
|
|
|
@@ -456,6 +456,9 @@ record_public_expectation() {
|
|
|
456
456
|
*) _fail "public producer fixture has no durable artifact for $expectation"; return ;;
|
|
457
457
|
esac
|
|
458
458
|
local -a args=(evidence --session-dir "$PUBLIC_SESSION" --expectation "$expectation" --status "$status" --summary "public producer fixture records a reviewable durable artifact" --evidence-ref-json "{\"kind\":\"artifact\",\"file\":\"$artifact\",\"summary\":\"Fixture artifact for $expectation.\"}")
|
|
459
|
+
if [ "$expectation" = "tests-evidence" ] && [ "$status" = "fail" ]; then
|
|
460
|
+
args+=(--route-reason implementation_defect)
|
|
461
|
+
fi
|
|
459
462
|
if [ "$expectation" = "tests-evidence" ] && [ "$status" = "pass" ]; then
|
|
460
463
|
local test_command criterion_one criterion_two command_ref
|
|
461
464
|
test_command="bash checks/check-public-session.sh .kontourai/flow-agents/$slug/state.json"
|
|
@@ -614,16 +617,46 @@ ROUTE_CRITIQUE_OUTPUT="$(public_review critique --session-dir "$PUBLIC_SESSION"
|
|
|
614
617
|
--artifact-ref "$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md" \
|
|
615
618
|
--lane-json "{\"id\":\"code-review\",\"status\":\"pass\",\"summary\":\"Public fixture code review completed.\",\"evidence_refs\":[{\"kind\":\"artifact\",\"file\":\"$PUBLIC_SESSION/$(basename "$PUBLIC_SESSION")--deliver.md\",\"summary\":\"Reviewed public fixture delivery artifact.\"}]}" 2>&1)" \
|
|
616
619
|
|| _fail "public authenticated critique failed before failed tests-evidence: $ROUTE_CRITIQUE_OUTPUT"
|
|
620
|
+
# Seed current verified acceptance prerequisites through the private producer
|
|
621
|
+
# without synchronizing Flow. The subsequent public failed tests claim replaces
|
|
622
|
+
# the provisional passing tests check, preserves these criteria + the clean
|
|
623
|
+
# critique, and is the only attachment/evaluation for this gate visit.
|
|
624
|
+
ROUTE_TEST_COMMAND="bash checks/check-public-session.sh .kontourai/flow-agents/$(basename "$PUBLIC_SESSION")/state.json"
|
|
625
|
+
ROUTE_COMMAND_REF="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
626
|
+
const command = process.argv[2];
|
|
627
|
+
process.stdout.write(JSON.stringify({ kind: 'command', excerpt: command, summary: 'Current route-back prerequisite command.' }));
|
|
628
|
+
NODE
|
|
629
|
+
)"
|
|
630
|
+
ROUTE_CRITERION_ONE="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
631
|
+
const command = process.argv[2];
|
|
632
|
+
process.stdout.write(JSON.stringify({ id: 'AC-1', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Current AC-1 prerequisite.' }] }));
|
|
633
|
+
NODE
|
|
634
|
+
)"
|
|
635
|
+
ROUTE_CRITERION_TWO="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
636
|
+
const command = process.argv[2];
|
|
637
|
+
process.stdout.write(JSON.stringify({ id: 'AC-2', status: 'pass', evidence_refs: [{ kind: 'command', excerpt: command, summary: 'Current AC-2 prerequisite.' }] }));
|
|
638
|
+
NODE
|
|
639
|
+
)"
|
|
640
|
+
ROUTE_OBSERVED="$(node - "$ROUTE_TEST_COMMAND" <<'NODE'
|
|
641
|
+
const command = process.argv[2];
|
|
642
|
+
process.stdout.write(JSON.stringify({ command, exit_code: 0, test_count: 1, output_sha256: '0'.repeat(64) }));
|
|
643
|
+
NODE
|
|
644
|
+
)"
|
|
645
|
+
CODEX_SESSION_ID=builder-public-producers flow_agents_node "workflow-sidecar" record-gate-claim "$PUBLIC_SESSION" \
|
|
646
|
+
--expectation tests-evidence --status pass --summary "Seed complete current acceptance prerequisites before routed failure." \
|
|
647
|
+
--command "$ROUTE_TEST_COMMAND" --observed-command-json "$ROUTE_OBSERVED" \
|
|
648
|
+
--evidence-ref-json "$ROUTE_COMMAND_REF" --criterion-json "$ROUTE_CRITERION_ONE" --criterion-json "$ROUTE_CRITERION_TWO" >/dev/null 2>&1 \
|
|
649
|
+
|| _fail "failed to seed current acceptance prerequisites for routed failure"
|
|
617
650
|
record_public_expectation "tests-evidence" "fail"
|
|
618
651
|
ROUTE_REPORT="$(public_flow status --session-dir "$PUBLIC_SESSION" --json 2>/dev/null)"
|
|
619
652
|
if node - "$ROUTE_REPORT" <<'NODE'
|
|
620
653
|
const report = JSON.parse(process.argv[2]);
|
|
621
|
-
if (report.current_step !== '
|
|
622
|
-
if ((report.next_action?.skills || []).join(',') !== '
|
|
623
|
-
if (!/attempt 1\/3 returned to `
|
|
654
|
+
if (report.current_step !== 'execute') process.exit(1);
|
|
655
|
+
if ((report.next_action?.skills || []).join(',') !== 'execute-plan') process.exit(2);
|
|
656
|
+
if (!/attempt 1\/3 returned to `execute` for `implementation_defect`/.test(report.next_action?.summary || '')) process.exit(3);
|
|
624
657
|
NODE
|
|
625
658
|
then
|
|
626
|
-
_pass "failed verify evidence routes back through Flow
|
|
659
|
+
_pass "complete failed verify evidence routes back through Flow once to execute for implementation_defect"
|
|
627
660
|
else
|
|
628
661
|
_fail "public failed-verify route-back was not projected correctly: $ROUTE_REPORT"
|
|
629
662
|
fi
|
|
@@ -285,7 +285,7 @@ else
|
|
|
285
285
|
_fail "pi install failed"
|
|
286
286
|
fi
|
|
287
287
|
|
|
288
|
-
USER_SKILLS_DIR="$CODEX_FULL_DEST/.
|
|
288
|
+
USER_SKILLS_DIR="$CODEX_FULL_DEST/.agents/sk""ills/user-skill"
|
|
289
289
|
mkdir -p "$CODEX_FULL_DEST/.codex/ag""ents" "$USER_SKILLS_DIR"
|
|
290
290
|
printf 'name = "user-agent"\n' > "$CODEX_FULL_DEST/.codex/ag""ents/user-agent.toml"
|
|
291
291
|
printf '# user skill\n' > "$USER_SKILLS_DIR/SKILL.md"
|
|
@@ -309,7 +309,7 @@ for dir in \
|
|
|
309
309
|
"$CLAUDE_DEST/.flow-agents" \
|
|
310
310
|
"$CLAUDE_DEST/.kontourai/flow-agents" \
|
|
311
311
|
"$CODEX_DEST/.codex/agents" \
|
|
312
|
-
"$CODEX_DEST/.
|
|
312
|
+
"$CODEX_DEST/.agents/skills" \
|
|
313
313
|
"$CODEX_DEST/.flow-agents" \
|
|
314
314
|
"$CODEX_DEST/.kontourai/flow-agents" \
|
|
315
315
|
"$CODEX_FULL_DEST/.flow-agents" \
|
|
@@ -1069,7 +1069,7 @@ else
|
|
|
1069
1069
|
_fail "packed npm consumer did not complete the public Builder workflow contract and lifecycle commands"
|
|
1070
1070
|
fi
|
|
1071
1071
|
|
|
1072
|
-
if node - "$CODEX_FULL_DEST/.
|
|
1072
|
+
if node - "$CODEX_FULL_DEST/.agents/skills" "$CODEX_FULL_DEST" <<'NODE'
|
|
1073
1073
|
const fs = require('node:fs');
|
|
1074
1074
|
const path = require('node:path');
|
|
1075
1075
|
const [root, installRoot] = process.argv.slice(2);
|
|
@@ -1094,7 +1094,12 @@ for (const skill of [...builder, 'agentic-engineering']) {
|
|
|
1094
1094
|
throw new Error('verify-work must ship criterion-backed substantive verification evidence guidance');
|
|
1095
1095
|
}
|
|
1096
1096
|
const refs = [...text.matchAll(/\b(?:context|docs|kits)\/[A-Za-z0-9_./-]+\.(?:md|json)\b/g)].map((match) => match[0]);
|
|
1097
|
-
for (const ref of refs)
|
|
1097
|
+
for (const ref of refs) {
|
|
1098
|
+
const skillLocal = path.join(path.dirname(file), ref);
|
|
1099
|
+
if (!fs.existsSync(skillLocal) && !fs.existsSync(path.join(installRoot, ref))) {
|
|
1100
|
+
throw new Error(`${skill} has unresolved installed resource ${ref}`);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1098
1103
|
}
|
|
1099
1104
|
}
|
|
1100
1105
|
NODE
|
|
@@ -1110,6 +1115,105 @@ else
|
|
|
1110
1115
|
_fail "Codex full install removed unknown user files"
|
|
1111
1116
|
fi
|
|
1112
1117
|
|
|
1118
|
+
echo ""
|
|
1119
|
+
echo "--- Dedicated Codex Home Universal Skills ---"
|
|
1120
|
+
GLOBAL_HOME="$TMPDIR_EVAL/global-home"
|
|
1121
|
+
GLOBAL_CODEX="$TMPDIR_EVAL/global-codex"
|
|
1122
|
+
GLOBAL_SKILLS="$TMPDIR_EVAL/global-agents/skills"
|
|
1123
|
+
mkdir -p "$GLOBAL_SKILLS/user-skill"
|
|
1124
|
+
printf '# user skill\n' > "$GLOBAL_SKILLS/user-skill/SKILL.md"
|
|
1125
|
+
GLOBAL_OUTPUT="$TMPDIR_EVAL/global-install.out"
|
|
1126
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$GLOBAL_CODEX" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$GLOBAL_CODEX" --skills-dir "$GLOBAL_SKILLS" >"$GLOBAL_OUTPUT"; then
|
|
1127
|
+
_pass "dedicated Codex installer accepts independent hermetic runtime and skill roots"
|
|
1128
|
+
else
|
|
1129
|
+
_fail "dedicated Codex installer failed with independent hermetic roots"
|
|
1130
|
+
fi
|
|
1131
|
+
if [[ -f "$GLOBAL_SKILLS/plan-work/SKILL.md" && -f "$GLOBAL_SKILLS/plan-work/context/contracts/planning-contract.md" && -f "$GLOBAL_SKILLS/user-skill/SKILL.md" && ! -e "$GLOBAL_CODEX/skills/plan-work" ]]; then
|
|
1132
|
+
_pass "global install uses self-contained universal skills and preserves user skills"
|
|
1133
|
+
else
|
|
1134
|
+
_fail "global universal skill layout, resource closure, or user preservation is wrong"
|
|
1135
|
+
fi
|
|
1136
|
+
if rg -q 'Installed Flow Agents into Codex home at .+/global-codex$' "$GLOBAL_OUTPUT" && rg -q 'Installed portable skills at .+/global-agents/skills$' "$GLOBAL_OUTPUT"; then
|
|
1137
|
+
_pass "installer reports both runtime and portable skill destinations"
|
|
1138
|
+
else
|
|
1139
|
+
_fail "installer output does not report both destinations"
|
|
1140
|
+
fi
|
|
1141
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$GLOBAL_CODEX" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$GLOBAL_CODEX" --skills-dir "$GLOBAL_SKILLS" >/dev/null; then
|
|
1142
|
+
_pass "split-root reinstall is idempotent"
|
|
1143
|
+
else
|
|
1144
|
+
_fail "split-root reinstall is not idempotent"
|
|
1145
|
+
fi
|
|
1146
|
+
|
|
1147
|
+
CONFLICT_CODEX="$TMPDIR_EVAL/conflict-codex"
|
|
1148
|
+
CONFLICT_SKILLS="$TMPDIR_EVAL/conflict-agents/skills"
|
|
1149
|
+
mkdir -p "$CONFLICT_SKILLS/plan-work" "$CONFLICT_CODEX/skills/plan-work" "$CONFLICT_CODEX/.flow-agents"
|
|
1150
|
+
printf '# user collision\n' > "$CONFLICT_SKILLS/plan-work/SKILL.md"
|
|
1151
|
+
cp "$ROOT_DIR/dist/codex/.agents/skills/plan-work/SKILL.md" "$CONFLICT_CODEX/skills/plan-work/SKILL.md"
|
|
1152
|
+
printf 'runtime sentinel\n' > "$CONFLICT_CODEX/runtime-sentinel"
|
|
1153
|
+
node - "$CONFLICT_CODEX" <<'NODE'
|
|
1154
|
+
const fs=require('node:fs'), path=require('node:path'), crypto=require('node:crypto'); const root=process.argv[2];
|
|
1155
|
+
const rel='skills' + '/plan-work/SKILL.md'; const sha256=crypto.createHash('sha256').update(fs.readFileSync(path.join(root,rel))).digest('hex');
|
|
1156
|
+
fs.writeFileSync(path.join(root,'.flow-agents/codex-install-manifest.json'), JSON.stringify({schema_version:'1.0',files:[{path:rel,sha256}]},null,2)+'\n');
|
|
1157
|
+
NODE
|
|
1158
|
+
CONFLICT_RUNTIME_BEFORE="$(shasum -a 256 "$CONFLICT_CODEX/skills/plan-work/SKILL.md" "$CONFLICT_CODEX/.flow-agents/codex-install-manifest.json" "$CONFLICT_CODEX/runtime-sentinel")"
|
|
1159
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$CONFLICT_CODEX" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CONFLICT_CODEX" --skills-dir "$CONFLICT_SKILLS" >/dev/null 2>&1; then
|
|
1160
|
+
_fail "global installer overwrote a user-owned skill collision"
|
|
1161
|
+
else
|
|
1162
|
+
CONFLICT_RUNTIME_AFTER="$(shasum -a 256 "$CONFLICT_CODEX/skills/plan-work/SKILL.md" "$CONFLICT_CODEX/.flow-agents/codex-install-manifest.json" "$CONFLICT_CODEX/runtime-sentinel")"
|
|
1163
|
+
if [[ "$(cat "$CONFLICT_SKILLS/plan-work/SKILL.md")" == "# user collision" && "$CONFLICT_RUNTIME_BEFORE" == "$CONFLICT_RUNTIME_AFTER" && ! -e "$CONFLICT_SKILLS/.flow-agents" ]]; then
|
|
1164
|
+
_pass "cross-root collision preflight preserves universal content, legacy skill, runtime sentinel, and manifests"
|
|
1165
|
+
else
|
|
1166
|
+
_fail "cross-root collision failure partially mutated an install root"
|
|
1167
|
+
fi
|
|
1168
|
+
fi
|
|
1169
|
+
|
|
1170
|
+
SYMLINK_TARGET="$TMPDIR_EVAL/symlink-target"
|
|
1171
|
+
SYMLINK_PARENT="$TMPDIR_EVAL/symlink-parent"
|
|
1172
|
+
mkdir -p "$SYMLINK_TARGET" "$SYMLINK_PARENT"
|
|
1173
|
+
ln -s "$SYMLINK_TARGET" "$SYMLINK_PARENT/catalog"
|
|
1174
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$TMPDIR_EVAL/symlink-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$TMPDIR_EVAL/symlink-codex" --skills-dir "$SYMLINK_PARENT/catalog/skills" >/dev/null 2>&1; then
|
|
1175
|
+
_fail "global installer followed a symlinked skill destination component"
|
|
1176
|
+
else
|
|
1177
|
+
[[ ! -e "$SYMLINK_TARGET/skills" ]] && _pass "global installer refuses symlinked skill destination components without mutation" || _fail "symlink rejection mutated its target"
|
|
1178
|
+
fi
|
|
1179
|
+
|
|
1180
|
+
SOURCE_ANCESTOR="$(dirname "$ROOT_DIR")"
|
|
1181
|
+
SOURCE_DESCENDANT="$ROOT_DIR/.fa-550-forbidden-skills"
|
|
1182
|
+
for unsafe in / "$SOURCE_ANCESTOR" "$SOURCE_DESCENDANT"; do
|
|
1183
|
+
rm -rf "$SOURCE_DESCENDANT"
|
|
1184
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$TMPDIR_EVAL/unsafe-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$TMPDIR_EVAL/unsafe-codex" --skills-dir "$unsafe" >/dev/null 2>&1; then
|
|
1185
|
+
_fail "global installer accepted unsafe skill namespace root: $unsafe"
|
|
1186
|
+
elif [[ ! -e "$SOURCE_DESCENDANT" && ! -e "$TMPDIR_EVAL/unsafe-codex" ]]; then
|
|
1187
|
+
_pass "unsafe root/overlap rejection occurs before destination mutation: $unsafe"
|
|
1188
|
+
else
|
|
1189
|
+
_fail "unsafe root/overlap rejection left destination mutations: $unsafe"
|
|
1190
|
+
fi
|
|
1191
|
+
done
|
|
1192
|
+
|
|
1193
|
+
MIGRATE_CODEX="$TMPDIR_EVAL/migrate-codex"
|
|
1194
|
+
MIGRATE_SKILLS="$TMPDIR_EVAL/migrate-agents/skills"
|
|
1195
|
+
LEGACY_SKILLS_SEGMENT="skills"
|
|
1196
|
+
LEGACY_USER_DIR="$MIGRATE_CODEX/$LEGACY_SKILLS_SEGMENT/user-legacy"
|
|
1197
|
+
mkdir -p "$MIGRATE_CODEX/skills/plan-work" "$LEGACY_USER_DIR" "$MIGRATE_CODEX/.flow-agents"
|
|
1198
|
+
cp "$ROOT_DIR/dist/codex/.agents/skills/plan-work/SKILL.md" "$MIGRATE_CODEX/skills/plan-work/SKILL.md"
|
|
1199
|
+
printf '# modified legacy user content\n' > "$LEGACY_USER_DIR/SKILL.md"
|
|
1200
|
+
node - "$MIGRATE_CODEX" <<'NODE'
|
|
1201
|
+
const fs = require('node:fs'); const path = require('node:path'); const crypto = require('node:crypto');
|
|
1202
|
+
const root = process.argv[2];
|
|
1203
|
+
const rels = ['skills' + '/plan-work/SKILL.md', 'skills' + '/user-legacy/SKILL.md'];
|
|
1204
|
+
const files = rels.map(p => ({path:p, sha256:crypto.createHash('sha256').update(fs.readFileSync(path.join(root,p))).digest('hex')}));
|
|
1205
|
+
fs.writeFileSync(path.join(root,'.flow-agents/codex-install-manifest.json'), JSON.stringify({schema_version:'1.0',files},null,2)+'\n');
|
|
1206
|
+
fs.appendFileSync(path.join(root,'skills' + '/user-legacy/SKILL.md'), 'kept modification\n');
|
|
1207
|
+
NODE
|
|
1208
|
+
if HOME="$GLOBAL_HOME" CODEX_REAL_HOME="$MIGRATE_CODEX" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$MIGRATE_CODEX" --skills-dir "$MIGRATE_SKILLS" >/dev/null 2>"$TMPDIR_EVAL/migrate.err" \
|
|
1209
|
+
&& [[ ! -e "$MIGRATE_CODEX/skills/plan-work/SKILL.md" ]] \
|
|
1210
|
+
&& rg -q 'kept modification' "$LEGACY_USER_DIR/SKILL.md" \
|
|
1211
|
+
&& [[ -f "$MIGRATE_SKILLS/plan-work/SKILL.md" ]]; then
|
|
1212
|
+
_pass "legacy migration removes unchanged owned skills and preserves modified legacy content"
|
|
1213
|
+
else
|
|
1214
|
+
_fail "legacy Flow Agents skill migration was destructive or incomplete"
|
|
1215
|
+
fi
|
|
1216
|
+
|
|
1113
1217
|
OPENCODE_AGENTS_DIR="$OPENCODE_FULL_DEST/.opencode/agents"
|
|
1114
1218
|
if [[ -f "$OPENCODE_AGENTS_DIR/tool-planner.md" && -f "$OPENCODE_AGENTS_DIR/dev.md" ]]; then
|
|
1115
1219
|
_pass "opencode full install ships the complete agent base"
|
|
@@ -164,7 +164,7 @@ OPENCODE_UPGRADE="$TMPDIR_EVAL/upgrade-opencode"
|
|
|
164
164
|
# Touch a marker into skill files in the COPIES (not dist/ originals)
|
|
165
165
|
UPGRADE_MARKER="# flow-agents-upgrade-test-marker"
|
|
166
166
|
CLAUDE_SKILL_FILE="$CLAUDE_BUNDLE_COPY/.claude/skills/plan-work/SKILL.md"
|
|
167
|
-
CODEX_SKILL_FILE="$CODEX_BUNDLE_COPY/.
|
|
167
|
+
CODEX_SKILL_FILE="$CODEX_BUNDLE_COPY/.agents/skills/plan-work/SKILL.md"
|
|
168
168
|
OPENCODE_SKILL_FILE="$OPENCODE_BUNDLE_COPY/.opencode/skills/plan-work/SKILL.md"
|
|
169
169
|
|
|
170
170
|
if [[ -f "$CLAUDE_SKILL_FILE" ]]; then
|
|
@@ -191,12 +191,10 @@ else
|
|
|
191
191
|
_fail "claude-code upgrade: skill change did not propagate to workspace"
|
|
192
192
|
fi
|
|
193
193
|
|
|
194
|
-
if [[ -f "$CODEX_SKILL_FILE" ]] && grep -qF "$UPGRADE_MARKER" "$CODEX_UPGRADE/.
|
|
194
|
+
if [[ -f "$CODEX_SKILL_FILE" ]] && grep -qF "$UPGRADE_MARKER" "$CODEX_UPGRADE/.agents/skills/plan-work/SKILL.md" 2>/dev/null; then
|
|
195
195
|
_pass "codex upgrade: modified skill file propagated to workspace"
|
|
196
|
-
elif [[ ! -f "$CODEX_SKILL_FILE" ]]; then
|
|
197
|
-
_pass "codex upgrade: skill file not in bundle (skipped)"
|
|
198
196
|
else
|
|
199
|
-
_fail "codex upgrade: skill change did not propagate
|
|
197
|
+
_fail "codex upgrade: required universal skill missing or change did not propagate"
|
|
200
198
|
fi
|
|
201
199
|
|
|
202
200
|
if [[ -f "$OPENCODE_SKILL_FILE" ]] && grep -qF "$UPGRADE_MARKER" "$OPENCODE_UPGRADE/.opencode/skills/plan-work/SKILL.md" 2>/dev/null; then
|
|
@@ -246,7 +244,7 @@ echo '{"custom":"data"}' > "$OPENCODE_USER/.kontourai/flow-agents/my-session/sta
|
|
|
246
244
|
|
|
247
245
|
# Modify an installed skill file to simulate user edits
|
|
248
246
|
CLAUDE_INSTALLED_SKILL="$CLAUDE_USER/.claude/skills/plan-work/SKILL.md"
|
|
249
|
-
CODEX_INSTALLED_SKILL="$CODEX_USER/.
|
|
247
|
+
CODEX_INSTALLED_SKILL="$CODEX_USER/.agents/skills/plan-work/SKILL.md"
|
|
250
248
|
OPENCODE_INSTALLED_SKILL="$OPENCODE_USER/.opencode/skills/plan-work/SKILL.md"
|
|
251
249
|
|
|
252
250
|
USER_EDIT_MARKER="# USER EDIT - should be overwritten by re-install"
|
|
@@ -22,6 +22,10 @@ set -euo pipefail
|
|
|
22
22
|
|
|
23
23
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
24
24
|
TMPDIR_EVAL="$(mktemp -d /tmp/install-merge.XXXXXX)"
|
|
25
|
+
export HOME="$TMPDIR_EVAL/hermetic-home"
|
|
26
|
+
export FLOW_AGENTS_SKILLS_DIR="$TMPDIR_EVAL/hermetic-universal/skills"
|
|
27
|
+
mkdir -p "$HOME/.agents" "$FLOW_AGENTS_SKILLS_DIR"
|
|
28
|
+
printf 'installer tests must not replace this file\n' > "$HOME/.agents/ambient-sentinel"
|
|
25
29
|
pass=0
|
|
26
30
|
fail=0
|
|
27
31
|
|
|
@@ -1138,7 +1142,8 @@ echo ""
|
|
|
1138
1142
|
echo "--- CH4: codex-home preserves user config, profiles, hooks, local kit state, and user skills ---"
|
|
1139
1143
|
|
|
1140
1144
|
CH4_DEST="$TMPDIR_EVAL/codex-home-ch4"
|
|
1141
|
-
|
|
1145
|
+
CH4_SKILLS="$TMPDIR_EVAL/codex-home-ch4-universal-skills"
|
|
1146
|
+
mkdir -p "$CH4_DEST/kits/local/repositories/user-kit" "$CH4_SKILLS/user-owned-skill" "$CH4_DEST/ag""ents"
|
|
1142
1147
|
|
|
1143
1148
|
CH4_GENERIC_DIRS=(agent-cards build context docs evals integrations packaging powers prompts schemas scripts kits)
|
|
1144
1149
|
for CH4_DIR in "${CH4_GENERIC_DIRS[@]}"; do
|
|
@@ -1197,14 +1202,14 @@ JSON
|
|
|
1197
1202
|
cat > "$CH4_DEST/kits/local/repositories/user-kit/kit.json" << 'JSON'
|
|
1198
1203
|
{"id":"user-kit","name":"User Kit"}
|
|
1199
1204
|
JSON
|
|
1200
|
-
cat > "$
|
|
1205
|
+
cat > "$CH4_SKILLS/user-owned-skill/SKILL.md" << 'EOF_SKILL'
|
|
1201
1206
|
# User Owned Skill
|
|
1202
1207
|
EOF_SKILL
|
|
1203
1208
|
cat > "$CH4_DEST/ag""ents/user-owned-agent.toml" << 'EOF_AGENT'
|
|
1204
1209
|
name = "user-owned-agent"
|
|
1205
1210
|
EOF_AGENT
|
|
1206
1211
|
|
|
1207
|
-
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1212
|
+
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" FLOW_AGENTS_SKILLS_DIR="$CH4_SKILLS" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1208
1213
|
|
|
1209
1214
|
if grep -q 'user-model' "$CH4_DEST/config.toml" \
|
|
1210
1215
|
&& grep -q 'user-profile-model' "$CH4_DEST/custom.config.toml" \
|
|
@@ -1243,10 +1248,10 @@ else
|
|
|
1243
1248
|
_fail "CH4: kits/local registry or repository was removed"
|
|
1244
1249
|
fi
|
|
1245
1250
|
|
|
1246
|
-
if [[ -f "$
|
|
1247
|
-
_pass "CH4: root, Builder Kit workflow, and user-owned skills coexist in
|
|
1251
|
+
if [[ -f "$CH4_SKILLS/search-first/SKILL.md" && -f "$CH4_SKILLS/plan-work/SKILL.md" && -f "$CH4_SKILLS/user-owned-skill/SKILL.md" ]]; then
|
|
1252
|
+
_pass "CH4: root, Builder Kit workflow, and user-owned skills coexist in universal Codex skills"
|
|
1248
1253
|
else
|
|
1249
|
-
_fail "CH4: root skill, Builder Kit workflow skill, or user-owned skill missing from
|
|
1254
|
+
_fail "CH4: root skill, Builder Kit workflow skill, or user-owned skill missing from universal Codex skills"
|
|
1250
1255
|
fi
|
|
1251
1256
|
|
|
1252
1257
|
if [[ -f "$CH4_DEST/scripts/install-merge.js" && -f "$CH4_DEST/build/src/cli/kit.js" && -f "$CH4_DEST/ag""ents/tool-worker.toml" && -f "$CH4_DEST/ag""ents/user-owned-agent.toml" && -f "$CH4_DEST/hooks.json" ]] \
|
|
@@ -1272,7 +1277,7 @@ else
|
|
|
1272
1277
|
_fail "CH4: installed scripts/kit.js could not run with installed build bundle"
|
|
1273
1278
|
fi
|
|
1274
1279
|
|
|
1275
|
-
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1280
|
+
CODEX_REAL_HOME="$TMPDIR_EVAL/fake-real-codex" FLOW_AGENTS_SKILLS_DIR="$CH4_SKILLS" bash "$ROOT_DIR/scripts/install-codex-home.sh" "$CH4_DEST" >/dev/null 2>&1
|
|
1276
1281
|
CH4_GENERIC_PRESERVED=1
|
|
1277
1282
|
for CH4_DIR in "${CH4_GENERIC_DIRS[@]}"; do
|
|
1278
1283
|
[[ "$(cat "$CH4_DEST/$CH4_DIR/user-owned.txt" 2>/dev/null)" == "user-owned-$CH4_DIR" ]] || CH4_GENERIC_PRESERVED=0
|
|
@@ -1288,7 +1293,7 @@ echo ""
|
|
|
1288
1293
|
# ─── codex-home: CH5: destination symlink containment ───────────────────────
|
|
1289
1294
|
echo "--- CH5: codex-home refuses managed destination symlinks ---"
|
|
1290
1295
|
|
|
1291
|
-
for CH5_REL in scripts kits
|
|
1296
|
+
for CH5_REL in scripts kits hooks.json; do
|
|
1292
1297
|
CH5_DEST="$TMPDIR_EVAL/codex-home-ch5-${CH5_REL//\//-}"
|
|
1293
1298
|
CH5_OUTSIDE="$TMPDIR_EVAL/codex-home-ch5-outside-${CH5_REL//\//-}"
|
|
1294
1299
|
mkdir -p "$CH5_DEST" "$CH5_OUTSIDE"
|
|
@@ -1680,6 +1685,11 @@ echo ""
|
|
|
1680
1685
|
|
|
1681
1686
|
echo ""
|
|
1682
1687
|
echo "==========================="
|
|
1688
|
+
if [[ "$(cat "$HOME/.agents/ambient-sentinel" 2>/dev/null)" == "installer tests must not replace this file" ]]; then
|
|
1689
|
+
_pass "dedicated Codex installer calls remain inside hermetic universal roots"
|
|
1690
|
+
else
|
|
1691
|
+
_fail "dedicated Codex installer calls mutated the isolated default-home sentinel"
|
|
1692
|
+
fi
|
|
1683
1693
|
total=$((pass + fail))
|
|
1684
1694
|
echo "Results: ${pass}/${total} passed, ${fail} failed"
|
|
1685
1695
|
[[ "$fail" -gt 0 ]] && exit 1
|
|
@@ -160,15 +160,21 @@ pass "status is canonical and byte-read-only"
|
|
|
160
160
|
|
|
161
161
|
FLOW_MANIFEST="$CONSUMER/.kontourai/flow/runs/acme-widgets-101/evidence/manifest.json"
|
|
162
162
|
BEFORE_EVIDENCE="$(node -p "JSON.parse(require('fs').readFileSync('$FLOW_MANIFEST')).evidence.length")"
|
|
163
|
-
run_candidate evidence --session-dir "$RELEASE_SESSION" --expectation pickup-probe-readiness --status not_verified --summary "Consumer fixture intentionally leaves this claim unverified." --json
|
|
163
|
+
PARTIAL_EVIDENCE="$(run_candidate evidence --session-dir "$RELEASE_SESSION" --expectation pickup-probe-readiness --status not_verified --summary "Consumer fixture intentionally leaves this claim unverified." --json)"
|
|
164
164
|
AFTER_EVIDENCE="$(node -p "JSON.parse(require('fs').readFileSync('$FLOW_MANIFEST')).evidence.length")"
|
|
165
|
-
[[ "$AFTER_EVIDENCE" -eq $
|
|
166
|
-
|
|
165
|
+
[[ "$AFTER_EVIDENCE" -eq "$BEFORE_EVIDENCE" ]] || fail "partial evidence changed the canonical manifest"
|
|
166
|
+
node -e 'const r=JSON.parse(process.argv[1]);if(r.attached!==false||r.awaiting_evidence!==true||r.current_step!=="design-probe")process.exit(1)' "$PARTIAL_EVIDENCE" || fail "partial evidence did not report an explicit awaiting-evidence result"
|
|
167
|
+
pass "partial evidence records locally without evaluation or canonical attachment"
|
|
167
168
|
|
|
168
169
|
PULL_REPORT="$RELEASE_SESSION/$(basename "$RELEASE_SESSION")--pull-work.md"
|
|
169
170
|
PULL_REPORT_REF="{\"kind\":\"artifact\",\"file\":\"$PULL_REPORT\",\"summary\":\"Concrete selected-work and probe report.\"}"
|
|
170
|
-
run_candidate evidence --session-dir "$RELEASE_SESSION" --expectation pickup-probe-readiness --status pass --summary "Complete the consumer readiness expectation after exercising NOT_VERIFIED." --evidence-ref-json "$PULL_REPORT_REF" --json
|
|
171
|
-
|
|
171
|
+
READINESS_PARTIAL="$(run_candidate evidence --session-dir "$RELEASE_SESSION" --expectation pickup-probe-readiness --status pass --summary "Complete the consumer readiness expectation after exercising NOT_VERIFIED." --evidence-ref-json "$PULL_REPORT_REF" --json)"
|
|
172
|
+
node -e 'const r=JSON.parse(process.argv[1]);if(r.attached!==false||r.awaiting_evidence!==true||r.current_step!=="design-probe")process.exit(1)' "$READINESS_PARTIAL" || fail "first passing member of a multi-expectation gate did not remain pending"
|
|
173
|
+
PROBE_COMPLETE="$(run_candidate evidence --session-dir "$RELEASE_SESSION" --expectation probe-decisions-or-accepted-gaps --status pass --summary "Complete the consumer probe gate." --evidence-ref-json "$PULL_REPORT_REF" --json)"
|
|
174
|
+
node -e 'const r=JSON.parse(process.argv[1]);if(r.attached!==true||r.awaiting_evidence!==false||r.current_step!=="plan")process.exit(1)' "$PROBE_COMPLETE" || fail "complete multi-expectation gate did not attach and advance exactly once"
|
|
175
|
+
AFTER_COMPLETE_EVIDENCE="$(node -p "JSON.parse(require('fs').readFileSync('$FLOW_MANIFEST')).evidence.length")"
|
|
176
|
+
[[ "$AFTER_COMPLETE_EVIDENCE" -eq $((BEFORE_EVIDENCE + 1)) ]] || fail "complete multi-expectation gate did not attach exactly once"
|
|
177
|
+
pass "multi-expectation evidence attaches atomically only when complete"
|
|
172
178
|
seed_pull_work acme/widgets#104
|
|
173
179
|
run_candidate_as poison-pointer start --artifact-root "$ARTIFACT_ROOT" --flow builder.build --work-item acme/widgets#104 --assignment-provider local-file --summary "Poison global pointer fixture" >/dev/null
|
|
174
180
|
node - "$ARTIFACT_ROOT" "$(basename "$RELEASE_SESSION")" <<'NODE'
|
|
@@ -10,7 +10,7 @@ pass=0
|
|
|
10
10
|
fail=0
|
|
11
11
|
|
|
12
12
|
cleanup() {
|
|
13
|
-
rm -rf "$REPRO_FIRST_DIR" "$REPRO_SECOND_DIR" "$ROOT_DIR/kits/zzz-collision-eval-probe"
|
|
13
|
+
rm -rf "$REPRO_FIRST_DIR" "$REPRO_SECOND_DIR" "$ROOT_DIR/kits/zzz-collision-eval-probe" "${MISSING_SKILL_DIR:-}"
|
|
14
14
|
}
|
|
15
15
|
trap cleanup EXIT
|
|
16
16
|
|
|
@@ -65,6 +65,49 @@ for dir in "$DIST_DIR/kiro" "$DIST_DIR/claude-code" "$DIST_DIR/codex" "$DIST_DIR
|
|
|
65
65
|
fi
|
|
66
66
|
done
|
|
67
67
|
|
|
68
|
+
if [[ -d "$DIST_DIR/codex/.agents/skills/plan-work" && ! -e "$DIST_DIR/codex/.codex/skills" ]]; then
|
|
69
|
+
_pass "Codex exports portable skills only in the universal .agents catalog"
|
|
70
|
+
else
|
|
71
|
+
_fail "Codex portable skills are not rooted exclusively at .agents/skills"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
if node - "$DIST_DIR/codex/.agents/skills" <<'NODE'
|
|
75
|
+
const fs = require("node:fs");
|
|
76
|
+
const path = require("node:path");
|
|
77
|
+
const root = process.argv[2];
|
|
78
|
+
const pattern = /(?:^|[`("'\s])(context\/contracts\/[A-Za-z0-9._/-]+\.md)(?=$|[`),"'\s])/gm;
|
|
79
|
+
for (const name of fs.readdirSync(root)) {
|
|
80
|
+
const skill = path.join(root, name);
|
|
81
|
+
const file = path.join(skill, "SKILL.md");
|
|
82
|
+
if (!fs.existsSync(file)) continue;
|
|
83
|
+
for (const match of fs.readFileSync(file, "utf8").matchAll(pattern)) {
|
|
84
|
+
const resolved = path.resolve(skill, match[1]);
|
|
85
|
+
if (!resolved.startsWith(`${path.resolve(skill)}${path.sep}`) || !fs.existsSync(resolved)) throw new Error(`${name}: ${match[1]}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
NODE
|
|
89
|
+
then
|
|
90
|
+
_pass "Codex skill-local instruction resources resolve inside each package"
|
|
91
|
+
else
|
|
92
|
+
_fail "Codex skill-local instruction resource closure failed"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
MISSING_SKILL_DIR="$ROOT_DIR/${SKILLS_SEGMENT:-skills}/zzz-missing-resource-probe"
|
|
96
|
+
MISSING_CONTRACT="${CONTEXT_SEGMENT:-context}/contracts/definitely-missing.md"
|
|
97
|
+
mkdir -p "$MISSING_SKILL_DIR"
|
|
98
|
+
printf '%s\n' '# Probe' '' "Read \`$MISSING_CONTRACT\`." > "$MISSING_SKILL_DIR/SKILL.md"
|
|
99
|
+
if (cd "$ROOT_DIR" && npm run build:bundles >/tmp/missing-skill-resource.stdout 2>/tmp/missing-skill-resource.stderr); then
|
|
100
|
+
_fail "bundle generation accepted a missing skill instruction resource"
|
|
101
|
+
else
|
|
102
|
+
if rg -q "skill 'zzz-missing-resource-probe': missing local resource '$MISSING_CONTRACT'" /tmp/missing-skill-resource.stderr; then
|
|
103
|
+
_pass "bundle generation rejects missing skill resources with actionable diagnostics"
|
|
104
|
+
else
|
|
105
|
+
_fail "missing skill resource failure did not name its skill and path"
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
rm -rf "$MISSING_SKILL_DIR"
|
|
109
|
+
(cd "$ROOT_DIR" && npm run build:bundles >/dev/null)
|
|
110
|
+
|
|
68
111
|
source_agents=$(find "$ROOT_DIR/agents" -maxdepth 1 -name '*.json' | wc -l | tr -d ' ')
|
|
69
112
|
codex_excluded_agents=$(node - "$ROOT_DIR/packaging/manifest.json" <<'NODE'
|
|
70
113
|
const fs = require("node:fs");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kontourai/flow-agents",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "Flow Agents — a Kontour product that applies Flow and Veritas discipline as a portable process layer inside the agent tools you already use: Claude Code, Codex, Kiro, opencode, pi, and GitHub Actions — with framework adapters (AWS Strands preview) on the same policy-engine contract.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -144,9 +144,9 @@
|
|
|
144
144
|
"kit": "npm run build --silent && node build/src/cli.js kit"
|
|
145
145
|
},
|
|
146
146
|
"devDependencies": {
|
|
147
|
-
"@types/node": "^26.1.
|
|
148
|
-
"promptfoo": "^0.121.
|
|
149
|
-
"typescript": "^
|
|
147
|
+
"@types/node": "^26.1.1",
|
|
148
|
+
"promptfoo": "^0.121.18",
|
|
149
|
+
"typescript": "^7.0.2"
|
|
150
150
|
},
|
|
151
151
|
"dependencies": {
|
|
152
152
|
"@kontourai/flow": "^3.1.4"
|
package/packaging/README.md
CHANGED
|
@@ -19,7 +19,7 @@ For the full source/generated/runtime inventory, see [Repository Structure](../d
|
|
|
19
19
|
|
|
20
20
|
- `dist/kiro/` keeps native Kiro JSON agents and rewrites path-bound config through the install token.
|
|
21
21
|
- `dist/claude-code/` exports `.claude/agents/*.md` and `.claude/skills/*/SKILL.md`.
|
|
22
|
-
- `dist/codex/` exports
|
|
22
|
+
- `dist/codex/` exports Codex-only agents and profiles beneath `.codex/`, and portable, self-contained skills beneath the universal `.agents/skills/` catalog.
|
|
23
23
|
|
|
24
24
|
All targets also receive shared canonical directories where supported: `context/`, `powers/`, `prompts/`, `scripts/`, and `evals/`.
|
|
25
25
|
|
package/scripts/README.md
CHANGED
|
@@ -113,7 +113,7 @@ prompting. Add `--allow-network` to probe a non-local HTTPS Console endpoint.
|
|
|
113
113
|
|
|
114
114
|
## Install And Repo Utilities
|
|
115
115
|
|
|
116
|
-
- `install-codex-home.sh`: installs
|
|
116
|
+
- `install-codex-home.sh`: installs Codex runtime assets into `CODEX_HOME` (or `~/.codex`) and portable skills into `$HOME/.agents/skills`. Use `--skills-dir PATH` or `FLOW_AGENTS_SKILLS_DIR` to select a hermetic or advanced-user skill catalog independently of the positional runtime destination. The installer reports both resolved roots, preserves user-owned files, migrates only unchanged Flow Agents-owned legacy skills, and refuses symlink destinations rather than creating a compatibility symlink.
|
|
117
117
|
- `setup-repo-hooks.sh`: configures this clone's Git hook path.
|
|
118
118
|
- `check-content-boundary.cjs`, `detect-tools.sh`, `discover-agents.sh`, `git-status.sh`: repo-local helper commands.
|
|
119
119
|
- `context-budget/` and `statusline/`: specialized support tooling copied into bundles where needed.
|