/**
 * Auto-Chain Pipeline Orchestrator
 *
 * Automatically chains Phases 2-6 after enterprise simulation (Phase 1).
 * Each phase reads artifacts from prior phases in ~/.agentics/runs/<traceId>/.
 *
 * This replaces the old executePipeline() which used weak generic stages.
 * The auto-chain calls the actual phase coordinators (phase2 through phase6)
 * that produce high-fidelity artifacts:
 *   Phase 2: Deep Research (research dossier from Phase 1 documents)
 *   Phase 3: SPARC + London TDD (specification, pseudocode, architecture, refinement, completion + test plan)
 *   Phase 4: ADRs + DDDs (architecture decision records + domain-driven design models)
 *   Phase 5: Build (code generation + deployable service from ADRs/DDDs)
 *   Phase 6: ERP Surface Push (registration + project materialization)
 */
import { type ExecutionMode } from './execution-context.js';
import { type PrimaryPhaseExecutionResult } from './ruflo-phase-executor.js';
import { type PhaseId as GatePhaseId, type BlockedPhase } from './gate/phase-dependency-gate.js';
export interface AutoChainOptions {
    readonly verbose?: boolean;
    readonly outputDir?: string;
    readonly executionMode?: ExecutionMode;
}
/**
 * ADR-094 Decision 4 — `skipped-due-to-upstream` is a distinct phase-result
 * state from `skipped` (which means "phase opted out") and `failed` (which
 * means "phase ran and errored"). It signals "this phase did not run because
 * an upstream phase was failed/blocked and we propagated", and ensures the
 * `chainResult.phases[]` trace contract holds even when Phase 5 fails before
 * Phase 6 runs. Pre-094 Phase 6 was invisible in the trace on upstream
 * failure; under 094 it is always present with this status.
 */
export type PhaseStatus = 'completed' | 'failed' | 'skipped' | 'skipped-due-to-upstream';
export interface PhaseResult {
    phase: number;
    label: string;
    status: PhaseStatus;
    timing: number;
    artifacts: string[];
    outputDir: string;
    error?: string;
    agenticsAgents?: {
        total: number;
        responded: number;
        domains: string[];
    };
}
export interface AutoChainResult {
    traceId: string;
    runDir: string;
    phases: PhaseResult[];
    totalTiming: number;
    success: boolean;
    executionMode: ExecutionMode;
    scenarioBranch?: string;
    commitHash?: string;
    githubUrl?: string;
    /**
     * ADR-PIPELINE-093 §Rule 3 — phases whose prerequisites were unreachable
     * after Ruflo retry. Surfaces to `formatAutoChainForDisplay` as a final
     * banner warning. Mirrors `manifest.json.blocked_phases` and
     * `status.json.blocked_phases`; present (possibly `[]`) on every result
     * so downstream consumers treat the shape as stable.
     */
    blockedPhases?: Array<{
        phase: string;
        missing: ReadonlyArray<string>;
    }>;
}
/** Canonical slot names in `.agentics/plans/`. */
export type PlanSlot = 'sparc' | 'adrs' | 'ddd' | 'tdd' | 'prompts' | 'implementation';
/** Per-slot promotion counts + MISSING detection. */
export interface PlanPromotionSummary {
    readonly counts: Record<PlanSlot, number>;
    readonly missing_slots: PlanSlot[];
    readonly total_copied: number;
    readonly total_skipped: number;
}
/**
 * Shared table-driven promotion routine (ADR-PIPELINE-092, Rules 1–5).
 *
 * Walks `PLAN_SLOT_SOURCES` for every slot, picks the best source via
 * `pickBestSourceForSlot`, promotes the source into the slot, then runs
 * any additive sources on top. Emits the `[PLANS] promoted ...` stderr
 * summary and one `[PLANS] MISSING <slot>` line per empty-and-unrecoverable
 * slot. Returns the summary so callers (final safety-net call) can merge
 * `planPromotion` into `manifest.json`.
 */
export declare function promotePlanningArtifacts(runDir: string, projectRoot: string): PlanPromotionSummary;
/**
 * Merge the ADR-PIPELINE-092 `planPromotion` block into `runDir/manifest.json`.
 * Read-modify-write pattern mirrors `writeExecutionBlockToManifest`.
 */
export declare function writePlanPromotionToManifest(runDir: string, summary: PlanPromotionSummary): void;
/**
 * Copy whatever planning artifacts exist from ~/.agentics/runs/<traceId>/
 * to .agentics/plans/ in the current working directory. Uses .agentics/plans/
 * instead of plans/ to avoid colliding with any existing plans/ folder in the
 * project (e.g., SPARC artifacts checked into the repo). Skips files that
 * already exist with identical content to avoid unnecessary duplication.
 *
 * Called after every phase so even if later phases fail, earlier artifacts
 * are still available.
 */
/**
 * ADR-PIPELINE-074: scaffold body for `src/logger.ts`.
 *
 * Uses `node:async_hooks` AsyncLocalStorage so concurrent Express/Hono
 * requests NEVER cross-contaminate log lines. The legacy
 * `let currentCorrelationId` module-level mutable has been removed; any
 * generator that reintroduces it is caught by PGV-016.
 *
 * Exports:
 *   - `Logger` interface with info/warn/error/child
 *   - `createLogger(service)` factory
 *   - `runWithCorrelation(id, fn)` — wraps an async scope with the ID
 *   - `getCorrelationId()` — returns the ID for the current async scope
 *   - `setCorrelationId(id)` — legacy shim; mutates the current store
 */
