diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec623937..b8252d63 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,7 @@ on: permissions: contents: write + id-token: write jobs: release: @@ -22,6 +23,7 @@ jobs: uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: '20.x' + registry-url: 'https://registry.npmjs.org' - name: Install dependencies run: npm ci @@ -53,6 +55,23 @@ jobs: - name: Verify release metadata stays in sync run: node tests/plugin-manifest.test.js + - name: Check npm publish state + id: npm_publish_state + run: | + PACKAGE_NAME=$(node -p "require('./package.json').name") + PACKAGE_VERSION=$(node -p "require('./package.json').version") + if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then + echo "already_published=true" >> "$GITHUB_OUTPUT" + else + echo "already_published=false" >> "$GITHUB_OUTPUT" + fi + + - name: Publish npm package + if: steps.npm_publish_state.outputs.already_published != 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --access public --provenance + - name: Generate release highlights id: highlights env: @@ -73,6 +92,8 @@ jobs: - Improved release-note generation and changelog hygiene ### Notes + - npm package: \`ecc-universal\` + - Claude marketplace/plugin identifier: \`everything-claude-code@everything-claude-code\` - For migration tips and compatibility notes, see README and CHANGELOG. EOF diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml index 607c1aa4..4e4aaa48 100644 --- a/.github/workflows/reusable-release.yml +++ b/.github/workflows/reusable-release.yml @@ -12,9 +12,13 @@ on: required: false type: boolean default: true + secrets: + NPM_TOKEN: + required: false permissions: contents: write + id-token: write jobs: release: @@ -31,6 +35,7 @@ jobs: uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: '20.x' + registry-url: 'https://registry.npmjs.org' - name: Install dependencies run: npm ci @@ -62,6 +67,23 @@ jobs: - name: Verify release metadata stays in sync run: node tests/plugin-manifest.test.js + - name: Check npm publish state + id: npm_publish_state + run: | + PACKAGE_NAME=$(node -p "require('./package.json').name") + PACKAGE_VERSION=$(node -p "require('./package.json').version") + if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then + echo "already_published=true" >> "$GITHUB_OUTPUT" + else + echo "already_published=false" >> "$GITHUB_OUTPUT" + fi + + - name: Publish npm package + if: steps.npm_publish_state.outputs.already_published != 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --access public --provenance + - name: Generate release highlights env: TAG_NAME: ${{ inputs.tag }} @@ -74,6 +96,10 @@ jobs: - Harness reliability and cross-platform compatibility - Eval-driven quality improvements - Better workflow and operator ergonomics + + ### Package Notes + - npm package: \`ecc-universal\` + - Claude marketplace/plugin identifier: \`everything-claude-code@everything-claude-code\` EOF - name: Create GitHub Release diff --git a/README.md b/README.md index c1b5413a..cef08393 100644 --- a/README.md +++ b/README.md @@ -174,10 +174,18 @@ 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 +/plugin install everything-claude-code@everything-claude-code ``` -> Install-name clarification: older posts may still show `ecc@ecc`. That shorthand is deprecated. Anthropic marketplace/plugin installs are keyed by a canonical plugin identifier, so ECC standardized on `everything-claude-code@everything-claude-code` to keep the listing name, install path, `/plugin list`, and repo docs aligned instead of maintaining two different public names for the same plugin. +### Naming + Migration Note + +ECC now has three public identifiers, and they are not interchangeable: + +- GitHub source repo: `affaan-m/everything-claude-code` +- Claude marketplace/plugin identifier: `everything-claude-code@everything-claude-code` +- npm package: `ecc-universal` + +This is intentional. Anthropic marketplace/plugin installs are keyed by a canonical plugin identifier, so ECC standardized on `everything-claude-code@everything-claude-code` to keep the listing name, `/plugin install`, `/plugin list`, and repo docs aligned to one public install surface. Older posts may still show the old short-form nickname; that shorthand is deprecated. Separately, the npm package stayed on `ecc-universal`, so npm installs and marketplace installs intentionally use different names. ### Step 2: Install Rules (Required) @@ -185,6 +193,8 @@ Get up and running in under 2 minutes: > > If your local Claude setup was wiped or reset, that does not mean you need to repurchase ECC. Start with `ecc list-installed`, then run `ecc doctor` and `ecc repair` before reinstalling anything. That usually restores ECC-managed files without rebuilding your setup. If the problem is account or marketplace access for ECC Tools, handle billing/account recovery separately. +> If your local Claude setup was wiped or reset, that does not mean you need to repurchase ECC. Start with `ecc list-installed`, then run `ecc doctor` and `ecc repair` before reinstalling anything. That usually restores ECC-managed files without rebuilding your setup. If the problem is account or marketplace access for ECC Tools, handle billing/account recovery separately. + ```bash # Clone the repo first git clone https://github.com/affaan-m/everything-claude-code.git @@ -650,7 +660,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 +/plugin install everything-claude-code@everything-claude-code ``` Or add directly to your `~/.claude/settings.json`: diff --git a/README.zh-CN.md b/README.zh-CN.md index b6557064..c07b4e2d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -102,10 +102,10 @@ /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 安装插件 -/plugin install everything-claude-code +/plugin install everything-claude-code@everything-claude-code ``` -> 安装名称说明:较早的帖子里可能还会出现 `ecc@ecc`。那个旧缩写现在已经废弃。Anthropic 的 marketplace/plugin 安装是按规范化插件标识符寻址的,因此 ECC 统一为 `everything-claude-code@everything-claude-code`,这样市场条目、安装命令、`/plugin list` 输出和仓库文档都使用同一个公开名称,不再出现两个名字指向同一插件的混乱。 +> 安装名称说明:较早的帖子里可能还会出现旧的短别名。那个旧缩写现在已经废弃。Anthropic 的 marketplace/plugin 安装是按规范化插件标识符寻址的,因此 ECC 统一为 `everything-claude-code@everything-claude-code`,这样市场条目、安装命令、`/plugin list` 输出和仓库文档都使用同一个公开名称,不再出现两个名字指向同一插件的混乱。 ### 第二步:安装规则(必需) @@ -548,7 +548,7 @@ Claude Code v2.1+ 会**按照约定自动加载**已安装插件中的 `hooks/ho /plugin marketplace add https://github.com/affaan-m/everything-claude-code # 安装插件 -/plugin install everything-claude-code +/plugin install everything-claude-code@everything-claude-code ``` 或直接添加到你的 `~/.claude/settings.json`: diff --git a/docs/ja-JP/skills/configure-ecc/SKILL.md b/docs/ja-JP/skills/configure-ecc/SKILL.md index 1097c31c..e93a4d0a 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 everything-claude-code@everything-claude-code` — プラグインがこのスキルを自動的にロードします 2. **手動**: このスキルのみを `~/.claude/skills/configure-ecc/SKILL.md` にコピーし、"configure ecc" と言って起動します --- diff --git a/docs/pt-BR/README.md b/docs/pt-BR/README.md index e2ca54dd..3c490ccb 100644 --- a/docs/pt-BR/README.md +++ b/docs/pt-BR/README.md @@ -124,7 +124,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 +/plugin install everything-claude-code@everything-claude-code ``` ### Passo 2: Instalar as Regras (Obrigatório) @@ -313,7 +313,7 @@ claude --version /plugin marketplace add https://github.com/affaan-m/everything-claude-code # Instalar o plugin -/plugin install everything-claude-code +/plugin install everything-claude-code@everything-claude-code ``` Ou adicione diretamente ao seu `~/.claude/settings.json`: diff --git a/docs/zh-CN/skills/configure-ecc/SKILL.md b/docs/zh-CN/skills/configure-ecc/SKILL.md index 54b8f6df..872fc1c1 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 everything-claude-code@everything-claude-code` — 插件会自动加载此技能 2. **手动**: 仅将此技能复制到 `~/.claude/skills/configure-ecc/SKILL.md`,然后通过说 "configure ecc" 激活 *** diff --git a/package.json b/package.json index 8baa18d5..baa8c775 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "ecc-universal", "version": "1.10.0", "description": "Complete collection of battle-tested Claude Code configs — agents, skills, hooks, rules, and legacy command shims evolved over 10+ months of intensive daily use by an Anthropic hackathon winner", + "publishConfig": { + "access": "public" + }, "keywords": [ "claude-code", "ai", diff --git a/tests/docs/install-identifiers.test.js b/tests/docs/install-identifiers.test.js new file mode 100644 index 00000000..3a1975d7 --- /dev/null +++ b/tests/docs/install-identifiers.test.js @@ -0,0 +1,51 @@ +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const repoRoot = path.resolve(__dirname, '..', '..'); + +let passed = 0; +let failed = 0; + +function test(name, fn) { + try { + fn(); + console.log(` ✓ ${name}`); + passed++; + } catch (error) { + console.log(` ✗ ${name}`); + console.log(` Error: ${error.message}`); + failed++; + } +} + +const publicInstallDocs = [ + 'README.md', + 'README.zh-CN.md', + 'docs/pt-BR/README.md', + 'docs/ja-JP/skills/configure-ecc/SKILL.md', + 'docs/zh-CN/skills/configure-ecc/SKILL.md', +]; + +console.log('\n=== Testing public install identifiers ===\n'); + +for (const relativePath of publicInstallDocs) { + const content = fs.readFileSync(path.join(repoRoot, relativePath), 'utf8'); + + test(`${relativePath} does not use the stale ecc@ecc plugin identifier`, () => { + assert.ok(!content.includes('ecc@ecc')); + }); + + test(`${relativePath} documents the canonical marketplace plugin identifier`, () => { + assert.ok(content.includes('everything-claude-code@everything-claude-code')); + }); +} + +if (failed > 0) { + console.log(`\nFailed: ${failed}`); + process.exit(1); +} + +console.log(`\nPassed: ${passed}`); diff --git a/tests/scripts/release-publish.test.js b/tests/scripts/release-publish.test.js new file mode 100644 index 00000000..b09c6979 --- /dev/null +++ b/tests/scripts/release-publish.test.js @@ -0,0 +1,60 @@ +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const repoRoot = path.resolve(__dirname, '..', '..'); + +let passed = 0; +let failed = 0; + +function test(name, fn) { + try { + fn(); + console.log(` ✓ ${name}`); + passed++; + } catch (error) { + console.log(` ✗ ${name}`); + console.log(` Error: ${error.message}`); + failed++; + } +} + +function load(relativePath) { + return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8'); +} + +console.log('\n=== Testing release publish workflow ===\n'); + +for (const workflow of [ + '.github/workflows/release.yml', + '.github/workflows/reusable-release.yml', +]) { + const content = load(workflow); + + test(`${workflow} grants id-token for npm provenance`, () => { + assert.match(content, /permissions:\s*[\s\S]*id-token:\s*write/m); + }); + + test(`${workflow} configures the npm registry`, () => { + assert.match(content, /registry-url:\s*['"]https:\/\/registry\.npmjs\.org['"]/); + }); + + test(`${workflow} checks whether the tagged npm version already exists`, () => { + assert.match(content, /Check npm publish state/); + assert.match(content, /npm view "\$\{PACKAGE_NAME\}@\$\{PACKAGE_VERSION\}" version/); + }); + + test(`${workflow} publishes new tag versions to npm`, () => { + assert.match(content, /npm publish --access public --provenance/); + assert.match(content, /NODE_AUTH_TOKEN:\s*\$\{\{\s*secrets\.NPM_TOKEN\s*\}\}/); + }); +} + +if (failed > 0) { + console.log(`\nFailed: ${failed}`); + process.exit(1); +} + +console.log(`\nPassed: ${passed}`);