mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-15 13:23:13 +08:00
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:
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -220,6 +220,10 @@ jobs:
|
|||||||
run: node scripts/ci/catalog.js --text
|
run: node scripts/ci/catalog.js --text
|
||||||
continue-on-error: false
|
continue-on-error: false
|
||||||
|
|
||||||
|
- name: Validate command registry
|
||||||
|
run: npm run command-registry:check
|
||||||
|
continue-on-error: false
|
||||||
|
|
||||||
- name: Check unicode safety
|
- name: Check unicode safety
|
||||||
run: node scripts/ci/check-unicode-safety.js
|
run: node scripts/ci/check-unicode-safety.js
|
||||||
continue-on-error: false
|
continue-on-error: false
|
||||||
@@ -253,6 +257,33 @@ jobs:
|
|||||||
- name: Run supply-chain IOC scan
|
- name: Run supply-chain IOC scan
|
||||||
run: npm run security: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:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -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)
|
### 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.
|
- **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.
|
- **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.
|
- **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.
|
- **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
898
docs/COMMAND-REGISTRY.json
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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'",
|
"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:check": "node scripts/ci/catalog.js --text",
|
||||||
"catalog:sync": "node scripts/ci/catalog.js --write --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",
|
"lint": "eslint . && markdownlint '**/*.md' --ignore node_modules",
|
||||||
"harness:adapters": "node scripts/harness-adapter-compliance.js",
|
"harness:adapters": "node scripts/harness-adapter-compliance.js",
|
||||||
"harness:audit": "node scripts/harness-audit.js",
|
"harness:audit": "node scripts/harness-audit.js",
|
||||||
@@ -295,7 +298,7 @@
|
|||||||
"orchestrate:status": "node scripts/orchestration-status.js",
|
"orchestrate:status": "node scripts/orchestration-status.js",
|
||||||
"orchestrate:worker": "bash scripts/orchestrate-codex-worker.sh",
|
"orchestrate:worker": "bash scripts/orchestrate-codex-worker.sh",
|
||||||
"orchestrate:tmux": "node scripts/orchestrate-worktrees.js",
|
"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",
|
"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",
|
"build:opencode": "node scripts/build-opencode.js",
|
||||||
"prepack": "npm run build:opencode",
|
"prepack": "npm run build:opencode",
|
||||||
|
|||||||
@@ -101,6 +101,19 @@ function parseReadmeExpectations(readmeContent) {
|
|||||||
{ category: 'commands', mode: 'exact', expected: Number(quickStartMatch[3]), source: 'README.md quick-start summary' }
|
{ 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);
|
const projectTreeAgentsMatch = readmeContent.match(/^\|\s*--\s*agents\/\s*#\s*(\d+)\s+specialized subagents for delegation\s*$/im);
|
||||||
if (!projectTreeAgentsMatch) {
|
if (!projectTreeAgentsMatch) {
|
||||||
throw new Error('README.md project tree is missing the agents count');
|
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`,
|
`${prefix}${catalog.agents.count}${agentsSuffix}${catalog.skills.count}${skillsSuffix}${catalog.commands.count} legacy command shims`,
|
||||||
'README.md quick-start summary'
|
'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 = replaceOrThrow(
|
||||||
nextContent,
|
nextContent,
|
||||||
/^(\|\s*--\s*agents\/\s*#\s*)(\d+)(\s+specialized subagents for delegation\s*)$/im,
|
/^(\|\s*--\s*agents\/\s*#\s*)(\d+)(\s+specialized subagents for delegation\s*)$/im,
|
||||||
|
|||||||
318
scripts/ci/generate-command-registry.js
Normal file
318
scripts/ci/generate-command-registry.js
Normal 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,
|
||||||
|
};
|
||||||
@@ -44,6 +44,7 @@ function writeEnglishReadme(root, counts, options = {}) {
|
|||||||
const unrelatedSkillsCount = options.unrelatedSkillsCount || 16;
|
const unrelatedSkillsCount = options.unrelatedSkillsCount || 16;
|
||||||
|
|
||||||
fs.writeFileSync(path.join(root, 'README.md'), `Access to ${counts.agents} agents, ${counts.skills} skills, and ${counts.commands} commands.
|
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
|
|-- agents/ # ${counts.agents} specialized subagents for delegation
|
||||||
| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |
|
| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@@ -221,6 +222,7 @@ function runTests() {
|
|||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
assert.ok(formatted.includes('README.md quick-start summary'));
|
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('README.md project tree'));
|
||||||
assert.ok(formatted.includes('AGENTS.md summary'));
|
assert.ok(formatted.includes('AGENTS.md summary'));
|
||||||
assert.ok(formatted.includes('.claude-plugin/plugin.json description'));
|
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');
|
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('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('|-- agents/ # 1 specialized subagents for delegation'));
|
||||||
assert.ok(readme.includes('| Skills | 42 | .agents/skills/ |'));
|
assert.ok(readme.includes('| Skills | 42 | .agents/skills/ |'));
|
||||||
assert.ok(agentsDoc.includes('providing 1 specialized agents, 1+ skills, 1 commands'));
|
assert.ok(agentsDoc.includes('providing 1 specialized agents, 1+ skills, 1 commands'));
|
||||||
|
|||||||
176
tests/ci/command-registry.test.js
Normal file
176
tests/ci/command-registry.test.js
Normal 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();
|
||||||
@@ -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, '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(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(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(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`);
|
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');
|
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('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/ # 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('| Agents | PASS: 1 agents |'), 'Should sync README comparison table');
|
||||||
assert.ok(readme.includes('| Skills | 16 | .agents/skills/ |'), 'Should not rewrite unrelated README tables');
|
assert.ok(readme.includes('| Skills | 16 | .agents/skills/ |'), 'Should not rewrite unrelated README tables');
|
||||||
|
|||||||
Reference in New Issue
Block a user