export declare const LOGGER_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-074)\n// Correlation IDs flow through an AsyncLocalStorage so concurrent requests\n// never cross-contaminate log lines. Import runWithCorrelation + createLogger\n// from here; NEVER reach for a module-level mutable to store the ID.\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nexport interface Logger {\n  info(event: string, data?: Record<string, unknown>): void;\n  warn(event: string, data?: Record<string, unknown>): void;\n  error(event: string, error: Error, data?: Record<string, unknown>): void;\n  child(bindings: Record<string, unknown>): Logger;\n}\n\ninterface LoggerContext {\n  correlationId?: string;\n  bindings: Record<string, unknown>;\n}\n\nconst storage = new AsyncLocalStorage<LoggerContext>();\n\n/**\n * Run `fn` with `correlationId` installed in the current async scope.\n * Every log line emitted inside `fn` and its async descendants will carry\n * this ID, and it will NOT leak to other concurrent requests.\n */\nexport function runWithCorrelation<T>(correlationId: string, fn: () => T): T {\n  const parent = storage.getStore();\n  const ctx: LoggerContext = {\n    correlationId,\n    bindings: parent?.bindings ?? {},\n  };\n  return storage.run(ctx, fn);\n}\n\n/** Returns the correlation ID for the current async scope, if any. */\nexport function getCorrelationId(): string | undefined {\n  return storage.getStore()?.correlationId;\n}\n\n/**\n * Back-compat shim \u2014 deprecated. Retained for legacy callers, but\n * SHOULD NOT be used inside request handlers. Use runWithCorrelation.\n * Under AsyncLocalStorage, this mutates the current store in place;\n * outside an async scope it is a silent no-op.\n */\nexport function setCorrelationId(id: string | undefined): void {\n  const ctx = storage.getStore();\n  if (ctx) ctx.correlationId = id;\n}\n\nexport function createLogger(service: string): Logger {\n  const build = (bindings: Record<string, unknown>): Logger => {\n    const emit = (level: string, event: string, extra?: Record<string, unknown>): void => {\n      const ctx = storage.getStore();\n      const entry = {\n        timestamp: new Date().toISOString(),\n        level,\n        service,\n        event,\n        ...(ctx?.correlationId ? { correlationId: ctx.correlationId } : {}),\n        ...bindings,\n        ...(ctx?.bindings ?? {}),\n        ...extra,\n      };\n      process.stderr.write(JSON.stringify(entry) + '\\n');\n    };\n    return {\n      info: (event, data) => emit('info', event, data),\n      warn: (event, data) => emit('warn', event, data),\n      error: (event, err, data) => emit('error', event, {\n        error: err.message,\n        stack: err.stack,\n        ...data,\n      }),\n      child: (childBindings) => build({ ...bindings, ...childBindings }),\n    };\n  };\n  return build({});\n}\n";
/**
 * ADR-PIPELINE-074: concurrency-correctness test emitted alongside
 * `src/logger.ts` in every generated project. Fails loudly if
 * AsyncLocalStorage wiring regresses.
 */
export declare const LOGGER_CONCURRENCY_TEST_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-074)\n// Proves correlation IDs do NOT leak across concurrent async tasks.\n// Works with vitest and jest \u2014 both expose describe/it/expect as globals.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { describe, it, expect } from 'vitest';\nimport { runWithCorrelation, getCorrelationId } from './logger.js';\n\ndescribe('logger correlation-id async scoping (ADR-PIPELINE-074)', () => {\n  it('does not leak correlation IDs across concurrent async tasks', async () => {\n    const results: Array<{ requested: string; observed: string | undefined }> = [];\n    const tasks: Promise<void>[] = [];\n    for (let i = 0; i < 50; i++) {\n      const id = `req-${i}`;\n      tasks.push(\n        runWithCorrelation(id, async () => {\n          await new Promise((r) => setTimeout(r, Math.random() * 10));\n          results.push({ requested: id, observed: getCorrelationId() });\n        }),\n      );\n    }\n    await Promise.all(tasks);\n    for (const r of results) {\n      expect(r.observed).toBe(r.requested);\n    }\n  });\n});\n";
/**
 * ADR-PIPELINE-068: scaffold body for `src/simulation-lineage.ts`.
 *
 * Exported so unit tests can write the file to a temp directory and
 * exercise the runtime behavior (env override, manifest walk, fallback)
 * without having to spin up the full pipeline.
 *
 * Invariants enforced by tests:
 * - Uses `readFileSync` + `fileURLToPath` (NEVER `require(`)
 * - Exports `loadSimulationLineage`, `requireSimulationLineage`,
 *   `formatLineageBanner`, and the legacy `loadSimulationId` alias
 * - Walks up at most 6 directories from the module location and from cwd
 */
export declare const SIMULATION_LINEAGE_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-068)\n// ESM-safe simulation lineage loader. Reads .agentics/plans/manifest.json\n// (or .agentics/runs/latest/manifest.json) using readFileSync \u2014 never\n// CommonJS require(). Do NOT reimplement this helper; import from it.\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve, dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport type SimulationLineageSource = 'env' | 'manifest' | 'fallback';\n\nexport interface SimulationLineage {\n  readonly simulationId: string;\n  readonly traceId: string;\n  readonly runId: string;\n  readonly source: SimulationLineageSource;\n  readonly manifestPath?: string;\n}\n\nconst MANIFEST_CANDIDATES: readonly string[] = [\n  '.agentics/plans/manifest.json',\n  '.agentics/runs/latest/manifest.json',\n];\n\nconst WALK_DEPTH = 6;\n\n/** Walk up from startDir looking for any manifest candidate path. */\nfunction findManifest(startDir: string): string | null {\n  let dir = startDir;\n  for (let i = 0; i < WALK_DEPTH; i++) {\n    for (const rel of MANIFEST_CANDIDATES) {\n      const candidate = resolve(dir, rel);\n      if (existsSync(candidate)) return candidate;\n    }\n    const parent = dirname(dir);\n    if (parent === dir) break;\n    dir = parent;\n  }\n  return null;\n}\n\nfunction moduleDir(): string {\n  try {\n    return dirname(fileURLToPath(import.meta.url));\n  } catch {\n    return process.cwd();\n  }\n}\n\n/**\n * Load the simulation lineage. Permissive \u2014 returns a fallback record when\n * nothing is available. Callers who need strict behavior should use\n * requireSimulationLineage() instead.\n *\n * Resolution order:\n *   1. AGENTICS_SIMULATION_ID / AGENTICS_TRACE_ID environment variables\n *   2. First manifest.json found walking up from this module (then cwd)\n *   3. Fallback record with source='fallback'\n */\nexport function loadSimulationLineage(): SimulationLineage {\n  const envSim = process.env['AGENTICS_SIMULATION_ID'];\n  const envTrace = process.env['AGENTICS_TRACE_ID'];\n  if (envSim) {\n    return {\n      simulationId: envSim,\n      traceId: envTrace ?? envSim,\n      runId: envSim,\n      source: 'env',\n    };\n  }\n\n  const startDirs = [moduleDir(), process.cwd()];\n  for (const start of startDirs) {\n    try {\n      const manifestPath = findManifest(start);\n      if (!manifestPath) continue;\n      const raw = JSON.parse(readFileSync(manifestPath, 'utf-8')) as Record<string, unknown>;\n      const runId = String(raw['run_id'] ?? raw['runId'] ?? '');\n      const simulationId = String(\n        raw['simulation_id'] ?? raw['simulationId'] ?? raw['execution_id'] ?? runId,\n      );\n      const traceId = String(raw['trace_id'] ?? raw['traceId'] ?? simulationId);\n      if (simulationId) {\n        return { simulationId, traceId, runId: runId || simulationId, source: 'manifest', manifestPath };\n      }\n    } catch {\n      // Try the next start dir. Never throw from the permissive loader.\n    }\n  }\n\n  return {\n    simulationId: 'sim-unknown',\n    traceId: 'trace-unknown',\n    runId: 'run-unknown',\n    source: 'fallback',\n  };\n}\n\n/**\n * Strict variant \u2014 throws ECLI-LIN-068 when no simulation lineage is\n * available. Use this at startup when the service MUST carry a real\n * simulation id (audit logs, ERP posts, etc.).\n */\nexport function requireSimulationLineage(): SimulationLineage {\n  const lineage = loadSimulationLineage();\n  if (lineage.source === 'fallback') {\n    throw new Error(\n      'ECLI-LIN-068: simulation lineage unavailable \u2014 set AGENTICS_SIMULATION_ID or place .agentics/plans/manifest.json in the project tree',\n    );\n  }\n  return lineage;\n}\n\n/**\n * Human-readable banner printed by the demo script when the loader falls\n * back. Makes the break visible instead of letting sim-unknown leak into\n * downstream audit logs and ERP posts.\n */\nexport function formatLineageBanner(lineage: SimulationLineage): string {\n  if (lineage.source !== 'fallback') {\n    return `simulation lineage: ${lineage.simulationId} (source: ${lineage.source})`;\n  }\n  return [\n    '',\n    '\u26A0\uFE0F  Simulation lineage unavailable (source: fallback)',\n    '    All audit entries and ERP posts will carry sim-unknown.',\n    '    Fix: place .agentics/plans/manifest.json in the project tree,',\n    '    or set AGENTICS_SIMULATION_ID=<run-id> before running the demo.',\n    '',\n  ].join('\\n');\n}\n\n/** Also exported under the legacy alias some older prompts referenced. */\nexport const loadSimulationId = (): string => loadSimulationLineage().simulationId;\n";
/**
 * ADR-PIPELINE-069: scaffold body for `src/circuit-breaker.ts`.
 *
 * Extracted from the legacy middleware.ts scaffold so generators can
 * `import { CircuitBreaker } from './circuit-breaker.js'` without pulling
 * the entire middleware module. middleware.ts now re-exports this symbol
 * so existing imports keep working.
 */
