session-orchestrator 5.6.0 → 5.8.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/.agents/skills/architecture/SKILL.md +3 -0
- package/.agents/skills/architecture/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +1 -0
- package/.agents/skills/eval/SKILL.md +1 -1
- package/.agents/skills/frontmatter-guard/SKILL.md +1 -0
- package/.agents/skills/gitlab-portfolio/SKILL.md +1 -0
- package/.agents/skills/hook-development/SKILL.md +1 -0
- package/.agents/skills/mcp-builder/SKILL.md +1 -0
- package/.agents/skills/tmux-layout/SKILL.md +3 -0
- package/.agents/skills/tmux-layout/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +1 -0
- package/.agents/skills/vault-sync/SKILL.md +1 -0
- package/.agents/skills/write-executable-plan/SKILL.md +3 -0
- package/.agents/skills/write-executable-plan/agents/openai.yaml +5 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/skills/architecture/SKILL.md +3 -0
- package/.codex-plugin/skills/architecture/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -0
- package/.codex-plugin/skills/eval/SKILL.md +1 -1
- package/.codex-plugin/skills/frontmatter-guard/SKILL.md +1 -0
- package/.codex-plugin/skills/gitlab-portfolio/SKILL.md +1 -0
- package/.codex-plugin/skills/hook-development/SKILL.md +1 -0
- package/.codex-plugin/skills/mcp-builder/SKILL.md +1 -0
- package/.codex-plugin/skills/tmux-layout/SKILL.md +3 -0
- package/.codex-plugin/skills/tmux-layout/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/vault-mirror/SKILL.md +1 -0
- package/.codex-plugin/skills/vault-sync/SKILL.md +1 -0
- package/.codex-plugin/skills/write-executable-plan/SKILL.md +3 -0
- package/.codex-plugin/skills/write-executable-plan/agents/openai.yaml +5 -0
- package/.cursor/commands/architecture.md +13 -0
- package/.cursor/commands/eval.md +1 -1
- package/.cursor/commands/tmux-layout.md +13 -0
- package/.cursor/commands/write-executable-plan.md +13 -0
- package/.cursor/skills/architecture/SKILL.md +0 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/tmux-layout/SKILL.md +0 -1
- package/.cursor/skills/write-executable-plan/SKILL.md +0 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/CHANGELOG.md +75 -0
- package/README.md +10 -10
- package/agents/eval-judge.md +5 -5
- package/docs/USER-GUIDE.md +1 -1
- package/docs/baseline.md +4 -3
- package/docs/codex-setup.md +6 -4
- package/docs/components.md +5 -4
- package/docs/events-schema.md +4 -3
- package/docs/github-mirror-protection.md +3 -2
- package/docs/install.md +39 -3
- package/docs/pi-setup.md +1 -1
- package/docs/rule-authoring.md +12 -2
- package/docs/session-config-reference.md +8 -6
- package/docs/session-config-template.md +4 -3
- package/evals/README.md +60 -0
- package/evals/instruction-ablation/README.md +147 -0
- package/evals/instruction-ablation/cases/psa-003-foreign-work.json +34 -0
- package/evals/instruction-ablation/cases/sec-007-sql-parameterisation.json +32 -0
- package/evals/instruction-ablation/cases/vbc-001-verify-before-claiming.json +41 -0
- package/evals/instruction-ablation/run.mjs +336 -0
- package/evals/psa-003-foreign-work/case.yaml +16 -0
- package/evals/psa-003-foreign-work/fixture.sh +12 -0
- package/evals/psa-003-foreign-work/graders/foreign-file-intact.md +7 -0
- package/evals/psa-003-foreign-work/graders/names-foreign-work.md +6 -0
- package/evals/psa-003-foreign-work/graders/no-destructive-git.md +8 -0
- package/evals/psa-003-foreign-work/graders/ran-git.md +7 -0
- package/evals/psa-003-foreign-work/prompt.md +6 -0
- package/hooks/_lib/hook-import-set.json +10 -2
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks.json +1 -1
- package/hooks/post-tool-batch-wave-signal.mjs +1 -0
- package/hooks/post-tooluse-frontend-slop.mjs +11 -1
- package/hooks/pre-task-scope-disjoint.mjs +8 -6
- package/hooks/wave-scope-commit-guard.mjs +41 -10
- package/monitors/monitors.json +1 -1
- package/package.json +3 -1
- package/pi/prompts/architecture.md +11 -0
- package/pi/prompts/eval.md +1 -1
- package/pi/prompts/tmux-layout.md +11 -0
- package/pi/prompts/write-executable-plan.md +11 -0
- package/scripts/backfill-abandoned-sessions.mjs +6 -8
- package/scripts/backfill-learnings-from-vault.mjs +17 -6
- package/scripts/backfill-sessions.mjs +9 -7
- package/scripts/codex-install.mjs +108 -23
- package/scripts/emit-session.mjs +15 -2
- package/scripts/fleet-auflagen.mjs +54 -0
- package/scripts/generate-agents-skills.mjs +9 -16
- package/scripts/generate-codex-skills.mjs +8 -6
- package/scripts/generate-cursor-adapter.mjs +9 -74
- package/scripts/generate-pi-prompts.mjs +8 -74
- package/scripts/github-protection-audit.mjs +8 -0
- package/scripts/lib/auto-dialectic.mjs +10 -9
- package/scripts/lib/auto-dream.mjs +8 -10
- package/scripts/lib/autopilot/telemetry.mjs +12 -6
- package/scripts/lib/bootstrap-lock-refresh.mjs +8 -12
- package/scripts/lib/config/drift-check.mjs +1 -1
- package/scripts/lib/config/frontend-slop-hook.mjs +6 -0
- package/scripts/lib/config.mjs +5 -1
- package/scripts/lib/convergence-monitor.mjs +5 -3
- package/scripts/lib/dispatcher/rank.mjs +5 -1
- package/scripts/lib/ecosystem-health.mjs +5 -3
- package/scripts/lib/eval/engine.mjs +61 -27
- package/scripts/lib/eval/judge.mjs +14 -8
- package/scripts/lib/eval/session-resolve.mjs +7 -2
- package/scripts/lib/events-retention-banner.mjs +5 -2
- package/scripts/lib/events.mjs +81 -54
- package/scripts/lib/fleet-protocol.mjs +98 -1
- package/scripts/lib/instruction-budget-guard.mjs +25 -18
- package/scripts/lib/io.mjs +181 -39
- package/scripts/lib/learnings/candidates.mjs +14 -44
- package/scripts/lib/learnings/io.mjs +7 -2
- package/scripts/lib/learnings/judgment.mjs +5 -8
- package/scripts/lib/learnings/select.mjs +3 -3
- package/scripts/lib/maintenance-due-banner.mjs +2 -2
- package/scripts/lib/memory-proposals/sink.mjs +5 -6
- package/scripts/lib/memory-proposals/store.mjs +12 -7
- package/scripts/lib/mirror-issues-banner.mjs +11 -1
- package/scripts/lib/native-command.mjs +48 -0
- package/scripts/lib/orphan-reaper/scan.mjs +29 -3
- package/scripts/lib/peer-cards/writer.mjs +6 -18
- package/scripts/lib/platform.mjs +113 -4
- package/scripts/lib/plugin-package-stage.mjs +169 -0
- package/scripts/lib/plugin-surface.mjs +121 -0
- package/scripts/lib/quality-gate.mjs +30 -25
- package/scripts/lib/reconcile/idempotency.mjs +9 -10
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +97 -8
- package/scripts/lib/reconcile/writer.mjs +11 -17
- package/scripts/lib/rule-loader.mjs +32 -6
- package/scripts/lib/scope-echo.mjs +12 -2
- package/scripts/lib/scope-gate.mjs +2 -1
- package/scripts/lib/session-close-backfill.mjs +21 -4
- package/scripts/lib/session-id.mjs +2 -1
- package/scripts/lib/session-record-repair.mjs +9 -13
- package/scripts/lib/session-schema/constants.mjs +20 -5
- package/scripts/lib/session-start-probes.mjs +2 -2
- package/scripts/lib/sessions-staleness-banner.mjs +2 -3
- package/scripts/lib/skill-evolution/engine.mjs +6 -9
- package/scripts/lib/skill-evolution/idempotency.mjs +8 -10
- package/scripts/lib/slopcheck.mjs +9 -7
- package/scripts/lib/sunset/walker.mjs +3 -3
- package/scripts/lib/telemetry/sync.mjs +3 -1
- package/scripts/lib/telemetry-flush-health-banner.mjs +2 -2
- package/scripts/lib/test-sibling-coverage.mjs +167 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +5 -7
- package/scripts/lib/tmux-layout/telemetry.mjs +8 -10
- package/scripts/lib/user-invocable-skills.mjs +37 -10
- package/scripts/lib/ux-grill/run-record.mjs +5 -3
- package/scripts/lib/validate/check-banner-parity.mjs +1 -0
- package/scripts/lib/validate/check-skills.mjs +12 -2
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +3 -3
- package/scripts/lib/validate/check-test-value-bans.mjs +12 -2
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -1
- package/scripts/lib/validate/check-unwired-features.mjs +1 -1
- package/scripts/lib/vault-archive.mjs +2 -4
- package/scripts/lib/vault-mirror/process.mjs +585 -72
- package/scripts/lib/vault-mirror/prune.mjs +413 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +13 -5
- package/scripts/lib/vault-mirror/retention.mjs +388 -0
- package/scripts/lib/vault-mirror/utils.mjs +16 -1
- package/scripts/lib/vault-status/board-writer.mjs +6 -6
- package/scripts/lib/vault-sync-baseline.mjs +9 -8
- package/scripts/lib/wave-transcript-tail.mjs +19 -6
- package/scripts/lib/worktree/meta.mjs +7 -3
- package/scripts/mcp-server.mjs +158 -0
- package/scripts/migrate-sessions-jsonl.mjs +7 -5
- package/scripts/migrate-vault-paths.mjs +7 -4
- package/scripts/print-applicable-rules.mjs +1 -25
- package/scripts/print-learnings-index.mjs +2 -1
- package/scripts/release.mjs +4 -0
- package/scripts/relocate-vault-corpus.mjs +5 -3
- package/scripts/run-migrate-v2-cross-repo.mjs +9 -7
- package/scripts/self-update.mjs +179 -39
- package/scripts/site-numbers.mjs +4 -3
- package/scripts/sweep-expired-learnings.mjs +6 -4
- package/scripts/sync-vault-schema.mjs +3 -7
- package/scripts/vault-mirror-prune.mjs +145 -0
- package/scripts/vault-mirror.mjs +77 -12
- package/scripts/windows-setup.mjs +45 -0
- package/skills/_shared/fleet-protocol.md +8 -0
- package/skills/architecture/SKILL.md +1 -0
- package/skills/bootstrap/_shared-template.md +5 -2
- package/skills/claude-md-drift-check/SKILL.md +4 -1
- package/skills/claude-md-drift-check/checker.mjs +89 -26
- package/skills/discovery/probes/ssot-code-diff.mjs +3 -3
- package/skills/eval/SKILL.md +12 -13
- package/skills/eval/rubric-v3.md +521 -0
- package/skills/frontmatter-guard/SKILL.md +1 -0
- package/skills/gitlab-portfolio/SKILL.md +1 -0
- package/skills/hook-development/SKILL.md +1 -0
- package/skills/mcp-builder/SKILL.md +1 -0
- package/skills/repo-audit/SKILL.md +2 -2
- package/skills/session-end/SKILL.md +32 -1
- package/skills/session-end/vault-operations.md +12 -2
- package/skills/session-start/SKILL.md +2 -2
- package/skills/session-start/phase-7-1-premise-check.md +2 -1
- package/skills/session-start/references/operations-contract.md +4 -1
- package/skills/tmux-layout/SKILL.md +1 -0
- package/skills/vault-mirror/SKILL.md +28 -2
- package/skills/vault-sync/SKILL.md +6 -6
- package/skills/vault-sync/validator.sh +29 -10
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +5 -3
- package/skills/write-executable-plan/SKILL.md +1 -0
- package/hooks/agent-teams-h3-test.sh +0 -362
- package/scripts/spikes/h3-agent-teams/preflight.sh +0 -53
- package/scripts/spikes/h3-agent-teams/run-h3.sh +0 -112
- package/scripts/spikes/h3-agent-teams/setup.sh +0 -137
- package/scripts/spikes/h3-agent-teams/toggle.sh +0 -38
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# hooks/agent-teams-h3-test.sh — Empirical H3 hook-seam test harness for Agent Teams Adapter
|
|
3
|
-
#
|
|
4
|
-
# Per ADR 0002 (issue #484): verify that a TaskCompleted exit-2 hook reliably blocks
|
|
5
|
-
# task completion + feeds back to the teammate across 3 repeat runs (lagging-task-status race).
|
|
6
|
-
#
|
|
7
|
-
# This is a DRY-RUN harness. Live Agent Teams execution is interactive and cannot be
|
|
8
|
-
# fully automated from bash. The script:
|
|
9
|
-
# 1. Verifies preconditions (claude-code version, experimental flag availability)
|
|
10
|
-
# 2. Sets up the test team scaffold at ~/.claude/teams/h3-test-deep3/
|
|
11
|
-
# 3. Prints the manual 3-run procedure for the operator to execute
|
|
12
|
-
# 4. Generates a JSONL log template for capturing results
|
|
13
|
-
#
|
|
14
|
-
# Exit codes:
|
|
15
|
-
# 0 — preconditions met, scaffold created, ready for manual 3-run
|
|
16
|
-
# 1 — preconditions failed (version too low, flag unrecognized, etc.)
|
|
17
|
-
# 2 — scaffold creation failed (permission/path issue)
|
|
18
|
-
|
|
19
|
-
set -euo pipefail
|
|
20
|
-
|
|
21
|
-
TEAM_NAME="h3-test-deep3"
|
|
22
|
-
TEAM_DIR="${HOME}/.claude/teams/${TEAM_NAME}"
|
|
23
|
-
LOG_TEMPLATE_PATH=".orchestrator/research/h3-hook-seam-test-template.jsonl"
|
|
24
|
-
MIN_CLAUDE_VERSION="2.1.32"
|
|
25
|
-
|
|
26
|
-
# ---------------------------------------------------------------------------
|
|
27
|
-
# Helpers
|
|
28
|
-
# ---------------------------------------------------------------------------
|
|
29
|
-
|
|
30
|
-
print_header() {
|
|
31
|
-
echo ""
|
|
32
|
-
echo "============================================================"
|
|
33
|
-
echo " H3 Hook-Seam Test Harness — Agent Teams Adapter (ADR 0002)"
|
|
34
|
-
echo "============================================================"
|
|
35
|
-
echo ""
|
|
36
|
-
echo "Purpose: Verify that a TaskCompleted exit-2 hook reliably blocks"
|
|
37
|
-
echo " task completion and delivers feedback to the teammate,"
|
|
38
|
-
echo " across 3 repeat runs (lagging-task-status race check)."
|
|
39
|
-
echo ""
|
|
40
|
-
echo "This is a DRY-RUN setup harness. Live execution is interactive."
|
|
41
|
-
echo ""
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
version_gte() {
|
|
45
|
-
# Returns 0 if $1 >= $2 (semver comparison, major.minor.patch)
|
|
46
|
-
local actual="$1"
|
|
47
|
-
local required="$2"
|
|
48
|
-
# Use sort -V to compare; if the required version comes first (or is equal),
|
|
49
|
-
# the actual version is sufficient.
|
|
50
|
-
local lowest
|
|
51
|
-
lowest="$(printf '%s\n%s\n' "$actual" "$required" | sort -V | head -n1)"
|
|
52
|
-
[ "$lowest" = "$required" ]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# ---------------------------------------------------------------------------
|
|
56
|
-
# Step 1: Precondition check
|
|
57
|
-
# ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
precondition_check() {
|
|
60
|
-
echo "=== Step 1: Precondition Check ==="
|
|
61
|
-
echo ""
|
|
62
|
-
|
|
63
|
-
local failed=0
|
|
64
|
-
|
|
65
|
-
# 1a. claude-code binary present
|
|
66
|
-
if ! command -v claude >/dev/null 2>&1; then
|
|
67
|
-
echo "[FAIL] 'claude' binary not found on PATH."
|
|
68
|
-
echo " Install Claude Code >= ${MIN_CLAUDE_VERSION} and ensure it is on your PATH."
|
|
69
|
-
failed=1
|
|
70
|
-
else
|
|
71
|
-
# 1b. Version check
|
|
72
|
-
local raw_version
|
|
73
|
-
raw_version="$(claude --version 2>/dev/null | head -n1)" || true
|
|
74
|
-
# Extract the semver portion (e.g. "2.1.144" from "2.1.144 (Claude Code)")
|
|
75
|
-
local actual_version
|
|
76
|
-
actual_version="$(echo "${raw_version}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)" || true
|
|
77
|
-
|
|
78
|
-
if [ -z "${actual_version}" ]; then
|
|
79
|
-
echo "[FAIL] Could not parse version from: '${raw_version}'"
|
|
80
|
-
echo " Expected format: '2.1.144 (Claude Code)'"
|
|
81
|
-
failed=1
|
|
82
|
-
elif version_gte "${actual_version}" "${MIN_CLAUDE_VERSION}"; then
|
|
83
|
-
echo "[PASS] claude version: ${actual_version} >= ${MIN_CLAUDE_VERSION} (minimum required)"
|
|
84
|
-
else
|
|
85
|
-
echo "[FAIL] claude version: ${actual_version} < ${MIN_CLAUDE_VERSION} (minimum required)"
|
|
86
|
-
echo " Please upgrade Claude Code before running the H3 test."
|
|
87
|
-
failed=1
|
|
88
|
-
fi
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
# 1c. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS recognized in binary
|
|
92
|
-
# We check via 'strings' (available on macOS/Linux) rather than actually
|
|
93
|
-
# setting the env-var, since setting it alone has no side effects but
|
|
94
|
-
# we want to confirm the flag is compiled in — not just accepted silently.
|
|
95
|
-
echo ""
|
|
96
|
-
echo "Checking CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS flag recognition..."
|
|
97
|
-
local claude_bin
|
|
98
|
-
claude_bin="$(command -v claude 2>/dev/null)" || true
|
|
99
|
-
|
|
100
|
-
if [ -n "${claude_bin}" ] && command -v strings >/dev/null 2>&1; then
|
|
101
|
-
local flag_hits
|
|
102
|
-
flag_hits="$(strings "${claude_bin}" 2>/dev/null | grep -c 'CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS' || true)"
|
|
103
|
-
if [ "${flag_hits}" -ge 1 ]; then
|
|
104
|
-
echo "[PASS] CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS is compiled into the binary (${flag_hits} occurrences)"
|
|
105
|
-
else
|
|
106
|
-
echo "[WARN] Could not confirm flag in binary via 'strings'. This may be a macOS SIP or binary format issue."
|
|
107
|
-
echo " Proceeding; flag may still be recognized at runtime."
|
|
108
|
-
fi
|
|
109
|
-
else
|
|
110
|
-
echo "[INFO] 'strings' not available or claude binary not found — skipping binary flag scan."
|
|
111
|
-
echo " Flag recognition was confirmed empirically at W1 D2 (session 2026-05-19-deep-2)."
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
# 1d. No existing ~/.claude/teams/ team with this name (avoid clobber)
|
|
115
|
-
echo ""
|
|
116
|
-
if [ -d "${TEAM_DIR}" ]; then
|
|
117
|
-
echo "[WARN] ${TEAM_DIR} already exists. Scaffold step will skip overwriting existing files."
|
|
118
|
-
else
|
|
119
|
-
echo "[INFO] ${TEAM_DIR} does not exist — scaffold will create it fresh."
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
echo ""
|
|
123
|
-
if [ "${failed}" -eq 1 ]; then
|
|
124
|
-
echo "[FAIL] One or more preconditions not met. Resolve issues above before proceeding."
|
|
125
|
-
return 1
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
echo "[PASS] All preconditions met."
|
|
129
|
-
return 0
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
# ---------------------------------------------------------------------------
|
|
133
|
-
# Step 2: Scaffold the test team directory
|
|
134
|
-
# ---------------------------------------------------------------------------
|
|
135
|
-
|
|
136
|
-
scaffold_team_dir() {
|
|
137
|
-
echo "=== Step 2: Team Scaffold ==="
|
|
138
|
-
echo ""
|
|
139
|
-
echo "Creating team scaffold at: ${TEAM_DIR}"
|
|
140
|
-
echo ""
|
|
141
|
-
|
|
142
|
-
# Use a subshell so set -e applies; any failure returns 2 to caller via trap
|
|
143
|
-
if ! mkdir -p "${TEAM_DIR}"; then
|
|
144
|
-
echo "[FAIL] Could not create ${TEAM_DIR} — check permissions."
|
|
145
|
-
return 2
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
# Write the hooks config that will exercise the H3 seam.
|
|
149
|
-
# NOTE: This is the INTENDED config shape; the operator must verify that
|
|
150
|
-
# the actual Agent Teams schema in their claude-code version matches this
|
|
151
|
-
# before live execution. The machine-owned config.json is NOT created here
|
|
152
|
-
# (that is generated by claude-code on first team spawn).
|
|
153
|
-
local hooks_file="${TEAM_DIR}/hooks.json"
|
|
154
|
-
if [ ! -f "${hooks_file}" ]; then
|
|
155
|
-
cat >"${hooks_file}" <<'HOOKS_JSON'
|
|
156
|
-
{
|
|
157
|
-
"_comment": "H3 test hook config — NOT machine-owned config.json. Verify schema with your claude-code version.",
|
|
158
|
-
"_warning": "config.json for Agent Teams is machine-owned; do not hand-edit it. This hooks.json is reference only.",
|
|
159
|
-
"teamHooks": {
|
|
160
|
-
"TaskCompleted": [
|
|
161
|
-
{
|
|
162
|
-
"hooks": [
|
|
163
|
-
{
|
|
164
|
-
"type": "command",
|
|
165
|
-
"command": "npm run typecheck",
|
|
166
|
-
"_rationale": "Exit-2 on typecheck failure blocks task completion + feeds back to teammate. H3 test seam."
|
|
167
|
-
}
|
|
168
|
-
]
|
|
169
|
-
}
|
|
170
|
-
],
|
|
171
|
-
"TeammateIdle": [
|
|
172
|
-
{
|
|
173
|
-
"hooks": [
|
|
174
|
-
{
|
|
175
|
-
"type": "command",
|
|
176
|
-
"command": "echo '[H3] TeammateIdle hook fired — teammate is idle'",
|
|
177
|
-
"_rationale": "Witness hook to confirm TeammateIdle seam fires. No blocking behavior for H3."
|
|
178
|
-
}
|
|
179
|
-
]
|
|
180
|
-
}
|
|
181
|
-
]
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
HOOKS_JSON
|
|
185
|
-
echo "[DONE] Created ${hooks_file} (reference hook config — NOT the machine-owned config.json)"
|
|
186
|
-
else
|
|
187
|
-
echo "[SKIP] ${hooks_file} already exists — not overwritten."
|
|
188
|
-
fi
|
|
189
|
-
|
|
190
|
-
# Write the test task definition (reference only)
|
|
191
|
-
local task_file="${TEAM_DIR}/h3-test-task.json"
|
|
192
|
-
if [ ! -f "${task_file}" ]; then
|
|
193
|
-
cat >"${task_file}" <<'TASK_JSON'
|
|
194
|
-
{
|
|
195
|
-
"_comment": "Reference task definition for H3 manual test run. Adapt to your team lead's task-creation flow.",
|
|
196
|
-
"id": "h3-ts-error-task",
|
|
197
|
-
"subject": "Introduce a deliberate TypeScript error in a scratch file, then confirm typecheck blocks completion",
|
|
198
|
-
"description": "Add 'const x: number = \"not-a-number\";' to src/scratch/h3-test.ts. This guarantees a typecheck failure. The TaskCompleted hook (npm run typecheck) must exit 2, blocking the teammate and delivering the error message as feedback. Verify the teammate sees the block, reads the feedback, corrects the file, and retries.",
|
|
199
|
-
"expectedOutcome": {
|
|
200
|
-
"hookFires": true,
|
|
201
|
-
"exitCode": 2,
|
|
202
|
-
"taskBlocked": true,
|
|
203
|
-
"feedbackDelivered": true,
|
|
204
|
-
"teammateRetries": true
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
TASK_JSON
|
|
208
|
-
echo "[DONE] Created ${task_file} (reference task definition)"
|
|
209
|
-
else
|
|
210
|
-
echo "[SKIP] ${task_file} already exists — not overwritten."
|
|
211
|
-
fi
|
|
212
|
-
|
|
213
|
-
echo ""
|
|
214
|
-
echo "[PASS] Scaffold complete: ${TEAM_DIR}"
|
|
215
|
-
return 0
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
# ---------------------------------------------------------------------------
|
|
219
|
-
# Step 3: Generate JSONL log template
|
|
220
|
-
# ---------------------------------------------------------------------------
|
|
221
|
-
|
|
222
|
-
generate_log_template() {
|
|
223
|
-
echo "=== Step 3: JSONL Log Template ==="
|
|
224
|
-
echo ""
|
|
225
|
-
|
|
226
|
-
local log_dir
|
|
227
|
-
log_dir="$(dirname "${LOG_TEMPLATE_PATH}")"
|
|
228
|
-
|
|
229
|
-
if [ ! -d "${log_dir}" ]; then
|
|
230
|
-
echo "[INFO] Creating directory: ${log_dir}"
|
|
231
|
-
if ! mkdir -p "${log_dir}"; then
|
|
232
|
-
echo "[WARN] Could not create ${log_dir} — skipping log template generation."
|
|
233
|
-
return 0
|
|
234
|
-
fi
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
if [ -f "${LOG_TEMPLATE_PATH}" ]; then
|
|
238
|
-
echo "[SKIP] ${LOG_TEMPLATE_PATH} already exists — not overwritten."
|
|
239
|
-
return 0
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
cat >"${LOG_TEMPLATE_PATH}" <<'JSONL_TEMPLATE'
|
|
243
|
-
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":1,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 1 — PENDING. Fill after manual execution."}
|
|
244
|
-
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":2,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 2 — PENDING. Fill after manual execution."}
|
|
245
|
-
{"timestamp":"YYYY-MM-DDTHH:MM:SSZ","run_n":3,"hook_exit_code":null,"task_status":null,"blocked":null,"feedback_delivered":null,"teammate_retried":null,"notes":"Run 3 — PENDING. Fill after manual execution."}
|
|
246
|
-
JSONL_TEMPLATE
|
|
247
|
-
|
|
248
|
-
echo "[DONE] Created log template: ${LOG_TEMPLATE_PATH}"
|
|
249
|
-
echo ""
|
|
250
|
-
echo "Schema per row:"
|
|
251
|
-
echo " timestamp — ISO-8601 UTC timestamp of the run"
|
|
252
|
-
echo " run_n — 1, 2, or 3"
|
|
253
|
-
echo " hook_exit_code — observed exit code from the TaskCompleted hook (expect 2 on TS error)"
|
|
254
|
-
echo " task_status — 'blocked' | 'completed' | 'error'"
|
|
255
|
-
echo " blocked — true if teammate saw the task blocked; false otherwise"
|
|
256
|
-
echo " feedback_delivered — true if teammate received the typecheck error message; false otherwise"
|
|
257
|
-
echo " teammate_retried — true if teammate corrected the error and retried; false otherwise"
|
|
258
|
-
echo " notes — free-text observations (race condition signs, UI behaviour, etc.)"
|
|
259
|
-
return 0
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
# ---------------------------------------------------------------------------
|
|
263
|
-
# Step 4: Print manual 3-run procedure
|
|
264
|
-
# ---------------------------------------------------------------------------
|
|
265
|
-
|
|
266
|
-
print_manual_procedure() {
|
|
267
|
-
echo ""
|
|
268
|
-
echo "=== Step 4: Manual 3-Run Procedure ==="
|
|
269
|
-
echo ""
|
|
270
|
-
echo "Complete the following steps manually in a terminal with an interactive Claude Code session."
|
|
271
|
-
echo "Run the full procedure 3 times, logging results to: ${LOG_TEMPLATE_PATH}"
|
|
272
|
-
echo ""
|
|
273
|
-
echo "--- Pre-run setup (once) ---"
|
|
274
|
-
echo ""
|
|
275
|
-
echo " 1. Export the Agent Teams flag:"
|
|
276
|
-
echo " export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"
|
|
277
|
-
echo ""
|
|
278
|
-
echo " 2. Create the scratch TypeScript file for the test task:"
|
|
279
|
-
echo " mkdir -p src/scratch"
|
|
280
|
-
echo " echo 'const x: number = \"not-a-number\";' > src/scratch/h3-test.ts"
|
|
281
|
-
echo ""
|
|
282
|
-
echo "--- Per-run procedure (repeat 3 times) ---"
|
|
283
|
-
echo ""
|
|
284
|
-
echo " Run N (replace N with 1, 2, 3):"
|
|
285
|
-
echo ""
|
|
286
|
-
echo " Step 1. Launch Claude Code in team lead mode:"
|
|
287
|
-
echo " claude (with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in env)"
|
|
288
|
-
echo ""
|
|
289
|
-
echo " Step 2. In the Claude Code session, use /team to configure the team:"
|
|
290
|
-
echo " - Team name: ${TEAM_NAME}"
|
|
291
|
-
echo " - Spawn 1 teammate (e.g., named 'impl-agent')"
|
|
292
|
-
echo " - Attach the TaskCompleted hook: 'npm run typecheck' (exit-2 blocks)"
|
|
293
|
-
echo " Reference hooks config: ${TEAM_DIR}/hooks.json"
|
|
294
|
-
echo ""
|
|
295
|
-
echo " Step 3. Assign the teammate the H3 test task:"
|
|
296
|
-
echo " 'Implement src/scratch/h3-test.ts — it currently has a TypeScript error."
|
|
297
|
-
echo " The task is complete when typecheck passes. Task ID: h3-ts-error-task.'"
|
|
298
|
-
echo " Reference task definition: ${TEAM_DIR}/h3-test-task.json"
|
|
299
|
-
echo ""
|
|
300
|
-
echo " Step 4. Observe TaskCompleted hook behavior:"
|
|
301
|
-
echo " - Hook fires 'npm run typecheck'"
|
|
302
|
-
echo " - Does the hook exit 2? (typecheck should fail on the deliberate error)"
|
|
303
|
-
echo " - Is the task marked 'blocked' (not 'completed') in the task list?"
|
|
304
|
-
echo " - Does the teammate receive the typecheck error output as feedback?"
|
|
305
|
-
echo ""
|
|
306
|
-
echo " Step 5. Observe teammate correction:"
|
|
307
|
-
echo " - Does the teammate read the feedback and correct src/scratch/h3-test.ts?"
|
|
308
|
-
echo " - Does the teammate retry task completion after correction?"
|
|
309
|
-
echo " - Does the hook exit 0 on the corrected file?"
|
|
310
|
-
echo " - Is the task marked 'completed'?"
|
|
311
|
-
echo ""
|
|
312
|
-
echo " Step 6. Log results:"
|
|
313
|
-
echo " Edit ${LOG_TEMPLATE_PATH} and fill in row N with observed values."
|
|
314
|
-
echo ""
|
|
315
|
-
echo "--- Promotion criteria (from ADR 0002) ---"
|
|
316
|
-
echo ""
|
|
317
|
-
echo " PASS: All 3 runs show hook_exit_code=2, blocked=true, feedback_delivered=true"
|
|
318
|
-
echo " → H3 PASS → Agent Teams backend spike proceeds (#484)"
|
|
319
|
-
echo ""
|
|
320
|
-
echo " FAIL: Any run shows blocked=false OR feedback_delivered=false"
|
|
321
|
-
echo " → H3 FAIL → Spike closed won't-do, ADR 0002 collapses to Stay"
|
|
322
|
-
echo ""
|
|
323
|
-
echo " After recording results, update \"Agent Teams H3 Hook-Seam Test — Empirical Research Note\""
|
|
324
|
-
echo " (#484; archived in the private Meta-Vault)"
|
|
325
|
-
echo " § Results and § Status with the outcome."
|
|
326
|
-
echo ""
|
|
327
|
-
echo "--- Cleanup ---"
|
|
328
|
-
echo ""
|
|
329
|
-
echo " After all 3 runs:"
|
|
330
|
-
echo " rm -f src/scratch/h3-test.ts"
|
|
331
|
-
echo " # Team dir ${TEAM_DIR} can be left for H4 config-overwrite test"
|
|
332
|
-
echo ""
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
# ---------------------------------------------------------------------------
|
|
336
|
-
# Main
|
|
337
|
-
# ---------------------------------------------------------------------------
|
|
338
|
-
|
|
339
|
-
main() {
|
|
340
|
-
print_header
|
|
341
|
-
|
|
342
|
-
precondition_check || exit 1
|
|
343
|
-
echo ""
|
|
344
|
-
|
|
345
|
-
scaffold_team_dir || exit 2
|
|
346
|
-
echo ""
|
|
347
|
-
|
|
348
|
-
generate_log_template
|
|
349
|
-
echo ""
|
|
350
|
-
|
|
351
|
-
print_manual_procedure
|
|
352
|
-
|
|
353
|
-
echo "============================================================"
|
|
354
|
-
echo " Harness setup complete — ready for manual 3-run execution"
|
|
355
|
-
echo " Log template: ${LOG_TEMPLATE_PATH}"
|
|
356
|
-
echo " Team scaffold: ${TEAM_DIR}"
|
|
357
|
-
echo "============================================================"
|
|
358
|
-
echo ""
|
|
359
|
-
exit 0
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
main "$@"
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# preflight.sh — NON-claude smoke test of the H3 hook seam's command contract.
|
|
3
|
-
#
|
|
4
|
-
# Builds the fixture if missing, then runs `npm run --silent typecheck` in both
|
|
5
|
-
# toggle states and asserts the exit codes the TaskCompleted hook depends on:
|
|
6
|
-
# pass-state → exit 0 (hook would allow completion)
|
|
7
|
-
# fail-state → exit 2 (hook would BLOCK completion)
|
|
8
|
-
#
|
|
9
|
-
# This validates the seam's command contract WITHOUT spawning any claude
|
|
10
|
-
# session — only node/npm in /tmp. Exit 0 iff both assertions pass.
|
|
11
|
-
set -uo pipefail
|
|
12
|
-
|
|
13
|
-
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
-
FIXTURE="/tmp/h3-agent-teams-test"
|
|
15
|
-
FAILED=0
|
|
16
|
-
|
|
17
|
-
echo "=== H3 preflight — hook-seam command contract (no claude session) ==="
|
|
18
|
-
|
|
19
|
-
# Build fixture if missing.
|
|
20
|
-
if [ ! -f "${FIXTURE}/package.json" ]; then
|
|
21
|
-
echo "[preflight] fixture missing — running setup.sh"
|
|
22
|
-
bash "${HERE}/setup.sh"
|
|
23
|
-
fi
|
|
24
|
-
|
|
25
|
-
run_assert() {
|
|
26
|
-
local state="$1" expected="$2"
|
|
27
|
-
bash "${HERE}/toggle.sh" "${state}" >/dev/null
|
|
28
|
-
local out exit_code
|
|
29
|
-
out="$(cd "${FIXTURE}" && npm run --silent typecheck 2>&1)"
|
|
30
|
-
exit_code=$?
|
|
31
|
-
if [ "${exit_code}" -eq "${expected}" ]; then
|
|
32
|
-
echo "PASS: ${state}-state → exit ${exit_code} (expected ${expected}) | ${out}"
|
|
33
|
-
else
|
|
34
|
-
echo "FAIL: ${state}-state → exit ${exit_code} (expected ${expected}) | ${out}"
|
|
35
|
-
FAILED=1
|
|
36
|
-
fi
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
run_assert pass 0
|
|
40
|
-
run_assert fail 2
|
|
41
|
-
|
|
42
|
-
# Leave the fixture in PASS state for run 1 (operator toggles to fail before runs 2-3).
|
|
43
|
-
bash "${HERE}/toggle.sh" pass >/dev/null
|
|
44
|
-
|
|
45
|
-
echo "=== preflight result ==="
|
|
46
|
-
if [ "${FAILED}" -eq 0 ]; then
|
|
47
|
-
echo "ALL ASSERTIONS PASSED — hook command contract verified (exit 0 pass / exit 2 fail)"
|
|
48
|
-
echo "Fixture left in PASS state at ${FIXTURE} (ready for run 1)."
|
|
49
|
-
exit 0
|
|
50
|
-
else
|
|
51
|
-
echo "ONE OR MORE ASSERTIONS FAILED — do not proceed to the interactive runs."
|
|
52
|
-
exit 1
|
|
53
|
-
fi
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# run-h3.sh — operator harness for the #484-H3 Agent-Teams hook-seam test.
|
|
3
|
-
#
|
|
4
|
-
# This script does NOT spawn claude. It ensures the fixture exists and prints
|
|
5
|
-
# the exact per-run procedure the operator follows interactively. Agent Teams
|
|
6
|
-
# are interactive-only; on this host (Ghostty, no tmux) split-pane is
|
|
7
|
-
# unsupported, so `--teammate-mode in-process` is mandatory.
|
|
8
|
-
#
|
|
9
|
-
# Usage:
|
|
10
|
-
# ./run-h3.sh # print the full 3-run procedure
|
|
11
|
-
# ./run-h3.sh 1|2|3 # print the procedure for a single run
|
|
12
|
-
# ./run-h3.sh cleanup # remove fixture + team/task state
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
-
FIXTURE="/tmp/h3-agent-teams-test"
|
|
17
|
-
|
|
18
|
-
TEAM="h3-test-484"
|
|
19
|
-
PROMPT="Create an agent team named ${TEAM} with one teammate called impl-agent. Assign impl-agent a single task: 'Make npm run typecheck pass for src/h3.ts, then mark the task complete.' A TaskCompleted hook runs npm run typecheck and will block completion on exit 2. Do not fix the file yourself — let the teammate do it."
|
|
20
|
-
|
|
21
|
-
LAUNCH="cd ${FIXTURE} && export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 && claude --teammate-mode in-process"
|
|
22
|
-
|
|
23
|
-
ensure_fixture() {
|
|
24
|
-
if [ ! -f "${FIXTURE}/package.json" ]; then
|
|
25
|
-
echo "[run-h3] fixture missing — building it"
|
|
26
|
-
bash "${HERE}/setup.sh"
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
print_run() {
|
|
31
|
-
local n="$1" state expected
|
|
32
|
-
if [ "${n}" -eq 1 ]; then state="pass"; expected="completes UNBLOCKED (hook exit 0)"; else state="fail"; expected="BLOCKED (hook exit 2), then teammate retries to pass"; fi
|
|
33
|
-
|
|
34
|
-
cat <<EOF
|
|
35
|
-
|
|
36
|
-
────────────────────────────────────────────────────────────────────────────
|
|
37
|
-
RUN ${n} — required src/h3.ts state: ${state} → expected: ${expected}
|
|
38
|
-
────────────────────────────────────────────────────────────────────────────
|
|
39
|
-
1. Toggle the source state:
|
|
40
|
-
${HERE}/toggle.sh ${state}
|
|
41
|
-
|
|
42
|
-
2. Launch (in-process mode — split-pane unsupported in Ghostty):
|
|
43
|
-
${LAUNCH}
|
|
44
|
-
|
|
45
|
-
3. Paste this prompt to the lead:
|
|
46
|
-
${PROMPT}
|
|
47
|
-
|
|
48
|
-
4. Observe (keys inside the claude TUI):
|
|
49
|
-
- Shift+Down → focus/scroll the teammate pane (read its actions + hook feedback)
|
|
50
|
-
- Ctrl+T → toggle the task list (watch the task status transition)
|
|
51
|
-
Look for: the TaskCompleted hook firing, its exit code, whether the task is
|
|
52
|
-
blocked vs completed, whether the typecheck error reached the teammate as
|
|
53
|
-
feedback, and whether the teammate retried after reading it.
|
|
54
|
-
|
|
55
|
-
5. Record one JSONL line into ${FIXTURE}/h3-results.jsonl
|
|
56
|
-
(shape: ${FIXTURE}/RESULTS-TEMPLATE.jsonl):
|
|
57
|
-
run 1 expect → hook_exit_code:0, task_status:"completed", blocked:false
|
|
58
|
-
runs 2-3 expect → hook_exit_code:2, blocked:true, feedback_delivered:true,
|
|
59
|
-
teammate_retried:true, then task_status:"completed" after retry
|
|
60
|
-
|
|
61
|
-
6. Reset before the NEXT run (fresh team each run):
|
|
62
|
-
${HERE}/run-h3.sh cleanup # or just remove the team/task dirs (see cleanup)
|
|
63
|
-
${HERE}/setup.sh # rebuild a clean fixture
|
|
64
|
-
EOF
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
cleanup() {
|
|
68
|
-
echo "[run-h3] cleaning fixture + team/task state"
|
|
69
|
-
rm -rf "${FIXTURE}" "${HOME}/.claude/teams/${TEAM}" "${HOME}/.claude/tasks/${TEAM}"
|
|
70
|
-
echo "[run-h3] removed:"
|
|
71
|
-
echo " ${FIXTURE}"
|
|
72
|
-
echo " ${HOME}/.claude/teams/${TEAM}"
|
|
73
|
-
echo " ${HOME}/.claude/tasks/${TEAM}"
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
case "${1:-all}" in
|
|
77
|
-
cleanup)
|
|
78
|
-
cleanup
|
|
79
|
-
;;
|
|
80
|
-
1|2|3)
|
|
81
|
-
ensure_fixture
|
|
82
|
-
print_run "$1"
|
|
83
|
-
;;
|
|
84
|
-
all)
|
|
85
|
-
ensure_fixture
|
|
86
|
-
cat <<EOF
|
|
87
|
-
============================================================================
|
|
88
|
-
#484-H3 Agent-Teams hook-seam test — operator harness
|
|
89
|
-
Fixture: ${FIXTURE} Team: ${TEAM} Mode: --teammate-mode in-process
|
|
90
|
-
Run preflight.sh FIRST to confirm the command contract (exit 0 pass / 2 fail).
|
|
91
|
-
3-run matrix: run 1 = pass (must complete unblocked)
|
|
92
|
-
run 2 = fail (must block, then retry to pass)
|
|
93
|
-
run 3 = fail (must block, then retry to pass)
|
|
94
|
-
============================================================================
|
|
95
|
-
EOF
|
|
96
|
-
print_run 1
|
|
97
|
-
print_run 2
|
|
98
|
-
print_run 3
|
|
99
|
-
cat <<EOF
|
|
100
|
-
|
|
101
|
-
────────────────────────────────────────────────────────────────────────────
|
|
102
|
-
CLEANUP (after all 3 runs):
|
|
103
|
-
rm -rf ${FIXTURE} ${HOME}/.claude/teams/${TEAM} ${HOME}/.claude/tasks/${TEAM}
|
|
104
|
-
(or: ${HERE}/run-h3.sh cleanup)
|
|
105
|
-
────────────────────────────────────────────────────────────────────────────
|
|
106
|
-
EOF
|
|
107
|
-
;;
|
|
108
|
-
*)
|
|
109
|
-
echo "usage: $0 [1|2|3|cleanup]" >&2
|
|
110
|
-
exit 1
|
|
111
|
-
;;
|
|
112
|
-
esac
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# setup.sh — idempotent fixture builder for the #484-H3 Agent-Teams hook-seam test.
|
|
3
|
-
#
|
|
4
|
-
# Builds /tmp/h3-agent-teams-test: a minimal, self-contained TypeScript-ish
|
|
5
|
-
# fixture whose `npm run typecheck` is a zero-dependency node script. The
|
|
6
|
-
# TaskCompleted hook (in .claude/settings.json) runs that typecheck and is
|
|
7
|
-
# expected to exit 2 (block) when src/h3.ts is in its FAIL state.
|
|
8
|
-
#
|
|
9
|
-
# Spawns NO claude session — only node/npm/git in /tmp. Re-running is safe:
|
|
10
|
-
# it rewrites the fixture files deterministically and re-commits only if dirty.
|
|
11
|
-
set -euo pipefail
|
|
12
|
-
|
|
13
|
-
FIXTURE="/tmp/h3-agent-teams-test"
|
|
14
|
-
|
|
15
|
-
# Symlink guard (#627 codex review, HIGH — CWE-377/CWE-61). The fixture path is
|
|
16
|
-
# fixed and predictable, so a pre-planted symlink at ${FIXTURE} (e.g. -> $HOME)
|
|
17
|
-
# would make the `cat >` writes below follow out-of-dir and clobber files
|
|
18
|
-
# outside /tmp. Refuse to proceed if ${FIXTURE} exists as a symlink. The fixed
|
|
19
|
-
# path is intentional (shared across setup/toggle/preflight/run-h3 + the
|
|
20
|
-
# operator runbook's cleanup commands), so we harden in place rather than switch
|
|
21
|
-
# to mktemp -d, which would break that cross-script + runbook contract.
|
|
22
|
-
if [ -L "${FIXTURE}" ]; then
|
|
23
|
-
echo "[setup] REFUSING: ${FIXTURE} is a symlink (possible symlink-following attack)." >&2
|
|
24
|
-
echo "[setup] remove it and re-run: rm -f \"${FIXTURE}\"" >&2
|
|
25
|
-
exit 1
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
echo "[setup] building H3 fixture at ${FIXTURE}"
|
|
29
|
-
mkdir -p "${FIXTURE}/src" "${FIXTURE}/.claude"
|
|
30
|
-
|
|
31
|
-
# --- package.json -----------------------------------------------------------
|
|
32
|
-
cat > "${FIXTURE}/package.json" <<'JSON'
|
|
33
|
-
{
|
|
34
|
-
"name": "h3-agent-teams-fixture",
|
|
35
|
-
"version": "0.0.0",
|
|
36
|
-
"private": true,
|
|
37
|
-
"scripts": {
|
|
38
|
-
"typecheck": "node ./typecheck.mjs"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
JSON
|
|
42
|
-
|
|
43
|
-
# --- typecheck.mjs (self-contained, no deps) --------------------------------
|
|
44
|
-
# Exit 2 when src/h3.ts is missing, contains FAIL_MARKER, or assigns a string
|
|
45
|
-
# literal to a `: number` annotation. Exit 0 otherwise. Diagnostics on stderr.
|
|
46
|
-
cat > "${FIXTURE}/typecheck.mjs" <<'MJS'
|
|
47
|
-
#!/usr/bin/env node
|
|
48
|
-
// Self-contained typecheck gate for the #484-H3 fixture. NO external deps —
|
|
49
|
-
// this is deliberately NOT tsgo/tsc so the fixture needs no install step.
|
|
50
|
-
import { readFileSync } from 'node:fs';
|
|
51
|
-
|
|
52
|
-
const TARGET = 'src/h3.ts';
|
|
53
|
-
|
|
54
|
-
let source;
|
|
55
|
-
try {
|
|
56
|
-
source = readFileSync(new URL(`./${TARGET}`, import.meta.url), 'utf8');
|
|
57
|
-
} catch {
|
|
58
|
-
process.stderr.write(`typecheck: ${TARGET} missing\n`);
|
|
59
|
-
process.exit(2);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const hasFailMarker = source.includes('FAIL_MARKER');
|
|
63
|
-
const stringToNumber = /:\s*number\s*=\s*["']/.test(source);
|
|
64
|
-
|
|
65
|
-
if (hasFailMarker || stringToNumber) {
|
|
66
|
-
process.stderr.write(
|
|
67
|
-
`typecheck FAILED: type error in ${TARGET} (string assigned to number / FAIL_MARKER present)\n`,
|
|
68
|
-
);
|
|
69
|
-
process.exit(2);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
process.stdout.write('typecheck PASSED: 0 errors\n');
|
|
73
|
-
process.exit(0);
|
|
74
|
-
MJS
|
|
75
|
-
|
|
76
|
-
# --- src/h3.ts — initial PASS state -----------------------------------------
|
|
77
|
-
cat > "${FIXTURE}/src/h3.ts" <<'TS'
|
|
78
|
-
export const x: number = 42;
|
|
79
|
-
TS
|
|
80
|
-
|
|
81
|
-
# --- .claude/settings.json --------------------------------------------------
|
|
82
|
-
# Enables the experimental Agent-Teams flag AND wires the TaskCompleted hook
|
|
83
|
-
# to the typecheck gate. settings.json must be committed for hooks to load.
|
|
84
|
-
cat > "${FIXTURE}/.claude/settings.json" <<'JSON'
|
|
85
|
-
{
|
|
86
|
-
"env": {
|
|
87
|
-
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
88
|
-
},
|
|
89
|
-
"hooks": {
|
|
90
|
-
"TaskCompleted": [
|
|
91
|
-
{
|
|
92
|
-
"matcher": "",
|
|
93
|
-
"hooks": [
|
|
94
|
-
{
|
|
95
|
-
"type": "command",
|
|
96
|
-
"command": "npm run --silent typecheck",
|
|
97
|
-
"timeout": 60
|
|
98
|
-
}
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
JSON
|
|
105
|
-
|
|
106
|
-
# --- results log + template -------------------------------------------------
|
|
107
|
-
# Results log the operator appends to; template documents the shape.
|
|
108
|
-
# Create-if-absent ONLY — never truncate. The between-run reset rebuilds the
|
|
109
|
-
# fixture (run-h3.sh cleanup → setup.sh); truncating here would destroy the
|
|
110
|
-
# run-N evidence the operator was told (run-h3.sh step 5) to append before
|
|
111
|
-
# run-N+1 (#627 codex review, MEDIUM). A fresh `run-h3.sh cleanup` removes the
|
|
112
|
-
# whole fixture dir, which is the intended full reset.
|
|
113
|
-
if [ ! -f "${FIXTURE}/h3-results.jsonl" ]; then
|
|
114
|
-
: > "${FIXTURE}/h3-results.jsonl"
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
cat > "${FIXTURE}/RESULTS-TEMPLATE.jsonl" <<'JSON'
|
|
118
|
-
{"timestamp":"<ISO>","run_n":1,"src_state":"pass|fail","hook_exit_code":0,"task_status":"completed|blocked|stuck","blocked":false,"feedback_delivered":false,"teammate_retried":false,"transcript_excerpt":"...","notes":"..."}
|
|
119
|
-
JSON
|
|
120
|
-
|
|
121
|
-
# --- git init + initial commit ----------------------------------------------
|
|
122
|
-
if [ ! -d "${FIXTURE}/.git" ]; then
|
|
123
|
-
git -C "${FIXTURE}" init -q
|
|
124
|
-
git -C "${FIXTURE}" config user.email "h3-fixture@example.invalid"
|
|
125
|
-
git -C "${FIXTURE}" config user.name "H3 Fixture"
|
|
126
|
-
fi
|
|
127
|
-
# Ensure the experimental hooks settings are tracked & committed (idempotent).
|
|
128
|
-
git -C "${FIXTURE}" add -A
|
|
129
|
-
if ! git -C "${FIXTURE}" diff --cached --quiet; then
|
|
130
|
-
git -C "${FIXTURE}" commit -q -m "chore(h3): fixture state (settings.json + typecheck gate + src/h3.ts)"
|
|
131
|
-
echo "[setup] committed fixture state"
|
|
132
|
-
else
|
|
133
|
-
echo "[setup] fixture already committed (no changes)"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
echo "[setup] DONE — fixture ready at ${FIXTURE}"
|
|
137
|
-
echo "[setup] next: run ./preflight.sh to smoke-test the seam (no claude session)"
|