Commit Graph

400 Commits

  • Merge pull request #1384 from KeWang0622/fix/lint-md028-eqeqeq
    fix: resolve markdownlint MD028 + ESLint eqeqeq lint failures
  • Merge pull request #1385 from KeWang0622/fix/block-no-verify-hook
    fix: route block-no-verify hook through run-with-flags.js
  • fix: harden release surface version and packaging sync (#1388)
    * fix: keep ecc release surfaces version-synced
    
    * fix: keep lockfile release version in sync
    
    * fix: remove release version drift from locks and tests
    
    * fix: keep root release metadata version-synced
    
    * fix: keep codex marketplace metadata version-synced
    
    * fix: gate release workflows on full metadata sync
    
    * fix: ship all versioned release metadata
    
    * fix: harden manual release path
    
    * fix: keep localized release docs version-synced
    
    * fix: sync install architecture version examples
    
    * test: cover shipped plugin metadata in npm pack
    
    * fix: verify final npm payload in release script
    
    * fix: ship opencode lockfile in npm package
    
    * docs: sync localized release highlights
    
    * fix: stabilize windows ci portability
    
    * fix: tighten release script version sync
    
    * fix: prefer repo-relative hook file paths
    
    * fix: make npm pack test shell-safe on windows
  • fix: detach ecc2 background session runners (#1387)
    * fix: detach ecc2 background session runners
    
    * fix: stabilize windows ci portability
    
    * fix: persist detached runner startup stderr
    
    * fix: prefer repo-relative hook file paths
    
    * fix: make npm pack test shell-safe on windows
  • fix: address PR review comments on block-no-verify hook
    - Add `minimal` profile so the security hook runs in all profiles
    - Scope -n/--no-verify flag check to the detected subcommand region,
      preventing false positives on chained commands (e.g. `git log -n 10`)
    - Guard stdin listeners with `require.main === module` so require()
      from run-with-flags.js does not register unnecessary listeners
    - Verify subcommand token is preceded only by flags/flag-args after
      "git", preventing misclassification of argument values as subcommands
    - Add integration tests for block-no-verify hook
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
  • fix: route block-no-verify hook through run-with-flags.js
    Replace inline `npx block-no-verify@1.1.2` with a standalone Node.js
    script routed through `run-with-flags.js`, matching every other hook.
    
    Fixes two bugs:
    1. npx inherits the project cwd and triggers EBADDEVENGINES in
       pnpm-only projects that set devEngines.packageManager.onFail=error.
    2. The hook bypassed run-with-flags.js so ECC_DISABLED_HOOKS had no
       effect — the isHookEnabled() check never ran.
    
    The new script replicates the full block-no-verify@1.1.2 detection
    logic (--no-verify, -n shorthand for commit, core.hooksPath override)
    with zero external dependencies.
    
    Closes #1378
  • fix: resolve markdownlint MD028 and ESLint eqeqeq warnings
    Fix two lint issues that cause `npm run lint` to exit non-zero:
    
    1. README.md (MD028): Two consecutive blockquotes separated by a bare
       blank line. Markdownlint treats this as one blockquote with an
       illegal blank line inside. Replace the blank line with a `>`
       continuation so both paragraphs stay in the same blockquote.
    
    2. session-activity-tracker.js (eqeqeq): Three instances of `== null`
       replaced with explicit `=== null || === undefined` guards to satisfy
       the repo's `eqeqeq: warn` ESLint rule.
    
    Closes #1366
  • fix: gate MultiEdit tool alongside Edit/Write
    MultiEdit was bypassing the fact-forcing gate because only Edit and
    Write were checked. Now MultiEdit triggers the same edit gate (list
    importers, public API, data schemas) before allowing file modifications.
    
    Updated both the hook logic and hooks.json matcher pattern.
    
    Addresses coderabbit/greptile/cubic-dev: "MultiEdit bypasses gate"
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • fix: allow destructive bash retry after facts presented
    Destructive bash gate previously denied every invocation with no
    isChecked call, creating an infinite deny loop. Now gates per-command
    on first attempt and allows retry after the model presents the required
    facts (targets, rollback plan, user instruction).
    
    Addresses greptile P1: "Destructive bash gate permanently blocks"
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • fix: address P2 review feedback (coderabbitai, cubic-dev-ai)
    - GATEGUARD_STATE_DIR env var for test isolation (hook + tests)
    - Exit code assertions on all 9 tests (no vacuous passes)
    - Non-vacuous allow-path assertions (verify pass-through preserves input)
    - Robust newline-injection assertion
    - clearState() now reports errors instead of swallowing
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • fix: address P1 review feedback from greptile bot
    1. Use run-with-flags.js wrapper (supports ECC_HOOK_PROFILE, ECC_DISABLED_HOOKS)
    2. Add session timeout (30min inactivity = state reset, fixes "once ever" bug)
    3. Add 9 integration tests (deny/allow/timeout/sanitize/disable)
    
    Refactored hook to module.exports.run() pattern for direct require() by
    run-with-flags.js (~50-100ms faster per invocation).
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • feat(hooks,skills): add gateguard fact-forcing pre-action gate
    A PreToolUse hook that forces Claude to investigate before editing.
    Instead of self-evaluation ("are you sure?"), it demands concrete facts:
    importers, public API, data schemas, user instruction.
    
    A/B tested: +2.25 quality points (9.0 vs 6.75) across two independent tasks.
    
    - scripts/hooks/gateguard-fact-force.js — standalone Node.js hook
    - skills/gateguard/SKILL.md — skill documentation
    - hooks/hooks.json — PreToolUse entries for Edit|Write and Bash
    
    Full package with config: pip install gateguard-ai
    Repo: https://github.com/zunoworks/gateguard
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • perf(hooks): batch format+typecheck at Stop instead of per Edit (#746)
    * perf(hooks): batch format+typecheck at Stop instead of per Edit
    
    Fixes #735. The per-edit post:edit:format and post:edit:typecheck hooks
    ran synchronously after every Edit call, adding 15-30s of latency per
    file — up to 7.5 minutes for a 10-file refactor.
    
    New approach:
    - post-edit-accumulator.js (PostToolUse/Edit): lightweight hook that
      records each edited JS/TS path to a session-scoped temp file in
      os.tmpdir(). No formatters, no tsc — exits in microseconds.
    - stop-format-typecheck.js (Stop): reads the accumulator once per
      response, groups files by project root and runs the formatter in
      one batched invocation per root, then groups .ts/.tsx files by
      tsconfig dir and runs tsc once per tsconfig. Clears the accumulator
      immediately on read so repeated Stop calls don't double-process.
    
    For a 10-file refactor: was 10 × (15s + 30s) = 7.5 min overhead,
    now 1 × (batch format + batch tsc) = ~5-30s total.
    
    * fix(hooks): address race condition, spawn timeout, and Windows path guard
    
    Three issues raised in code review:
    
    1. Race condition: switched accumulator from non-atomic JSON
       read-modify-write to appendFileSync (one path per line). Concurrent
       Edit hook processes each append independently without clobbering each
       other. Deduplication moved to the Stop hook at read time.
    
    2. Effective timeout: added run() export to stop-format-typecheck.js so
       run-with-flags.js uses the direct require() path instead of falling
       through to spawnSync (which has a hardcoded 30s cap). The 120s
       timeout in hooks.json now governs the full batch as intended.
    
    3. Windows path guard: added spaces and parentheses to UNSAFE_PATH_CHARS
       so paths like "C:\Users\John Doe\project\file.ts" are caught before
       being passed to cmd.exe with shell: true.
    
    * fix(hooks): fix session fallback, stale comment, trim verbose comments
    
    - Replace 'default' session ID fallback with a cwd-based sha1 hash so
      concurrent sessions in different projects don't share the same
      accumulator file when CLAUDE_SESSION_ID is unset
    - Remove stale "JSON file" reference in accumulator header (format is
      now newline-delimited plain text)
    - Remove redundant/verbose inline comments throughout both files
    
    * fix(hooks): sanitize session ID, fix Windows tsc, proportional timeouts
    
    - Sanitize CLAUDE_SESSION_ID with /[^a-zA-Z0-9_-]/g before embedding in
      the temp filename so crafted separators or '..' sequences cannot escape
      os.tmpdir() (cubic P1)
    - Fix typecheckBatch on Windows: npx.cmd requires shell:true like
      formatBatch already does; use spawnSync and extract stdout/stderr from
      the result object (coderabbit P1)
    - Proportional per-batch timeouts: divide 270s budget across all format
      and typecheck batches so sequential runs in monorepos stay within the
      Stop hook wall-clock limit (greptile P2)
    - Raise Stop hook timeout from 120s to 300s to give large monorepos
      adequate headroom (cubic P2)
    
    * fix(hooks): extend accumulator to Write|MultiEdit, fix tests
    
    - Extend matcher from Edit to Edit|Write|MultiEdit so files created with
      Write and all files in a MultiEdit batch are included in the Stop-time
      format+typecheck pass (cubic P1)
    - Handle tool_input.edits[] array in accumulator for MultiEdit support
    - Rename misleading 'concurrent writes' test to clarify it tests append
      preservation, not true concurrency (cubic P2)
    - Add Stop hook dedup test: writes duplicate paths to accumulator and
      verifies the hook clears it cleanly (cubic P2)
    - Add Write and MultiEdit accumulation tests
    
    * fix(hooks): move timeout to command level, add dedup unit tests
    
    - Move timeout: 300 from the matcher object to the hook command object
      where it is actually enforced; the previous position was a no-op
      (cubic P2)
    - Extract parseAccumulator() and export it so tests can assert dedup
      behavior directly without relying only on side effects (cubic P2)
    - Add two unit tests for parseAccumulator: deduplication and blank-line
      handling; rename the integration test to match its scope
    
    * fix(hooks): replace removed format/typecheck hooks with accumulator in cursor adapter
  • feat(install): add CodeBuddy(Tencent) adaptation with installation scripts (#1038)
    * feat(install): add CodeBuddy(Tencent) adaptation with installation scripts
    
    * fix: add codebuddy to SUPPORTED_INSTALL_TARGETS
    
    * fix(codebuddy): resolve installer path issues, unused vars, and uninstall safety
  • feat: add GAN-style generator-evaluator harness (#1029)
    Implements Anthropic's March 2026 harness design pattern — a multi-agent
    architecture that separates generation from evaluation, creating an
    adversarial feedback loop that produces production-quality applications.
    
    Components:
    - 3 agent definitions (planner, generator, evaluator)
    - 1 skill with full documentation (skills/gan-style-harness/)
    - 2 commands (gan-build for full apps, gan-design for frontend)
    - 1 shell orchestrator (scripts/gan-harness.sh)
    - Examples and configuration reference
    
    Based on: https://www.anthropic.com/engineering/harness-design-long-running-apps
    
    Co-authored-by: Hao Chen <haochen806@gmail.com>
  • fix: filter session-start injection by cwd/project to prevent cross-project contamination (#1054)
    * fix: filter session-start injection by cwd/project to prevent cross-project contamination
    
    The SessionStart hook previously selected the most recent session file
    purely by timestamp, ignoring the current working directory. This caused
    Claude to receive a previous project's session context when switching
    between projects, leading to incorrect file reads and project analysis.
    
    session-end.js already writes **Project:** and **Worktree:** header
    fields into each session file. This commit adds selectMatchingSession()
    which uses those fields with the following priority:
    
    1. Exact worktree (cwd) match — most recent
    2. Same project name match — most recent
    3. Fallback to overall most recent (preserves backward compatibility)
    
    No new dependencies. Gracefully falls back to original behavior when
    no matching session exists.
    
    * fix: address review feedback — eliminate duplicate I/O, add null guards, improve docstrings
    
    - Return { session, content, matchReason } from selectMatchingSession()
      to avoid reading the same file twice (coderabbitai, greptile P2)
    - Add empty array guard: return null when sessions.length === 0 (coderabbitai)
    - Stop mutating input objects — no more session._matchReason (coderabbitai)
    - Add null check on result before accessing properties (coderabbitai)
    - Only log "selected" after confirming content is readable (cubic-dev-ai P3)
    - Add full JSDoc with @param/@returns (docstring coverage)
    
    * fix: track fallback session object to prevent session/content mismatch
    
    When sessions[0] is unreadable, fallbackContent came from a later
    session (e.g. sessions[1]) while the returned session object still
    pointed to sessions[0]. This caused misleading logs and injected
    content from the wrong session — the exact problem this PR fixes.
    
    Now tracks fallbackSession alongside fallbackContent so the returned
    pair is always consistent.
    
    Addresses greptile-apps P1 review feedback.
    
    * fix: normalize worktree paths to handle symlinks and case differences
    
    On macOS /var is a symlink to /private/var, and on Windows paths may
    differ in casing (C:\repo vs c:\repo). Use fs.realpathSync() to
    resolve both sides before comparison so worktree matching is reliable
    across symlinked and case-insensitive filesystems.
    
    cwd is normalized once outside the loop to avoid repeated syscalls.
    
    Addresses coderabbitai Major review feedback.
    
    ---------
    
    Co-authored-by: kuqili <kuqili@tencent.com>