export declare const CIRCUIT_BREAKER_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-069)\n// Owned by the scaffold \u2014 do NOT redeclare CircuitBreaker in generated code.\nimport { createLogger } from './logger.js';\n\n/** Simple circuit breaker for external service calls. */\nexport class CircuitBreaker {\n  private failures = 0;\n  private state: 'closed' | 'open' | 'half-open' = 'closed';\n  private nextAttempt = 0;\n\n  constructor(\n    private readonly name: string,\n    private readonly threshold = 5,\n    private readonly cooldownMs = 30000,\n    private readonly logger = createLogger('circuit-breaker'),\n  ) {}\n\n  async call<T>(fn: () => Promise<T>): Promise<T> {\n    if (this.state === 'open') {\n      if (Date.now() < this.nextAttempt) {\n        throw new Error(`Circuit breaker '${this.name}' is OPEN \u2014 retry after ${new Date(this.nextAttempt).toISOString()}`);\n      }\n      this.state = 'half-open';\n      this.logger.info('circuit.half-open', { name: this.name });\n    }\n    try {\n      const result = await fn();\n      if (this.state === 'half-open') {\n        this.state = 'closed';\n        this.failures = 0;\n        this.logger.info('circuit.closed', { name: this.name });\n      }\n      return result;\n    } catch (err) {\n      this.failures++;\n      if (this.failures >= this.threshold) {\n        this.state = 'open';\n        this.nextAttempt = Date.now() + this.cooldownMs;\n        this.logger.warn('circuit.open', { name: this.name, failures: this.failures, retryAt: new Date(this.nextAttempt).toISOString() });\n      }\n      throw err;\n    }\n  }\n\n  getState(): string { return this.state; }\n}\n";
/**
 * ADR-PIPELINE-075: scaffold body for `src/persistence/repository.ts`.
 *
 * Defines the `Repository<T>` interface every stateful service should
 * depend on. Each entity is identified by `idOf(entity)`, validated by a
 * Zod schema on read, and bound to a table name for the SQLite backend.
 */
export declare const REPOSITORY_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-075)\n// Repository interface every stateful service should depend on.\n// Generators: use this instead of storing state in a Map<string, T>.\nimport type { ZodType } from 'zod';\n\nexport interface Repository<T> {\n  save(entity: T): Promise<void>;\n  get(id: string): Promise<T | null>;\n  list(filter?: Partial<T>): Promise<readonly T[]>;\n  delete(id: string): Promise<void>;\n}\n\nexport interface RepositoryOptions<T> {\n  /** How to extract the primary key from an entity. */\n  readonly idOf: (entity: T) => string;\n  /** Zod schema used to re-validate rows on load (SQLite JSON columns are untrusted). */\n  readonly schema: ZodType<T>;\n  /** Table name for SQLite backend. Must match /^[a-zA-Z_][a-zA-Z0-9_]*$/. */\n  readonly tableName: string;\n}\n\n/** Errors thrown by all Repository implementations. */\nexport class RepositoryError extends Error {\n  constructor(message: string, public readonly code: string) {\n    super(`${code}: ${message}`);\n    this.name = 'RepositoryError';\n  }\n}\n";
/**
 * ADR-PIPELINE-075: scaffold body for `src/persistence/in-memory-repository.ts`.
 *
 * Test-friendly `Repository<T>` implementation backed by a Map. Validates
 * on write AND read so test fixtures catch schema drift. Production
 * services should swap in SqliteRepository via the composition root.
 */
export declare const IN_MEMORY_REPO_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-075)\n// In-memory Repository<T> for tests. Not for production use.\nimport type { Repository, RepositoryOptions } from './repository.js';\n\nexport class InMemoryRepository<T> implements Repository<T> {\n  private readonly rows = new Map<string, T>();\n  constructor(private readonly options: RepositoryOptions<T>) {}\n\n  async save(entity: T): Promise<void> {\n    const validated = this.options.schema.parse(entity);\n    this.rows.set(this.options.idOf(validated), validated);\n  }\n\n  async get(id: string): Promise<T | null> {\n    const row = this.rows.get(id);\n    return row === undefined ? null : row;\n  }\n\n  async list(filter?: Partial<T>): Promise<readonly T[]> {\n    const all = Array.from(this.rows.values());\n    if (!filter) return all;\n    return all.filter(row =>\n      Object.entries(filter).every(\n        ([k, v]) => (row as Record<string, unknown>)[k] === v,\n      ),\n    );\n  }\n\n  async delete(id: string): Promise<void> {\n    this.rows.delete(id);\n  }\n\n  /** Test helper \u2014 never call from production code. */\n  clear(): void {\n    this.rows.clear();\n  }\n\n  /** Test helper \u2014 returns the current row count. */\n  get size(): number {\n    return this.rows.size;\n  }\n}\n";
/**
 * ADR-PIPELINE-075: scaffold body for `src/persistence/sqlite-repository.ts`.
 *
 * Production `Repository<T>` backed by better-sqlite3. Stores each entity
 * as a JSON column keyed by its primary key. Zod re-validates on read
 * because the JSON column is untrusted at runtime.
 *
 * Generated projects must add better-sqlite3 + @types/better-sqlite3 to
 * their package.json — the cross-cutting prompt footer reminds the coding
 * agent to include these deps.
 */
