/**
 * Governance-artifact scaffolding utilities (mmnto/totem#1288).
 *
 * Shared helpers for the `totem proposal new` and `totem adr new` commands.
 * Nothing in this module carries module-level state — every helper takes
 * its context via arguments so the tests can exercise both the submodule
 * (`<totem>/.strategy/`) and the standalone (strategy-repo root) cases.
 */
import { type StrategyResolverConfig } from '@mmnto/totem';
export type GovernanceType = 'proposal' | 'adr';
export interface ScaffoldOptions {
    type: GovernanceType;
    title: string;
    cwd: string;
    /**
     * Loaded `TotemConfig` (or any object with a `strategyRoot?: string` field).
     * Forwarded to the strategy-root resolver so `TotemConfig.strategyRoot`
     * wins precedence-2 over the sibling / submodule layers (mmnto-ai/totem#1710).
     */
    config?: StrategyResolverConfig;
}
export interface GovernancePaths {
    /** Directory that anchors the governance layout (strategy repo root or submodule root). */
    rootDir: string;
    /** Directory that holds the NNN-prefixed artifact files. */
    targetDir: string;
    /** On-disk template path. May not exist; caller falls back to the hardcoded default. */
    templatePath: string;
    /** Dashboard README refreshed by `docs:inject`. */
    dashboardFile: string;
}
/**
 * Best-effort `TotemConfig` load for the governance commands. Returns
 * `undefined` when the config is missing, unparseable, OR resolves to the
 * global `~/.totem/` profile — both missing and unparseable are legitimate
 * states for a freshly-cloned consumer repo, and a global-profile config
 * is intentionally NOT used as a repo-local `strategyRoot` source (that
 * would let one user's personal pointer leak across every repo on disk).
 * The strategy-root resolver still has env / sibling / submodule layers
 * to fall back on (mmnto-ai/totem#1710 R3 — CR R3 global-config-leak fix).
 *
 * Shared by `proposalNewCommand` and `adrNewCommand` so the load idiom +
 * its `// totem-context: intentional best-effort` annotation live in one
 * place (mmnto-ai/totem#1710 R2).
 */
export declare function loadGovernanceConfig(cwd: string): Promise<StrategyResolverConfig | undefined>;
/**
 * Resolve governance paths for the current invocation.
 *
 * Two layout shapes supported:
 *
 * 1. **Standalone (cwd IS the strategy repo)** — `<gitRoot>` itself contains
 *    `proposals/` or `adr/` at the top level. Used when the CLI runs from
 *    inside the strategy repo directly. Detected here in the helper before
 *    delegating to the resolver because the strategy-root resolver answers
 *    "where IS the strategy repo from somewhere else", not "are we INSIDE
 *    one already."
 *
 * 2. **Resolved (cwd is in a consuming repo)** — defer to
 *    `resolveStrategyRoot` (mmnto-ai/totem#1710). The resolver walks env →
 *    config → sibling → submodule precedence and returns an absolute path.
 *    Throws an actionable `TotemError` (ADR-088) when none of the layers
 *    resolve.
 *
 * Also throws `TotemError` when cwd is not inside a git repo.
 */
export declare function resolveGovernancePaths(cwd: string, type: GovernanceType, config?: StrategyResolverConfig): GovernancePaths;
/**
 * Scan `targetDir` for `NNN-slug.md` files, parse the prefix to an int,
 * and return `(max + 1)` zero-padded to three digits.
 *
 * Returns `'001'` when the directory is missing or contains no matching
 * files. Files that do not match `^(\d{3})-(.+)\.md$` are ignored so
 * README.md or non-padded prefixes (e.g. `42-x.md`) do not pollute the
 * count. Throws `TotemError` when the next id would exceed 999.
 */
export declare function getNextArtifactId(targetDir: string): string;
/**
 * Build the final artifact filename from a numeric id and a raw title.
 *
 * Sanitization: lowercase, any non-alphanumeric run becomes a single hyphen,
 * leading/trailing hyphens are stripped. Throws `TotemError` when the
 * sanitized slug is empty — the error fires BEFORE any filesystem write so
 * the caller never strands a half-written artifact.
 */
export declare function formatArtifactFilename(id: string, title: string): string;
/**
 * Sanitize a raw title for safe inclusion in the scaffolded markdown body.
 *
 * Strips C0 control characters and `DEL` (0x00-0x1F, 0x7F) — most notably
 * newlines, carriage returns, and tabs — then collapses any remaining run
 * of whitespace to a single space and trims the edges. Without this pass,
 * a title like `Fix\n## Fake Heading` would inject a fresh markdown block
 * into the scaffolded artifact, shifting document structure out of the
 * scaffolder's control. The `#` character itself is allowed through on
 * purpose: a single-line heading that contains `#` characters stays a
 * single h1 heading in markdown.
 */
export declare function sanitizeArtifactTitle(title: string): string;
/**
 * Default proposal template. Exported so tests and callers can inspect the
 * baseline shape without re-deriving it. Uses ADR-091's exact heading form
 * (`# Proposal NNN: Title` with a SPACE separator, not a hyphen). Keep in
 * sync with `DEFAULT_ADR_TEMPLATE` below.
 */
