mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-11 02:33:10 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2707ef2eb2 |
File diff suppressed because one or more lines are too long
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"sessionId": "d43d7ca3-7fe6-40a0-8bf6-92c3848903b8",
|
|
||||||
"eventCount": 13,
|
|
||||||
"lastAnalysisTimestamp": null,
|
|
||||||
"lastAnalysisEventCount": 0
|
|
||||||
}
|
|
||||||
15
.github/workflows/reusable-test.yml
vendored
15
.github/workflows/reusable-test.yml
vendored
@@ -149,21 +149,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CLAUDE_CODE_PACKAGE_MANAGER: ${{ inputs.package-manager }}
|
CLAUDE_CODE_PACKAGE_MANAGER: ${{ inputs.package-manager }}
|
||||||
|
|
||||||
- name: Run coverage
|
|
||||||
run: npm run coverage
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
CLAUDE_CODE_PACKAGE_MANAGER: ${{ inputs.package-manager }}
|
|
||||||
|
|
||||||
- name: Upload coverage reports
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
||||||
with:
|
|
||||||
name: coverage-${{ inputs.os }}-node${{ inputs.node-version }}-${{ inputs.package-manager }}
|
|
||||||
path: |
|
|
||||||
coverage/
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
- name: Upload test artifacts
|
- name: Upload test artifacts
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
|||||||
@@ -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: 60 agents, 228 skills, and 75 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: 55 agents, 208 skills, and 72 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.
|
||||||
|
|||||||
@@ -1,798 +0,0 @@
|
|||||||
{
|
|
||||||
"generated": "2026-05-14T18:36:38.210Z",
|
|
||||||
"totalCommands": 75,
|
|
||||||
"commands": [
|
|
||||||
{
|
|
||||||
"command": "aside",
|
|
||||||
"description": "Aside Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/aside.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "auto-update",
|
|
||||||
"description": "Auto Update",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/auto-update.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "build-fix",
|
|
||||||
"description": "Build and Fix",
|
|
||||||
"type": "refactoring",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/build-fix.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "checkpoint",
|
|
||||||
"description": "Checkpoint Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/checkpoint.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "code-review",
|
|
||||||
"description": "Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/code-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "cost-report",
|
|
||||||
"description": "Cost Report",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/cost-report.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "cpp-build",
|
|
||||||
"description": "C++ Build and Fix",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"cpp-coding-standards"
|
|
||||||
],
|
|
||||||
"path": "commands/cpp-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "cpp-review",
|
|
||||||
"description": "C++ Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"cpp-coding-standards",
|
|
||||||
"cpp-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/cpp-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "cpp-test",
|
|
||||||
"description": "C++ TDD Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"cpp-testing",
|
|
||||||
"tdd-workflow"
|
|
||||||
],
|
|
||||||
"path": "commands/cpp-test.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "ecc-guide",
|
|
||||||
"description": "/ecc-guide",
|
|
||||||
"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": "FastAPI Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/fastapi-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "feature-dev",
|
|
||||||
"description": "",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/feature-dev.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "flutter-build",
|
|
||||||
"description": "Flutter Build and Fix",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"flutter-dart-code-review"
|
|
||||||
],
|
|
||||||
"path": "commands/flutter-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "flutter-review",
|
|
||||||
"description": "Flutter Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"flutter-dart-code-review"
|
|
||||||
],
|
|
||||||
"path": "commands/flutter-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "flutter-test",
|
|
||||||
"description": "Flutter Test",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"flutter-dart-code-review"
|
|
||||||
],
|
|
||||||
"path": "commands/flutter-test.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "gan-build",
|
|
||||||
"description": "",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/gan-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "gan-design",
|
|
||||||
"description": "",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/gan-design.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "go-build",
|
|
||||||
"description": "Go Build and Fix",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"golang-patterns"
|
|
||||||
],
|
|
||||||
"path": "commands/go-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "go-review",
|
|
||||||
"description": "Go Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"golang-patterns",
|
|
||||||
"golang-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/go-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "go-test",
|
|
||||||
"description": "Go TDD Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"golang-testing",
|
|
||||||
"tdd-workflow"
|
|
||||||
],
|
|
||||||
"path": "commands/go-test.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "gradle-build",
|
|
||||||
"description": "Gradle Build Fix",
|
|
||||||
"type": "build",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/gradle-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "harness-audit",
|
|
||||||
"description": "Harness Audit Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/harness-audit.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "hookify-configure",
|
|
||||||
"description": "",
|
|
||||||
"type": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/hookify-configure.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "hookify-help",
|
|
||||||
"description": "",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/hookify-help.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "hookify-list",
|
|
||||||
"description": "",
|
|
||||||
"type": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/hookify-list.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "hookify",
|
|
||||||
"description": "",
|
|
||||||
"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": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"continuous-learning-v2"
|
|
||||||
],
|
|
||||||
"path": "commands/instinct-status.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "jira",
|
|
||||||
"description": "Jira Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"jira-integration"
|
|
||||||
],
|
|
||||||
"path": "commands/jira.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "kotlin-build",
|
|
||||||
"description": "Kotlin Build and Fix",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"kotlin-patterns"
|
|
||||||
],
|
|
||||||
"path": "commands/kotlin-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "kotlin-review",
|
|
||||||
"description": "Kotlin Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"kotlin-patterns",
|
|
||||||
"kotlin-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/kotlin-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "kotlin-test",
|
|
||||||
"description": "Kotlin TDD Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"kotlin-testing",
|
|
||||||
"tdd-workflow"
|
|
||||||
],
|
|
||||||
"path": "commands/kotlin-test.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "learn-eval",
|
|
||||||
"description": "\"Under 130 characters\"",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/learn-eval.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "learn",
|
|
||||||
"description": "/learn - Extract Reusable Patterns",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/learn.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "loop-start",
|
|
||||||
"description": "Loop Start Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/loop-start.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "loop-status",
|
|
||||||
"description": "Loop Status Command",
|
|
||||||
"type": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/loop-status.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "model-route",
|
|
||||||
"description": "Model Route Command",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/model-route.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "multi-backend",
|
|
||||||
"description": "Backend - Backend-Focused Development",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/multi-backend.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "multi-execute",
|
|
||||||
"description": "Execute - Multi-Model Collaborative Execution",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/multi-execute.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "multi-frontend",
|
|
||||||
"description": "Frontend - Frontend-Focused Development",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/multi-frontend.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "multi-plan",
|
|
||||||
"description": "Plan - Multi-Model Collaborative Planning",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"accessibility"
|
|
||||||
],
|
|
||||||
"path": "commands/multi-plan.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "multi-workflow",
|
|
||||||
"description": "Workflow - Multi-Model Collaborative Development",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/multi-workflow.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "plan-prd",
|
|
||||||
"description": "PRD Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/plan-prd.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "plan",
|
|
||||||
"description": "Plan Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/plan.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "pm2",
|
|
||||||
"description": "PM2 Init",
|
|
||||||
"type": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/pm2.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "pr",
|
|
||||||
"description": "Create Pull Request",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/pr.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "project-init",
|
|
||||||
"description": "/project-init",
|
|
||||||
"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": "Smart Commit",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/prp-commit.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "prp-implement",
|
|
||||||
"description": "PRP Implement",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/prp-implement.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "prp-plan",
|
|
||||||
"description": "PRP Plan",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/prp-plan.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "prp-pr",
|
|
||||||
"description": "Create Pull Request",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/prp-pr.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "prp-prd",
|
|
||||||
"description": "Product Requirements Document Generator",
|
|
||||||
"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": "Python Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"python-patterns",
|
|
||||||
"python-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/python-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "quality-gate",
|
|
||||||
"description": "Quality Gate Command",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/quality-gate.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "refactor-clean",
|
|
||||||
"description": "Refactor Clean",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/refactor-clean.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "resume-session",
|
|
||||||
"description": "Resume Session Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/resume-session.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "review-pr",
|
|
||||||
"description": "",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/review-pr.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "rust-build",
|
|
||||||
"description": "Rust Build and Fix",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"rust-patterns"
|
|
||||||
],
|
|
||||||
"path": "commands/rust-build.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "rust-review",
|
|
||||||
"description": "Rust Code Review",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"rust-patterns",
|
|
||||||
"rust-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/rust-review.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "rust-test",
|
|
||||||
"description": "Rust TDD Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"rust-patterns",
|
|
||||||
"rust-testing"
|
|
||||||
],
|
|
||||||
"path": "commands/rust-test.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "santa-loop",
|
|
||||||
"description": "Santa Loop",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/santa-loop.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "save-session",
|
|
||||||
"description": "Save Session Command",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/save-session.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "security-scan",
|
|
||||||
"description": "Security Scan Command",
|
|
||||||
"type": "review",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [
|
|
||||||
"security-scan"
|
|
||||||
],
|
|
||||||
"path": "commands/security-scan.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "sessions",
|
|
||||||
"description": "Sessions Command",
|
|
||||||
"type": "general",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/sessions.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "setup-pm",
|
|
||||||
"description": "Package Manager Setup",
|
|
||||||
"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": "Test Coverage",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/test-coverage.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "update-codemaps",
|
|
||||||
"description": "Update Codemaps",
|
|
||||||
"type": "planning",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/update-codemaps.md"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "update-docs",
|
|
||||||
"description": "Update Documentation",
|
|
||||||
"type": "testing",
|
|
||||||
"primaryAgents": [],
|
|
||||||
"allAgents": [],
|
|
||||||
"skills": [],
|
|
||||||
"path": "commands/update-docs.md"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"statistics": {
|
|
||||||
"byType": {
|
|
||||||
"testing": 52,
|
|
||||||
"refactoring": 1,
|
|
||||||
"review": 11,
|
|
||||||
"build": 2,
|
|
||||||
"general": 8,
|
|
||||||
"planning": 1
|
|
||||||
},
|
|
||||||
"topAgents": [],
|
|
||||||
"topSkills": [
|
|
||||||
{
|
|
||||||
"skill": "continuous-learning-v2",
|
|
||||||
"count": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "tdd-workflow",
|
|
||||||
"count": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "flutter-dart-code-review",
|
|
||||||
"count": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "rust-patterns",
|
|
||||||
"count": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "cpp-coding-standards",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "cpp-testing",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "ecc-guide",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "security-scan",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "golang-patterns",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"skill": "golang-testing",
|
|
||||||
"count": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -285,8 +285,6 @@
|
|||||||
"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",
|
|
||||||
"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",
|
||||||
|
|||||||
@@ -1,249 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/**
|
|
||||||
* Generate Command → Agent/Skill Registry
|
|
||||||
*
|
|
||||||
* Scans all command markdown files and extracts:
|
|
||||||
* - Command name/description
|
|
||||||
* - Primary agent(s) referenced
|
|
||||||
* - Skills referenced
|
|
||||||
* - Command type (workflow, testing, review, etc.)
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* node scripts/ci/generate-command-registry.js
|
|
||||||
* node scripts/ci/generate-command-registry.js --json
|
|
||||||
* node scripts/ci/generate-command-registry.js --write
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const ROOT = path.join(__dirname, '../..');
|
|
||||||
const COMMANDS_DIR = path.join(ROOT, 'commands');
|
|
||||||
const AGENTS_DIR = path.join(ROOT, 'agents');
|
|
||||||
const OUTPUT_PATH = path.join(ROOT, 'docs', 'COMMAND-REGISTRY.json');
|
|
||||||
const WRITE_MODE = process.argv.includes('--write');
|
|
||||||
const OUTPUT_JSON = process.argv.includes('--json');
|
|
||||||
|
|
||||||
const KNOWN_AGENTS = new Set();
|
|
||||||
const KNOWN_SKILLS = new Set();
|
|
||||||
|
|
||||||
// Scan agents directory for known agents
|
|
||||||
function scanKnownAgents() {
|
|
||||||
if (!fs.existsSync(AGENTS_DIR)) return;
|
|
||||||
|
|
||||||
const files = fs.readdirSync(AGENTS_DIR, { withFileTypes: true });
|
|
||||||
files.forEach(entry => {
|
|
||||||
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
||||||
const agentName = entry.name.replace('.md', '');
|
|
||||||
KNOWN_AGENTS.add(agentName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan skills directory for known skills
|
|
||||||
function scanKnownSkills() {
|
|
||||||
const skillsDir = path.join(ROOT, 'skills');
|
|
||||||
if (!fs.existsSync(skillsDir)) return;
|
|
||||||
|
|
||||||
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
||||||
entries.forEach(entry => {
|
|
||||||
if (entry.isDirectory() && fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md'))) {
|
|
||||||
KNOWN_SKILLS.add(entry.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract agents and skills from markdown content
|
|
||||||
function extractReferences(content) {
|
|
||||||
const agents = new Set();
|
|
||||||
const skills = new Set();
|
|
||||||
|
|
||||||
// Pattern: @agent-name or agent-name in code blocks, lists, or descriptions
|
|
||||||
const agentPatterns = [
|
|
||||||
/@([a-z][a-z0-9-]*)/gi, // @agent-name
|
|
||||||
/agent:\s*([a-z][a-z0-9-]*)/gi, // agent: name
|
|
||||||
/subagent(?:_type)?:\s*["']?([a-z][a-z0-9-]*)/gi, // subagent_type: "name"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Pattern: /skill-name or /command-name
|
|
||||||
const skillPatterns = [
|
|
||||||
/\/([a-z][a-z0-9-]*)/gi, // /skill-name
|
|
||||||
/skill:\s*\/?([a-z][a-z0-9-]*)/gi, // skill: /name or skill: name
|
|
||||||
];
|
|
||||||
|
|
||||||
// Extract agents
|
|
||||||
agentPatterns.forEach(pattern => {
|
|
||||||
const matches = content.matchAll(pattern);
|
|
||||||
for (const match of matches) {
|
|
||||||
const ref = match[1];
|
|
||||||
if (KNOWN_AGENTS.has(ref)) {
|
|
||||||
agents.add(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Extract skills
|
|
||||||
skillPatterns.forEach(pattern => {
|
|
||||||
const matches = content.matchAll(pattern);
|
|
||||||
for (const match of matches) {
|
|
||||||
const ref = match[1];
|
|
||||||
if (KNOWN_SKILLS.has(ref)) {
|
|
||||||
skills.add(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
agents: Array.from(agents).sort(),
|
|
||||||
skills: Array.from(skills).sort()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infer command type from content
|
|
||||||
function inferCommandType(content, filename) {
|
|
||||||
const lower = content.toLowerCase();
|
|
||||||
|
|
||||||
if (lower.includes('test') || lower.includes('tdd') || lower.includes('coverage')) {
|
|
||||||
return 'testing';
|
|
||||||
}
|
|
||||||
if (lower.includes('review') || lower.includes('audit') || lower.includes('quality')) {
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
if (filename.startsWith('multi-')) {
|
|
||||||
return 'orchestration';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'general';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process single command file
|
|
||||||
function processCommandFile(filename) {
|
|
||||||
const filePath = path.join(COMMANDS_DIR, filename);
|
|
||||||
const content = fs.readFileSync(filePath, 'utf8');
|
|
||||||
|
|
||||||
// Extract description from frontmatter or first heading
|
|
||||||
let description = '';
|
|
||||||
const frontmatterMatch = content.match(/^---\n[\s\S]*?\ndescription:\s*(.+?)\n[\s\S]*?^---/m);
|
|
||||||
if (frontmatterMatch) {
|
|
||||||
description = frontmatterMatch[1].trim();
|
|
||||||
} else {
|
|
||||||
const headingMatch = content.match(/^#\s+(.+)$/m);
|
|
||||||
if (headingMatch) {
|
|
||||||
description = headingMatch[1].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const commandName = filename.replace('.md', '');
|
|
||||||
const references = extractReferences(content);
|
|
||||||
const type = inferCommandType(content, filename);
|
|
||||||
|
|
||||||
return {
|
|
||||||
command: commandName,
|
|
||||||
description,
|
|
||||||
type,
|
|
||||||
primaryAgents: references.agents.slice(0, 3), // Top 3 agents
|
|
||||||
allAgents: references.agents,
|
|
||||||
skills: references.skills,
|
|
||||||
path: `commands/${filename}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate full registry
|
|
||||||
function generateRegistry() {
|
|
||||||
scanKnownAgents();
|
|
||||||
scanKnownSkills();
|
|
||||||
|
|
||||||
if (!fs.existsSync(COMMANDS_DIR)) {
|
|
||||||
console.error('commands/ directory not found');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = fs.readdirSync(COMMANDS_DIR, { withFileTypes: true })
|
|
||||||
.filter(entry => entry.isFile() && entry.name.endsWith('.md'))
|
|
||||||
.map(entry => entry.name)
|
|
||||||
.sort();
|
|
||||||
|
|
||||||
const registry = {
|
|
||||||
generated: new Date().toISOString(),
|
|
||||||
totalCommands: files.length,
|
|
||||||
commands: files.map(processCommandFile)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add statistics
|
|
||||||
const typeCounts = {};
|
|
||||||
const agentUsage = {};
|
|
||||||
const skillUsage = {};
|
|
||||||
|
|
||||||
registry.commands.forEach(cmd => {
|
|
||||||
typeCounts[cmd.type] = (typeCounts[cmd.type] || 0) + 1;
|
|
||||||
cmd.allAgents.forEach(agent => {
|
|
||||||
agentUsage[agent] = (agentUsage[agent] || 0) + 1;
|
|
||||||
});
|
|
||||||
cmd.skills.forEach(skill => {
|
|
||||||
skillUsage[skill] = (skillUsage[skill] || 0) + 1;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
registry.statistics = {
|
|
||||||
byType: typeCounts,
|
|
||||||
topAgents: Object.entries(agentUsage)
|
|
||||||
.sort((a, b) => b[1] - a[1])
|
|
||||||
.slice(0, 10)
|
|
||||||
.map(([agent, count]) => ({ agent, count })),
|
|
||||||
topSkills: Object.entries(skillUsage)
|
|
||||||
.sort((a, b) => b[1] - a[1])
|
|
||||||
.slice(0, 10)
|
|
||||||
.map(([skill, count]) => ({ skill, count }))
|
|
||||||
};
|
|
||||||
|
|
||||||
return registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main execution
|
|
||||||
function main() {
|
|
||||||
const registry = generateRegistry();
|
|
||||||
|
|
||||||
if (OUTPUT_JSON) {
|
|
||||||
console.log(JSON.stringify(registry, null, 2));
|
|
||||||
} else {
|
|
||||||
console.log('\n📊 Command Registry Statistics\n');
|
|
||||||
console.log(`Total commands: ${registry.totalCommands}`);
|
|
||||||
console.log('\nBy type:');
|
|
||||||
Object.entries(registry.statistics.byType)
|
|
||||||
.sort((a, b) => b[1] - a[1])
|
|
||||||
.forEach(([type, count]) => {
|
|
||||||
console.log(` ${type}: ${count}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('\nTop 10 agents:');
|
|
||||||
registry.statistics.topAgents.forEach(({ agent, count }) => {
|
|
||||||
console.log(` ${agent}: ${count} commands`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('\nTop 10 skills:');
|
|
||||||
registry.statistics.topSkills.forEach(({ skill, count }) => {
|
|
||||||
console.log(` ${skill}: ${count} commands`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`\n📄 Generated: ${registry.generated}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WRITE_MODE) {
|
|
||||||
fs.mkdirSync(path.dirname(OUTPUT_PATH), { recursive: true });
|
|
||||||
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(registry, null, 2) + '\n');
|
|
||||||
console.log(`\n✅ Registry written to: ${OUTPUT_PATH}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,63 +1,157 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Cost Tracker Hook
|
* Cost Tracker Hook (v2)
|
||||||
*
|
*
|
||||||
* Appends lightweight session usage metrics to ~/.claude/metrics/costs.jsonl.
|
* Reads transcript_path from Stop hook stdin, sums usage across all
|
||||||
|
* assistant turns in the session JSONL, and appends one row to
|
||||||
|
* ~/.claude/metrics/costs.jsonl.
|
||||||
|
*
|
||||||
|
* Stop hook stdin payload: { session_id, transcript_path, cwd, hook_event_name, ... }
|
||||||
|
* The Stop payload does NOT include `usage` or `model` directly. The previous
|
||||||
|
* version of this hook expected those fields and silently produced zero-filled
|
||||||
|
* rows (verified: 2,340 rows captured with 0.0% non-zero token rate over 52
|
||||||
|
* days). The fix is to read the transcript file Claude Code already passes us.
|
||||||
|
*
|
||||||
|
* JSONL assistant entry shape (per Claude Code):
|
||||||
|
* { type: "assistant", message: { model, usage: { input_tokens, output_tokens,
|
||||||
|
* cache_creation_input_tokens, cache_read_input_tokens } } }
|
||||||
|
*
|
||||||
|
* Cumulative behavior: Stop fires per assistant response, not per session.
|
||||||
|
* Each row therefore represents the cumulative session total up to that point.
|
||||||
|
* To get per-session cost, take the last row per session_id. To get per-day
|
||||||
|
* spend, aggregate.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { ensureDir, appendFile, getClaudeDir } = require('../lib/utils');
|
const { ensureDir, appendFile, getClaudeDir } = require('../lib/utils');
|
||||||
const { estimateCost } = require('../lib/cost-estimate');
|
|
||||||
const { sanitizeSessionId } = require('../lib/session-bridge');
|
const { sanitizeSessionId } = require('../lib/session-bridge');
|
||||||
|
|
||||||
const MAX_STDIN = 1024 * 1024;
|
// Approximate per-1M-token billing rates (USD).
|
||||||
let raw = '';
|
// Cache creation: 1.25x input rate. Cache read: 0.1x input rate.
|
||||||
|
const RATE_TABLE = {
|
||||||
|
haiku: { in: 0.80, out: 4.0, cacheWrite: 1.00, cacheRead: 0.08 },
|
||||||
|
sonnet: { in: 3.00, out: 15.0, cacheWrite: 3.75, cacheRead: 0.30 },
|
||||||
|
opus: { in: 15.00, out: 75.0, cacheWrite: 18.75, cacheRead: 1.50 }
|
||||||
|
};
|
||||||
|
|
||||||
function toNumber(value) {
|
function getRates(model) {
|
||||||
const n = Number(value);
|
const m = String(model || '').toLowerCase();
|
||||||
|
if (m.includes('haiku')) return RATE_TABLE.haiku;
|
||||||
|
if (m.includes('opus')) return RATE_TABLE.opus;
|
||||||
|
return RATE_TABLE.sonnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toNumber(v) {
|
||||||
|
const n = Number(v);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan the session JSONL and sum token usage across all assistant turns.
|
||||||
|
* Returns { inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens, model }
|
||||||
|
* or null on read failure.
|
||||||
|
*/
|
||||||
|
function sumUsageFromTranscript(transcriptPath) {
|
||||||
|
let content;
|
||||||
|
try {
|
||||||
|
content = fs.readFileSync(transcriptPath, 'utf8');
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputTokens = 0;
|
||||||
|
let outputTokens = 0;
|
||||||
|
let cacheWriteTokens = 0;
|
||||||
|
let cacheReadTokens = 0;
|
||||||
|
let model = 'unknown';
|
||||||
|
|
||||||
|
for (const line of content.split('\n')) {
|
||||||
|
if (!line.trim()) continue;
|
||||||
|
let entry;
|
||||||
|
try { entry = JSON.parse(line); } catch { continue; }
|
||||||
|
|
||||||
|
if (entry.type !== 'assistant') continue;
|
||||||
|
const msg = entry.message;
|
||||||
|
if (!msg || !msg.usage) continue;
|
||||||
|
|
||||||
|
const u = msg.usage;
|
||||||
|
inputTokens += toNumber(u.input_tokens);
|
||||||
|
outputTokens += toNumber(u.output_tokens);
|
||||||
|
cacheWriteTokens += toNumber(u.cache_creation_input_tokens);
|
||||||
|
cacheReadTokens += toNumber(u.cache_read_input_tokens);
|
||||||
|
|
||||||
|
if (msg.model && msg.model !== 'unknown') model = msg.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens, model };
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_STDIN = 64 * 1024;
|
||||||
|
let raw = '';
|
||||||
|
|
||||||
process.stdin.setEncoding('utf8');
|
process.stdin.setEncoding('utf8');
|
||||||
process.stdin.on('data', chunk => {
|
process.stdin.on('data', chunk => {
|
||||||
if (raw.length < MAX_STDIN) {
|
if (raw.length < MAX_STDIN) raw += chunk.substring(0, MAX_STDIN - raw.length);
|
||||||
const remaining = MAX_STDIN - raw.length;
|
|
||||||
raw += chunk.substring(0, remaining);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
process.stdin.on('end', () => {
|
process.stdin.on('end', () => {
|
||||||
try {
|
try {
|
||||||
const input = raw.trim() ? JSON.parse(raw) : {};
|
const input = raw.trim() ? JSON.parse(raw) : {};
|
||||||
const usage = input.usage || input.token_usage || {};
|
|
||||||
const inputTokens = toNumber(usage.input_tokens || usage.prompt_tokens || 0);
|
|
||||||
const outputTokens = toNumber(usage.output_tokens || usage.completion_tokens || 0);
|
|
||||||
|
|
||||||
const model = String(input.model || input._cursor?.model || process.env.CLAUDE_MODEL || 'unknown');
|
const transcriptPath = (typeof input.transcript_path === 'string' && input.transcript_path)
|
||||||
|
? input.transcript_path
|
||||||
|
: process.env.CLAUDE_TRANSCRIPT_PATH || null;
|
||||||
|
|
||||||
const sessionId =
|
const sessionId =
|
||||||
sanitizeSessionId(input.session_id) ||
|
sanitizeSessionId(input.session_id) ||
|
||||||
sanitizeSessionId(process.env.ECC_SESSION_ID) ||
|
sanitizeSessionId(process.env.ECC_SESSION_ID) ||
|
||||||
sanitizeSessionId(process.env.CLAUDE_SESSION_ID) ||
|
sanitizeSessionId(process.env.CLAUDE_SESSION_ID) ||
|
||||||
'default';
|
'default';
|
||||||
|
|
||||||
|
let usageTotals = null;
|
||||||
|
if (transcriptPath && fs.existsSync(transcriptPath)) {
|
||||||
|
usageTotals = sumUsageFromTranscript(transcriptPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
inputTokens = 0,
|
||||||
|
outputTokens = 0,
|
||||||
|
cacheWriteTokens = 0,
|
||||||
|
cacheReadTokens = 0,
|
||||||
|
model = 'unknown'
|
||||||
|
} = usageTotals || {};
|
||||||
|
|
||||||
|
const rates = getRates(model);
|
||||||
|
const estimatedCostUsd = Math.round((
|
||||||
|
(inputTokens / 1e6) * rates.in +
|
||||||
|
(outputTokens / 1e6) * rates.out +
|
||||||
|
(cacheWriteTokens / 1e6) * rates.cacheWrite +
|
||||||
|
(cacheReadTokens / 1e6) * rates.cacheRead
|
||||||
|
) * 1e6) / 1e6;
|
||||||
|
|
||||||
const metricsDir = path.join(getClaudeDir(), 'metrics');
|
const metricsDir = path.join(getClaudeDir(), 'metrics');
|
||||||
ensureDir(metricsDir);
|
ensureDir(metricsDir);
|
||||||
|
|
||||||
const row = {
|
const row = {
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
|
transcript_path: transcriptPath || '',
|
||||||
model,
|
model,
|
||||||
input_tokens: inputTokens,
|
input_tokens: inputTokens,
|
||||||
output_tokens: outputTokens,
|
output_tokens: outputTokens,
|
||||||
estimated_cost_usd: estimateCost(model, inputTokens, outputTokens)
|
cache_write_tokens: cacheWriteTokens,
|
||||||
|
cache_read_tokens: cacheReadTokens,
|
||||||
|
estimated_cost_usd: estimatedCostUsd
|
||||||
};
|
};
|
||||||
|
|
||||||
appendFile(path.join(metricsDir, 'costs.jsonl'), `${JSON.stringify(row)}\n`);
|
appendFile(path.join(metricsDir, 'costs.jsonl'), `${JSON.stringify(row)}\n`);
|
||||||
} catch {
|
} catch {
|
||||||
// Keep hook non-blocking.
|
// Non-blocking — never fail the Stop hook.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass stdin through (required by ECC hook convention).
|
||||||
process.stdout.write(raw);
|
process.stdout.write(raw);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user