export declare const SQLITE_REPO_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-075)\n// SQLite-backed Repository<T> using better-sqlite3.\n// Requires: better-sqlite3 in dependencies, @types/better-sqlite3 in devDependencies.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { Repository, RepositoryOptions } from './repository.js';\nimport { RepositoryError } from './repository.js';\n\n// Minimal structural type \u2014 works with better-sqlite3 without importing it\n// into the scaffold (so the scaffold compiles even when the dependency\n// isn't installed in the pipeline's own test environment).\nexport interface BetterSqliteDatabase {\n  exec(sql: string): void;\n  prepare(sql: string): {\n    run(...params: any[]): { changes: number; lastInsertRowid: number | bigint };\n    get(...params: any[]): any;\n    all(...params: any[]): any[];\n  };\n}\n\nexport interface SqliteRepositoryDeps {\n  readonly db: BetterSqliteDatabase;\n}\n\nexport class SqliteRepository<T> implements Repository<T> {\n  constructor(\n    private readonly deps: SqliteRepositoryDeps,\n    private readonly options: RepositoryOptions<T>,\n  ) {\n    this.assertSafeTableName();\n    this.deps.db.exec(`\n      CREATE TABLE IF NOT EXISTS ${this.options.tableName} (\n        id TEXT PRIMARY KEY,\n        data TEXT NOT NULL,\n        updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))\n      );\n    `);\n  }\n\n  private assertSafeTableName(): void {\n    if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(this.options.tableName)) {\n      throw new RepositoryError(`unsafe table name: ${this.options.tableName}`, 'ECLI-REPO-001');\n    }\n  }\n\n  async save(entity: T): Promise<void> {\n    const validated = this.options.schema.parse(entity);\n    const id = this.options.idOf(validated);\n    const data = JSON.stringify(validated);\n    this.deps.db\n      .prepare(\n        `INSERT INTO ${this.options.tableName} (id, data) VALUES (?, ?)\n         ON CONFLICT(id) DO UPDATE SET data = excluded.data,\n           updated_at = strftime('%Y-%m-%dT%H:%M:%fZ','now')`,\n      )\n      .run(id, data);\n  }\n\n  async get(id: string): Promise<T | null> {\n    const row = this.deps.db\n      .prepare(`SELECT data FROM ${this.options.tableName} WHERE id = ?`)\n      .get(id) as { data: string } | undefined;\n    if (!row) return null;\n    return this.options.schema.parse(JSON.parse(row.data));\n  }\n\n  async list(filter?: Partial<T>): Promise<readonly T[]> {\n    const rows = this.deps.db\n      .prepare(`SELECT data FROM ${this.options.tableName}`)\n      .all() as Array<{ data: string }>;\n    const parsed = rows.map(r => this.options.schema.parse(JSON.parse(r.data)));\n    if (!filter) return parsed;\n    return parsed.filter(row =>\n      Object.entries(filter).every(\n        ([k, v]) => (row as Record<string, unknown>)[k] === v,\n      ),\n    );\n  }\n\n  async delete(id: string): Promise<void> {\n    this.deps.db.prepare(`DELETE FROM ${this.options.tableName} WHERE id = ?`).run(id);\n  }\n}\n";
/**
 * ADR-PIPELINE-075: scaffold body for `src/persistence/audit-repository.ts`.
 *
 * Append-only audit repository. NO update, NO delete — an audit entry is
 * committed and lives forever. Services that need to mutate a past entry
 * have to bypass the repository and talk raw SQL, which PGV and code
 * review will catch.
 */
export declare const AUDIT_REPO_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-075)\n// Append-only audit repository. No update, no delete by design.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { BetterSqliteDatabase } from './sqlite-repository.js';\n\nexport interface AuditEntry {\n  readonly entryId: string;\n  readonly prevHash: string;\n  readonly hash: string;\n  readonly payload: Record<string, unknown>;\n  readonly actor: string;\n  readonly action: string;\n  readonly entityType: string;\n  readonly entityId: string;\n  readonly createdAt: string;\n}\n\nexport interface AuditRepositoryDeps {\n  readonly db: BetterSqliteDatabase;\n}\n\nexport class AppendOnlyAuditRepository {\n  constructor(private readonly deps: AuditRepositoryDeps) {\n    this.deps.db.exec(`\n      CREATE TABLE IF NOT EXISTS audit_log (\n        sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n        entry_id TEXT NOT NULL UNIQUE,\n        prev_hash TEXT NOT NULL,\n        hash TEXT NOT NULL,\n        payload TEXT NOT NULL,\n        actor TEXT NOT NULL,\n        action TEXT NOT NULL,\n        entity_type TEXT NOT NULL,\n        entity_id TEXT NOT NULL,\n        created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))\n      );\n      CREATE INDEX IF NOT EXISTS idx_audit_log_entity\n        ON audit_log(entity_type, entity_id);\n    `);\n  }\n\n  append(entry: AuditEntry): void {\n    this.deps.db\n      .prepare(\n        `INSERT INTO audit_log\n         (entry_id, prev_hash, hash, payload, actor, action, entity_type, entity_id, created_at)\n         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n      )\n      .run(\n        entry.entryId,\n        entry.prevHash,\n        entry.hash,\n        JSON.stringify(entry.payload),\n        entry.actor,\n        entry.action,\n        entry.entityType,\n        entry.entityId,\n        entry.createdAt,\n      );\n  }\n\n  list(): readonly AuditEntry[] {\n    const rows = this.deps.db\n      .prepare(`SELECT * FROM audit_log ORDER BY sequence ASC`)\n      .all() as Array<{\n      entry_id: string;\n      prev_hash: string;\n      hash: string;\n      payload: string;\n      actor: string;\n      action: string;\n      entity_type: string;\n      entity_id: string;\n      created_at: string;\n    }>;\n    return rows.map(r => ({\n      entryId: r.entry_id,\n      prevHash: r.prev_hash,\n      hash: r.hash,\n      payload: JSON.parse(r.payload),\n      actor: r.actor,\n      action: r.action,\n      entityType: r.entity_type,\n      entityId: r.entity_id,\n      createdAt: r.created_at,\n    }));\n  }\n\n  listByEntity(entityType: string, entityId: string): readonly AuditEntry[] {\n    const rows = this.deps.db\n      .prepare(\n        `SELECT * FROM audit_log\n         WHERE entity_type = ? AND entity_id = ?\n         ORDER BY sequence ASC`,\n      )\n      .all(entityType, entityId) as Array<{\n      entry_id: string;\n      prev_hash: string;\n      hash: string;\n      payload: string;\n      actor: string;\n      action: string;\n      entity_type: string;\n      entity_id: string;\n      created_at: string;\n    }>;\n    return rows.map(r => ({\n      entryId: r.entry_id,\n      prevHash: r.prev_hash,\n      hash: r.hash,\n      payload: JSON.parse(r.payload),\n      actor: r.actor,\n      action: r.action,\n      entityType: r.entity_type,\n      entityId: r.entity_id,\n      createdAt: r.created_at,\n    }));\n  }\n\n  /** Total row count \u2014 used by verify() and reconciliation jobs. */\n  size(): number {\n    const row = this.deps.db\n      .prepare('SELECT COUNT(*) AS n FROM audit_log')\n      .get() as { n: number };\n    return row.n;\n  }\n}\n";
/**
 * ADR-PIPELINE-078: scaffold body for `src/persistence/canonical-json.ts`.
 *
 * Deterministic JSON serialization for audit hash chains and idempotency
 * keys. Follows JCS (RFC 8785) closely enough for the pipeline's needs:
 * object keys are sorted lexicographically at every depth; arrays preserve
 * order; strings, numbers, booleans, and null use standard JSON encoding.
 *
 * Rejects undefined, BigInt, and circular references. Date objects should
 * be serialized as ISO strings at the boundary BEFORE passing to this
 * function.
 */