export declare const DEFAULT_PROPOSAL_TEMPLATE = "# Proposal {{ID}}: {{TITLE}}\n\n**Status:** Draft\n**Date:** {{DATE}}\n\n## Problem Statement\n\n_Describe the problem this proposal addresses._\n\n## Proposal\n\n_Describe the proposed change._\n\n## Alternatives Considered\n\n_List alternatives and why they were rejected._\n\n## Impact\n\n_Who / what does this affect?_\n";
/**
 * Default ADR template. Mirrors `DEFAULT_PROPOSAL_TEMPLATE` but with the
 * `# ADR NNN: Title` heading form required by ADR-091.
 */
export declare const DEFAULT_ADR_TEMPLATE = "# ADR {{ID}}: {{TITLE}}\n\n**Status:** Draft\n**Date:** {{DATE}}\n\n## Context\n\n_Describe the architectural context and forces at play._\n\n## Decision\n\n_State the decision._\n\n## Consequences\n\n_List the consequences. Note what improves and what regresses._\n";
export interface RenderTemplateOptions {
    type: GovernanceType;
    id: string;
    title: string;
    templatePath: string;
    date: string;
}
/**
 * Render the artifact template with variable substitution.
 *
 * If `templatePath` exists on disk, its contents are used; otherwise the
 * hardcoded `DEFAULT_PROPOSAL_TEMPLATE` / `DEFAULT_ADR_TEMPLATE` string is
 * used. Substitutes `{{TITLE}}`, `{{DATE}}`, and `{{ID}}` globally.
 *
 * MVP variable set per spec #1288: only `{{TITLE}}` and `{{DATE}}` are
 * user-facing; `{{ID}}` is internal to the default templates so the NNN
 * number lands in the heading without the caller having to splice it.
 */
export declare function renderArtifactTemplate(opts: RenderTemplateOptions): string;
/**
 * Thin injection seam so tests can verify exact argv without spawning a
 * real subprocess. Production callers omit the `exec` field and we default
 * to `safeExec`.
 */
export type ExecFn = (cmd: string, args: string[], cwd?: string) => void;
export interface PostScaffoldHookOptions {
    rootDir: string;
    newFilePath: string;
    dashboardFile: string;
    /** Override the exec function (test seam). Defaults to `safeExec`. */
    exec?: ExecFn;
}
export interface PostScaffoldHookResult {
    /** True if `pnpm run docs:inject` exited 0. False when the script is missing or failed. */
    dashboardRefreshed: boolean;
    /** True if `git add` staged the two paths. False if git returned non-zero. */
    staged: boolean;
}
/**
 * Run the two post-scaffold side-effects in sequence:
 *
 * 1. `pnpm run docs:inject` (refresh the dashboard index). On non-zero exit
 *    or missing script, warn to stderr and continue — the scaffolded file
 *    already exists on disk, so a dashboard refresh failure should not
 *    strand the artifact.
 * 2. `git add <newFilePath> <dashboardFile>`. Stages ONLY those two paths;
 *    never `-A` or `.` (per lesson-8067935e / lesson-4a01b498). On failure,
 *    warn and return `staged: false` so the caller can surface the stage
 *    state in its user-facing summary.
 *
 * Neither step throws; both failures degrade gracefully so the user always
 * walks away with the new artifact on disk.
 */
export declare function runPostScaffoldHooks(opts: PostScaffoldHookOptions): PostScaffoldHookResult;
export interface ScaffoldArtifactResult {
    /** Zero-padded NNN id chosen for the artifact. */
    id: string;
    /** Basename of the new file (`NNN-kebab-title.md`). */
    filename: string;
    /** Absolute path the file was written to. */
    filePath: string;
    /** Absolute path to the dashboard README that `docs:inject` refreshes. */
    dashboardFile: string;
    /** True if `pnpm run docs:inject` succeeded. */
    dashboardRefreshed: boolean;
    /** True if `git add` staged the two paths. */
    staged: boolean;
}
export interface ScaffoldArtifactInternals {
    /** Override the exec function (test seam). Defaults to `safeExec`. */
    exec?: ExecFn;
    /** Override the date string (test seam). Defaults to today in `YYYY-MM-DD`. */
    date?: string;
    /**
     * Force a specific NNN id instead of calling `getNextArtifactId`. Test-only
     * seam for deterministic collision scenarios; production callers must not
     * pass this (the auto-increment is the spec behavior).
     */
    forceId?: string;
}
/**
 * Full scaffolding pipeline, invoked by both `totem proposal new` and
 * `totem adr new`:
 *
 *   resolve paths → compute id → sanitize filename → render template →
 *   collision guard → write file → run docs:inject + git add
 *
 * Pre-disk validation (path resolution, id computation, slug sanitization,
 * collision check) happens BEFORE the filesystem is touched so a bad input
 * never strands a half-written artifact.
 */
export declare function scaffoldGovernanceArtifact(options: ScaffoldOptions, internals?: ScaffoldArtifactInternals): ScaffoldArtifactResult;
//# sourceMappingURL=governance.d.ts.map