import { z } from "zod"; /** * Threshold at which a spec must be marked needs-clarification rather than * proceeding to sprint decomposition. Mirrors the planner agent's autonomous * mode rule. Scores are 0..10 inclusive. */ export declare const AMBIGUITY_BLOCK_THRESHOLD = 7; export declare const PrioritySchema: z.ZodEnum<["must-have", "should-have", "nice-to-have"]>; export type Priority = z.infer; export declare const EstimatedComplexitySchema: z.ZodEnum<["low", "medium", "high"]>; export type EstimatedComplexity = z.infer; /** * Lifecycle of a plan spec. * * - `draft` — planner just emitted, no sprints run yet * - `needs-clarification` — planner refused to fully decompose: ambiguityScore * >= 7 OR open questions remain. The pipeline will not run sprints from * this spec until status flips to `ready`. * - `ready` — clarifications resolved (or never needed), pipeline may proceed * - `in-progress` — at least one sprint has started * - `completed` — all sprints finished * - `abandoned` — planner or user explicitly dropped this spec */ export declare const PlanSpecStatusSchema: z.ZodEnum<["draft", "needs-clarification", "ready", "in-progress", "completed", "abandoned"]>; export type PlanSpecStatus = z.infer; export declare const PlanSpecModeSchema: z.ZodEnum<["greenfield", "brownfield"]>; export type PlanSpecMode = z.infer; /** * Categories the planner uses to group clarifying questions. Matches the * categories listed in `.claude/agents/bober-planner.md` Phase 2. */ export declare const ClarificationCategorySchema: z.ZodEnum<["scope", "user-personas", "data-model", "tech-constraints", "design-ux", "integrations", "non-functional", "error-handling", "integration-risk", "pattern-conflict", "regression-risk", "other"]>; export type ClarificationCategory = z.infer; export declare const ClarificationOptionSchema: z.ZodObject<{ /** Short label shown to the user (e.g. "A", "B", "Custom") */ label: z.ZodString; /** What this option means in plain English */ description: z.ZodString; }, "strip", z.ZodTypeAny, { description: string; label: string; }, { description: string; label: string; }>; export type ClarificationOption = z.infer; export declare const ClarificationQuestionSchema: z.ZodObject<{ questionId: z.ZodString; category: z.ZodEnum<["scope", "user-personas", "data-model", "tech-constraints", "design-ux", "integrations", "non-functional", "error-handling", "integration-risk", "pattern-conflict", "regression-risk", "other"]>; /** The question itself — should end with a "?" */ question: z.ZodString; /** Optional multiple-choice options, including an "Other" escape hatch */ options: z.ZodOptional, "many">>; /** Planner's recommended answer based on codebase evidence */ recommendation: z.ZodOptional; /** * How much this question contributes to the overall ambiguityScore. * Useful for the user to know which questions matter most to resolve. */ ambiguityWeight: z.ZodOptional; }, "strip", z.ZodTypeAny, { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }, { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }>; export type ClarificationQuestion = z.infer; export declare const ResolvedClarificationSchema: z.ZodObject<{ questionId: z.ZodString; /** The user-supplied answer (free-form, may reference an option label) */ answer: z.ZodString; /** ISO 8601 timestamp when the answer was recorded */ resolvedAt: z.ZodString; /** Who answered: "user" (interactive) or "planner" (autonomous self-answer) */ resolvedBy: z.ZodDefault>; }, "strip", z.ZodTypeAny, { answer: string; questionId: string; resolvedAt: string; resolvedBy: "user" | "planner"; }, { answer: string; questionId: string; resolvedAt: string; resolvedBy?: "user" | "planner" | undefined; }>; export type ResolvedClarification = z.infer; export declare const FeatureSpecSchema: z.ZodObject<{ featureId: z.ZodString; title: z.ZodString; description: z.ZodString; priority: z.ZodEnum<["must-have", "should-have", "nice-to-have"]>; acceptanceCriteria: z.ZodArray; dependencies: z.ZodDefault>; estimatedComplexity: z.ZodOptional>; /** Legacy field kept for backward compat — prefer estimatedComplexity */ estimatedSprints: z.ZodOptional; }, "strip", z.ZodTypeAny, { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies: string[]; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }, { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies?: string[] | undefined; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }>; export type FeatureSpec = z.infer; export declare const PlanSpecSchema: z.ZodObject<{ specId: z.ZodString; version: z.ZodDefault; title: z.ZodString; description: z.ZodString; status: z.ZodEnum<["draft", "needs-clarification", "ready", "in-progress", "completed", "abandoned"]>; mode: z.ZodEnum<["greenfield", "brownfield"]>; features: z.ZodArray; acceptanceCriteria: z.ZodArray; dependencies: z.ZodDefault>; estimatedComplexity: z.ZodOptional>; /** Legacy field kept for backward compat — prefer estimatedComplexity */ estimatedSprints: z.ZodOptional; }, "strip", z.ZodTypeAny, { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies: string[]; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }, { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies?: string[] | undefined; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }>, "many">; assumptions: z.ZodDefault>; outOfScope: z.ZodDefault>; /** * Self-rated ambiguity 0..10. >= AMBIGUITY_BLOCK_THRESHOLD must result in * status === "needs-clarification" with at least one open question. */ ambiguityScore: z.ZodOptional; /** Open questions awaiting user answer. Empty when status is ready/completed. */ clarificationQuestions: z.ZodDefault; /** The question itself — should end with a "?" */ question: z.ZodString; /** Optional multiple-choice options, including an "Other" escape hatch */ options: z.ZodOptional, "many">>; /** Planner's recommended answer based on codebase evidence */ recommendation: z.ZodOptional; /** * How much this question contributes to the overall ambiguityScore. * Useful for the user to know which questions matter most to resolve. */ ambiguityWeight: z.ZodOptional; }, "strip", z.ZodTypeAny, { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }, { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }>, "many">>; /** Question/answer history, both autonomous self-answers and user inputs */ resolvedClarifications: z.ZodDefault>; }, "strip", z.ZodTypeAny, { answer: string; questionId: string; resolvedAt: string; resolvedBy: "user" | "planner"; }, { answer: string; questionId: string; resolvedAt: string; resolvedBy?: "user" | "planner" | undefined; }>, "many">>; techStack: z.ZodDefault>; techNotes: z.ZodOptional>; nonFunctionalRequirements: z.ZodDefault>; constraints: z.ZodDefault>; sprints: z.ZodOptional>; metadata: z.ZodOptional>; createdAt: z.ZodString; updatedAt: z.ZodString; completedAt: z.ZodOptional; }, "strip", z.ZodTypeAny, { createdAt: string; status: "completed" | "draft" | "needs-clarification" | "ready" | "in-progress" | "abandoned"; mode: "greenfield" | "brownfield"; description: string; specId: string; version: number; title: string; features: { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies: string[]; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }[]; assumptions: string[]; outOfScope: string[]; clarificationQuestions: { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }[]; resolvedClarifications: { answer: string; questionId: string; resolvedAt: string; resolvedBy: "user" | "planner"; }[]; techStack: string[]; nonFunctionalRequirements: unknown[]; constraints: string[]; updatedAt: string; ambiguityScore?: number | undefined; techNotes?: Record | undefined; sprints?: unknown[] | undefined; metadata?: Record | undefined; completedAt?: string | undefined; }, { createdAt: string; status: "completed" | "draft" | "needs-clarification" | "ready" | "in-progress" | "abandoned"; mode: "greenfield" | "brownfield"; description: string; specId: string; title: string; features: { description: string; title: string; featureId: string; priority: "must-have" | "should-have" | "nice-to-have"; acceptanceCriteria: string[]; dependencies?: string[] | undefined; estimatedComplexity?: "high" | "medium" | "low" | undefined; estimatedSprints?: number | undefined; }[]; updatedAt: string; version?: number | undefined; assumptions?: string[] | undefined; outOfScope?: string[] | undefined; ambiguityScore?: number | undefined; clarificationQuestions?: { category: "other" | "scope" | "user-personas" | "data-model" | "tech-constraints" | "design-ux" | "integrations" | "non-functional" | "error-handling" | "integration-risk" | "pattern-conflict" | "regression-risk"; questionId: string; question: string; options?: { description: string; label: string; }[] | undefined; recommendation?: string | undefined; ambiguityWeight?: number | undefined; }[] | undefined; resolvedClarifications?: { answer: string; questionId: string; resolvedAt: string; resolvedBy?: "user" | "planner" | undefined; }[] | undefined; techStack?: string[] | undefined; techNotes?: Record | undefined; nonFunctionalRequirements?: unknown[] | undefined; constraints?: string[] | undefined; sprints?: unknown[] | undefined; metadata?: Record | undefined; completedAt?: string | undefined; }>; export type PlanSpec = z.infer; export interface CreateSpecOptions { mode?: PlanSpecMode; status?: PlanSpecStatus; ambiguityScore?: number; clarificationQuestions?: ClarificationQuestion[]; assumptions?: string[]; outOfScope?: string[]; techStack?: string[]; } /** * Create a new plan specification with sensible defaults. */ export declare function createSpec(title: string, description: string, features: Omit[], options?: CreateSpecOptions): PlanSpec; /** * Return true when the spec has unresolved clarification questions. * * NOTE: This checks question state only, NOT spec.status — `status` is * downstream of this. If you want "is the pipeline blocked?", check * `spec.status === "needs-clarification" || hasOpenClarifications(spec)` * instead, or use `isPipelineReady(spec)`. */ export declare function hasOpenClarifications(spec: PlanSpec): boolean; /** * Return true when the pipeline is allowed to run sprints from this spec. * Combines the explicit status check with the question-resolution check. */ export declare function isPipelineReady(spec: PlanSpec): boolean; /** * Return the questions that haven't been answered yet. */ export declare function getOpenClarifications(spec: PlanSpec): ClarificationQuestion[]; /** * Record an answer to a clarification question. Returns a new spec — does * not mutate. If this answer was the last open question, the spec status * flips from `needs-clarification` to `ready`. * * Throws if the questionId doesn't exist on the spec. */ export declare function resolveClarification(spec: PlanSpec, questionId: string, answer: string, resolvedBy?: ResolvedClarification["resolvedBy"]): PlanSpec; //# sourceMappingURL=spec.d.ts.map