export declare const CANONICAL_JSON_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-078)\n// Deterministic JSON for audit hash chains. Keys sorted at every depth.\n\nexport class CanonicalJsonError extends Error {\n  constructor(message: string) {\n    super(`ECLI-CJ-078: ${message}`);\n    this.name = 'CanonicalJsonError';\n  }\n}\n\n/**\n * Canonicalize `value` into a deterministic JSON string. Keys are sorted\n * at every level; arrays preserve order; primitives use standard encoding.\n */\nexport function canonicalJson(value: unknown): string {\n  const visited = new WeakSet<object>();\n  return serialize(value, visited);\n}\n\nfunction serialize(value: unknown, visited: WeakSet<object>): string {\n  if (value === undefined) {\n    throw new CanonicalJsonError('undefined is not canonicalizable \u2014 pass null instead');\n  }\n  if (value === null) return 'null';\n  if (typeof value === 'boolean') return value ? 'true' : 'false';\n  if (typeof value === 'number') {\n    if (!Number.isFinite(value)) {\n      throw new CanonicalJsonError(`non-finite number: ${String(value)}`);\n    }\n    return JSON.stringify(value);\n  }\n  if (typeof value === 'string') {\n    return JSON.stringify(value);\n  }\n  if (typeof value === 'bigint') {\n    throw new CanonicalJsonError('BigInt is not canonicalizable \u2014 convert to string at the boundary');\n  }\n  if (Array.isArray(value)) {\n    if (visited.has(value)) throw new CanonicalJsonError('circular reference in array');\n    visited.add(value);\n    const parts = value.map(item => serialize(item, visited));\n    visited.delete(value);\n    return '[' + parts.join(',') + ']';\n  }\n  if (typeof value === 'object') {\n    if (visited.has(value as object)) throw new CanonicalJsonError('circular reference in object');\n    visited.add(value as object);\n    const record = value as Record<string, unknown>;\n    const keys = Object.keys(record).sort();\n    const pairs: string[] = [];\n    for (const key of keys) {\n      const v = record[key];\n      if (v === undefined) continue;\n      pairs.push(JSON.stringify(key) + ':' + serialize(v, visited));\n    }\n    visited.delete(value as object);\n    return '{' + pairs.join(',') + '}';\n  }\n  throw new CanonicalJsonError(`unsupported value type: ${typeof value}`);\n}\n";
/**
 * ADR-PIPELINE-078: scaffold body for `src/persistence/audit-hash.ts`.
 *
 * Wraps `canonicalJson` with audit-log-specific conventions. Every
 * generated `AuditService.append()` method should call `hashAuditEntry`
 * rather than rolling its own `JSON.stringify + createHash` chain.
 */
export declare const AUDIT_HASH_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-078)\n// Audit hash-chain helper. Import hashAuditEntry instead of hand-rolling\n// createHash('sha256').update(JSON.stringify(...)).\nimport { createHash } from 'node:crypto';\nimport { canonicalJson } from './canonical-json.js';\n\nexport interface HashChainInput {\n  readonly prevHash: string;\n  readonly entryId: string;\n  readonly actor: string;\n  readonly action: string;\n  readonly entityType: string;\n  readonly entityId: string;\n  readonly payload: unknown;\n  readonly createdAt: string;\n}\n\n/**\n * Deterministically hash an audit entry's content + its link to the\n * previous entry. Payload keys are sorted at every depth so mutations\n * at any nesting level change the hash.\n */\nexport function hashAuditEntry(input: HashChainInput): string {\n  const body = canonicalJson({\n    prevHash: input.prevHash,\n    entryId: input.entryId,\n    actor: input.actor,\n    action: input.action,\n    entityType: input.entityType,\n    entityId: input.entityId,\n    payload: input.payload,\n    createdAt: input.createdAt,\n  });\n  return createHash('sha256').update(body).digest('hex');\n}\n";
/**
 * ADR-PIPELINE-077: scaffold body for `src/erp/schema-provenance.ts`.
 *
 * Every generated ERP adapter file (schema.ts, <system>-adapter.ts, etc.)
 * must export an `ERP_SCHEMA_PROVENANCE` constant of type
 * `ErpSchemaProvenance` declaring whether the schema was invented,
 * pulled from a catalog, or validated by an SME. Under
 * `AGENTICS_ERP_STRICT=true`, `assertErpProvenanceOrFail` refuses to
 * start when source='invented'. PGV-020 enforces presence, PGV-021
 * enforces reviewer + catalog_version on validated entries.
 */
