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>
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
- 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
- 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
- claw askClaude: prefer native .exe, route only .cmd/.bat through cmd.exe
with a quoted command line (DEP0190-safe, same pattern as
mcp-health-check); never exec .ps1 directly (not executable without
powershell); model allowlist retained so the shell line carries no
attacker metacharacters
- executor sync path: close un-awaited coroutine before returning the
generic failure, eliminating RuntimeWarning noise
Independent local Codex review PASS at 73b07f8d17, no P0/P1. Independent 66 tests and strict validation of 810 skills passed. CI run 34683976362 passed; all 48 current checks green. Incomplete memory reads fail closed with safe MCP diagnostics; canonical guidance synchronized across harness skill copies. Rollback: revert this squash commit. No deployment or installation claim.
Independent local Codex review PASS at 472cfa94fb, no P0/P1. Independent retrospective, CLI, envelope and capsule tests: 73 passed. CI run 34664487219 attempt 2 passed all 42 jobs. Read-only offline capsule grouping only; no provenance, scoring, execution or promotion claim. Rollback: revert this squash commit.
Exact-head independent local Codex review PASS with no P0/P1. CI run 34680860653 attempt 2 passed at 0707cd431c. Includes HTTP/schema failure handling, coalesced sampling cache and regression tests. Disclosed P2 follow-ups remain in the merge-queue receipt. Rollback: revert this squash commit. No deployment or publication claim.
Move stable hook metadata to a validated sidecar while preserving hook commands and installer identity. Reject moved fingerprints and duplicate IDs, and validate before updating metadata. Independent local review passed at c315271624a1fd055b992f2bff889ad2a0ff8a6b; CI run 34678210149 passed. Rollback: revert this squash commit.
Two cases the word-level rewrite still got wrong. Short options that take an optional stuck value (-u[mode], -S[keyid]) end the cluster scan, so git commit -uno and -Sn are allowed while -nu stays blocked. Git accepts any unambiguous long-option prefix, so --no-veri and --no-verif on commit, push, merge and rebase are now blocked; --no-verbose stays allowed. Quoted data such as -m "--no-verify" is still treated as data. Independent exact-head review probed 34 commands in-process and against real git with no bypass and no false positive; hook test 35/35, eslint clean, CI 44/44 at the head.
pre-bash-commit-quality spawned Windows .cmd/.bat linters unquoted, so a spaced path failed, and passed --format compact, which ESLint 9 removed (#3075). Batch executables now run through cmd.exe with each argument carried in an env token and quoted, with quote, NUL, CR and LF rejected before spawn; non-batch Windows and POSIX paths keep direct argv spawn with shell false. ESLint uses its bundled default formatter, present on 8, 9 and 10. Regression tests cover the batch, non-batch and POSIX branches and the formatter change. Independent exact-head review passed with no P0/P1; CI 44/44 at the head.
github-coordination sync listed every repo issue and pushed the epic label onto all of them (#3084). Scope the listing to issues carrying the policy's epic label plus issues whose body still holds the coordination marker (label-drift recovery), deduped by number, and reject an empty labels.epic in loadPolicy. Tests cover the filtered path and the recovery path with exact gh argv. Independent exact-head review passed with no P0/P1; CI 44/44 at the head.
tools/list and tools/call on main already admit `_meta` — MCP reserves it
for request metadata and a client may attach it to any request. ping still
refused every parameter, so a client that sends `_meta` on everything
(Codex does) got -32602 on its keepalive.
Rebased onto main and narrowed: when this branch was first written the same
gap existed on tools/list, which has since been fixed upstream. Only the
ping handler is left, so only the ping handler is touched.
Refs #2810
Generalize PR #2981 ownership protection to every managed target. Reject mismatched target state and preserve files that appear during writes or failed-install checkpoints. Keep prior hashes for managed files a failed attempt never writes.
Integrate PR #2980 preview wording and global dry-run propagation, with PR #2956 fail-closed environment validation and CLI/legacy regression coverage.
Fixes#2964. Fixes#2952.
Co-authored-by: ilkmajans-cpu <ilkmajans-cpu@users.noreply.github.com>
Co-authored-by: wellkilo <wellkilo@foxmail.com>
Reject directory replacement after temporary file creation or staging, preserve unrelated files during cleanup, and retry settings edits observed before the final rename. Add three regression tests for the review findings.
Address #2921 and complete the segment-anchoring direction in #2979. Preserve explicit absolute exemptions while denying accidental matches in unrelated projects.
Addresses Greptile's review on #2994:
- missing-dependency.js no longer hardcodes a second copy of the four
runtime dependency versions; it reads them from package.json's
dependencies field instead, so the two can't silently drift apart.
describeMissingDependencyError() still recognizes a tracked
dependency even if package.json can't be read for some reason,
just without a version-pinned install command in that case.
- The regression test now asserts no ancestor directory of its
temp fixture has a node_modules, so a stray one wouldn't let
Node resolve ajv/sql.js from there and mask what the test is
actually meant to exercise. Also copies package.json into the
fixture, matching a real plugin-marketplace git clone and what
the version-lookup above now needs.
install-plan.js and install-apply.js both require ./lib/install/config at
load time, and that module required ajv unconditionally at the top of the
file even though ajv is only actually used when validating an
ecc-install.json. When ECC is installed via the Claude Code plugin
marketplace, the marketplace directory is a bare git clone with no
node_modules, so requiring ajv crashes commands like --list-profiles that
never touch install-config validation at all.
Same root cause in scripts/lib/control-pane/state.js: sql.js and
@iarna/toml were required at module scope even though they are only used
inside openSqlDatabase() and readTomlConfig(), so control-pane.js --help
crashed too.
Make both requires lazy so they only load when the feature that actually
needs them runs. For the case where ajv/sql.js/js-yaml/@iarna-toml is
genuinely needed and still missing, add a small helper that turns the raw
MODULE_NOT_FOUND into an actionable message naming the package and the
install command, instead of a stack trace (install-apply.js) or, worse, an
unhandled crash with a usage banner tacked on that reads like a bad
argument (install-plan.js, control-pane.js). Applied the same helper to
memory-mcp.mjs, where ajv is genuinely load-bearing (it compiles every MCP
tool's JSON schema up front) so it can't be made lazy the same way.
Added a regression test that copies just scripts/, schemas/, and
manifests/ into a directory with no node_modules anywhere above it in the
filesystem, which reproduces the plugin-marketplace install exactly, and
asserts install-plan.js and control-pane.js still work.
Forward-port #2925 for #2924 and verify ASCII and multibyte over-limit input suppression. Supersedes the overlapping direct-entrypoint fix in #2978.
Co-authored-by: jackie-cqz <2557911191@qq.com>
Review on #2829 found the regex fix widened a false positive: matching
`\bdd\s+if=` against the whole flattened line gated `echo dd if=/dev/zero`
and `grep dd if=/dev/zero file`, neither of which runs dd. That class was
already present before — `echo dd if=x` matched the old arm too — but the
boundary fix extended it to the slash and dot spellings, so the arm now
decides on text position rather than on what is being executed.
dd moves to isDestructiveDd(tokens), next to isDestructiveRm and
isDestructiveGit, and DESTRUCTIVE_SQL_DD goes back to SQL only. The
per-segment loop already tokenizes every executable body, so the check runs
where the command word is known.
This resolves four things the text match could not:
dd if=/dev/zero of=/dev/sda was allowed -> denied (the reported bug)
sudo dd if=/dev/zero was allowed -> denied
dd of=/dev/sda if=/dev/zero was allowed -> denied (operands are order-free)
echo dd if=x was denied -> allowed (pre-existing false positive)
Leading sudo/doas/env, their flags, and VAR=value assignment prefixes are
skipped so a wrapped invocation still resolves to dd; flags are only skipped
once a wrapper has been seen, so the scan cannot walk into an unrelated
command's arguments.
Tests: 6 fail on upstream main, 155 pass with this change.
Refs #2642
DESTRUCTIVE_SQL_DD shared one trailing \b across every alternation arm.
`dd\s+if=` ends in `=`, and a \b after a non-word character only holds when
the NEXT character is a word character, so the arm matched `dd if=x` and
missed every path starting with `/`, `.` or a quote:
dd if=/dev/zero of=/dev/sda allowed
dd if=./disk.img of=/dev/sdb allowed
dd if="/dev/zero" of=/dev/sda allowed
The word-boundary suffix now applies only to the arms that end in a word
character. The split is what keeps the widening bounded: dropping the
trailing \b outright would let `truncate` match `truncated`, and dropping the
leading \b would let `dd if=` match inside `add if=`. Both are covered.
This is the half of #2642 that survived the structural findGitSubcommand()
parser, which already handles `git checkout -- .`.
Not addressed here: `dd of=/dev/sda if=/dev/zero` with the operands reversed
is still allowed, before and after, because the pattern requires `if=`
immediately after `dd`. That is a different defect from the boundary bug and
widening a P0 gate's pattern shape is a maintainer call.
Refs #2642
Same class of bug as the session_id fix, one field over, found by code-reviewer
before merge: CLAUDE_HOOK_EVENT_NAME is never set for hook subprocesses either
(currently a harmless no-op since the dispatcher only ever calls this hook under
PostToolUse, but a real latent bug if that wiring ever changes). Also runs the
stdin-derived session_id through sanitizeSessionId(), matching the established
pattern already used in cost-tracker.js, ecc-context-monitor.js,
ecc-metrics-bridge.js, and gateguard-fact-force.js.