/**
 * Workflow management library.
 *
 * Workflows are directory bundles with a WORKFLOW.md containing YAML frontmatter.
 * They optionally contain subagents/, skills/, and plugins/ subdirectories that
 * are composed at runtime by `agents run <workflow>`.
 */
import type { AgentId } from './types.js';
/**
 * The `loop:` block as it appears in WORKFLOW.md frontmatter (YAML, snake_case).
 * Parsed defensively and translated to the camelCase LoopConfig the driver
 * consumes (src/lib/loop.ts). See docs/execution.md.
 */
export interface LoopConfigRaw {
    /** Stop condition. Only `signal` is supported today. */
    until?: 'signal';
    /** Hard cap on iterations. */
    max_iterations?: number;
    /** Token hard-cap, enforced outside the agent. */
    budget?: number;
    /** Delay between iterations ("0" back-to-back, "30m" paces). */
    interval?: string;
}
/**
 * The `verify:` sub-block of a `for_each:` construct (issue #343).
 *
 * Each produced item's stage teammate can be gated by a panel of independent
 * skeptics: `votes` of them run (as teammates that depend on the stage), and
 * `keep_if` records how their verdicts converge (`majority` / `all` / `any`).
 * The vote-counting itself is a downstream concern — the declarative layer's
 * job is to expand the panel; see `expandForEach`.
 */
export interface ForEachVerifySpec {
    /** Subagent / agent id that plays skeptic for each item. */
    agent: string;
    /** Prompt template for each skeptic (`{{item}}`, `{{index}}` substituted). */
    prompt?: string;
    /** How many independent skeptics run per item (>= 1). */
    votes: number;
    /** Convergence rule for keeping a finding. */
    keep_if: 'majority' | 'all' | 'any';
}
/**
 * The `for_each:` block as it appears in WORKFLOW.md frontmatter (issue #343).
 *
 * Declarative dynamic fan-out: a producer emits a list at runtime, one stage
 * teammate runs per produced item (runtime-computed N), optionally followed by
 * a `verify` panel. This is a thin declarative layer over the existing teams
 * substrate — each expanded teammate is staged into the supervisor's
 * mid-flight-add path (`AgentManager.spawn`), NOT a new engine. See
 * `expandForEach` and `src/lib/teams/forEach.ts`.
 *
 * Parsed defensively (mirrors `parseLoopBlock`): a malformed block drops to
 * undefined rather than passing a bad shape downstream.
 */
export interface ForEachSpec {
    /**
     * The producer: a shell command or subagent whose stdout is a JSON array (or
     * newline-delimited list) of items. Alternatively `itemsRef` names a prior
     * step's output. At least one of the two is expected for a runnable spec.
     */
    produce?: string;
    /** `${step}`-style reference to a prior step's produced list. */
    itemsRef?: string;
    /** Subagent / agent id for the per-item stage. */
    agent: string;
    /** Base name for the expanded teammates (default `item`). */
    name?: string;
    /** Per-item prompt template (`{{item}}`, `{{index}}` substituted). */
    prompt: string;
    /** In-flight cap — maps to the supervisor's wave size (>= 1). */
    concurrency?: number;
    /**
     * Hard runaway guard: the producer can emit at most this many items before
     * the fan-out is truncated. Defaults to `DEFAULT_FOR_EACH_CAP`.
     */
    max_items?: number;
    /** Optional convergence gate run after each item's stage. */
    verify?: ForEachVerifySpec;
}
/**
 * Hard upper bound on items a single `for_each` expands, absent an explicit
 * `max_items`. A guard against a runaway producer spawning unbounded teammates
 * (acceptance criterion in issue #343). Anthropic's Dynamic Workflows cap at
 * 1000; we default lower and let authors raise it deliberately.
 */
