import type { ClarificationQuestion, ClarificationRequest, NormalizedWorkflowSpec } from '../spec-intake/types.js';
import type { RenderedArtifact, SkillContext, WorkflowExecutionTarget } from './types.js';
export declare const WORKFORCE_PERSONA_INTENT_CANDIDATES: readonly ["agent-relay-workflow", "relay-orchestrator", "persona-authoring", "opencode-workflow-correctness", "architecture-plan", "documentation"];
export interface WorkforcePersonaRuntime {
    harness: string;
    model: string;
    systemPrompt?: string;
    harnessSettings?: {
        reasoning?: string;
        timeoutSeconds?: number;
    };
}
export interface WorkforcePersonaSelection {
    personaId: string;
    tier: string;
    runtime: WorkforcePersonaRuntime;
    rationale?: string;
    skills?: Array<{
        id: string;
        source: string;
        description: string;
    }>;
    env?: Record<string, string>;
}
export interface WorkforcePersonaExecutionResult {
    status: 'completed' | 'failed' | 'cancelled' | 'timeout';
    output: string;
    stderr: string;
    exitCode: number | null;
    durationMs: number;
    workflowRunId?: string;
    stepName?: string;
}
export interface WorkforcePersonaExecution extends Promise<WorkforcePersonaExecutionResult> {
    cancel(reason?: string): void;
    readonly runId: Promise<string>;
}
export interface WorkforcePersonaContext {
    selection: WorkforcePersonaSelection;
    sendMessage(task: string, options?: WorkforcePersonaSendOptions): WorkforcePersonaExecution;
}
export interface WorkforcePersonaModule {
    useRunnablePersona?: (intent: string, options?: WorkforceRunnablePersonaOptions) => WorkforcePersonaContext;
    useRunnableSelection?: (selection: unknown, options?: WorkforceRunnableSelectionOptions) => WorkforcePersonaContext;
}
export interface WorkforceSelectionModule {
    usePersona(intent: string, options?: WorkforceSelectionOptions): unknown;
}
export interface WorkforceSelectionOptions {
    tier?: string;
    profile?: unknown;
    profileId?: string;
    installRoot?: string;
}
export interface WorkforceRunnablePersonaOptions extends WorkforceSelectionOptions {
    harness?: string;
    commandOverrides?: Record<string, string>;
}
export interface WorkforceRunnableSelectionOptions {
    harness?: string;
    installRoot?: string;
    commandOverrides?: Record<string, string>;
}
export interface WorkforcePersonaSendOptions {
    workingDirectory?: string;
    name?: string;
    mode?: 'one-shot';
    responseFormat?: 'structured-json-or-fenced-artifact';
    timeoutSeconds?: number;
    inputs?: Record<string, string | number | boolean>;
    installSkills?: boolean;
    env?: NodeJS.ProcessEnv;
    signal?: AbortSignal;
    onProgress?: (chunk: {
        stream: 'stdout' | 'stderr';
        text: string;
    }) => void;
}
export interface WorkforcePersonaWriterOptions {
    repoRoot: string;
    workflowName?: string;
    targetMode: WorkflowExecutionTarget;
    outputPath: string;
    relevantFiles?: Array<{
        path: string;
        content?: string;
    }>;
    timeoutSeconds?: number;
    installSkills?: boolean;
    installRoot?: string;
    tier?: string;
    /** Absolute path to the source spec file when known. The writer task references it so the persona can Read the spec instead of receiving it inline. */
    specPath?: string;
    env?: NodeJS.ProcessEnv;
    signal?: AbortSignal;
    onProgress?: (chunk: {
        stream: 'stdout' | 'stderr';
        text: string;
    }) => void;
    personaIntentCandidates?: readonly string[];
    resolver?: WorkforcePersonaResolver;
    skillContext?: SkillContext;
    validationFeedback?: WorkforcePersonaValidationFeedback;
}
export interface WorkforcePersonaValidationFeedback {
    errors: string[];
    previousContent: string;
    previousAttempts?: WorkforcePersonaPrewriteRepairAttempt[];
}
export interface WorkforcePersonaPrewriteRepairAttempt {
    attempt: number;
    requestedFixes: string[];
    returnedErrors: string[];
}
export interface WorkforcePersonaWriterMetadata {
    personaId: string;
    tier: string;
    harness: string;
    model: string;
    promptDigest: string;
    warnings: string[];
    runId: string | null;
    source: 'package';
    selectedIntent: string;
    responseFormat: 'structured-json' | 'fenced-artifact';
    outputPath: string;
    promptInputs: {
        workflowName: string;
        targetMode: WorkflowExecutionTarget;
        repoRoot: string;
        relevantFileCount: number;
    };
}
export interface WorkforcePersonaWriterResult {
    artifact: {
        content: string;
        metadata: Record<string, unknown>;
    };
    metadata: WorkforcePersonaWriterMetadata;
}
export interface PersonaResponseParseOptions {
    repoRoot?: string;
    readFileText?: (path: string) => string;
    /**
     * Optional `Date.now()`-style ms timestamp captured *before* the writer
     * subprocess was spawned. When set, the parser's "stdout was truncated
     * but a file exists on disk at expectedPath" fallback only fires for a
     * file whose mtime is newer than this — i.e. one this writer call
     * produced — so the parser cannot accidentally accept a stale leftover
     * artifact from a prior attempt as the current writer's output.
     *
     * Without this timestamp the parser treats the file as untrusted and
     * skips the disk fallback (preserving prior behavior).
     */
    writerInvokedAtMs?: number;
    /**
     * Optional stat-by-path used by the disk fallback. Defaults to
     * `fs.statSync(path)` swallowing ENOENT to `undefined`. Override for
     * deterministic tests of the freshness check without touching the real
     * filesystem.
     */
    statFile?: (path: string) => {
        mtimeMs: number;
    } | undefined;
}
export interface ResolvedWorkforcePersonaContext {
    source: 'package';
    intent: string;
    context: WorkforcePersonaContext;
    warnings: string[];
}
export type WorkforcePersonaResolver = (intents: readonly string[], options: {
    tier?: string;
    installRoot?: string;
}) => Promise<ResolvedWorkforcePersonaContext>;
type WorkforcePackageImporter = (packageName: string) => Promise<object>;
export declare class WorkforcePersonaWriterError extends Error {
    readonly warnings: string[];
    constructor(message: string, warnings?: string[]);
}
export declare class WorkforcePersonaClarificationError extends WorkforcePersonaWriterError {
    readonly questions: ClarificationQuestion[];
    constructor(questions: ClarificationQuestion[], warnings?: string[]);
}
interface ParsedPersonaResponse {
    content?: string;
    metadata: Record<string, unknown>;
    responseFormat: WorkforcePersonaWriterMetadata['responseFormat'] | 'needs-clarification';
    clarification?: ClarificationRequest;
}
export declare function writeWorkflowWithWorkforcePersona(spec: NormalizedWorkflowSpec, options: WorkforcePersonaWriterOptions): Promise<WorkforcePersonaWriterResult>;
export declare function defaultWorkforcePersonaResolver(intents: readonly string[], options?: {
    tier?: string;
    installRoot?: string;
}): Promise<ResolvedWorkforcePersonaContext>;
export declare function resolveWorkforcePersonaContextWithModules(intents: readonly string[], options: {
    tier?: string;
    installRoot?: string;
}, moduleResult: {
    module: WorkforcePersonaModule;
    source: 'package';
    warnings: string[];
}, loadSelectionModule?: () => Promise<{
    module: WorkforceSelectionModule;
    source: 'package';
    warnings: string[];
}>): Promise<ResolvedWorkforcePersonaContext>;
export declare function loadWorkforcePersonaModule(importPackage?: WorkforcePackageImporter): Promise<{
    module: WorkforcePersonaModule;
    source: 'package';
    warnings: string[];
}>;
export declare function loadWorkforceSelectionModule(importPackage?: WorkforcePackageImporter): Promise<{
    module: WorkforceSelectionModule;
    source: 'package';
    warnings: string[];
}>;
export declare function buildWorkflowPersonaTask(spec: NormalizedWorkflowSpec, input: {
    workflowName: string;
    targetMode: WorkflowExecutionTarget;
    repoRoot: string;
    outputPath: string;
    relevantFiles: Array<{
        path: string;
        content?: string;
    }>;
    skillContext?: SkillContext;
    validationFeedback?: WorkforcePersonaValidationFeedback;
    specPath?: string;
}): string;
interface SummarizedSpec {
    spec: NormalizedWorkflowSpec;
    descriptionTruncated: boolean;
}
/**
 * Produces a writer-task-ready clone of the normalized spec with the
 * raw spec payload elided (it duplicates `description`) and `description`
 * + `targetContext` truncated when oversized. Keeps every structured
 * field intact — target files, constraints, evidence requirements, and
 * acceptance gates are short and are what the persona actually needs to
 * decompose the workflow.
 */
