fix: shorten plugin slug to ecc

This commit is contained in:
Affaan Mustafa
2026-04-05 14:31:30 -07:00
parent 908116d736
commit 1346f83b08
27 changed files with 233 additions and 144 deletions

View File

@@ -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": "../.."

View File

@@ -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",

View File

@@ -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": {

View File

@@ -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 |

View File

@@ -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": {

View File

@@ -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
<summary><b>How do I check which agents/commands are installed?</b></summary>
```bash
/plugin list everything-claude-code@everything-claude-code
/plugin list ecc@ecc
```
This shows all available agents, commands, and skills from the plugin.

View File

@@ -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
}
}
```

View File

@@ -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

View File

@@ -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:

View File

@@ -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
}
}
```

View File

@@ -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" と言って起動します
---

View File

@@ -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/
<summary><b>설치된 에이전트/커맨드 확인은 어떻게 하나요?</b></summary>
```bash
/plugin list everything-claude-code@everything-claude-code
/plugin list ecc@ecc
```
플러그인에서 사용할 수 있는 모든 에이전트, 커맨드, 스킬을 보여줍니다.

View File

@@ -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 à
<summary><b>Como verificar quais agentes/comandos estão instalados?</b></summary>
```bash
/plugin list everything-claude-code@everything-claude-code
/plugin list ecc@ecc
```
</details>

View File

@@ -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
<summary><b>Hangi agent/command'ların kurulu olduğunu nasıl kontrol ederim?</b></summary>
```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.

View File

@@ -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

View File

@@ -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/
<summary><b>如何检查已安装的代理/命令?</b></summary>
```bash
/plugin list everything-claude-code@everything-claude-code
/plugin list ecc@ecc
```
这会显示插件中所有可用的代理、命令和技能。

View File

@@ -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

View File

@@ -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" 激活
***

View File

@@ -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
}
}
```

View File

@@ -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
}

View File

@@ -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.',

View File

@@ -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/<org>/<version>/
// Walk versioned cache: ~/.claude/plugins/cache/{ecc,everything-claude-code}/<org>/<version>/
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;
}
}
}
}

View File

@@ -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/<plugin-name>/<org>/<version>/
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 = <paste INLINE_RESOLVE>;
* 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,

View File

@@ -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"
---

View File

@@ -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})`,

View File

@@ -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') {

View File

@@ -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 });