export declare const DEFAULT_FOR_EACH_CAP = 256;
/** Parsed WORKFLOW.md frontmatter. */
export interface WorkflowFrontmatter {
    name: string;
    description: string;
    model?: string;
    tools?: string[];
    skills?: string[];
    mcpServers?: string[];
    allowedAgents?: string[];
    /**
     * Secrets bundle names this workflow needs (e.g. `linear.app`, `github.com`).
     * When `agents run <workflow>` resolves a workflow, these are unioned into the
     * effective `--secrets` list and resolved from the macOS Keychain before spawn.
     * Pass `--no-auto-secrets` to skip this injection.
     */
    secrets?: string[];
    /**
     * Optional loop block: wraps the workflow in a bounded until-condition loop
     * (issue #332). When present, `agents run <workflow>` honors it without a
     * `--loop` flag. Validated/coerced in parseWorkflowFrontmatter.
     */
    loop?: LoopConfigRaw;
    /**
     * Optional declarative dynamic fan-out (issue #343): a producer emits a list
     * and one stage teammate runs per item, with an optional verify panel.
     * Validated/coerced in parseWorkflowFrontmatter via `parseForEachBlock`.
     */
    forEach?: ForEachSpec;
}
/** A workflow found during repo discovery. */
export interface DiscoveredWorkflow {
    name: string;
    path: string;
    frontmatter: WorkflowFrontmatter;
    subagentCount: number;
}
/** A workflow in central storage (~/.agents/workflows/ or ~/.agents/.system/workflows/). */
export interface InstalledWorkflow {
    name: string;
    path: string;
    frontmatter: WorkflowFrontmatter;
    subagentCount: number;
}
/** Parse WORKFLOW.md frontmatter from a workflow directory. Returns null if invalid. */
export declare function parseWorkflowFrontmatter(workflowDir: string): WorkflowFrontmatter | null;
/**
 * Defensively coerce a frontmatter `loop:` value into a LoopConfigRaw.
 *
 * Mirrors the asStringArray discipline above: a malformed field is dropped to
 * undefined rather than passed through, so the loop driver never sees a bad
 * shape. Returns undefined when `loop:` is absent or not an object, or when no
 * recognized field survives coercion (an all-garbage block is treated as
 * "no loop", not "empty loop").
 *
 * Field rules:
 *   - until:          only the literal `signal` is accepted; anything else dropped.
 *   - max_iterations: a finite positive integer; non-numbers/<=0 dropped.
 *   - budget:         a finite positive number (tokens); non-numbers/<=0 dropped.
 *   - interval:       a string (e.g. "0", "30m"); non-strings dropped.
 */
export declare function parseLoopBlock(v: unknown): LoopConfigRaw | undefined;
/**
 * Defensively coerce a frontmatter `verify:` sub-block into a ForEachVerifySpec.
 *
 * Requires an `agent`; drops the whole block otherwise (a verify panel with no
 * skeptic is meaningless). `votes` defaults to 1 (a single confirmation) and
 * `keep_if` to `majority`; both are validated against their allowed shapes.
 */
export declare function parseVerifyBlock(v: unknown): ForEachVerifySpec | undefined;
/**
 * Defensively coerce a frontmatter `for_each:` block into a ForEachSpec (issue
 * #343). Mirrors `parseLoopBlock`'s discipline: a block missing the two
 * load-bearing fields (`agent` + `prompt`) drops to undefined rather than
 * passing a half-formed spec to the expander. Optional numeric/verify fields
 * are individually validated and dropped when malformed.
 */
