/** * [WHO]: Evolution ledger path resolution, scope/root agreement enforcement, per-scope evidence cursor, candidate/revision validation, rejected-candidate listing, skill_manifest body structure enforcement, the refinement change budget, the shared artifact hash, and behavioral prose dedup, no-IO executable DSL manifests, usage records, prediction manifests, post-hoc attribution, eval_fixture dedupe/retention, gated promotion, quarantine, rollback, and conservative auto-rollback * [FROM]: Depends on node fs/path/crypto for owner-only runtime state below agentDir/evolution/v1 * [TO]: Consumed by optional evolution extension command handlers and tests * [HERE]: extensions/optional/evolution/evolution-store.ts - durable store for controlled self-evolution */ import type { EvolutionArtifact, EvolutionAttribution, EvolutionCandidate, EvolutionCandidateInput, EvolutionCurrent, EvolutionGateReport, EvolutionInspection, EvolutionRevision, EvolutionScope, EvolutionScopeSelector, EvolutionValidationReport, EvolutionUsageRecord, EvolutionFeedbackRecord } from "./evolution-types.js"; export interface EvolutionClockOptions { now?: () => string; id?: () => string; } export interface EvolutionPromotionOptions extends EvolutionClockOptions { approvedBy?: string; gateReport?: EvolutionGateReport; } export interface EvolutionRejectOptions extends EvolutionClockOptions { rejectedBy?: string; } export interface EvolutionRollbackOptions extends EvolutionClockOptions { requestedBy?: string; } export interface EvolutionGateFailureOptions extends EvolutionClockOptions { gateReport: EvolutionGateReport; } export interface EvolutionAttributionOptions extends EvolutionClockOptions { gateReport: EvolutionGateReport; attributedBy?: string; } export interface EvolutionAutoRollbackOptions extends EvolutionAttributionOptions { rollbackBy?: string; } export interface EvolutionUsageOptions extends EvolutionClockOptions { artifact: EvolutionArtifact; scope: EvolutionUsageRecord["scope"]; revisionId?: string; status: EvolutionUsageRecord["status"]; usedBy?: string; input?: Record; resultSummary?: string; error?: string; } export interface EvolutionFeedbackOptions extends EvolutionClockOptions { usageId: string; outcome: EvolutionFeedbackRecord["outcome"]; note?: string; recordedBy?: string; } /** * The scope a root belongs to, read from the fixed layout `<...>/evolution/v1/`. * * The alternative is to have every caller pass its scope alongside the root and trust it, but that * is the hole this closes: a candidate's own `scope` field and the directory it is written to can * disagree, and every scope-keyed policy reads the field. A candidate declaring `workspace` inside * the global root is refused here; without the check `canAutoPromoteGlobalEvolution` sees * `scope !== "global"` and waves a `skill_manifest` through a gate that exists to forbid exactly * that. Undefined means the path is not an evolution root at all, which callers treat as a refusal * rather than as a wildcard. */ export declare function evolutionScopeOfRoot(scopeRoot: string): EvolutionScope | undefined; export declare function getEvolutionScopeRoot(agentDir: string, selector: EvolutionScopeSelector): string; /** * The identity of an artifact's meaning, not of its record. `overrides` is excluded because it is a * proposal-time instruction that is resolved away before anything is stored. */ export declare function evolutionArtifactHash(artifact: EvolutionArtifact): string; export interface EvolutionLogicalChanges { added: number; changed: number; removed: number; } export declare function validateEvolutionCandidateInput(input: EvolutionCandidateInput, options?: EvolutionClockOptions, /** * Deliberately not an exported option: the read path is the only consumer, and a public switch * that disables validation is a switch some future caller will disable by accident. * `loadRevision` re-validates what is already on disk, and a revision promoted before the skill * body rule existed must still load, render, and roll back; enforcing there would quarantine * every such skill and silently drop it out of discovery. Write paths leave it on, so nothing * non-conforming can become active. */ validation?: { enforceSkillBodyStructure?: boolean; }): EvolutionValidationReport; export declare function canAutoPromoteGlobalEvolution(input: EvolutionCandidateInput): { allowed: boolean; reason?: string; }; export declare function createEvolutionCandidate(scopeRoot: string, input: EvolutionCandidateInput, options?: EvolutionClockOptions): EvolutionCandidate; export declare function recordEvolutionGateFailure(scopeRoot: string, candidateId: string, options: EvolutionGateFailureOptions): EvolutionCandidate; export declare function recordEvolutionUsage(scopeRoot: string, options: EvolutionUsageOptions): EvolutionUsageRecord; export declare function recordEvolutionFeedback(scopeRoot: string, options: EvolutionFeedbackOptions): EvolutionFeedbackRecord; export declare function currentEvolutionRevisionId(scopeRoot: string): string | undefined; export declare function loadCurrentEvolution(scopeRoot: string): EvolutionCurrent | undefined; export declare function promoteEvolutionCandidate(scopeRoot: string, candidateId: string, options?: EvolutionPromotionOptions): EvolutionRevision; export declare function recordEvolutionAttribution(scopeRoot: string, revisionId: string, options: EvolutionAttributionOptions): EvolutionAttribution; export declare function recordEvolutionAttributionAndMaybeRollback(scopeRoot: string, revisionId: string, options: EvolutionAutoRollbackOptions): { attribution: EvolutionAttribution; rollback?: EvolutionCurrent; reason?: string; }; /** * Rejected candidates at this scope, most recently rejected first. * * Read for the refiner's history block, so it deliberately returns the whole record rather than a * pre-shaped summary: what counts as untrusted is decided at the point where the text becomes * prompt, not here. Rejected records are excluded from duplicate detection for the same reason they * are included here — a proposal that failed once is still allowed to be made again, because the * conditions that failed it may no longer hold. */ /** * How far this scope's turn stream has been consumed. * * `sessionId` is part of the record because turn indices restart. A scope can be written by many * sessions — global and workspace scopes are shared — and a cursor from a finished session would * otherwise suppress every early turn of the next one, silently, for as long as it took to climb back * past the old high-water mark. A cursor from a different stream is simply not a cursor for this one. */ export interface EvolutionEvidenceCursor { schemaVersion: 1; sessionId: string; lastTurnIndex: number; updatedAt: string; } /** * The cursor for this stream, or undefined if there is none that applies. * * A corrupt cursor reads as absent. The two ways to be wrong are reprocessing one turn's evidence, * which costs a duplicate candidate, and refusing every turn, which costs the feature entirely; only * one of those is recoverable, and the ledger beside it keeps the real usage record either way. */ export declare function readEvolutionEvidenceCursor(scopeRoot: string, sessionId: string): EvolutionEvidenceCursor | undefined; /** * Advances the cursor, never rewinding it. Out-of-order events are normal when several turns settle * at once, and a cursor that moved backwards would re-admit evidence already consumed. */ export declare function recordEvolutionEvidenceCursor(scopeRoot: string, sessionId: string, turnIndex: number, options?: EvolutionClockOptions): EvolutionEvidenceCursor; export declare function listRejectedCandidates(scopeRoot: string): EvolutionCandidate[]; export declare function rejectEvolutionCandidate(scopeRoot: string, candidateId: string, reason: string, options?: EvolutionRejectOptions): EvolutionCandidate; export declare function rollbackEvolution(scopeRoot: string, revisionId: string, options?: EvolutionRollbackOptions): EvolutionCurrent; export declare function autoEvaluateAndRollback(scopeRoot: string): { rolledBack: string[]; }; export declare function loadActiveEvolutionArtifacts(scopeRoot: string): EvolutionArtifact[]; export declare function loadActiveEvolutionSkillPaths(scopeRoot: string): string[]; /** * Revision ids that some rollback moved away from. * * `rollbackEvolution` records `rollbackOf: ` in history.jsonl, and * auto-rollback routes through the same function, so one event covers both paths. History is * used rather than the `current` pointer because the pointer's `rollbackOf` only remembers the * most recent rollback: a second rollback would otherwise resurrect the first withdrawn revision. * * Malformed lines are skipped, so a corrupted log degrades to "nothing withdrawn" — the prior * behavior — rather than throwing during resource discovery. */ export declare function readWithdrawnRevisionIds(scopeRoot: string): Set; /** * Scan all revision directories under /revisions/ for SKILL.md files. * Unlike loadActiveEvolutionSkillPaths (which only materializes the current active * revision's skills), this discovers every skill that was ever promoted, enabling * local-only users to benefit from all their accumulated skills without needing * remote push or global auto-promotion. * * Revisions that a rollback withdrew are excluded, and any directory an earlier run left behind * is removed. Without this, a rolled-back skill would keep being offered to the model through * this historical scan even though `rollbackEvolution` moved the current pointer away from it. */ export declare function discoverLocalSkillPaths(scopeRoot: string): string[]; export declare function loadActiveEvalFixtureArtifacts(scopeRoot: string): EvolutionArtifact[]; export declare function inspectEvolution(scopeRoot: string): EvolutionInspection;