diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6b37068..7debbb2 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,7 +11,7 @@ "homepage": "https://github.com/Drix10/agent-flow", "name": "agent-flow", "source": "./", - "version": "1.1.4" + "version": "1.1.5" } ] } \ No newline at end of file diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 202e266..fc9b111 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -15,5 +15,5 @@ "license": "MIT", "name": "agent-flow", "repository": "https://github.com/Drix10/agent-flow", - "version": "1.1.4" + "version": "1.1.5" } \ No newline at end of file diff --git a/.github/workflows/harness-flags.yml b/.github/workflows/harness-flags.yml new file mode 100644 index 0000000..6ada6cc --- /dev/null +++ b/.github/workflows/harness-flags.yml @@ -0,0 +1,30 @@ +name: Harness flags + +# Installs each harness CLI and checks that the flags launch.md relies on still appear in its --help. +# No API keys, no model calls. Weekly, because these CLIs change without notice. +on: + schedule: + - cron: "17 4 * * 1" + workflow_dispatch: + pull_request: + paths: ["skills/invoking-agents/**", "scripts/check-harness-flags.mjs", ".github/workflows/harness-flags.yml"] + +jobs: + flags: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install harness CLIs (best effort) + shell: bash + run: | + for p in @anthropic-ai/claude-code @openai/codex @google/gemini-cli @earendil-works/pi-coding-agent; do + npm install -g "$p" || echo "::warning::could not install $p" + done + - run: node scripts/check-harness-flags.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index d369b9b..d17d141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,37 @@ All notable changes to this project are documented here. Format: [Keep a Changel ## [Unreleased] +## [1.1.5] - 2026-10-01 + +- Read each vendor's hook docs and source and fixed what they contradicted: Gemini's hook now matches every tool (the allow-list named a tool that doesn't exist and missed others); Cursor's Windows BOM on stdin no longer makes the guard fail open, and Cursor's Delete tool counts as a write; the OpenCode plugin is one flat file with no SDK import (v1 and v2 load it; it no longer writes `.opencode/package.json` or depends on `@opencode/plugin`). `docs/HARNESS-MATRIX.md` says, per harness, what is live-verified and what is docs-verified only, with the caveats each vendor's docs give (untrusted folders, fail-open exits, headless modes). + +- Codex guard hook live-verified on Linux/WSL (protected write, `--no-verify` commit and hook-config write all blocked); docs note that Codex's bypass-hook-trust / full-access options disable enforcement. +- Guard: PowerShell writes are judged like their POSIX twins — named parameters in any order (`-LiteralPath`, `-Destination`, …), Windows `\` paths, `Copy-Item` writes only its destination, and .NET `[IO.File]::Write*` calls count as writes. A live Codex-on-Windows probe found `Set-Content -LiteralPath .codex/hooks.json …` slipped through. +- Guard blocks also print a JSON deny (`permissionDecision`) on stdout besides exit 2 + stderr; set `AGENT_FLOW_GUARD_JSON_ONLY=1` to deny by JSON with exit 0 (experiment for a harness that ignores exit 2). +- `agent-flow sandbox [--ro] [--no-net] [--hide-home] [--allow ] -- ` runs a command under bubblewrap (read-only filesystem except the worktree), an OS-level boundary the hook cannot give. Linux/WSL only. + +- `doctor` warns (never fails) when `protected_paths` have no CODEOWNERS entry, since only the host can stop a pull request editing them. +- Guard: recognises Codex/OpenCode patch payloads, Gemini `replace`, argv-form shells, `workdir`/`dir_path`, and protects the Gemini/Codex/Cursor/OpenCode hook wiring from edits. + +- `install --harness gemini|codex|cursor` also installs the guard as a pre-tool hook; the guard understands Cursor's tool-less `beforeShellExecution`/`beforeReadFile` payloads. Live verification pending. +- `policy.deny_commands: ["infra"]` shorthand accepted (it used to load no rule at all). + +- `install --harness opencode`: OpenCode guard plugin (`tool.execute.before`), fails closed. Live verification pending. +- Guard: `mv x ~/` no longer flagged when the repo lives under the home directory (found by a live OpenCode run). + +### Added +- **Cross-vendor roles.** `pipeline.harness_by_role` (`{"reviewer": "codex"}`) runs a role on another harness than the orchestrator's; the orchestrator skill reads it into `env.sh`, the verdict still goes through the schema, round cap and audit chain, and a missing CLI is Needs Me, not a silent fallback. On the last allowed round the Implementer uses `pipeline.models.high_reasoning`. +- **`policy.deny_commands`** (opt-in): presets `database` and `infra` plus custom regexes that the guard refuses in every agent session, with an additive floor from the default branch and the usual human override. +- **Bounded stop gate for interactive Claude Code sessions.** Gates marked `on_stop: true` run from a Stop hook (`agent-flow gates stop`, installed with `install --harness claude --stop-gate`) when the tree changed since the last pass. It holds a session back at most `pipeline.max_stop_blocks` (default 2, max 5) times per turn, then lets it stop and records `stop_gate_exhausted`. Gates come from the default branch's manifest; `.agent-flow/stop-gate.json` and `.agent-flow/gates/` are tamper-proof. +- **Per-issue cost cap.** `pipeline.max_cost_usd`: once an issue's role runs have cost that much, `state update` (and the Pi `state_update` tool) escalates the next new phase or round to Needs Me `budget_exceeded` with the cost per round (exit 3 in the CLI). Counts only harnesses that report cost; `audit summary` now shows how many runs reported none. +- **`doctor` checks commands, links and commits, not just paths.** `npm|pnpm run