export declare function parseForEachBlock(v: unknown): ForEachSpec | undefined;
/** One teammate produced by expanding a `for_each` spec against a produced list. */
export interface ForEachTeammate {
    /** `stage` runs the per-item work; `verify` is a skeptic in the panel. */
    role: 'stage' | 'verify';
    /** Unique teammate name within the team (used for `--after` linkage). */
    name: string;
    /** Subagent / agent id this teammate runs as. */
    agentType: string;
    /** Fully-resolved prompt (template variables already substituted). */
    prompt: string;
    /** Names of sibling teammates this one waits on (`--after` semantics). */
    after: string[];
    /** The produced item this teammate handles. */
    item: string;
    /** Zero-based index of the item in the (capped) produced list. */
    itemIndex: number;
    /** For `verify` teammates: 1-based vote index and the panel's gate config. */
    vote?: number;
    votes?: number;
    keep_if?: 'majority' | 'all' | 'any';
}
/** Result of expanding a `for_each` spec: the teammates plus cap accounting. */
export interface ForEachExpansion {
    teammates: ForEachTeammate[];
    /** How many items the producer emitted (pre-cap). */
    producedCount: number;
    /** How many items were actually expanded (post-cap). */
    usedCount: number;
    /** producedCount - usedCount; > 0 means the runaway guard truncated. */
    truncated: number;
    /** The effective per-`for_each` item cap that was applied. */
    cap: number;
}
/**
 * Substitute `{{item}}` / `{{index}}` (and 1-based `{{n}}`) in a prompt
 * template. Unknown `{{...}}` tokens are left intact so a template can carry
 * placeholders the caller resolves elsewhere.
 */
export declare function renderForEachTemplate(template: string, item: string, index: number): string;
/**
 * Expand a `for_each` spec against a producer's output into concrete teammate
 * descriptors (issue #343) — the heart of the declarative fan-out.
 *
 * Pure and deterministic: no I/O, no spawning. `src/lib/teams/forEach.ts`
 * feeds the result to `AgentManager.spawn`, staging each descriptor into the
 * supervisor's existing mid-flight-add path — so this reuses the dynamic-DAG
 * substrate rather than introducing a new engine.
 *
 * For N produced items (capped at `spec.max_items` / `DEFAULT_FOR_EACH_CAP`):
 *   - one `stage` teammate per item, depending on `producerName` if given;
 *   - when `verify` is set, `votes` `verify` teammates per item, each
 *     depending on that item's stage teammate.
 *
 * Names are unique (`<base>-<n>` and `<base>-<n>-verify-<v>`) so `--after`
 * linkage and the teams cycle check carry over unchanged.
 */
export declare function expandForEach(spec: ForEachSpec, items: string[], opts?: {
    producerName?: string;
}): ForEachExpansion;
/**
 * Decide which subagent .md stems a workflow may use, given the discovered
 * subagent files and the parsed `allowedAgents` frontmatter. This is the
 * fail-closed security boundary for issue #324:
 *
 *   - `allowedAgents === undefined` (field absent)  -> NO restriction; allow all.
 *   - `allowedAgents === []`        (present, empty) -> allow ZERO; copy none.
 *   - `allowedAgents = [a, b]`                       -> allow only those stems.
 *
 * An explicit empty array must NEVER widen to "allow all" — that would copy
 * every subagent definition into the run, granting MORE access than declared.
 *
 * `available` are the .md filenames found in subagents/ (e.g. `security.md`).
 * Returns the stems to copy and any allowedAgents entries with no matching file.
 */
export declare function resolveAllowedSubagents(available: string[], allowedAgents: string[] | undefined): {
    allowedStems: string[];
    missing: string[];
};
/** The Claude tool an orchestrator uses to dispatch subagents. Must stay in a
 *  workflow's `--tools` allowlist whenever the workflow ships dispatchable
 *  subagents, or the orchestrator has no way to reach them. */
export declare const SUBAGENT_DISPATCH_TOOL = "Task";
/**
 * Keep the subagent-dispatch tool (`Task`) in a `tools:`-restricted workflow's
 * allowlist when the workflow actually ships subagents to dispatch.
 *
 * A WORKFLOW.md `tools:` list becomes Claude's `--tools` set, which *restricts*
 * the available built-ins. An orchestrator whose `subagents/` files were just
 * copied into the shared agents dir but whose `tools:` omits `Task` cannot
 * reach any of them — it silently no-ops (observed: the run emits only "I'll
 * wait for the completion notification" and exits). Omitting `Task` while
 * shipping a `subagents/` dir is always an authoring miss, so we re-add it at
 * the source rather than relying on every workflow author to remember.
 *
 * Returns `tools` unchanged when the workflow has no subagents or already lists
 * `Task`; otherwise appends `Task`.
 */
