import type { Provider, TurnResult } from '../types/run-result.js'; import type { AgentType } from '../types/task-spec.js'; import type { TaskType, SandboxPolicy } from './type-registry.js'; import { type DispatchedContractTask } from './contract-match.js'; import { type ContractPlanSnapshot } from './contract-plan.js'; /** Result of running one plan-authored acceptance-test command. */ export interface AcceptanceCommandResult { exitCode: number; stdout: string; stderr: string; } /** Injectable seam for running an acceptance-test command (tests substitute a fake). * The production default tokenizes the command by whitespace into `[cmd, ...args]` * (the plan parser guarantees a shell-metacharacter-free argv) and runs it via * `execFile` with no shell. */ export type RunAcceptanceCommand = (command: string, cwd: string) => Promise; export interface PipelineInput { type: TaskType; readerFacing: boolean; implementerSkill: string; reviewerSkill: string; /** Committed procedure guidance for the resolved Method (SPEC-005), or `undefined`/`null` * when no Method resolved for this execution. Injected as ONE identical block into both * the implementer and the reviewer prompt, alongside the existing writing-style and * search-hygiene blocks — never route-specific, never selected by `type` or `subtype`. * Omitting it (the common case) must leave both generic prompts byte-identical to the * pre-Method baseline. */ methodGuidance?: string | null; taskPayload: string; implementerProvider: Provider; reviewerProvider: Provider; implementerTier: AgentType; reviewerTier: AgentType; reviewPolicy: 'reviewed' | 'none'; cwd: string; sandboxPolicy: SandboxPolicy; resumeImplementer?: string; resumeReviewer?: string; timeoutMs?: number; /** The caller's per-execution abort signal (cooperative cancellation). Every * provider session this pipeline opens receives it; the pipeline also checks * it at phase boundaries and returns a terminal `aborted` failure instead of * starting the next phase. Callers that never cancel may omit it. */ abortSignal?: AbortSignal; /** True for the write routes (delegate / execute_plan). The engine captures a git baseline * before the worker starts and commits on the caller's branch afterwards. Read routes never * touch git. The engine never creates a branch or a worktree — the caller owns those. */ writeRoute?: boolean; taskId?: string; /** Goal condition for the implementer — keeps the agent working until met. */ implementerGoal?: string; /** Goal condition for the reviewer. */ reviewerGoal?: string; /** EnvelopeBus for provider-level event streaming (stderr + JSONL + telemetry). */ bus?: object; /** Called before each phase starts. */ onPhaseChange?: (phase: 'implementing' | 'reviewing') => void; /** For execute_plan / journal_record: prompt-facing labels injected into the reviewer prompt * for completeness verification. Prose — never the matching key. */ dispatchedTasks?: string[]; /** For execute_plan: the id-keyed records the contract matcher resolves reviewer output * against. Stable ids, not prose, are what decide contract satisfaction. */ dispatchedContractTasks?: DispatchedContractTask[]; /** For execute_plan: the immutable parsed-and-validated frozen Contract Task * snapshot selected at dispatch time. Type-only here — the behavior that * materializes/re-materializes its acceptance tests lives downstream. */ acceptanceTestSnapshot?: ContractPlanSnapshot; /** Injectable acceptance-command runner (execute_plan scoring). Tests substitute a * fake; production uses the no-shell execFile default. */ runAcceptanceCommand?: RunAcceptanceCommand; /** Resolved context block content (max 2). Injected as a ## Prior Context * section between the skill prompt and the ## Task payload. */ contextBlocks?: string[]; /** When true, always run the reviewer even if applyDecisions reports invariants passed * (caller explicitly requested review). */ forceReview?: boolean; /** Deterministic post-implementer hook (journal_record). Applies the implementer's * decision output to the corpus and returns the applied result. When it reports * invariantsPassed the reviewer is skipped (unless forceReview). */ applyDecisions?: (implementerOutput: string) => Promise<{ recorded: unknown[]; failed: unknown[]; invariantsPassed: boolean; }>; } export interface SessionInfo { tier: AgentType; sessionId: string | null; resumeSupported: boolean; } export interface PipelineResult { status: 'done' | 'done_with_concerns' | 'failed'; implementerOutput: string; implementerTurn: TurnResult; reviewerOutput: unknown | null; reviewerRaw: string | null; reviewerTurn: TurnResult | null; reviewerParseError: string | null; sessions: { implementer: SessionInfo; reviewer: SessionInfo | null; }; cost: { implementerUsd: number; reviewerUsd: number | null; }; /** Response-compatibility key, permanently null: the engine no longer owns worktrees. */ worktree: null; /** FR-4 — was the caller's tree already dirty when we were dispatched? Discloses that * pre-existing work was swept into the engine commit by `git add -A`. */ dirtyAtDispatch: boolean; /** FR-3 — `git diff --name-only ..HEAD` for a committed git target. * Null when the route did not commit (read routes, non-git targets, nothing to commit). */ filesChangedFromGit: string[] | null; /** The commit-time SHA (`CommitOutcome.head`), captured the instant `commitWork()` actually * creates a commit — never re-derived from live git state later. Null when nothing was * committed (read routes, non-git targets, a write route that changed nothing, or a * pre-commit terminal state). Persisted into the terminal envelope so a replay of this * execution's outbox row (`InitiativeLinker`) records THIS commit as Evidence even if a * later commit has since landed in the same `cwd` (SPEC-003 B6 defect 2). */ commitSha: string | null; /** FR-9 — populated only when reviewer output could not be resolved onto dispatched task * ids. Distinct from "the work is incomplete". */ contractNote: { code: 'contract_unverifiable'; message: string; availableTaskIds: string[]; } | null; /** Completion score (0–100). For execute_plan, derived from contract satisfaction * plus the re-materialized acceptance-test run; the commit gate is `>= 80`. Other * task types default to 100 on success / 0 on failure. */ completionPercent: number; /** Set on a pre/mid-pipeline failure (e.g. malformed/collision/materialization) so * the handler can render a specific terminal envelope instead of a generic one. */ failureReason?: { code: string; message: string; }; } export declare function runTwoPhasePipeline(input: PipelineInput): Promise; //# sourceMappingURL=two-phase-pipeline.d.ts.map