feat: add command registry and coverage checks (#1906)

Salvages the useful parts of #1897 without generated .caliber state or stale counts.

- adds a deterministic command registry generator and drift check
- commits the current command registry for 75 commands
- validates the rc.1 README catalog summary against live counts
- adds a single Ubuntu Node 20 coverage job instead of running coverage in every matrix cell

Co-authored-by: jodunk <jodunk@users.noreply.github.com>
This commit is contained in:
Affaan Mustafa
2026-05-14 22:02:36 -04:00
committed by GitHub
parent 375d750b4c
commit f7315016c0
9 changed files with 1453 additions and 3 deletions

View File

@@ -220,6 +220,10 @@ jobs:
run: node scripts/ci/catalog.js --text
continue-on-error: false
- name: Validate command registry
run: npm run command-registry:check
continue-on-error: false
- name: Check unicode safety
run: node scripts/ci/check-unicode-safety.js
continue-on-error: false
@@ -253,6 +257,33 @@ jobs:
- name: Run supply-chain IOC scan
run: npm run security:ioc-scan
coverage:
name: Coverage
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20.x'
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Run coverage
run: npm run coverage
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-ubuntu-node20-npm
path: coverage/
lint:
name: Lint
runs-on: ubuntu-latest

View File

@@ -89,7 +89,7 @@ This repo is the raw code only. The guides explain everything.
### v2.0.0-rc.1 — Surface Refresh, Operator Workflows, and ECC 2.0 Alpha (Apr 2026)
- **Dashboard GUI** — New Tkinter-based desktop application (`ecc_dashboard.py` or `npm run dashboard`) with dark/light theme toggle, font customization, and project logo in header and taskbar.
- **Public surface synced to the live repo** — metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: 55 agents, 208 skills, and 72 legacy command shims.
- **Public surface synced to the live repo** — metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: 60 agents, 229 skills, and 75 legacy command shims.
- **Operator and outbound workflow expansion** — `brand-voice`, `social-graph-ranker`, `connections-optimizer`, `customer-billing-ops`, `ecc-tools-cost-audit`, `google-workspace-ops`, `project-flow-ops`, and `workspace-surface-audit` round out the operator lane.
- **Media and launch tooling** — `manim-video`, `remotion-video-creation`, and upgraded social publishing surfaces make technical explainers and launch content part of the same system.
- **Framework and product surface growth** — `nestjs-patterns`, richer Codex/OpenCode install surfaces, and expanded cross-harness packaging keep the repo usable beyond Claude Code alone.

898
docs/COMMAND-REGISTRY.json Normal file
View File

@@ -0,0 +1,898 @@
{
"schemaVersion": 1,
"totalCommands": 75,
"commands": [
{
"command": "aside",
"description": "Answer a quick side question without interrupting or losing context from the current task. Resume work automatically after answering.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/aside.md"
},
{
"command": "auto-update",
"description": "Pull the latest ECC repo changes and reinstall the current managed targets.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/auto-update.md"
},
{
"command": "build-fix",
"description": "Detect the project build system and incrementally fix build/type errors with minimal safe changes.",
"type": "refactoring",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/build-fix.md"
},
{
"command": "checkpoint",
"description": "Create, verify, or list workflow checkpoints after running verification checks.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/checkpoint.md"
},
{
"command": "code-review",
"description": "Code review — local uncommitted changes or GitHub PR (pass PR number/URL for PR mode)",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/code-review.md"
},
{
"command": "cost-report",
"description": "Generate a local Claude Code cost report from a cost-tracker SQLite database.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/cost-report.md"
},
{
"command": "cpp-build",
"description": "Fix C++ build errors, CMake issues, and linker problems incrementally. Invokes the cpp-build-resolver agent for minimal, surgical fixes.",
"type": "testing",
"primaryAgents": [
"cpp-build-resolver"
],
"allAgents": [
"cpp-build-resolver"
],
"skills": [
"cpp-coding-standards"
],
"path": "commands/cpp-build.md"
},
{
"command": "cpp-review",
"description": "Comprehensive C++ code review for memory safety, modern C++ idioms, concurrency, and security. Invokes the cpp-reviewer agent.",
"type": "testing",
"primaryAgents": [
"cpp-reviewer"
],
"allAgents": [
"cpp-reviewer"
],
"skills": [
"cpp-coding-standards",
"cpp-testing"
],
"path": "commands/cpp-review.md"
},
{
"command": "cpp-test",
"description": "Enforce TDD workflow for C++. Write GoogleTest tests first, then implement. Verify coverage with gcov/lcov.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"cpp-testing",
"tdd-workflow"
],
"path": "commands/cpp-test.md"
},
{
"command": "ecc-guide",
"description": "Navigate ECC's current agents, skills, commands, hooks, install profiles, and docs from the live repository surface.",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [
"ecc-guide",
"security-scan"
],
"path": "commands/ecc-guide.md"
},
{
"command": "evolve",
"description": "Analyze instincts and suggest or generate evolved structures",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/evolve.md"
},
{
"command": "fastapi-review",
"description": "Review a FastAPI application for architecture, async correctness, dependency injection, Pydantic schemas, security, performance, and testability.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/fastapi-review.md"
},
{
"command": "feature-dev",
"description": "Guided feature development with codebase understanding and architecture focus",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/feature-dev.md"
},
{
"command": "flutter-build",
"description": "Fix Dart analyzer errors and Flutter build failures incrementally. Invokes the dart-build-resolver agent for minimal, surgical fixes.",
"type": "testing",
"primaryAgents": [
"dart-build-resolver"
],
"allAgents": [
"dart-build-resolver"
],
"skills": [
"flutter-dart-code-review"
],
"path": "commands/flutter-build.md"
},
{
"command": "flutter-review",
"description": "Review Flutter/Dart code for idiomatic patterns, widget best practices, state management, performance, accessibility, and security. Invokes the flutter-reviewer agent.",
"type": "testing",
"primaryAgents": [
"flutter-reviewer"
],
"allAgents": [
"flutter-reviewer"
],
"skills": [
"flutter-dart-code-review"
],
"path": "commands/flutter-review.md"
},
{
"command": "flutter-test",
"description": "Run Flutter/Dart tests, report failures, and incrementally fix test issues. Covers unit, widget, golden, and integration tests.",
"type": "testing",
"primaryAgents": [
"dart-build-resolver",
"flutter-reviewer"
],
"allAgents": [
"dart-build-resolver",
"flutter-reviewer"
],
"skills": [
"flutter-dart-code-review"
],
"path": "commands/flutter-test.md"
},
{
"command": "gan-build",
"description": "Run a generator/evaluator build loop for implementation tasks with bounded iterations and scoring.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/gan-build.md"
},
{
"command": "gan-design",
"description": "Run a generator/evaluator design loop for frontend or visual work with bounded iterations and scoring.",
"type": "planning",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/gan-design.md"
},
{
"command": "go-build",
"description": "Fix Go build errors, go vet warnings, and linter issues incrementally. Invokes the go-build-resolver agent for minimal, surgical fixes.",
"type": "testing",
"primaryAgents": [
"go-build-resolver"
],
"allAgents": [
"go-build-resolver"
],
"skills": [
"golang-patterns"
],
"path": "commands/go-build.md"
},
{
"command": "go-review",
"description": "Comprehensive Go code review for idiomatic patterns, concurrency safety, error handling, and security. Invokes the go-reviewer agent.",
"type": "testing",
"primaryAgents": [
"go-reviewer"
],
"allAgents": [
"go-reviewer"
],
"skills": [
"golang-patterns",
"golang-testing"
],
"path": "commands/go-review.md"
},
{
"command": "go-test",
"description": "Enforce TDD workflow for Go. Write table-driven tests first, then implement. Verify 80%+ coverage with go test -cover.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"golang-testing",
"tdd-workflow"
],
"path": "commands/go-test.md"
},
{
"command": "gradle-build",
"description": "Fix Gradle build errors for Android and KMP projects",
"type": "build",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/gradle-build.md"
},
{
"command": "harness-audit",
"description": "Run a deterministic repository harness audit and return a prioritized scorecard.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/harness-audit.md"
},
{
"command": "hookify-configure",
"description": "Enable or disable hookify rules interactively",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/hookify-configure.md"
},
{
"command": "hookify-help",
"description": "Get help with the hookify system",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/hookify-help.md"
},
{
"command": "hookify-list",
"description": "List all configured hookify rules",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/hookify-list.md"
},
{
"command": "hookify",
"description": "Create hooks to prevent unwanted behaviors from conversation analysis or explicit instructions",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/hookify.md"
},
{
"command": "instinct-export",
"description": "Export instincts from project/global scope to a file",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/instinct-export.md"
},
{
"command": "instinct-import",
"description": "Import instincts from file or URL into project/global scope",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/instinct-import.md"
},
{
"command": "instinct-status",
"description": "Show learned instincts (project + global) with confidence",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/instinct-status.md"
},
{
"command": "jira",
"description": "Retrieve a Jira ticket, analyze requirements, update status, or add comments. Uses the jira-integration skill and MCP or REST API.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"jira-integration"
],
"path": "commands/jira.md"
},
{
"command": "kotlin-build",
"description": "Fix Kotlin/Gradle build errors, compiler warnings, and dependency issues incrementally. Invokes the kotlin-build-resolver agent for minimal, surgical fixes.",
"type": "testing",
"primaryAgents": [
"kotlin-build-resolver"
],
"allAgents": [
"kotlin-build-resolver"
],
"skills": [
"kotlin-patterns"
],
"path": "commands/kotlin-build.md"
},
{
"command": "kotlin-review",
"description": "Comprehensive Kotlin code review for idiomatic patterns, null safety, coroutine safety, and security. Invokes the kotlin-reviewer agent.",
"type": "testing",
"primaryAgents": [
"kotlin-reviewer"
],
"allAgents": [
"kotlin-reviewer"
],
"skills": [
"kotlin-patterns",
"kotlin-testing"
],
"path": "commands/kotlin-review.md"
},
{
"command": "kotlin-test",
"description": "Enforce TDD workflow for Kotlin. Write Kotest tests first, then implement. Verify 80%+ coverage with Kover.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"kotlin-testing",
"tdd-workflow"
],
"path": "commands/kotlin-test.md"
},
{
"command": "learn-eval",
"description": "Extract reusable patterns from the session, self-evaluate quality before saving, and determine the right save location (Global vs Project).",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/learn-eval.md"
},
{
"command": "learn",
"description": "Extract reusable patterns from the current session and save them as candidate skills or guidance.",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/learn.md"
},
{
"command": "loop-start",
"description": "Start a managed autonomous loop pattern with safety defaults and explicit stop conditions.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/loop-start.md"
},
{
"command": "loop-status",
"description": "Inspect active loop state, progress, failure signals, and recommended intervention.",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/loop-status.md"
},
{
"command": "model-route",
"description": "Recommend the best model tier for the current task based on complexity, risk, and budget.",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/model-route.md"
},
{
"command": "multi-backend",
"description": "Run a backend-focused multi-model workflow for APIs, algorithms, data, and business logic.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/multi-backend.md"
},
{
"command": "multi-execute",
"description": "Execute a multi-model implementation plan while preserving Claude as the only filesystem writer.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/multi-execute.md"
},
{
"command": "multi-frontend",
"description": "Run a frontend-focused multi-model workflow for components, layouts, animation, and UI polish.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/multi-frontend.md"
},
{
"command": "multi-plan",
"description": "Create a multi-model implementation plan without modifying production code.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [
"accessibility"
],
"path": "commands/multi-plan.md"
},
{
"command": "multi-workflow",
"description": "Run a full multi-model development workflow with research, planning, execution, optimization, and review.",
"type": "orchestration",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/multi-workflow.md"
},
{
"command": "plan-prd",
"description": "Generate a lean, problem-first PRD and hand off to /plan for implementation planning.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/plan-prd.md"
},
{
"command": "plan",
"description": "Restate requirements, assess risks, and create step-by-step implementation plan. WAIT for user CONFIRM before touching any code.",
"type": "testing",
"primaryAgents": [
"planner"
],
"allAgents": [
"planner"
],
"skills": [],
"path": "commands/plan.md"
},
{
"command": "pm2",
"description": "Analyze a project and generate PM2 service commands for detected frontend, backend, or database services.",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/pm2.md"
},
{
"command": "pr",
"description": "Create a GitHub PR from current branch with unpushed commits — discovers templates, analyzes changes, pushes",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/pr.md"
},
{
"command": "project-init",
"description": "Detect a project's stack and produce a dry-run ECC onboarding plan using the repository's install manifests and stack mappings.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"ecc-guide"
],
"path": "commands/project-init.md"
},
{
"command": "projects",
"description": "List known projects and their instinct statistics",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/projects.md"
},
{
"command": "promote",
"description": "Promote project-scoped instincts to global scope",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/promote.md"
},
{
"command": "prp-commit",
"description": "Quick commit with natural language file targeting — describe what to commit in plain English",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/prp-commit.md"
},
{
"command": "prp-implement",
"description": "Execute an implementation plan with rigorous validation loops",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/prp-implement.md"
},
{
"command": "prp-plan",
"description": "Create comprehensive feature implementation plan with codebase analysis and pattern extraction",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/prp-plan.md"
},
{
"command": "prp-pr",
"description": "Create a GitHub PR from current branch with unpushed commits — discovers templates, analyzes changes, pushes",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/prp-pr.md"
},
{
"command": "prp-prd",
"description": "Interactive PRD generator - problem-first, hypothesis-driven product spec with back-and-forth questioning",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/prp-prd.md"
},
{
"command": "prune",
"description": "Delete pending instincts older than 30 days that were never promoted",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [
"continuous-learning-v2"
],
"path": "commands/prune.md"
},
{
"command": "python-review",
"description": "Comprehensive Python code review for PEP 8 compliance, type hints, security, and Pythonic idioms. Invokes the python-reviewer agent.",
"type": "testing",
"primaryAgents": [
"python-reviewer"
],
"allAgents": [
"python-reviewer"
],
"skills": [
"python-patterns",
"python-testing"
],
"path": "commands/python-review.md"
},
{
"command": "quality-gate",
"description": "Run the ECC quality pipeline for a file or project scope and report remediation steps.",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/quality-gate.md"
},
{
"command": "refactor-clean",
"description": "Safely identify and remove dead code with verification after each change.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/refactor-clean.md"
},
{
"command": "resume-session",
"description": "Load the most recent session file from ~/.claude/session-data/ and resume work with full context from where the last session ended.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/resume-session.md"
},
{
"command": "review-pr",
"description": "Comprehensive PR review using specialized agents",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/review-pr.md"
},
{
"command": "rust-build",
"description": "Fix Rust build errors, borrow checker issues, and dependency problems incrementally. Invokes the rust-build-resolver agent for minimal, surgical fixes.",
"type": "testing",
"primaryAgents": [
"rust-build-resolver"
],
"allAgents": [
"rust-build-resolver"
],
"skills": [
"rust-patterns"
],
"path": "commands/rust-build.md"
},
{
"command": "rust-review",
"description": "Comprehensive Rust code review for ownership, lifetimes, error handling, unsafe usage, and idiomatic patterns. Invokes the rust-reviewer agent.",
"type": "testing",
"primaryAgents": [
"rust-reviewer"
],
"allAgents": [
"rust-reviewer"
],
"skills": [
"rust-patterns",
"rust-testing"
],
"path": "commands/rust-review.md"
},
{
"command": "rust-test",
"description": "Enforce TDD workflow for Rust. Write tests first, then implement. Verify 80%+ coverage with cargo-llvm-cov.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [
"rust-patterns",
"rust-testing"
],
"path": "commands/rust-test.md"
},
{
"command": "santa-loop",
"description": "Adversarial dual-review convergence loop — two independent model reviewers must both approve before code ships.",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/santa-loop.md"
},
{
"command": "save-session",
"description": "Save current session state to a dated file in ~/.claude/session-data/ so work can be resumed in a future session with full context.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/save-session.md"
},
{
"command": "security-scan",
"description": "Run AgentShield against agent, hook, MCP, permission, and secret surfaces.",
"type": "review",
"primaryAgents": [
"security-reviewer"
],
"allAgents": [
"security-reviewer"
],
"skills": [
"security-scan"
],
"path": "commands/security-scan.md"
},
{
"command": "sessions",
"description": "Manage Claude Code session history, aliases, and session metadata.",
"type": "general",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/sessions.md"
},
{
"command": "setup-pm",
"description": "Configure your preferred package manager (npm/pnpm/yarn/bun)",
"type": "build",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/setup-pm.md"
},
{
"command": "skill-create",
"description": "Analyze local git history to extract coding patterns and generate SKILL.md files. Local version of the Skill Creator GitHub App.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/skill-create.md"
},
{
"command": "skill-health",
"description": "Show skill portfolio health dashboard with charts and analytics",
"type": "review",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/skill-health.md"
},
{
"command": "test-coverage",
"description": "Analyze coverage, identify gaps, and generate missing tests toward the target threshold.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/test-coverage.md"
},
{
"command": "update-codemaps",
"description": "Scan project structure and generate token-lean architecture codemaps.",
"type": "planning",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/update-codemaps.md"
},
{
"command": "update-docs",
"description": "Sync documentation from source-of-truth files such as scripts, schemas, routes, and exports.",
"type": "testing",
"primaryAgents": [],
"allAgents": [],
"skills": [],
"path": "commands/update-docs.md"
}
],
"statistics": {
"byType": {
"build": 2,
"general": 8,
"orchestration": 6,
"planning": 2,
"refactoring": 1,
"review": 9,
"testing": 47
},
"topAgents": [
{
"agent": "dart-build-resolver",
"count": 2
},
{
"agent": "flutter-reviewer",
"count": 2
},
{
"agent": "cpp-build-resolver",
"count": 1
},
{
"agent": "cpp-reviewer",
"count": 1
},
{
"agent": "go-build-resolver",
"count": 1
},
{
"agent": "go-reviewer",
"count": 1
},
{
"agent": "kotlin-build-resolver",
"count": 1
},
{
"agent": "kotlin-reviewer",
"count": 1
},
{
"agent": "planner",
"count": 1
},
{
"agent": "python-reviewer",
"count": 1
}
],
"topSkills": [
{
"skill": "continuous-learning-v2",
"count": 6
},
{
"skill": "flutter-dart-code-review",
"count": 3
},
{
"skill": "rust-patterns",
"count": 3
},
{
"skill": "tdd-workflow",
"count": 3
},
{
"skill": "cpp-coding-standards",
"count": 2
},
{
"skill": "cpp-testing",
"count": 2
},
{
"skill": "ecc-guide",
"count": 2
},
{
"skill": "golang-patterns",
"count": 2
},
{
"skill": "golang-testing",
"count": 2
},
{
"skill": "kotlin-patterns",
"count": 2
}
]
}
}