export declare function summarizeSpecForPersona(spec: NormalizedWorkflowSpec): SummarizedSpec;
interface SummarizedRelevantFiles {
    files: Array<{
        path: string;
        content: string | null;
        bytesOmitted?: number;
        omitted?: true;
    }>;
    includedCount: number;
}
/**
 * Caps the total byte budget of inlined relevant-file contents. Files past
 * the budget are listed as path-only entries so the persona still sees the
 * full list, and any individual file body is truncated at
 * `MAX_RELEVANT_FILE_BYTES`.
 */
export declare function summarizeRelevantFilesForPersona(relevantFiles: Array<{
    path: string;
    content?: string;
}>): SummarizedRelevantFiles;
export declare function parsePersonaWorkflowResponse(output: string, expectedPath: string, options?: PersonaResponseParseOptions): ParsedPersonaResponse;
/**
 * Walks `text` looking for the first top-level balanced `{ ... }` object
 * and parses it. String literals (including nested escape sequences) and
 * the brace-tracking are handled inline so the scanner is not confused by
 * a `}` that appears inside a JSON string value (e.g. the embedded
 * TypeScript source the writer returns inside `artifact.content`).
 *
 * Returns the parsed object or `null` when no balanced object exists or
 * the candidate substring is not valid JSON.
 */
