Documentation
¶
Overview ¶
Package undo records what an import wrote and reverses it on request, backing `cct undo`. Import is cct's only operation that changes files, so a clean, verifiable reversal of the last import is the natural safety net.
A journal is written per import into cct's own config directory (never inside a coding-agent home). Each entry carries the destination path, the SHA-256 of the bytes cct wrote, and — for a replaced or merge-updated file — a backup of the original. Reversal is conservative: it only removes or restores a file whose current contents still match what the import wrote, so edits made after the import are never destroyed.
Index ¶
Constants ¶
const JournalVersion = 1
JournalVersion is the on-disk journal schema version.
Variables ¶
This section is empty.
Functions ¶
func Record ¶
Record writes a journal for a completed import and prunes old journals to the retention limit. A journal with no entries is not written (nothing to undo).
func Validate ¶ added in v1.3.1
Validate checks a journal is structurally sound and self-consistent before any reversal touches the disk. Every failure mode here resolves to "change nothing": an unsupported version, a missing/relative path, a path that escapes the recorded agent home, a missing hash, or a created/overwritten record that disagrees with its backup fields all reject the whole journal.
Types ¶
type Entry ¶
type Entry struct {
// Action mirrors the bundle import action ("import", "import-copy",
// "replace", "update"); it is informational for display.
Action string `json:"action"`
// Dest is the absolute path of the file the import wrote.
Dest string `json:"dest"`
// WroteSHA is the SHA-256 of the bytes the import wrote to Dest. Reversal only
// proceeds when Dest still hashes to this, so later edits are never clobbered.
WroteSHA string `json:"wrote_sha256"`
// Backup, when set, is the absolute path to a copy of the file that existed at
// Dest before the import overwrote it (replace and merge-update). Reversal
// restores it. Empty for a newly created file, which reversal deletes.
Backup string `json:"backup,omitempty"`
// BackupSHA is the SHA-256 of the backup's contents, recorded at import time.
// Reversal refuses to restore a backup whose bytes no longer match, so a
// swapped or tampered backup can never be written over a session.
BackupSHA string `json:"backup_sha256,omitempty"`
// Created is true when the import created a new file (no prior file at Dest),
// so reversal deletes it rather than restoring a backup.
Created bool `json:"created"`
// ThreadID and Preview are carried for a readable undo listing.
ThreadID string `json:"thread_id,omitempty"`
Preview string `json:"preview,omitempty"`
}
Entry is the reversal record for one written file.
type Journal ¶
type Journal struct {
Version int `json:"version"`
Time string `json:"time"` // RFC3339, when the import ran
Tool string `json:"tool"`
Home string `json:"home"` // agent home root the import wrote into
Bundle string `json:"bundle"` // source bundle path (for display)
Entries []Entry `json:"entries"`
// contains filtered or unexported fields
}
Journal is the full record of one import.
func Latest ¶
Latest returns the most recent journal for reversal, or nil when none exist.
It is deliberately strict: it loads the single newest journal file and validates it, and if that file is missing fields, points outside its recorded home, is truncated, or is otherwise malformed, it returns an error rather than silently falling back to an older journal. This upholds the core invariant — a corrupt, manipulated, or ambiguous journal must lead to "change nothing".
type Outcome ¶
type Outcome struct {
Entry Entry
Status string // removed | restored | already-gone | changed | not-regular |
// backup-missing | backup-changed | error
Message string
}
Outcome is what reversal did to one entry.
type Result ¶
Result summarizes a reversal.
func Reverse ¶
Reverse undoes an import journal. It deletes files the import created and restores backups for files it overwrote — but only when the file on disk still matches what the import wrote, so any change made afterward is left untouched and reported as skipped. On a real (non-dry-run) reversal, restored backups are removed and the journal file is deleted afterward by the caller via Remove.