diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index 7b9b2d670..57735ad9c 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -4,7 +4,7 @@ This file provides Gemini CLI with the baseline ECC workflow, review standards, ## Overview -Everything Claude Code (ECC) is a cross-harness coding system with 36 specialized agents, 142 skills, and 68 commands. +Everything Claude Code (ECC) is a cross-harness coding system with 68 specialized agents, 286 skills, and 94 commands. Gemini support is currently focused on a strong project-local instruction layer via `.gemini/GEMINI.md`, plus the shared MCP catalog and package-manager setup assets shipped by the installer. diff --git a/SOUL.md b/SOUL.md index 38e79ffa3..b9f77891e 100644 --- a/SOUL.md +++ b/SOUL.md @@ -1,7 +1,7 @@ # Soul ## Core Identity -Everything Claude Code (ECC) is a production-ready AI coding plugin with 30 specialized agents, 135 skills, 60 commands, and automated hook workflows for software development. +Everything Claude Code (ECC) is a production-ready AI coding plugin with 68 specialized agents, 286 skills, 94 commands, and automated hook workflows for software development. ## Core Principles 1. **Agent-First** — route work to the right specialist as early as possible. diff --git a/scripts/ci/catalog.js b/scripts/ci/catalog.js index d538dad36..fffa37a3d 100644 --- a/scripts/ci/catalog.js +++ b/scripts/ci/catalog.js @@ -18,6 +18,8 @@ const path = require('path'); const ROOT = path.join(__dirname, '../..'); const README_PATH = path.join(ROOT, 'README.md'); const AGENTS_PATH = path.join(ROOT, 'AGENTS.md'); +const SOUL_PATH = path.join(ROOT, 'SOUL.md'); +const GEMINI_PATH = path.join(ROOT, '.gemini', 'GEMINI.md'); const README_ZH_CN_PATH = path.join(ROOT, 'README.zh-CN.md'); const DOCS_ZH_CN_README_PATH = path.join(ROOT, 'docs', 'zh-CN', 'README.md'); const DOCS_ZH_CN_AGENTS_PATH = path.join(ROOT, 'docs', 'zh-CN', 'AGENTS.md'); @@ -273,6 +275,30 @@ function parseAgentsDocExpectations(agentsContent) { return expectations; } +function parseCrossHarnessIdentityExpectations(content, source) { + const match = content.match(/with\s+(\d+)\s+specialized agents,\s+(\d+)\s+skills,\s+(?:and\s+)?(\d+)\s+commands/i); + if (!match) { + throw new Error(`${source} is missing the catalog summary line`); + } + + return [ + { category: 'agents', mode: 'exact', expected: Number(match[1]), source }, + { category: 'skills', mode: 'exact', expected: Number(match[2]), source }, + { category: 'commands', mode: 'exact', expected: Number(match[3]), source }, + ]; +} + +function syncCrossHarnessIdentity(content, catalog, source) { + return replaceOrThrow( + content, + /(with\s+)(\d+)(\s+specialized agents,\s+)(\d+)(\s+skills,\s+(?:and\s+)?)(\d+)(\s+commands)/i, + (_, prefix, __, agentsSuffix, ___, skillsSuffix, ____, commandsSuffix) => ( + `${prefix}${catalog.agents.count}${agentsSuffix}${catalog.skills.count}${skillsSuffix}${catalog.commands.count}${commandsSuffix}` + ), + source + ); +} + function parseZhAgentsDocExpectations(agentsContent) { const summaryMatch = agentsContent.match(/提供\s+(\d+)\s+个专业代理、\s*(\d+)(\+)?\s*项技能、\s*(\d+)\s+条命令/i); if (!summaryMatch) { @@ -563,6 +589,8 @@ function createDocumentSpecs(paths = {}) { const { readmePath = README_PATH, agentsPath = AGENTS_PATH, + soulPath = SOUL_PATH, + geminiPath = GEMINI_PATH, zhRootReadmePath = README_ZH_CN_PATH, zhDocsReadmePath = DOCS_ZH_CN_README_PATH, zhDocsAgentsPath = DOCS_ZH_CN_AGENTS_PATH, @@ -581,6 +609,16 @@ function createDocumentSpecs(paths = {}) { parseExpectations: parseAgentsDocExpectations, syncContent: syncEnglishAgents, }, + { + filePath: soulPath, + parseExpectations: content => parseCrossHarnessIdentityExpectations(content, 'SOUL.md'), + syncContent: (content, catalog) => syncCrossHarnessIdentity(content, catalog, 'SOUL.md'), + }, + { + filePath: geminiPath, + parseExpectations: content => parseCrossHarnessIdentityExpectations(content, '.gemini/GEMINI.md'), + syncContent: (content, catalog) => syncCrossHarnessIdentity(content, catalog, '.gemini/GEMINI.md'), + }, { filePath: zhRootReadmePath, parseExpectations: parseZhRootReadmeExpectations, @@ -633,6 +671,8 @@ function createDocumentSpecsForRoot(root) { return createDocumentSpecs({ readmePath: path.join(root, 'README.md'), agentsPath: path.join(root, 'AGENTS.md'), + soulPath: path.join(root, 'SOUL.md'), + geminiPath: path.join(root, '.gemini', 'GEMINI.md'), zhRootReadmePath: path.join(root, 'README.zh-CN.md'), zhDocsReadmePath: path.join(root, 'docs', 'zh-CN', 'README.md'), zhDocsAgentsPath: path.join(root, 'docs', 'zh-CN', 'AGENTS.md'), @@ -742,6 +782,7 @@ module.exports = { formatExpectation, main, parseAgentsDocExpectations, + parseCrossHarnessIdentityExpectations, parseCatalogDescriptionExpectations, parseReadmeExpectations, parseZhAgentsDocExpectations, @@ -751,6 +792,7 @@ module.exports = { syncCatalogDescription, syncEnglishAgents, syncEnglishReadme, + syncCrossHarnessIdentity, syncZhAgents, syncZhDocsReadme, syncZhRootReadme, diff --git a/tests/ci/catalog.test.js b/tests/ci/catalog.test.js index 34a73275d..4e8a4f2f1 100644 --- a/tests/ci/catalog.test.js +++ b/tests/ci/catalog.test.js @@ -95,6 +95,20 @@ commands/ - ${counts.commands} slash commands `); } +function writeCrossHarnessIdentityDocs(root, counts) { + fs.writeFileSync( + path.join(root, 'SOUL.md'), + `Everything Claude Code (ECC) is a production-ready AI coding plugin with ${counts.agents} specialized agents, ${counts.skills} skills, ${counts.commands} commands, and automated hook workflows.\n` + ); + + const geminiDir = path.join(root, '.gemini'); + fs.mkdirSync(geminiDir, { recursive: true }); + fs.writeFileSync( + path.join(geminiDir, 'GEMINI.md'), + `Everything Claude Code (ECC) is a cross-harness coding system with ${counts.agents} specialized agents, ${counts.skills} skills, and ${counts.commands} commands.\n` + ); +} + function writeZhRootReadme(root, counts) { fs.writeFileSync(path.join(root, 'README.zh-CN.md'), `你现在可以使用 ${counts.agents} 个代理、${counts.skills} 个技能和 ${counts.commands} 个命令。\n`); } @@ -158,6 +172,7 @@ function writeCatalogFixture(root, options = {}) { writeEnglishReadme(root, documentedCounts, { unrelatedSkillsCount }); writeEnglishAgents(root, documentedCounts, { skillsMinimum }); + writeCrossHarnessIdentityDocs(root, documentedCounts); writeZhRootReadme(root, documentedCounts); writeZhDocsReadme(root, documentedCounts, { unrelatedSkillsCount }); writeZhAgents(root, documentedCounts, { skillsMinimum }); @@ -224,6 +239,8 @@ function runTests() { assert.ok(formatted.includes('README.md quick-start summary')); assert.ok(formatted.includes('README.md project tree')); assert.ok(formatted.includes('AGENTS.md summary')); + assert.ok(formatted.includes('SOUL.md')); + assert.ok(formatted.includes('.gemini/GEMINI.md')); assert.ok(formatted.includes('.claude-plugin/plugin.json description')); assert.ok(formatted.includes('.claude-plugin/marketplace.json plugin description')); assert.ok(formatted.includes('README.zh-CN.md quick-start summary')); @@ -250,6 +267,8 @@ function runTests() { const readme = fs.readFileSync(path.join(testDir, 'README.md'), 'utf8'); const agentsDoc = fs.readFileSync(path.join(testDir, 'AGENTS.md'), 'utf8'); + const soulDoc = fs.readFileSync(path.join(testDir, 'SOUL.md'), 'utf8'); + const geminiDoc = fs.readFileSync(path.join(testDir, '.gemini', 'GEMINI.md'), 'utf8'); const zhReadme = fs.readFileSync(path.join(testDir, 'docs', 'zh-CN', 'README.md'), 'utf8'); const zhAgentsDoc = fs.readFileSync(path.join(testDir, 'docs', 'zh-CN', 'AGENTS.md'), 'utf8'); const pluginJson = fs.readFileSync(path.join(testDir, '.claude-plugin', 'plugin.json'), 'utf8'); @@ -261,6 +280,8 @@ function runTests() { assert.ok(readme.includes('| Skills | 42 | .agents/skills/ |')); assert.ok(agentsDoc.includes('providing 1 specialized agents, 1+ skills, 1 commands')); assert.ok(agentsDoc.includes('skills/ - 1+ workflow skills and domain knowledge')); + assert.ok(soulDoc.includes('with 1 specialized agents, 1 skills, 1 commands')); + assert.ok(geminiDoc.includes('with 1 specialized agents, 1 skills, and 1 commands')); assert.ok(zhReadme.includes('| 技能 | 42 | .agents/skills/ |')); assert.ok(zhAgentsDoc.includes('提供 1 个专业代理、1+ 项技能、1 条命令')); assert.ok(zhAgentsDoc.includes('skills/ - 1+ 个工作流技能和领域知识'));