export declare function extractFirstBalancedJsonObject(text: string): Record<string, unknown> | null;
export declare function applyPersonaArtifactToRenderedArtifact(base: RenderedArtifact, personaResult: WorkforcePersonaWriterResult): RenderedArtifact;
/**
 * Returns a list of human-readable mismatches between what the spec asked
 * the writer to ship and what the writer actually emitted. Empty array
 * means "writer output is consistent with the spec's declared intent" —
 * safe to proceed.
 *
 * This is complementary to `detectWorkflowIntentRegressions` in
 * workforce-persona-repairer.ts (which fires during the *repair* path).
 * That guard catches: "the original ship-a-PR workflow was replaced by a
 * placeholder during repair." This guard catches: "the writer's first
 * emit was already a placeholder even though the spec declared a PR-
 * shipping outcome."
 *
 * Heuristics:
 * - PR-shipping intent: if the spec's description contains markers like
 *   `Outcome: ... pull request`, `createGitHubStep`, `GitHubStepExecutor`,
 *   or `@agent-relay/github-primitive`, the workflow must import or
 *   reference at least one of `@agent-relay/github-primitive`,
 *   `GitHubStepExecutor`, or `createGitHubStep`.
 * - Step-count floor: when the spec is large enough that the writer
 *   should produce at least 8 real steps (heuristic: spec.description
 *   length > 4 KB), the workflow must have at least 4 `.step(...)` chain
 *   calls. Catches the master-executor stub shape whose top-level chain
 *   is just `prepare-context → lead-plan → materialize-child-workflows
 *   → final-signoff` with the actual impl work hidden inside string
 *   literals for child-workflow definitions (which don't run until the
 *   master step materializes them, and which the auto-fix loop has
 *   historically failed on).
 *
 * **Source-Text Analysis (AGENTS.md):** every workflow-side check
 * inspects the parsed TypeScript AST via `ts.createSourceFile`. Imports
 * come from `ImportDeclaration.moduleSpecifier`, identifier references
 * from `Identifier` walks, and `.step(...)` chain calls from
 * `CallExpression` nodes with a `step` property-access expression. This
 * rules out the verified false-negative the reviewers on #120 flagged:
 * a degenerate master-executor stub hiding `createGitHubStep` /
 * `.step("...")` inside string literals (nested-string child workflow
 * definitions) cannot fool the guard into thinking the work is there.
 * Mirrors the same approach `analyzeWorkflowSource` uses in
 * workforce-persona-repairer.ts — the canonical implementation for the
 * repair-time validator. Duplicated here rather than imported to avoid a
 * circular dependency back through the repairer module.
 *
 * Both checks are conservative — a healthy workflow trivially satisfies
 * them; they only fire on the failure mode this guard addresses.
 */
