Commit Graph

2102 Commits

  • Finalize and enhance SLSA generic generator workflow (#2197)
    * Add SLSA generic generator workflow
    
    * ci: finalize SLSA generator and fix bun test timeout
    
    - Harden SLSA workflow with persist-credentials: false and pinned actions
    - Update SLSA workflow to build real npm artifacts and fix digest outputs
    - Increase trae-install test timeout to prevent ETIMEDOUT under Bun
    - Fix Validate Components security violation in SLSA workflow
    
    * ci: finalize SLSA generator and fix bun test timeout
    
    - Harden SLSA workflow with persist-credentials: false and pinned actions
    - Update SLSA workflow to build real npm artifacts and fix digest outputs
    - Rename workflow to "SLSA generic generator workflow #1"
    - Increase trae-install test timeout to prevent ETIMEDOUT under Bun
    - Fix Validate Components security violation in SLSA workflow
    
    * Update generator-generic-ossf-slsa3-publish.yml
    
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
    
    * generator-generic-ossf-slsa3-publish.yml
    
    * .github/workflows/generator-generic-ossf-slsa3-publish.yml
    
    Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
    
    * Update .github/workflows/generator-generic-ossf-slsa3-publish.yml
    
    Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
    Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
  • fix: add plugin cache health check (#2249)
    * fix: add plugin cache health check
    
    * fix: harden plugin cache diagnostics
    
    * fix: reject escaping plugin cache refs
    
    * test: remove unused plugin cache fixture
  • feat: add dry-run mode for hook execution (#2116) (#2188)
    - Global --dry-run flag and ECC_DRY_RUN=1 env var
    - Enriched preview: shows target file path, tool name, and command
    - --dry-run stripped from argv so command routing works correctly
    - Handles non-JSON and empty stdin gracefully (session/stop hooks)
    - 10 tests covering isDryRun(), hook gating, enriched output, CLI routing
  • feat: add web capabilities dashboard (#2100)
    * feat: add web capabilities dashboard with agents, skills, commands, MCPs, rules, and hooks
    
    * fix: address code review - XSS, env exposure, port validation, error handling, packaging
    
    * add tests for dashboard
  • docs: add MCP server and tools integration for tinystruct (#2244)
    * docs: add MCP server and tools integration for tinystruct
    
    * Update the doc to specify the package for apis and security reminder, checks for prompt.
  • docs(skills): document tdd plan handoff evidence (#2235)
    * docs(skills): document tdd plan handoff evidence
    
    Address issue #2138 by clarifying how tdd-workflow should continue from a plan file, preserve human-readable test guarantees, and retain RED/GREEN evidence across squash merges.
    
    * docs(skills): harden tdd plan handoff guidance
    
    Address review feedback on #2235: use angle-bracket argument hint, treat plan files as untrusted input, and prefer project-local documentation paths for TDD evidence reports.
    
    * docs(skills): clarify plan handoff injection guard
    
    Address review feedback by explicitly stating that plan file content is data, not AI instructions, and that validation commands from untrusted plans require sanitization and approval before execution.
    
    * Update skills/tdd-workflow/SKILL.md
    
    Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
    
    * docs(skills): address tdd workflow review nits
    
    Clarify plan handoff safety decisions, remove redundant untrusted-input wording, and show consistent TDD evidence path examples.
    
    ---------
    
    Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • feat(browser-qa): read-only safety default, baseline-or-die, honest a11y scope (#2186)
    Additive-only hardening of skills/browser-qa/SKILL.md.
    
    Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
  • fix: sanitize subprocess call in runner.py (#2149)
    * fix: V-001 security vulnerability
    
    Automated security fix generated by OrbisAI Security
    
    * fix: sanitize subprocess call in runner.py
    
    The runner
    
    * fix: address PR review comments on V-001 allowlist and test coverage
    
    Remove dangerous interpreters (python, python3, node, curl, wget) from
    ALLOWED_SETUP_EXECUTABLES — they can execute arbitrary code via argument
    flags and are not needed for sandbox setup. Rewrite test_invariant_runner
    to call _setup_sandbox directly instead of spawning runner.py as a
    subprocess (which had no __main__ entrypoint and never exercised the fix).
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
  • fix(security): add host/origin allowlist + validate git refs + quote workflow input (#2185)
    Three defense-in-depth fixes around untrusted input flowing to subprocess execution:
    
    1. **Control-pane HTTP server (scripts/lib/control-pane/server.js)**
       The local control-pane API binds to 127.0.0.1 but had no Host or Origin
       validation, so a DNS-rebinding attack from a malicious website could pivot
       into the loopback endpoints — including POST /api/actions/:id, which spawns
       'cargo run -- graph ...' with caller-supplied query strings. Add a hostname
       allowlist (loopback variants plus the explicitly configured --host) and
       reject mismatched Host (421) or non-loopback Origin (403) before any route
       handler runs.
    
    2. **OpenCode git-summary tool (.opencode/tools/git-summary.ts)**
       The tool was building 'git diff ${baseBranch}...HEAD --stat' with execSync
       and a raw model-supplied baseBranch string. Switch run() to execFileSync
       with an args array (no shell), validate baseBranch against a conservative
       git-ref allowlist (rejects shell metacharacters, leading -, embedded ..),
       and clamp the depth arg to a small positive integer before interpolating
       into 'git log --oneline -<N>'.
    
    3. **Reusable test workflow (.github/workflows/reusable-test.yml)**
       The 'Install dependencies' step interpolated ${{ inputs.package-manager }}
       directly into a bash 'case' and into an echo, so a downstream caller that
       forwarded attacker-controllable input could inject into the runner. Move
       the input into a PACKAGE_MANAGER env var and reference $PACKAGE_MANAGER
       inside the script per the GitHub script-injection guidance.
    
    Detected by Aeon + semgrep p/security-audit (host check via threat-model
    manual-review axis; git-summary via detect-child-process; workflow via
    run-shell-injection).
    
    Verification: node tests/run-all.js — 2686/2687 pre-existing tests pass; the
    one failure (observe.sh legacy output fallback) reproduces on main without
    this branch applied. Added 2 new control-pane tests covering the allowlist
    classifier and the DNS-rebinding-gate behavior end-to-end.
    
    ---
    Filed by [Aeon](https://github.com/aaronjmars/aeon-aaron).
    
    Co-authored-by: aeonframework <aeon@aaronjmars.com>
  • Remove model version numbers (#2144)
    Remove model version numbers so that the rules stay relevant as the new models are released
  • fix(skills): replace star ratings with ASCII N/5 (#2194)
    Change-Id: I72b7d094bb982070706595255536b69aa5998862
  • fix: prevent IOC scanner false positives on hook filenames and scan .cursor configs (#2245)
    * fix: prevent IOC scanner false positives on hook filenames and scan .cursor configs
    
    The supply-chain IOC scanner matched CRITICAL_TEXT_INDICATORS with plain
    substring search, so legitimate hook filenames that merely end with a known
    payload name (e.g. the stock Cursor hook before-shell-execution.js vs the
    payload execution.js) were flagged as CRITICAL. Indicator matching now
    requires a non-filename character before the match.
    
    Also add .cursor/ to the special config paths so Cursor hooks.json files
    (a known persistence vector already listed in PERSISTENCE_FILENAMES) are
    actually inspected in normal checkouts - previously they were only scanned
    by accident when the repo path happened to contain /.claude/.
    
    * test: cover underscore-prefixed filenames in IOC boundary suppression
    
    Make explicit that '_' is treated as a filename word character, so
    snake_case hook names like post_execution.js are intentionally not
    flagged by the execution.js indicator (real payload references appear
    after '/', quotes, or whitespace).
  • fix(hooks): stop pre/post Bash dispatcher from echoing the input event (#2240)
    runHooks() returned the unmodified raw stdin (the PreToolUse/PostToolUse
    input event) on stdout whenever no sub-hook produced additionalContext.
    Claude Code parses a hook's stdout as JSON and validates it against the
    hook-output schema, so echoing the input object
    ({session_id, hook_event_name, tool_name, tool_input, ...}) fails with
    "Hook JSON output validation failed — (root): Invalid input" on nearly
    every Bash command.
    
    Track whether a sub-hook deliberately set stdout (string / {stdout}, e.g.
    GateGuard) via a rawModified flag and emit '' in the pass-through case
    instead of the echoed input. Preserves GateGuard pass-through and
    block-no-verify's exit-2 blocking.
    
    Update the three dispatcher tests that codified the buggy echo behavior to
    expect empty stdout, and add a regression test for a plain pass-through
    command.
    
    Fixes #2239
    
    Co-authored-by: WOZCODE <contact@withwoz.com>
  • fix(ecc2): resolve kill_process duplicate definition on Windows (#2195)
    On Windows both cfg(windows) and cfg(not(unix)) evaluate true, so the sync taskkill kill_process and the async taskkill kill_process both compiled in and collided (E0428). Call sites are synchronous and never await it (passed as a fn pointer to enforce_session_heartbeats_with, and called as kill_process(pid)? in stop_session_recorded), so remove the stray async cfg(not(unix)) definition. The sync cfg(windows) version already handles termination via taskkill /T /F.
  • chore(deps): bump git2 from 0.20.4 to 0.21.0 in /ecc2 (#2263)
    Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.20.4 to 0.21.0.
    - [Changelog](https://github.com/rust-lang/git2-rs/blob/main/CHANGELOG.md)
    - [Commits](https://github.com/rust-lang/git2-rs/compare/git2-0.20.4...git2-0.21.0)
    
    ---
    updated-dependencies:
    - dependency-name: git2
      dependency-version: 0.21.0
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • chore(deps): bump cron from 0.12.1 to 0.16.0 in /ecc2 (#2262)
    Bumps [cron](https://github.com/zslayton/cron) from 0.12.1 to 0.16.0.
    - [Release notes](https://github.com/zslayton/cron/releases)
    - [Commits](https://github.com/zslayton/cron/commits)
    
    ---
    updated-dependencies:
    - dependency-name: cron
      dependency-version: 0.16.0
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • chore(deps): bump toml from 0.8.23 to 1.1.2+spec-1.1.0 in /ecc2 (#2261)
    Bumps [toml](https://github.com/toml-rs/toml) from 0.8.23 to 1.1.2+spec-1.1.0.
    - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.23...toml-v1.1.2)
    
    ---
    updated-dependencies:
    - dependency-name: toml
      dependency-version: 1.1.2+spec-1.1.0
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • docs: add official-sources security warning to README (#2248)
    * docs: add official-sources security warning to README
    
    Add a GFM [!WARNING] alert near the top of README.md identifying
    github.com/affaan-m/ECC and the ecc-universal / ecc-agentshield npm
    packages as the only verified distribution channels, and warning users
    that third-party re-uploads may contain malware.
    
    Closes #2242
    
    * Update README.md
    
    Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
    Co-authored-by: Affaan Mustafa <affaan.mustafa09@gmail.com>
    Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
  • fix: context-size /compact trigger, Codex marketplace plugin path, live README badges (#2237)
    - suggest-compact hook now reads the latest usage record from the session
      transcript and suggests /compact at a window-scaled token threshold
      (160k/200k window, 250k/1M window; COMPACT_CONTEXT_THRESHOLD and
      COMPACT_CONTEXT_INTERVAL overridable), re-firing per 60k-token growth
      bucket; tool-call count stays as the secondary signal (#2155)
    - Codex repo marketplace now points at ./plugins/ecc instead of ./ — Codex
      never discovers plugins whose local marketplace source.path is the
      marketplace root (verified on Codex CLI 0.137.0); plugins/ecc is a thin
      folder referencing root skills/.mcp.json per maintainer direction on
      #2097; docs flag plugin mode as experimental with the upstream blocker
      openai/codex#26037 linked (#2128)
    - README badges for installs/stars/forks now use shields endpoint badges
      backed by api.ecc.tools (live install count 3,712 vs the stale static
      150), which also eliminates shields' 'Unable to select next GitHub token
      from pool' render in the stars badge
    
    Closes #2155
    Closes #2128
  • chore(deps): bump rusqlite from 0.32.1 to 0.40.1 in /ecc2 (#2211)
    * chore(deps): bump rusqlite from 0.32.1 to 0.40.1 in /ecc2
    
    Bumps [rusqlite](https://github.com/rusqlite/rusqlite) from 0.32.1 to 0.40.1.
    - [Release notes](https://github.com/rusqlite/rusqlite/releases)
    - [Changelog](https://github.com/rusqlite/rusqlite/blob/master/Changelog.md)
    - [Commits](https://github.com/rusqlite/rusqlite/compare/v0.32.1...v0.40.1)
    
    ---
    updated-dependencies:
    - dependency-name: rusqlite
      dependency-version: 0.40.1
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    * fix(ecc2): cast u64 columns at sqlite boundary for rusqlite 0.40
    
    rusqlite 0.40 removed the u64 ToSql/FromSql impls (SQLite stores
    INTEGER as i64). Cast token counts, durations, counts, and paging
    values to/from i64 at each bind/read site in session/store.rs.
    
    ---------
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
  • chore(deps): bump crossterm from 0.28.1 to 0.29.0 in /ecc2 (#2210)
    * chore(deps): bump crossterm from 0.28.1 to 0.29.0 in /ecc2
    
    Bumps [crossterm](https://github.com/crossterm-rs/crossterm) from 0.28.1 to 0.29.0.
    - [Release notes](https://github.com/crossterm-rs/crossterm/releases)
    - [Changelog](https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/crossterm-rs/crossterm/commits/0.29)
    
    ---
    updated-dependencies:
    - dependency-name: crossterm
      dependency-version: 0.29.0
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    * fix(ecc2): switch ratatui feature to crossterm_0_29
    
    Keep a single crossterm version in the tree after the 0.29 bump;
    with crossterm_0_28 the lockfile carried both 0.28.1 and 0.29.0.
    
    ---------
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
  • fix(assets): replace hero brand mark with website coral circuit mark (#2232)
    * fix(assets): replace hero brand mark with website coral circuit mark
    
    The top-left mark in the hero banner was the assets/ecc-icon.svg double-E
    lettermark, not the actual brand logo. Swap in the coral vector circuit
    mark from the ECC-website header (src/styles/brandMarks.ts), keeping the
    ~70px footprint, the soft coral glow, and every other element identical.
    PNG re-rendered at 2400x1350 via sharp with palette compression.
    
    * docs: sync skill count to 262 across catalog surfaces
    
    catalog:check was failing on main after config-gc (#2216) landed without
    a count bump. Ran npm run catalog:sync.
  • fix(ecc2): port webhook sender to ureq 3 Agent API (#2231)
    #2209 bumped ureq to 3.x but the AgentBuilder-based webhook sender
    was not ported (branch update raced the merge). ureq 3 replaces
    AgentBuilder with Agent::config_builder(); timeouts are Option-wrapped
    and status() returns http::StatusCode.
  • chore(deps): bump ureq from 2.12.1 to 3.3.0 in /ecc2 (#2209)
    Bumps [ureq](https://github.com/algesten/ureq) from 2.12.1 to 3.3.0.
    - [Changelog](https://github.com/algesten/ureq/blob/main/CHANGELOG.md)
    - [Commits](https://github.com/algesten/ureq/compare/2.12.1...3.3.0)
    
    ---
    updated-dependencies:
    - dependency-name: ureq
      dependency-version: 3.3.0
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • docs: sync skill count to 262 after config-gc skill landed (#2230)
    npm run catalog:sync — #2216 added skills/config-gc without bumping
    documented counts, leaving catalog:check (and npm test) red on main.
  • chore(deps): bump sha2 from 0.10.9 to 0.11.0 in /ecc2 (#2208)
    * chore(deps): bump sha2 from 0.10.9 to 0.11.0 in /ecc2
    
    Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.9 to 0.11.0.
    - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0)
    
    ---
    updated-dependencies:
    - dependency-name: sha2
      dependency-version: 0.11.0
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    * fix(ecc2): hex-encode sha2 0.11 digest output manually
    
    sha2 0.11 (digest 0.11 / hybrid-array) output arrays no longer
    implement LowerHex, so format the fingerprint bytes directly.
    
    ---------
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
  • docs: restore hero banner with ECC wordmark, v2.0.0 badge, and brand lettermark (#2229)
    Recreates the v1.10 hero banner design (sourced from commit 602894ef)
    that PR #2225 replaced with a plain HTML header:
    
    - Wordmark and breadcrumb now read ECC / affaan-m/ECC
    - Version badge reads v2.0.0 · Jun 2026, eyebrow updated to V2.0
    - Top-left mark is the actual assets/ecc-icon.svg lettermark (amber E,
      coral CC) instead of a generic coral square
    - Catalog columns refreshed with live counts (261 skills, 64 agents,
      84 commands, 409 catalog) and real item names from the repo
    - Harness pills updated to the current README list (Claude Code, Codex,
      Cursor, OpenCode, Gemini, Zed, Copilot)
    - SVG source committed as assets/hero.svg so future edits never need
      image archaeology; rendered to PNG at 2400x1350 via sharp
    
    README hero line restored to the markdown image; badges, sponsor table,
    and guide cards from #2225 kept intact.
  • docs(zh-CN): translate ecc-guide and parallel-execution-optimizer skills (#2217)
    * docs(zh-CN): translate ecc-guide and parallel-execution-optimizer skills
    
    Adds Simplified Chinese translations for two untranslated skills,
    following the existing docs/zh-CN/skills/ conventions (frontmatter
    name/origin preserved, code blocks and output templates kept in
    English, prose fully translated).
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * docs(zh-CN): polish two phrasings per review
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
  • feat(skills): add config-gc skill (#2216)
    * feat(skills): add config-gc skill
    
    Garbage collection for Claude Code configuration sprawl: 8 scan
    channels (skills, memory, hooks, permissions, MCP, reminders,
    project history, caches), confirm-each-deletion human-in-the-loop,
    soft-delete with undo log. Subtractive counterpart to
    workspace-surface-audit and configure-ecc.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(skills): address review feedback on config-gc
    
    - Replace invalid comment-out strategy for JSON permission files with
      backup + gc_log entry + jq array removal (cubic P1)
    - Swap GNU-only find -printf for portable du -k (works on macOS/BSD)
    - Capture gc date once into a variable so trash dir and undo log agree
    - Simplify shadowed-permission detection with jq index() guard
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
  • docs(zh-CN): add Chinese translation of SKILL-DEVELOPMENT-GUIDE (#2200)
    * docs(zh-CN): add Chinese translation of SKILL-DEVELOPMENT-GUIDE
    
    Translate the comprehensive Skill Development Guide to Chinese,
    enabling Chinese-speaking contributors to learn how to create
    effective ECC skills.
    
    * fix(docs): correct all relative links in zh-CN translation
    
    Fix CONTRIBUTING.md link to zh-CN local copy, and skills links
    to point to repo-root skills/ directory instead of non-existent
    docs/skills/.
    
    ---------
    
    Co-authored-by: lege962 <1515808962@qq.com>
    Co-authored-by: legeZZZ <277193585+legeZZZ@users.noreply.github.com>
  • chore: pin rust toolchain to 1.96 for edition2024 deps (#2228)
    - add ecc2/rust-toolchain.toml pinning stable 1.96 (deps now require
      edition2024, which needs rustc 1.85+; local 1.84 could no longer build)
    - make git test fixtures hermetic: disable core.hooksPath inside temp
      repos so global identity-checking pre-push hooks cannot fail tests
  • fix: stability batch — hook stdin truncation, Codex exa TOML, Stop hook JSON, GateGuard repetition (#2227)
    * fix(hooks): fail open on oversized stdin instead of echoing truncated JSON (#2222)
    
    run-with-flags.js capped stdin at 1MB but every fallthrough path still
    echoed the truncated string to stdout. The harness parses hook stdout as
    JSON, got a document cut mid-stream, and blocked the tool call — so any
    Edit/Write with a >1MB hook payload was permanently blocked by every
    registered pre-write hook, before ECC_HOOK_PROFILE / ECC_DISABLED_HOOKS
    gating could run.
    
    - Exit 0 with empty stdout (no opinion) when the stdin cap trips, before
      any echo or gating logic.
    - Flush stdout via write callback before process.exit: exiting right
      after stdout.write() dropped everything past the ~64KB pipe buffer,
      cutting even sub-cap pass-through payloads mid-JSON.
    
    Regression tests cover the enabled, disabled, and missing-arg paths for
    oversized payloads plus full echo of sub-cap >64KB payloads.
    
    * fix(codex): stop emitting invalid exa url entry, align merge with connector policy (#2224)
    
    The Codex MCP merge declared exa with a url key, but Codex's
    [mcp_servers.*] TOML schema is stdio-only — the url key makes the
    entire config.toml fail to load, bricking both the codex CLI and the
    desktop app. Every install/update re-injected the line because the
    urlEntry branch treated the broken entry as present.
    
    - ECC_SERVERS now emits only the current default set per
      docs/MCP-CONNECTOR-POLICY.md: chrome-devtools (stdio, command/args).
      Retired servers (supabase, playwright, context7, exa, github, memory,
      sequential-thinking) are never re-emitted; existing user-managed
      entries are untouched.
    - The merge now repairs the exact ECC-emitted broken form (url-only
      exa entry) on every run so re-running the installer fixes broken
      configs instead of preserving them. User stdio exa entries
      (command + mcp-remote) are left alone.
    - check-codex-global-state.sh requires chrome-devtools instead of the
      retired set, and flags url-only exa entries with a repair hint.
    
    Tests cover repair, re-run idempotence, stdio-entry preservation, and
    no-retired-server emission in add, update, dry-run, and disabled modes.
    
    * fix(hooks): never echo truncated stdin from Stop hooks (#2090)
    
    Stop hooks follow the ECC pass-through convention (echo stdin on
    stdout), but every echoing Stop hook capped stdin and echoed the capped
    string. The Stop payload carries last_assistant_message, so a long
    final assistant message produced a JSON document cut mid-stream on
    stdout, which the harness reports as 'Stop hook error: JSON validation
    failed' across the whole Stop chain.
    
    Reproduced: a Stop payload with a >64KB last_assistant_message run
    through run-with-flags + cost-tracker emitted exactly 65536 bytes of
    invalid JSON (cost-tracker capped stdin at 64KB — far below realistic
    Stop payloads).
    
    - cost-tracker: raise the cap to 1MB (matching all other hooks) and
      suppress the pass-through echo when stdin was truncated.
    - check-console-log, stop-format-typecheck, desktop-notify: suppress
      the echo when stdin was truncated; flush stdout before process.exit
      so sub-cap payloads are not cut at the ~64KB pipe buffer.
    - All hooks keep exiting 0 (fail-open); diagnostics go to stderr.
    
    New stop-hooks-stdout test asserts the contract for every registered
    Stop hook: stdout is empty or valid JSON, exit code 0 — for realistic
    100KB payloads and oversized >1MB payloads, via the production runner
    and via direct invocation. Updated the old hooks.test.js case that
    codified the truncated-echo behavior.
    
    * fix(hooks): dampen GateGuard fact-force repetition in long sessions (#2142)
    
    In long autonomous sessions the fact-force gate produced 10+
    near-identical 'state facts -> blocked -> restate -> retry' blocks in
    one context window, which measurably raises the odds of the model
    collapsing into a degenerate single-token repetition loop.
    
    - Track a per-session fact_force_denials counter in GateGuard state
      (merged max across concurrent writers, reset with the session, robust
      to malformed on-disk values).
    - The first GATEGUARD_FACT_FORCE_FULL_DENIALS denials (default 3) keep
      the full four-fact block; later denials emit a condensed single-line
      message that carries the denial ordinal, so consecutive denials are
      structurally different and never textually identical.
    - True retries of the same target remain allowed without re-prompting
      (unchanged). Destructive-Bash and routine-Bash gates are unchanged,
      as are the ECC_GATEGUARD=off / ECC_DISABLED_HOOKS escape hatches.
    
    Eight new tests cover budget counting, condensed format, ordinal
    advancement, retry pass-through, env tuning, malformed state, MultiEdit
    dampening, and destructive-gate exemption.
    
    * fix(hooks): keep security hooks able to block on oversized stdin (#2222)
    
    Refine the truncation fail-open: instead of skipping the hook entirely,
    the runner now suppresses only its own raw-echo when stdin was
    truncated. The hook still executes and receives the truncated flag
    (run() context / ECC_HOOK_INPUT_TRUNCATED), so config-protection keeps
    blocking truncated protected-config payloads (its test requires exit 2)
    while pass-through hooks fail open with empty stdout as before.
    
    * style: apply repo formatter to touched hook files
  • docs: restore on-brand ECC header, consolidate sponsor placement, make guide links visual (#2225)
    - Replace off-brand hero PNG (wrong product name + baked version) with a
      centered HTML header using assets/ecc-icon.svg, h1, and tagline
    - Consolidate duplicated sponsor sections: polished centered sponsor table
      at top (CodeRabbit, Greptile, community sponsors, sponsor links); bottom
      section reduced to a one-liner pointing to SPONSORS.md
    - Convert guide links to visual cards using the guides' own header images,
      linked to the local guide files
    - Fix broken tmux video URL in the shortform guide to the in-repo asset
  • chore(deps): bump the cargo-minor-and-patch group (#2207)
    Bumps the cargo-minor-and-patch group in /ecc2 with 8 updates:
    
    | Package | From | To |
    | --- | --- | --- |
    | [ratatui](https://github.com/ratatui/ratatui) | `0.30.0` | `0.30.1` |
    | [tokio](https://github.com/tokio-rs/tokio) | `1.50.0` | `1.52.3` |
    | [serde_json](https://github.com/serde-rs/json) | `1.0.149` | `1.0.150` |
    | [regex](https://github.com/rust-lang/regex) | `1.12.3` | `1.12.4` |
    | [clap](https://github.com/clap-rs/clap) | `4.6.0` | `4.6.1` |
    | [libc](https://github.com/rust-lang/libc) | `0.2.183` | `0.2.186` |
    | [chrono](https://github.com/chronotope/chrono) | `0.4.44` | `0.4.45` |
    | [uuid](https://github.com/uuid-rs/uuid) | `1.22.0` | `1.23.3` |
    
    
    Updates `ratatui` from 0.30.0 to 0.30.1
    - [Release notes](https://github.com/ratatui/ratatui/releases)
    - [Changelog](https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md)
    - [Commits](https://github.com/ratatui/ratatui/compare/ratatui-v0.30.0...ratatui-v0.30.1)
    
    Updates `tokio` from 1.50.0 to 1.52.3
    - [Release notes](https://github.com/tokio-rs/tokio/releases)
    - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.50.0...tokio-1.52.3)
    
    Updates `serde_json` from 1.0.149 to 1.0.150
    - [Release notes](https://github.com/serde-rs/json/releases)
    - [Commits](https://github.com/serde-rs/json/compare/v1.0.149...v1.0.150)
    
    Updates `regex` from 1.12.3 to 1.12.4
    - [Release notes](https://github.com/rust-lang/regex/releases)
    - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/rust-lang/regex/compare/1.12.3...1.12.4)
    
    Updates `clap` from 4.6.0 to 4.6.1
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.0...clap_complete-v4.6.1)
    
    Updates `libc` from 0.2.183 to 0.2.186
    - [Release notes](https://github.com/rust-lang/libc/releases)
    - [Changelog](https://github.com/rust-lang/libc/blob/0.2.186/CHANGELOG.md)
    - [Commits](https://github.com/rust-lang/libc/compare/0.2.183...0.2.186)
    
    Updates `chrono` from 0.4.44 to 0.4.45
    - [Release notes](https://github.com/chronotope/chrono/releases)
    - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
    - [Commits](https://github.com/chronotope/chrono/compare/v0.4.44...v0.4.45)
    
    Updates `uuid` from 1.22.0 to 1.23.3
    - [Release notes](https://github.com/uuid-rs/uuid/releases)
    - [Commits](https://github.com/uuid-rs/uuid/compare/v1.22.0...v1.23.3)
    
    ---
    updated-dependencies:
    - dependency-name: ratatui
      dependency-version: 0.30.1
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: tokio
      dependency-version: 1.52.3
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: cargo-minor-and-patch
    - dependency-name: serde_json
      dependency-version: 1.0.150
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: regex
      dependency-version: 1.12.4
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: clap
      dependency-version: 4.6.1
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: libc
      dependency-version: 0.2.186
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: chrono
      dependency-version: 0.4.45
      dependency-type: direct:production
      update-type: version-update:semver-patch
      dependency-group: cargo-minor-and-patch
    - dependency-name: uuid
      dependency-version: 1.23.3
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: cargo-minor-and-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • chore(deps-dev): bump the npm-minor-and-patch group across 1 directory with 2 updates (#2205)
    Bumps the npm-minor-and-patch group with 2 updates in the / directory: @opencode-ai/plugin and [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).
    
    
    Updates `@opencode-ai/plugin` from 1.15.3 to 1.16.2
    
    Updates `@types/node` from 25.7.0 to 25.9.2
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
    
    ---
    updated-dependencies:
    - dependency-name: "@opencode-ai/plugin"
      dependency-version: 1.16.2
      dependency-type: direct:development
      update-type: version-update:semver-minor
      dependency-group: npm-minor-and-patch
    - dependency-name: "@types/node"
      dependency-version: 25.9.2
      dependency-type: direct:development
      update-type: version-update:semver-minor
      dependency-group: npm-minor-and-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • chore(deps): bump actions/setup-node (#2204)
    Bumps the actions-minor-and-patch group with 1 update in the / directory: [actions/setup-node](https://github.com/actions/setup-node).
    
    
    Updates `actions/setup-node` from 6.3.0 to 6.4.0
    - [Release notes](https://github.com/actions/setup-node/releases)
    - [Commits](https://github.com/actions/setup-node/compare/53b83947a5a98c8d113130e565377fae1a50d02f...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e)
    
    ---
    updated-dependencies:
    - dependency-name: actions/setup-node
      dependency-version: 6.4.0
      dependency-type: direct:production
      update-type: version-update:semver-minor
      dependency-group: actions-minor-and-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • feat(mcp): single-connector default set + connector policy (#2219)
    Reduce the default .mcp.json to one connector (chrome-devtools) per the
    new policy in docs/MCP-CONNECTOR-POLICY.md: a default earns its slot only
    if it is universal AND MCP beats a CLI/API wrapped in a skill. June 2026
    audit verdicts: github -> gh via github-ops skill; context7 -> REST via
    documentation-lookup; exa -> harness-native search (+ exa-search skill);
    memory -> native harness memory + instincts; playwright -> playwright CLI
    skills (vendor moved agent flows off MCP); sequential-thinking -> native
    extended thinking. All six remain opt-in in mcp-configs/mcp-servers.json.
    Tests updated: plugin-manifest policy assertions + install-apply Cursor
    expectations.
    
    Co-authored-by: ECC Test <ecc@example.test>
  • release: 2.0.0 — the agent harness operating system
    Graduate 2.0.0-rc.1 to stable. Bump version across package, plugin,
    marketplace, OpenCode, agent metadata, VERSION, and all localized docs.
    Add 2.0.0 release notes + README sections (en/zh/pt-BR/tr), CHANGELOG
    entry, and the ECC community Discord bot (dependency-free gateway client
    + guild command registrar). Update copilot-support and release-surface
    tests for the sponsored-review migration and the 2.0.0 surface.
  • feat(discord): release -> #announcements auto-post + pin + GitHub Discussions (#2201)
    On a published GitHub release, post the notes to the ECC Discord
    #announcements channel (via bot), pin it, and cross-post to GitHub
    Discussions (Announcements category). Release data flows through env vars
    (no shell interpolation of untrusted input). Secrets: DISCORD_BOT_TOKEN,
    DISCORD_ANNOUNCE_CHANNEL_ID (repo secrets), GITHUB_TOKEN.
    
    Ties the 2.0.0/1.11.0 official release to the community launch.
    
    Co-authored-by: ECC Test <ecc@example.test>
  • feat: add orch-* orchestrator skill family (#2153)
    * feat: add orch-* orchestrator skill family
    
    Lightweight wrappers that orchestrate existing ECC agents through a gated Research -> Plan -> TDD -> Review -> Commit pipeline, right-sized per task.
    
    - orch-pipeline: shared engine (phases, size classifier, two gates, agent map)
    - orch-add-feature/change-feature/fix-defect/refine-code/build-mvp: thin wrappers delegating to the engine
    
    * chore: register orch-* family in catalog, command registry, and agent.yaml (post-rebase onto green main)
    
    ---------
    
    Co-authored-by: ECC Test <ecc@example.test>
  • fix: make plugin hooks run on Node 21+ and green the suite under modern Node (#2184)
    ROOT CAUSE: hooks load plugin-hook-bootstrap.js via
    `node -e "...; process.argv.splice(1,0,s); require(s)"`. On Node 21+,
    require.main is `undefined` under --eval, so the `if (require.main === module)`
    guard was false and main() never ran — every plugin hook silently no-op'd
    (e.g. the MCP-health PreToolUse hook stopped blocking). CI (Node 18/20) hid
    this; it only surfaces on Node 21+. Fix: also run main() when require.main is
    undefined (the eval-bootstrap case), while staying dormant on real imports.
    
    Also clears pre-existing main debt the full local suite enforces:
    - catalog:sync — README/docs agent+skill counts drifted after recent merges
    - tests/ci/supply-chain-watch-workflow: update checkout SHA to the merged v6.0.3 (#2183)
    - markdownlint + check-unicode-safety --write across docs/skills
    
    Suite: 2683/2683 green under Node v25; lint + unicode clean.
    
    Co-authored-by: ECC Test <ecc@example.test>