From 29edd57708bee26f16363c16a28fec7f6b09f53f Mon Sep 17 00:00:00 2001 From: ECC Test Date: Tue, 9 Jun 2026 21:20:33 -0400 Subject: [PATCH] =?UTF-8?q?release:=202.0.0=20=E2=80=94=20the=20agent=20ha?= =?UTF-8?q?rness=20operating=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Graduate 2.0.0-rc.1 to stable. Bump version across package, plugin, marketplace, OpenCode, agent metadata, VERSION, and all localized docs. Add 2.0.0 release notes + README sections (en/zh/pt-BR/tr), CHANGELOG entry, and the ECC community Discord bot (dependency-free gateway client + guild command registrar). Update copilot-support and release-surface tests for the sponsored-review migration and the 2.0.0 surface. --- .agents/plugins/marketplace.json | 2 +- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- .opencode/package-lock.json | 4 +- .opencode/package.json | 2 +- .opencode/plugins/ecc-hooks.ts | 2 +- AGENTS.md | 2 +- CHANGELOG.md | 19 ++ README.md | 21 ++- README.zh-CN.md | 4 + VERSION | 2 +- agent.yaml | 2 +- docs/SELECTIVE-INSTALL-ARCHITECTURE.md | 2 +- docs/pt-BR/README.md | 4 + docs/releases/2.0.0/release-notes.md | 43 +++++ docs/tr/AGENTS.md | 2 +- docs/tr/README.md | 4 + docs/zh-CN/AGENTS.md | 2 +- docs/zh-CN/README.md | 6 +- package-lock.json | 4 +- package.json | 2 +- scripts/discord/ecc-bot.mjs | 222 ++++++++++++++++++++++++ scripts/discord/register-commands.mjs | 38 ++++ tests/docs/copilot-support.test.js | 22 +-- tests/docs/ecc2-release-surface.test.js | 119 +++---------- 26 files changed, 402 insertions(+), 134 deletions(-) create mode 100644 docs/releases/2.0.0/release-notes.md create mode 100644 scripts/discord/ecc-bot.mjs create mode 100644 scripts/discord/register-commands.mjs diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 7c1d7e30..6168f2e4 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -6,7 +6,7 @@ "plugins": [ { "name": "ecc", - "version": "2.0.0-rc.1", + "version": "2.0.0", "source": { "source": "local", "path": "./" diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a6210b24..34cd150f 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,7 +12,7 @@ "name": "ecc", "source": "./", "description": "Harness-native ECC operator layer - 64 agents, 261 skills, 84 legacy command shims, reusable hooks, rules, selective install profiles, and production-ready workflows for Claude Code, Codex, OpenCode, Cursor, and related agent harnesses", - "version": "2.0.0-rc.1", + "version": "2.0.0", "author": { "name": "Affaan Mustafa", "email": "me@affaanmustafa.com" diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index be1a95cf..1e973dad 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ecc", - "version": "2.0.0-rc.1", + "version": "2.0.0", "description": "Harness-native ECC plugin for engineering teams - 64 agents, 261 skills, 84 legacy command shims, reusable hooks, rules, MCP conventions, and operator workflows for Claude Code plus adjacent agent harnesses", "author": { "name": "Affaan Mustafa", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 508365d6..f8373161 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ecc", - "version": "2.0.0-rc.1", + "version": "2.0.0", "description": "Harness-native ECC workflows for Codex: shared skills, production-ready MCP configs, and selective-install-aligned conventions for TDD, security scanning, code review, and autonomous development.", "author": { "name": "Affaan Mustafa", diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json index ef323f1d..2cc653a7 100644 --- a/.opencode/package-lock.json +++ b/.opencode/package-lock.json @@ -1,12 +1,12 @@ { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "license": "MIT", "devDependencies": { "@opencode-ai/plugin": "^1.4.3", diff --git a/.opencode/package.json b/.opencode/package.json index f343e56d..0cdcfb96 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "description": "ECC plugin for OpenCode - agents, commands, hooks, and skills", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/.opencode/plugins/ecc-hooks.ts b/.opencode/plugins/ecc-hooks.ts index 606bcb7c..05792ce9 100644 --- a/.opencode/plugins/ecc-hooks.ts +++ b/.opencode/plugins/ecc-hooks.ts @@ -453,7 +453,7 @@ export const ECCHooksPlugin: ECCHooksPluginFn = async ({ const contextBlock = [ "# ECC Context (preserve across compaction)", "", - "## Active Plugin: ECC v2.0.0-rc.1", + "## Active Plugin: ECC v2.0.0", "- 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)", diff --git a/AGENTS.md b/AGENTS.md index f791d13a..f941a0e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ This is a **production-ready AI coding plugin** providing 64 specialized agents, 261 skills, 84 commands, and automated hook workflows for software development. -**Version:** 2.0.0-rc.1 +**Version:** 2.0.0 ## Core Principles diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d796711..61c9f446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 2.0.0 - 2026-06-09 + +### Added + +- Discord community launch: server + GitHub PR/issue/release feed, `release-announce.yml` workflow (announce + pin + Discussions cross-post), and a dependency-free community bot (`scripts/discord/ecc-bot.mjs`) with `/ecc`, `/help`, `/skill`, `/docs`, `/release`. +- `orch-*` orchestrator skill family and dynamic workflow team orchestration. +- `kubernetes-patterns` skill, worktree-lifecycle service, MCP inventory (`ecc.mcp.v1`), codex-worktree and opencode session adapters. + +### Fixed + +- Plugin hooks silently no-oped on Node 21+ (`require.main` undefined under `node -e`). +- Windows reliability: `CLAUDE_PLUGIN_ROOT` normalization, stdin prompt passing, symlink/chmod test guards. +- Session-end `$`-sequence corruption, project-detect boundary matching, install manifest gaps, corrupted legacy shim truncation. + +### Changed + +- Version graduated to 2.0.0 stable across package, plugin, marketplace, OpenCode, and agent metadata. +- Smaller default OpenCode install surface; `rules/zh` removed from the always-loaded default install. + ## 2.0.0-rc.1 - 2026-04-28 ### Highlights diff --git a/README.md b/README.md index fda50f58..f7de06b1 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Not just configs. A complete system: skills, instincts, memory optimization, con Works across **Codex**, **Claude Code**, **Cursor**, **OpenCode**, **Gemini**, **Zed**, **GitHub Copilot**, 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). +ECC v2.0.0 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 [2.0.0 release notes](docs/releases/2.0.0/release-notes.md) and [cross-harness architecture](docs/architecture/cross-harness.md). --- @@ -127,6 +127,10 @@ This repo is the raw code only. The guides explain everything. ## What's New +### v2.0.0 — The Agent Harness Operating System (Jun 2026) + +Stable graduation of the 2.0 line: 261 skills, the control-pane substrate (session adapters + MCP inventory), the worktree-lifecycle service, the `orch-*` orchestrator family, and the launch of the [ECC Discord community](https://discord.gg/36yGMHGFbR). Full notes: [docs/releases/2.0.0/release-notes.md](docs/releases/2.0.0/release-notes.md). + ### 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. @@ -1578,10 +1582,9 @@ ECC provides **GitHub Copilot support** for VS Code via Copilot Chat's native in | Component | File | Purpose | |-----------|------|---------| | Core instructions | `.github/copilot-instructions.md` | Always-loaded rules: coding style, security, testing, git workflow | -| VS Code settings | `.vscode/settings.json` | Per-task instruction files for code gen, test gen, review, and commit messages | +| VS Code settings | `.vscode/settings.json` | Per-task instruction files for code gen, test gen, and commit messages | | Plan prompt | `.github/prompts/plan.prompt.md` | Phased implementation planning | | TDD prompt | `.github/prompts/tdd.prompt.md` | Red-Green-Improve cycle | -| Code review prompt | `.github/prompts/code-review.prompt.md` | Quality and security review | | Security review prompt | `.github/prompts/security-review.prompt.md` | Deep OWASP-aligned security analysis | | Build fix prompt | `.github/prompts/build-fix.prompt.md` | Systematic build and CI error resolution | | Refactor prompt | `.github/prompts/refactor.prompt.md` | Dead code cleanup and simplification | @@ -1594,16 +1597,16 @@ The committed `.vscode/settings.json` enables `chat.promptFiles` so VS Code can To use the workflow prompts in Copilot Chat: 1. Open the Copilot Chat panel in VS Code. 2. Click the **paperclip / attach** icon and select **Prompt...**, or type `/` and choose a prompt. -3. Select the prompt (e.g. `plan`, `tdd`, `code-review`). +3. Select the prompt (e.g. `plan`, `tdd`, `security-review`). ### How It Works GitHub Copilot in VS Code reads two types of files automatically: - **`.github/copilot-instructions.md`** — repository-level instructions, always injected into every Copilot Chat request. Contains ECC's core coding standards, security checklist, testing requirements, and git workflow. -- **`.github/prompts/*.prompt.md`** — reusable prompt files users invoke on demand. Each prompt walks Copilot through a specific ECC workflow (plan → TDD → review → ship). +- **`.github/prompts/*.prompt.md`** — reusable prompt files users invoke on demand. Each prompt walks Copilot through a specific ECC workflow such as planning, TDD, security review, build-fix, or refactor. -The **`.vscode/settings.json`** adds per-task instruction overlays so Copilot receives the right context depending on whether you are generating code, writing tests, reviewing a selection, or drafting a commit message. +The **`.vscode/settings.json`** adds per-task instruction overlays so Copilot receives the right context for code generation, test generation, and commit message drafting. ### Feature Coverage @@ -1613,7 +1616,7 @@ The **`.vscode/settings.json`** adds per-task instruction overlays so Copilot re | Security checklist | Always-on + `security-review` prompt | | Testing / TDD | Always-on + `tdd` prompt | | Implementation planning | `plan` prompt | -| Code review | `code-review` prompt | +| Code review | External PR review via CodeRabbit + Greptile | | Build error resolution | `build-fix` prompt | | Refactoring | `refactor` prompt | | Commit message format | Per-task instruction in `settings.json` | @@ -1633,7 +1636,7 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e | Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode | GitHub Copilot | |---------|-----------------------|------------|-----------|----------|----------------| | **Agents** | 64 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 | N/A | -| **Commands** | 84 | Shared | Instruction-based | 35 | 6 prompts | +| **Commands** | 84 | Shared | Instruction-based | 35 | 5 prompts | | **Skills** | 261 | Shared | 10 (native format) | 37 | Via instructions | | **Hook Events** | 8 types | 15 types | None yet | 11 types | None | | **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks | N/A | @@ -1644,7 +1647,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 | copilot-instructions.md | | **Secret Detection** | Hook-based | beforeSubmitPrompt hook | Sandbox-based | Hook-based | Instruction-based | | **Auto-Format** | PostToolUse hook | afterFileEdit hook | N/A | file.edited hook | N/A | -| **Version** | Plugin | Plugin | Reference config | 2.0.0-rc.1 | Instruction layer | +| **Version** | Plugin | Plugin | Reference config | 2.0.0 | Instruction layer | **Key architectural decisions:** - **AGENTS.md** at root is the universal cross-tool file (read by Claude Code, Cursor, Codex, and OpenCode — GitHub Copilot uses `.github/copilot-instructions.md` instead) diff --git a/README.zh-CN.md b/README.zh-CN.md index d532eb9b..9bde9e40 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -80,6 +80,10 @@ ## 最新动态 +### v2.0.0 — 智能体 Harness 操作系统(2026年6月) + +2.0 主线稳定版:261 个技能、control-pane 基底(会话适配器 + MCP 清单)、worktree 生命周期服务,以及 [ECC Discord 社区](https://discord.gg/36yGMHGFbR)。 + ### v2.0.0-rc.1 — 表面同步、运营工作流与 ECC 2.0 Alpha(2026年4月) - **公共表面已与真实仓库同步** —— 元数据、目录数量、插件清单以及安装文档现在都与实际开源表面保持一致。 diff --git a/VERSION b/VERSION index 97041a78..227cea21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.0-rc.1 +2.0.0 diff --git a/agent.yaml b/agent.yaml index 4759b9c4..ed7122e3 100644 --- a/agent.yaml +++ b/agent.yaml @@ -1,6 +1,6 @@ spec_version: "0.1.0" name: ecc -version: 2.0.0-rc.1 +version: 2.0.0 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 diff --git a/docs/SELECTIVE-INSTALL-ARCHITECTURE.md b/docs/SELECTIVE-INSTALL-ARCHITECTURE.md index c412cb25..25e5bff9 100644 --- a/docs/SELECTIVE-INSTALL-ARCHITECTURE.md +++ b/docs/SELECTIVE-INSTALL-ARCHITECTURE.md @@ -703,7 +703,7 @@ Suggested payload: "skippedModules": [] }, "source": { - "repoVersion": "2.0.0-rc.1", + "repoVersion": "2.0.0", "repoCommit": "git-sha", "manifestVersion": 1 }, diff --git a/docs/pt-BR/README.md b/docs/pt-BR/README.md index 312ddac2..cccfb79c 100644 --- a/docs/pt-BR/README.md +++ b/docs/pt-BR/README.md @@ -80,6 +80,10 @@ Este repositório contém apenas o código. Os guias explicam tudo. ## O Que Há de Novo +### v2.0.0 — O Sistema Operacional do Harness de Agentes (Jun 2026) + +Graduação estável da linha 2.0: 261 skills, substrato de control-pane, inventário MCP, serviço de ciclo de vida de worktrees e a comunidade no [Discord](https://discord.gg/36yGMHGFbR). + ### 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. diff --git a/docs/releases/2.0.0/release-notes.md b/docs/releases/2.0.0/release-notes.md new file mode 100644 index 00000000..e950b329 --- /dev/null +++ b/docs/releases/2.0.0/release-notes.md @@ -0,0 +1,43 @@ +# ECC 2.0.0 — The Agent Harness Operating System + +ECC 2.0.0 is the stable graduation of the 2.0 line: ECC as a cross-harness operating system for agentic work. Claude Code stays first-class; Codex, OpenCode, Cursor, Gemini, Zed, and terminal-only workflows share the same skills, rules, hooks, MCP conventions, release gates, and operator workflows. + +## Highlights + +- 261 public skills across coding, research, security, media, enterprise ops, and agent workflows. +- ECC 2.0 control-pane substrate: harness-neutral session adapters (`ecc.session.v1`) covering Claude Code, Codex, OpenCode, and dmux. +- MCP inventory (`ecc.mcp.v1`): one normalized view of MCP server configs across harnesses, with fragmentation and drift detection and secret redaction. +- Worktree-lifecycle service: deterministic conflict prediction and safe garbage collection for parallel agent worktrees. +- `orch-*` orchestrator skill family plus dynamic workflow team orchestration. +- Rollout-derived optimization pack: `parallel-execution-optimizer`, `benchmark-optimization-loop`, `data-throughput-accelerator`, `latency-critical-systems`, `recursive-decision-ledger`. + +## Hardening since rc.1 + +Roughly thirty PRs of fixes landed between rc.1 and stable. The ones worth knowing about: + +- **Plugin hooks were silently no-ops on Node 21+** (#2184). The hook runner depended on `require.main` under `node -e`, which newer Node leaves undefined — every plugin hook exited cleanly without running. If you are on Node 21 or newer, update now. +- Windows reliability: `CLAUDE_PLUGIN_ROOT` path normalization (#2139), prompts passed via stdin so the shell does not mangle them (#2174), broken-symlink and chmod test guards (#2171, #2176). +- Security: curl credentials kept out of argv (#2175), gateguard now gates force/path checkouts as destructive (#2158) with env knobs for routine-command gating (#2161), advisory intake hardening. +- Correctness: session-end summaries no longer corrupt `$`-sequences in user messages (#2180), project detection matches package keys on boundaries so `preact` no longer reads as `react` (#2181), install manifest packaging gaps closed (#2172), corrupted legacy command shims truncated safely (#2167). +- Slimmer defaults: smaller OpenCode install surface with gated hooks-runtime (#2140), `rules/zh` out of the always-loaded default install (#2170). +- New surfaces: `kubernetes-patterns` skill (#2178), worktree-lifecycle service (#2164), MCP inventory (#2146), codex-worktree and opencode session adapters (#2145), the `orch-*` family (#2153). + +## Community launch + +The ECC Discord is live: + +- Release news lands in #announcements, auto-posted and pinned by the release workflow shipped in this very release (#2201). +- A live PR and issue feed runs in #pr-and-issues. +- The ECC bot answers `/skill`, `/docs`, and `/release` lookups in-server. +- #feedback and #feature-requests are read directly by the maintainer and shape the roadmap. + +## Install or upgrade + +``` +/plugin marketplace add https://github.com/affaan-m/ECC +/plugin install ecc +``` + +Existing installs: `/plugin update ecc` + +Full changelog: diff --git a/docs/tr/AGENTS.md b/docs/tr/AGENTS.md index c133c113..69403dcf 100644 --- a/docs/tr/AGENTS.md +++ b/docs/tr/AGENTS.md @@ -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:** 2.0.0-rc.1 +**Sürüm:** 2.0.0 ## Temel İlkeler diff --git a/docs/tr/README.md b/docs/tr/README.md index 96968906..e5543071 100644 --- a/docs/tr/README.md +++ b/docs/tr/README.md @@ -79,6 +79,10 @@ Bu repository yalnızca ham kodu içerir. Rehberler her şeyi açıklıyor. ## Yenilikler +### v2.0.0 — Ajan Harness İşletim Sistemi (Haz 2026) + +2.0 hattının kararlı sürümü: 261 skill, control-pane altyapısı, MCP envanteri, worktree yaşam döngüsü servisi ve [Discord topluluğu](https://discord.gg/36yGMHGFbR). + ### 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. diff --git a/docs/zh-CN/AGENTS.md b/docs/zh-CN/AGENTS.md index 54f7f93b..967cd5a5 100644 --- a/docs/zh-CN/AGENTS.md +++ b/docs/zh-CN/AGENTS.md @@ -2,7 +2,7 @@ 这是一个**生产就绪的 AI 编码插件**,提供 64 个专业代理、261 项技能、84 条命令以及自动化钩子工作流,用于软件开发。 -**版本:** 2.0.0-rc.1 +**版本:** 2.0.0 ## 核心原则 diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md index a0a3fcfa..6ca77284 100644 --- a/docs/zh-CN/README.md +++ b/docs/zh-CN/README.md @@ -81,6 +81,10 @@ ## 最新动态 +### v2.0.0 — 智能体 Harness 操作系统(2026年6月) + +2.0 主线稳定版:261 个技能、control-pane 基底(会话适配器 + MCP 清单)、worktree 生命周期服务,以及 [ECC Discord 社区](https://discord.gg/36yGMHGFbR)。 + ### v2.0.0-rc.1 — 表面同步、运营工作流与 ECC 2.0 Alpha(2026年4月) * **公共表面已与真实仓库同步** —— 元数据、目录数量、插件清单以及安装文档现在都与实际开源表面保持一致。 @@ -1256,7 +1260,7 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以 | **上下文文件** | CLAUDE.md + AGENTS.md | AGENTS.md | AGENTS.md | AGENTS.md | | **秘密检测** | 基于钩子 | beforeSubmitPrompt 钩子 | 基于沙箱 | 基于钩子 | | **自动格式化** | PostToolUse 钩子 | afterFileEdit 钩子 | N/A | file.edited 钩子 | -| **版本** | 插件 | 插件 | 参考配置 | 2.0.0-rc.1 | +| **版本** | 插件 | 插件 | 参考配置 | 2.0.0 | **关键架构决策:** diff --git a/package-lock.json b/package-lock.json index 315102fb..423f95fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3d4bc021..3c15ca12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ecc-universal", - "version": "2.0.0-rc.1", + "version": "2.0.0", "description": "Harness-native agent operating system for Codex, OpenCode, Cursor, Gemini, Claude Code, and terminal workflows - skills, hooks, rules, MCP conventions, and operator control-plane patterns", "publishConfig": { "access": "public" diff --git a/scripts/discord/ecc-bot.mjs b/scripts/discord/ecc-bot.mjs new file mode 100644 index 00000000..7699d9ed --- /dev/null +++ b/scripts/discord/ecc-bot.mjs @@ -0,0 +1,222 @@ +#!/usr/bin/env node +// ECC community Discord bot — dependency-free (Node 22+ native WebSocket). +// Slash commands: /ecc /help /skill /docs /release +// +// Env: DISCORD_BOT_TOKEN (required), DISCORD_APP_ID (required), +// ECC_REPO (path to local clone, default ~/GitHub/ECC/everything-claude-code), +// DISCORD_INVITE (optional, shown in /ecc) +// +// Crash-only design: any gateway close, error, or missed heartbeat ack exits +// the process; the launchd/pm2 supervisor restarts it with a fresh identify. +// Register commands first: node scripts/discord/register-commands.mjs +'use strict'; + +import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs'; +import { join } from 'node:path'; +import { homedir } from 'node:os'; + +const TOKEN = process.env.DISCORD_BOT_TOKEN; +const APP_ID = process.env.DISCORD_APP_ID; +if (!TOKEN || !APP_ID) { + console.error('missing DISCORD_BOT_TOKEN / DISCORD_APP_ID'); + process.exit(1); +} +const REPO = process.env.ECC_REPO || join(homedir(), 'GitHub/ECC/everything-claude-code'); +const REPO_URL = 'https://github.com/affaan-m/ECC'; +const INVITE = process.env.DISCORD_INVITE || ''; +const API = 'https://discord.com/api/v10'; + +const log = (...a) => console.log(new Date().toISOString(), ...a); + +// ---------- skill + docs lookup (local clone as the data source) ---------- + +function parseFrontmatter(text) { + const m = text.match(/^---\n([\s\S]*?)\n---/); + if (!m) return {}; + const out = {}; + for (const line of m[1].split('\n')) { + const kv = line.match(/^(\w[\w-]*):\s*(.+)$/); + if (kv) out[kv[1]] = kv[2].replace(/^["']|["']$/g, ''); + } + return out; +} + +function loadSkills() { + const dir = join(REPO, 'skills'); + if (!existsSync(dir)) return []; + const skills = []; + for (const name of readdirSync(dir)) { + const md = join(dir, name, 'SKILL.md'); + if (!existsSync(md)) continue; + try { + const fm = parseFrontmatter(readFileSync(md, 'utf8')); + skills.push({ name, description: fm.description || '(no description)' }); + } catch { /* unreadable skill dirs are skipped, not fatal */ } + } + return skills; +} + +function findSkill(query) { + const q = query.toLowerCase().trim().replace(/\s+/g, '-'); + const skills = loadSkills(); + const exact = skills.find(s => s.name === q); + const ranked = exact + ? [exact, ...skills.filter(s => s !== exact && s.name.includes(q))] + : skills.filter(s => s.name.includes(q) || s.description.toLowerCase().includes(query.toLowerCase())); + return ranked.slice(0, 5); +} + +function searchDocs(query) { + const terms = query.toLowerCase().split(/\s+/).filter(Boolean); + const hits = []; + const roots = ['docs', 'README.md']; + const walk = rel => { + const abs = join(REPO, rel); + if (!existsSync(abs)) return; + if (statSync(abs).isDirectory()) { + for (const f of readdirSync(abs)) walk(join(rel, f)); + return; + } + if (!rel.endsWith('.md')) return; + const nameScore = terms.filter(t => rel.toLowerCase().includes(t)).length; + let score = nameScore * 3; + if (nameScore < terms.length) { + try { + const head = readFileSync(abs, 'utf8').slice(0, 4000).toLowerCase(); + score += terms.filter(t => head.includes(t)).length; + } catch { /* skip unreadable */ } + } + if (score > 0) hits.push({ rel, score }); + }; + for (const r of roots) walk(r); + return hits.sort((a, b) => b.score - a.score).slice(0, 5); +} + +// ---------- command handlers ---------- + +const HELP = [ + '**ECC bot commands**', + '- `/ecc` — what ECC is + all the links', + '- `/skill name:` — look up an ECC skill', + '- `/docs query:` — search the ECC docs', + '- `/release` — latest ECC release', + '- `/help` — this message', +].join('\n'); + +const handlers = { + ecc: () => [ + '**Everything Claude Code (ECC)** — the agent harness performance system.', + 'Skills, agents, rules, hooks, MCP conventions, and operator workflows that move across Claude Code, Codex, OpenCode, Cursor, Gemini, and Zed.', + '', + `- repo: ${REPO_URL}`, + '- site: https://ecc.tools', + `- install: \`/plugin marketplace add affaan-m/everything-claude-code\` then \`/plugin install ecc\``, + INVITE ? `- invite a friend: ${INVITE}` : '', + ].filter(Boolean).join('\n'), + + help: () => HELP, + + skill: (options) => { + const query = options.find(o => o.name === 'name')?.value || ''; + const found = findSkill(query); + if (!found.length) return `no skill matching \`${query}\` — browse all: ${REPO_URL}/tree/main/skills`; + const [top, ...rest] = found; + return [ + `**${top.name}** — ${top.description}`, + `${REPO_URL}/tree/main/skills/${top.name}`, + rest.length ? `\nalso close: ${rest.map(s => `\`${s.name}\``).join(', ')}` : '', + ].filter(Boolean).join('\n'); + }, + + docs: (options) => { + const query = options.find(o => o.name === 'query')?.value || ''; + const hits = searchDocs(query); + if (!hits.length) return `nothing found for \`${query}\` — try ${REPO_URL}/tree/main/docs`; + return [`**docs matching \`${query}\`:**`, ...hits.map(h => `- ${REPO_URL}/blob/main/${h.rel.replace(/\\/g, '/')}`)].join('\n'); + }, + + release: async () => { + const res = await fetch('https://api.github.com/repos/affaan-m/ECC/releases/latest', { + headers: { 'User-Agent': 'ecc-discord-bot' }, + }); + if (!res.ok) return `couldn't reach GitHub (${res.status}) — ${REPO_URL}/releases`; + const r = await res.json(); + return `**${r.name || r.tag_name}**\n${r.html_url}`; + }, +}; + +async function respond(interaction) { + const name = interaction.data?.name; + const handler = handlers[name]; + const url = `${API}/interactions/${interaction.id}/${interaction.token}/callback`; + if (!handler) { + await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type: 4, data: { content: `unknown command \`${name}\`` } }), + }); + return; + } + try { + const content = await handler(interaction.data?.options || []); + await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type: 4, data: { content: String(content).slice(0, 1990) } }), + }); + log('handled', `/${name}`); + } catch (err) { + log('handler error', name, err.message); + await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type: 4, data: { content: 'something broke handling that — try again in a minute' } }), + }).catch(() => {}); + } +} + +// ---------- gateway (crash-only: exit on any failure, supervisor restarts) ---------- + +let seq = null; +let acked = true; + +async function main() { + const gw = await fetch(`${API}/gateway/bot`, { headers: { Authorization: `Bot ${TOKEN}` } }).then(r => r.json()); + if (!gw.url) { console.error('gateway discovery failed:', JSON.stringify(gw).slice(0, 200)); process.exit(1); } + const ws = new WebSocket(`${gw.url}?v=10&encoding=json`); + const send = payload => ws.send(JSON.stringify(payload)); + const die = reason => { log('exiting:', reason); process.exit(1); }; + + ws.onmessage = ev => { + const msg = JSON.parse(ev.data); + if (msg.s) seq = msg.s; + switch (msg.op) { + case 10: { // HELLO + const interval = msg.d.heartbeat_interval; + setTimeout(() => { + send({ op: 1, d: seq }); + setInterval(() => { + if (!acked) die('missed heartbeat ack'); + acked = false; + send({ op: 1, d: seq }); + }, interval); + }, interval * Math.random()); + send({ op: 2, d: { token: TOKEN, intents: 1, properties: { os: 'darwin', browser: 'ecc-bot', device: 'ecc-bot' } } }); + break; + } + case 11: acked = true; break; // HEARTBEAT_ACK + case 1: send({ op: 1, d: seq }); break; // server-requested heartbeat + case 7: die('server requested reconnect'); break; + case 9: die('invalid session'); break; + case 0: + if (msg.t === 'READY') log(`READY as ${msg.d.user.username}#${msg.d.user.discriminator}`); + if (msg.t === 'INTERACTION_CREATE' && msg.d.type === 2) respond(msg.d); + break; + default: break; + } + }; + ws.onclose = ev => die(`gateway closed (${ev.code})`); + ws.onerror = () => die('gateway error'); +} + +main().catch(err => { console.error('fatal:', err.message); process.exit(1); }); diff --git a/scripts/discord/register-commands.mjs b/scripts/discord/register-commands.mjs new file mode 100644 index 00000000..61b3abe7 --- /dev/null +++ b/scripts/discord/register-commands.mjs @@ -0,0 +1,38 @@ +#!/usr/bin/env node +// Registers the ECC bot's guild slash commands (bulk overwrite, instant). +// Env: DISCORD_BOT_TOKEN, DISCORD_APP_ID, DISCORD_GUILD_ID +'use strict'; + +const { DISCORD_BOT_TOKEN: TOKEN, DISCORD_APP_ID: APP_ID, DISCORD_GUILD_ID: GUILD } = process.env; +if (!TOKEN || !APP_ID || !GUILD) { + console.error('missing DISCORD_BOT_TOKEN / DISCORD_APP_ID / DISCORD_GUILD_ID'); + process.exit(1); +} + +const COMMANDS = [ + { name: 'ecc', description: 'What ECC is + all the links' }, + { name: 'help', description: 'List ECC bot commands' }, + { + name: 'skill', + description: 'Look up an ECC skill by name', + options: [{ type: 3, name: 'name', description: 'skill name or keyword', required: true }], + }, + { + name: 'docs', + description: 'Search the ECC docs', + options: [{ type: 3, name: 'query', description: 'search terms', required: true }], + }, + { name: 'release', description: 'Latest ECC release' }, +]; + +const res = await fetch(`https://discord.com/api/v10/applications/${APP_ID}/guilds/${GUILD}/commands`, { + method: 'PUT', + headers: { Authorization: `Bot ${TOKEN}`, 'Content-Type': 'application/json' }, + body: JSON.stringify(COMMANDS), +}); +if (!res.ok) { + console.error('registration failed:', res.status, (await res.text()).slice(0, 300)); + process.exit(1); +} +const registered = await res.json(); +console.log('registered:', registered.map(c => `/${c.name}`).join(' ')); diff --git a/tests/docs/copilot-support.test.js b/tests/docs/copilot-support.test.js index 1e7ec718..277382b1 100644 --- a/tests/docs/copilot-support.test.js +++ b/tests/docs/copilot-support.test.js @@ -46,21 +46,16 @@ console.log('\n=== Testing GitHub Copilot support surface ===\n'); test('VS Code settings enable Copilot prompt files', () => { const settings = JSON.parse(read('.vscode/settings.json')); assert.strictEqual(settings['chat.promptFiles'], true); + assert.ok(!Object.prototype.hasOwnProperty.call(settings, 'github.copilot.chat.reviewSelection.instructions')); }); test('Copilot prompt files use current VS Code frontmatter', () => { - const promptFiles = fs.readdirSync(promptDir) + const promptFiles = fs + .readdirSync(promptDir) .filter(file => file.endsWith('.prompt.md')) .sort(); - assert.deepStrictEqual(promptFiles, [ - 'build-fix.prompt.md', - 'code-review.prompt.md', - 'plan.prompt.md', - 'refactor.prompt.md', - 'security-review.prompt.md', - 'tdd.prompt.md', - ]); + assert.deepStrictEqual(promptFiles, ['build-fix.prompt.md', 'plan.prompt.md', 'refactor.prompt.md', 'security-review.prompt.md', 'tdd.prompt.md']); for (const file of promptFiles) { const relativePath = `.github/prompts/${file}`; @@ -74,18 +69,15 @@ test('Copilot prompt files use current VS Code frontmatter', () => { }); test('Copilot docs advertise slash prompt invocation instead of hash commands', () => { - const sources = [ - '.github/copilot-instructions.md', - 'README.md', - ].map(read).join('\n'); + const sources = ['.github/copilot-instructions.md', 'README.md'].map(read).join('\n'); - for (const command of ['plan', 'tdd', 'code-review', 'security-review', 'build-fix', 'refactor']) { + for (const command of ['plan', 'tdd', 'security-review', 'build-fix', 'refactor']) { assert.ok(!sources.includes(`#${command}`), `Expected no stale #${command} command syntax`); } assert.ok(sources.includes('/plan')); assert.ok(sources.includes('/tdd')); - assert.ok(sources.includes('/code-review')); + assert.ok(sources.includes('/security-review')); }); test('Copilot instructions include a prompt defense baseline', () => { diff --git a/tests/docs/ecc2-release-surface.test.js b/tests/docs/ecc2-release-surface.test.js index 554eb363..442ad8ea 100644 --- a/tests/docs/ecc2-release-surface.test.js +++ b/tests/docs/ecc2-release-surface.test.js @@ -55,7 +55,7 @@ const expectedReleaseFiles = [ 'video-suite-production.md', 'partner-sponsor-talks-pack.md', 'owner-approval-packet-2026-05-19.md', - 'release-name-plugin-publication-checklist-2026-05-18.md', + 'release-name-plugin-publication-checklist-2026-05-18.md' ]; test('release candidate directory includes the public launch pack', () => { @@ -64,10 +64,10 @@ test('release candidate directory includes the public launch pack', () => { } }); -test('README links to Hermes setup and rc.1 release notes', () => { +test('README links to Hermes setup and current 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'); + assert.ok(readme.includes('docs/releases/2.0.0/release-notes.md'), 'README must link to the 2.0.0 release notes'); }); test('cross-harness architecture doc exists and names core harnesses', () => { @@ -109,37 +109,19 @@ test('release docs do not contain unresolved public-link placeholders', () => { test('business launch copy stays aligned with the rc.1 public surface', () => { const source = read('docs/business/social-launch-copy.md'); assert.ok(source.includes('ECC v2.0.0-rc.1'), 'business launch copy should use the rc.1 release'); - assert.ok( - source.includes('preview pack is ready for final release review'), - 'business launch copy should stay pre-publication until release URLs exist' - ); - assert.ok( - source.includes('https://github.com/affaan-m/ECC'), - 'business launch copy should include the public repo URL' - ); - assert.ok( - source.includes( - 'https://github.com/affaan-m/ECC/blob/main/docs/releases/2.0.0-rc.1/release-notes.md' - ), - 'business launch copy should link to the rc.1 release notes' - ); + assert.ok(source.includes('preview pack is ready for final release review'), 'business launch copy should stay pre-publication until release URLs exist'); + assert.ok(source.includes('https://github.com/affaan-m/ECC'), 'business launch copy should include the public repo URL'); + assert.ok(source.includes('https://github.com/affaan-m/ECC/blob/main/docs/releases/2.0.0-rc.1/release-notes.md'), 'business launch copy should link to the rc.1 release notes'); assert.ok(!source.includes(''), 'business launch copy should not contain repo placeholders'); assert.ok(!source.includes('v1.8.0'), 'business launch copy should not stay pinned to v1.8.0'); }); test('announcement drafts avoid live-release claims before publication', () => { - const announcementFiles = [ - 'docs/releases/2.0.0-rc.1/linkedin-post.md', - 'docs/releases/2.0.0-rc.1/partner-sponsor-talks-pack.md', - 'docs/business/social-launch-copy.md', - ]; + const announcementFiles = ['docs/releases/2.0.0-rc.1/linkedin-post.md', 'docs/releases/2.0.0-rc.1/partner-sponsor-talks-pack.md', 'docs/business/social-launch-copy.md']; for (const relativePath of announcementFiles) { const source = read(relativePath); - assert.ok( - !/ECC v2\.0\.0-rc\.1 is live\./.test(source), - `${relativePath} must not claim rc.1 is live before the release gate completes` - ); + assert.ok(!/ECC v2\.0\.0-rc\.1 is live\./.test(source), `${relativePath} must not claim rc.1 is live before the release gate completes`); } }); @@ -184,7 +166,7 @@ test('preview pack manifest assembles release, Hermes, and publication gates', ( 'docs/releases/2.0.0-rc.1/owner-approval-packet-2026-05-19.md', 'docs/releases/2.0.0-rc.1/video-suite-production.md', 'docs/releases/2.0.0-rc.1/publication-evidence-2026-05-19.md', - 'docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md', + 'docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md' ]) { assert.ok(manifest.includes(artifact), `preview pack manifest missing ${artifact}`); } @@ -194,7 +176,7 @@ test('preview pack manifest assembles release, Hermes, and publication gates', ( 'npm `ecc-universal@2.0.0-rc.1`', 'Claude plugin tag', 'Codex repo-marketplace distribution evidence', - 'ECC Tools billing/product readiness', + 'ECC Tools billing/product readiness' ]) { assert.ok(manifest.includes(blocker), `preview pack manifest missing blocker ${blocker}`); } @@ -223,7 +205,7 @@ test('owner approval packet consolidates the final gated decisions', () => { 'Video upload', 'Final URL Fill-In', 'Do Not Approve If', - 'No outbound email, personal-account post, package publish, plugin tag, or billing announcement is authorized by this packet alone.', + 'No outbound email, personal-account post, package publish, plugin tag, or billing announcement is authorized by this packet alone.' ]) { assert.ok(packet.includes(marker), `owner approval packet missing ${marker}`); } @@ -233,18 +215,12 @@ test('owner approval packet consolidates the final gated decisions', () => { 'npm run preview-pack:smoke -- --format json', 'npm run release:approval-gate -- --format json', 'npm run release:video-suite -- --format json', - 'node tests/run-all.js', + 'node tests/run-all.js' ]) { assert.ok(packet.includes(command), `owner approval packet missing command ${command}`); } - for (const urlSurface of [ - 'GitHub prerelease URL', - 'npm rc package URL', - 'Claude plugin tag URL', - 'Primary launch video URL', - 'ECC Tools billing/readiness URL', - ]) { + for (const urlSurface of ['GitHub prerelease URL', 'npm rc package URL', 'Claude plugin tag URL', 'Primary launch video URL', 'ECC Tools billing/readiness URL']) { assert.ok(packet.includes(urlSurface), `owner approval packet missing ${urlSurface}`); } @@ -272,7 +248,7 @@ test('GA roadmap mirrors the current May 19 release evidence', () => { '467d148a-712a-4777-aad9-95593e9f1739', '7642ee9c-3107-400c-a229-53e2895a8914', 'ecc-may-19-post-pr-2002-sync-64cef8f668e0', - 'owner approval packet', + 'owner approval packet' ]) { assert.ok(roadmap.includes(marker), `GA roadmap missing current evidence marker ${marker}`); } @@ -331,19 +307,12 @@ test('release video suite manifest gates the content launch lane', () => { 'Do Not Publish If', 'renders/ecc-2-primary-launch-rough-v1.mp4', 'timelines/primary-launch-v1.timeline.json', - 'Primary launch video', + 'Primary launch video' ]) { assert.ok(videoManifest.includes(marker), `video suite manifest missing ${marker}`); } - for (const asset of [ - 'longform-full-wide.mp4', - 'sf-thread-2-whatisecc.mp4', - 'thread-2-ghapp-money.mp4', - 'coverage-montage-wide.mp4', - 'star_history.png', - 'x_analytics.png', - ]) { + for (const asset of ['longform-full-wide.mp4', 'sf-thread-2-whatisecc.mp4', 'thread-2-ghapp-money.mp4', 'coverage-montage-wide.mp4', 'star_history.png', 'x_analytics.png']) { assert.ok(videoManifest.includes(asset), `video suite manifest missing asset ${asset}`); } @@ -365,7 +334,7 @@ test('release approval gate blocks publication until owner decisions and URLs ar 'owner-decisions-approved', 'release-url-ledger-finalized', 'announcement-copy-finalized', - 'No outbound email, personal-account post, package publish, plugin tag, or billing announcement', + 'No outbound email, personal-account post, package publish, plugin tag, or billing announcement' ]) { assert.ok(script.includes(marker), `release approval gate missing ${marker}`); } @@ -402,7 +371,7 @@ test('partner sponsor talks pack gates the hypergrowth outbound lane', () => { 'GitHub Discussion Announcement', 'Video CTA Hooks', 'Do Not Send Or Publish If', - 'The user has not approved outbound sponsor, partner, consulting, or media', + 'The user has not approved outbound sponsor, partner, consulting, or media' ]) { assert.ok(partnerPack.includes(marker), `partner pack missing ${marker}`); } @@ -416,10 +385,7 @@ test('partner sponsor talks pack gates the hypergrowth outbound lane', () => { }); test('release video suite public docs do not expose private media paths', () => { - const releaseVideoDocs = [ - 'docs/releases/2.0.0-rc.1/video-suite-production.md', - 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md', - ]; + const releaseVideoDocs = ['docs/releases/2.0.0-rc.1/video-suite-production.md', 'docs/releases/2.0.0/ecc-2-hypergrowth-release-command-center.md']; const offenders = []; for (const relativePath of releaseVideoDocs) { @@ -437,37 +403,15 @@ test('publication readiness checklist gates public release actions on evidence', const may15Evidence = read('docs/releases/2.0.0-rc.1/publication-evidence-2026-05-15.md'); const discussionPlaybook = read('docs/architecture/discussion-response-playbook.md'); - for (const section of [ - '## Release Identity Matrix', - '## Publication Gates', - '## Required Command Evidence', - '## Do Not Publish If', - '## Announcement Order', - ]) { + for (const section of ['## Release Identity Matrix', '## Publication Gates', '## Required Command Evidence', '## Do Not Publish If', '## Announcement Order']) { assert.ok(source.includes(section), `publication readiness missing ${section}`); } - for (const field of [ - 'Fresh check', - 'Evidence artifact', - 'Owner', - 'Status', - 'Blocker field', - 'Recorded output', - ]) { + for (const field of ['Fresh check', 'Evidence artifact', 'Owner', 'Status', 'Blocker field', 'Recorded output']) { assert.ok(source.includes(field), `publication readiness missing ${field}`); } - for (const surface of [ - 'GitHub release', - 'npm package', - 'Claude plugin', - 'Codex plugin', - 'Codex repo marketplace', - 'OpenCode package', - 'ECC Tools billing reference', - 'Announcement copy', - ]) { + for (const surface of ['GitHub release', 'npm package', 'Claude plugin', 'Codex plugin', 'Codex repo marketplace', 'OpenCode package', 'ECC Tools billing reference', 'Announcement copy']) { assert.ok(source.includes(surface), `publication readiness missing ${surface}`); } @@ -502,14 +446,7 @@ test('publication readiness checklist gates public release actions on evidence', assert.ok(source.includes('platform audit sampled 59 trunk discussions')); assert.ok(source.includes('0 needing maintainer touch')); assert.ok(source.includes('discussion-response-playbook.md')); - for (const expected of [ - 'Public Support', - 'Maintainer Coordination', - 'Stale Or Concluded', - 'Release Announcement', - 'Security Escalation', - 'classified as informational', - ]) { + for (const expected of ['Public Support', 'Maintainer Coordination', 'Stale Or Concluded', 'Release Announcement', 'Security Escalation', 'classified as informational']) { assert.ok(discussionPlaybook.includes(expected), `discussion playbook missing ${expected}`); } assert.ok(may15Evidence.includes('env -u GITHUB_TOKEN')); @@ -518,9 +455,7 @@ test('publication readiness checklist gates public release actions on evidence', }); test('release name and plugin publication checklist freezes rc.1 surfaces', () => { - const checklist = read( - 'docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md' - ); + const checklist = read('docs/releases/2.0.0-rc.1/release-name-plugin-publication-checklist-2026-05-18.md'); const launchChecklist = read('docs/releases/2.0.0-rc.1/launch-checklist.md'); const referenceArchitecture = read('docs/ECC-2.0-REFERENCE-ARCHITECTURE.md'); @@ -534,7 +469,7 @@ test('release name and plugin publication checklist freezes rc.1 surfaces', () = 'Codex plugin', 'do not claim official directory listing until OpenAI publishing path is available', 'Do not rename the npm package until rc.1 is published', - 'Do not announce billing, Marketplace, or native payments', + 'Do not announce billing, Marketplace, or native payments' ]) { assert.ok(checklist.includes(value), `release name/plugin checklist missing ${value}`); } @@ -545,7 +480,7 @@ test('release name and plugin publication checklist freezes rc.1 surfaces', () = 'codex plugin marketplace add --help', 'npm publish --tag next --dry-run', 'npm run preview-pack:smoke', - 'npm run release:approval-gate -- --format json', + 'npm run release:approval-gate -- --format json' ]) { assert.ok(checklist.includes(command), `release name/plugin checklist missing command ${command}`); } @@ -569,7 +504,7 @@ test('active release identity surfaces use canonical ECC repo URLs', () => { 'docs/releases/2.0.0-rc.1/release-url-ledger-2026-05-19.md', 'ecc2/Cargo.toml', 'scripts/platform-audit.js', - 'scripts/discussion-audit.js', + 'scripts/discussion-audit.js' ]; const offenders = [];