import type { RunGh } from "../utils/gh"; import { type CrashSignatureView, type CrashStatePaths } from "./index-store"; import { type LoadedCrashRecord } from "./record-loader"; import { type SanitizeVerdict } from "./sanitize"; /** The one repository this command may ever target. */ export declare const CRASH_REPORT_REPO = "Yeachan-Heo/gajae-code"; export declare const CRASH_REPORT_ISSUE_PREFIX = "https://github.com/Yeachan-Heo/gajae-code/issues/"; export interface CrashReportEnvironment { platform: string; gjcVersion: string; bunVersion: string; } export interface CrashReportAnswers { steps: string; expected: string; provider: string; area: string; additional: string; } export declare function defaultCrashReportEnvironment(): CrashReportEnvironment; /** Generic title built from normalized inputs only — never from raw crash text. */ export declare function buildCrashReportTitle(signature: CrashSignatureView, record: LoadedCrashRecord): string; export interface BuildCrashReportBodyInput { signature: CrashSignatureView; record: LoadedCrashRecord; answers: CrashReportAnswers; environment: CrashReportEnvironment; } /** * Render the full issue body. Every `bug_report.yml` required field is present: * crash-derived fields prefilled, non-derivable fields carried through from the * interactive answers (or an explicit "not captured" prompt). * * All crash-derived text lives inside fenced blocks with backticks neutralized * and `@` de-fanged; the machine marker is emitted outside those blocks so a * forged marker inside crash text cannot impersonate one. */ export declare function buildCrashReportBody(input: BuildCrashReportBodyInput): SanitizeVerdict; export interface CrashReportSnapshot { path: string; digest: string; byteLength: number; title: string; body: string; } /** * Freeze the exact bytes that may be submitted into a 0600 file. * * `wx` refuses to follow or clobber an existing path, so a planted symlink * cannot redirect the snapshot, and the digest shown to the user is verified * again immediately before submission. */ export declare function writeCrashReportSnapshot(dir: string, title: string, body: string): Promise; /** * Prefilled issue URL for installs without `gh`. * * Built with `URL`/`URLSearchParams` against a fixed allowlisted origin and * carrying only bounded-grammar fields — never message or stack content. Never * auto-opened. */ export declare function buildPrefillUrl(title: string, fingerprint: string, version: string): string | undefined; export interface DuplicateCandidate { url: string; title: string; author: string; } export type DuplicateCheck = { status: "none"; } | { status: "candidate"; candidate: DuplicateCandidate; } | { status: "uncertain"; reason: string; }; /** Validate that a `gh`-returned URL really points at the canonical repository. */ export declare function isCanonicalIssueUrl(value: string): boolean; /** * Read-only duplicate search, always `--repo` pinned. Any timeout, auth failure * or unparseable result is `uncertain`, which refuses creation unless the user * explicitly overrides. */ export declare function checkForDuplicateIssue(runGh: RunGh, fingerprint: string): Promise; export interface CrashReportIo { print(text: string): void; /** Returns the chosen index, or undefined when cancelled. */ select(prompt: string, options: string[]): Promise; input(prompt: string): Promise; confirm(prompt: string): Promise; } export interface CrashReportDeps { io: CrashReportIo; paths: CrashStatePaths; snapshotDir: string; runGh: RunGh; interactive: boolean; environment?: CrashReportEnvironment; now?: () => Date; } export type CrashReportOutcome = { status: "no-signatures"; } | { status: "non-interactive"; snapshotPath?: string; } | { status: "cancelled"; } | { status: "acknowledged"; fingerprint: string; } | { status: "refused"; reason: string; } | { status: "unmatchable"; fingerprint: string; } | { status: "manual"; snapshotPath: string; prefillUrl?: string; } | { status: "duplicate"; url: string; } | { status: "commented"; url: string; } | { status: "created"; url: string; }; /** * The whole flow. Steps 1–4 are strictly local; `deps.runGh` is first reachable * at step 5, after the digest-confirmed consent gate. */ export declare function runCrashReportFlow(deps: CrashReportDeps): Promise;