mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-29 13:05:18 +02:00
fix(ci): validate cross-harness catalog counts
This commit is contained in:
+1
-1
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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+ 个工作流技能和领域知识'));
|
||||
|
||||
Reference in New Issue
Block a user