export declare function ensureSubagentDispatchTool(tools: string[], hasSubagents: boolean): string[];
/**
 * Prune stale workflow-managed subagent files from the shared per-agent agents
 * dir before a scoped run writes the permitted set (issue #401, follow-up to
 * #324). A prior *unrestricted* run of a workflow copies every subagent
 * definition into the shared `~/.claude/agents/` dir; a later run that declares
 * `allowedAgents:` copies only the permitted ones but never removes the
 * leftovers — so an unlisted subagent stays on disk and remains dispatchable,
 * silently defeating the fail-closed scope.
 *
 * Fail-closed fix (mirrors how `cleanupWorkflowMcpConfig` only tears down what
 * the workflow itself created): remove any file that (a) belongs to THIS
 * workflow's subagents/ — matched by filename, i.e. the workflow-managed
 * universe — and (b) is NOT in the permitted set. A user's own hand-placed
 * subagent shares no name with a workflow subagent file, so it is never
 * touched. Permitted files are left in place; the caller (re)copies them.
 *
 * `workflowSubagentFiles` are the .md filenames in the workflow's subagents/
 * dir (e.g. `security.md`); `allowedStems` are the permitted stems from
 * `resolveAllowedSubagents`. Returns the filenames actually removed.
 */
export declare function pruneStaleWorkflowSubagents(sharedAgentsDir: string, workflowSubagentFiles: string[], allowedStems: string[]): string[];
/** Count subagent .md files in a workflow's subagents/ directory. */
export declare function countWorkflowSubagents(workflowDir: string): number;
/** Convert a canonical agents-cli workflow bundle into a Kimi flow skill. */
export declare function transformWorkflowForKimi(workflowPath: string, name: string): string;
/**
 * Convert a canonical agents-cli workflow bundle into an Antigravity workflow
 * markdown file. Antigravity discovers workflows as flat `<name>.md` files under
 * `~/.gemini/config/global_workflows/` (scanned by `agy` at startup) and exposes
 * each as a `/<name>` slash command. Frontmatter carries the required `description`
 * plus the shared `agents_workflow` ownership marker so agents-cli never clobbers a
 * user-authored workflow of the same name.
 */
export declare function transformWorkflowForAntigravity(workflowPath: string, name: string): string;
/** Convert a canonical agents-cli workflow bundle into an OpenClaw Lobster file. */
export declare function transformWorkflowForOpenClaw(workflowPath: string, name: string): string;
/** Marker comment prefix written into agents-cli-managed Grok `.rhai` files. */
export declare const GROK_WORKFLOW_MARKER = "agents_workflow";
/**
 * Convert a canonical agents-cli workflow bundle into a Grok native Rhai
 * workflow script. Grok discovers saved workflows as
 * `~/.grok/workflows/<name>.rhai` (and project `.grok/workflows/`) and exposes
 * each as a `/<name>` slash command (enabled by default since v0.2.111).
 *
 * The projection is a single-agent orchestrator that feeds the WORKFLOW.md
 * body as the agent prompt plus the caller's `args.prompt` (or string args).
 * Multi-phase fan-out is left to hand-authored Rhai — agents-cli's job is to
 * land the orchestrator instructions in the native path.
 */
export declare function transformWorkflowForGrok(workflowPath: string, name: string): string;
/** Read the agents_workflow marker from a Grok `.rhai` file, if present. */
export declare function grokWorkflowMarker(filePath: string): string | null;
/**
 * Plugin `workflows/` directories in discovery order (project → user → system →
 * extra). Used by name resolution and listing so a plugin-packaged workflow is
 * runnable via `agents run <name>` without a separate install into
 * ~/.agents/workflows/ (Phase 5 packaging). Within the plugin band, project
 * plugins beat user/system plugins (same first-hit-wins as other layers).
 *
 * Pass `pluginName` to restrict to one plugin (for `name@plugin` resolution).
 */
