Commit Graph
3943 Commits
Author SHA1 Message Date
Affaan Mustafa 34de45f210 fix(hooks): enforce loader-documented keys in shipped hooks configs (#3163)
hooks/hooks.json already ships only schema-valid keys with metadata in the
hooks.metadata.json sidecar. Add scripts/ci/check-hooks-schema-keys.js, a
strict allowlist check that fails when hooks/hooks.json or
hooks/codex-hooks.json carry any key outside their loader's documented set,
wire it into the npm test chain, and cover it with fixture tests.

Refs #3138, #3114
2026-09-18 18:37:40 -04:00
Affaan Mustafa da214d73b7 fix: stop home installs copying .agents into ~/.claude and ~/.codex 2026-09-18 18:37:05 -04:00
Affaan Mustafa db61d1c76a fix(gateguard): warn that parallel-batch siblings may already be applied (#3136)
A first-touch Edit/Write denial marks the file checked so the retry
passes. Sibling edits to the same file in the same parallel batch are
therefore judged against post-denial state and silently apply, leaving
the file in a state neither version intended.

Hooks see tool calls one at a time, so a batch-wide lock is not
possible. Instead make the partial application explicit: the Edit,
Write, MultiEdit, and condensed denials now name the file and warn
that other edits from the same batch may already have been applied,
and SKILL.md tells agents to send dependent edits sequentially and
re-read the file after a gated batch.
2026-09-18 18:37:01 -04:00
affaan-m 4be4eb4cf3 fix(install): reconcile OpenCode hook consent with current main
Preserve the contributor change and current installer contracts. Make automatically discovered plugin entrypoints inert without explicit runtime consent, verify managed ownership before deactivation, and retain prior consent on incomplete migration.

Source-PR: https://github.com/affaan-m/ECC/pull/3008
Source-Head: f8c0c2c182
2026-09-18 18:35:19 -04:00
affaan-m 0a1e0780d3 fix(ci): reconcile catalog validation with current main
Preserve the contributor implementation, synchronize summaries to the current tree, and keep the unrelated installer timeout unchanged.

Source-PR: https://github.com/affaan-m/ECC/pull/3060

Source-Head: 3a9c2b2589
2026-09-18 18:30:39 -04:00
Affaan Mustafa ab66f51a29 docs: repair README badges and live star history 2026-09-18 17:04:08 -04:00
Affaan Mustafa b15f7d8171 docs(mcp): expose memory auth boundary (#3134)
* fix(memory): classify directory traversal failures

* docs(mcp): expose memory auth boundary
2026-09-18 17:01:14 -04:00
Seekers2001 3155504f0b Merge remote-tracking branch 'upstream/main' into codex/docs-governance-audit-foundation 2026-09-18 17:34:11 +08:00
kenima-arcandClaude Fable 5.1 fc52d4375d docs(astra-review): point the workflow at /ecc:tdd-workflow
The guides referenced a non-existent /ecc:tdd command; the TDD entry
point is the tdd-workflow skill (/ecc:tdd-workflow), optionally fed a
*.plan.md from /ecc:plan.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 13:19:38 +09:00
kenima-arcandClaude Fable 5.1 5b4ebcf0f9 docs(astra-review): add day-to-day workflow for a separate project
Step-by-step section in the English and Japanese guides: plugin refresh
and Codex login check, creating the project and starting Claude Code
there, running /ecc:astra-review, committing on PASS, and gating the push.
Notes that the project does not need to live under the ECC checkout and
gives the installed script path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 10:22:11 +09:00
Juan Garibay 4869db30c4 fix(hooks): match the index case-insensitively, and isolate the pytest probe
Red-teaming the guard from 3c317470 found two more ways to get a repository's own
code executed. Both are demonstrated by a planted binary that appends to a witness
file, counted before and after.

Case folding. git matches index pathspecs case-sensitively even where
core.ignorecase is set, but APFS does not -- so a repository that commits
`.venv/bin/Python` gets `$venv/bin/python` opening and running that file while the
guard's lowercase query finds nothing in the index and reports it untracked. The
witness logged two invocations. It applies to `venv` and `env` as well, and to any
folding of the name. The query now uses a `:(icase)` pathspec; all nine
directory-by-spelling combinations are refused, and an untracked venv still runs.

Module shadowing. `python -c "import pytest"` puts the working directory first on
sys.path, so a repository that commits a `pytest.py` in its root has that file
imported, and executed, by a check whose only job is to answer whether pytest is
installed. The probe is now `python -I -c "import pytest"` on the virtualenv, uv
and poetry paths alike. Isolation does not hide a real pytest -- it lives in the
interpreter's own site-packages, confirmed against a venv holding pytest 9.1.1.

Still true, and not something this hook can fix: running the repository's declared
suite runs the repository's code. `pytest` imports conftest.py, and the Node arm
runs package.json scripts. That is what a pre-push verification hook is for. The
line this guard draws is narrower and worth keeping -- a capability probe, and the
choice of which interpreter to trust, should not be things the pushed repository
gets to decide.
2026-09-17 17:17:19 -04:00
Juan Garibay 3c31747016 fix(hooks): resolve the venv path before asking git whether it is tracked
The guard added in 9cdc40e6 was incomplete. `git ls-files` reports paths as they
are indexed and does not follow symlinks, so a repository that commits `.venv` as
a symlink to its own root alongside a tracked `bin/python` gets asked about
`.venv/bin/python` -- a path git has never heard of -- and the answer is
"untracked". The interpreter then runs. Measured on that shape: the planted
executable logged two invocations against 9cdc40e6 and none against this commit.

`repo_ships_interpreter` now resolves the bin directory with `cd -P`/`pwd -P`,
resolves the worktree root the same way, and asks git about the resolved path
relative to it. The three cases that matter all hold: a plainly committed venv is
still refused, the symlink shape is now refused, and a developer's own untracked
venv still resolves and runs.

`cd -P`/`pwd -P` rather than `realpath` or `readlink -f`, because neither is
portable to a stock macOS.
2026-09-17 16:55:11 -04:00
Juan Garibay ca1a5ad8bc fix(hooks): name the remedy in the blank-override failure
The hook is global and this message blocks a push, so "ECC_PYTEST_CMD is set but
names no command" left the operator holding a refusal with no next step. It now
says to point the variable at a runner or unset it to fall back to discovery,
which is the same advice the no-pytest-found branch already gives from the other
direction.
2026-09-17 16:51:43 -04:00
Juan Garibay 9cdc40e6d1 fix(hooks): do not run a virtualenv interpreter the repository ships
This branch taught the hook to run `.venv/bin/python`, and that is a binary the
repository can supply. On main the Python arm only ever ran `pytest` from PATH --
the developer's own -- and on a machine without one it ran nothing at all, which
is exactly the machine this branch was written for. So the exposure is new, and
it arrived with the fix.

The hook is installed globally through core.hooksPath. Cloning a hostile
repository, committing nothing, and pushing it to your own fork is enough: the
pre-push hook finds the committed `.venv/bin/python`, runs it once to probe for
pytest and again to run the suite. Reproduced -- the planted executable logged
two invocations under the previous commit and none under this one.

A virtualenv is never committed. It is platform-specific binaries and every
Python project gitignores it, so `git ls-files --error-unmatch` separates the
two cases exactly: a developer's own venv is untracked and still resolves, a
tracked one is skipped with the reason printed. An absolute $VIRTUAL_ENV outside
the worktree reads as untracked, as it should.

Not addressed here, and worth a maintainer's view: `uv run` and `poetry run`
resolve from the repository's own lockfile, so they carry the same shape of
trust in a form this check cannot see. They are gated behind a lockfile being
present, and changing their semantics is a larger decision than this fix.
2026-09-17 16:44:33 -04:00
Juan Garibay 08b173f12f fix(hooks): a blank ECC_PYTEST_CMD is an override, and say when one is in use
`[[ -n "${ECC_PYTEST_CMD:-}" ]]` asked whether the variable had a value, not
whether it was set, so `ECC_PYTEST_CMD=` fell through to virtualenv discovery
while `ECC_PYTEST_CMD="   "` failed the push. Two spellings of the same mistake,
two behaviours. Falling through is the wrong one: an override that evaluated to
nothing -- a command substitution that found no pytest, say -- then silently ran
a different runner than the operator named, which is exactly the substitution
this resolver refuses to make anywhere else. Both now fail closed.

`${ECC_PYTEST_CMD+set}` rather than `[[ -v ECC_PYTEST_CMD ]]`, because `-v` is
bash 4.2 and a stock macOS /bin/bash is 3.2, where it is not a false but a
syntax error. The hook runs under whatever `env bash` resolves to.

The override is still not probed -- probing runs the operator's command, and a
wrapper that ignores `--version` executes the whole suite and is then rejected
for not printing a version. What the gate can honestly do about a stale override
is refuse to be quiet about it, so a push that uses one now says so, every time,
and says the hook has not checked that it is pytest. A bypass that announces
itself is not the silent gate this resolver exists to prevent.

The fixture env is built from nothing instead of inheriting process.env with two
keys blanked. Blanking is no longer neutral: a blanked ECC_PYTEST_CMD is now an
override, and every one of these tests would have taken that branch.
2026-09-17 16:33:37 -04:00
Juan Garibay c6195edb2f fix(hooks): stop probing the pytest override, and stop failing on exit 5
Three defects, found by reviewing this branch against a running pytest rather
than by reading it.

Exit 5 is not a failure. pytest reserves it for NO_TESTS_COLLECTED, and
`|| fail "pytest failed"` collapsed it into a blocked push. The `|| fail`
predates this branch, but this branch is what makes it reachable: a repository
whose pyproject.toml only configures ruff or black, with pytest in its venv and
no test files, used to hit the "pytest is not installed" skip and now gets
gated. $VIRTUAL_ENV is the first candidate, so merely having a venv activated in
the pushing shell drags any requirements.txt repository into this path, and the
hook is installed globally. Reproduced with pytest 9.1.1. Exit 5 is now
non-blocking but loud -- a bad rootdir, testpaths or an unimportable conftest
also collects nothing, and swallowing that silently would reopen the hole this
resolver exists to close. Other non-zero codes now carry the code, because 1
(tests failed) and 4 (usage error) call for different responses.

The ECC_PYTEST_CMD probe ran the operator's command. Validating the override
with `--version` assumed it would answer like pytest. A wrapper that sets an
environment variable and execs pytest ignores the flag and runs the whole suite,
so the probe executed the tests, then rejected the command for not printing a
version, then blocked the push -- with the suite green. That is worse than the
silent gate the probe was added to close, so the override is taken as given
again: it is a deliberate setting, the hook cannot inspect it without running
it, and pointing it at something that is not pytest is the operator's call.
`is_pytest` still guards the PATH candidate, which this script composes itself,
where `pytest --version` is harmless. An empty override still fails closed.

The tests inherited the ambient environment. `runHermeticPythonPrePush` passed
process.env through, so an exported ECC_PYTEST_CMD or an activated virtualenv
resolved a pytest the fixture never created and the venv test failed for anyone
who runs the suite that way. Both variables are now neutralised in the base env.

Coverage: the gate had no test proving it blocks. Changing the run line to
`|| true` left all three previous tests green. Seven now cover a spaced venv
path, a red suite, exit 5, an override invoked exactly once with no probe, an
empty override, and the PATH candidate in both directions.
2026-09-17 16:19:57 -04:00
Juan Garibay 1f5cd2af73 test(hooks): build the pre-push python fixture env without mutation
AGENTS.md makes immutability mandatory and the helper built `env` by assigning
into it. Rather than reassigning a `let` through spreads, the two stub paths are
now resolved before the object exists, so `env` is a single `const` built in one
expression with the conditional keys spread in. Nothing to mutate and nothing to
rebind.
2026-09-17 16:04:41 -04:00
Juan Garibay 5cbe78c22b fix(hooks): keep venv paths intact and check every pytest candidate
Two holes in the resolver this branch added, both found in review.

A virtualenv path may contain spaces. `resolve_pytest` returned one string and
the caller expanded it unquoted, so `/home/me/my env/bin/python -m pytest` split
into `/home/me/my` and `env/bin/python`. The probe that accepted the candidate
was correctly quoted, so the hook reported the venv as usable and then failed to
run anything in it -- rejecting the push for a reason with nothing to do with
the code being pushed. It now builds an argv array and runs `"${PYTEST_CMD[@]}"`.

The resolver's contract is that every candidate is confirmed to be pytest, and
two of them were not. `ECC_PYTEST_CMD` was returned unchecked, so
`ECC_PYTEST_CMD=true` made the hook run `true -q`, exit 0 and report a Python
project verified by nothing. The PATH branch used `command -v pytest`, which
proves only that a file of that name exists. Both now go through `is_pytest`,
which runs `--version` and requires the output to name pytest -- `--version`
alone is not evidence, since `true --version` also exits 0.

A bad `ECC_PYTEST_CMD` fails the push rather than falling through to the next
candidate. An operator who set it asked for that command, and silently running
a different one hides the misconfiguration -- which is the same silent-gate
failure this branch exists to remove, one level along.

Three regression tests cover the three paths: a venv whose directory name
contains a space, an override that is not pytest, and an override that is.
2026-09-17 15:57:09 -04:00
Juan Garibay fc6fe5e5df fix(hooks): pre-push skipped every Python project that uses a virtualenv
The Python block gates on `command -v pytest`, so it only runs when pytest is
on PATH. Installing a project's tools into a virtualenv is the norm rather
than the exception, so in practice the hook printed

    [ECC pre-push] Python project detected but pytest is not installed. Skipping.

while standing in a directory with `.venv/bin/pytest` in it, and pushed.

The failure mode is worse than not having the hook. A skip line reads like a
pass: the push succeeds, the output looks healthy, and nothing indicates the
gate declined to gate. A repository can sit behind it for months believing
its tests run on every push. Found on a project with 893 tests, none of which
the hook had ever executed.

`resolve_pytest` now looks, in order, at `ECC_PYTEST_CMD`, `$VIRTUAL_ENV`,
`.venv`, `venv`, `env`, `uv run` when a `uv.lock` is present, `poetry run`
when a `poetry.lock` is, and finally PATH. Each candidate is confirmed by
importing pytest rather than by the path existing, so a half-built venv falls
through to the next one instead of failing the push.

Two deliberate choices:

The log line names the command it resolved -- `Running: .venv/bin/python -m
pytest -q` -- so which interpreter ran is visible in the push output rather
than inferred. When nothing resolves, the message says where it looked and
names `ECC_PYTEST_CMD`, instead of asserting pytest is not installed when it
may well be.

`uv run` passes `--no-sync` so the hook cannot mutate the developer's
environment on its way to running the tests.

Behaviour change worth flagging for the release note: on any Python project
with a working virtualenv this hook now actually runs the suite, and will
block a push whose tests fail. That is the intent, but it is new behaviour
for every such repository, and `ECC_SKIP_PREPUSH=1` remains the escape.

Verified on two real repositories: a uv/venv Python project (resolves
`.venv/bin/python -m pytest`, 893 tests, exits 0; exits 1 when the suite
fails) and a Node project (unchanged, still runs lint/typecheck/test/build).
2026-09-17 15:06:49 -04:00
Sharad. 6e024eb881 docs(rules): fix ECC plugin agent location and ecc: prefix 2026-09-18 00:19:40 +05:30
Affaan Mustafa dd6ee538ae Merge pull request #3156 from affaan-m/fix/sponsor-status-20260917
docs: move Atlas Cloud to past sponsors
2026-09-17 14:04:06 -04:00
Frank_zhu 7cfc9b3608 fix(gateguard): ignore heredoc prose for tee and path-qualified sinks (#2886)
Expand proven-passive heredoc recognition beyond bare `cat` so documentation
writes via `tee`, `/bin/cat`, and `command cat` no longer trip the destructive
command detector on body text, while still failing closed for shells and pipes.
2026-09-17 17:29:26 +00:00
Affaan Mustafa 15cd6ff506 docs: archive Atlas Cloud sponsorship 2026-09-17 13:13:17 -04:00
Jasir Zaeemandgreptile-apps[bot] bb1c58a350 docs: Add SerpApi as a sponsor (#3155)
* docs: add SerpApi as a new sponsor

* Remove extra anchor closing tag

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-09-17 12:46:44 -04:00
kenima-arcandClaude Fable 5.1 1d143e3098 docs(ja-JP): refresh Japanese README to match the English README
Full retranslation of README.md (structure preserved 1:1): 2.2 install
flows, Codex and Kimi support, platform tables, security, and
troubleshooting. Relative links rewritten for docs/ja-JP/ and in-page
anchors mapped to the Japanese headings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 00:41:25 +09:00
kenima-arcandClaude Fable 5.1 f81a375de9 docs(astra-review): add usage guide in English and Japanese
Full manual for /astra-review: setup (Codex CLI, ChatGPT login, plugin
freshness), scopes, script options and exit codes, verdict format, the fix
loop, push gating, what leaves the machine, troubleshooting, and limits.
Linked from both READMEs, the Japanese quick reference, and the command docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 00:18:44 +09:00
Suliman Abdulrazzaq ab53d62604 docs(gateguard): note the denial cap is best effort under concurrent hooks
Concurrent hook processes can lose a fact_force_denials increment, which only adds denials; say so where the variable is documented as capping the total.
2026-09-17 18:09:30 +03:00
kenima-arcandClaude Fable 5.1 4018d3dc56 fix(astra-review): harden report writing and make tests portable
Findings from three /astra-review rounds on the previous commit:

- writeReport: write to an exclusively created 0600 temp file in the
  destination directory and rename it into place. Removes the lstat/write
  race, replaces (never follows) a pre-existing symlink, and tightens
  permissions on an existing world-readable report. Full-write semantics via
  writeFileSync on the descriptor; temp file removed on any failure.
- scope: normalize the git toplevel and cwd with path.resolve before
  realpath (git reports forward slashes on Windows) and display file paths
  git-style with forward slashes.
- tests: build fixture roots with path.resolve/path.join so containment
  checks hold on Windows; skip POSIX permission and symlink assertions where
  the platform cannot support them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 00:07:00 +09:00
kenima-arcandClaude Fable 5.1 946b80198f feat: add /astra-review cross-provider code review via Codex CLI
Send Claude-written code to GPT-6-Astra (Codex CLI, ChatGPT login) for an
independent review and return a structured PASS/FAIL verdict with
severity-tagged findings.

- commands/astra-review.md (+ ja-JP): review, fix, re-run workflow
- scripts/astra-review.js + scripts/lib/astra-review/{scope,prompt,codex}.js
- scopes: uncommitted, --base, --commit, --files, --files-from-commit
- reviewer isolation: read-only sandbox, web search off, user config
  skipped, every configured MCP server disabled by name, filtered env
- safe collection: no symlink following, repo containment, --no-ext-diff,
  NUL-delimited inventories, explicit failure on overflow
- 87 tests; registry, agent.yaml, package files, install manifest updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 00:07:00 +09:00
Suliman Abdulrazzaq 32d0201b53 docs(gateguard): say when the denial cap starts allowing new paths
The first N new paths are denied and later ones pass (denials > cap at the Edit/Write and MultiEdit gates), so describe the switch as happening after the configured number of denials.
2026-09-17 17:05:12 +03:00
Suliman Abdulrazzaq 09c8069fb0 docs(gateguard): note that the denial cap also covers MultiEdit 2026-09-17 15:55:11 +03:00
Suliman Abdulrazzaq bc464fd42c chore: restore yarn.lock from main
ef0a487 regenerated yarn.lock with Yarn classic (lockfile v1), but the
repository pins yarn@4.9.2, so hardened installs on pull requests reject
the rewrite (YN0028). Restore the merge-base lockfile; this PR changes no
dependencies.
2026-09-17 15:53:25 +03:00
Md. Kishor MorolandKishor Morol 6f967dcee4 fix(bengali): version-safe collation check, accurate \w guidance
The pg_collation check referenced colllocale unconditionally. That column
only exists on PostgreSQL 17+; 15-16 call it colliculocale and <= 14 keep
the ICU locale in collcollate, so the query failed with "column does not
exist" on anything older than 17. Read the columns through to_jsonb(c),
which tolerates missing keys. Verified against postgres:14, :16 and :17 —
all return icu_provider = t, locale = bn-BD.

The reviewer's regex rule flagged `\w` unconditionally. In Python str
patterns `\w` does match Bengali letters, but not vowel signs or hasanta
(category M), so `re.findall(r'\w+', 'রহিম')` gives ['রহ', 'ম']. Say
that precisely, note where `\w` is ASCII-only (JavaScript, re.ASCII), and
point at [ঀ-৿] or \p{Bengali} instead.

Co-Authored-By: Kishor Morol <kishormorol@gmail.com>
2026-09-17 08:28:24 -04:00
Md. Kishor MorolandKishor Morol bcb23704a8 fix(install): accept --locale bn
locale:bn was the only locale component with no --locale alias, so the
Bengali docs were reachable through `--with locale:bn` but `--locale bn`
was rejected as an unsupported locale.

Register bn (and the bn-BD alias, matching the ja-JP/zh-CN pattern) in
SUPPORTED_LOCALES and LOCALE_ALIAS_TO_COMPONENT_ID.

The existing test only checked the forward direction — that every alias
resolves to a real component — which is why this gap passed. Add the
reverse assertion: every locale component must be reachable through
--locale.

Co-Authored-By: Kishor Morol <kishormorol@gmail.com>
2026-09-17 01:30:45 -04:00
Md. Kishor MorolandKishor Morol f70e5c1c47 chore: merge main and address outstanding review feedback
Resolve the 19 conflicts from 314 upstream commits (all language-selector
and catalog-count lines), then fix the review threads still open on #2655.

Merge resolution:
- Keep both new locales: every language selector now lists Українська and বাংলা,
  including the selectors that previously carried only one of them.
- Resync catalog counts to 69 agents / 293 skills across README.md, AGENTS.md,
  README.zh-CN.md, docs/zh-CN/*, docs/tr/AGENTS.md, and the plugin manifests.

Review fixes:
- install-components.json: drop the explicit skill:bengali-nlp -> framework-language
  mapping so the selector resolves to the generated single-skill component.
  Selecting it installed 70 skill paths plus core modules; it now installs
  skills/bengali-nlp only. (Greptile P1)
- docs/bn/README.md: point the Stars/Forks/Contributors badges at affaan-m/ECC
  instead of affaan-m/everything-claude-code, align the header with the other
  translations, add the 2.2.1 release section, and update 67+/281+ to 69/293.
- skills/bengali-nlp/SKILL.md: split the U+09F0-U+09FA row by character type;
  reject empty search queries; replace the delimiter-only prompt boundary with
  structured messages; require provider and locale checks before relying on the
  bn-BD ICU collation; rewrite the isdigit() anti-pattern, which claimed the
  method misses Bengali digits when it accepts them; add Best Practices and
  Related Skills per the CONTRIBUTING template.
- agents/bengali-reviewer.md: HIGH findings now need a fix or a written waiver
  with an owner and expiry, otherwise the verdict is BLOCK.
- tests/ci/bengali-language-surface.test.js: parse fences so an unclosed
  ```python block fails, track a missing interpreter as skipped rather than
  passed, assert the single-skill install plan, and check every language
  selector instead of only the root README.

Co-Authored-By: Kishor Morol <kishormorol@gmail.com>
2026-09-17 01:11:01 -04:00
Affaan Mustafa a0283ac561 docs: add lane rules and Ito desk relationship notes (2026-09-16) 2026-09-17 00:11:40 -04:00
Aniruddha Adak 6502cf24bf fix(llm): forward max_tokens to Ollama num_predict 2026-09-17 02:33:20 +05:30
yashraj4 e404468a62 fix: correct agent location and add ecc: prefix to agent names in rules
- rules/common/agents.md: Fix incorrect location (was ~/.claude/agents/, now explains plugin ships with ecc@ecc)
- Add ecc: prefix to all agent names in tables and orchestration sections
- Update all 4 translated copies (es, ja-JP, zh-CN, tr) with same fixes
- Update root AGENTS.md with ecc: prefix for consistency

Fixes #3143
2026-09-16 23:07:27 +05:30
SulimanAbdulrazzaqandClaude Opus 5 ef0a487edd fix(gateguard): validate the denial cap as a whole integer
Review findings on the rebased branch.

Number.parseInt accepted partial values, so GATEGUARD_FACT_FORCE_MAX_DENIALS
set to '3.5', '3oops', or '0x3' silently became a finite cap of 3 and weakened
the gate on a typo. The value is now matched whole and anything that is not a
complete non-negative decimal integer leaves the gate uncapped, which is the
stricter outcome.

Also names the setting in the condensed denial's recovery text, so a capped
session can discover the control that is dampening it, and documents that
malformed values fall back to uncapped.

Tests: adds a Write pass-through case, an exact-boundary case where the denial
that reaches the cap still denies and the next path passes, one case per
malformed value, and an assertion that the condensed denial names the cap.
Pass-through assertions now require a parsed output object rather than
accepting a missing one. 207 hook tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvrwu6iCpKP3C2rh8tBsdJ
2026-09-16 13:00:16 +00:00
Suliman Abdulrazzaq 241b4b535b fix(gateguard): cap session fact-force denials 2026-09-16 12:35:32 +00:00
ECC Agent 48acd64ae6 fix(pi): recognize @scope/pi-subagents in /ecc-doctor companion check
The /ecc-doctor false-negative for users who installed @tintinweb/pi-subagents
(a working, separately-published subagents implementation) because matching
was a bare exact string match against COMPANION_PACKAGES.

Matching is now asymmetric:
- exact match first (stable reported name when both present)
- unscoped entry also satisfied by @scope/<bare-name> (via @ + /suffix check,
  not plain endsWith, so my-pi-subagents does not qualify)
- scoped entry is exact-only (no silent substitution by another publisher's
  rpiv-todo for @juicesharp/rpiv-todo)
- non-exact match emits "satisfied by: <actual>" so user sees the real impl

Verification (already performed, not re-run here):
- node tests/pi/pi-extension-adapter.test.js: 31/31 pass
- Mutation test: the three reverts (old .has loop; delete scoped guard;
  plain endsWith) each fail the new test
- Real settings.json with npm:@tintinweb/pi-subagents produces correct
  "installed      pi-subagents" / "satisfied by: @tintinweb/pi-subagents"
- Full npm test: 4546/4636 pass, failures byte-identical to clean main

Refs: pi-subagents capability, ecc-doctor report
2026-09-15 20:26:49 +00:00
Affaan Mustafa e3afc47a8b test: align release expectations with version and OpenCode dist 2026-09-15 14:39:38 -04:00
Affaan Mustafa e65f12bf7e release: ecc-universal 2.2.2 2026-09-15 14:22:02 -04:00
kapelame 2cdc218c45 fix(opencode): preserve ECC guidance in custom compaction prompts 2026-09-15 12:20:14 -04:00
Yann Roberto 08094a34f9 test: require preserved Codex ledger entries 2026-09-15 15:11:52 +08:00
Yann Roberto c0ee747789 fix: preserve edited Codex user configuration 2026-09-15 14:47:27 +08:00
Affaan Mustafa 3734f6cb3a feat: add passive TCAS shadow receipts 2026-09-15 01:42:13 -04:00
Geronimo d5dee31321 fix(security): stderr skip, independent audit, home MCP trust, dry-run conflict check
- pre-push: send skip diagnostic to stderr (not stdout) so consumers
  relying on stderr for warnings receive the message
- pre-push: move ECC_PREPUSH_AUDIT outside RUN_CHECKS gate so audit-only
  configurations still check dependencies
- mcp-health-check: classify home config paths as trusted before applying
  workspace opt-in gate; when cwd == home, ~/.claude.json was incorrectly
  blocked as untrusted workspace config
- install-global-git-hooks: check conflicting global core.hooksPath in
  dry-run mode too, so dry-run accurately reflects what apply would do
2026-09-15 00:29:23 +05:30
Varun Gore fb8c36f6cc Merge pull request #4 from VarunGore36/fix/reviewer-followups
fix(security): security follow-ups for worker, installer, claw, hooks
2026-09-15 00:12:46 +05:30
Geronimo c5bbee3cb8 fix(worker,installer,claw): correct approval flag, installer order, percent path hardening
- orchestrate-codex-worker: pass approval policy via --ask-for-approval,
  not -p profile
- codex global hooks: validate conflicting global hooksPath before backup/copy,
  so refused install is side-effect free
- claw: reject percent-delimited Windows paths in cmd.exe fallback to avoid
  %NAME% expansion
- codex-hooks: opt into ECC_PREPUSH_RUN_CHECKS=1 in existing verification
  fixtures and add default-skip coverage
2026-09-14 23:52:01 +05:30