/** * Everything-Claude-Code (ECC) code-review bridge — adapter that * takes the ECC `code-review` agent's structured envelope * (`{ passed, violations[], gateAction }`) and renders it into the * `rd/code-review.md` markdown format that `peaks request transition` * Gate B3 already reads (`mustContain: ['## Findings', 'CRITICAL']`). * * ECC is the in-skill agent option and the production Gate B3 path. * * === Why a bridge (not a direct swap) === * * `peaks-rd/references/parallel-review-fanout.md` sub-agent 1 has a * hard contract: write `rd/code-review.md` with sections * `Summary / Findings / Required Fixes / Recommended / Verdict`. * The CLI gate at `rd:qa-handoff` enforces `mustContain: ['## Findings', * 'CRITICAL']` and refuses the transition otherwise. ECC's structured * envelope does not match that shape — it returns `{ passed, violations, * gateAction }`. Hence the bridge: render the envelope into the * canonical markdown shape, so ECC and the legacy inline reviewer * share the same downstream contract. * * === Why no `peaksConfig.ecc.*` block === * * ECC ships as the `ecc-universal` npm package — the same repository as * github.com/affaan-m/ECC — and peaks-loop depends on it, so the agents are read * from that dependency, not downloaded. ECC may ALSO be present as the * `everything-claude-code` Claude Code plugin, the native path `detectEcc` * prefers. Either way peaks-loop writes and reads no LLM endpoint config for ECC; * add a `peaksConfig.ecc.*` block only when a release actually needs one. * * === Source: peaks-rd/references/parallel-review-fanout.md === * * Sub-agent 1 contract (Tier 7 v2.11.0): the parent RD loop calls * `Agent({ subagent_type: 'ecc:code-reviewer', ... })` * with the diff + handoff in scope, receives the structured envelope, * then runs `adaptEccEnvelopeToRdCodeReview(env, { rid, generatedAt })` * and writes the resulting body to * `.peaks/_runtime//rd/code-review.md`. */ export type EccViolationKind = 'correctness' | 'type-safety' | 'error-handling' | 'mutation' | 'file-size' | 'naming' | 'dead-code' | 'regression' | 'contract-drift' | 'other'; export interface EccViolation { readonly kind: string; readonly line: number; readonly snippet: string; readonly hint: string; } export type EccGateAction = 'pass' | 'warn' | 'block'; export interface EccEnvelope { readonly passed: boolean; readonly violations: ReadonlyArray; readonly gateAction: EccGateAction; } /** * The real upstream ECC agent name for the code-review role: * `~/.peaks/agents/ecc/code-reviewer.md`. Upstream ships `-reviewer` * agents and has NO `code-review.md`, so this is the default the * `ready-via-cache` nextActions name when the caller does not pass the * output of `resolveMaterializedAgentName(['code-reviewer', 'code-review'])`. */ export declare const DEFAULT_CACHE_ECC_AGENT_NAME = "code-reviewer"; /** * The native (plugin) ECC agent id dispatched through the Agent tool. * Verified upstream: the plugin is named `ecc` (`.claude-plugin/plugin.json`, * `marketplace.json`) and the agent's frontmatter `name` is `code-reviewer` * (`~/.peaks/agents/ecc/code-reviewer.md`), so the composed id is * `ecc:code-reviewer`. The previous id composed the OLD repo name * (`everything-claude-code`) with a non-existent `code-review` agent, so it * matched no registry entry and the native path silently fell through to * inline review. */ export declare const DEFAULT_NATIVE_ECC_AGENT_ID = "ecc:code-reviewer"; /** * 6-state ECC detection result: * - `ready` — ECC plugin is installed and reachable * - `ready-via-cache` — plugin/agent absent, but the materialized ECC * review agent (real name `code-reviewer`, NOT * `code-review`) exists under `~/.peaks/agents/ecc/`; * dispatch a GENERIC sub-agent with that body * - `plugin-missing` — `everything-claude-code` not in skill list and no materialized cache * - `agent-missing` — plugin present but `code-review` agent absent and no materialized cache * - `dispatch-failed` — Agent tool call threw before returning envelope * - `envelope-malformed` — returned value failed `isEccEnvelope` validation * * cache-backed generic agent → inline. The caller (peaks-rd's sub-agent 1 * contract) inspects `state` and either proceeds with the envelope or records * a degradation note in the request artifact body * (`code-review-ecc-degraded-to-inline`). */ export type EccDetectState = 'ready' | 'ready-via-cache' | 'plugin-missing' | 'agent-missing' | 'dispatch-failed' | 'envelope-malformed'; export interface EccDetectResult { readonly state: EccDetectState; readonly pluginInstalled: boolean; readonly agentAvailable: boolean; readonly warnings: readonly string[]; readonly nextActions: readonly string[]; } export type RdCodeReviewVerdict = 'pass' | 'warn' | 'block'; export interface RdCodeReviewDoc { /** Full markdown body, ready to write to `rd/code-review.md`. */ readonly body: string; /** Mirror of `gateAction` for the parent RD loop to log/aggregate. */ readonly verdict: RdCodeReviewVerdict; /** Counts per severity bucket — populated only when violations exist. */ readonly counts: { readonly total: number; readonly byKind: Readonly>; }; } /** * Validate a raw value as an EccEnvelope. Accepts the strict shape * only — extra fields are tolerated (forward-compat for ECC adding * new top-level keys), but missing/typed-wrong fields reject. * * Defensive on purpose: ECC is external code, and a malformed envelope * must not propagate into `rd/code-review.md` (would corrupt Gate B3). */ export declare function isEccEnvelope(value: unknown): value is EccEnvelope; /** * Render an ECC envelope to the canonical `rd/code-review.md` shape. * Verdict → sections: * - `pass` → Summary + Findings (empty) + Verdict: pass * - `warn` → Summary + Findings + Required Fixes + Recommended + Verdict: warn * - `block` → Summary + Findings + Required Fixes + Recommended + Verdict: block * + the `CRITICAL: ` marker that Gate B3's * `mustContain: ['## Findings', 'CRITICAL']` requires */ export declare function adaptEccEnvelopeToRdCodeReview(env: EccEnvelope, opts: { rid: string; generatedAt: string; }): RdCodeReviewDoc; /** * 6-state detector — mirrors `detectOcr`'s shape (state enum + warnings * + nextActions). The caller passes in the result of its own probe: * * - `pluginInstalled`: did the skill list scan find `everything-claude-code`? * - `agentAvailable`: did the Agent tool say `code-review` is registered? * - `cacheAgentAvailable`: does the resolved materialized agent exist * (`~/.peaks/agents/ecc/.md`, default `code-reviewer`)? * - `dispatchError`: optional — the Agent tool threw before returning. * - `envelope`: optional — what came back (if anything). * * The detector never blocks: when the state is not dispatchable * (`ready` / `ready-via-cache`), the parent RD loop records a * `code-review-ecc-degraded-to-inline` note and falls back to inline * review. This matches `detectOcr`'s soft-fail policy. * * Backward compat: the native id is `DEFAULT_NATIVE_ECC_AGENT_ID` * (`ecc:code-reviewer` — plugin `ecc`, agent `code-reviewer`). A registry * that still exposes the OLD `everything-claude-code` plugin id will not * match it, so the operator should pin the id explicitly. peaks-loop * cannot enumerate the user's plugin registry: detection stays * caller-supplied (`pluginInstalled` / `agentAvailable`), never probed here. */ export declare function detectEcc(input: { readonly pluginInstalled: boolean; readonly agentAvailable: boolean; /** * Did the caller find the materialized review agent (written by * `peaks ecc install` / `materializeEccAgents`) under `~/.peaks/agents/ecc/`? * When true and the native plugin path is unavailable, `state` becomes * `ready-via-cache` so the RD loop can dispatch a generic sub-agent with * the materialized body. */ readonly cacheAgentAvailable?: boolean; /** * Resolved materialized agent name — pass * `resolveMaterializedAgentName(['code-reviewer', 'code-review'])` from * `peaks-loop-mut`. Defaults to `code-reviewer` (the real upstream name); * upstream has no `code-review.md`. */ readonly cacheAgentName?: string; readonly dispatchError?: unknown; readonly envelope?: unknown; }): EccDetectResult; /** * Convenience: run `detectEcc` and `adaptEccEnvelopeToRdCodeReview` * in one call. The parent RD loop calls this after the Agent tool * returns. When `detectEcc` returns a non-dispatchable state * (`plugin-missing` / `agent-missing` / `dispatch-failed` / * `envelope-malformed`), the caller should NOT call * `adaptEccEnvelopeToRdCodeReview` — fall back to inline review instead. * * Both `ready` (native plugin) and `ready-via-cache` (materialized generic * agent) adapt the envelope through the SAME bridge. */ export declare function runEccCodeReview(input: { readonly rid: string; readonly generatedAt: string; readonly pluginInstalled: boolean; readonly agentAvailable: boolean; readonly cacheAgentAvailable?: boolean; /** Resolved materialized agent name (see `detectEcc`); defaults to `code-reviewer`. */ readonly cacheAgentName?: string; readonly dispatchError?: unknown; readonly envelope?: unknown; }): { detect: EccDetectResult; doc: RdCodeReviewDoc | null; }; /** * The exact JSON shape the generic (cache-backed) sub-agent MUST return. * Kept as a const so the RD reference docs and the prompt builder cannot * drift: `isEccEnvelope` is the authoritative validator. */ export declare const ECC_OUTPUT_CONTRACT: string; /** * Compose the plugin-free dispatch prompt for sub-agent 1. * * `instructions` is the body of the materialized review agent * (`~/.peaks/agents/ecc/code-reviewer.md` — resolve the real name with * `resolveMaterializedAgentName`, never hardcode `code-review.md`); * `diff` is the slice diff. The * composed prompt is handed to a GENERIC sub-agent (no ECC plugin needed) * and its reply is validated with `isEccEnvelope`, then rendered by * `adaptEccEnvelopeToRdCodeReview` — the same bridge the native path uses. */ export declare function buildCacheBackedEccPrompt(input: { readonly rid: string; readonly instructions: string; readonly diff: string; }): string;