Commit Graph

1471 Commits

  • fix(observe): skip Windows AppInstallerPythonRedirector.exe in resolve_python_cmd (#1511)
    On Windows 10/11 without Python installed from the Microsoft Store, the
    "App Execution Alias" stubs at %LOCALAPPDATA%\Microsoft\WindowsApps\python.exe
    and python3.exe are symlinks to AppInstallerPythonRedirector.exe. These
    stubs neither launch Python nor honor `-c`; calls print a bare "Python "
    line and exit, silently breaking every JSON-parsing step in observe.sh.
    
    Net effect: observations.jsonl is never written, CLV2 appears installed
    correctly, and the only residual artifact is `.last-purge`.
    
    This commit:
      1. Adds `_is_windows_app_installer_stub` helper that detects the stub
         via `command -v` output and optional `readlink -f` resolution.
      2. Teaches `resolve_python_cmd` to skip stub candidates and fall
         through to the next real interpreter (typically C:\...\Python3xx\python.exe).
      3. Exports the stub-aware CLV2_PYTHON_CMD before sourcing
         detect-project.sh, which already honors an already-set value,
         so the shared helper does not re-resolve and re-select the stub.
    
    POSIX-compatible. No behavior change on macOS / Linux / WSL where no
    such stub exists.
    
    Refs: observations.jsonl empty on Windows Claude Desktop users.
  • docs: fix bottom overflow in hero PNG, tighten stats labels (#1535)
    The merged hero was being clipped at the bottom by the Puppeteer capture
    because the HTML body used flex-centering with 24px padding, shifting the
    stage below the viewport top.
    
    - Captures now flush to (0,0) via a min-width 1300px media-query wrapper
      so the in-browser preview keeps its padding but the capture viewport
      does not.
    - Shortens bottom-row labels so the stats row no longer overlaps the foot
      line at 1200px:
      Catalog, Harnesses, Rust plane, MIT  /  npm: ecc-universal · AgentShield
    
    No other content changes.
    
    Co-authored-by: livlign <livlign@users.noreply.github.com>
  • fix(hooks): avoid Claude Code v2.1.116 argv-dup bug in settings.local.json (#1524)
    * fix: resolve Claude Code Bash hook "cannot execute binary file" on Windows
    
    Root cause in ~/.claude/settings.local.json (user-global):
    1. UTF-8 BOM + CRLF line endings left by patch_settings_cl_v2_simple.ps1
    2. Double-wrapped command "\"bash.exe\" \"wrapper.sh\"" broke Windows
       argument splitting on the space in "Program Files", making bash.exe
       try to execute itself as a script.
    
    Fix:
    - Rewrite settings.local.json as UTF-8 (no BOM), LF, with the hook command
      pointing directly at observe-wrapper.sh and passing "pre"/"post" as a
      positional arg so HOOK_PHASE is populated correctly in observe.sh.
    
    Docs:
    - docs/fixes/HOOK-FIX-20260421.md — full root-cause analysis.
    - docs/fixes/apply-hook-fix.sh — idempotent applier script.
    
    * docs: addendum for HOOK-FIX-20260421 (v2.1.116 argv duplication detail)
    
    - Documents Claude Code v2.1.116 argv duplication bug as the underlying
      cause of the bash.exe:bash.exe:cannot execute binary file error
    - Records night-session fix variant using explicit `bash <path>` prefix
      (matches hooks.json observer pattern, avoids EFTYPE on Node spawn)
    - Keeps morning commit 527c18b intact; both variants are now documented
    
    ---------
    
    Co-authored-by: suusuu0927 <sugi.go.go.gm@gmail.com>
  • fix: install native Cursor hook and MCP config (#1543)
    * fix: install native cursor hook and MCP config
    
    * fix: avoid false healthy stdio mcp probes
  • Merge pull request #1540 from suusuu0927/claude/install-hook-wrapper-argv-dup-fix-20260422
    fix(hooks): rewrite install_hook_wrapper.ps1 to avoid argv-dup bug
  • Merge pull request #1542 from suusuu0927/claude/patch-settings-simple-fix-20260422
    fix(hooks): rewrite patch_settings_cl_v2_simple.ps1 to avoid argv-dup bug
  • Merge pull request #1495 from ratorin/fix/session-end-transcript-path-isolation
    fix(hooks): isolate session-end.js filename using transcript_path UUID (#1494)
  • Merge pull request #1490 from gaurav0107/fix/1459-remove-agents-manifest-field
    fix: remove unsupported `agents` field from plugin.json
  • Merge pull request #1539 from suusuu0927/claude/detect-project-locale-fix-20260421
    fix: make detect-project.sh locale-independent and handle Windows bac…
  • fix(hooks): wrap SessionStart summary with stale-replay guard (#1536)
    The SessionStart hook injects the most recent *-session.tmp as
    additionalContext labelled only with 'Previous session summary:'.
    After a /compact boundary, the model frequently re-executes stale
    slash-skill invocations it finds inside that summary, re-running
    ARGUMENTS-bearing skills (e.g. /fw-task-new, /fw-raise-pr) with the
    last ARGUMENTS they saw.
    
    Observed on claude-opus-4-7 with ECC v1.9.0 on a firmware project:
    after compaction resume, the model spontaneously re-enters the prior
    skill with stale ARGUMENTS, duplicating GitHub issues, Notion tasks,
    and branches for work that is already merged.
    
    ECC cannot fix Claude Code's skill-state replay across compactions,
    but it can stop amplifying it. Wrap the injected summary in an
    explicit HISTORICAL REFERENCE ONLY preamble with a STALE-BY-DEFAULT
    contract and delimit the block with BEGIN/END markers so the model
    treats everything inside as frozen reference material.
    
    Tests: update the two hooks.test.js cases that asserted on the old
    'Previous session summary' literal to assert on the new guard
    preamble, the STALE-BY-DEFAULT contract, and both delimiters. 219/219
    tests pass locally.
    
    Tracked at: #1534
  • fix(gateguard): rewrite routineBashMsg to use fact-presentation pattern (#1531)
    * fix(gateguard): rewrite routineBashMsg to use fact-presentation pattern
    
    The imperative 'Quote user's instruction verbatim. Then retry.' phrasing
    triggers Claude Code's runtime anti-prompt-injection filter, deadlocking
    the first Bash call of every session. The sibling gates (edit, write,
    destructive) use multi-point fact-list framing that the runtime accepts.
    
    Align routineBashMsg with that pattern to restore the gate's intended
    behavior without changing run(), state schema, or any public API.
    
    Closes #1530
    
    * docs(gateguard): sync SKILL.md routine gate spec with new message format
    
    CodeRabbit flagged that skills/gateguard/SKILL.md still described the
    pre-fix imperative message. Update the Routine Bash Gate section to
    match the numbered fact-list format used by the new routineBashMsg().
  • fix(scripts): resolve claude.cmd on Windows by enabling shell for spawn (#1471)
    Fixes #1469.
    
    On Windows the `claude` binary installed via `npm i -g @anthropic-ai/claude-code`
    is `claude.cmd`, and Node's spawn() cannot resolve .cmd wrappers via PATH
    without shell: true. The call failed with `spawn claude ENOENT` and claw.js
    returned an error string to the caller.
    
    Mirrors the fix pattern applied in PR #1456 for the MCP health-check hook.
    'claude' is a hardcoded literal (not user input), so enabling shell on Windows
    only is safe.
  • fix(hooks): add Windows PowerShell 5.1 compatibility to install_hook_wrapper.ps1
    `ConvertFrom-Json -AsHashtable` is PowerShell 7+ only, and the Windows 11
    reference machine used to validate this PR ships with Windows PowerShell
    5.1 only (no `pwsh` on PATH). Without this follow-up, running the
    installer on stock Windows fails at the parse step and leaves the
    installation half-applied.
    
    - Fall back to a manual `PSCustomObject` -> `Hashtable` conversion when
      `-AsHashtable` raises, so the script parses the existing
      settings.local.json on both PS 5.1 and PS 7+.
    - Normalize both hook buckets (`PreToolUse`, `PostToolUse`) and their
      inner `hooks` arrays as `System.Collections.ArrayList` before
      serialization. PS 5.1 `ConvertTo-Json` otherwise collapses
      single-element arrays into bare objects, which breaks the canonical
      PR #1524 shape.
    - Create the `skills/continuous-learning/hooks` destination directory
      when it does not exist yet, and emit a clearer error if
      settings.local.json is missing entirely.
    - Update `INSTALL-HOOK-WRAPPER-FIX-20260422.md` to document the PS 5.1
      compatibility guarantee and to cross-link PR #1542 (companion simple
      patcher).
    
    Verified on Windows 11 / Windows PowerShell 5.1.26100.8115 by running
    `powershell -NoProfile -ExecutionPolicy Bypass -File
    docs/fixes/install_hook_wrapper.ps1` against a sandbox `$env:USERPROFILE`
    and against the real settings.local.json. Both produce the canonical
    PR #1524 shape with LF-only output.
  • fix(hooks): rewrite patch_settings_cl_v2_simple.ps1 to avoid argv-dup bug
    - Use PATH-resolved `bash` as first token instead of quoted `.exe` path
      so Claude Code v2.1.116 argv duplication does not feed a binary to
      bash as its $0 (repro: exit 126 "cannot execute binary file").
    - Point the command at `observe-wrapper.sh` and pass distinct `pre` /
      `post` positional arguments so PreToolUse and PostToolUse are
      registered as separate entries.
    - Normalize the wrapper path to forward slashes before embedding in the
      hook command to avoid MSYS backslash surprises.
    - Write UTF-8 (no BOM) with CRLF normalized to LF so downstream JSON
      parsers never see mixed line endings.
    - Preserve existing hooks (legacy `observe.sh`, third-party entries)
      by appending only when the canonical command string is not already
      registered. Re-runs are idempotent ([SKIP] both phases).
    - Keep the script compatible with Windows PowerShell 5.1: fall back to
      a manual PSCustomObject → Hashtable conversion when
      `ConvertFrom-Json -AsHashtable` is unavailable, and materialize hook
      arrays as `System.Collections.ArrayList` so single-element arrays
      survive PS 5.1 `ConvertTo-Json` serialization.
    
    Companion to PR #1524 (settings.local.json shape fix) and PR #1540
    (install_hook_wrapper.ps1 argv-dup fix).
  • fix(hooks): rewrite install_hook_wrapper.ps1 to avoid argv-dup bug
    Under Claude Code v2.1.116 the first argv token of a hook command is
    duplicated. When the token is a quoted Windows .exe path, bash.exe is
    re-invoked with itself as script (exit 126). PR #1524 fixed the shape
    of settings.local.json; this script keeps the installer consistent so
    re-running it does not regenerate the broken form.
    
    Changes:
    - First token is now PATH-resolved `bash` instead of the quoted bash.exe
    - Wrapper path is normalized to forward slashes for MSYS safety
    - PreToolUse and PostToolUse get distinct pre/post positional arguments
    - JSON output is written with LF endings (no mixed CRLF/LF)
    
    Companion doc: docs/fixes/INSTALL-HOOK-WRAPPER-FIX-20260422.md
  • docs: remove stars/forks stats from hero, shrink file size
    Re-renders hero.png without the baked-in stars (163k) and forks (25k) numbers
    that were drifting from the README's own dynamic badges. Bottom stats now show
    repo-derived catalog counts that don't rot: 310 total items (183 skills + 48
    agents + 79 commands), 7 harnesses, ECC 2.0α, MIT.
    
    Also shrinks the file from 534 KB to ~131 KB via tighter pngquant settings.
    
    Addresses review comments from cubic and greptile (stat drift) and CodeRabbit
    (file size).
  • fix: make detect-project.sh locale-independent and handle Windows backslash paths
    Two bugs in skills/continuous-learning-v2/scripts/detect-project.sh that
    silently split the same project into multiple project_id records:
    
    1. Locale-dependent SHA-256 input (HIGH)
       The project_id hash was computed with
         printf '%s' "$hash_input" | python -c 'sys.stdin.buffer.read()'
       which ships shell-locale-encoded bytes to Python. On a system with a
       non-UTF-8 LC_ALL (e.g. ja_JP.CP932 / CP1252) the same project root
       produced a different 12-char hash than the UTF-8 locale would produce,
       so observations/instincts were silently written under a separate
       project directory. Fixed by passing the value via an env var and
       encoding as UTF-8 inside Python, making the hash locale-independent.
    
    2. basename cannot split Windows backslash paths (MEDIUM)
       basename "C:\Users\...\ECC作成" returns the whole string on POSIX
       bash, so project_name was garbled whenever CLAUDE_PROJECT_DIR was
       passed as a native Windows path. Normalize backslashes to forward
       slashes before calling basename.
    
    Both the primary project_id hash and the legacy-compat fallback hash
    are updated to use the env-var / UTF-8 approach.
    
    Verified: id is stable across en_US.UTF-8, ja_JP.UTF-8, ja_JP.CP932, C,
    and POSIX locales; Windows-path input yields project_name=ECC作成;
    ASCII-only paths regress-free.
  • review: broaden CLAUDE_TRANSCRIPT_PATH fallback to cover missing/empty JSON fields
    Previously the env fallback ran only when JSON.parse threw. If stdin was valid
    JSON but omitted transcript_path or provided a non-string/empty value, the
    script dropped to the getSessionIdShort() fallback path, re-introducing the
    collision this PR targets.
    
    Validate the parsed transcript_path and apply the env-var fallback for any
    unusable value, not just malformed JSON. Matches coderabbit's outside-diff
    suggestion and keeps both input-source paths equivalent.
    
    Refs #1494
  • review: apply sanitizeSessionId to UUID shortId, fix test comment
    - Route the transcript-derived shortId through sanitizeSessionId so the
      fallback and transcript branches remain byte-for-byte equivalent for any
      non-UUID session IDs that still land in CLAUDE_SESSION_ID (greptile P1).
    - Clarify the inline comment in the first regression test: clearing
      CLAUDE_SESSION_ID exercises the transcript_path branch, not the
      getSessionIdShort() fallback (coderabbit P2).
    
    Refs #1494
  • review: address P1/P2 bot feedback on shortId derivation
    - Use last-8 chars of transcript UUID instead of first-8, matching
      getSessionIdShort()'s .slice(-8) convention. Same session now produces the
      same filename whether shortId comes from CLAUDE_SESSION_ID or transcript_path,
      so existing .tmp files are not orphaned on upgrade.
    - Normalize extracted hex prefix to lowercase to avoid case-driven filename
      divergence from sanitizeSessionId()'s lowercase output.
    - Explicitly clear CLAUDE_SESSION_ID in the first regression test so the env
      leak from parent test runs cannot hide the fallback path.
    - Add regression tests for the lowercase-normalization path and for the case
      where CLAUDE_SESSION_ID and transcript_path refer to the same UUID (backward
      compat guarantee).
    
    Refs #1494
  • fix(hooks): isolate session-end.js filename using transcript_path UUID
    When session-end.js runs and CLAUDE_SESSION_ID is unset, getSessionIdShort()
    falls back to the project/worktree name. If any other Stop-hook in the chain
    spawns a claude subprocess (e.g. an AI-summary generator using 'claude -p'),
    the subprocess also fires the full Stop chain and writes to the same project-
    name-based filename, clobbering the parent's valid session summary with a
    summary of the summarization prompt itself.
    
    Fix: when stdin JSON (or CLAUDE_TRANSCRIPT_PATH) provides a transcript_path,
    extract the first 8 hex chars of the session UUID from the filename and use
    that as shortId. Falls back to the original getSessionIdShort() when no
    transcript_path is available, so existing behavior is preserved for all
    callers that do not set it.
    
    Adds a regression test in tests/hooks/hooks.test.js.
    
    Refs #1494
  • fix: remove agents field from plugin.json manifest (#1459)
    The Claude Code plugin validator rejects the "agents" field entirely.
    Remove it from the manifest, schema, and tests. Update schema notes
    to document this as a known constraint alongside the hooks field.
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • Merge pull request #1462 from affaan-m/fix/remove-legacy-ecc-install-refs
    fix: restore string hook commands for Claude Code schema
  • Merge pull request #1448 from affaan-m/fix/manual-release-dispatch
    fix: allow manual release workflow dispatch
  • Merge pull request #1446 from affaan-m/fix/release-publish-and-migration-docs
    fix: publish npm releases and clarify install identifiers
  • Merge pull request #1445 from affaan-m/fix/plugin-installed-hook-root-resolution
    fix: resolve plugin-installed hook root on marketplace installs
  • Merge pull request #1439 from affaan-m/fix/urgent-install-and-name
    fix: unblock urgent install and gateguard regressions