/** * v0.8.2 §5.2 — sensitive-command confirmation gate. * * When an engineering SKILL tries to run a sensitive Bash command — `git * push`, `gh pr merge`, `gh pr close` — the PM session must be notified, the * user must answer `y` in their command channel, and only then the command * proceeds. Default timeout is 30 minutes; on timeout the command is * cancelled and the spawn receives a `tool_result` saying so. * * Audit trail lives in `/memory/dev-confirmations.jsonl`, append-only. * The route-event sink (v0.6 §4 archive FTS5) picks it up by tail-reading * the file at archive-rotate time — no synchronous DB write on the spawn * hot path. * * Design constraints: * - **Bot-process state**, not Claude-process state. The PM-runner holds * the in-flight `DevConfirmController` and wires its resolve/reject to * the next user message arriving on `command-`. * - **No filesystem locks**. Single-bot-process invariant per workspace * (per v0.7 lifecycle precheck) means an in-memory map is enough. * - **30-min default timeout** — configurable via constructor. * - **Cancel propagation**. If the PM session aborts, every pending * confirmation is rejected with `"pm-aborted"`. */ export declare const DEV_CONFIRM_DEFAULT_TIMEOUT_MS: number; /** Patterns that trigger the gate. Matched left-trimmed against the bash command. */ export declare const SENSITIVE_BASH_PREFIXES: readonly string[]; export type DevConfirmDecision = "y" | "n" | "timeout" | "pm-aborted"; export interface DevConfirmRequest { /** Stable id — derived from skill+user+ts for log correlation. */ id: string; user: string; skill: string; cmd: string; /** Earliest ISO timestamp the request was created. */ ts: string; /** Workspace path used to resolve the JSONL log location. */ workspace: string; /** Org slug — where the JSONL log lives (`/memory/...`). */ orgSlug: string; /** Override timeout (ms) — defaults to 30 min. */ timeoutMs?: number; /** Stable "now" injection for tests. */ now?: () => number; } export interface DevConfirmAuditEntry { ts: string; user: string; skill: string; cmd: string; decision: DevConfirmDecision; duration_ms: number; } export interface DevConfirmController { /** Resolves once a decision (or timeout) lands. */ promise: Promise; /** Called by the messenger reader when a user replies. */ resolve: (decision: "y" | "n") => void; /** Called by chief-runner if the PM session aborts mid-flight. */ abort: () => void; /** The original request (for callers that want to render a message). */ request: DevConfirmRequest; } /** Test seam: lets us replace the wall clock in unit tests. */ export interface DevConfirmDeps { setTimeout?: (cb: () => void, ms: number) => unknown; clearTimeout?: (handle: unknown) => void; /** Override the audit write path (mostly tests). */ writeAudit?: (entry: DevConfirmAuditEntry, target: string) => void; /** * Generic post-approval sink — fired exactly once when the decision is * `"y"` (approved), after the audit write. Best-effort: errors are swallowed * so the gate's resolved decision is never affected. Dormant until the gate * goes live (v1.3.0); no production code constructs a gate yet. (v1.2.9 Part * B originally used this for a `git-` push notification; that feed * was dropped in v1.2.10 — push notifications are now the user's own * GitHub→messenger webhook. The hook stays as a neutral extension point.) */ onApproved?: (request: DevConfirmRequest) => void; } export declare const DEFAULT_DEV_CONFIRM_DEPS: Required>; /** * Detect whether a bash command requires a confirmation gate. Returns the * matched prefix (for audit logs / UI rendering) or `null` when the command * is OK to run without confirmation. */ export declare function detectSensitiveCommand(cmd: string): string | null; /** * Build a stable id for a confirmation request. Used as the correlation token * the PM session relays to the user (`"확인 #abc123: git push origin feat/x ?"`). */ export declare function makeConfirmId(req: Pick): string; /** * Create a controller. The caller is responsible for: * 1. Holding the controller in a `Map` * keyed by the request id. * 2. Calling `resolve("y"|"n")` when the user replies on their channel. * 3. Calling `abort()` if the PM session crashes / a new turn arrives. * 4. Awaiting `promise` from the bash-tool wrapper to gate execution. * * The controller writes a `DevConfirmAuditEntry` to * `/memory/dev-confirmations.jsonl` regardless of outcome. */ export declare function createDevConfirm(request: DevConfirmRequest, deps?: DevConfirmDeps): DevConfirmController; /** Path to the audit JSONL — exposed for tests + archive-rotate. */ export declare function devConfirmAuditPath(workspace: string, orgSlug: string): string;