From 1346f83b08b0bedef56e63810ca0119e5054678d Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Sun, 5 Apr 2026 14:31:30 -0700 Subject: [PATCH] fix: shorten plugin slug to ecc --- .agents/plugins/marketplace.json | 4 +- .claude-plugin/marketplace.json | 4 +- .claude-plugin/plugin.json | 2 +- .codex-plugin/README.md | 3 ++ .codex-plugin/plugin.json | 2 +- README.md | 20 ++++---- README.zh-CN.md | 12 ++--- TROUBLESHOOTING.md | 2 +- WORKING-CONTEXT.md | 1 + docs/ja-JP/README.md | 12 ++--- docs/ja-JP/skills/configure-ecc/SKILL.md | 2 +- docs/ko-KR/README.md | 20 ++++---- docs/pt-BR/README.md | 20 ++++---- docs/tr/README.md | 14 +++--- docs/tr/TROUBLESHOOTING.md | 2 +- docs/zh-CN/README.md | 20 ++++---- docs/zh-CN/TROUBLESHOOTING.md | 2 +- docs/zh-CN/skills/configure-ecc/SKILL.md | 2 +- docs/zh-TW/README.md | 12 ++--- hooks/hooks.json | 14 +++--- scripts/harness-audit.js | 22 ++++++--- scripts/hooks/session-start-bootstrap.js | 44 +++++++++++------ scripts/lib/resolve-ecc-root.js | 62 +++++++++++++++--------- skills/configure-ecc/SKILL.md | 2 +- tests/lib/resolve-ecc-root.test.js | 55 ++++++++++++++++----- tests/plugin-manifest.test.js | 16 ++++++ tests/scripts/harness-audit.test.js | 6 +-- 27 files changed, 233 insertions(+), 144 deletions(-) diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index a1561e41..14abfa12 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -1,11 +1,11 @@ { - "name": "everything-claude-code", + "name": "ecc", "interface": { "displayName": "Everything Claude Code" }, "plugins": [ { - "name": "everything-claude-code", + "name": "ecc", "source": { "source": "local", "path": "../.." diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 3bc2bb09..bdae85c8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,6 +1,6 @@ { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", - "name": "everything-claude-code", + "name": "ecc", "description": "Battle-tested Claude Code configurations from an Anthropic hackathon winner — agents, skills, hooks, rules, and legacy command shims evolved over 10+ months of intensive daily use", "owner": { "name": "Affaan Mustafa", @@ -11,7 +11,7 @@ }, "plugins": [ { - "name": "everything-claude-code", + "name": "ecc", "source": "./", "description": "The most comprehensive Claude Code plugin — 38 agents, 156 skills, 72 legacy command shims, selective install profiles, and production-ready hooks for TDD, security scanning, code review, and continuous learning", "version": "1.10.0", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 9ccf8884..44a6b536 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,5 +1,5 @@ { - "name": "everything-claude-code", + "name": "ecc", "version": "1.10.0", "description": "Battle-tested Claude Code plugin for engineering teams — 38 agents, 156 skills, 72 legacy command shims, production-ready hooks, and selective install workflows evolved through continuous real-world use", "author": { diff --git a/.codex-plugin/README.md b/.codex-plugin/README.md index 32281142..66e090f2 100644 --- a/.codex-plugin/README.md +++ b/.codex-plugin/README.md @@ -30,6 +30,9 @@ codex plugin install ./ Run this from the repository root so `./` points to the repo root and `.mcp.json` resolves correctly. ``` +The installed plugin registers under the short slug `ecc` so tool and command names +stay below provider length limits. + ## MCP Servers Included | Server | Purpose | diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 04a481e2..f5c7aa2b 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,5 +1,5 @@ { - "name": "everything-claude-code", + "name": "ecc", "version": "1.10.0", "description": "Battle-tested Codex workflows — 156 shared ECC skills, production-ready MCP configs, and selective-install-aligned conventions for TDD, security scanning, code review, and autonomous development.", "author": { diff --git a/README.md b/README.md index a9d5c620..adc6491f 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ Get up and running in under 2 minutes: /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Install plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### Step 2: Install Rules (Required) @@ -227,13 +227,13 @@ For manual install instructions see the README in the `rules/` folder. When copy # Existing slash-style command names still work while ECC migrates off commands/. # Plugin install uses the namespaced form -/everything-claude-code:plan "Add user authentication" +/ecc:plan "Add user authentication" # Manual install keeps the shorter slash form: # /plan "Add user authentication" # Check available commands -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **That's it!** You now have access to 38 agents, 159 skills, and 72 legacy command shims. @@ -621,7 +621,7 @@ The easiest way to use this repo - install as a Claude Code plugin: /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Install the plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` Or add directly to your `~/.claude/settings.json`: @@ -629,7 +629,7 @@ Or add directly to your `~/.claude/settings.json`: ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -637,7 +637,7 @@ Or add directly to your `~/.claude/settings.json`: } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` @@ -781,8 +781,8 @@ Not sure where to start? Use this quick reference. Skills are the canonical work | I want to... | Use this command | Agent used | |--------------|-----------------|------------| -| Plan a new feature | `/everything-claude-code:plan "Add auth"` | planner | -| Design system architecture | `/everything-claude-code:plan` + architect agent | architect | +| Plan a new feature | `/ecc:plan "Add auth"` | planner | +| Design system architecture | `/ecc:plan` + architect agent | architect | | Write code with tests first | `/tdd` | tdd-guide | | Review code I just wrote | `/code-review` | code-reviewer | | Fix a failing build | `/build-fix` | build-error-resolver | @@ -801,7 +801,7 @@ Slash forms below are shown because they are still the fastest familiar entrypoi **Starting a new feature:** ``` -/everything-claude-code:plan "Add user authentication with OAuth" +/ecc:plan "Add user authentication with OAuth" → planner creates implementation blueprint /tdd → tdd-guide enforces write-tests-first /code-review → code-reviewer checks your work @@ -829,7 +829,7 @@ Slash forms below are shown because they are still the fastest familiar entrypoi How do I check which agents/commands are installed? ```bash -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` This shows all available agents, commands, and skills from the plugin. diff --git a/README.zh-CN.md b/README.zh-CN.md index 0a421020..df7ef956 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -71,7 +71,7 @@ /plugin marketplace add affaan-m/everything-claude-code # 安装插件 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### 第二步:安装规则(必需) @@ -97,13 +97,13 @@ cp -r everything-claude-code/rules/perl ~/.claude/rules/ ```bash # 尝试一个命令(插件安装使用命名空间形式) -/everything-claude-code:plan "添加用户认证" +/ecc:plan "添加用户认证" # 手动安装(选项2)使用简短形式: # /plan "添加用户认证" # 查看可用命令 -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **完成!** 你现在可以使用 38 个代理、159 个技能和 72 个命令。 @@ -339,7 +339,7 @@ everything-claude-code/ /plugin marketplace add affaan-m/everything-claude-code # 安装插件 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` 或直接添加到你的 `~/.claude/settings.json`: @@ -347,7 +347,7 @@ everything-claude-code/ ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -355,7 +355,7 @@ everything-claude-code/ } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 57ffa2e4..4aed5eae 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -370,7 +370,7 @@ chmod -R u+rwX,go+rX ~/.claude/homunculus ```bash # Install plugin dependencies -cd ~/.claude/plugins/cache/everything-claude-code +cd ~/.claude/plugins/cache/ecc npm install # Or for manual install diff --git a/WORKING-CONTEXT.md b/WORKING-CONTEXT.md index e533e3bd..b38d1bfc 100644 --- a/WORKING-CONTEXT.md +++ b/WORKING-CONTEXT.md @@ -11,6 +11,7 @@ Public ECC plugin repo for agents, skills, commands, hooks, rules, install surfa - Default branch: `main` - Public release surface is aligned at `v1.10.0` - Public catalog truth is `38` agents, `72` commands, and `159` skills +- Public plugin slug is now `ecc`; legacy `everything-claude-code` install paths remain supported for compatibility - Release discussion: `#1272` - ECC 2.0 exists in-tree and builds, but it is still alpha rather than GA - Main active operational work: diff --git a/docs/ja-JP/README.md b/docs/ja-JP/README.md index 6d50088f..f35cb4f4 100644 --- a/docs/ja-JP/README.md +++ b/docs/ja-JP/README.md @@ -110,7 +110,7 @@ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # プラグインをインストール -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### ステップ2:ルールをインストール(必須) @@ -134,13 +134,13 @@ cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ ```bash # コマンドを試す(プラグインはネームスペース形式) -/everything-claude-code:plan "ユーザー認証を追加" +/ecc:plan "ユーザー認証を追加" # 手動インストール(オプション2)は短縮形式: # /plan "ユーザー認証を追加" # 利用可能なコマンドを確認 -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **完了です!** これで13のエージェント、43のスキル、31のコマンドにアクセスできます。 @@ -427,7 +427,7 @@ Duplicate hook file detected: ./hooks/hooks.json is already resolved to a loaded /plugin marketplace add https://github.com/affaan-m/everything-claude-code # プラグインをインストール -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` または、`~/.claude/settings.json` に直接追加: @@ -435,7 +435,7 @@ Duplicate hook file detected: ./hooks/hooks.json is already resolved to a loaded ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -443,7 +443,7 @@ Duplicate hook file detected: ./hooks/hooks.json is already resolved to a loaded } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` diff --git a/docs/ja-JP/skills/configure-ecc/SKILL.md b/docs/ja-JP/skills/configure-ecc/SKILL.md index 0a9ba790..7f55f686 100644 --- a/docs/ja-JP/skills/configure-ecc/SKILL.md +++ b/docs/ja-JP/skills/configure-ecc/SKILL.md @@ -17,7 +17,7 @@ Everything Claude Code プロジェクトのインタラクティブなステッ ## 前提条件 このスキルは起動前に Claude Code からアクセス可能である必要があります。ブートストラップには2つの方法があります: -1. **プラグイン経由**: `/plugin install everything-claude-code` — プラグインがこのスキルを自動的にロードします +1. **プラグイン経由**: `/plugin install ecc@ecc` — プラグインがこのスキルを自動的にロードします 2. **手動**: このスキルのみを `~/.claude/skills/configure-ecc/SKILL.md` にコピーし、"configure ecc" と言って起動します --- diff --git a/docs/ko-KR/README.md b/docs/ko-KR/README.md index 163c3ac0..5bff5224 100644 --- a/docs/ko-KR/README.md +++ b/docs/ko-KR/README.md @@ -115,7 +115,7 @@ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 플러그인 설치 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### 2단계: 룰 설치 (필수) @@ -141,13 +141,13 @@ cd everything-claude-code ```bash # 커맨드 실행 (플러그인 설치 시 네임스페이스 형태 사용) -/everything-claude-code:plan "사용자 인증 추가" +/ecc:plan "사용자 인증 추가" # 수동 설치(옵션 2) 시에는 짧은 형태를 사용: # /plan "사용자 인증 추가" # 사용 가능한 커맨드 확인 -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **끝!** 이제 16개 에이전트, 65개 스킬, 40개 커맨드를 사용할 수 있습니다. @@ -359,7 +359,7 @@ Claude Code v2.1+는 설치된 플러그인의 `hooks/hooks.json`을 **자동으 /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 플러그인 설치 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` 또는 `~/.claude/settings.json`에 직접 추가: @@ -367,7 +367,7 @@ Claude Code v2.1+는 설치된 플러그인의 `hooks/hooks.json`을 **자동으 ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -375,7 +375,7 @@ Claude Code v2.1+는 설치된 플러그인의 `hooks/hooks.json`을 **자동으 } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` @@ -489,8 +489,8 @@ rules/ | 하고 싶은 것 | 사용할 커맨드 | 사용되는 에이전트 | |-------------|-------------|-----------------| -| 새 기능 계획하기 | `/everything-claude-code:plan "인증 추가"` | planner | -| 시스템 아키텍처 설계 | `/everything-claude-code:plan` + architect 에이전트 | architect | +| 새 기능 계획하기 | `/ecc:plan "인증 추가"` | planner | +| 시스템 아키텍처 설계 | `/ecc:plan` + architect 에이전트 | architect | | 테스트를 먼저 작성하며 코딩 | `/tdd` | tdd-guide | | 방금 작성한 코드 리뷰 | `/code-review` | code-reviewer | | 빌드 실패 수정 | `/build-fix` | build-error-resolver | @@ -507,7 +507,7 @@ rules/ **새로운 기능 시작:** ``` -/everything-claude-code:plan "OAuth를 사용한 사용자 인증 추가" +/ecc:plan "OAuth를 사용한 사용자 인증 추가" → planner가 구현 청사진 작성 /tdd → tdd-guide가 테스트 먼저 작성 강제 /code-review → code-reviewer가 코드 검토 @@ -535,7 +535,7 @@ rules/ 설치된 에이전트/커맨드 확인은 어떻게 하나요? ```bash -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` 플러그인에서 사용할 수 있는 모든 에이전트, 커맨드, 스킬을 보여줍니다. diff --git a/docs/pt-BR/README.md b/docs/pt-BR/README.md index ce009ce2..65f6f47d 100644 --- a/docs/pt-BR/README.md +++ b/docs/pt-BR/README.md @@ -115,7 +115,7 @@ Comece em menos de 2 minutos: /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Instalar plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### Passo 2: Instalar as Regras (Obrigatório) @@ -152,13 +152,13 @@ npx ecc-install typescript ```bash # Experimente um comando (a instalação do plugin usa forma com namespace) -/everything-claude-code:plan "Adicionar autenticação de usuário" +/ecc:plan "Adicionar autenticação de usuário" # Instalação manual (Opção 2) usa a forma mais curta: # /plan "Adicionar autenticação de usuário" # Verificar comandos disponíveis -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **Pronto!** Você agora tem acesso a 28 agentes, 116 skills e 59 comandos. @@ -304,7 +304,7 @@ claude --version /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Instalar o plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` Ou adicione diretamente ao seu `~/.claude/settings.json`: @@ -312,7 +312,7 @@ Ou adicione diretamente ao seu `~/.claude/settings.json`: ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -320,7 +320,7 @@ Ou adicione diretamente ao seu `~/.claude/settings.json`: } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` @@ -399,8 +399,8 @@ Regras são diretrizes sempre seguidas, organizadas em `common/` (agnóstico à | Quero... | Use este comando | Agente usado | |----------|-----------------|--------------| -| Planejar um novo recurso | `/everything-claude-code:plan "Adicionar auth"` | planner | -| Projetar arquitetura de sistema | `/everything-claude-code:plan` + agente architect | architect | +| Planejar um novo recurso | `/ecc:plan "Adicionar auth"` | planner | +| Projetar arquitetura de sistema | `/ecc:plan` + agente architect | architect | | Escrever código com testes primeiro | `/tdd` | tdd-guide | | Revisar código que acabei de escrever | `/code-review` | code-reviewer | | Corrigir build com falha | `/build-fix` | build-error-resolver | @@ -415,7 +415,7 @@ Regras são diretrizes sempre seguidas, organizadas em `common/` (agnóstico à **Começando um novo recurso:** ``` -/everything-claude-code:plan "Adicionar autenticação de usuário com OAuth" +/ecc:plan "Adicionar autenticação de usuário com OAuth" → planner cria blueprint de implementação /tdd → tdd-guide aplica escrita de testes primeiro /code-review → code-reviewer verifica seu trabalho @@ -443,7 +443,7 @@ Regras são diretrizes sempre seguidas, organizadas em `common/` (agnóstico à Como verificar quais agentes/comandos estão instalados? ```bash -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` diff --git a/docs/tr/README.md b/docs/tr/README.md index 1cead38a..98a1de70 100644 --- a/docs/tr/README.md +++ b/docs/tr/README.md @@ -116,7 +116,7 @@ Bu repository yalnızca ham kodu içerir. Rehberler her şeyi açıklıyor. /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Plugin'i kur -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### Adım 2: Rule'ları Kurun (Gerekli) @@ -155,13 +155,13 @@ Manuel kurulum talimatları için `rules/` klasöründeki README'ye bakın. ```bash # Bir command deneyin (plugin kurulumu namespace'li form kullanır) -/everything-claude-code:plan "Kullanıcı kimlik doğrulaması ekle" +/ecc:plan "Kullanıcı kimlik doğrulaması ekle" # Manuel kurulum (Seçenek 2) daha kısa formu kullanır: # /plan "Kullanıcı kimlik doğrulaması ekle" # Mevcut command'ları kontrol edin -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **Bu kadar!** Artık 28 agent, 116 skill ve 59 command'a erişiminiz var. @@ -299,8 +299,8 @@ Nereden başlayacağınızdan emin değil misiniz? Bu hızlı referansı kullan | Yapmak istediğim... | Bu command'ı kullan | Kullanılan agent | |---------------------|---------------------|------------------| -| Yeni bir feature planla | `/everything-claude-code:plan "Auth ekle"` | planner | -| Sistem mimarisi tasarla | `/everything-claude-code:plan` + architect agent | architect | +| Yeni bir feature planla | `/ecc:plan "Auth ekle"` | planner | +| Sistem mimarisi tasarla | `/ecc:plan` + architect agent | architect | | Önce testlerle kod yaz | `/tdd` | tdd-guide | | Yazdığım kodu incele | `/code-review` | code-reviewer | | Başarısız bir build'i düzelt | `/build-fix` | build-error-resolver | @@ -315,7 +315,7 @@ Nereden başlayacağınızdan emin değil misiniz? Bu hızlı referansı kullan **Yeni bir feature başlatma:** ``` -/everything-claude-code:plan "OAuth ile kullanıcı kimlik doğrulaması ekle" +/ecc:plan "OAuth ile kullanıcı kimlik doğrulaması ekle" → planner implementasyon planı oluşturur /tdd → tdd-guide önce-test-yaz'ı zorunlu kılar /code-review → code-reviewer çalışmanızı kontrol eder @@ -343,7 +343,7 @@ Nereden başlayacağınızdan emin değil misiniz? Bu hızlı referansı kullan Hangi agent/command'ların kurulu olduğunu nasıl kontrol ederim? ```bash -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` Bu, plugin'den mevcut tüm agent'ları, command'ları ve skill'leri gösterir. diff --git a/docs/tr/TROUBLESHOOTING.md b/docs/tr/TROUBLESHOOTING.md index 866bfae6..00f3e5d9 100644 --- a/docs/tr/TROUBLESHOOTING.md +++ b/docs/tr/TROUBLESHOOTING.md @@ -370,7 +370,7 @@ chmod -R u+rwX,go+rX ~/.claude/homunculus ```bash # Eklenti bağımlılıklarını kur -cd ~/.claude/plugins/cache/everything-claude-code +cd ~/.claude/plugins/cache/ecc npm install # Veya manuel kurulum için diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md index 4636ddc8..5cefd63f 100644 --- a/docs/zh-CN/README.md +++ b/docs/zh-CN/README.md @@ -161,7 +161,7 @@ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Install plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### 步骤 2:安装规则(必需) @@ -200,13 +200,13 @@ npx ecc-install typescript ```bash # Try a command (plugin install uses namespaced form) -/everything-claude-code:plan "Add user authentication" +/ecc:plan "Add user authentication" # Manual install (Option 2) uses the shorter form: # /plan "Add user authentication" # Check available commands -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **搞定!** 你现在可以使用 38 个智能体、159 项技能和 72 个命令了。 @@ -585,7 +585,7 @@ Claude Code v2.1+ **会自动加载** 任何已安装插件中的 `hooks/hooks.j /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Install the plugin -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` 或者直接添加到您的 `~/.claude/settings.json`: @@ -593,7 +593,7 @@ Claude Code v2.1+ **会自动加载** 任何已安装插件中的 `hooks/hooks.j ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -601,7 +601,7 @@ Claude Code v2.1+ **会自动加载** 任何已安装插件中的 `hooks/hooks.j } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` @@ -744,8 +744,8 @@ rules/ | 我想要... | 使用此命令 | 使用的智能体 | |--------------|-----------------|------------| -| 规划新功能 | `/everything-claude-code:plan "Add auth"` | planner | -| 设计系统架构 | `/everything-claude-code:plan` + architect agent | architect | +| 规划新功能 | `/ecc:plan "Add auth"` | planner | +| 设计系统架构 | `/ecc:plan` + architect agent | architect | | 先写测试再写代码 | `/tdd` | tdd-guide | | 评审我刚写的代码 | `/code-review` | code-reviewer | | 修复失败的构建 | `/build-fix` | build-error-resolver | @@ -763,7 +763,7 @@ rules/ **开始新功能:** ``` -/everything-claude-code:plan "使用 OAuth 添加用户身份验证" +/ecc:plan "使用 OAuth 添加用户身份验证" → 规划器创建实现蓝图 /tdd → tdd-guide 强制执行先写测试 /code-review → 代码审查员检查你的工作 @@ -793,7 +793,7 @@ rules/ 如何检查已安装的代理/命令? ```bash -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` 这会显示插件中所有可用的代理、命令和技能。 diff --git a/docs/zh-CN/TROUBLESHOOTING.md b/docs/zh-CN/TROUBLESHOOTING.md index ab62f011..93f6a0fc 100644 --- a/docs/zh-CN/TROUBLESHOOTING.md +++ b/docs/zh-CN/TROUBLESHOOTING.md @@ -394,7 +394,7 @@ chmod -R u+rwX,go+rX ~/.claude/homunculus ```bash # Install plugin dependencies -cd ~/.claude/plugins/cache/everything-claude-code +cd ~/.claude/plugins/cache/ecc npm install # Or for manual install diff --git a/docs/zh-CN/skills/configure-ecc/SKILL.md b/docs/zh-CN/skills/configure-ecc/SKILL.md index fad024c3..95654941 100644 --- a/docs/zh-CN/skills/configure-ecc/SKILL.md +++ b/docs/zh-CN/skills/configure-ecc/SKILL.md @@ -19,7 +19,7 @@ origin: ECC 此技能必须在激活前对 Claude Code 可访问。有两种引导方式: -1. **通过插件**: `/plugin install everything-claude-code` — 插件会自动加载此技能 +1. **通过插件**: `/plugin install ecc@ecc` — 插件会自动加载此技能 2. **手动**: 仅将此技能复制到 `~/.claude/skills/configure-ecc/SKILL.md`,然后通过说 "configure ecc" 激活 *** diff --git a/docs/zh-TW/README.md b/docs/zh-TW/README.md index 99cb91ef..0095b8c3 100644 --- a/docs/zh-TW/README.md +++ b/docs/zh-TW/README.md @@ -70,7 +70,7 @@ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 安裝外掛程式 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` ### 第二步:安裝規則(必需) @@ -89,13 +89,13 @@ cp -r everything-claude-code/rules/* ~/.claude/rules/ ```bash # 嘗試一個指令(外掛安裝使用命名空間形式) -/everything-claude-code:plan "新增使用者認證" +/ecc:plan "新增使用者認證" # 手動安裝(選項2)使用簡短形式: # /plan "新增使用者認證" # 查看可用指令 -/plugin list everything-claude-code@everything-claude-code +/plugin list ecc@ecc ``` **完成!** 您現在使用 15+ 代理程式、30+ 技能和 20+ 指令。 @@ -270,7 +270,7 @@ everything-claude-code/ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 安裝外掛程式 -/plugin install everything-claude-code@everything-claude-code +/plugin install ecc@ecc ``` 或直接新增到您的 `~/.claude/settings.json`: @@ -278,7 +278,7 @@ everything-claude-code/ ```json { "extraKnownMarketplaces": { - "everything-claude-code": { + "ecc": { "source": { "source": "github", "repo": "affaan-m/everything-claude-code" @@ -286,7 +286,7 @@ everything-claude-code/ } }, "enabledPlugins": { - "everything-claude-code@everything-claude-code": true + "ecc@ecc": true } } ``` diff --git a/hooks/hooks.json b/hooks/hooks.json index 84f21a83..c0a38037 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -305,7 +305,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:format-typecheck','scripts/hooks/stop-format-typecheck.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:300000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:format-typecheck','scripts/hooks/stop-format-typecheck.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:300000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "timeout": 300 } ], @@ -317,7 +317,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:check-console-log','scripts/hooks/check-console-log.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"" + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:check-console-log','scripts/hooks/check-console-log.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"" } ], "description": "Check for console.log in modified files after each response", @@ -328,7 +328,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:session-end','scripts/hooks/session-end.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:session-end','scripts/hooks/session-end.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "async": true, "timeout": 10 } @@ -341,7 +341,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:evaluate-session','scripts/hooks/evaluate-session.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:evaluate-session','scripts/hooks/evaluate-session.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "async": true, "timeout": 10 } @@ -354,7 +354,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:cost-tracker','scripts/hooks/cost-tracker.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:cost-tracker','scripts/hooks/cost-tracker.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "async": true, "timeout": 10 } @@ -367,7 +367,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:desktop-notify','scripts/hooks/desktop-notify.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'stop:desktop-notify','scripts/hooks/desktop-notify.js','standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[Stop] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[Stop] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "async": true, "timeout": 10 } @@ -382,7 +382,7 @@ "hooks": [ { "type": "command", - "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{const cacheBase=path.join(claudeDir,'plugins','cache','everything-claude-code');for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'session:end:marker','scripts/hooks/session-end-marker.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[SessionEnd] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[SessionEnd] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", + "command": "node -e \"const fs=require('fs');const path=require('path');const {spawnSync}=require('child_process');const raw=fs.readFileSync(0,'utf8');const rel=path.join('scripts','hooks','run-with-flags.js');const hasRunnerRoot=candidate=>{const value=typeof candidate==='string'?candidate.trim():'';return value.length>0&&fs.existsSync(path.join(path.resolve(value),rel));};const root=(()=>{const envRoot=process.env.CLAUDE_PLUGIN_ROOT||'';if(hasRunnerRoot(envRoot))return path.resolve(envRoot.trim());const home=require('os').homedir();const claudeDir=path.join(home,'.claude');if(hasRunnerRoot(claudeDir))return claudeDir;for(const candidate of [path.join(claudeDir,'plugins','ecc'),path.join(claudeDir,'plugins','ecc@ecc'),path.join(claudeDir,'plugins','marketplace','ecc'),path.join(claudeDir,'plugins','everything-claude-code'),path.join(claudeDir,'plugins','everything-claude-code@everything-claude-code'),path.join(claudeDir,'plugins','marketplace','everything-claude-code')]){if(hasRunnerRoot(candidate))return candidate;}try{for(const slug of ['ecc','everything-claude-code']){const cacheBase=path.join(claudeDir,'plugins','cache',slug);for(const org of fs.readdirSync(cacheBase,{withFileTypes:true})){if(!org.isDirectory())continue;for(const version of fs.readdirSync(path.join(cacheBase,org.name),{withFileTypes:true})){if(!version.isDirectory())continue;const candidate=path.join(cacheBase,org.name,version.name);if(hasRunnerRoot(candidate))return candidate;}}}}catch{}return claudeDir;})();const script=path.join(root,rel);if(fs.existsSync(script)){const result=spawnSync(process.execPath,[script,'session:end:marker','scripts/hooks/session-end-marker.js','minimal,standard,strict'],{input:raw,encoding:'utf8',env:process.env,cwd:process.cwd(),timeout:30000});const stdout=typeof result.stdout==='string'?result.stdout:'';if(stdout)process.stdout.write(stdout);else process.stdout.write(raw);if(result.stderr)process.stderr.write(result.stderr);if(result.error||result.status===null||result.signal){const reason=result.error?result.error.message:(result.signal?'signal '+result.signal:'missing exit status');process.stderr.write('[SessionEnd] ERROR: hook runner failed: '+reason+String.fromCharCode(10));process.exit(1);}process.exit(Number.isInteger(result.status)?result.status:0);}process.stderr.write('[SessionEnd] WARNING: could not resolve ECC plugin root; skipping hook'+String.fromCharCode(10));process.stdout.write(raw);\"", "async": true, "timeout": 10 } diff --git a/scripts/harness-audit.js b/scripts/harness-audit.js index 836eb15a..6180eb48 100644 --- a/scripts/harness-audit.js +++ b/scripts/harness-audit.js @@ -188,12 +188,22 @@ function detectTargetMode(rootDir) { function findPluginInstall(rootDir) { const homeDir = process.env.HOME || ''; - const candidates = [ - path.join(rootDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'), - path.join(rootDir, '.claude', 'plugins', 'everything-claude-code', 'plugin.json'), - homeDir && path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'), - homeDir && path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', 'plugin.json'), + const pluginDirs = [ + 'ecc', + 'ecc@ecc', + 'everything-claude-code', + 'everything-claude-code@everything-claude-code', + ]; + const candidateRoots = [ + path.join(rootDir, '.claude', 'plugins'), + homeDir && path.join(homeDir, '.claude', 'plugins'), ].filter(Boolean); + const candidates = candidateRoots.flatMap((pluginsDir) => + pluginDirs.flatMap((pluginDir) => [ + path.join(pluginsDir, pluginDir, '.claude-plugin', 'plugin.json'), + path.join(pluginsDir, pluginDir, 'plugin.json'), + ]) + ); return candidates.find(candidate => fs.existsSync(candidate)) || null; } @@ -480,7 +490,7 @@ function getConsumerChecks(rootDir) { category: 'Tool Coverage', points: 4, scopes: ['repo'], - path: '~/.claude/plugins/everything-claude-code/', + path: '~/.claude/plugins/ecc/ (legacy everything-claude-code paths also supported)', description: 'Everything Claude Code is installed for the active user or project', pass: Boolean(pluginInstall), fix: 'Install the ECC plugin for this user or project before auditing project-specific harness quality.', diff --git a/scripts/hooks/session-start-bootstrap.js b/scripts/hooks/session-start-bootstrap.js index 581df60b..eb911400 100644 --- a/scripts/hooks/session-start-bootstrap.js +++ b/scripts/hooks/session-start-bootstrap.js @@ -30,6 +30,18 @@ const fs = require('fs'); const path = require('path'); const { spawnSync } = require('child_process'); +const CURRENT_PLUGIN_SLUG = 'ecc'; +const LEGACY_PLUGIN_SLUG = 'everything-claude-code'; +const KNOWN_PLUGIN_PATHS = [ + [CURRENT_PLUGIN_SLUG], + [`${CURRENT_PLUGIN_SLUG}@${CURRENT_PLUGIN_SLUG}`], + ['marketplace', CURRENT_PLUGIN_SLUG], + [LEGACY_PLUGIN_SLUG], + [`${LEGACY_PLUGIN_SLUG}@${LEGACY_PLUGIN_SLUG}`], + ['marketplace', LEGACY_PLUGIN_SLUG], +]; +const CACHE_PLUGIN_SLUGS = [CURRENT_PLUGIN_SLUG, LEGACY_PLUGIN_SLUG]; + // Read the raw JSON event from stdin const raw = fs.readFileSync(0, 'utf8'); @@ -52,8 +64,8 @@ function hasRunnerRoot(candidate) { * Resolves the ECC plugin root using the following priority order: * 1. CLAUDE_PLUGIN_ROOT environment variable * 2. ~/.claude (direct install) - * 3. Several well-known plugin sub-paths under ~/.claude/plugins/ - * 4. Versioned cache directories under ~/.claude/plugins/cache/everything-claude-code/ + * 3. Several well-known plugin sub-paths under ~/.claude/plugins/ (current + legacy) + * 4. Versioned cache directories under ~/.claude/plugins/cache/{ecc,everything-claude-code}/ * 5. Falls back to ~/.claude if nothing else matches * * @returns {string} @@ -71,11 +83,9 @@ function resolvePluginRoot() { return claudeDir; } - const knownPaths = [ - path.join(claudeDir, 'plugins', 'everything-claude-code'), - path.join(claudeDir, 'plugins', 'everything-claude-code@everything-claude-code'), - path.join(claudeDir, 'plugins', 'marketplace', 'everything-claude-code'), - ]; + const knownPaths = KNOWN_PLUGIN_PATHS.map((segments) => + path.join(claudeDir, 'plugins', ...segments) + ); for (const candidate of knownPaths) { if (hasRunnerRoot(candidate)) { @@ -83,16 +93,18 @@ function resolvePluginRoot() { } } - // Walk versioned cache: ~/.claude/plugins/cache/everything-claude-code/// + // Walk versioned cache: ~/.claude/plugins/cache/{ecc,everything-claude-code}/// try { - const cacheBase = path.join(claudeDir, 'plugins', 'cache', 'everything-claude-code'); - for (const org of fs.readdirSync(cacheBase, { withFileTypes: true })) { - if (!org.isDirectory()) continue; - for (const version of fs.readdirSync(path.join(cacheBase, org.name), { withFileTypes: true })) { - if (!version.isDirectory()) continue; - const candidate = path.join(cacheBase, org.name, version.name); - if (hasRunnerRoot(candidate)) { - return candidate; + for (const slug of CACHE_PLUGIN_SLUGS) { + const cacheBase = path.join(claudeDir, 'plugins', 'cache', slug); + for (const org of fs.readdirSync(cacheBase, { withFileTypes: true })) { + if (!org.isDirectory()) continue; + for (const version of fs.readdirSync(path.join(cacheBase, org.name), { withFileTypes: true })) { + if (!version.isDirectory()) continue; + const candidate = path.join(cacheBase, org.name, version.name); + if (hasRunnerRoot(candidate)) { + return candidate; + } } } } diff --git a/scripts/lib/resolve-ecc-root.js b/scripts/lib/resolve-ecc-root.js index c282a263..d5456ee5 100644 --- a/scripts/lib/resolve-ecc-root.js +++ b/scripts/lib/resolve-ecc-root.js @@ -4,14 +4,28 @@ const fs = require('fs'); const path = require('path'); const os = require('os'); +const CURRENT_PLUGIN_SLUG = 'ecc'; +const LEGACY_PLUGIN_SLUG = 'everything-claude-code'; +const CURRENT_PLUGIN_HANDLE = `${CURRENT_PLUGIN_SLUG}@${CURRENT_PLUGIN_SLUG}`; +const LEGACY_PLUGIN_HANDLE = `${LEGACY_PLUGIN_SLUG}@${LEGACY_PLUGIN_SLUG}`; +const PLUGIN_CACHE_SLUGS = [CURRENT_PLUGIN_SLUG, LEGACY_PLUGIN_SLUG]; +const PLUGIN_ROOT_SEGMENTS = [ + [CURRENT_PLUGIN_SLUG], + [CURRENT_PLUGIN_HANDLE], + ['marketplace', CURRENT_PLUGIN_SLUG], + [LEGACY_PLUGIN_SLUG], + [LEGACY_PLUGIN_HANDLE], + ['marketplace', LEGACY_PLUGIN_SLUG], +]; + /** * Resolve the ECC source root directory. * * Tries, in order: * 1. CLAUDE_PLUGIN_ROOT env var (set by Claude Code for hooks, or by user) * 2. Standard install location (~/.claude/) — when scripts exist there - * 3. Exact legacy plugin roots under ~/.claude/plugins/ - * 4. Plugin cache auto-detection — scans ~/.claude/plugins/cache/everything-claude-code/ + * 3. Known plugin roots under ~/.claude/plugins/ (current + legacy slugs) + * 4. Plugin cache auto-detection — scans ~/.claude/plugins/cache/{ecc,everything-claude-code}/ * 5. Fallback to ~/.claude/ (original behaviour) * * @param {object} [options] @@ -41,11 +55,9 @@ function resolveEccRoot(options = {}) { // Exact legacy plugin install locations. These preserve backwards // compatibility without scanning arbitrary plugin trees. - const legacyPluginRoots = [ - path.join(claudeDir, 'plugins', 'everything-claude-code'), - path.join(claudeDir, 'plugins', 'everything-claude-code@everything-claude-code'), - path.join(claudeDir, 'plugins', 'marketplace', 'everything-claude-code') - ]; + const legacyPluginRoots = PLUGIN_ROOT_SEGMENTS.map((segments) => + path.join(claudeDir, 'plugins', ...segments) + ); for (const candidate of legacyPluginRoots) { if (fs.existsSync(path.join(candidate, probe))) { @@ -56,25 +68,27 @@ function resolveEccRoot(options = {}) { // Plugin cache — Claude Code stores marketplace plugins under // ~/.claude/plugins/cache//// try { - const cacheBase = path.join(claudeDir, 'plugins', 'cache', 'everything-claude-code'); - const orgDirs = fs.readdirSync(cacheBase, { withFileTypes: true }); + for (const slug of PLUGIN_CACHE_SLUGS) { + const cacheBase = path.join(claudeDir, 'plugins', 'cache', slug); + const orgDirs = fs.readdirSync(cacheBase, { withFileTypes: true }); - for (const orgEntry of orgDirs) { - if (!orgEntry.isDirectory()) continue; - const orgPath = path.join(cacheBase, orgEntry.name); + for (const orgEntry of orgDirs) { + if (!orgEntry.isDirectory()) continue; + const orgPath = path.join(cacheBase, orgEntry.name); - let versionDirs; - try { - versionDirs = fs.readdirSync(orgPath, { withFileTypes: true }); - } catch { - continue; - } + let versionDirs; + try { + versionDirs = fs.readdirSync(orgPath, { withFileTypes: true }); + } catch { + continue; + } - for (const verEntry of versionDirs) { - if (!verEntry.isDirectory()) continue; - const candidate = path.join(orgPath, verEntry.name); - if (fs.existsSync(path.join(candidate, probe))) { - return candidate; + for (const verEntry of versionDirs) { + if (!verEntry.isDirectory()) continue; + const candidate = path.join(orgPath, verEntry.name); + if (fs.existsSync(path.join(candidate, probe))) { + return candidate; + } } } } @@ -96,7 +110,7 @@ function resolveEccRoot(options = {}) { * const _r = ; * const sm = require(_r + '/scripts/lib/session-manager'); */ -const INLINE_RESOLVE = `(()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;for(var l of [p.join(d,'plugins','everything-claude-code'),p.join(d,'plugins','everything-claude-code@everything-claude-code'),p.join(d,'plugins','marketplace','everything-claude-code')])if(f.existsSync(p.join(l,q)))return l;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b,{withFileTypes:true})){if(!o.isDirectory())continue;for(var v of f.readdirSync(p.join(b,o.name),{withFileTypes:true})){if(!v.isDirectory())continue;var c=p.join(b,o.name,v.name);if(f.existsSync(p.join(c,q)))return c}}}catch(x){}return d})()`; +const INLINE_RESOLVE = `(()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;for(var s of ${JSON.stringify(PLUGIN_ROOT_SEGMENTS)}){var l=p.join(d,'plugins',...s);if(f.existsSync(p.join(l,q)))return l}try{for(var g of ${JSON.stringify(PLUGIN_CACHE_SLUGS)}){var b=p.join(d,'plugins','cache',g);for(var o of f.readdirSync(b,{withFileTypes:true})){if(!o.isDirectory())continue;for(var v of f.readdirSync(p.join(b,o.name),{withFileTypes:true})){if(!v.isDirectory())continue;var c=p.join(b,o.name,v.name);if(f.existsSync(p.join(c,q)))return c}}}}catch(x){}return d})()`; module.exports = { resolveEccRoot, diff --git a/skills/configure-ecc/SKILL.md b/skills/configure-ecc/SKILL.md index 9521dd7d..f12848cb 100644 --- a/skills/configure-ecc/SKILL.md +++ b/skills/configure-ecc/SKILL.md @@ -18,7 +18,7 @@ An interactive, step-by-step installation wizard for the Everything Claude Code ## Prerequisites This skill must be accessible to Claude Code before activation. Two ways to bootstrap: -1. **Via Plugin**: `/plugin install everything-claude-code` — the plugin loads this skill automatically +1. **Via Plugin**: `/plugin install ecc@ecc` — the plugin loads this skill automatically 2. **Manual**: Copy only this skill to `~/.claude/skills/configure-ecc/SKILL.md`, then activate by saying "configure ecc" --- diff --git a/tests/lib/resolve-ecc-root.test.js b/tests/lib/resolve-ecc-root.test.js index 5ee4b4bd..628e53a9 100644 --- a/tests/lib/resolve-ecc-root.test.js +++ b/tests/lib/resolve-ecc-root.test.js @@ -47,10 +47,10 @@ function setupLegacyPluginInstall(homeDir, segments) { fs.writeFileSync(path.join(scriptDir, 'utils.js'), '// stub'); return legacyDir; } -function setupPluginCache(homeDir, orgName, version) { +function setupPluginCache(homeDir, pluginSlug, orgName, version) { const cacheDir = path.join( homeDir, '.claude', 'plugins', 'cache', - 'everything-claude-code', orgName, version + pluginSlug, orgName, version ); const scriptDir = path.join(cacheDir, 'scripts', 'lib'); fs.mkdirSync(scriptDir, { recursive: true }); @@ -111,6 +111,28 @@ function runTests() { } })) passed++; else failed++; + if (test('finds current plugin install at ~/.claude/plugins/ecc', () => { + const homeDir = createTempDir(); + try { + const expected = setupLegacyPluginInstall(homeDir, ['ecc']); + const result = resolveEccRoot({ envRoot: '', homeDir }); + assert.strictEqual(result, expected); + } finally { + fs.rmSync(homeDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + + if (test('finds current plugin install at ~/.claude/plugins/ecc@ecc', () => { + const homeDir = createTempDir(); + try { + const expected = setupLegacyPluginInstall(homeDir, ['ecc@ecc']); + const result = resolveEccRoot({ envRoot: '', homeDir }); + assert.strictEqual(result, expected); + } finally { + fs.rmSync(homeDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + if (test('finds exact legacy plugin install at ~/.claude/plugins/everything-claude-code', () => { const homeDir = createTempDir(); try { @@ -133,6 +155,17 @@ function runTests() { } })) passed++; else failed++; + if (test('finds marketplace current plugin install at ~/.claude/plugins/marketplace/ecc', () => { + const homeDir = createTempDir(); + try { + const expected = setupLegacyPluginInstall(homeDir, ['marketplace', 'ecc']); + const result = resolveEccRoot({ envRoot: '', homeDir }); + assert.strictEqual(result, expected); + } finally { + fs.rmSync(homeDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + if (test('finds marketplace legacy plugin install at ~/.claude/plugins/marketplace/everything-claude-code', () => { const homeDir = createTempDir(); try { @@ -147,8 +180,8 @@ function runTests() { if (test('prefers exact legacy plugin install over plugin cache', () => { const homeDir = createTempDir(); try { - const expected = setupLegacyPluginInstall(homeDir, ['marketplace', 'everything-claude-code']); - setupPluginCache(homeDir, 'everything-claude-code', '1.8.0'); + const expected = setupLegacyPluginInstall(homeDir, ['marketplace', 'ecc']); + setupPluginCache(homeDir, 'ecc', 'affaan-m', '1.10.0'); const result = resolveEccRoot({ envRoot: '', homeDir }); assert.strictEqual(result, expected); } finally { @@ -160,7 +193,7 @@ function runTests() { if (test('discovers plugin root from cache directory', () => { const homeDir = createTempDir(); try { - const expected = setupPluginCache(homeDir, 'everything-claude-code', '1.8.0'); + const expected = setupPluginCache(homeDir, 'ecc', 'affaan-m', '1.10.0'); const result = resolveEccRoot({ envRoot: '', homeDir }); assert.strictEqual(result, expected); } finally { @@ -172,7 +205,7 @@ function runTests() { const homeDir = createTempDir(); try { const claudeDir = setupStandardInstall(homeDir); - setupPluginCache(homeDir, 'everything-claude-code', '1.8.0'); + setupPluginCache(homeDir, 'ecc', 'affaan-m', '1.10.0'); const result = resolveEccRoot({ envRoot: '', homeDir }); assert.strictEqual(result, claudeDir, 'Standard install should take precedence over plugin cache'); @@ -184,13 +217,13 @@ function runTests() { if (test('handles multiple versions in plugin cache', () => { const homeDir = createTempDir(); try { - setupPluginCache(homeDir, 'everything-claude-code', '1.7.0'); - const expected = setupPluginCache(homeDir, 'everything-claude-code', '1.8.0'); + setupPluginCache(homeDir, 'everything-claude-code', 'legacy-org', '1.7.0'); + const expected = setupPluginCache(homeDir, 'ecc', 'affaan-m', '1.10.0'); const result = resolveEccRoot({ envRoot: '', homeDir }); // Should find one of them (either is valid) assert.ok( result === expected || - result === path.join(homeDir, '.claude', 'plugins', 'cache', 'everything-claude-code', 'everything-claude-code', '1.7.0'), + result === path.join(homeDir, '.claude', 'plugins', 'cache', 'everything-claude-code', 'legacy-org', '1.7.0'), 'Should resolve to a valid plugin cache directory' ); } finally { @@ -262,7 +295,7 @@ function runTests() { if (test('INLINE_RESOLVE discovers exact legacy plugin root when env var is unset', () => { const homeDir = createTempDir(); try { - const expected = setupLegacyPluginInstall(homeDir, ['marketplace', 'everything-claude-code']); + const expected = setupLegacyPluginInstall(homeDir, ['marketplace', 'ecc']); const { execFileSync } = require('child_process'); const result = execFileSync('node', [ '-e', `console.log(${INLINE_RESOLVE})`, @@ -278,7 +311,7 @@ function runTests() { if (test('INLINE_RESOLVE discovers plugin cache when env var is unset', () => { const homeDir = createTempDir(); try { - const expected = setupPluginCache(homeDir, 'everything-claude-code', '1.10.0'); + const expected = setupPluginCache(homeDir, 'ecc', 'affaan-m', '1.10.0'); const { execFileSync } = require('child_process'); const result = execFileSync('node', [ '-e', `console.log(${INLINE_RESOLVE})`, diff --git a/tests/plugin-manifest.test.js b/tests/plugin-manifest.test.js index 32510873..20ad64bb 100644 --- a/tests/plugin-manifest.test.js +++ b/tests/plugin-manifest.test.js @@ -79,6 +79,10 @@ test('claude plugin.json has version field', () => { assert.ok(claudePlugin.version, 'Expected version field'); }); +test('claude plugin.json uses short plugin slug', () => { + assert.strictEqual(claudePlugin.name, 'ecc'); +}); + test('claude plugin.json agents is an array', () => { assert.ok(Array.isArray(claudePlugin.agents), 'Expected agents to be an array (not a string/directory)'); }); @@ -146,6 +150,10 @@ test('codex plugin.json has name field', () => { assert.ok(codexPlugin.name, 'Expected name field'); }); +test('codex plugin.json uses short plugin slug', () => { + assert.strictEqual(codexPlugin.name, 'ecc'); +}); + test('codex plugin.json has version field', () => { assert.ok(codexPlugin.version, 'Expected version field'); }); @@ -240,6 +248,10 @@ test('marketplace.json has name field', () => { assert.ok(marketplace.name, 'Expected name field'); }); +test('marketplace.json uses short marketplace slug', () => { + assert.strictEqual(marketplace.name, 'ecc'); +}); + test('marketplace.json has plugins array with at least one entry', () => { assert.ok(Array.isArray(marketplace.plugins) && marketplace.plugins.length > 0, 'Expected plugins array'); }); @@ -253,6 +265,10 @@ test('marketplace.json plugin entries have required fields', () => { } }); +test('marketplace.json plugin entry uses short plugin slug', () => { + assert.strictEqual(marketplace.plugins[0].name, 'ecc'); +}); + test('marketplace local plugin path resolves to the repo-root Codex bundle', () => { for (const plugin of marketplace.plugins) { if (!plugin.source || plugin.source.source !== 'local') { diff --git a/tests/scripts/harness-audit.test.js b/tests/scripts/harness-audit.test.js index 0ec43faf..7019fd8b 100644 --- a/tests/scripts/harness-audit.test.js +++ b/tests/scripts/harness-audit.test.js @@ -99,10 +99,10 @@ function runTests() { const projectRoot = createTempDir('harness-audit-project-'); try { - fs.mkdirSync(path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin'), { recursive: true }); + fs.mkdirSync(path.join(homeDir, '.claude', 'plugins', 'ecc', '.claude-plugin'), { recursive: true }); fs.writeFileSync( - path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'), - JSON.stringify({ name: 'everything-claude-code' }, null, 2) + path.join(homeDir, '.claude', 'plugins', 'ecc', '.claude-plugin', 'plugin.json'), + JSON.stringify({ name: 'ecc' }, null, 2) ); fs.mkdirSync(path.join(projectRoot, '.github', 'workflows'), { recursive: true });