@kontourai/flow-agents 3.8.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +8 -0
- package/CHANGELOG.md +24 -0
- package/README.md +1 -1
- package/build/src/builder-flow-runtime.js +16 -10
- package/build/src/cli/assignment-provider.js +4 -18
- package/build/src/cli/continuation-adapter.d.ts +26 -0
- package/build/src/cli/continuation-adapter.js +243 -0
- package/build/src/cli/validate-workflow-artifacts.js +21 -1
- package/build/src/cli/workflow-sidecar.js +15 -20
- package/build/src/cli/workflow.js +99 -6
- package/build/src/continuation-driver.d.ts +116 -0
- package/build/src/continuation-driver.js +527 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/tools/build-universal-bundles.js +52 -25
- package/build/src/tools/validate-source-tree.js +5 -2
- package/context/scripts/hooks/lib/continuation-turn-authority.js +386 -0
- package/context/scripts/hooks/stop-goal-fit.js +244 -73
- package/context/scripts/hooks/workflow-steering.js +24 -15
- package/context/scripts/telemetry/lib/pricing.sh +18 -6
- package/context/scripts/telemetry/lib/transport.sh +139 -37
- package/context/scripts/telemetry/lib/usage.sh +282 -32
- package/context/scripts/telemetry/lib/usage_model_guard.sh +42 -0
- package/context/scripts/telemetry/telemetry.sh +76 -1
- package/docs/coordination-guide.md +21 -5
- package/docs/fixture-ownership.md +2 -1
- package/docs/public-workflow-cli.md +98 -0
- package/docs/spec/runtime-hook-surface.md +8 -4
- package/docs/workflow-usage-guide.md +7 -0
- package/evals/acceptance/prove-capture-teeth-declared.sh +13 -0
- package/evals/acceptance/prove-capture-teeth.sh +13 -0
- package/evals/ci/run-baseline.sh +2 -0
- package/evals/fixtures/codex-legacy-agents/5273878130bdafc8a024a650bb5b66c9b003f1f859b5dc6e5b588cbf4ab23228.md +25 -0
- package/evals/fixtures/telemetry/usage-transcript-adversarial.jsonl +2 -0
- package/evals/fixtures/telemetry/usage-transcript-malformed-sandwich.jsonl +3 -0
- package/evals/fixtures/telemetry/usage-transcript-negative-tokens.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-oversized-prefix.jsonl +201 -0
- package/evals/fixtures/telemetry/usage-transcript-oversized-tokens.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-prefixed-secret-lower.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-prefixed-secret-upper.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-secret-model-jwt.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-secret-model.jsonl +1 -0
- package/evals/fixtures/telemetry/usage-transcript-torn-trailing.jsonl +2 -0
- package/evals/integration/test_actor_identity.sh +63 -0
- package/evals/integration/test_assignment_provider_local_file.sh +34 -0
- package/evals/integration/test_builder_entry_enforcement.sh +5 -1
- package/evals/integration/test_bundle_install.sh +106 -17
- package/evals/integration/test_bundle_lifecycle.sh +17 -3
- package/evals/integration/test_captured_fail_reconciliation.sh +11 -0
- package/evals/integration/test_ci_actor_identity.sh +2 -2
- package/evals/integration/test_command_log_concurrency.sh +11 -0
- package/evals/integration/test_command_log_fork_classification.sh +11 -0
- package/evals/integration/test_command_log_integrity.sh +11 -0
- package/evals/integration/test_current_json_per_actor.sh +416 -21
- package/evals/integration/test_enforcer_expects_driven.sh +11 -0
- package/evals/integration/test_ensure_session_ownership_guard.sh +39 -0
- package/evals/integration/test_evidence_capture_hook.sh +25 -6
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flowdef_union_floor_regression.sh +11 -0
- package/evals/integration/test_gate_bypass_chain.sh +11 -0
- package/evals/integration/test_gate_lockdown.sh +10 -0
- package/evals/integration/test_goal_fit_ghost_session.sh +11 -0
- package/evals/integration/test_goal_fit_hook.sh +257 -9
- package/evals/integration/test_goal_fit_rederive.sh +11 -0
- package/evals/integration/test_install_merge.sh +141 -3
- package/evals/integration/test_liveness_conflict_injection.sh +39 -3
- package/evals/integration/test_liveness_heartbeat.sh +46 -9
- package/evals/integration/test_phase_map_and_gate_claim.sh +10 -1
- package/evals/integration/test_public_workflow_cli.sh +6 -6
- package/evals/integration/test_session_resume_roundtrip.sh +30 -0
- package/evals/integration/test_stop_hook_release.sh +111 -11
- package/evals/integration/test_telemetry_tool_usage.sh +394 -0
- package/evals/integration/test_verify_hold.sh +64 -1
- package/evals/integration/test_workflow_sidecar_writer.sh +10 -1
- package/evals/integration/test_workflow_steering_hook.sh +20 -4
- package/evals/run.sh +2 -0
- package/evals/static/test_universal_bundles.sh +123 -0
- package/package.json +4 -4
- package/packaging/README.md +21 -0
- package/packaging/codex-legacy-agents-fingerprints.json +33 -0
- package/scripts/README.md +2 -1
- package/scripts/audit-codex-legacy-agents.js +43 -0
- package/scripts/classify-codex-legacy-agents.js +71 -0
- package/scripts/hooks/evidence-capture.js +18 -6
- package/scripts/hooks/lib/actor-identity.js +62 -29
- package/scripts/hooks/lib/continuation-turn-authority.js +386 -0
- package/scripts/hooks/lib/current-pointer.js +114 -12
- package/scripts/hooks/lib/liveness-heartbeat.js +15 -12
- package/scripts/hooks/stop-goal-fit.js +244 -73
- package/scripts/hooks/workflow-steering.js +24 -15
- package/scripts/install-codex-home.sh +8 -7
- package/scripts/telemetry/lib/pricing.sh +18 -6
- package/scripts/telemetry/lib/transport.sh +71 -0
- package/scripts/telemetry/lib/usage.sh +282 -32
- package/scripts/telemetry/lib/usage_model_guard.sh +42 -0
- package/scripts/telemetry/telemetry.sh +76 -1
- package/src/builder-flow-runtime.ts +9 -3
- package/src/cli/assignment-provider.ts +5 -26
- package/src/cli/builder-flow-runtime.test.mjs +215 -2
- package/src/cli/continuation-adapter.ts +265 -0
- package/src/cli/continuation-driver.test.mjs +1303 -0
- package/src/cli/public-api.test.mjs +1 -0
- package/src/cli/validate-workflow-artifacts.ts +19 -1
- package/src/cli/workflow-sidecar.ts +18 -23
- package/src/cli/workflow.ts +113 -6
- package/src/continuation-driver.ts +638 -0
- package/src/index.ts +24 -0
- package/src/tools/build-universal-bundles.ts +61 -25
- package/src/tools/validate-source-tree.ts +5 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "assistant", "message": {"model": "claude-opus-4-8", "usage": {"input_tokens": 1e+308, "output_tokens": 20, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"assistant","message":{"model":"claude-abcdefghijklmnopqrstuvwxyz0","usage":{"input_tokens":13,"output_tokens":26,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"assistant","message":{"model":"claude-UPPERCASE-REJECTED","usage":{"input_tokens":11,"output_tokens":22,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "assistant", "message": {"model": "not-a-real-jwt.payload-user-at-example-com.sig", "usage": {"input_tokens": 30, "output_tokens": 9, "cache_creation_input_tokens": 1, "cache_read_input_tokens": 2}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "assistant", "message": {"model": "sk-ant-api03-abcDEF123456789_secretlookingkey-XYZ", "usage": {"input_tokens": 42, "output_tokens": 17, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0}}}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
{"type": "assistant", "message": {"model": "claude-torn-trailing-safe", "usage": {"input_tokens": 15, "output_tokens": 25, "cache_creation_input_tokens": 1, "cache_read_input_tokens": 2}}}
|
|
2
|
+
{"type":"assistant","message":{"model":"claude-torn-victim","usage":{"input_tokens":999,"output_tok
|
|
@@ -245,6 +245,69 @@ else
|
|
|
245
245
|
_fail "resolveActor did not honor a deliberate literal FLOW_AGENTS_ACTOR=unknown override"
|
|
246
246
|
fi
|
|
247
247
|
|
|
248
|
+
# 11 (#554). CODEX_THREAD_ID is the preferred native Codex signal. Its raw value must never
|
|
249
|
+
# become durable actor text: it is transformed into a stable, domain-separated 96-bit token.
|
|
250
|
+
if node - "$MODULE" <<'NODE'
|
|
251
|
+
const path = process.argv[2];
|
|
252
|
+
const { detectRuntime, runtimeSessionId, resolveActor, resolveActorIdentity, serializeActor } = require(path);
|
|
253
|
+
const rawA = "thread:private/value\nwith-control";
|
|
254
|
+
const rawB = "thread:other-private-value";
|
|
255
|
+
const envA = { CODEX_THREAD_ID: rawA, CODEX_SESSION_ID: "legacy-must-lose" };
|
|
256
|
+
if (detectRuntime(envA) !== "codex") throw new Error("CODEX_THREAD_ID did not detect codex");
|
|
257
|
+
if (runtimeSessionId(envA) !== rawA) throw new Error("CODEX_THREAD_ID did not win ordered priority");
|
|
258
|
+
if (runtimeSessionId({ CODEX_SESSION_ID: "legacy-ok" }) !== "legacy-ok") throw new Error("legacy CODEX_SESSION_ID stopped working");
|
|
259
|
+
const first = resolveActor(envA);
|
|
260
|
+
const repeat = resolveActor(envA);
|
|
261
|
+
const distinct = resolveActor({ CODEX_THREAD_ID: rawB });
|
|
262
|
+
const identity = resolveActorIdentity(envA);
|
|
263
|
+
if (JSON.stringify(first) !== JSON.stringify(repeat)) throw new Error("same thread was unstable");
|
|
264
|
+
if (first.actor === distinct.actor) throw new Error("distinct threads collided");
|
|
265
|
+
if (first.source !== "runtime-session-id:codex") throw new Error(`wrong source: ${JSON.stringify(first)}`);
|
|
266
|
+
if (!identity.actorStruct || identity.actor !== serializeActor(identity.actorStruct)) throw new Error("canonical actor struct/key diverged");
|
|
267
|
+
if (identity.actorStruct.session_id.includes("private")) throw new Error("raw id leaked through canonical actor struct");
|
|
268
|
+
if (!/^codex:thread-[a-f0-9]{24}:[A-Za-z0-9_.-]+$/.test(first.actor)) throw new Error(`unsafe actor shape: ${JSON.stringify(first)}`);
|
|
269
|
+
if (first.actor.includes(rawA) || first.actor.includes("private") || first.actor.includes("legacy-must-lose")) throw new Error("raw native id leaked");
|
|
270
|
+
NODE
|
|
271
|
+
then
|
|
272
|
+
_pass "CODEX_THREAD_ID yields a stable, distinct, privacy-safe Codex actor and wins over the legacy signal"
|
|
273
|
+
else
|
|
274
|
+
_fail "CODEX_THREAD_ID native identity contract failed"
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
# 12 (#554). Ancestry is explicitly classified in its display string but remains unstable by source.
|
|
278
|
+
if node - "$MODULE" <<'NODE'
|
|
279
|
+
const path = process.argv[2];
|
|
280
|
+
const { resolveActorIdentity, serializeActor } = require(path);
|
|
281
|
+
const out = resolveActorIdentity({});
|
|
282
|
+
if (!out || out.source !== "process-ancestry") throw new Error(`wrong fallback source: ${JSON.stringify(out)}`);
|
|
283
|
+
if (!out.actor.startsWith("process-ancestry:anc-")) throw new Error(`fallback remains misleading: ${JSON.stringify(out)}`);
|
|
284
|
+
if (out.actor.startsWith("unknown:anc-")) throw new Error(`legacy fallback still emitted: ${JSON.stringify(out)}`);
|
|
285
|
+
if (!out.actorStruct || out.actorStruct.runtime !== "process-ancestry" || out.actor !== serializeActor(out.actorStruct)) throw new Error(`fallback struct/key diverged: ${JSON.stringify(out)}`);
|
|
286
|
+
NODE
|
|
287
|
+
then
|
|
288
|
+
_pass "ancestry fallback is explicitly labeled process-ancestry without changing its source classification"
|
|
289
|
+
else
|
|
290
|
+
_fail "ancestry fallback label/source contract failed"
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# 13 (#554). Historical actor values remain opaque and readable; no alias/schema rewrite is needed.
|
|
294
|
+
if node - "$ROOT/scripts/hooks/lib/liveness-read.js" <<'NODE'
|
|
295
|
+
const { freshHolders } = require(process.argv[2]);
|
|
296
|
+
const legacy = "unknown:anc-eabf4cb9ef38:old-host";
|
|
297
|
+
const at = "2026-07-11T12:00:00.000Z";
|
|
298
|
+
const events = [{ type: "claim", subjectId: "legacy-work", actor: legacy, at, ttlSeconds: 1800 }];
|
|
299
|
+
const foreign = freshHolders(events, "legacy-work", "new-self", Date.parse(at) + 1000);
|
|
300
|
+
const self = freshHolders(events, "legacy-work", legacy, Date.parse(at) + 1000);
|
|
301
|
+
if (foreign.length !== 1 || foreign[0].actor !== legacy) throw new Error(`legacy record unreadable: ${JSON.stringify(foreign)}`);
|
|
302
|
+
if (self.length !== 0) throw new Error(`legacy self-filter failed: ${JSON.stringify(self)}`);
|
|
303
|
+
if (events[0].actor !== legacy || Object.prototype.hasOwnProperty.call(events[0], "actor_key")) throw new Error("legacy record was mutated");
|
|
304
|
+
NODE
|
|
305
|
+
then
|
|
306
|
+
_pass "legacy unknown:anc-* records remain readable, self-filterable, and unmodified"
|
|
307
|
+
else
|
|
308
|
+
_fail "legacy unknown:anc-* compatibility failed"
|
|
309
|
+
fi
|
|
310
|
+
|
|
248
311
|
if [[ "$errors" -eq 0 ]]; then
|
|
249
312
|
echo "Actor identity resolver integration passed."
|
|
250
313
|
exit 0
|
|
@@ -268,6 +268,40 @@ fi
|
|
|
268
268
|
[[ "$(json_query "$TMPDIR_EVAL/status-race.json" "assignment.assignee")" == "$EXPECTED_RACE_HOLDER" ]] && pass "on-disk record holder matches the process that actually exited 0 (no silent overwrite by the loser)" || fail "on-disk record holder matches the process that actually exited 0 (no silent overwrite by the loser)"
|
|
269
269
|
|
|
270
270
|
echo ""
|
|
271
|
+
|
|
272
|
+
# 8. #554: auto-derived Codex identity persists only the canonical privacy-safe struct/key.
|
|
273
|
+
CODEX_ROOT="$TMPDIR_EVAL/codex-artifact-root"
|
|
274
|
+
CODEX_SUBJECT="codex-private-identity"
|
|
275
|
+
CODEX_RAW='PRIVATE-SENTINEL:thread/value-with-punctuation'
|
|
276
|
+
CODEX_THREAD_ID="$CODEX_RAW" CODEX_SESSION_ID= node "$CLI" assignment-provider claim \
|
|
277
|
+
--provider local-file --artifact-root "$CODEX_ROOT" --subject-id "$CODEX_SUBJECT" \
|
|
278
|
+
--branch agent/codex-private --artifact-dir .kontourai/flow-agents/codex-private \
|
|
279
|
+
>"$TMPDIR_EVAL/codex-claim.json" 2>"$TMPDIR_EVAL/codex-claim.err"
|
|
280
|
+
CODEX_RECORD="$CODEX_ROOT/assignment/$CODEX_SUBJECT.json"
|
|
281
|
+
if node - "$CODEX_RECORD" "$ROOT/scripts/hooks/lib/actor-identity.js" <<'NODE'
|
|
282
|
+
const fs = require('fs');
|
|
283
|
+
const record = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
284
|
+
const { serializeActor } = require(process.argv[3]);
|
|
285
|
+
if (record.actor.runtime !== 'codex') throw new Error('wrong runtime');
|
|
286
|
+
if (!/^thread-[a-f0-9]{24}$/.test(record.actor.session_id)) throw new Error('unsafe session token');
|
|
287
|
+
if (record.actor_key !== serializeActor(record.actor)) throw new Error('actor_key differs from stored actor');
|
|
288
|
+
NODE
|
|
289
|
+
then pass "Codex assignment record stores one canonical privacy-safe struct/key"
|
|
290
|
+
else fail "Codex assignment record did not store the canonical privacy-safe struct/key"
|
|
291
|
+
fi
|
|
292
|
+
if rg -qF 'PRIVATE-SENTINEL' "$CODEX_ROOT" "$TMPDIR_EVAL/codex-claim.json" "$TMPDIR_EVAL/codex-claim.err"; then
|
|
293
|
+
fail "raw CODEX_THREAD_ID sentinel leaked into assignment artifacts or command output"
|
|
294
|
+
else
|
|
295
|
+
pass "raw CODEX_THREAD_ID sentinel is absent from the complete assignment artifact/output set"
|
|
296
|
+
fi
|
|
297
|
+
CODEX_KEY="$(json_query "$CODEX_RECORD" "actor_key")"
|
|
298
|
+
CODEX_THREAD_ID="$CODEX_RAW" CODEX_SESSION_ID= node "$CLI" assignment-provider status \
|
|
299
|
+
--provider local-file --artifact-root "$CODEX_ROOT" --subject-id "$CODEX_SUBJECT" \
|
|
300
|
+
--liveness-events-json <(echo '[]') --self-actor "$CODEX_KEY" >"$TMPDIR_EVAL/codex-status.json"
|
|
301
|
+
[[ "$(json_query "$TMPDIR_EVAL/codex-status.json" "effective.reason")" == "self_is_holder" ]] \
|
|
302
|
+
&& pass "subsequent assignment status recognizes the canonical Codex actor as self" \
|
|
303
|
+
|| fail "subsequent assignment status did not recognize the canonical Codex actor as self"
|
|
304
|
+
|
|
271
305
|
if [[ "$errors" -eq 0 ]]; then
|
|
272
306
|
echo "test_assignment_provider_local_file: all checks passed."
|
|
273
307
|
else
|
|
@@ -478,7 +478,11 @@ else
|
|
|
478
478
|
fail "preexisting assignment was treated as current selection evidence: $(cat "$TMP/preexisting.out")"
|
|
479
479
|
fi
|
|
480
480
|
|
|
481
|
-
|
|
481
|
+
# #440 FIXTURE-GAP: $TMP/local's session was established under FLOW_AGENTS_ACTOR=builder-entry-local
|
|
482
|
+
# (see the "workflow start" call above) -- the Stop hook must run as that SAME actor so
|
|
483
|
+
# stop-goal-fit.js's ownership-scoped analyze() finds builder-entry-local's own per-actor pointer
|
|
484
|
+
# (established by workflow start's dual-write), not nothing for an unrelated ambient actor.
|
|
485
|
+
if FLOW_AGENTS_ACTOR=builder-entry-local FLOW_AGENTS_GOAL_FIT_MODE=block FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000 \
|
|
482
486
|
node "$ROOT/scripts/hooks/stop-goal-fit.js" >"$TMP/stop.out" 2>"$TMP/stop.err" <<JSON
|
|
483
487
|
{"hook_event_name":"Stop","cwd":"$TMP/local"}
|
|
484
488
|
JSON
|
|
@@ -44,35 +44,94 @@ OPENCODE_DEST="$TMPDIR_EVAL/opencode-workspace"
|
|
|
44
44
|
OPENCODE_CONSOLE_DEST="$TMPDIR_EVAL/opencode-console-workspace"
|
|
45
45
|
OPENCODE_FULL_DEST="$TMPDIR_EVAL/opencode-full-workspace"
|
|
46
46
|
PI_DEST="$TMPDIR_EVAL/pi-workspace"
|
|
47
|
+
INSTRUCTION_FIXTURES="$TMPDIR_EVAL/instruction-fixtures"
|
|
47
48
|
CONSOLE_TOKEN_FILE="$TMPDIR_EVAL/console-token"
|
|
48
49
|
printf 'test-token\n' > "$CONSOLE_TOKEN_FILE"
|
|
49
50
|
chmod 600 "$CONSOLE_TOKEN_FILE" 2>/dev/null || true
|
|
50
51
|
|
|
52
|
+
instruction_fixture_key() {
|
|
53
|
+
printf '%s' "$1" | shasum -a 256 | awk '{print $1}'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
instruction_file_identity() {
|
|
57
|
+
local file="$1"
|
|
58
|
+
printf '%s %s\n' "$(wc -c < "$file" | tr -d ' ')" "$(shasum -a 256 "$file" | awk '{print $1}')"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
seed_instruction_fixture() {
|
|
62
|
+
local dest="$1"
|
|
63
|
+
local label="$2"
|
|
64
|
+
local key
|
|
65
|
+
key="$(instruction_fixture_key "$dest")"
|
|
66
|
+
mkdir -p "$dest" "$INSTRUCTION_FIXTURES"
|
|
67
|
+
printf '# Repository AGENTS instructions\nfixture=%s\nkind=agents\nliteral=__KIRO_PACKAGE_ROOT__\n' "$label" > "$dest/AGENTS.md"
|
|
68
|
+
printf '# Repository CLAUDE instructions\nfixture=%s\nkind=claude\nliteral=__KIRO_PACKAGE_ROOT__\n' "$label" > "$dest/CLAUDE.md"
|
|
69
|
+
instruction_file_identity "$dest/AGENTS.md" > "$INSTRUCTION_FIXTURES/$key.AGENTS.md.identity"
|
|
70
|
+
instruction_file_identity "$dest/CLAUDE.md" > "$INSTRUCTION_FIXTURES/$key.CLAUDE.md.identity"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
assert_instruction_fixture_preserved() {
|
|
74
|
+
local dest="$1"
|
|
75
|
+
local label="$2"
|
|
76
|
+
local key filename expected actual
|
|
77
|
+
key="$(instruction_fixture_key "$dest")"
|
|
78
|
+
for filename in AGENTS.md CLAUDE.md; do
|
|
79
|
+
expected="$(cat "$INSTRUCTION_FIXTURES/$key.$filename.identity")"
|
|
80
|
+
if [[ -f "$dest/$filename" ]]; then
|
|
81
|
+
actual="$(instruction_file_identity "$dest/$filename")"
|
|
82
|
+
else
|
|
83
|
+
actual="missing"
|
|
84
|
+
fi
|
|
85
|
+
if [[ "$actual" == "$expected" ]]; then
|
|
86
|
+
_pass "$label preserves existing $filename byte-for-byte"
|
|
87
|
+
else
|
|
88
|
+
_fail "$label changed or deleted existing $filename (expected identity: $expected; actual: $actual)"
|
|
89
|
+
fi
|
|
90
|
+
done
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Every install path starts with distinct repository-owned instructions. Kiro's
|
|
94
|
+
# fixture is intentionally at the rsync --delete destination root so deletion,
|
|
95
|
+
# not only replacement, is covered by this regression test.
|
|
96
|
+
seed_instruction_fixture "$KIRO_DEST" "direct-kiro-delete-sync"
|
|
97
|
+
seed_instruction_fixture "$BASE_DEST" "direct-base"
|
|
98
|
+
seed_instruction_fixture "$CLAUDE_DEST" "direct-claude-code"
|
|
99
|
+
seed_instruction_fixture "$CODEX_DEST" "direct-codex"
|
|
100
|
+
seed_instruction_fixture "$OPENCODE_DEST" "direct-opencode"
|
|
101
|
+
seed_instruction_fixture "$PI_DEST" "direct-pi"
|
|
102
|
+
seed_instruction_fixture "$BASE_INIT_DEST" "cli-base"
|
|
103
|
+
seed_instruction_fixture "$CODEX_INIT_DEST" "cli-codex"
|
|
104
|
+
seed_instruction_fixture "$OPENCODE_FULL_DEST" "cli-opencode"
|
|
105
|
+
|
|
51
106
|
echo ""
|
|
52
107
|
echo "--- Install ---"
|
|
53
|
-
if (cd "$ROOT_DIR/dist/kiro" && bash install.sh "$KIRO_DEST" >/dev/null); then
|
|
108
|
+
if (cd "$ROOT_DIR/dist/kiro" && bash install.sh "$KIRO_DEST/" >/dev/null); then
|
|
54
109
|
_pass "Kiro install succeeded"
|
|
55
110
|
else
|
|
56
111
|
_fail "Kiro install failed"
|
|
57
112
|
fi
|
|
113
|
+
assert_instruction_fixture_preserved "$KIRO_DEST" "Kiro direct install with trailing-slash destination and rsync --delete"
|
|
58
114
|
|
|
59
115
|
if (cd "$ROOT_DIR/dist/base" && bash install.sh "$BASE_DEST" >/dev/null); then
|
|
60
116
|
_pass "Base install succeeded"
|
|
61
117
|
else
|
|
62
118
|
_fail "Base install failed"
|
|
63
119
|
fi
|
|
120
|
+
assert_instruction_fixture_preserved "$BASE_DEST" "Base direct install"
|
|
64
121
|
|
|
65
122
|
if (cd "$ROOT_DIR/dist/claude-code" && bash install.sh "$CLAUDE_DEST" >/dev/null); then
|
|
66
123
|
_pass "Claude Code install succeeded"
|
|
67
124
|
else
|
|
68
125
|
_fail "Claude Code install failed"
|
|
69
126
|
fi
|
|
127
|
+
assert_instruction_fixture_preserved "$CLAUDE_DEST" "Claude Code direct install"
|
|
70
128
|
|
|
71
129
|
if (cd "$ROOT_DIR/dist/codex" && bash install.sh "$CODEX_DEST" >/dev/null); then
|
|
72
130
|
_pass "Codex install succeeded"
|
|
73
131
|
else
|
|
74
132
|
_fail "Codex install failed"
|
|
75
133
|
fi
|
|
134
|
+
assert_instruction_fixture_preserved "$CODEX_DEST" "Codex direct install"
|
|
76
135
|
|
|
77
136
|
if (cd "$ROOT_DIR/dist/codex" && bash install.sh "$CODEX_CONSOLE_DEST" --telemetry-sink local-kontour-console --console-token-file "$CONSOLE_TOKEN_FILE" --console-tenant tenant-a >/dev/null); then
|
|
78
137
|
_pass "Codex install with Console telemetry config succeeded"
|
|
@@ -118,17 +177,19 @@ else
|
|
|
118
177
|
_pass "Codex install rejects unsafe hosted Console http URL"
|
|
119
178
|
fi
|
|
120
179
|
|
|
121
|
-
if node "$ROOT_DIR/build/src/cli.js" init --dest "$BASE_INIT_DEST" --telemetry-sink local-kontour-console --yes >/dev/null; then
|
|
180
|
+
if node "$ROOT_DIR/build/src/cli.js" init --runtime base --dest "$BASE_INIT_DEST" --telemetry-sink local-kontour-console --yes >/dev/null; then
|
|
122
181
|
_pass "flow-agents init headless base install succeeded"
|
|
123
182
|
else
|
|
124
183
|
_fail "flow-agents init headless base install failed"
|
|
125
184
|
fi
|
|
185
|
+
assert_instruction_fixture_preserved "$BASE_INIT_DEST" "flow-agents init Base install"
|
|
126
186
|
|
|
127
187
|
if node "$ROOT_DIR/build/src/cli.js" init --runtime codex --dest "$CODEX_INIT_DEST" --telemetry-sink local-kontour-console --console-tenant tenant-a --activate-kits --yes >/dev/null; then
|
|
128
188
|
_pass "flow-agents init headless Codex install succeeded"
|
|
129
189
|
else
|
|
130
190
|
_fail "flow-agents init headless Codex install failed"
|
|
131
191
|
fi
|
|
192
|
+
assert_instruction_fixture_preserved "$CODEX_INIT_DEST" "flow-agents init Codex install"
|
|
132
193
|
|
|
133
194
|
echo ""
|
|
134
195
|
echo "--- Guided Console-Connect Wizard (G2/G3): headless regression + summary/verify ---"
|
|
@@ -266,6 +327,7 @@ if (cd "$ROOT_DIR/dist/opencode" && bash install.sh "$OPENCODE_DEST" >/dev/null)
|
|
|
266
327
|
else
|
|
267
328
|
_fail "opencode install failed"
|
|
268
329
|
fi
|
|
330
|
+
assert_instruction_fixture_preserved "$OPENCODE_DEST" "OpenCode direct install"
|
|
269
331
|
|
|
270
332
|
if (cd "$ROOT_DIR/dist/opencode" && bash install.sh "$OPENCODE_CONSOLE_DEST" --telemetry-sink local-kontour-console --console-token-file "$CONSOLE_TOKEN_FILE" --console-tenant tenant-oc >/dev/null); then
|
|
271
333
|
_pass "opencode install with Console telemetry config succeeded"
|
|
@@ -278,12 +340,14 @@ if node "$ROOT_DIR/build/src/cli.js" init --runtime opencode --dest "$OPENCODE_F
|
|
|
278
340
|
else
|
|
279
341
|
_fail "flow-agents init headless opencode install failed"
|
|
280
342
|
fi
|
|
343
|
+
assert_instruction_fixture_preserved "$OPENCODE_FULL_DEST" "flow-agents init OpenCode install"
|
|
281
344
|
|
|
282
345
|
if (cd "$ROOT_DIR/dist/pi" && bash install.sh "$PI_DEST" >/dev/null); then
|
|
283
346
|
_pass "pi install succeeded"
|
|
284
347
|
else
|
|
285
348
|
_fail "pi install failed"
|
|
286
349
|
fi
|
|
350
|
+
assert_instruction_fixture_preserved "$PI_DEST" "pi direct install"
|
|
287
351
|
|
|
288
352
|
USER_SKILLS_DIR="$CODEX_FULL_DEST/.agents/sk""ills/user-skill"
|
|
289
353
|
mkdir -p "$CODEX_FULL_DEST/.codex/ag""ents" "$USER_SKILLS_DIR"
|
|
@@ -323,7 +387,7 @@ done
|
|
|
323
387
|
|
|
324
388
|
echo ""
|
|
325
389
|
echo "--- Placeholder Rewriting ---"
|
|
326
|
-
if rg -n '__KIRO_PACKAGE_ROOT__' "$KIRO_DEST" >/tmp/kiro-placeholder-leaks.txt 2>/dev/null; then
|
|
390
|
+
if rg -n --glob '!AGENTS.md' --glob '!CLAUDE.md' '__KIRO_PACKAGE_ROOT__' "$KIRO_DEST" >/tmp/kiro-placeholder-leaks.txt 2>/dev/null; then
|
|
327
391
|
_fail "Kiro install left placeholder tokens behind (see /tmp/kiro-placeholder-leaks.txt)"
|
|
328
392
|
else
|
|
329
393
|
_pass "Kiro install rewrote package root placeholders"
|
|
@@ -373,13 +437,13 @@ else
|
|
|
373
437
|
_fail "flow-agents init did not persist Console config or activate Codex kits"
|
|
374
438
|
fi
|
|
375
439
|
|
|
376
|
-
if [[ -f "$BASE_INIT_DEST/
|
|
440
|
+
if [[ -f "$BASE_INIT_DEST/README.md" ]] \
|
|
377
441
|
&& [[ -d "$BASE_INIT_DEST/.flow-agents" ]] \
|
|
378
442
|
&& [[ -d "$BASE_INIT_DEST/.kontourai/flow-agents" ]] \
|
|
379
443
|
&& rg -F -q "console_telemetry_url=$LOCAL_KONTOUR_CONSOLE_URL" "$BASE_INIT_DEST/scripts/telemetry/telemetry.conf"; then
|
|
380
|
-
_pass "flow-agents init default installs base
|
|
444
|
+
_pass "flow-agents init default installs base documented workspace contract"
|
|
381
445
|
else
|
|
382
|
-
_fail "flow-agents init default did not install base
|
|
446
|
+
_fail "flow-agents init default did not install base documented workspace contract"
|
|
383
447
|
fi
|
|
384
448
|
|
|
385
449
|
if rg -F -q "console_telemetry_url=$LOCAL_KONTOUR_CONSOLE_URL" "$OPENCODE_CONSOLE_DEST/scripts/telemetry/telemetry.conf" \
|
|
@@ -636,11 +700,18 @@ fi
|
|
|
636
700
|
|
|
637
701
|
KIRO_WORKSPACE="$TMPDIR_EVAL/kiro-workspace"
|
|
638
702
|
mkdir -p "$KIRO_WORKSPACE"
|
|
639
|
-
if node - "$CLAUDE_DEST" "$CODEX_DEST" "$KIRO_DEST" "$KIRO_WORKSPACE" <<'NODE'
|
|
703
|
+
if node - "$CLAUDE_DEST" "$CODEX_DEST" "$KIRO_DEST" "$KIRO_WORKSPACE" "$ROOT_DIR/scripts/hooks/lib/current-pointer.js" <<'NODE'
|
|
640
704
|
const fs = require("node:fs");
|
|
641
705
|
const path = require("node:path");
|
|
642
706
|
const { spawnSync } = require("node:child_process");
|
|
643
|
-
const [claudeDest, codexDest, kiroDest, kiroWorkspace] = process.argv.slice(2);
|
|
707
|
+
const [claudeDest, codexDest, kiroDest, kiroWorkspace, currentPointerHelperPath] = process.argv.slice(2);
|
|
708
|
+
const { writePerActorCurrent } = require(currentPointerHelperPath);
|
|
709
|
+
// #440 FIXTURE-GAP: this fixture was written before #440's per-actor ownership scoping and never
|
|
710
|
+
// established a per-actor current pointer for the invoking actor -- under a RESOLVED ambient
|
|
711
|
+
// actor, workflow-steering.js's actorScopedWorkflowState now scopes to that actor's own
|
|
712
|
+
// (nonexistent) pointer and never surfaces the WORKFLOW STATE ATTENTION banner. Give each
|
|
713
|
+
// runCommand invocation a stable, explicit actor below (see FLOW_AGENTS_ACTOR in env).
|
|
714
|
+
const installedHookActor = "eval-actor-bundle-install-installed-hook";
|
|
644
715
|
const state = {
|
|
645
716
|
schema_version: "1.0",
|
|
646
717
|
task_slug: "installed-hook-demo",
|
|
@@ -661,6 +732,10 @@ function writeFixture(root) {
|
|
|
661
732
|
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
662
733
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
663
734
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
735
|
+
const flowAgentsDir = path.join(root, ".kontourai/flow-agents");
|
|
736
|
+
const currentPayload = { schema_version: "1.0", active_slug: "installed-hook-demo", artifact_dir: "installed-hook-demo" };
|
|
737
|
+
fs.writeFileSync(path.join(flowAgentsDir, "current.json"), JSON.stringify(currentPayload, null, 2) + "\n");
|
|
738
|
+
writePerActorCurrent(flowAgentsDir, installedHookActor, currentPayload);
|
|
664
739
|
}
|
|
665
740
|
function eventGroups(file, ...names) {
|
|
666
741
|
const hooks = JSON.parse(fs.readFileSync(file, "utf8")).hooks || {};
|
|
@@ -683,7 +758,7 @@ function workflowCommand(file, ...eventNames) {
|
|
|
683
758
|
}
|
|
684
759
|
function runCommand(label, command, cwd, runtimeJson) {
|
|
685
760
|
const payload = JSON.stringify({ hook_event_name: "UserPromptSubmit", cwd, prompt: "continue" });
|
|
686
|
-
const env = { ...process.env, SA_HOOK_PROFILE: "standard", CLAUDE_PROJECT_DIR: cwd };
|
|
761
|
+
const env = { ...process.env, SA_HOOK_PROFILE: "standard", CLAUDE_PROJECT_DIR: cwd, FLOW_AGENTS_ACTOR: installedHookActor };
|
|
687
762
|
if (label === "Codex") env.CODEX_HOME = cwd;
|
|
688
763
|
const result = spawnSync(command, { input: payload, cwd, env, shell: true, encoding: "utf8", timeout: 30000 });
|
|
689
764
|
if (result.status !== 0) throw new Error(`${label} installed hook failed: rc=${result.status} stdout=${result.stdout} stderr=${result.stderr}`);
|
|
@@ -709,11 +784,14 @@ fi
|
|
|
709
784
|
# Execute the opencode plugin's workflow-steering command path directly
|
|
710
785
|
OPENCODE_WORKSPACE="$TMPDIR_EVAL/opencode-exec-workspace"
|
|
711
786
|
mkdir -p "$OPENCODE_WORKSPACE"
|
|
712
|
-
if node - "$OPENCODE_DEST" "$OPENCODE_WORKSPACE" <<'NODE'
|
|
787
|
+
if node - "$OPENCODE_DEST" "$OPENCODE_WORKSPACE" "$ROOT_DIR/scripts/hooks/lib/current-pointer.js" <<'NODE'
|
|
713
788
|
const fs = require("node:fs");
|
|
714
789
|
const path = require("node:path");
|
|
715
790
|
const { spawnSync } = require("node:child_process");
|
|
716
|
-
const [opencodeDest, opencodeWorkspace] = process.argv.slice(2);
|
|
791
|
+
const [opencodeDest, opencodeWorkspace, currentPointerHelperPath] = process.argv.slice(2);
|
|
792
|
+
const { writePerActorCurrent } = require(currentPointerHelperPath);
|
|
793
|
+
// #440 FIXTURE-GAP: see the installed-prompt-submit block above for the full rationale.
|
|
794
|
+
const opencodeHookActor = "eval-actor-bundle-install-opencode-hook";
|
|
717
795
|
const state = {
|
|
718
796
|
schema_version: "1.0",
|
|
719
797
|
task_slug: "opencode-hook-demo",
|
|
@@ -730,6 +808,10 @@ function writeFixture(root) {
|
|
|
730
808
|
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
731
809
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
732
810
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
811
|
+
const flowAgentsDir = path.join(root, ".kontourai/flow-agents");
|
|
812
|
+
const currentPayload = { schema_version: "1.0", active_slug: "opencode-hook-demo", artifact_dir: "opencode-hook-demo" };
|
|
813
|
+
fs.writeFileSync(path.join(flowAgentsDir, "current.json"), JSON.stringify(currentPayload, null, 2) + "\n");
|
|
814
|
+
writePerActorCurrent(flowAgentsDir, opencodeHookActor, currentPayload);
|
|
733
815
|
}
|
|
734
816
|
function runOpencodeAdapter(bundleDest, cwd) {
|
|
735
817
|
const adapterPath = path.join(bundleDest, "scripts", "hooks", "opencode-hook-adapter.js");
|
|
@@ -737,7 +819,7 @@ function runOpencodeAdapter(bundleDest, cwd) {
|
|
|
737
819
|
const result = spawnSync(process.execPath, [adapterPath, "UserPromptSubmit", "workflow-steering", "workflow-steering.js", "default"], {
|
|
738
820
|
input: payload,
|
|
739
821
|
cwd,
|
|
740
|
-
env: { ...process.env, SA_HOOK_PROFILE: "standard", FLOW_AGENTS_HOOK_RUNTIME: "opencode" },
|
|
822
|
+
env: { ...process.env, SA_HOOK_PROFILE: "standard", FLOW_AGENTS_HOOK_RUNTIME: "opencode", FLOW_AGENTS_ACTOR: opencodeHookActor },
|
|
741
823
|
encoding: "utf8",
|
|
742
824
|
timeout: 30000,
|
|
743
825
|
});
|
|
@@ -761,11 +843,14 @@ fi
|
|
|
761
843
|
# Execute the pi extension's hook adapter command path directly
|
|
762
844
|
PI_WORKSPACE="$TMPDIR_EVAL/pi-exec-workspace"
|
|
763
845
|
mkdir -p "$PI_WORKSPACE"
|
|
764
|
-
if node - "$PI_DEST" "$PI_WORKSPACE" <<'NODE'
|
|
846
|
+
if node - "$PI_DEST" "$PI_WORKSPACE" "$ROOT_DIR/scripts/hooks/lib/current-pointer.js" <<'NODE'
|
|
765
847
|
const fs = require("node:fs");
|
|
766
848
|
const path = require("node:path");
|
|
767
849
|
const { spawnSync } = require("node:child_process");
|
|
768
|
-
const [piDest, piWorkspace] = process.argv.slice(2);
|
|
850
|
+
const [piDest, piWorkspace, currentPointerHelperPath] = process.argv.slice(2);
|
|
851
|
+
const { writePerActorCurrent } = require(currentPointerHelperPath);
|
|
852
|
+
// #440 FIXTURE-GAP: see the installed-prompt-submit block above for the full rationale.
|
|
853
|
+
const piHookActor = "eval-actor-bundle-install-pi-hook";
|
|
769
854
|
const state = {
|
|
770
855
|
schema_version: "1.0",
|
|
771
856
|
task_slug: "pi-hook-demo",
|
|
@@ -782,6 +867,10 @@ function writeFixture(root) {
|
|
|
782
867
|
fs.writeFileSync(path.join(taskDir, "trust.bundle"), JSON.stringify(trustBundle), "utf8");
|
|
783
868
|
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
784
869
|
fs.writeFileSync(path.join(root, "docs/context-map.md"), "# Context Map\n", "utf8");
|
|
870
|
+
const flowAgentsDir = path.join(root, ".kontourai/flow-agents");
|
|
871
|
+
const currentPayload = { schema_version: "1.0", active_slug: "pi-hook-demo", artifact_dir: "pi-hook-demo" };
|
|
872
|
+
fs.writeFileSync(path.join(flowAgentsDir, "current.json"), JSON.stringify(currentPayload, null, 2) + "\n");
|
|
873
|
+
writePerActorCurrent(flowAgentsDir, piHookActor, currentPayload);
|
|
785
874
|
}
|
|
786
875
|
function runPiAdapter(bundleDest, cwd) {
|
|
787
876
|
const adapterPath = path.join(bundleDest, "scripts", "hooks", "pi-hook-adapter.js");
|
|
@@ -789,7 +878,7 @@ function runPiAdapter(bundleDest, cwd) {
|
|
|
789
878
|
const result = spawnSync(process.execPath, [adapterPath, "UserPromptSubmit", "workflow-steering", "workflow-steering.js", "default"], {
|
|
790
879
|
input: payload,
|
|
791
880
|
cwd,
|
|
792
|
-
env: { ...process.env, SA_HOOK_PROFILE: "standard", FLOW_AGENTS_HOOK_RUNTIME: "pi" },
|
|
881
|
+
env: { ...process.env, SA_HOOK_PROFILE: "standard", FLOW_AGENTS_HOOK_RUNTIME: "pi", FLOW_AGENTS_ACTOR: piHookActor },
|
|
793
882
|
encoding: "utf8",
|
|
794
883
|
timeout: 30000,
|
|
795
884
|
});
|
|
@@ -890,11 +979,11 @@ NODE
|
|
|
890
979
|
)"
|
|
891
980
|
|
|
892
981
|
package_flow() {
|
|
893
|
-
(cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CLI" workflow "$@")
|
|
982
|
+
(cd "$PACKAGE_PROJECT" && env -u CODEX_THREAD_ID CODEX_SESSION_ID=packed-package-consumer node "$PACKAGE_CLI" workflow "$@")
|
|
894
983
|
}
|
|
895
984
|
|
|
896
985
|
package_review() {
|
|
897
|
-
(cd "$PACKAGE_PROJECT" && CODEX_SESSION_ID=packed-package-reviewer node "$PACKAGE_CLI" workflow "$@")
|
|
986
|
+
(cd "$PACKAGE_PROJECT" && env -u CODEX_THREAD_ID CODEX_SESSION_ID=packed-package-reviewer node "$PACKAGE_CLI" workflow "$@")
|
|
898
987
|
}
|
|
899
988
|
|
|
900
989
|
if (cd "$ROOT_DIR" && npm pack --silent --pack-destination "$TMPDIR_EVAL" >"$PACKAGE_PACK_LOG") \
|
|
@@ -528,11 +528,11 @@ fi
|
|
|
528
528
|
DOGFOOD_WORKSPACE="$CLAUDE_IDEM" # reuse the installed workspace from the idempotent section
|
|
529
529
|
mkdir -p "$DOGFOOD_WORKSPACE/.kontourai/flow-agents"
|
|
530
530
|
|
|
531
|
-
if node - "$DOGFOOD_DEST2/.claude/settings.json" "$DOGFOOD_WORKSPACE" << 'NODE'
|
|
531
|
+
if node - "$DOGFOOD_DEST2/.claude/settings.json" "$DOGFOOD_WORKSPACE" "$ROOT_DIR/scripts/hooks/lib/current-pointer.js" << 'NODE'
|
|
532
532
|
const fs = require("node:fs");
|
|
533
533
|
const path = require("node:path");
|
|
534
534
|
const { spawnSync } = require("node:child_process");
|
|
535
|
-
const [settingsPath, workspace] = process.argv.slice(2);
|
|
535
|
+
const [settingsPath, workspace, currentPointerHelperPath] = process.argv.slice(2);
|
|
536
536
|
|
|
537
537
|
// Write minimal fixtures for workflow-steering into the workspace
|
|
538
538
|
const taskDir = path.join(workspace, ".kontourai", "flow-agents", "dogfood-hook-demo");
|
|
@@ -583,10 +583,24 @@ for (const group of groups) {
|
|
|
583
583
|
}
|
|
584
584
|
if (!wsCommand) throw new Error("workflow-steering hook command not found");
|
|
585
585
|
|
|
586
|
+
// #440 FIXTURE-GAP: this fixture was written before #440's per-actor ownership scoping and
|
|
587
|
+
// never established a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
588
|
+
// ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI),
|
|
589
|
+
// workflow-steering.js's actorScopedWorkflowState now scopes to that actor's own (nonexistent)
|
|
590
|
+
// pointer and never surfaces the WORKFLOW STATE ATTENTION banner. Give the hook a stable,
|
|
591
|
+
// explicit actor and seed that actor's own per-actor pointer for dogfood-hook-demo, mirroring
|
|
592
|
+
// workflow-sidecar.ts's real writeCurrent() dual-write via current-pointer.js's own
|
|
593
|
+
// writePerActorCurrent.
|
|
594
|
+
const dogfoodActor = "eval-actor-bundle-lifecycle-dogfood";
|
|
595
|
+
const flowAgentsDir = path.join(workspace, ".kontourai", "flow-agents");
|
|
596
|
+
const currentPayload = { schema_version: "1.0", active_slug: "dogfood-hook-demo", artifact_dir: "dogfood-hook-demo" };
|
|
597
|
+
fs.writeFileSync(path.join(flowAgentsDir, "current.json"), JSON.stringify(currentPayload, null, 2) + "\n");
|
|
598
|
+
require(currentPointerHelperPath).writePerActorCurrent(flowAgentsDir, dogfoodActor, currentPayload);
|
|
599
|
+
|
|
586
600
|
// Execute the hook. CLAUDE_PROJECT_DIR must point to the workspace that has scripts/hooks/.
|
|
587
601
|
// In the real dogfood use case this is the repo root; here we use the installed test workspace.
|
|
588
602
|
const payload = JSON.stringify({ hook_event_name: "UserPromptSubmit", cwd: workspace, prompt: "continue" });
|
|
589
|
-
const env = { ...process.env, SA_HOOK_PROFILE: "standard", CLAUDE_PROJECT_DIR: workspace };
|
|
603
|
+
const env = { ...process.env, SA_HOOK_PROFILE: "standard", CLAUDE_PROJECT_DIR: workspace, FLOW_AGENTS_ACTOR: dogfoodActor };
|
|
590
604
|
const result = spawnSync(wsCommand, {
|
|
591
605
|
input: payload,
|
|
592
606
|
cwd: workspace,
|
|
@@ -29,6 +29,17 @@ set -uo pipefail
|
|
|
29
29
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
30
30
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
31
31
|
|
|
32
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
33
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
34
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
35
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
36
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
37
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
38
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
39
|
+
# global-scan discovery every assertion below was written against).
|
|
40
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
41
|
+
export NODE_ENV=test
|
|
42
|
+
|
|
32
43
|
export FLOW_AGENTS_GOAL_FIT_MAX_BLOCKS=100000
|
|
33
44
|
|
|
34
45
|
TMP="$(mktemp -d)"
|
|
@@ -60,7 +60,7 @@ process.stdout.write(process.argv[2] === "source" ? r.source : r.actor);
|
|
|
60
60
|
verify_hold_under_ci() {
|
|
61
61
|
local dir="$1"; shift
|
|
62
62
|
(
|
|
63
|
-
unset FLOW_AGENTS_ACTOR CLAUDE_CODE_SESSION_ID CODEX_SESSION_ID OPENCODE_SESSION_ID PI_SESSION_ID CLAUDECODE
|
|
63
|
+
unset FLOW_AGENTS_ACTOR CLAUDE_CODE_SESSION_ID CODEX_THREAD_ID CODEX_SESSION_ID OPENCODE_SESSION_ID PI_SESSION_ID CLAUDECODE
|
|
64
64
|
while [[ $# -gt 0 ]]; do export "${1?}"; shift; done
|
|
65
65
|
flow_agents_node "$WRITER" verify-hold "$dir"
|
|
66
66
|
)
|
|
@@ -150,7 +150,7 @@ CLI="$ROOT/build/src/cli.js"
|
|
|
150
150
|
RT_ROOT="$TMPDIR_EVAL/rt-artifact-root"
|
|
151
151
|
RT_SLUG="ci-roundtrip"
|
|
152
152
|
(
|
|
153
|
-
unset FLOW_AGENTS_ACTOR CLAUDE_CODE_SESSION_ID CODEX_SESSION_ID OPENCODE_SESSION_ID PI_SESSION_ID CLAUDECODE
|
|
153
|
+
unset FLOW_AGENTS_ACTOR CLAUDE_CODE_SESSION_ID CODEX_THREAD_ID CODEX_SESSION_ID OPENCODE_SESSION_ID PI_SESSION_ID CLAUDECODE
|
|
154
154
|
export "${GHA[@]}"
|
|
155
155
|
node "$CLI" assignment-provider claim --provider local-file --artifact-root "$RT_ROOT" \
|
|
156
156
|
--subject-id "$RT_SLUG" --branch main --artifact-dir "$RT_SLUG"
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
set -uo pipefail
|
|
19
19
|
|
|
20
20
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
21
|
+
|
|
22
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
23
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
24
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
25
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
26
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
27
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
28
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
29
|
+
# global-scan discovery every assertion below was written against).
|
|
30
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
31
|
+
export NODE_ENV=test
|
|
21
32
|
CAPTURE="$ROOT/scripts/hooks/evidence-capture.js"
|
|
22
33
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
23
34
|
|
|
@@ -15,6 +15,17 @@ set -uo pipefail
|
|
|
15
15
|
|
|
16
16
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
17
17
|
export GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
18
|
+
|
|
19
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
20
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
21
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
22
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
23
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
24
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
25
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
26
|
+
# global-scan discovery every assertion below was written against).
|
|
27
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
28
|
+
export NODE_ENV=test
|
|
18
29
|
REPAIR="$ROOT/scripts/repair-command-log.js"
|
|
19
30
|
|
|
20
31
|
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
|
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
set -uo pipefail
|
|
17
17
|
|
|
18
18
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
19
|
+
|
|
20
|
+
# #440 FIXTURE-GAP: this suite's fixtures were written before #440's per-actor ownership scoping
|
|
21
|
+
# and never establish a per-actor current pointer for the invoking actor -- under a RESOLVED
|
|
22
|
+
# ambient actor (ancestry-derived locally, GITHUB_RUN_ID-derived CI-runtime in CI), stop-goal-fit.js's
|
|
23
|
+
# analyze() now scopes to that actor's own (nonexistent) pointer and never reaches the
|
|
24
|
+
# fixture-under-test at all. This suite is about anti-gaming/gate mechanics, not #440's ownership
|
|
25
|
+
# scoping, so forcing the documented test-only unresolved-actor escape hatch restores EXACTLY this
|
|
26
|
+
# suite's pre-#440 behavior (D3 compat: an unresolved actor keeps the unchanged legacy-fallback/
|
|
27
|
+
# global-scan discovery every assertion below was written against).
|
|
28
|
+
export FLOW_AGENTS_ACTOR_TEST_FORCE_UNRESOLVED=1
|
|
29
|
+
export NODE_ENV=test
|
|
19
30
|
CAPTURE="$ROOT/scripts/hooks/evidence-capture.js"
|
|
20
31
|
GATE="$ROOT/scripts/hooks/stop-goal-fit.js"
|
|
21
32
|
|