import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { type Semver } from "./engine-compat.js"; export declare const HARNESS_TYPES: readonly ["pi", "opencode", "hermes"]; export type HarnessType = (typeof HARNESS_TYPES)[number]; export interface HarnessRuntimeInfo { harness_type: HarnessType; wired: boolean; } export declare const HARNESS_RUNTIME_INFO: Record; /** * Supported harness descriptor schema versions. Additive only across minors; an old * version is dropped only at a major bump paired with a `schemaVersion` bump. */ export declare const DEFAULT_SUPPORTED_SCHEMA_VERSIONS: readonly number[]; /** Schema versions still loadable but deprecated; the loader warns and continues. */ export declare const DEFAULT_DEPRECATED_SCHEMA_VERSIONS: readonly number[]; export interface HarnessConfig { schemaVersion: number; id: string; harness_type: HarnessType; wired: boolean; /** When true, a run resolving this harness demands run-level git-worktree isolation (auto-isolate even without an explicit `isolation`/`worktreeRequired` run option). */ worktreeRequired?: boolean; /** `worktreeRequired` was present but not a boolean (loader warns; treated as not-required). */ worktreeRequiredMalformed?: boolean; engineMin?: string; engineMinMalformed?: boolean; /** Mandatory tools required by this harness. If unavailable, we clean-skip execution. */ requiredTools?: string[]; /** Optional preferred tools for this harness. If unavailable, we degrade gracefully with a warning. */ preferredTools?: string[]; /** `requiredTools` was present but malformed (bare string, mixed array, non-array); an empty array is NOT malformed. Loader warns and clean-skips. */ requiredToolsMalformed?: boolean; /** `preferredTools` was present but malformed; loader warns and clean-skips (a preferred list must be a string array; an empty array is valid). */ preferredToolsMalformed?: boolean; /** Loader skipped this descriptor (e.g. engine.min above the running engine); kept in the registry so an explicit `--harness-config ` can clean-skip with the reason instead of silently falling back to pi. */ skipped?: boolean; skipReason?: string; displayName?: string; description?: string; trigger?: string; triggerRules?: Record; legacyHarnessType?: string; invalid?: boolean; invalidReason?: string; source: "project" | "user"; path?: string; raw: Record; } export type HarnessConfigRegistry = Map; export interface LoadHarnessConfigRegistryOptions { projectDir?: string; userDir?: string; onWarning?: (message: string) => void; /** Running engine version for the `engine.min` floor check. Defaults to this package's version. */ engineVersion?: Semver; /** Schema versions the loader accepts; defaults to DEFAULT_SUPPORTED_SCHEMA_VERSIONS. */ supportedSchemaVersions?: readonly number[]; /** Schema versions that still load but emit a deprecation warning. */ deprecatedSchemaVersions?: readonly number[]; } export interface ParseHarnessConfigDescriptorOptions { supportedSchemaVersions?: readonly number[]; } export declare function parseHarnessConfigDescriptor(content: string, source: "project" | "user", fileName?: string, opts?: ParseHarnessConfigDescriptorOptions): HarnessConfig | null; export declare function loadHarnessConfigRegistry(cwd: string, opts?: LoadHarnessConfigRegistryOptions): HarnessConfigRegistry; export declare function listHarnessConfigs(registry: HarnessConfigRegistry): HarnessConfig[]; export declare function renderHarnessConfigs(registry: HarnessConfigRegistry): string; export declare function registerHarnessConfigsCommand(pi: ExtensionAPI, opts: { cwd: string; }): void; /** A single layer of harness overrides (e.g. run-level, frontmatter, per-call). */ export interface HarnessOverrides { harness_type?: string; harness_config?: string; } /** * Resolve the final harness override set from an ordered list of layers, * lowest precedence first (e.g. [runLevel, frontmatter, perCall]). * * Higher-index layers override lower-index layers. An undefined layer is * skipped. Within a layer, a field that is `undefined` inherits the lower * layer's value; an explicit `"none"` is a real override (not inheritance). */ export declare function resolveHarnessLayers(layers: ReadonlyArray): { harness_type?: string; harness_config?: string; }; /** * Pure expansion of a resolved harness_config into concrete runWorkflow * override fields. Callers may merge this into the `agent()` call options * before scheduling work. */ export interface HarnessExpansion { harness_type: HarnessType; harness_config: string; wired: boolean; /** When not-wired due to a loader-skipped descriptor (e.g. engine.min), the specific reason; surfaced by the run-level clean-skip instead of the generic "not wired" message. */ skipReason?: string; contextMode?: string; inheritProjectContext?: boolean; inheritSkills?: boolean; inheritMainRules?: boolean; systemPromptMode?: string; tools?: string[]; disallowedTools?: string[]; /** Mandatory tools required by this harness expansion. */ requiredTools?: string[]; /** Optional preferred tools for this harness expansion. */ preferredTools?: string[]; /** Whether the harness execution is degraded due to missing preferred tools. */ degraded?: boolean; /** The reason why the harness execution is degraded. */ degradeReason?: string; stageCheckDefaults?: Record; agentOverrides?: Record; componentExtensions?: string[]; indexExtensions?: string[]; directoryModuleSelfFile?: boolean; frontendPathTriggers?: string[]; } /** * Expand a resolved harness_config (from the registry) into a concrete * `HarnessExpansion` with all agent/context/tool/stageCheck overrides * derived from the descriptor's raw payload. * * Pure — reads only the passed registry. When `readOnly` is true the * returned `tools` array will not include known write tool names. The * `applyToolPolicy` read-only fence also strips write tools as a final guard. */ export declare function expandHarnessConfig(opts: { harness_type?: string; harness_config?: string; registry: HarnessConfigRegistry; readOnly?: boolean; }): HarnessExpansion; /** * Check whether a given harness_type is wired (connected to the Pi * runtime). Unknown types are treated as not wired. */ export declare function isHarnessWired(harness_type?: string): boolean; /** * Produce a structured clean-skip payload so callers can short-circuit * when the active harness is not wired. */ export declare function harnessNotWiredSkip(selection: { harness_type?: string; harness_config?: string; reason?: string; }): { status: "harness-not-wired"; harness_type: string; harness_config: string; reason: string; }; /** * Pull a `--harness-type ` / `--harness-type=` / `--no-harness` flag out of a * raw args string, returning the harness type (if present) and the args with the * matched flag removed. The flag may appear anywhere; remaining args keep order * and are trimmed. Case-insensitive on the flag, not on the value. * * `--no-harness` maps to `harnessType: "none"`. */ export declare function extractHarnessTypeFlag(args: string): { harnessType?: string; rest: string; }; /** * Pull a `--harness-config ` or `--harness-config=` flag out of a raw * args string, returning the harness config (if present) and the args with the * flag removed. The flag may appear anywhere; remaining args keep order and * are trimmed. Case-insensitive on the flag, not on the value. */ export declare function extractHarnessConfigFlag(args: string): { harnessConfig?: string; rest: string; };