export declare function listPluginWorkflowDirs(cwd?: string, pluginName?: string): string[];
/**
 * True when `ref` is a single bare workflow / source identifier (no path
 * separators, no `..`, no `@`). Name lookup must not path-join multi-segment
 * or traversal refs into search roots. `name@source` is parsed separately.
 */
export declare function isBareWorkflowName(ref: string): boolean;
/** Parsed `agents run` workflow reference (docs/07-entrypoints). */
export interface ParsedWorkflowRef {
    /** Workflow directory name (WORKFLOW.md parent). */
    name: string;
    /**
     * When set (`name@source`), pin resolution to that source only:
     * a plugin name, or an enabled extra-repo alias.
     */
    source?: string;
}
/**
 * Parse a workflow run target: optional `workflow:` type prefix and optional
 * `@source` pin. Returns null when the form is not a valid name lookup.
 */
export declare function parseWorkflowRef(ref: string): ParsedWorkflowRef | null;
/**
 * Resolve an `agents run <workflow>` reference.
 *
 * Directories are accepted anywhere on disk when they contain WORKFLOW.md.
 * Name lookup precedence (docs/07-entrypoints): project > user > plugin > extra > system.
 * Pin a source with `name@plugin` or `name@extra-alias` (optional `workflow:` prefix).
 */
export declare function resolveWorkflowRef(ref: string, cwd?: string): string | null;
/**
 * Discover all workflow directories (those containing WORKFLOW.md) in a local path.
 * Checks if the path itself is a workflow, then scans a top-level workflows/ subdirectory,
 * then falls back to scanning all immediate subdirectories.
 */
export declare function discoverWorkflowsFromRepo(repoPath: string): DiscoveredWorkflow[];
/**
 * List all workflows in central storage + plugin packages.
 * Precedence: user > plugin > extra > system (first writer wins; project is
 * cwd-scoped and handled by resolveWorkflowRef / the resource handler).
 */
export declare function listInstalledWorkflows(cwd?: string): Map<string, InstalledWorkflow>;
/** Copy a workflow directory into user central storage (~/.agents/workflows/<name>/). */
export declare function installWorkflowCentrally(sourcePath: string, name: string): {
    success: boolean;
    error?: string;
};
/** Move a workflow from user central storage to trash. */
export declare function removeWorkflow(name: string): {
    success: boolean;
    error?: string;
};
/** List workflow names synced into a specific agent version home. */
export declare function listWorkflowsForAgent(agent: AgentId, versionHome: string): string[];
/**
 * True when workflow `name` materialized in `agent`'s version home byte-matches
 * what the writer would produce NOW from `sourcePath` — the content-drift
 * predicate `agents doctor` uses. Layout-aware per the same per-harness map the
 * writer (`syncWorkflowToVersion`) and detector use: Claude/default copy the
 * whole WORKFLOW.md tree (recursive dir compare); Kimi/Antigravity/OpenClaw/Grok
 * render one transformed file; Goose renders a recipe YAML. Antigravity's target
 * is the shared HOME-global dir, not a per-version path. Returns false when the
 * home copy is absent (surfaced as `missing` at the name level, not here).
 */
export declare function workflowContentMatches(agent: AgentId, versionHome: string, name: string, sourcePath: string): boolean;
/** Copy a workflow directory into a version home at {versionHome}/workflows/<name>/. */
export declare function syncWorkflowToVersion(workflowPath: string, name: string, agent: AgentId, versionHome: string): {
    success: boolean;
    error?: string;
};
/** Remove a workflow from a specific agent version home. */
export declare function removeWorkflowFromVersion(agent: AgentId, version: string, name: string): {
    success: boolean;
    error?: string;
};
/** Iterate all installed (agent, version) pairs that support workflows. */
export declare function iterWorkflowsCapableVersions(filter?: {
    agent?: AgentId;
    version?: string;
}): Array<{
    agent: AgentId;
    version: string;
}>;
