Files
ECC/.claude-plugin
JongHyeok ParkGitHubAffaan Mustafadevin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>affaanBoube
914a58a716 feat(workflows): re-land orch-review workflow + add /orch-review command (#2400)
* feat(workflows): re-land orch-review workflow + add /orch-review command

Re-lands #2363 (reverted by #2393 to unbreak main's lint) and fixes the
root cause so it stays green:

- Restore workflows/orch-review.workflow.js + workflows/README.md.
- eslint.config.js: ignore 'workflows/**/*.workflow.*' and '.claude/workflows/**'
  per the maintainer's note in #2393. Workflow DSL scripts use both top-level
  export (ESM) and top-level return (the runtime wraps them in an async fn),
  which no single eslint sourceType can parse — they must be excluded, not
  lint-fixed. 'npx eslint .' is green with this ignore.
- Add commands/orch-review.md (the /orch-review surface) + regenerate
  docs/COMMAND-REGISTRY.json.

Supersedes #2397 (command-only), which referenced the reverted workflow.

* fix(workflows): address orch-review bot review findings

- Verifier uncertainty no longer demotes blockers (Greptile P1 + CodeRabbit):
  isReal=false only refutes when confidence >= 0.8; low-confidence 'false'
  is treated as uncertain and kept blocking (fail closed).
- Treat the diff (and finding text) as untrusted input in both review and
  verify prompts; ignore embedded directives (prompt-injection hardening).
- Validate changedFiles entries are strings, not just that it is an array.
- Enforce proof for HIGH/CRITICAL in FINDINGS_SCHEMA, not only in the prompt.
- Remove in-place mutation in dimension build + dedup merge (immutable).
- /orch-review: extract & validate a numeric PR id before shelling out to gh.
- Docs: complete the stats example, soften wording, refresh follow-up list.

* style(workflows): apply formatter to orch-review assembly

* fix(plan-orchestrate): detect ecc@ecc marketplace + emit ecc: agent prefix (#2316) (#2409)

* fix(plan-orchestrate): detect ecc@ecc marketplace + emit ecc: agent prefix (#2316)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368) (#2410)

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368)

The inline node -e resolver blob was duplicated ~60x across hooks.json,
command docs, and translations. Each copy inlined the full ~700-char
plugin-root search using a spread over nested array literals
(p.join(d,'plugins',...s) over [['ecc'],...]), which breaks Windows hook
execution due to shell quoting (#2368).

Collapse every copy to a 250-char locator that loads the committed
resolve-ecc-root module and delegates to resolveEccRoot() — no spread, no
nested array literals, no escaped double quotes. The real search logic now
lives in one tested module. Also route session-start-bootstrap.js through
resolveEccRoot() instead of its own duplicated reimplementation, and fix
the auto-update.md 'marketplace' (singular) typo along the way.

Guard tests updated: discovery behavior is asserted against resolveEccRoot();
the inline is asserted to delegate and to contain no Windows-fragile
constructs.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(resolve-ecc-root): restore full env-unset discovery in inline resolver

Address Greptile review on #2410: when CLAUDE_PLUGIN_ROOT is unset the
delegating inline could only load the resolver module from ~/.claude,
returning ~/.claude without ever reaching the plugin/cache search. Restore
the old inline's discovery breadth (exact plugin roots + versioned cache)
Windows-safely (no spread, nested arrays, or escaped quotes), then delegate
the authoritative decision to resolveEccRoot(). Add regression tests for
plugin-subdir and versioned-cache bootstrap with env unset.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: docs/COMMAND-REGISTRY.json check fails on fresh Windows clone (missing .gitattributes) (#2437)

* fix: add .gitattributes to force LF line endings for text files

npm run command-registry:check (part of npm test) fails on a fresh clone
on Windows with the common core.autocrlf=true setting: git checks out
docs/COMMAND-REGISTRY.json with CRLF, but generate-command-registry.js
always writes LF, so the strict string comparison in checkRegistry()
never matches. Forcing LF via .gitattributes makes checkouts consistent
across platforms regardless of a contributor's local autocrlf setting.

* fix: normalize CRLF line endings to LF per .gitattributes

pyproject.toml, src/llm/__init__.py, src/llm/prompt/builder.py,
src/llm/providers/claude.py, and tests/test_builder.py had CRLF line
endings committed to the repo, inconsistent with the rest of the
codebase. Renormalized via 'git add --renormalize .' now that
.gitattributes enforces eol=lf.

---------

Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>

* chore(catalog): sync command counts (92->93) + register orch-review in agent.yaml surface

---------

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Boube <109886533+Cb2i@users.noreply.github.com>
Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
2026-07-03 20:26:40 -07:00
..

Plugin Manifest Gotchas

If you plan to edit .claude-plugin/plugin.json, be aware that the Claude plugin validator enforces several undocumented but strict constraints that can cause installs to fail with vague errors (for example, agents: Invalid input). In particular, component fields must be arrays, agents is not a supported manifest field and must not be included in plugin.json, and a version field is required for reliable validation and installation.

These constraints are not obvious from public examples and have caused repeated installation failures in the past. They are documented in detail in .claude-plugin/PLUGIN_SCHEMA_NOTES.md, which should be reviewed before making any changes to the plugin manifest.

Custom Endpoints and Gateways

ECC does not override Claude Code transport settings. If Claude Code is configured to run through an official LLM gateway or a compatible custom endpoint, the plugin continues to work because hooks, skills, and any retained legacy command shims execute locally after the CLI starts successfully.

Use Claude Code's own environment/configuration for transport selection, for example:

export ANTHROPIC_BASE_URL=https://your-gateway.example.com
export ANTHROPIC_AUTH_TOKEN=your-token
claude