export declare const ERP_SCHEMA_PROVENANCE_SCAFFOLD = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-077)\n// Provenance tag for generated ERP schemas. MANDATORY on every file\n// under src/erp/ that exports Zod schemas targeting an external ERP.\n\nexport type ErpProvenanceSource = 'invented' | 'catalog' | 'validated';\n\nexport interface ErpSchemaProvenance {\n  /** Target ERP system \u2014 e.g. 'Ramco Aviation', 'Oracle OPERA', 'SAP S/4HANA'. */\n  readonly erp_system: string;\n  /** Specific module the schema targets \u2014 'Flight Catering Order'. */\n  readonly module: string;\n  /** Validation stage: invented (no review), catalog (fields match), validated (SME-reviewed). */\n  readonly source: ErpProvenanceSource;\n  /** Version identifier of the catalog source, when known. */\n  readonly catalog_version: string | null;\n  /** ISO timestamp of SME review when source='validated'. */\n  readonly validated_at: string | null;\n  /** Reviewer name + role when source='validated'. */\n  readonly reviewer: { name: string; role: string } | null;\n  /** Free-text notes visible in startup logs and generated README. */\n  readonly notes: string;\n}\n\n/**\n * Assert an ERP adapter is allowed to run in the current environment.\n * Under AGENTICS_ERP_STRICT=true, source='invented' throws ECLI-ERP-077\n * and the process exits with code 77.\n */\nexport function assertErpProvenanceOrFail(\n  provenance: ErpSchemaProvenance,\n  env: NodeJS.ProcessEnv = process.env,\n): void {\n  const strict = env['AGENTICS_ERP_STRICT'] === 'true';\n  if (strict && provenance.source === 'invented') {\n    throw new Error(\n      `ECLI-ERP-077: ERP adapter for ${provenance.erp_system}/${provenance.module} has source='invented' ` +\n      `and AGENTICS_ERP_STRICT=true. Pilot deployment requires an SME review \u2014 set source='validated' ` +\n      `and provide reviewer + catalog_version before enabling strict mode.`,\n    );\n  }\n}\n\n/** Console-friendly banner for startup logs + demo output. */\nexport function formatProvenanceBanner(provenance: ErpSchemaProvenance): string {\n  const icon = provenance.source === 'validated' ? '\u2705' :\n               provenance.source === 'catalog'   ? '\uD83D\uDFE1' :\n                                                    '\u26A0\uFE0F ';\n  const lines: string[] = [\n    `${icon} ERP SCHEMA PROVENANCE \u2014 ${provenance.erp_system} / ${provenance.module}`,\n    `   source: ${provenance.source}`,\n  ];\n  if (provenance.catalog_version) lines.push(`   catalog: ${provenance.catalog_version}`);\n  if (provenance.validated_at) lines.push(`   validated: ${provenance.validated_at}`);\n  if (provenance.reviewer) lines.push(`   reviewer: ${provenance.reviewer.name} (${provenance.reviewer.role})`);\n  if (provenance.source === 'invented') {\n    lines.push(\n      '   ',\n      '   WARNING: This schema has not been validated against a real ERP document catalog.',\n      '   Pilot deployment requires an SME review before the first live call.',\n      \"   Set AGENTICS_ERP_STRICT=true in production to block runs until source='validated'.\",\n    );\n  }\n  return lines.join('\\n');\n}\n\n/** Convenience wrapper \u2014 prints the banner to stderr. */\nexport function printProvenanceBanner(provenance: ErpSchemaProvenance): void {\n  process.stderr.write(formatProvenanceBanner(provenance) + '\\n');\n}\n";
/**
 * ADR-PIPELINE-076: scaffold body for `src/api/base-app.ts` (Hono variant).
 *
 * Ships a wire-complete base app so the coding agent never writes
 * middleware/metrics/health plumbing from scratch. Generators extend
 * via `createBaseApp({...}).route('/api/<domain>', yourRouter)` instead
 * of rebuilding.
 *
 * Every generated project that imports `createBaseApp` gets:
 *   - correlation middleware (AsyncLocalStorage-scoped, ADR-074)
 *   - request logging with duration histogram
 *   - GET /health/live       (process up check)
 *   - GET /health/ready      (every readiness check passes)
 *   - GET /metrics           (Prometheus text, ADR-051)
 *   - structured error handler (last)
 */
export declare const BASE_APP_SCAFFOLD_HONO = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-076)\n// Wire-complete Hono app base. DO NOT rewrite \u2014 extend via\n// `createBaseApp(deps).route('/api/...', yourRouter)` from your routes module.\nimport { Hono } from 'hono';\nimport { randomUUID } from 'node:crypto';\nimport { runWithCorrelation, createLogger } from '../logger.js';\nimport { incrementCounter, recordHistogram, metricsHandler } from '../middleware.js';\n\nexport interface HealthCheck {\n  readonly name: string;\n  readonly check: () => Promise<{ ok: boolean; detail?: string }>;\n}\n\nexport interface BaseAppDeps {\n  readonly serviceName: string;\n  readonly version: string;\n  readonly readiness: readonly HealthCheck[];\n}\n\nexport interface BaseAppContextVariables {\n  correlationId: string;\n  startedAt: number;\n}\n\nconst baseLogger = createLogger('base-app');\n\n/**\n * Build the wire-complete base app.\n *\n * Returned Hono instance already has:\n *   - correlation ID middleware (AsyncLocalStorage-scoped)\n *   - request logging with duration histogram\n *   - GET /health/live       process-up check\n *   - GET /health/ready      runs every registered check\n *   - GET /metrics           Prometheus text format\n *   - structured error handler\n *\n * Add domain routes with `.route('/api/<domain>', yourRouter)`.\n */\nexport function createBaseApp(\n  deps: BaseAppDeps,\n): Hono<{ Variables: BaseAppContextVariables }> {\n  const app = new Hono<{ Variables: BaseAppContextVariables }>();\n\n  // Correlation ID \u2014 MUST be first so every downstream log carries it\n  app.use('*', async (c, next) => {\n    const id = c.req.header('x-correlation-id') ?? randomUUID();\n    c.set('correlationId', id);\n    c.set('startedAt', Date.now());\n    c.header('X-Correlation-Id', id);\n    await runWithCorrelation(id, async () => {\n      await next();\n    });\n  });\n\n  // Request logging + metrics\n  app.use('*', async (c, next) => {\n    await next();\n    const durationMs = Date.now() - c.get('startedAt');\n    const status = c.res.status;\n    baseLogger.info('http.request', {\n      method: c.req.method,\n      path: c.req.path,\n      status,\n      durationMs,\n    });\n    incrementCounter('http_requests_total', {\n      method: c.req.method,\n      status: String(status),\n    });\n    recordHistogram('http_request_duration_ms', durationMs, {\n      method: c.req.method,\n    });\n  });\n\n  // Liveness \u2014 always returns OK if the process is running\n  app.get('/health/live', (c) => {\n    return c.json({\n      status: 'ok',\n      service: deps.serviceName,\n      version: deps.version,\n      uptime_sec: Math.round(process.uptime()),\n    });\n  });\n\n  // Readiness \u2014 runs every registered check\n  app.get('/health/ready', async (c) => {\n    const results: Array<{ name: string; ok: boolean; detail?: string }> = [];\n    for (const check of deps.readiness) {\n      try {\n        const r = await check.check();\n        results.push({ name: check.name, ok: r.ok, ...(r.detail ? { detail: r.detail } : {}) });\n      } catch (err) {\n        results.push({\n          name: check.name,\n          ok: false,\n          detail: err instanceof Error ? err.message : String(err),\n        });\n      }\n    }\n    const allOk = results.every((r) => r.ok);\n    return c.json(\n      { status: allOk ? 'ready' : 'not-ready', checks: results },\n      allOk ? 200 : 503,\n    );\n  });\n\n  // Metrics \u2014 Prometheus text format\n  app.get('/metrics', (c) => {\n    return c.text(metricsHandler(), 200, {\n      'Content-Type': 'text/plain; version=0.0.4',\n    });\n  });\n\n  // Error handler \u2014 last, so it catches everything above\n  app.onError((err, c) => {\n    baseLogger.error('http.error', err as Error, {\n      method: c.req.method,\n      path: c.req.path,\n    });\n    const status = (err as { httpStatus?: number }).httpStatus ?? 500;\n    return c.json(\n      {\n        error: {\n          message: err.message,\n          code: (err as { code?: string }).code ?? 'INTERNAL_ERROR',\n        },\n      },\n      status as 500,\n    );\n  });\n\n  return app;\n}\n";
/**
 * ADR-PIPELINE-076: scaffold body for `src/api/base-app.ts` (Express variant).
 *
 * Used when the generator detects Express in Phase 4. Same guarantees as
 * the Hono variant — wires correlation / logging / liveness / readiness
 * / metrics / error handler in the correct order.
 */
