feat(ecc2): finalize rc1 release surface

This commit is contained in:
Affaan Mustafa
2026-04-28 22:10:04 -04:00
parent 4e66b2882d
commit 0a87323eda
40 changed files with 863 additions and 76 deletions

View File

@@ -6,7 +6,7 @@
"plugins": [
{
"name": "ecc",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"source": {
"source": "local",
"path": "../.."

View File

@@ -11,8 +11,8 @@
{
"name": "everything-claude-code",
"source": "./",
"description": "The most comprehensive Claude Code plugin — 38 agents, 156 skills, 72 legacy command shims, selective install profiles, and production-ready hooks for TDD, security scanning, code review, and continuous learning",
"version": "1.10.0",
"description": "The most comprehensive Claude Code plugin — 48 agents, 184 skills, 79 legacy command shims, selective install profiles, and production-ready hooks for TDD, security scanning, code review, and continuous learning",
"version": "2.0.0-rc.1",
"author": {
"name": "Affaan Mustafa",
"email": "me@affaanmustafa.com"

View File

@@ -1,7 +1,7 @@
{
"name": "everything-claude-code",
"version": "1.10.0",
"description": "Battle-tested Claude Code plugin for engineering teams — 38 agents, 156 skills, 72 legacy command shims, production-ready hooks, and selective install workflows evolved through continuous real-world use",
"version": "2.0.0-rc.1",
"description": "Battle-tested Claude Code plugin for engineering teams — 48 agents, 184 skills, 79 legacy command shims, production-ready hooks, and selective install workflows evolved through continuous real-world use",
"author": {
"name": "Affaan Mustafa",
"url": "https://x.com/affaanmustafa"

View File

@@ -1,6 +1,6 @@
{
"name": "ecc",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"description": "Battle-tested Codex workflows — 156 shared ECC skills, production-ready MCP configs, and selective-install-aligned conventions for TDD, security scanning, code review, and autonomous development.",
"author": {
"name": "Affaan Mustafa",

View File

@@ -2,7 +2,8 @@ name: CI
on:
push:
branches: [main]
branches: [main, 'release/**']
tags: ['v*']
pull_request:
branches: [main]

View File

@@ -33,8 +33,8 @@ jobs:
- name: Validate version tag
run: |
if ! [[ "${REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z"
if ! [[ "${REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z or vX.Y.Z-prerelease"
exit 1
fi
@@ -60,17 +60,13 @@ jobs:
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
PACKAGE_VERSION=$(node -p "require('./package.json').version")
NPM_DIST_TAG=$(node -p "require('./package.json').version.includes('-') ? 'next' : 'latest'")
if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish npm package
if: steps.npm_publish_state.outputs.already_published != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance
echo "dist_tag=${NPM_DIST_TAG}" >> "$GITHUB_OUTPUT"
- name: Generate release highlights
id: highlights
@@ -102,3 +98,11 @@ jobs:
with:
body_path: release_body.md
generate_release_notes: true
prerelease: ${{ contains(github.ref_name, '-') }}
make_latest: ${{ contains(github.ref_name, '-') && 'false' || 'true' }}
- name: Publish npm package
if: steps.npm_publish_state.outputs.already_published != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance --tag "${{ steps.npm_publish_state.outputs.dist_tag }}"

View File

@@ -18,7 +18,7 @@ on:
workflow_dispatch:
inputs:
tag:
description: 'Version tag to release or republish (e.g., v1.10.0)'
description: 'Version tag to release or republish (e.g., v2.0.0-rc.1)'
required: true
type: string
generate-notes:
@@ -41,6 +41,7 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
@@ -58,8 +59,8 @@ jobs:
env:
INPUT_TAG: ${{ inputs.tag }}
run: |
if ! [[ "$INPUT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z"
if ! [[ "$INPUT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z or vX.Y.Z-prerelease"
exit 1
fi
@@ -83,17 +84,13 @@ jobs:
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
PACKAGE_VERSION=$(node -p "require('./package.json').version")
NPM_DIST_TAG=$(node -p "require('./package.json').version.includes('-') ? 'next' : 'latest'")
if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish npm package
if: steps.npm_publish_state.outputs.already_published != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance
echo "dist_tag=${NPM_DIST_TAG}" >> "$GITHUB_OUTPUT"
- name: Generate release highlights
env:
@@ -119,3 +116,11 @@ jobs:
tag_name: ${{ inputs.tag }}
body_path: release_body.md
generate_release_notes: ${{ inputs.generate-notes }}
prerelease: ${{ contains(inputs.tag, '-') }}
make_latest: ${{ contains(inputs.tag, '-') && 'false' || 'true' }}
- name: Publish npm package
if: steps.npm_publish_state.outputs.already_published != 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance --tag "${{ steps.npm_publish_state.outputs.dist_tag }}"

2
.opencode/.npmignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules
bun.lock

View File

@@ -1,12 +1,12 @@
{
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"license": "MIT",
"devDependencies": {
"@opencode-ai/plugin": "^1.4.3",

View File

@@ -1,6 +1,6 @@
{
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"description": "Everything Claude Code (ECC) plugin for OpenCode - agents, commands, hooks, and skills",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -456,7 +456,7 @@ export const ECCHooksPlugin: ECCHooksPluginFn = async ({
const contextBlock = [
"# ECC Context (preserve across compaction)",
"",
"## Active Plugin: Everything Claude Code v1.10.0",
"## Active Plugin: Everything Claude Code v2.0.0-rc.1",
"- Hooks: file.edited, tool.execute.before/after, session.created/idle/deleted, shell.env, compacting, permission.ask",
"- Tools: run-tests, check-coverage, security-audit, format-code, lint-check, git-summary, changed-files",
"- Agents: 13 specialized (planner, architect, tdd-guide, code-reviewer, security-reviewer, build-error-resolver, e2e-runner, refactor-cleaner, doc-updater, go-reviewer, go-build-resolver, database-reviewer, python-reviewer)",

View File

@@ -1,8 +1,8 @@
# Everything Claude Code (ECC) — Agent Instructions
This is a **production-ready AI coding plugin** providing 48 specialized agents, 183 skills, 79 commands, and automated hook workflows for software development.
This is a **production-ready AI coding plugin** providing 48 specialized agents, 184 skills, 79 commands, and automated hook workflows for software development.
**Version:** 1.10.0
**Version:** 2.0.0-rc.1
## Core Principles
@@ -146,7 +146,7 @@ Troubleshoot failures: check test isolation → verify mocks → fix implementat
```
agents/ — 48 specialized subagents
skills/ — 183 workflow skills and domain knowledge
skills/ — 184 workflow skills and domain knowledge
commands/ — 79 slash commands
hooks/ — Trigger-based automations
rules/ — Always-follow guidelines (common + per-language)

View File

@@ -1,5 +1,25 @@
# Changelog
## 2.0.0-rc.1 - 2026-04-28
### Highlights
- Adds the public ECC 2.0 release-candidate surface for the Hermes operator story.
- Documents ECC as the reusable cross-harness substrate across Claude Code, Codex, Cursor, OpenCode, and Gemini.
- Adds a sanitized Hermes import skill surface instead of publishing private operator state.
### Release Surface
- Updated package, plugin, marketplace, OpenCode, agent, and README metadata to `2.0.0-rc.1`.
- Added `docs/releases/2.0.0-rc.1/` with release notes, social drafts, launch checklist, handoff notes, and demo prompts.
- Added `docs/architecture/cross-harness.md` and regression coverage for the ECC/Hermes boundary.
- Kept `ecc2/` versioning independent for now; it remains an alpha control-plane scaffold unless release engineering decides otherwise.
### Notes
- This is a release candidate, not a GA claim for the full ECC 2.0 control-plane roadmap.
- Prerelease npm publishing should use the `next` dist-tag unless release engineering explicitly chooses otherwise.
## 1.10.0 - 2026-04-05
### Highlights

View File

@@ -40,6 +40,8 @@ Not just configs. A complete system: skills, instincts, memory optimization, con
Works across **Claude Code**, **Codex**, **Cursor**, **OpenCode**, **Gemini**, and other AI agent harnesses.
ECC v2.0.0-rc.1 adds the public Hermes operator story on top of that reusable layer: start with the [Hermes setup guide](docs/HERMES-SETUP.md), then review the [rc.1 release notes](docs/releases/2.0.0-rc.1/release-notes.md) and [cross-harness architecture](docs/architecture/cross-harness.md).
---
## The Guides
@@ -84,7 +86,7 @@ This repo is the raw code only. The guides explain everything.
## What's New
### v1.10.0 — 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.
- **Public surface synced to the live repo** — metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: 38 agents, 156 skills, and 72 legacy command shims.
@@ -247,7 +249,7 @@ For manual install instructions see the README in the `rules/` folder. When copy
/plugin list everything-claude-code@everything-claude-code
```
**That's it!** You now have access to 48 agents, 183 skills, and 79 legacy command shims.
**That's it!** You now have access to 48 agents, 184 skills, and 79 legacy command shims.
### Dashboard GUI
@@ -1215,7 +1217,7 @@ The configuration is automatically detected from `.opencode/opencode.json`.
|---------|-------------|----------|--------|
| Agents | PASS: 48 agents | PASS: 12 agents | **Claude Code leads** |
| Commands | PASS: 79 commands | PASS: 31 commands | **Claude Code leads** |
| Skills | PASS: 183 skills | PASS: 37 skills | **Claude Code leads** |
| Skills | PASS: 184 skills | PASS: 37 skills | **Claude Code leads** |
| Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** |
| Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** |
| MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** |
@@ -1324,7 +1326,7 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
|---------|------------|------------|-----------|----------|
| **Agents** | 48 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |
| **Commands** | 79 | Shared | Instruction-based | 31 |
| **Skills** | 183 | Shared | 10 (native format) | 37 |
| **Skills** | 184 | Shared | 10 (native format) | 37 |
| **Hook Events** | 8 types | 15 types | None yet | 11 types |
| **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks |
| **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions |
@@ -1334,7 +1336,7 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
| **Context File** | CLAUDE.md + AGENTS.md | AGENTS.md | AGENTS.md | AGENTS.md |
| **Secret Detection** | Hook-based | beforeSubmitPrompt hook | Sandbox-based | Hook-based |
| **Auto-Format** | PostToolUse hook | afterFileEdit hook | N/A | file.edited hook |
| **Version** | Plugin | Plugin | Reference config | 1.10.0 |
| **Version** | Plugin | Plugin | Reference config | 2.0.0-rc.1 |
**Key architectural decisions:**
- **AGENTS.md** at root is the universal cross-tool file (read by all 4 tools)

View File

@@ -80,7 +80,7 @@
## 最新动态
### v1.10.0 — 表面同步、运营工作流与 ECC 2.0 Alpha2026年4月
### v2.0.0-rc.1 — 表面同步、运营工作流与 ECC 2.0 Alpha2026年4月
- **公共表面已与真实仓库同步** —— 元数据、目录数量、插件清单以及安装文档现在都与实际开源表面保持一致。
- **运营与外向型工作流扩展** —— `brand-voice``social-graph-ranker``customer-billing-ops``google-workspace-ops` 等运营型 skill 已纳入同一系统。
@@ -160,7 +160,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
/plugin list everything-claude-code@everything-claude-code
```
**完成!** 你现在可以使用 48 个代理、183 个技能和 79 个命令。
**完成!** 你现在可以使用 48 个代理、184 个技能和 79 个命令。
### multi-* 命令需要额外配置

View File

@@ -1 +1 @@
1.10.0
2.0.0-rc.1

View File

@@ -1,6 +1,6 @@
spec_version: "0.1.0"
name: everything-claude-code
version: 1.10.0
version: 2.0.0-rc.1
description: "Initial gitagent export surface for ECC's shared skill catalog, governance, and identity. Native agents, commands, and hooks remain authoritative in the repository while manifest coverage expands."
author: affaan-m
license: MIT

View File

@@ -100,9 +100,9 @@ This stack is useful when you want:
- automation that can nudge, audit, and escalate
- a public repo that shows the system shape without exposing your private operator state
## Public Preview Scope
## Public Release Candidate Scope
ECC 2.0 preview documents the Hermes surface and ships launch collateral now.
ECC v2.0.0-rc.1 documents the Hermes surface and ships launch collateral now.
The remaining private pieces can be layered later:

View File

@@ -703,7 +703,7 @@ Suggested payload:
"skippedModules": []
},
"source": {
"repoVersion": "1.10.0",
"repoVersion": "2.0.0-rc.1",
"repoCommit": "git-sha",
"manifestVersion": 1
},

View File

@@ -0,0 +1,111 @@
# Cross-Harness Architecture
ECC is the reusable workflow layer. Harnesses are execution surfaces.
The goal is to keep the durable parts of agentic work in one repo:
- skills
- rules and instructions
- hooks where the harness supports them
- MCP configuration
- install manifests
- session and orchestration patterns
Claude Code, Codex, OpenCode, Cursor, Gemini, and future harnesses should adapt those assets at the edge instead of requiring a new workflow model for every tool.
## Portability Model
| Surface | Shared Source | Harness Adapter | Current Status |
|---------|---------------|-----------------|----------------|
| Skills | `skills/*/SKILL.md` | Claude plugin, Codex plugin, `.agents/skills`, Cursor skill copies, OpenCode plugin/config | Supported with harness-specific packaging |
| Rules and instructions | `rules/`, `AGENTS.md`, translated docs | Claude rules install, Codex `AGENTS.md`, Cursor rules, OpenCode instructions | Supported, but not identical across harnesses |
| Hooks | `hooks/hooks.json`, `scripts/hooks/` | Claude native hooks, OpenCode plugin events, Cursor hook adapter | Hook-backed in Claude/OpenCode/Cursor; instruction-backed in Codex |
| MCPs | `.mcp.json`, `mcp-configs/` | Native MCP config import per harness | Supported where the harness exposes MCP |
| Commands | `commands/`, CLI scripts | Claude slash commands, compatibility shims, CLI entrypoints | Supported, but command semantics vary |
| Sessions | `ecc2/`, session adapters, orchestration scripts | TUI/daemon, tmux/worktree orchestration, harness-specific runners | Alpha |
## What Travels Unchanged
`SKILL.md` is the most portable unit.
A good ECC skill should:
- use YAML frontmatter with `name`, `description`, and `origin`
- describe when to use the skill
- state required tools or connectors without embedding secrets
- keep examples repo-relative or generic
- avoid harness-only command assumptions unless the section is clearly labeled
The same source skill can be installed into multiple harnesses because it is mostly instructions, constraints, and workflow shape.
## What Gets Adapted
Each harness has different loading and enforcement behavior:
- Claude Code loads plugin assets and has native hook execution.
- Codex reads `AGENTS.md`, plugin metadata, skills, and MCP config, but hook parity is instruction-driven.
- OpenCode has a plugin/event system that can reuse ECC hook logic through an adapter layer.
- Cursor uses its own rule and hook layout, so ECC maintains translated surfaces under `.cursor/`.
- Gemini support is install/instruction oriented and should be treated as a compatibility surface, not as full hook parity.
Adapters should stay thin. The shared behavior belongs in `skills/`, `rules/`, `hooks/`, `scripts/`, and `mcp-configs/`.
## Hermes Boundary
Hermes is not the public ECC runtime.
Hermes is an operator shell that can consume ECC assets:
- import selected ECC skills into a Hermes skills directory
- use ECC MCP conventions for tool access
- route chat, CLI, cron, and handoff workflows through reusable ECC patterns
- distill repeated local operator work back into sanitized ECC skills
The public repo should ship reusable patterns, not local Hermes state.
Do ship:
- sanitized setup docs
- repo-relative demo prompts
- general operator skills
- examples that do not depend on private credentials
Do not ship:
- OAuth tokens or API keys
- raw `~/.hermes` exports
- personal workspace memory
- private datasets
- local-only automation packs that have not been reviewed
## Today vs Later
Supported today:
- shared skill source in `skills/`
- Claude Code plugin packaging
- Codex plugin metadata and MCP reference config
- OpenCode package/plugin surface
- Cursor-adapted rules, hooks, and skills
- `ecc2/` as an alpha Rust control plane
Still maturing:
- exact hook parity across all harnesses
- automated skill sync into Hermes
- release packaging for `ecc2/`
- cross-harness session resume semantics
- deeper memory and operator planning layers
## Rule For New Work
When adding a workflow, put the durable behavior in ECC first.
Use harness-specific files only for:
- loading the shared asset
- adapting event shapes
- mapping command names
- handling platform limits
If a workflow only works in one harness, document that boundary directly.

View File

@@ -80,7 +80,7 @@ Este repositório contém apenas o código. Os guias explicam tudo.
## O Que Há de Novo
### v1.10.0 — Sincronização de Superfície, Fluxos Operacionais e ECC 2.0 Alpha (Abr 2026)
### v2.0.0-rc.1 — Sincronização de Superfície, Fluxos Operacionais e ECC 2.0 Alpha (Abr 2026)
- **Superfície pública sincronizada com o repositório real** — metadados, contagens de catálogo, manifests de plugin e documentação de instalação agora refletem a superfície OSS que realmente é entregue.
- **Expansão dos fluxos operacionais e externos** — `brand-voice`, `social-graph-ranker`, `customer-billing-ops`, `google-workspace-ops` e skills relacionadas fortalecem a trilha operacional dentro do mesmo sistema.

View File

@@ -0,0 +1,61 @@
# Article Outline - ECC v2.0.0-rc.1
## Working Title
Turning ECC Into a Cross-Harness Operator System
## Core Argument
Most agentic work breaks down because the tools stay isolated.
The leverage comes from treating the harness, reusable workflow layer, and operator shell as one system:
- skills for repeatable work
- hooks and tests for enforcement
- MCPs for tool access
- memory and handoffs for continuity
- one operator shell that can route daily execution
## Structure
### 1. The Problem
- too many chat windows
- too many tool-specific workflows
- too much context living in personal habit instead of reusable system shape
### 2. What ECC Already Solved
- reusable skill format
- cross-harness install surfaces
- hooks and verification discipline
- security and review patterns
- operator workflow skills around content, research, and business ops
### 3. Why Hermes Is the Operator Layer
- chat, CLI, TUI, cron, and handoffs can sit above the reusable ECC layer
- business and content work can run next to engineering work
- the daily loop becomes easier to inspect and improve
### 4. What Ships in rc.1
- sanitized Hermes setup guide
- release and distribution collateral
- cross-harness architecture doc
- Hermes import guidance
- clearer 2.0 positioning in the repo
### 5. What Stays Local
- secrets and auth
- raw workspace exports
- personal datasets
- operator-specific automations that have not been sanitized
- deeper CRM, finance, and Google Workspace playbooks
### 6. Closing Point
The goal is not to copy one exact stack.
The goal is to build an operator system that turns repeated work into reusable, measurable surfaces.

View File

@@ -0,0 +1,42 @@
# Hermes x ECC Demo Prompts
## Prompt 1: ECC Builds ECC
Use the current ECC repo and the public release pack at `docs/releases/2.0.0-rc.1/`.
Do 4 things in order:
1. Inspect git status and the current repo diff, then give me a concise ECC v2.0.0-rc.1 PR or release summary that proves ECC is being used to build ECC itself.
2. Finalize one strong X thread.
3. Finalize one strong LinkedIn post.
4. Tell me the exact 3 recordings I should do next plus what Hermes can generate automatically after I record.
Keep it decisive and practical.
## Prompt 2: Turn Recording Into Assets
Assume I just recorded:
- one face-camera hook
- one screen capture of Hermes using ECC to ship ECC v2.0.0-rc.1
- one setup walkthrough of the Hermes x ECC workspace
Give me:
1. a short-form edit plan for X, LinkedIn, TikTok, and YouTube Shorts
2. a voiceover script if I want to re-record clean audio
3. the exact repo-relative filenames and folders I should use for raw footage
4. the assets Hermes can generate automatically after I drop the files in place
Keep it operational.
## Prompt 3: Public Launch Push
Using the ECC v2.0.0-rc.1 release pack, give me:
1. one release tweet
2. one follow-up tweet
3. one LinkedIn comment I can paste under the post
4. one short Telegram handoff I can send to Hermes later to keep distributing this launch across channels
Make it sound like an operator shipping real work, not a launch thread cliche.

View File

@@ -0,0 +1,41 @@
# ECC v2.0.0-rc.1 Launch Checklist
## Repo
- verify local `main` is synced to `origin/main`
- verify `docs/HERMES-SETUP.md` is present
- verify `docs/architecture/cross-harness.md` is present
- verify this release directory is committed
- keep private tokens, personal docs, and raw workspace exports out of the repo
## Release Surface
- confirm package and plugin version policy for `2.0.0-rc.1` (drafted in manifest bump prep)
- confirm whether `ecc2/Cargo.toml` moves from `0.1.0` to `2.0.0-rc.1`
- update release metadata in one dedicated release-version PR
- run the root test suite
- run `cd ecc2 && cargo test`
## Content
- publish the X thread from `x-thread.md`
- publish the LinkedIn draft from `linkedin-post.md`
- use `article-outline.md` for the longer writeup
- record one 30-60 second proof-of-work clip
## Demo Asset Suggestions
- Hermes plus ECC side by side
- release docs being generated or reviewed from the repo
- a workflow moving from brief to post to checklist
- `ecc2/` dashboard or session surface with alpha framing
## Messaging
Use language like:
- "release candidate"
- "sanitized operator stack"
- "cross-harness operating system for agentic work"
- "ECC is the reusable substrate; Hermes is the operator shell"
- "private/local integrations land after sanitization"

View File

@@ -0,0 +1,28 @@
# LinkedIn Draft - ECC v2.0.0-rc.1
ECC v2.0.0-rc.1 is live as the first release-candidate pass at the 2.0 direction.
The practical shift is simple: ECC is no longer framed as only a Claude Code plugin or config bundle.
It is becoming a cross-harness operating system for agentic work:
- reusable skills instead of one-off prompts
- hooks and tests instead of manual discipline
- MCP-backed access to docs, code, browser automation, and research
- Codex, OpenCode, Cursor, Gemini, and Claude Code surfaces that share the same core workflow layer
- Hermes as the operator shell for chat, cron, handoffs, and daily work routing
For this release-candidate surface, I kept the repo honest.
I did not publish private workspace state. I shipped the reusable layer:
- sanitized Hermes setup documentation
- release notes and launch collateral
- cross-harness architecture notes
- Hermes import guidance for turning local operator patterns into public ECC skills
The leverage is not just better prompting.
It is reducing the number of isolated surfaces, turning repeated workflows into reusable skills, and making the operating system around the agent measurable.
There is still more to harden before GA, especially around packaging, installers, and the `ecc2/` control plane. But rc.1 is enough to show the shape clearly.

View File

@@ -0,0 +1,54 @@
# ECC v2.0.0-rc.1 Release Notes
## Positioning
ECC v2.0.0-rc.1 is the first release-candidate surface for ECC as a cross-harness operating system for agentic work.
Claude Code remains a core target. Codex, OpenCode, Cursor, Gemini, and other harnesses are treated as execution surfaces that can share the same skills, rules, MCP conventions, and operator workflows. ECC is the reusable substrate; Hermes is documented as the operator shell that can sit on top of that layer.
## What Changed
- Added the sanitized Hermes setup guide to the public release story.
- Added launch collateral in-repo so the release can ship from one reviewed surface.
- Clarified the split between ECC as the reusable substrate and Hermes as the operator shell.
- Documented the cross-harness portability model for skills, hooks, MCPs, rules, and instructions.
- Added a Hermes import playbook for turning local operator patterns into publishable ECC skills.
## Why This Matters
ECC is no longer only a Claude Code plugin or config bundle.
The system now has a clearer shape:
- reusable skills instead of one-off prompts
- hooks and tests for workflow discipline
- MCP-backed access to docs, code, browser automation, and research
- cross-harness install surfaces for Claude Code, Codex, OpenCode, Cursor, and related tools
- Hermes as an optional operator shell for chat, cron, handoffs, and daily work routing
## Preview Boundaries
This is a release candidate, not the final GA claim.
What ships in this surface:
- public Hermes setup documentation
- release notes and launch collateral
- cross-harness architecture documentation
- Hermes import guidance for sanitized operator workflows
What stays local:
- secrets, OAuth tokens, and API keys
- private workspace exports
- personal datasets
- operator-specific automations that have not been sanitized
- deeper CRM, finance, and Google Workspace playbooks
## Upgrade Motion
1. Read the [Hermes setup guide](../../HERMES-SETUP.md).
2. Review the [cross-harness architecture](../../architecture/cross-harness.md).
3. Start with one workflow lane: engineering, research, content, or outreach.
4. Import only sanitized operator patterns into ECC skills.
5. Treat `ecc2/` as an alpha control plane until release packaging and installer behavior are finalized.

View File

@@ -0,0 +1,26 @@
# Telegram Handoff For Hermes
Send this to Hermes when you want it to help package the launch workflow.
```text
Use the public ECC release pack in the repo:
- docs/releases/2.0.0-rc.1/release-notes.md
- docs/releases/2.0.0-rc.1/x-thread.md
- docs/releases/2.0.0-rc.1/linkedin-post.md
- docs/releases/2.0.0-rc.1/article-outline.md
- docs/releases/2.0.0-rc.1/launch-checklist.md
- docs/HERMES-SETUP.md
- docs/architecture/cross-harness.md
Task:
1. Finalize one strong X thread for ECC v2.0.0-rc.1.
2. Finalize one strong LinkedIn post for ECC v2.0.0-rc.1.
3. Give me one 30-60 second Hermes x ECC video script and one 15-30 second variant.
4. Tell me exactly what to record now with screen capture, face camera, and voice lines.
5. Tell me what Hermes can generate automatically after I record.
6. End with a minimal checklist of the assets or logins still needed.
Be decisive. Return final drafts plus a practical recording checklist.
```

View File

@@ -0,0 +1,65 @@
# X Thread Draft - ECC v2.0.0-rc.1
1/ ECC v2.0.0-rc.1 is the first release-candidate pass at the 2.0 direction.
The repo is moving from a Claude Code config pack into a cross-harness operating system for agentic work.
2/ The important split:
ECC is the reusable substrate.
Hermes is the operator shell that can run on top.
Skills, hooks, MCP configs, rules, and workflow packs live in ECC.
3/ Claude Code is still a core target.
Codex, OpenCode, Cursor, Gemini, and other harnesses are part of the same story now.
The goal is fewer one-off harness tricks and more reusable workflow surface.
4/ The rc.1 surface ships the public pieces:
- Hermes setup guide
- release notes
- launch checklist
- X and LinkedIn drafts
- cross-harness architecture doc
- Hermes import guidance
5/ It does not ship private workspace state.
No secrets.
No OAuth tokens.
No raw local exports.
No personal datasets.
The point is to publish the reusable system shape.
6/ Why Hermes matters:
Most agent systems fail in the daily operating loop.
They can code, but they do not keep research, content, handoffs, reminders, and execution in one measurable surface.
7/ ECC gives the reusable layer.
Hermes gives the operator shell.
Together they make the work feel less like scattered chat windows and more like a system you can run.
8/ This is still a release candidate.
The public docs and reusable surfaces are ready for review.
The deeper local integrations stay local until they are sanitized.
9/ Start here:
Repo:
<https://github.com/affaan-m/everything-claude-code>
Hermes x ECC setup:
<https://github.com/affaan-m/everything-claude-code/blob/main/docs/HERMES-SETUP.md>
Release notes:
<https://github.com/affaan-m/everything-claude-code/blob/main/docs/releases/2.0.0-rc.1/release-notes.md>

View File

@@ -2,7 +2,7 @@
Bu, yazılım geliştirme için 28 özel agent, 116 skill, 59 command ve otomatik hook iş akışları sağlayan **üretime hazır bir AI kodlama eklentisidir**.
**Sürüm:** 1.10.0
**Sürüm:** 2.0.0-rc.1
## Temel İlkeler

View File

@@ -79,7 +79,7 @@ Bu repository yalnızca ham kodu içerir. Rehberler her şeyi açıklıyor.
## Yenilikler
### v1.10.0 — Surface Sync, Operatör İş Akışları ve ECC 2.0 Alpha (Nis 2026)
### v2.0.0-rc.1 — Surface Sync, Operatör İş Akışları ve ECC 2.0 Alpha (Nis 2026)
- **Public surface canlı repo ile senkronlandı** — metadata, katalog sayıları, plugin manifest'leri ve kurulum odaklı dokümanlar artık gerçek OSS yüzeyiyle eşleşiyor.
- **Operatör ve dışa dönük iş akışları büyüdü** — `brand-voice`, `social-graph-ranker`, `customer-billing-ops`, `google-workspace-ops` ve ilgili operatör skill'leri aynı sistem içinde tamamlandı.

View File

@@ -1,8 +1,8 @@
# Everything Claude Code (ECC) — 智能体指令
这是一个**生产就绪的 AI 编码插件**,提供 48 个专业代理、183 项技能、79 条命令以及自动化钩子工作流,用于软件开发。
这是一个**生产就绪的 AI 编码插件**,提供 48 个专业代理、184 项技能、79 条命令以及自动化钩子工作流,用于软件开发。
**版本:** 1.10.0
**版本:** 2.0.0-rc.1
## 核心原则
@@ -147,7 +147,7 @@
```
agents/ — 48 个专业子代理
skills/ — 183 个工作流技能和领域知识
skills/ — 184 个工作流技能和领域知识
commands/ — 79 个斜杠命令
hooks/ — 基于触发的自动化
rules/ — 始终遵循的指导方针(通用 + 每种语言)

View File

@@ -215,7 +215,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
/plugin list everything-claude-code@everything-claude-code
```
**搞定!** 你现在可以使用 48 个智能体、183 项技能和 79 个命令了。
**搞定!** 你现在可以使用 48 个智能体、184 项技能和 79 个命令了。
***
@@ -1102,7 +1102,7 @@ opencode
|---------|-------------|----------|--------|
| 智能体 | PASS: 48 个 | PASS: 12 个 | **Claude Code 领先** |
| 命令 | PASS: 79 个 | PASS: 31 个 | **Claude Code 领先** |
| 技能 | PASS: 183 项 | PASS: 37 项 | **Claude Code 领先** |
| 技能 | PASS: 184 项 | PASS: 37 项 | **Claude Code 领先** |
| 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** |
| 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** |
| MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** |
@@ -1214,7 +1214,7 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
|---------|------------|------------|-----------|----------|
| **智能体** | 48 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
| **命令** | 79 | 共享 | 基于指令 | 31 |
| **技能** | 183 | 共享 | 10 (原生格式) | 37 |
| **技能** | 184 | 共享 | 10 (原生格式) | 37 |
| **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 |
| **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 |
| **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 |
@@ -1224,7 +1224,7 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
| **上下文文件** | CLAUDE.md + AGENTS.md | AGENTS.md | AGENTS.md | AGENTS.md |
| **秘密检测** | 基于钩子 | beforeSubmitPrompt 钩子 | 基于沙箱 | 基于钩子 |
| **自动格式化** | PostToolUse 钩子 | afterFileEdit 钩子 | N/A | file.edited 钩子 |
| **版本** | 插件 | 插件 | 参考配置 | 1.10.0 |
| **版本** | 插件 | 插件 | 参考配置 | 2.0.0-rc.1 |
**关键架构决策:**

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "ecc-universal",
"version": "1.10.0",
"version": "2.0.0-rc.1",
"description": "Complete collection of battle-tested Claude Code configs — agents, skills, hooks, rules, and legacy command shims evolved over 10+ months of intensive daily use by an Anthropic hackathon winner",
"publishConfig": {
"access": "public"

View File

@@ -20,6 +20,9 @@ OPENCODE_PACKAGE_JSON=".opencode/package.json"
OPENCODE_PACKAGE_LOCK_JSON=".opencode/package-lock.json"
OPENCODE_ECC_HOOKS_PLUGIN=".opencode/plugins/ecc-hooks.ts"
README_FILE="README.md"
ROOT_ZH_CN_README_FILE="README.zh-CN.md"
TR_README_FILE="docs/tr/README.md"
PT_BR_README_FILE="docs/pt-BR/README.md"
ZH_CN_README_FILE="docs/zh-CN/README.md"
SELECTIVE_INSTALL_ARCHITECTURE_DOC="docs/SELECTIVE-INSTALL-ARCHITECTURE.md"
@@ -36,9 +39,9 @@ if [[ -z "$VERSION" ]]; then
usage
fi
# Validate VERSION is semver format (X.Y.Z)
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: VERSION must be in semver format (e.g., 1.5.0)"
# Validate VERSION is semver format (X.Y.Z or X.Y.Z-prerelease)
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "Error: VERSION must be in semver format (e.g., 1.5.0 or 2.0.0-rc.1)"
exit 1
fi
@@ -56,7 +59,7 @@ if [[ -n "$(git status --porcelain --untracked-files=all)" ]]; then
fi
# Verify versioned manifests exist
for FILE in "$ROOT_PACKAGE_JSON" "$PACKAGE_LOCK_JSON" "$ROOT_AGENTS_MD" "$TR_AGENTS_MD" "$ZH_CN_AGENTS_MD" "$AGENT_YAML" "$VERSION_FILE" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$OPENCODE_PACKAGE_LOCK_JSON" "$OPENCODE_ECC_HOOKS_PLUGIN" "$README_FILE" "$ZH_CN_README_FILE" "$SELECTIVE_INSTALL_ARCHITECTURE_DOC"; do
for FILE in "$ROOT_PACKAGE_JSON" "$PACKAGE_LOCK_JSON" "$ROOT_AGENTS_MD" "$TR_AGENTS_MD" "$ZH_CN_AGENTS_MD" "$AGENT_YAML" "$VERSION_FILE" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$OPENCODE_PACKAGE_LOCK_JSON" "$OPENCODE_ECC_HOOKS_PLUGIN" "$README_FILE" "$ROOT_ZH_CN_README_FILE" "$TR_README_FILE" "$PT_BR_README_FILE" "$ZH_CN_README_FILE" "$SELECTIVE_INSTALL_ARCHITECTURE_DOC"; do
if [[ ! -f "$FILE" ]]; then
echo "Error: $FILE not found"
exit 1
@@ -64,7 +67,7 @@ for FILE in "$ROOT_PACKAGE_JSON" "$PACKAGE_LOCK_JSON" "$ROOT_AGENTS_MD" "$TR_AGE
done
# Read current version from plugin.json
OLD_VERSION=$(grep -oE '"version": *"[^"]*"' "$PLUGIN_JSON" | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
OLD_VERSION=$(grep -oE '"version": *"[^"]*"' "$PLUGIN_JSON" | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?')
if [[ -z "$OLD_VERSION" ]]; then
echo "Error: Could not extract current version from $PLUGIN_JSON"
exit 1
@@ -123,7 +126,7 @@ update_readme_version_row() {
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
new RegExp(
`^\\| \\*\\*${escape(label)}\\*\\* \\| ${escape(firstCol)} \\| ${escape(secondCol)} \\| ${escape(thirdCol)} \\| [0-9]+\\.[0-9]+\\.[0-9]+ \\|$`,
`^\\| \\*\\*${escape(label)}\\*\\* \\| ${escape(firstCol)} \\| ${escape(secondCol)} \\| ${escape(thirdCol)} \\| [0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)? \\|$`,
"m"
),
`| **${label}** | ${firstCol} | ${secondCol} | ${thirdCol} | ${version} |`
@@ -136,6 +139,25 @@ update_readme_version_row() {
' "$file" "$VERSION" "$label" "$first_col" "$second_col" "$third_col"
}
update_latest_release_heading() {
local file="$1"
node -e '
const fs = require("fs");
const file = process.argv[1];
const version = process.argv[2];
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
/^### v[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?( .*)$/m,
`### v${version}$1`
);
if (updated === current) {
console.error(`Error: could not update latest release heading in ${file}`);
process.exit(1);
}
fs.writeFileSync(file, updated);
' "$file" "$VERSION"
}
update_selective_install_repo_version() {
local file="$1"
node -e '
@@ -144,7 +166,7 @@ update_selective_install_repo_version() {
const version = process.argv[2];
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
/("repoVersion":\s*")[0-9][0-9.]*(")/,
/("repoVersion":\s*")[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(")/,
`$1${version}$2`
);
if (updated === current) {
@@ -165,7 +187,7 @@ update_agents_version() {
const label = process.argv[3];
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
new RegExp(`^\\*\\*${label}:\\*\\* [0-9][0-9.]*$`, "m"),
new RegExp(`^\\*\\*${label}:\\*\\* [0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?$`, "m"),
`**${label}:** ${version}`
);
if (updated === current) {
@@ -183,7 +205,7 @@ update_agent_yaml_version() {
const version = process.argv[2];
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
/^version:\s*[0-9][0-9.]*$/m,
/^version:\s*[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/m,
`version: ${version}`
);
if (updated === current) {
@@ -225,7 +247,7 @@ update_opencode_hook_banner_version() {
const version = process.argv[2];
const current = fs.readFileSync(file, "utf8");
const updated = current.replace(
/(## Active Plugin: Everything Claude Code v)[0-9]+\.[0-9]+\.[0-9]+/,
/(## Active Plugin: Everything Claude Code v)[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?/,
`$1${version}`
);
if (updated === current) {
@@ -253,6 +275,10 @@ update_package_lock_version "$OPENCODE_PACKAGE_LOCK_JSON"
update_opencode_hook_banner_version
update_readme_version_row "$README_FILE" "Version" "Plugin" "Plugin" "Reference config"
update_readme_version_row "$ZH_CN_README_FILE" "版本" "插件" "插件" "参考配置"
update_latest_release_heading "$README_FILE"
update_latest_release_heading "$ROOT_ZH_CN_README_FILE"
update_latest_release_heading "$TR_README_FILE"
update_latest_release_heading "$PT_BR_README_FILE"
update_selective_install_repo_version "$SELECTIVE_INSTALL_ARCHITECTURE_DOC"
# Verify the bumped release surface is still internally consistent before
@@ -263,7 +289,7 @@ node tests/scripts/build-opencode.test.js
node tests/plugin-manifest.test.js
# Stage, commit, tag, and push
git add "$ROOT_PACKAGE_JSON" "$PACKAGE_LOCK_JSON" "$ROOT_AGENTS_MD" "$TR_AGENTS_MD" "$ZH_CN_AGENTS_MD" "$AGENT_YAML" "$VERSION_FILE" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$OPENCODE_PACKAGE_LOCK_JSON" "$OPENCODE_ECC_HOOKS_PLUGIN" "$README_FILE" "$ZH_CN_README_FILE" "$SELECTIVE_INSTALL_ARCHITECTURE_DOC"
git add "$ROOT_PACKAGE_JSON" "$PACKAGE_LOCK_JSON" "$ROOT_AGENTS_MD" "$TR_AGENTS_MD" "$ZH_CN_AGENTS_MD" "$AGENT_YAML" "$VERSION_FILE" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$OPENCODE_PACKAGE_LOCK_JSON" "$OPENCODE_ECC_HOOKS_PLUGIN" "$README_FILE" "$ROOT_ZH_CN_README_FILE" "$TR_README_FILE" "$PT_BR_README_FILE" "$ZH_CN_README_FILE" "$SELECTIVE_INSTALL_ARCHITECTURE_DOC"
git commit -m "chore: bump plugin version to $VERSION"
git tag "v$VERSION"
git push origin main "v$VERSION"

View File

@@ -0,0 +1,88 @@
---
name: hermes-imports
description: Convert local Hermes operator workflows into sanitized ECC skills and release-pack artifacts. Use when preparing a Hermes workflow for public ECC reuse without leaking private workspace state, credentials, or local-only paths.
origin: ECC
---
# Hermes Imports
Use this skill when turning a repeated Hermes workflow into something safe to ship in ECC.
Hermes is the operator shell. ECC is the reusable workflow layer. Imports should move stable patterns from Hermes into ECC without moving private state.
## When To Use
- A Hermes workflow has repeated enough times to become reusable.
- A local operator prompt should become a public ECC skill.
- A launch, content, research, or engineering workflow needs sanitized handoff docs.
- A workflow mentions local paths, credentials, personal datasets, or private account names that must be removed before publication.
## Import Rules
- Convert local paths to repo-relative paths or placeholders.
- Replace live account names with role labels such as `operator`, `default profile`, or `workspace owner`.
- Describe credential requirements by provider name only.
- Keep examples narrow and operational.
- Do not ship raw workspace exports, tokens, OAuth files, health data, CRM data, or finance data.
- If the workflow requires private state to make sense, keep it local.
## Sanitization Checklist
Before committing an imported workflow, scan for:
- absolute paths such as `/Users/...`
- `~/.hermes` paths unless the doc is explicitly explaining local setup
- API keys, tokens, cookies, OAuth files, or bearer strings
- phone numbers, private email addresses, and personal contact graphs
- client names, family names, or account names that are not already public
- revenue, health, or CRM details
- raw logs that include tool output from private systems
## Conversion Pattern
1. Identify the repeatable operator loop.
2. Strip private inputs and outputs.
3. Rewrite local paths as repo-relative examples.
4. Turn one-off instructions into a `When To Use` section and a short process.
5. Add concrete output requirements.
6. Run a secret and local-path scan before opening a PR.
## Example: Launch Handoff
Local Hermes prompt:
```text
Read my local workspace files and finalize launch copy.
```
ECC-safe version:
```text
Use the public release pack under docs/releases/<version>/.
Return one X thread, one LinkedIn post, one recording checklist, and the missing assets list.
```
## Example: Quiet-Hours Operator Job
Local Hermes job:
```text
Run my private inbox, finance, and content checks overnight.
```
ECC-safe version:
```text
Describe the scheduler policy, the quiet-hours window, the escalation rules, and the categories of checks. Do not include private data sources or credentials.
```
## Output Contract
Return:
- candidate ECC skill name
- sanitized workflow summary
- required public inputs
- private inputs removed
- remaining risks
- files that should be created or updated

View File

@@ -0,0 +1,120 @@
'use strict';
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const repoRoot = path.resolve(__dirname, '..', '..');
const releaseDir = path.join(repoRoot, 'docs', 'releases', '2.0.0-rc.1');
let passed = 0;
let failed = 0;
function test(name, fn) {
try {
fn();
console.log(`${name}`);
passed++;
} catch (error) {
console.log(`${name}`);
console.log(` Error: ${error.message}`);
failed++;
}
}
function read(relativePath) {
return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
}
function walkMarkdown(rootPath) {
const files = [];
for (const entry of fs.readdirSync(rootPath, { withFileTypes: true })) {
const nextPath = path.join(rootPath, entry.name);
if (entry.isDirectory()) {
files.push(...walkMarkdown(nextPath));
} else if (entry.isFile() && entry.name.endsWith('.md')) {
files.push(nextPath);
}
}
return files;
}
console.log('\n=== Testing ECC 2.0 release surface ===\n');
const expectedReleaseFiles = [
'release-notes.md',
'x-thread.md',
'linkedin-post.md',
'article-outline.md',
'launch-checklist.md',
'telegram-handoff.md',
'demo-prompts.md',
];
test('release candidate directory includes the public launch pack', () => {
for (const fileName of expectedReleaseFiles) {
assert.ok(fs.existsSync(path.join(releaseDir, fileName)), `Missing ${fileName}`);
}
});
test('README links to Hermes setup and rc.1 release notes', () => {
const readme = read('README.md');
assert.ok(readme.includes('docs/HERMES-SETUP.md'), 'README must link to Hermes setup');
assert.ok(readme.includes('docs/releases/2.0.0-rc.1/release-notes.md'), 'README must link to rc.1 release notes');
});
test('cross-harness architecture doc exists and names core harnesses', () => {
const source = read('docs/architecture/cross-harness.md');
for (const harness of ['Claude Code', 'Codex', 'OpenCode', 'Cursor', 'Gemini', 'Hermes']) {
assert.ok(source.includes(harness), `Expected cross-harness doc to mention ${harness}`);
}
});
test('Hermes import skill exists and declares sanitization rules', () => {
const source = read('skills/hermes-imports/SKILL.md');
assert.ok(source.includes('name: hermes-imports'));
assert.ok(source.includes('Sanitization Checklist'));
assert.ok(source.includes('Do not ship raw workspace exports'));
});
test('release docs do not contain private local workspace paths', () => {
const offenders = [];
for (const filePath of walkMarkdown(releaseDir)) {
const source = fs.readFileSync(filePath, 'utf8');
if (source.includes('/Users/') || source.includes('/.hermes/')) {
offenders.push(path.relative(repoRoot, filePath));
}
}
assert.deepStrictEqual(offenders, []);
});
test('release docs do not contain unresolved public-link placeholders', () => {
const offenders = [];
for (const filePath of walkMarkdown(releaseDir)) {
const source = fs.readFileSync(filePath, 'utf8');
if (source.includes('<repo-link>')) {
offenders.push(path.relative(repoRoot, filePath));
}
}
assert.deepStrictEqual(offenders, []);
});
test('Hermes setup uses release-candidate wording for the rc.1 surface', () => {
const source = read('docs/HERMES-SETUP.md');
assert.ok(source.includes('Public Release Candidate Scope'));
assert.ok(source.includes('ECC v2.0.0-rc.1 documents the Hermes surface'));
assert.ok(!source.includes('Public Preview Scope'));
});
test('release docs preserve the ECC/Hermes boundary', () => {
const releaseNotes = read('docs/releases/2.0.0-rc.1/release-notes.md');
assert.ok(releaseNotes.includes('ECC is the reusable substrate'));
assert.ok(releaseNotes.includes('Hermes as the operator shell'));
});
if (failed > 0) {
console.log(`\nFailed: ${failed}`);
process.exit(1);
}
console.log(`\nPassed: ${passed}`);

View File

@@ -35,6 +35,7 @@ const selectiveInstallArchitecturePath = path.join(repoRoot, 'docs', 'SELECTIVE-
const opencodePackageJsonPath = path.join(repoRoot, '.opencode', 'package.json');
const opencodePackageLockPath = path.join(repoRoot, '.opencode', 'package-lock.json');
const opencodeHooksPluginPath = path.join(repoRoot, '.opencode', 'plugins', 'ecc-hooks.ts');
const semverPattern = '[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?';
let passed = 0;
let failed = 0;
@@ -118,28 +119,28 @@ test('package-lock.json root version matches package.json', () => {
test('AGENTS.md version line matches package.json', () => {
const agentsSource = fs.readFileSync(rootAgentsPath, 'utf8');
const match = agentsSource.match(/^\*\*Version:\*\* ([0-9]+\.[0-9]+\.[0-9]+)$/m);
const match = agentsSource.match(new RegExp(`^\\*\\*Version:\\*\\* (${semverPattern})$`, 'm'));
assert.ok(match, 'Expected AGENTS.md to declare a top-level version line');
assert.strictEqual(match[1], expectedVersion);
});
test('docs/tr/AGENTS.md version line matches package.json', () => {
const agentsSource = fs.readFileSync(trAgentsPath, 'utf8');
const match = agentsSource.match(/^\*\*Sürüm:\*\* ([0-9]+\.[0-9]+\.[0-9]+)$/m);
const match = agentsSource.match(new RegExp(`^\\*\\*Sürüm:\\*\\* (${semverPattern})$`, 'm'));
assert.ok(match, 'Expected docs/tr/AGENTS.md to declare a top-level version line');
assert.strictEqual(match[1], expectedVersion);
});
test('docs/zh-CN/AGENTS.md version line matches package.json', () => {
const agentsSource = fs.readFileSync(zhCnAgentsPath, 'utf8');
const match = agentsSource.match(/^\*\*版本:\*\* ([0-9]+\.[0-9]+\.[0-9]+)$/m);
const match = agentsSource.match(new RegExp(`^\\*\\*版本:\\*\\* (${semverPattern})$`, 'm'));
assert.ok(match, 'Expected docs/zh-CN/AGENTS.md to declare a top-level version line');
assert.strictEqual(match[1], expectedVersion);
});
test('agent.yaml version matches package.json', () => {
const agentYamlSource = fs.readFileSync(agentYamlPath, 'utf8');
const match = agentYamlSource.match(/^version:\s*([0-9]+\.[0-9]+\.[0-9]+)$/m);
const match = agentYamlSource.match(new RegExp(`^version:\\s*(${semverPattern})$`, 'm'));
assert.ok(match, 'Expected agent.yaml to declare a top-level version field');
assert.strictEqual(match[1], expectedVersion);
});
@@ -152,14 +153,14 @@ test('VERSION file matches package.json', () => {
test('docs/SELECTIVE-INSTALL-ARCHITECTURE.md repoVersion example matches package.json', () => {
const source = fs.readFileSync(selectiveInstallArchitecturePath, 'utf8');
const match = source.match(/"repoVersion":\s*"([0-9]+\.[0-9]+\.[0-9]+)"/);
const match = source.match(new RegExp(`"repoVersion":\\s*"(${semverPattern})"`));
assert.ok(match, 'Expected docs/SELECTIVE-INSTALL-ARCHITECTURE.md to declare a repoVersion example');
assert.strictEqual(match[1], expectedVersion);
});
test('.opencode/plugins/ecc-hooks.ts active plugin banner matches package.json', () => {
const source = fs.readFileSync(opencodeHooksPluginPath, 'utf8');
const match = source.match(/## Active Plugin: Everything Claude Code v([0-9]+\.[0-9]+\.[0-9]+)/);
const match = source.match(new RegExp(`## Active Plugin: Everything Claude Code v(${semverPattern})`));
assert.ok(match, 'Expected .opencode/plugins/ecc-hooks.ts to declare an active plugin banner');
assert.strictEqual(match[1], expectedVersion);
});
@@ -445,7 +446,7 @@ test('.opencode/package-lock.json root version matches package.json', () => {
test('README version row matches package.json', () => {
const readme = fs.readFileSync(path.join(repoRoot, 'README.md'), 'utf8');
const match = readme.match(/^\| \*\*Version\*\* \| Plugin \| Plugin \| Reference config \| ([0-9][0-9.]*) \|$/m);
const match = readme.match(new RegExp(`^\\| \\*\\*Version\\*\\* \\| Plugin \\| Plugin \\| Reference config \\| (${semverPattern}) \\|$`, 'm'));
assert.ok(match, 'Expected README version summary row');
assert.strictEqual(match[1], expectedVersion);
});
@@ -497,7 +498,7 @@ test('user-facing docs do not use the legacy non-URL marketplace add form', () =
test('docs/zh-CN/README.md version row matches package.json', () => {
const readme = fs.readFileSync(zhCnReadmePath, 'utf8');
const match = readme.match(/^\| \*\*版本\*\* \| 插件 \| 插件 \| 参考配置 \| ([0-9][0-9.]*) \|$/m);
const match = readme.match(new RegExp(`^\\| \\*\\*版本\\*\\* \\| 插件 \\| 插件 \\| 参考配置 \\| (${semverPattern}) \\|$`, 'm'));
assert.ok(match, 'Expected docs/zh-CN/README.md version summary row');
assert.strictEqual(match[1], expectedVersion);
});

View File

@@ -50,6 +50,18 @@ for (const workflow of [
assert.match(content, /npm publish --access public --provenance/);
assert.match(content, /NODE_AUTH_TOKEN:\s*\$\{\{\s*secrets\.NPM_TOKEN\s*\}\}/);
});
test(`${workflow} creates the GitHub Release before publishing to npm`, () => {
const releaseIndex = content.indexOf('name: Create GitHub Release');
const publishIndex = content.indexOf('name: Publish npm package');
assert.ok(releaseIndex >= 0, `${workflow} should create a GitHub Release`);
assert.ok(publishIndex >= 0, `${workflow} should publish the npm package`);
assert.ok(
releaseIndex < publishIndex,
`${workflow} should not publish to npm until GitHub Release creation has succeeded`
);
});
}
if (failed > 0) {

View File

@@ -8,6 +8,19 @@ const path = require('path');
const scriptPath = path.join(__dirname, '..', '..', 'scripts', 'release.sh');
const source = fs.readFileSync(scriptPath, 'utf8');
const releaseWorkflowPath = path.join(__dirname, '..', '..', '.github', 'workflows', 'release.yml');
const reusableReleaseWorkflowPath = path.join(
__dirname,
'..',
'..',
'.github',
'workflows',
'reusable-release.yml'
);
const ciWorkflowPath = path.join(__dirname, '..', '..', '.github', 'workflows', 'ci.yml');
const releaseWorkflowSource = fs.readFileSync(releaseWorkflowPath, 'utf8');
const reusableReleaseWorkflowSource = fs.readFileSync(reusableReleaseWorkflowPath, 'utf8');
const ciWorkflowSource = fs.readFileSync(ciWorkflowPath, 'utf8');
function test(name, fn) {
try {
@@ -64,6 +77,71 @@ function runTests() {
);
})) passed++; else failed++;
if (test('release script supports prerelease semver and release heading sync', () => {
assert.ok(
source.includes('2.0.0-rc.1'),
'release.sh should document an accepted prerelease semver example'
);
assert.ok(
source.includes('(-[0-9A-Za-z.-]+)?'),
'release.sh should allow prerelease semver suffixes'
);
assert.ok(
source.includes('update_latest_release_heading "$ROOT_ZH_CN_README_FILE"'),
'release.sh should update localized latest-release headings that plugin-manifest.test.js verifies'
);
})) passed++; else failed++;
if (test('release workflows mark prerelease tags as GitHub prereleases', () => {
assert.ok(
releaseWorkflowSource.includes('prerelease: ${{ contains(github.ref_name, \'-\') }}'),
'release.yml should mark hyphenated tag pushes as GitHub prereleases'
);
assert.ok(
releaseWorkflowSource.includes('make_latest: ${{ contains(github.ref_name, \'-\') && \'false\' || \'true\' }}'),
'release.yml should avoid making hyphenated prereleases the latest GitHub release'
);
assert.ok(
reusableReleaseWorkflowSource.includes('prerelease: ${{ contains(inputs.tag, \'-\') }}'),
'reusable-release.yml should mark hyphenated manual tags as GitHub prereleases'
);
assert.ok(
reusableReleaseWorkflowSource.includes('make_latest: ${{ contains(inputs.tag, \'-\') && \'false\' || \'true\' }}'),
'reusable-release.yml should avoid making hyphenated prereleases the latest GitHub release'
);
})) passed++; else failed++;
if (test('reusable release checks out the requested tag before validating and publishing', () => {
const checkoutIndex = reusableReleaseWorkflowSource.indexOf('uses: actions/checkout@');
const refIndex = reusableReleaseWorkflowSource.indexOf('ref: ${{ inputs.tag }}');
const validateIndex = reusableReleaseWorkflowSource.indexOf('name: Validate version tag');
assert.ok(checkoutIndex >= 0, 'reusable-release.yml should check out repository content');
assert.ok(refIndex >= 0, 'reusable-release.yml checkout should use inputs.tag as ref');
assert.ok(validateIndex >= 0, 'reusable-release.yml should validate requested tag');
assert.ok(
checkoutIndex < refIndex && refIndex < validateIndex,
'reusable release should check out inputs.tag before tag validation and publish steps'
);
})) passed++; else failed++;
if (test('CI runs for release branches and version tags before release workflows execute', () => {
const pushBlockMatch = ciWorkflowSource.match(/on:\n\s+push:\n([\s\S]*?)\n\s+pull_request:/);
const pushBlock = pushBlockMatch ? pushBlockMatch[1] : '';
assert.ok(pushBlock, 'ci.yml should define a push trigger block');
assert.match(
pushBlock,
/branches:\s*\[[^\]]*main[^\]]*['"]release\/\*\*['"][^\]]*\]/,
'ci.yml push branches should include release/**'
);
assert.match(
pushBlock,
/tags:\s*\[[^\]]*['"]v\*['"][^\]]*\]/,
'ci.yml push tags should include v*'
);
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}