/** * REQ-ID acceptance gate operations for `cleo req add|list|migrate`. * * Each operation reads/writes the `Task.acceptance` mixed array * (`(string | AcceptanceGate)[]`) via the DataAccessor without touching * any other task fields. * * @epic T760 * @task T782 */ import type { AcceptanceGate, AcceptanceItem } from '@cleocode/contracts'; import type { DataAccessor } from '../store/data-accessor.js'; /** Shape returned by `reqList`. */ export interface ReqListEntry { /** Zero-based index in the task's acceptance array. */ index: number; /** The REQ-ID (always present — strings are filtered out). */ req: string; /** Gate kind discriminant. */ kind: AcceptanceGate['kind']; /** Human-readable description. */ description: string; /** Advisory flag. */ advisory: boolean; } /** Proposal produced by `reqMigrate`. */ export interface MigrationProposal { /** Zero-based index in the original acceptance array. */ index: number; /** Original free-text string. */ original: string; /** Proposed gate (null means no heuristic matched — item is left as-is). */ proposed: AcceptanceGate | null; /** Auto-generated REQ-ID for the proposed gate. */ reqId: string | null; /** Short label for the matched heuristic ('test'|'file'|'lint'|'command'|'manual'). */ heuristic: string | null; } /** Result of `reqMigrate` with `apply: true`. */ export interface MigrationApplyResult { /** Proposed replacements evaluated against the transaction snapshot. */ proposals: MigrationProposal[]; /** Number of free-text criteria replaced by validated gates. */ applied: number; } /** * Add a typed `AcceptanceGate` (with a REQ-ID) to a task's acceptance array. * * @remarks * Validates before opening storage. Reading existing acceptance, checking REQ-ID * uniqueness and persisting the task/AC projection share one transaction, so * competing appends cannot overwrite each other. This records a gate; it does * not execute it or record passing verification evidence. * * @returns The committed acceptance array and its owning task identity. * @example * ```typescript * const gate: AcceptanceGate = { * kind: 'test', command: 'node', args: ['verify.mjs'], expect: 'exit0', * req: 'PARTNER-121', description: 'Task-specific checks pass', * }; * await reqAdd(projectRoot, 'T121', gate, undefined); * ``` * * @param projectRoot - Absolute path to project root * @param taskId - Target task ID * @param gate - Typed gate; runtime schema validation also applies to SDK callers * @param accessor - Optional pre-created accessor (for testing) * * @throws CleoError E_NOT_FOUND when the task does not exist * @throws CleoError E_VALIDATION when the REQ-ID already exists on the task * * @task T782 */ export declare function reqAdd(projectRoot: string, taskId: string, gate: AcceptanceGate, accessor?: DataAccessor): Promise<{ task: { id: string; acceptance: AcceptanceItem[]; }; }>; /** Result of {@link reqReplace}. */ export interface ReqReplaceResult { /** The task and its committed acceptance array. */ task: { id: string; acceptance: AcceptanceItem[]; }; /** The replaced REQ-ID. */ req: string; /** Zero-based index of the gate in the acceptance array (unchanged). */ index: number; /** The gate that was superseded, kept in the AC history and the audit row. */ superseded: AcceptanceGate; /** False when the new gate equals the current one (nothing was written). */ changed: boolean; } /** * Replace the typed gate that carries `req` with `gate`, in place (T12988). * * @remarks * The gate keeps its index, its AC row (id and ordinal: a REQ-ID row's id * derives from the REQ-ID, `evidenceBoundSourceKey`) and therefore its * evidence bindings, which go stale rather than being re-pointed: typed results * and criterion links are pinned to the criterion text hash, so the replaced * gate must be verified again. The superseded gate is kept as an AC history row * (reason `replace`) and in the task audit row, with its last typed result. In * a locked pipeline stage the change needs `reason`, exactly as `cleo update * --acceptance` does. * * @param projectRoot - Absolute path to the project root. * @param taskId - Target task ID. * @param req - REQ-ID of the gate to replace. * @param gate - The new gate. Its `req` must be absent or equal `req`. * @param options - `reason` for a locked stage; `accessor` for tests. * @returns The committed acceptance array and the superseded gate. * @throws CleoError E_NOT_FOUND for an unknown task or REQ-ID, E_VALIDATION for * an invalid gate or a REQ-ID mismatch, AC_LOCKED in a locked stage without `reason`. * @example * ```typescript * await reqReplace(root, 'T42', 'TIMER-01', { * kind: 'test', command: 'pnpm', args: ['--filter', 'app', 'exec', 'vitest', 'run'], * expect: 'pass', description: 'Timer tests pass', req: 'TIMER-01', * }); * ``` * @task T12988 */ export declare function reqReplace(projectRoot: string, taskId: string, req: string, gate: AcceptanceGate, options?: { reason?: string; accessor?: DataAccessor; }): Promise; /** * List all REQ-ID–addressed acceptance gates on a task. * * @remarks * Free-text strings are skipped because they have no REQ-ID. This summary does * not execute gates or establish verification; full payloads remain on the task. * * @returns Requirement identity, index, kind and description for each named gate. * @example * ```typescript * const { gates } = await reqList(projectRoot, 'T121', undefined); * ``` * * @param projectRoot - Absolute path to project root * @param taskId - Target task ID * @param accessor - Optional pre-created accessor (for testing) * * @throws CleoError E_NOT_FOUND when the task does not exist * * @task T782 */ export declare function reqList(projectRoot: string, taskId: string, accessor?: DataAccessor): Promise<{ taskId: string; gates: ReqListEntry[]; }>; /** * Heuristic migrator: reads free-text acceptance strings and proposes typed * `AcceptanceGate` replacements. * * @remarks * Without `apply: true` only proposals are returned. With `apply: true` the * matched strings are replaced in the task's acceptance array and the updated * array is persisted. * * Auto-generated REQ-IDs use the pattern `MIGRATED-001`, `MIGRATED-002`, etc. * Existing structured gates and their requirement identities are preserved. * Apply plans and persists under one transaction; preview does not write. * * @returns Proposed replacements and, when applied, the committed replacement count. * @example * ```typescript * const preview = await reqMigrate(projectRoot, 'T121', false, undefined); * ``` * * @param projectRoot - Absolute path to project root * @param taskId - Target task ID * @param apply - When true, writes the proposals back to the task * @param accessor - Optional pre-created accessor (for testing) * * @throws CleoError E_NOT_FOUND when the task does not exist * * @task T782 */ export declare function reqMigrate(projectRoot: string, taskId: string, apply: boolean, accessor?: DataAccessor): Promise<{ proposals: MigrationProposal[]; applied?: number; }>; /** * Validate a raw JSON string against the `acceptanceGateSchema` Zod schema. * * Returns the parsed `AcceptanceGate` on success or throws a `CleoError` * with exit code `E_VALIDATION` on failure. * * @remarks * Uses the same schema boundary as direct SDK writes and rejects unsupported * fields, including nested fields that the schema would otherwise strip. * * @returns The validated gate without executing its command. * @example * ```typescript * const raw = '{"kind":"manual","description":"Review","prompt":"Approve?"}'; * const gate = parseGateJson(raw); * ``` * @param raw - Raw JSON string from `--gate` CLI flag * * @throws CleoError E_VALIDATION when JSON is malformed or schema invalid * * @task T782 */ export declare function parseGateJson(raw: string): AcceptanceGate; //# sourceMappingURL=req.d.ts.map