export declare const BASE_APP_SCAFFOLD_EXPRESS = "// Auto-generated by Agentics pipeline (ADR-PIPELINE-076)\n// Wire-complete Express app base. DO NOT rewrite \u2014 mount your routes\n// onto the returned `app` instance instead.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport express from 'express';\nimport { randomUUID } from 'node:crypto';\nimport { runWithCorrelation, createLogger } from '../logger.js';\nimport { incrementCounter, recordHistogram, metricsHandlerExpress } from '../middleware.js';\n\nexport interface HealthCheck {\n  readonly name: string;\n  readonly check: () => Promise<{ ok: boolean; detail?: string }>;\n}\n\nexport interface BaseAppDeps {\n  readonly serviceName: string;\n  readonly version: string;\n  readonly readiness: readonly HealthCheck[];\n}\n\nconst baseLogger = createLogger('base-app');\n\nexport function createBaseApp(deps: BaseAppDeps): express.Express {\n  const app = express();\n  app.use(express.json({ limit: '1mb' }));\n\n  // Correlation ID \u2014 AsyncLocalStorage-scoped for the request's\n  // entire async continuation.\n  app.use((req: any, res: any, next: () => void) => {\n    const id = (req.headers['x-correlation-id'] as string) || randomUUID();\n    req.correlationId = id;\n    res.setHeader('X-Correlation-Id', id);\n    runWithCorrelation(id, next);\n  });\n\n  // Request logging + metrics\n  app.use((req: any, res: any, next: () => void) => {\n    const started = Date.now();\n    res.on('finish', () => {\n      const durationMs = Date.now() - started;\n      baseLogger.info('http.request', {\n        method: req.method,\n        path: req.path,\n        status: res.statusCode,\n        durationMs,\n      });\n      incrementCounter('http_requests_total', {\n        method: req.method,\n        status: String(res.statusCode),\n      });\n      recordHistogram('http_request_duration_ms', durationMs, {\n        method: req.method,\n      });\n    });\n    next();\n  });\n\n  app.get('/health/live', (_req, res) => {\n    res.json({\n      status: 'ok',\n      service: deps.serviceName,\n      version: deps.version,\n      uptime_sec: Math.round(process.uptime()),\n    });\n  });\n\n  app.get('/health/ready', async (_req, res) => {\n    const results: Array<{ name: string; ok: boolean; detail?: string }> = [];\n    for (const check of deps.readiness) {\n      try {\n        const r = await check.check();\n        results.push({ name: check.name, ok: r.ok, ...(r.detail ? { detail: r.detail } : {}) });\n      } catch (err) {\n        results.push({\n          name: check.name,\n          ok: false,\n          detail: err instanceof Error ? err.message : String(err),\n        });\n      }\n    }\n    const allOk = results.every((r) => r.ok);\n    res.status(allOk ? 200 : 503).json({\n      status: allOk ? 'ready' : 'not-ready',\n      checks: results,\n    });\n  });\n\n  app.get('/metrics', metricsHandlerExpress);\n\n  app.use((err: any, req: any, res: any, _next: () => void) => {\n    baseLogger.error('http.error', err as Error, {\n      method: req.method,\n      path: req.path,\n    });\n    const status = err?.httpStatus ?? 500;\n    res.status(status).json({\n      error: {\n        message: err?.message ?? 'Internal error',\n        code: err?.code ?? 'INTERNAL_ERROR',\n      },\n    });\n  });\n\n  return app;\n}\n";
/**
 * ADR-PIPELINE-069: Single source of truth for scaffold-owned modules.
 *
 * Every module the pipeline emits into `.agentics/plans/scaffold/src/` is
 * listed here with its public exports. The list is consumed by:
 *   - `copyPlanningArtifacts()`     — writes OWNED_MODULES.json sidecar
 *   - `prompt-generator.ts`         — injects "do not reimplement" block
 *   - `post-generation-validator.ts` PGV-012 — bans duplicate declarations
 *
 * When you add a new scaffold file, add it here in the same change.
 */
export interface OwnedScaffoldModule {
    readonly path: string;
    readonly exports: readonly string[];
}
export declare const OWNED_SCAFFOLD_MODULES: readonly OwnedScaffoldModule[];
export interface OwnedModulesManifest {
    readonly version: '1.0';
    readonly generated_at: string;
    readonly owned: readonly OwnedScaffoldModule[];
}
export declare function buildOwnedModulesManifest(now?: Date): OwnedModulesManifest;
export interface ScaffoldDuplicateFinding {
    /** Absolute path of the file that redeclares an owned export. */
    readonly path: string;
    /** The export name that collides. */
    readonly exportName: string;
    /** Scaffold path that owns the export. */
    readonly ownedPath: string;
}
/**
 * ADR-PIPELINE-069: Walk a project tree looking for generator-emitted files
 * that redeclare an export listed in OWNED_SCAFFOLD_MODULES. Skips:
 *   - the scaffold-owned files themselves (matched by basename)
 *   - test files
 *   - node_modules / dist / .agentics
 *
 * Returns one finding per (file, export) pair.
 */
export declare function detectScaffoldDuplicates(projectRoot: string, owned?: readonly OwnedScaffoldModule[]): ScaffoldDuplicateFinding[];
export declare function copyPlanningArtifacts(runDir: string, targetRoot?: string): void;
export declare function executeAutoChain(traceId: string, options?: AutoChainOptions): Promise<AutoChainResult>;
/**
 * Shape of a remote agent entry as recorded in the Phase 1 `manifest.json`.
 * `status` is typically `"success" | "invoked"` for ok and anything else for
 * errored (e.g., `"503"`, `"timeout"`, `"error"`). Mirrors the inline type in
 * `printPhase1Summary`.
 */
