Commit Graph

39 Commits

  • fix: refresh stale technical content in agents, rules, and skills (#2168)
    Several published examples contained APIs that no longer exist, code that
    does not run, or model versions that drifted from reality:
    
    - agents/performance-optimizer.md used the web-vitals v3 API
      (getCLS/getFID/getLCP/getFCP/getTTFB) and reported FID. web-vitals v4
      renamed the imports to onCLS/onINP/onLCP/onFCP/onTTFB and FID was
      replaced by INP (target < 200ms)
    - rules/common/performance.md pinned stale model versions in the
      model-selection guidance; refresh to the versions the repo itself uses
      (agent.yaml pins claude-opus-4-6) and add the PowerShell variant for
      MAX_THINKING_TOKENS next to the bash export
    - skills/python-patterns/SKILL.md: both get_value examples referenced
      default_value without declaring the parameter (NameError); add
      default_value: Any = None to the EAFP and LBYL signatures
    - skills/frontend-patterns/SKILL.md: the custom useQuery example rebuilt
      refetch whenever callers passed inline fetchers/options, re-triggering
      the effect after every state update (infinite fetch loop). Keep the
      latest fetcher/options in refs so refetch stays referentially stable.
      The PASS-labelled useMemo example mutated its input with in-place sort;
      copy before sorting
    - skills/coding-standards/SKILL.md repeated the same PASS-labelled
      in-place-sort-in-useMemo example; same fix
    - rules/typescript/security.md used a vendor-specific OPENAI_API_KEY in
      generic guidance; switch to a neutral API_KEY
    
    Every hand-maintained copy of the affected content is synced in the same
    change: locale mirrors (ja-JP, ko-KR, pt-BR, tr, zh-CN, zh-TW - each only
    where it carries the affected file) and the .agents/.kiro/.cursor harness
    mirrors. Two structural divergences are left alone and noted here:
    .kiro/steering/performance.md has no extended-thinking control list to
    carry the PowerShell variant, and docs/zh-TW/rules/performance.md keeps an
    older condensed thinking section without the budget-cap line.
    rules/zh/performance.md is intentionally untouched - the rules/zh tree is
    being retired in a separate change
  • fix(.cursor/hooks): route block-no-verify through local hook to fix message-body false positives (#2107) (#2177)
    Cursor hooks still called `npx block-no-verify@1.1.2`, the broken external
    package whose matcher over-matches: it blocks legitimate `git commit`
    whenever `--no-verify` (or `no-verify`) appears anywhere in the command
    string, including inside the commit message body. The Claude Code surface
    already routes through the in-repo `scripts/hooks/block-no-verify.js`,
    which performs flag-position-aware tokenisation and passes 25 regression
    tests covering every false-positive case from #2107.
    
    Add a thin Cursor wrapper (`before-shell-execution-block-no-verify.js`)
    that reads Cursor stdin, transforms to the Claude Code `tool_input.command`
    shape, delegates to the local hook's exported `run()`, and forwards exit
    code and stderr. Update `.cursor/hooks.json` to call the wrapper instead
    of the npx package. New 14-case test file pins the false-positive cases
    from the issue plus the still-blocked real bypass attempts.
    
    Fixes #2107
  • fix: install native Cursor hook and MCP config (#1543)
    * fix: install native cursor hook and MCP config
    
    * fix: avoid false healthy stdio mcp probes
  • 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: add block-no-verify hook for Claude Code and Cursor (#649)
    Adds npx block-no-verify@1.1.2 as a PreToolUse Bash hook in hooks/hooks.json
    and a beforeShellExecution hook in .cursor/hooks.json to prevent AI agents
    from bypassing git hooks via the hook-bypass flag.
    
    This closes the last enforcement gap in the ECC security stack — the bypass
    flag silently skips pre-commit, commit-msg, and pre-push hooks.
    
    Closes #648
    
    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
  • feat(skills): add mcp-server-patterns (#531)
    * feat(skills): add mcp-server-patterns
    
    Made-with: Cursor
    
    * chore: add mcp-server-patterns to .agents/skills and .cursor/skills (cross-harness)
    
    Made-with: Cursor
    
    * fix: address PR review — When to Use / How It Works / Examples sections; Prompts primitive; stdio connect example; Streamable HTTP; resource handler(uri); SDK API note (tool vs registerTool)
    
    Made-with: Cursor
    
    * mcp-server-patterns: replace invalid StdioServerTransport.create() with version-agnostic note
    
    Made-with: Cursor
    
    * mcp-server-patterns: remove GitHub link, document SDK signature variance
    
    Made-with: Cursor
  • fix(hooks): allow tmux-wrapped dev server commands (#321)
    * fix(hooks): fix shell splitter redirection/escape bugs, extract shared module
    
    - Fix single & incorrectly splitting redirection operators (&>, >&, 2>&1)
    - Fix escaped quotes (\", \') not being handled inside quoted strings
    - Extract splitShellSegments into shared scripts/lib/shell-split.js
      to eliminate duplication between hooks.json, before-shell-execution.js,
      and pre-bash-dev-server-block.js
    - Add comprehensive tests for shell splitting edge cases
    
    * fix(hooks): handle backslash escapes outside quotes in shell splitter
    
    Escaped operators like \&& and \; outside quotes were still being
    treated as separators. Add escape handling for unquoted context.
  • feat: add Cursor, Codex, and OpenCode harnesses — maximize every AI coding tool
    - AGENTS.md: universal cross-tool file read by Claude Code, Cursor, Codex, and OpenCode
    - .cursor/: 15 hook events via hooks.json, 16 hook scripts with DRY adapter pattern,
      29 rules (9 common + 20 language-specific) with Cursor YAML frontmatter
    - .codex/: reference config.toml, Codex-specific AGENTS.md supplement,
      10 skills ported to .agents/skills/ with openai.yaml metadata
    - .opencode/: 3 new tools (format-code, lint-check, git-summary), 3 new hooks
      (shell.env, experimental.session.compacting, permission.ask), expanded instructions,
      version bumped to 1.6.0
    - README: fixed Cursor section, added Codex section, added cross-tool parity table
    - install.sh: now copies hooks.json + hooks/ for --target cursor
  • address review: remove .cursor/ duplicate, use is not None checks
    Changes based on CodeRabbit review feedback:
    
    1. Remove entire .cursor/ directory — it was an identical copy of the
       main skills/commands/agents/rules, causing maintenance drift.
       Users of Cursor can reference the canonical files directly.
    
    2. Use explicit `is not None` checks instead of truthiness for
       parsed['input'] and parsed['output']. Empty strings or empty
       dicts are valid values that should be preserved.
  • fix: use CLI argument for hook phase detection in observe.sh
    The observe.sh script receives "pre" or "post" as $1 from the hook
    config, but the Python code was looking for a "hook_type" field in
    the stdin JSON. Claude Code does NOT include "hook_type" in the
    JSON payload passed to hooks, so it always defaulted to "unknown",
    causing all observations to be recorded as "tool_complete" —
    PreToolUse events were never distinguished from PostToolUse.
    
    Fix: capture $1 as HOOK_PHASE and pass it to Python via env var.
    This also fixes TIMESTAMP export in the .cursor copy where inline
    `VAR=val cmd` syntax didn't propagate to the python subprocess.
  • chore: update Sonnet model references from 4.5 to 4.6
    Update MODEL_SONNET constant and all documentation references
    to reflect the new claude-sonnet-4-6 model version.
  • feat(ecc): prune plugin 43→12 items, promote 7 rules to .claude/rules/ (#245)
    ECC community plugin pruning: removed 530+ non-essential files
    (.cursor/, .opencode/, docs/ja-JP, docs/zh-CN, docs/zh-TW,
    language-specific skills/agents/rules). Retained 4 agents,
    3 commands, 5 skills. Promoted 13 rule files (8 common + 5
    typescript) to .claude/rules/ for CC native loading. Extracted
    reusable patterns to EXTRACTED-PATTERNS.md.
  • chore: update skill count from 37 to 43, add 5 new skills to directory listing
    New community skills: content-hash-cache-pattern, cost-aware-llm-pipeline,
    regex-vs-llm-structured-text, swift-actor-persistence, swift-protocol-di-testing
  • Update .cursor/skills/cpp-coding-standards/SKILL.md
    Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • feat: add cpp-coding-standards skill based on C++ Core Guidelines
    Comprehensive coding standards for modern C++ (C++17/20/23) derived
    from isocpp.github.io/CppCoreGuidelines. Covers philosophy, functions,
    classes, resource management, expressions, error handling, immutability,
    concurrency, templates, standard library, enumerations, naming, and
    performance with DO/DON'T examples and a pre-commit checklist.
  • fix: sync Cursor suggest-compact.js with corrected hooks version
    The .cursor copy had diverged from scripts/hooks/suggest-compact.js:
    - Fixed interval calculation: count % 25 → (count - threshold) % 25
      so suggestions fire relative to the configured threshold
    - Added upper bound clamp (<=1000000) to prevent counter corruption
      from large values converting to scientific notation strings
    - Removed unreliable String(process.ppid) fallback for session ID
  • fix: include .md files in instinct-cli glob (completes #216)
    The observer agent creates instinct files as .md with YAML frontmatter,
    but load_all_instincts() only globbed *.yaml and *.yml. Add *.md to the
    glob so instinct-cli status discovers all instinct files.
  • fix: instinct-cli glob and evolve --generate (fixes #216, #217)
    - Load both .yaml and .yml files in load_all_instincts() (#216)
      The *.yaml-only glob missed .yml files, causing 'No instincts found'
    - Implement evolve --generate to create skill/command/agent files (#217)
      Previously printed a stub message. Now generates SKILL.md, command .md,
      and agent .md files from the clustering analysis into ~/.claude/homunculus/evolved/
  • fix: correct stale counts and broken paths across docs
    - .cursor/README.md: skills 30→37, commands ~28→31
    - .opencode/MIGRATION.md: fix rules paths (rules/ → rules/common/)
    - README.zh-CN.md: fix agent/skill/command counts
    - docs/ja-JP/README.md: fix agent/skill/command counts
  • fix: broken cross-references, version sync, and enhanced command validator
    - Fix /build-and-fix → /build-fix in tdd.md, plan.md (+ cursor, zh-CN)
    - Fix non-existent explorer agent → planner in orchestrate.md (+ cursor, zh-CN, zh-TW)
    - Fix /python-test → /tdd in python-review.md (+ cursor, zh-CN)
    - Sync package.json version from 1.0.0 to 1.4.1 to match plugin.json
    - Enhance validate-commands.js with cross-reference checking:
      command refs, agent path refs, skill dir refs, workflow diagrams
    - Strip fenced code blocks before scanning to avoid false positives
    - Skip hypothetical "Creates:" lines in evolve.md examples
    - Add 46 new tests (suggest-compact, session-manager, utils, hooks)
  • fix: migrate hooks to stdin JSON input, fix duplicate main() calls, add threshold validation
    - Migrate session-end.js and evaluate-session.js from CLAUDE_TRANSCRIPT_PATH
      env var to stdin JSON transcript_path (correct hook input mechanism)
    - Remove duplicate main() calls that ran before stdin was read, causing
      session files to be created with empty data
    - Add range validation (1-10000) on COMPACT_THRESHOLD in suggest-compact.js
      to prevent negative or absurdly large thresholds
    - Add integration/hooks.test.js to tests/run-all.js so CI runs all 97 tests
    - Update evaluate-session.sh to parse transcript_path from stdin JSON
    - Update hooks.test.js to pass transcript_path via stdin instead of env var
    - Sync .cursor/ copies
  • fix: renameAlias data corruption, empty sessionId match, NaN threshold
    - Fix renameAlias() leaving orphaned newAlias key on save failure,
      causing in-memory data corruption with both old and new keys present
    - Add sessionPath validation to setAlias() to reject empty/null paths
    - Guard getSessionById() against empty string matching all sessions
      (startsWith('') is always true in JavaScript)
    - Fix suggest-compact.js NaN comparison when COMPACT_THRESHOLD env var
      is set to a non-numeric value — falls back to 50 instead of silently
      disabling the threshold check
    - Sync suggest-compact.js to .cursor/ copy
  • fix: harden CI validators, shell scripts, and expand test suite
    - Add try-catch around readFileSync in validate-agents, validate-commands,
      validate-skills to handle TOCTOU races and file read errors
    - Add validate-hooks.js and all test suites to package.json test script
      (was only running 4/5 validators and 0/4 test files)
    - Fix shell variable injection in observe.sh: use os.environ instead of
      interpolating $timestamp/$OBSERVATIONS_FILE into Python string literals
    - Fix $? always being 0 in start-observer.sh: capture exit code before
      conditional since `if !` inverts the status
    - Add OLD_VERSION validation in release.sh and use pipe delimiter in sed
      to avoid issues with slash-containing values
    - Add jq dependency check in evaluate-session.sh before parsing config
    - Sync .cursor/ copies of all modified shell scripts
  • chore: sync .cursor/ directory with latest agents, commands, and skills
    - Sync 13 agent files with updated descriptions and configurations
    - Sync 23 command files with latest YAML frontmatter and content
    - Sync 7 skill SKILL.md files with proper YAML frontmatter quoting
    - Copy missing cpp-testing and security-scan skills to .cursor/
    - Fix integration tests: send matching input to blocking hook test and
      expect correct exit code 2 (was 1)
  • fix: remove dead export, harden session-aliases, sync .cursor scripts
    - Remove duplicate getAliasesPath() from utils.js (only used in
      session-aliases.js which has its own copy)
    - session-aliases.js: validate cleanupAliases param is a function,
      check saveAliases return value, guard resolveAlias against empty input
    - Sync .cursor/skills/strategic-compact/suggest-compact.sh with the
      fixed main version (CLAUDE_SESSION_ID instead of $$)
  • fix: harden error handling, fix TOCTOU races, and improve test accuracy
    Core library fixes:
    - session-manager.js: wrap all statSync calls in try-catch to prevent
      TOCTOU crashes when files are deleted between readdir and stat
    - session-manager.js: use birthtime||ctime fallback for Linux compat
    - session-manager.js: remove redundant existsSync before readFile
    - utils.js: fix findFiles TOCTOU race on statSync inside readdir loop
    
    Hook improvements:
    - Add 1MB stdin buffer limits to all PostToolUse hooks to prevent
      unbounded memory growth from large payloads
    - suggest-compact.js: use fd-based atomic read+write for counter file
      to reduce race window between concurrent invocations
    - session-end.js: log when transcript file is missing, check
      replaceInFile return value for failed timestamp updates
    - start-observer.sh: log claude CLI failures instead of silently
      swallowing them, check observations file exists before analysis
    
    Test fixes:
    - Fix blocking hook tests to send matching input (dev server command)
      and expect correct exit code 2 instead of 1
  • fix: sync .cursor observe.sh and fix suggest-compact.sh session tracking
    - Sync .cursor/observe.sh with corrected main version (use stdin pipe
      instead of broken heredoc json.loads pattern)
    - Fix suggest-compact.sh to use CLAUDE_SESSION_ID instead of $$ which
      gives a new PID per invocation, preventing counter from incrementing
  • fix(sessions): also fix require() paths in Cursor and zh-CN sessions commands
    Same fix as the main sessions.md — use CLAUDE_PLUGIN_ROOT with
    ~/.claude/ fallback instead of relative paths.
  • feat: add Cursor IDE support with pre-translated configs
    Add complete .cursor/ directory with rules, agents, skills, commands,
    and MCP config adapted for Cursor's format. This makes ecc-universal
    a truly cross-IDE package supporting Claude Code, Cursor, and OpenCode.
    
    - 27 rule files with YAML frontmatter (description, globs, alwaysApply)
    - 13 agent files with full model IDs and readonly flags
    - 30 skill directories (identical Agent Skills standard, no translation)
    - 31 command files (5 multi-* stubbed for missing codeagent-wrapper)
    - MCP config with Cursor env interpolation syntax
    - README.md and MIGRATION.md documentation
    - install.sh --target cursor flag for project-scoped installation
    - package.json updated with .cursor/ in files and cursor keywords