doover-core 0.1.2

Core library for doover: session-scoped snapshot, journal, and undo for AI agent shell actions
Documentation
# doover reversibility registry — coreutils (data: CC0-1.0)
# Schema: doover-mvp-spec.md §4.5. Effects: safe | mutating | externalizing |
# destructive | irreversible. Undo: snapshot-restore | none | recompute.

rules:
  - id: coreutils.rm
    match: { command: rm }
    effect: destructive
    scope: { paths: positional, globs: true, recursive_flags: ["-r", "-R", "--recursive"] }
    undo: snapshot-restore
    notes: "Bypasses Trash; no native recovery."

  - id: coreutils.rmdir
    match: { command: rmdir }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore

  - id: coreutils.unlink
    match: { command: unlink }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore

  - id: coreutils.mv
    match: { command: mv }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
    notes: "Destination overwrite and source relocation both need pre-state."

  - id: coreutils.cp
    match: { command: cp }
    effect: destructive
    scope: { paths: positional-last }
    undo: snapshot-restore
    notes: "Only the destination is at risk; snapshot the last positional."

  - id: coreutils.dd
    match: { command: dd }
    effect: destructive
    scope: { paths: none }
    undo: snapshot-restore
    notes: "Target is of=; needs parser flag handling (step 2). Until then scope=none falls back to the unknown policy."

  - id: coreutils.truncate
    match: { command: truncate }
    effect: destructive
    scope: { paths: positional, flag_args: ["-s", "--size"] }
    undo: snapshot-restore

  - id: coreutils.shred
    match: { command: shred }
    effect: irreversible
    scope: { paths: positional }
    undo: snapshot-restore
    notes: "Snapshot best-effort; the whole point of shred is that recovery fails. Gate."

  - id: coreutils.tee
    match: { command: tee }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
    notes: "-a appends (additive); plain tee truncates targets."

  - id: coreutils.chmod
    match: { command: chmod }
    effect: destructive
    scope: { paths: positional, skip: 1, recursive_flags: ["-R"] }
    undo: snapshot-restore
    notes: "Metadata-only loss; snapshots preserve mode bits. skip:1 drops the mode argument."

  - id: coreutils.chown
    match: { command: chown }
    effect: destructive
    scope: { paths: positional, skip: 1, recursive_flags: ["-R"] }
    undo: snapshot-restore
    notes: "skip:1 drops the owner:group argument."

  - id: coreutils.ln
    match: { command: ln }
    effect: destructive
    scope: { paths: positional-last }
    undo: snapshot-restore
    notes: "-sf silently replaces the target."

  - id: coreutils.install
    match: { command: install }
    effect: destructive
    scope:
      paths: positional
      flag_args: ["-m", "--mode", "-o", "--owner", "-g", "--group", "-s", "--strip-program", "-b", "--suffix", "-S"]
    undo: snapshot-restore
    notes: >
      Copies sources over a destination, replacing it. `paths: positional`
      captures the dest (and, harmlessly, the sources); a separate-word
      `-t DIR` target also falls through as a captured positional. flag_args
      swallows the value options so their values are not mistaken for paths.
      Precise capture beats the cwd-only fallback for an out-of-cwd target.
      `install -d` only creates dirs (no data at risk).

  # Compressors that REPLACE the original file in place (gzip file -> file.gz,
  # removing file). Undo snapshots the positional so the original is
  # recoverable. `-c/--stdout` writes to stdout instead (then the capture is
  # harmless over-work, not wrong). `-k/--keep` keeps the original (likewise).
  - id: coreutils.gzip
    match: { command: gzip }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.gunzip
    match: { command: gunzip }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.bzip2
    match: { command: bzip2 }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.bunzip2
    match: { command: bunzip2 }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.xz
    match: { command: xz }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.unxz
    match: { command: unxz }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.zstd
    match: { command: zstd }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore
  - id: coreutils.unzstd
    match: { command: unzstd }
    effect: destructive
    scope: { paths: positional }
    undo: snapshot-restore

  - id: coreutils.mkdir
    match: { command: mkdir }
    effect: mutating
    undo: none

  - id: coreutils.touch
    match: { command: touch }
    effect: mutating
    undo: none
    notes: "Creates or bumps mtime; content never lost."

  - id: coreutils.ls
    match: { command: ls }
    effect: safe
    undo: none

  - id: coreutils.cat
    match: { command: cat }
    effect: safe
    undo: none
    notes: "Read-only unless combined with a redirect; redirects match their own rules."