export declare function detectSpecIntentMismatch(spec: SpecIntentLike, workflowContent: string): string[];
export declare function stripGlobalGithubExecutorForMixedWorkflow(workflowContent: string): {
    content: string;
    stripped: boolean;
};
interface SpecIntentLike {
    description?: string;
    targetContext?: string | null;
    targetFiles?: readonly string[];
    desiredAction?: {
        summary?: string;
    };
    constraints?: readonly unknown[];
    acceptanceGates?: readonly unknown[];
    evidenceRequirements?: readonly unknown[];
}
export declare function markdownLabelFields(markdown: string): Map<string, string>;
export declare function hasExplicitWorkflowRunCwd(content: string): boolean;
/**
 * Awaits the harness-kit writer execution with a watchdog so a stuck
 * subprocess settle path can't hang the caller indefinitely.
 *
 * ⚠️  Known limitation: the watchdog uses `setTimeout`, which only fires
 * when Node's event loop is free to run timer callbacks. A hang in a
 * native libuv code path that does not yield (observed 2026-05-15: writer
 * authored 43 KB to disk + staged 12 files via the Write tool, then ricky
 * sat at 0% CPU for 60+ minutes without ever advancing past the
 * `Promise.all` await) prevents this watchdog from firing. The only
 * reliable hang-recovery in that scenario is an OS-level timeout outside
 * the process, e.g. `gtimeout --kill-after=30s 5400s ricky ...` in batch
 * mode. The JS watchdog here remains as a best-effort defense-in-depth
 * for the common half-open-pipe case.
 *
 * Background — production hang on 2026-05-15:
 * - claude writer subprocess ran to its harness-kit-declared timeout
 *   (3600s), got SIGTERM, then SIGKILL.
 * - The subprocess exited (gone from `ps`) but its stdio pipe stayed
 *   half-open with ~16 KB of buffered bytes. harness-kit's `finish()`
 *   resolution never fired because its `exit` handler was waiting on a
 *   `stdout` close that never came.
 * - Ricky's `await Promise.all([run, run.runId])` then hung at 0% CPU
 *   for an additional 60+ minutes with FD 4/5 = PIPE, blocking the
 *   master script from advancing to the next spec.
 *
 * This watchdog forces a settle at `timeoutSeconds + grace`. If it
 * fires, `run.cancel()` is invoked first so any subprocess handles the
 * runner still owns get released, then a WorkforcePersonaWriterError is
 * raised so the master loop can move on rather than block forever.
 *
 * The watchdog is opt-out by design: every caller already passes
 * `timeoutSeconds` via the persona's `harnessSettings`, so the watchdog
 * fires at most `grace` seconds after the harness-kit-internal timeout
 * was supposed to land. The happy path (writer settles before its own
 * timeout) clears the watchdog timer in the `finally` block and never
 * pays any wall-clock cost.
 */
export declare function waitForWriterWithWatchdog<R extends Promise<unknown> & {
    runId: Promise<string | null>;
    cancel?: () => void;
}>(run: R, timeoutSeconds: number | undefined, resolverWarnings: string[]): Promise<[Awaited<R>, string | null]>;
export interface PersonaDebugDumpInput {
    /** Which persona pass produced the output — keeps writer and reviewer dumps separate on disk. */
    kind: 'writer' | 'reviewer';
    /** Coarse reason for the dump so the operator can tell parse failures from non-completions at a glance. */
    reason: 'noncompletion' | 'parse-error' | 'no-content' | 'success' | 'spec-intent-mismatch';
    repoRoot: string;
    /** SHA-256 digest of the task prompt, used as the dump directory name so repeated runs against the same prompt overwrite a single entry. */
    promptDigest: string;
    /** The full task prompt that was sent to the harness; written so the operator can replay the spawn outside Ricky. */
    task: string;
    result: WorkforcePersonaExecutionResult;
    selection: WorkforcePersonaSelection;
    resolved: ResolvedWorkforcePersonaContext;
    /** Artifact path Ricky asked the persona to produce; recorded in the dump metadata for cross-referencing with the run state. */
    outputPath: string;
}
/**
 * Persists the raw persona output, the prompt that produced it, and the
 * selection metadata under `<repoRoot>/.workflow-artifacts/ricky-persona-debug/`
 * so operators can inspect what a Workforce persona actually returned when
 * the parser rejected it (or when explicit debug capture is requested via
 * `RICKY_PERSONA_DEBUG=1`).
 *
 * - On every failure path (`noncompletion` / `parse-error` / `no-content`)
 *   the dump is always written so failed runs are self-debuggable.
 * - On the `success` path the dump only runs when `RICKY_PERSONA_DEBUG=1`
 *   is set, so green production runs do not litter the artifact tree.
 *
 * Dump layout (one directory per `(kind, promptDigest)` pair):
 * - `output.raw.txt`   — the persona's stdout as captured by harness-kit
 * - `task.prompt.txt`  — the task body that was sent to the persona
 * - `meta.json`        — selection, status, exit code, stderr, durationMs
 *
 * Failures inside this helper are swallowed and surfaced through stderr —
 * the dump is debugging telemetry; it must never mask the original
 * writer/reviewer error.
 */
export declare function dumpPersonaDebug(input: PersonaDebugDumpInput): Promise<void>;
export {};
