/** * @slowcook 0.19.0-α.44 — multifurcation pre-step. * * Some GitHub issues are not stories. They are programs of work disguised * as tickets ("everything according to mock", "rewrite the patient app", * "wire X to Y" where X and Y are whole subsystems). Forcing those * through refine produces a fuzzy mega-spec that no downstream agent can * reasonably implement. * * This module runs a cheap LLM pass BEFORE refine's relationship + * refinement calls. It returns either: * * - { kind: "one", rationale } — refine proceeds normally * - { kind: "many", sub_issues, rationale } — refine posts a * PM-facing proposal listing the proposed sub-issues + halts; the * PM decides whether to file the split. The original issue is * marked `slowcook-multifurcation-proposed` so refine doesn't loop. * * Sub-issue titles + summaries are PM-style by contract (see prompt * rules): intent-shaped, no file paths or pipeline names, ≤ 80 char * titles, 1-3 sentence summaries. Quality of the proposal is the * PM's call — the comment template makes editing easy. */ import type { LlmClient, Spec } from "@slowcook-ai/core"; /** * One existing spec the model needs to be aware of when proposing a * split, so it can mark sub-issues that overlap with active scope * INSTEAD of silently omitting them. The PM needs to see the full * picture, not a hidden side-channel. * * Built from `listActiveSpecs(repoRoot)` — a single line of Spec. */ export interface ActiveSpecDigest { story_id: string; title: string; summary: string; } export interface MultifurcationSubIssue { title: string; summary: string; /** Optional — titles of OTHER sub-issues this one depends on landing first. */ depends_on?: string[]; /** * cli α.45 — set when the proposed sub-issue's scope is already covered * by an active spec. The PM still sees the sub-issue (so the parent * issue's full scope is visible), but the comment renders an "Already * covered by story-NNN" annotation and the PM can fold it into the * existing story rather than opening a duplicate. */ existing_spec_id?: string; } export type MultifurcationVerdict = { kind: "one"; rationale: string; } | { kind: "many"; rationale: string; sub_issues: MultifurcationSubIssue[]; }; export interface MultifurcationInputs { issueTitle: string; issueBody: string; /** * cli α.45 — list of currently active specs in this repo. The * multifurcation prompt uses them to annotate sub-issues that * overlap with existing scope (story_id is the PM-visible * reference; title + summary give the model enough context to * decide whether overlap is real). * * Empty array is fine — model just won't tag anything. */ activeSpecs?: ActiveSpecDigest[]; } export interface MultifurcationResult { verdict: MultifurcationVerdict; costUsd: number; usage: { inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheCreateTokens: number; }; } export declare function assessMultifurcation(inputs: MultifurcationInputs, opts: { llm: LlmClient; model: string; }): Promise; /** * Compose the user-side message. Exported for tests so the snapshot can * assert active-specs context lands where the model expects it. */ export declare function buildMultifurcationUserMessage(inputs: MultifurcationInputs): string; /** * Compact a Spec list down to the digest shape the multifurcation * prompt consumes. Summary is the first ~150 chars of the first * acceptance scenario (the most spec-like prose); falls back to a * non_goal or empty string. */ export declare function digestActiveSpecs(specs: Spec[]): ActiveSpecDigest[]; /** * Parse the JSON verdict. Tolerant of leading/trailing prose (some * models still wrap JSON in fences despite the prompt). Defaults to * `{ kind: "one", rationale: "(parser fallback — model output unparseable)" }` * so that an LLM hiccup never blocks refine. */ export declare function parseMultifurcationJson(text: string): MultifurcationVerdict; /** * PM-facing comment body listing the proposed sub-issues. The template * mirrors the refine "questions-first" layout — proposal up top, agent's * rationale folded into a
block, action prompts at the bottom. * * The HTML comment `` is a sentinel * future refine runs grep for to skip re-proposing on the same issue. */ export declare function multifurcationCommentBody(proposal: { rationale: string; sub_issues: MultifurcationSubIssue[]; }, opts: { issueTitle: string; }): string; /** * Detect whether a multifurcation proposal has already been posted on * an issue's comment thread. Used by the agent to skip re-running the * LLM pass when the PM is still deciding. */ export declare function hasExistingMultifurcationComment(comments: Array<{ body: string; }>): boolean; //# sourceMappingURL=multifurcate.d.ts.map