View File

@@ -286,6 +286,9 @@
"postinstall": "echo '\\n ecc-universal installed!\\n Run: npx ecc typescript\\n Compat: npx ecc-install typescript\\n Docs: https://github.com/affaan-m/everything-claude-code\\n'",
"catalog:check": "node scripts/ci/catalog.js --text",
"catalog:sync": "node scripts/ci/catalog.js --write --text",
"command-registry:generate": "node scripts/ci/generate-command-registry.js",
"command-registry:write": "node scripts/ci/generate-command-registry.js --write",
"command-registry:check": "node scripts/ci/generate-command-registry.js --check",
"lint": "eslint . && markdownlint '**/*.md' --ignore node_modules",
"harness:adapters": "node scripts/harness-adapter-compliance.js",
"harness:audit": "node scripts/harness-audit.js",
@@ -295,7 +298,7 @@
"orchestrate:status": "node scripts/orchestration-status.js",
"orchestrate:worker": "bash scripts/orchestrate-codex-worker.sh",
"orchestrate:tmux": "node scripts/orchestrate-worktrees.js",
"test": "node scripts/ci/check-unicode-safety.js && node scripts/ci/validate-agents.js && node scripts/ci/validate-commands.js && node scripts/ci/validate-rules.js && node scripts/ci/validate-skills.js && node scripts/ci/validate-hooks.js && node scripts/ci/validate-install-manifests.js && node scripts/ci/validate-no-personal-paths.js && npm run catalog:check && node tests/run-all.js",
"test": "node scripts/ci/check-unicode-safety.js && node scripts/ci/validate-agents.js && node scripts/ci/validate-commands.js && node scripts/ci/validate-rules.js && node scripts/ci/validate-skills.js && node scripts/ci/validate-hooks.js && node scripts/ci/validate-install-manifests.js && node scripts/ci/validate-no-personal-paths.js && npm run catalog:check && npm run command-registry:check && node tests/run-all.js",
"coverage": "c8 --all --include=\"scripts/**/*.js\" --check-coverage --lines 80 --functions 80 --branches 80 --statements 80 --reporter=text --reporter=lcov node tests/run-all.js",
"build:opencode": "node scripts/build-opencode.js",
"prepack": "npm run build:opencode",