export interface RemoteAgentInvocation {
    readonly domain: string;
    readonly agent: string;
    readonly status: string;
}
/** Snapshot of the remote enrichment fleet taken from `manifest.agents_invoked`. */
export interface RemoteEnrichmentSnapshot {
    readonly available: string[];
    readonly errored: string[];
    /** Raw entries from the manifest, kept for dossier context plumbing. */
    readonly entries: RemoteAgentInvocation[];
}
/**
 * Read `manifest.agents_invoked` from the run dir and partition into
 * successful vs errored remote enrichment agents. ADR-PIPELINE-091 §5.
 *
 * Treats `status === "success"` and `status === "invoked"` as available; any
 * other status (including HTTP error codes, `"timeout"`, `"error"`) is
 * counted as errored. Missing / unreadable manifest => empty lists.
 */
export declare function readRemoteEnrichmentSnapshot(runDir: string): RemoteEnrichmentSnapshot;
/**
 * Build the `execution` block that ADR-PIPELINE-091 §5 writes back into
 * `runDir/manifest.json`. Pure function so it can be unit-tested without
 * spinning up the actual pipeline.
 */
export declare function computeExecutionBlock(rufloResults: ReadonlyArray<PrimaryPhaseExecutionResult | null | undefined>, enrichment: RemoteEnrichmentSnapshot): {
    engineering_tier: 'ruflo-local' | 'template';
    tier_counts: {
        'ruflo-local': number;
        template: number;
    };
    enrichment: {
        remote_agents_available: string[];
        remote_agents_errored: string[];
        enrichment_depth_pct: number | null;
    };
};
/**
 * Merge the ADR-091 `execution` block into `runDir/manifest.json` in-place.
 * Reads the existing manifest, sets `execution`, writes it back with the
 * same mode/encoding convention used elsewhere in this file. Non-fatal on
 * I/O or JSON errors — the pipeline continues if manifest merge fails.
 */
export declare function writeExecutionBlockToManifest(runDir: string, block: ReturnType<typeof computeExecutionBlock>): void;
/**
 * Per-phase gate outcomes accumulated across the auto-chain execution.
 * Populated as each phase's gate runs, then flushed to `manifest.json`
 * at pipeline completion so downstream consumers (MCP `agentics-status`
 * tool, final banner) see a stable schema.
 */
interface GateAccumulator {
    readonly blocked: BlockedPhase[];
    /** per-phase list of input paths that the gate produced via Ruflo */
    readonly producedByGate: Record<GatePhaseId, string[]>;
    /** optional scaffold-language skip record (Rule 5) */
    phase5bSkipped: {
        reason: string;
        detected: string;
        template: string;
    } | null;
}
/**
 * ADR-PIPELINE-093 — merge `blocked_phases`, per-phase
 * `phase{N}_inputs_produced_by_gate`, and `phase5b_skipped` into
 * `runDir/manifest.json`. Read-modify-write pattern mirrors
 * `writeExecutionBlockToManifest` / `writePlanPromotionToManifest`.
 *
 * `blocked_phases` is always present (empty array when no phase blocked).
 * The per-phase `inputs_produced_by_gate` keys are always present so
 * downstream readers can treat them as a stable schema.
 */
export declare function writeGateBlockToManifest(runDir: string, acc: GateAccumulator): void;
/**
 * ADR-PIPELINE-093 §Rule 3 (surface b) — same gate-block payload, written
 * into `runDir/status.json` so the CLI `status` command + MCP
 * `agentics-status` tool carry `blocked_phases` and the per-phase
 * `phase{N}_inputs_produced_by_gate` arrays alongside the ADR-088 keys.
 *
 * Read-modify-write pattern matches the CLI's local `updateStatus` helper
 * (`src/cli/index.ts`:~2501). Best-effort: if `status.json` does not exist
 * (e.g. running outside the MCP fast-return path), the file is created so
 * the gate block is always observable regardless of entry point.
 *
 * Both `writeGateBlockToManifest` and this function should be called from
 * the same accumulator snapshot so manifest.json and status.json stay in
 * sync. The CLI-surfaced `status.json` is the source of truth for the MCP
 * `agentics-status` tool (which shells out to `agentics status`).
 */
export declare function writeGateBlockToStatusJson(runDir: string, acc: GateAccumulator): void;
type ScaffoldLanguage = 'typescript' | 'python' | 'go' | 'rust' | 'unknown';
/**
 * Detect the target project language from Phase 1 manifest.json
 * (`project.language`) first, then falls back to common project root
 * marker files. Returns `'unknown'` when no signal is available — the
 * caller decides whether to skip or proceed in that case.
 */
/**
 * ADR-PIPELINE-093 §Rule 5 — single arbiter for which scaffold template set
 * `copyPlanningArtifacts` should emit. Called ONCE per invocation so the TS
 * block and the Python block gate on the same decision.
 *
 * - `typescript`            → emit TS, skip Python, no manifest record.
 * - `python`                → skip TS, emit Python, no manifest record.
 * - `go`|`rust`|`unknown`   → skip both, record `phase5b_skipped` with the
 *                             detected language and `template: 'typescript'`
 *                             (kept for Scenario-5 compatibility — the
 *                             skip block's shape is the ADR-093 schema).
 *
 * The detected-language + template-name pair in `skipped` matches what the
 * pre-093-fix gate wrote to `manifest.json`, so downstream status.json /
 * MCP consumers don't see a shape change on the mismatch path.
 */
export declare function decideScaffoldEmission(detected: ScaffoldLanguage): {
    emitTs: boolean;
    emitPy: boolean;
    skipped: null | {
        reason: 'language-mismatch';
        detected: string;
        template: string;
    };
};
export declare function detectProjectLanguage(projectRoot: string, phase1Manifest?: Record<string, unknown>): ScaffoldLanguage;
/**
 * Format the auto-chain result for stdout display.
 * This is the consolidated pipeline summary that surfaces Phase 2-6 details
 * to callers who only see stdout (e.g., Claude Code rendering `agentics ask`).
 */
export declare function formatAutoChainForDisplay(result: AutoChainResult): string;
/**
 * ADR-094 Decision 4 — Phase 6 always emits a phase-result entry. When an
 * upstream phase ends in `failed` or `blocked`, every downstream phase that
 * has not already been pushed gets a `skipped-due-to-upstream` entry. This
 * preserves the `chainResult.phases[]` trace contract: every run produces
 * an entry per phase, regardless of where the chain ended.
 *
 * Mutates `phases` in place. Idempotent — phases already present on the list
 * are not re-pushed. Exported for unit tests; production callers go through
 * the early-return sites in `executeAutoChain`.
 */
export declare function pushSkippedDueToUpstream(phases: PhaseResult[], upstream: {
    phase: number;
    label: string;
    reason: string;
}, runDir: string): void;
export {};
//# sourceMappingURL=auto-chain.d.ts.map