/** * Single source of precedence for the workflow settings surfaces. * * Every workflow runtime (ralplan, ultragoal, deep-interview) reads its * settings through {@link resolveWorkflowSetting}; no runtime hand-rolls file * discovery, YAML/JSON parsing, or key extraction. The precedence is fixed: * * 1. project `.gjc/config.yml` * 2. user `/config.yml` (default `~/.gjc/agent/config.yml`) * 3. built-in default * * Project configuration always beats user configuration, and `config.yml` is * the primary settings surface: the legacy `settings.json` files (project and * config-root) are retired, their workflow values migrated into `config.yml` by * Settings once. The retained legacy source still applies while the migration * has NOT durably recorded ownership/completion for its key: the project source * until the per-key migrated-keys marker records the key, the config-root * source until the migration retires it. A completed migration owns the value * (a later `gjc config unset` sticks), so an owned key is never resurrected; * the project legacy sits above the agent config.yml, the config-root legacy * below it. Settings therefore writes exactly what the runtimes read: `gjc * config set gjc.ralplan.maxIterations 7` is honored by ralplan. * * `config.yml` uses the nested schema form (`gjc: { ralplan: { maxIterations } }`); * flat dotted keys are honored only while parsing a legacy `settings.json` * during migration (see Settings) or the retained-legacy fallback layer. * * This module must stay pure and acyclic: it imports only path helpers and the * pure `gjcRoot`/`dirs` utilities, never `Settings`, discovery/capability * loaders, or workflow runtimes. All config/agent paths are constructed inside * each resolver call (never at module scope) because `dirs.ts` caches directory * resolution at module load. */ export type WorkflowSettingKey = "gjc.deepInterview.ambiguityThreshold" | "gjc.ralplan.autoHandoff" | "gjc.ralplan.maxIterations" | "gjc.ralplan.maxReviewPassesPerLane" | "gjc.ultragoal.nudgeBudget"; export type WorkflowSettingLayer = "project-config" | "agent-config"; export type WorkflowSettingParseResult = { kind: "valid"; value: T; } | { kind: "invalid"; reason: string; }; export type WorkflowSettingDiagnosticStatus = "missing-file" | "empty-document" | "missing-key" | "invalid" | "valid"; export interface WorkflowSettingDiagnostic { layer: WorkflowSettingLayer; /** Lexical absolute candidate; missing paths stay actionable. */ path: string; format: "yaml" | "json"; status: WorkflowSettingDiagnosticStatus; classification?: "read" | "syntax" | "shape" | "value"; reason?: string; } export interface ResolveWorkflowSettingOptions { defaultValue: T; parse: (value: unknown) => WorkflowSettingParseResult; /** Omitted means "continue"; ralplan passes "throw" explicitly. */ invalidPolicy?: "throw" | "continue"; /** * The session's effective agent directory. Defaults to the process-global * `getAgentDir()`; an SDK embedder that created the session with * `createAgentSession({ agentDir })` must pass that directory here so the * agent-config layer matches the profile `Settings.init` loaded and * migrated, instead of inheriting an unrelated default-profile value. */ agentDir?: string; } export interface WorkflowSettingResolution { value: T; /** Canonical realpath for a winning existing file, or "default". */ source: string; diagnostics: readonly WorkflowSettingDiagnostic[]; } export type WorkflowSettingInvalidClassification = "read" | "syntax" | "shape" | "value"; /** Raised under the strict ("throw") invalid policy; stable properties for callers. */ export declare class WorkflowSettingError extends Error { readonly diagnostic: WorkflowSettingDiagnostic; readonly path: string; readonly layer: WorkflowSettingLayer; readonly classification: WorkflowSettingInvalidClassification; readonly reason: string; constructor(diagnostic: WorkflowSettingDiagnostic & { classification: WorkflowSettingInvalidClassification; reason: string; }); } /** * Extract a workflow key from a parsed settings document. Flat dotted keys are * honored only while parsing a legacy `settings.json` during migration (see * Settings) - `config.yml` uses the nested (schema) form, so the public * Settings/config CLI path (which addresses nested paths) can manage every * effective override. Flat keys are checked before the nested `gjc: { ... }` * shape (flat wins); an explicitly present `undefined` value counts as present. */ export declare function extractWorkflowSetting(document: unknown, key: WorkflowSettingKey, options?: { flat?: boolean; }): { present: boolean; value: unknown; malformedParent?: boolean; }; /** * Resolve a workflow setting across the fixed three-layer precedence (project * `.gjc/config.yml`, then user `/config.yml`, then the built-in * default). Returns the first valid configured value, otherwise * {@link options.defaultValue} with `source: "default"`. Diagnostics are * retained for unit tests and optional logging; runtime public wrappers expose * their existing compact result shapes. */ export declare function resolveWorkflowSetting(cwd: string, key: WorkflowSettingKey, options: ResolveWorkflowSettingOptions): Promise>;