View File

@@ -101,6 +101,19 @@ function parseReadmeExpectations(readmeContent) {
{ category: 'commands', mode: 'exact', expected: Number(quickStartMatch[3]), source: 'README.md quick-start summary' }
);
const releaseNoteMatch = readmeContent.match(
/actual OSS surface:\s+(\d+)\s+agents,\s+(\d+)\s+skills,\s+and\s+(\d+)\s+legacy command shims/i
);
if (!releaseNoteMatch) {
throw new Error('README.md is missing the rc.1 release-note catalog summary');
}
expectations.push(
{ category: 'agents', mode: 'exact', expected: Number(releaseNoteMatch[1]), source: 'README.md rc.1 release-note summary' },
{ category: 'skills', mode: 'exact', expected: Number(releaseNoteMatch[2]), source: 'README.md rc.1 release-note summary' },
{ category: 'commands', mode: 'exact', expected: Number(releaseNoteMatch[3]), source: 'README.md rc.1 release-note summary' }
);
const projectTreeAgentsMatch = readmeContent.match(/^\|\s*--\s*agents\/\s*#\s*(\d+)\s+specialized subagents for delegation\s*$/im);
if (!projectTreeAgentsMatch) {
throw new Error('README.md project tree is missing the agents count');
@@ -415,6 +428,13 @@ function syncEnglishReadme(content, catalog) {
`${prefix}${catalog.agents.count}${agentsSuffix}${catalog.skills.count}${skillsSuffix}${catalog.commands.count} legacy command shims`,
'README.md quick-start summary'
);
nextContent = replaceOrThrow(
nextContent,
/(actual OSS surface:\s+)(\d+)(\s+agents,\s+)(\d+)(\s+skills,\s+and\s+)(\d+)(\s+legacy command shims)/i,
(_, prefix, __, agentsSuffix, ___, skillsSuffix, ____, commandsSuffix) =>
`${prefix}${catalog.agents.count}${agentsSuffix}${catalog.skills.count}${skillsSuffix}${catalog.commands.count}${commandsSuffix}`,
'README.md rc.1 release-note summary'
);
nextContent = replaceOrThrow(
nextContent,
/^(\|\s*--\s*agents\/\s*#\s*)(\d+)(\s+specialized subagents for delegation\s*)$/im,

View File

@@ -0,0 +1,318 @@
#!/usr/bin/env node
/**
* Generate a deterministic command-to-agent/skill registry.
*
* Usage:
* node scripts/ci/generate-command-registry.js
* node scripts/ci/generate-command-registry.js --json
* node scripts/ci/generate-command-registry.js --write
* node scripts/ci/generate-command-registry.js --check
*/
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '../..');
const DEFAULT_OUTPUT_PATH = path.join(ROOT, 'docs', 'COMMAND-REGISTRY.json');
function normalizePath(relativePath) {
return relativePath.split(path.sep).join('/');
}
function listMarkdownFiles(root, relativeDir) {
const directory = path.join(root, relativeDir);
if (!fs.existsSync(directory)) {
return [];
}
return fs.readdirSync(directory, { withFileTypes: true })
.filter(entry => entry.isFile() && entry.name.endsWith('.md'))
.map(entry => entry.name)
.sort();
}
function listKnownAgents(root) {
return new Set(
listMarkdownFiles(root, 'agents')
.map(filename => filename.replace(/\.md$/, ''))
);
}
function listKnownSkills(root) {
const skillsDir = path.join(root, 'skills');
if (!fs.existsSync(skillsDir)) {
return new Set();
}
return new Set(
fs.readdirSync(skillsDir, { withFileTypes: true })
.filter(entry => (
entry.isDirectory() && fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md'))
))
.map(entry => entry.name)
.sort()
);
}
function cleanYamlScalar(value) {
return value.trim()
.replace(/^['"]/, '')
.replace(/['"]$/, '');
}
function extractDescription(content) {
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (frontmatter) {
const description = frontmatter[1].match(/^description:\s*(.+)$/m);
if (description) {
return cleanYamlScalar(description[1]);
}
}
const heading = content.match(/^#\s+(.+)$/m);
return heading ? heading[1].trim() : '';
}
function collectKnownReferences(content, patterns, knownNames) {
const refs = new Set();
for (const pattern of patterns) {
for (const match of content.matchAll(pattern)) {
const ref = match[1];
if (knownNames.has(ref)) {
refs.add(ref);
}
}
}
return refs;
}
function extractReferences(content, knownAgents, knownSkills) {
const agentPatterns = [
/@([a-z][a-z0-9-]*)/gi,
/\bagent:\s*['"]?([a-z][a-z0-9-]*)/gi,
/\bsubagent(?:_type)?:\s*['"]?([a-z][a-z0-9-]*)/gi,
/\bagents\/([a-z][a-z0-9-]*)\.md\b/gi,
];
const skillPatterns = [
/\bskill:\s*['"]?\/?([a-z][a-z0-9-]*)/gi,
/\bskills\/([a-z][a-z0-9-]*)\/SKILL\.md\b/gi,
/\bskills\/([a-z][a-z0-9-]*)\b/gi,
/\/([a-z][a-z0-9-]*)\b/gi,
];
return {
agents: Array.from(collectKnownReferences(content, agentPatterns, knownAgents)).sort(),
skills: Array.from(collectKnownReferences(content, skillPatterns, knownSkills)).sort(),
};
}
function inferCommandType(content, commandName) {
const lower = `${commandName}\n${content}`.toLowerCase();
if (commandName.startsWith('multi-') || lower.includes('orchestrat')) {
return 'orchestration';
}
if (lower.includes('test') || lower.includes('tdd') || lower.includes('coverage')) {
return 'testing';
}
if (lower.includes('review') || lower.includes('audit') || lower.includes('security')) {
return 'review';
}
if (lower.includes('plan') || lower.includes('design') || lower.includes('architecture')) {
return 'planning';
}
if (lower.includes('refactor') || lower.includes('clean') || lower.includes('simplify')) {
return 'refactoring';
}
if (lower.includes('build') || lower.includes('compile') || lower.includes('setup')) {
return 'build';
}
return 'general';
}
function processCommandFile(root, filename, knownAgents, knownSkills) {
const commandName = filename.replace(/\.md$/, '');
const relativePath = normalizePath(path.join('commands', filename));
const content = fs.readFileSync(path.join(root, relativePath), 'utf8');
const references = extractReferences(content, knownAgents, knownSkills);
return {
command: commandName,
description: extractDescription(content),
type: inferCommandType(content, commandName),
primaryAgents: references.agents.slice(0, 3),
allAgents: references.agents,
skills: references.skills,
path: relativePath,
};
}
function sortCountMap(countMap) {
return Object.fromEntries(
Object.entries(countMap).sort(([left], [right]) => left.localeCompare(right))
);
}
function topUsage(countMap, keyName) {
return Object.entries(countMap)
.sort(([leftName, leftCount], [rightName, rightCount]) => (
rightCount - leftCount || leftName.localeCompare(rightName)
))
.slice(0, 10)
.map(([name, count]) => ({ [keyName]: name, count }));
}
function generateRegistry(options = {}) {
const root = options.root || ROOT;
const commandFiles = listMarkdownFiles(root, 'commands');
const knownAgents = listKnownAgents(root);
const knownSkills = listKnownSkills(root);
const commands = commandFiles.map(filename => (
processCommandFile(root, filename, knownAgents, knownSkills)
));
const byType = {};
const agentUsage = {};
const skillUsage = {};
for (const command of commands) {
byType[command.type] = (byType[command.type] || 0) + 1;
for (const agent of command.allAgents) {
agentUsage[agent] = (agentUsage[agent] || 0) + 1;
}
for (const skill of command.skills) {
skillUsage[skill] = (skillUsage[skill] || 0) + 1;
}
}
return {
schemaVersion: 1,
totalCommands: commands.length,
commands,
statistics: {
byType: sortCountMap(byType),
topAgents: topUsage(agentUsage, 'agent'),
topSkills: topUsage(skillUsage, 'skill'),
},
};
}
function formatRegistry(registry) {
return `${JSON.stringify(registry, null, 2)}\n`;
}
function writeRegistry(registry, outputPath = DEFAULT_OUTPUT_PATH) {
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, formatRegistry(registry), 'utf8');
}
function checkRegistry(registry, outputPath = DEFAULT_OUTPUT_PATH) {
const expected = formatRegistry(registry);
let current;
try {
current = fs.readFileSync(outputPath, 'utf8');
} catch (error) {
throw new Error(`Failed to read ${normalizePath(path.relative(ROOT, outputPath))}: ${error.message}`);
}
if (current !== expected) {
throw new Error(`${normalizePath(path.relative(ROOT, outputPath))} is out of date; run npm run command-registry:write`);
}
}
function formatTextSummary(registry) {
const lines = [
'Command registry statistics',
'',
`Total commands: ${registry.totalCommands}`,
'',
'By type:',
];
for (const [type, count] of Object.entries(registry.statistics.byType)) {
lines.push(` ${type}: ${count}`);
}
lines.push('', 'Top agents:');
for (const { agent, count } of registry.statistics.topAgents) {
lines.push(` ${agent}: ${count}`);
}
lines.push('', 'Top skills:');
for (const { skill, count } of registry.statistics.topSkills) {
lines.push(` ${skill}: ${count}`);
}
return `${lines.join('\n')}\n`;
}
function parseArgs(argv) {
const allowed = new Set(['--json', '--write', '--check']);
const flags = new Set();
for (const arg of argv) {
if (!allowed.has(arg)) {
throw new Error(`Unknown argument: ${arg}`);
}
flags.add(arg);
}
return {
json: flags.has('--json'),
write: flags.has('--write'),
check: flags.has('--check'),
};
}
function run(argv = process.argv.slice(2), options = {}) {
const stdout = options.stdout || process.stdout;
const stderr = options.stderr || process.stderr;
const outputPath = options.outputPath || DEFAULT_OUTPUT_PATH;
try {
const args = parseArgs(argv);
const registry = generateRegistry({ root: options.root || ROOT });
if (args.check) {
checkRegistry(registry, outputPath);
stdout.write('Command registry is up to date.\n');
return 0;
}
if (args.write) {
writeRegistry(registry, outputPath);
stdout.write(`Command registry written to ${normalizePath(path.relative(process.cwd(), outputPath))}\n`);
return 0;
}
stdout.write(args.json ? formatRegistry(registry) : formatTextSummary(registry));
return 0;
} catch (error) {
stderr.write(`${error.message}\n`);
return 1;
}
}
if (require.main === module) {
process.exit(run());
}
module.exports = {
checkRegistry,
extractDescription,
extractReferences,
formatRegistry,
generateRegistry,
inferCommandType,
parseArgs,
run,
writeRegistry,
};

View File

@@ -44,6 +44,7 @@ function writeEnglishReadme(root, counts, options = {}) {
const unrelatedSkillsCount = options.unrelatedSkillsCount || 16;
fs.writeFileSync(path.join(root, 'README.md'), `Access to ${counts.agents} agents, ${counts.skills} skills, and ${counts.commands} commands.
- **Public surface synced to the live repo** - metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: ${counts.agents} agents, ${counts.skills} skills, and ${counts.commands} legacy command shims.
|-- agents/ # ${counts.agents} specialized subagents for delegation
| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |
| --- | --- | --- | --- | --- |
@@ -221,6 +222,7 @@ function runTests() {
.join('\n');
assert.ok(formatted.includes('README.md quick-start summary'));
assert.ok(formatted.includes('README.md rc.1 release-note summary'));
assert.ok(formatted.includes('README.md project tree'));
assert.ok(formatted.includes('AGENTS.md summary'));
assert.ok(formatted.includes('.claude-plugin/plugin.json description'));
@@ -255,6 +257,7 @@ function runTests() {
const marketplaceJson = fs.readFileSync(path.join(testDir, '.claude-plugin', 'marketplace.json'), 'utf8');
assert.ok(readme.includes('Access to 1 agents, 1 skills, and 1 legacy command shims'));
assert.ok(readme.includes('actual OSS surface: 1 agents, 1 skills, and 1 legacy command shims'));
assert.ok(readme.includes('|-- agents/ # 1 specialized subagents for delegation'));
assert.ok(readme.includes('| Skills | 42 | .agents/skills/ |'));
assert.ok(agentsDoc.includes('providing 1 specialized agents, 1+ skills, 1 commands'));

View File

@@ -0,0 +1,176 @@
/**
* Direct coverage for scripts/ci/generate-command-registry.js.
*/
'use strict';
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const {
checkRegistry,
formatRegistry,
generateRegistry,
parseArgs,
run,
writeRegistry,
} = require('../../scripts/ci/generate-command-registry');
function createTestDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-command-registry-'));
}
function cleanupTestDir(testDir) {
fs.rmSync(testDir, { recursive: true, force: true });
}
function writeFixture(root) {
fs.mkdirSync(path.join(root, 'commands'), { recursive: true });
fs.mkdirSync(path.join(root, 'agents'), { recursive: true });
fs.mkdirSync(path.join(root, 'skills', 'tdd-workflow'), { recursive: true });
fs.mkdirSync(path.join(root, 'skills', 'security-review'), { recursive: true });
fs.writeFileSync(path.join(root, 'agents', 'code-reviewer.md'), '---\nmodel: sonnet\ntools: Read\n---\n');
fs.writeFileSync(path.join(root, 'agents', 'test-writer.md'), '---\nmodel: sonnet\ntools: Read\n---\n');
fs.writeFileSync(path.join(root, 'skills', 'tdd-workflow', 'SKILL.md'), '# TDD workflow\n');
fs.writeFileSync(path.join(root, 'skills', 'security-review', 'SKILL.md'), '# Security review\n');
fs.writeFileSync(path.join(root, 'commands', 'review.md'), `---
description: Review changes
---
# Review
Use @code-reviewer and skill: security-review.
`);
fs.writeFileSync(path.join(root, 'commands', 'tdd.md'), `---
description: "Write tests first"
---
# TDD
Call subagent_type: test-writer and skills/tdd-workflow/SKILL.md.
`);
}
function test(name, fn) {
try {
fn();
console.log(` PASS ${name}`);
return true;
} catch (error) {
console.log(` FAIL ${name}`);
console.log(` Error: ${error.message}`);
return false;
}
}
function runTests() {
console.log('\n=== Testing command registry generation ===\n');
let passed = 0;
let failed = 0;
if (test('generates deterministic command metadata and usage statistics', () => {
const testDir = createTestDir();
try {
writeFixture(testDir);
const registry = generateRegistry({ root: testDir });
assert.strictEqual(registry.schemaVersion, 1);
assert.strictEqual(registry.totalCommands, 2);
assert.deepStrictEqual(
registry.commands.map(command => command.command),
['review', 'tdd']
);
assert.deepStrictEqual(registry.commands[0].allAgents, ['code-reviewer']);
assert.deepStrictEqual(registry.commands[0].skills, ['security-review']);
assert.deepStrictEqual(registry.commands[1].allAgents, ['test-writer']);
assert.deepStrictEqual(registry.commands[1].skills, ['tdd-workflow']);
assert.deepStrictEqual(registry.statistics.byType, { review: 1, testing: 1 });
assert.deepStrictEqual(registry.statistics.topAgents[0], { agent: 'code-reviewer', count: 1 });
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('write and check modes use stable JSON without timestamps', () => {
const testDir = createTestDir();
try {
writeFixture(testDir);
const outputPath = path.join(testDir, 'docs', 'COMMAND-REGISTRY.json');
const registry = generateRegistry({ root: testDir });
writeRegistry(registry, outputPath);
const firstWrite = fs.readFileSync(outputPath, 'utf8');
writeRegistry(registry, outputPath);
const secondWrite = fs.readFileSync(outputPath, 'utf8');
assert.strictEqual(firstWrite, secondWrite);
assert.ok(!firstWrite.includes('generated'));
assert.doesNotThrow(() => checkRegistry(registry, outputPath));
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('check mode fails when the registry file is stale', () => {
const testDir = createTestDir();
try {
writeFixture(testDir);
const outputPath = path.join(testDir, 'docs', 'COMMAND-REGISTRY.json');
const registry = generateRegistry({ root: testDir });
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, `${formatRegistry(registry).trimEnd()}\n \n`);
assert.throws(
() => checkRegistry(registry, outputPath),
/out of date/
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('CLI reports unknown arguments and supports check output', () => {
const testDir = createTestDir();
try {
writeFixture(testDir);
const outputPath = path.join(testDir, 'docs', 'COMMAND-REGISTRY.json');
const registry = generateRegistry({ root: testDir });
writeRegistry(registry, outputPath);
let stdout = '';
let stderr = '';
const streams = {
stdout: { write: chunk => { stdout += chunk; } },
stderr: { write: chunk => { stderr += chunk; } },
};
assert.deepStrictEqual(parseArgs(['--json', '--write']), {
json: true,
write: true,
check: false,
});
assert.strictEqual(run(['--check'], { root: testDir, outputPath, ...streams }), 0);
assert.ok(stdout.includes('up to date'));
assert.strictEqual(stderr, '');
stdout = '';
stderr = '';
assert.strictEqual(run(['--bogus'], { root: testDir, outputPath, ...streams }), 1);
assert.strictEqual(stdout, '');
assert.ok(stderr.includes('Unknown argument'));
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}
runTests();

View File

@@ -270,7 +270,7 @@ function writeCatalogFixture(testDir, options = {}) {
fs.writeFileSync(path.join(testDir, 'commands', 'plan.md'), '---\ndescription: Plan\n---\n# Plan');
fs.writeFileSync(path.join(testDir, 'skills', 'demo-skill', 'SKILL.md'), '---\nname: demo-skill\ndescription: Demo skill\norigin: ECC\n---\n# Demo Skill');
fs.writeFileSync(readmePath, `Access to ${readmeCounts.agents} agents, ${readmeCounts.skills} skills, and ${readmeCounts.commands} commands.\n|-- agents/ # ${readmeProjectTreeAgents} specialized subagents for delegation\n| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |\n|---------|------------|------------|-----------|----------|\n| Agents | PASS: ${readmeTableCounts.agents} agents | Shared | Shared | 1 |\n| Commands | PASS: ${readmeTableCounts.commands} commands | Shared | Shared | 1 |\n| Skills | PASS: ${readmeTableCounts.skills} skills | Shared | Shared | 1 |\n\n| Feature | Count | Format |\n|-----------|-------|---------|\n| Skills | ${readmeUnrelatedSkillsCount} | .agents/skills/ |\n\n## Cross-Tool Feature Parity\n\n| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |\n|---------|------------|------------|-----------|----------|\n| **Agents** | ${readmeParityCounts.agents} | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |\n| **Commands** | ${readmeParityCounts.commands} | Shared | Instruction-based | 31 |\n| **Skills** | ${readmeParityCounts.skills} | Shared | 10 (native format) | 37 |\n`);
fs.writeFileSync(readmePath, `Access to ${readmeCounts.agents} agents, ${readmeCounts.skills} skills, and ${readmeCounts.commands} commands.\n- **Public surface synced to the live repo** - metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: ${readmeCounts.agents} agents, ${readmeCounts.skills} skills, and ${readmeCounts.commands} legacy command shims.\n|-- agents/ # ${readmeProjectTreeAgents} specialized subagents for delegation\n| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |\n|---------|------------|------------|-----------|----------|\n| Agents | PASS: ${readmeTableCounts.agents} agents | Shared | Shared | 1 |\n| Commands | PASS: ${readmeTableCounts.commands} commands | Shared | Shared | 1 |\n| Skills | PASS: ${readmeTableCounts.skills} skills | Shared | Shared | 1 |\n\n| Feature | Count | Format |\n|-----------|-------|---------|\n| Skills | ${readmeUnrelatedSkillsCount} | .agents/skills/ |\n\n## Cross-Tool Feature Parity\n\n| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |\n|---------|------------|------------|-----------|----------|\n| **Agents** | ${readmeParityCounts.agents} | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |\n| **Commands** | ${readmeParityCounts.commands} | Shared | Instruction-based | 31 |\n| **Skills** | ${readmeParityCounts.skills} | Shared | 10 (native format) | 37 |\n`);
fs.writeFileSync(agentsPath, `This is a **production-ready AI coding plugin** providing ${summaryCounts.agents} specialized agents, ${summaryCounts.skills} skills, ${summaryCounts.commands} commands, and automated hook workflows for software development.\n\n\`\`\`\n${structureLines.join('\n')}\n\`\`\`\n`);
fs.writeFileSync(zhRootReadmePath, `**完成!** 你现在可以使用 ${zhRootReadmeCounts.agents} 个代理、${zhRootReadmeCounts.skills} 个技能和 ${zhRootReadmeCounts.commands} 个命令。\n`);
fs.writeFileSync(zhDocsReadmePath, `**搞定!** 你现在可以使用 ${zhDocsReadmeCounts.agents} 个智能体、${zhDocsReadmeCounts.skills} 项技能和 ${zhDocsReadmeCounts.commands} 个命令了。\n| 功能特性 | Claude Code | OpenCode | 状态 |\n|---------|-------------|----------|--------|\n| 智能体 | \u2705 ${zhDocsTableCounts.agents} 个 | \u2705 12 个 | **Claude Code 领先** |\n| 命令 | \u2705 ${zhDocsTableCounts.commands} 个 | \u2705 31 个 | **Claude Code 领先** |\n| 技能 | \u2705 ${zhDocsTableCounts.skills} 项 | \u2705 37 项 | **Claude Code 领先** |\n\n| 功能特性 | 数量 | 格式 |\n|-----------|-------|---------|\n| 技能 | ${zhDocsUnrelatedSkillsCount} | .agents/skills/ |\n\n## 跨工具功能对等\n\n| 功能特性 | Claude Code | Cursor IDE | Codex CLI | OpenCode |\n|---------|------------|------------|-----------|----------|\n| **智能体** | ${zhDocsParityCounts.agents} | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |\n| **命令** | ${zhDocsParityCounts.commands} | 共享 | 基于指令 | 31 |\n| **技能** | ${zhDocsParityCounts.skills} | 共享 | 10 (原生格式) | 37 |\n`);
@@ -595,6 +595,7 @@ function runTests() {
const marketplaceJson = fs.readFileSync(marketplaceJsonPath, 'utf8');
assert.ok(readme.includes('Access to 1 agents, 1 skills, and 1 legacy command shims'), 'Should sync README quick-start summary');
assert.ok(readme.includes('actual OSS surface: 1 agents, 1 skills, and 1 legacy command shims'), 'Should sync README release-note summary');
assert.ok(readme.includes('|-- agents/ # 1 specialized subagents for delegation'), 'Should sync README project tree agents count');
assert.ok(readme.includes('| Agents | PASS: 1 agents |'), 'Should sync README comparison table');
assert.ok(readme.includes('| Skills | 16 | .agents/skills/ |'), 'Should not rewrite unrelated README tables');