src — checkpoints

Module: src-checkpoints Cohesion: 0.80 Members: 0

src — checkpoints

The src/checkpoints module provides a suite of tools for managing and restoring file states within a project. It offers various strategies, from simple in-memory undo/redo to persistent, Git-backed versioning, catering to different needs for state preservation and recovery.

Core Concepts

At the heart of this module are two fundamental interfaces:

Checkpointing Strategies

The module implements four distinct checkpointing mechanisms, each with its own purpose and persistence model.

1. In-Memory Checkpoints (CheckpointManager)

The CheckpointManager provides a lightweight, session-scoped undo/redo capability. It stores checkpoints in an in-memory array, making it suitable for temporary state management during an active session.

Purpose:

How it Works:

Key API:

Usage Example:

import { getCheckpointManager } from './checkpoint-manager.js';

const manager = getCheckpointManager();

class="hl-cmt">// Before making a change
manager.checkpointBeforeEdit('src/my-file.ts', 'Before refactoring function X');

class="hl-cmt">// ... perform file modifications ...

class="hl-cmt">// If something goes wrong, rewind
const result = manager.rewindToLast();
if (result.success) {
  console.log('Successfully rewound:', result.restored);
} else {
  console.error('Failed to rewind:', result.errors);
}

console.log(manager.formatCheckpointList());

Integration: The CheckpointManager is used by src/agent/tool-executor.ts to create checkpoints before tool dispatches, allowing for immediate undo of agent actions.

2. Persistent Checkpoints (PersistentCheckpointManager)

The PersistentCheckpointManager extends the concept of checkpoints by storing them on disk, providing cross-session persistence. This is inspired by tools like Gemini CLI's /restore command.

Purpose:

How it Works:

Key API:

Usage Example:

import { getPersistentCheckpointManager } from './persistent-checkpoint-manager.js';

const manager = getPersistentCheckpointManager();

class="hl-cmt">// On application start, load existing checkpoints
console.log(manager.formatCheckpointList());

class="hl-cmt">// Create a checkpoint before a major operation
manager.createCheckpoint('Before attempting complex refactor');

class="hl-cmt">// ... application runs, potentially restarts ...

class="hl-cmt">// Restore to a specific checkpoint from the list
const result = manager.restore('cp_123abc_def456');
if (result.success) {
  console.log('Restored to checkpoint:', result.checkpoint?.description);
}

Integration: The PersistentCheckpointManager is used by commands/handlers/extra-handlers.ts for the /undo command, allowing users to revert to previous states. src/features/index.ts also uses it to report feature status.

3. Git-based Ghost Snapshots (GhostSnapshotManager)

The GhostSnapshotManager leverages Git to create "ghost" commits that capture the workspace state without polluting the user's main Git history. This is ideal for automatic, frequent snapshots, especially for agent-driven development, enabling easy undo/redo of agent turns.

Purpose:

How it Works:

  1. Stages all changes (git add -A).
  2. If there are changes, it creates a commit (git commit --allow-empty -m "[ghost]...") but then immediately performs a git reset --soft HEAD~1 to unstage the changes, leaving them in the working directory.
  3. The commit hash is then stored as a Git reference under a special namespace: refs/codebuddy/ghost/. This makes the commit reachable by its ref but not part of any branch.
  4. If no changes, it just records the current HEAD hash.

Key API:

Usage Example:

import { getGhostSnapshotManager } from './ghost-snapshot.js';

const manager = getGhostSnapshotManager();
await manager.initialize();

if (manager.isGitRepo) {
  class="hl-cmt">// Before an agent performs an action
  await manager.createSnapshot('Agent turn 1: Implemented feature X');

  class="hl-cmt">// ... agent modifies files ...

  class="hl-cmt">// If the user wants to undo the last agent turn
  const undone = await manager.undoLastTurn();
  if (undone) {
    console.log('Undone to:', undone.description);
  }

  class="hl-cmt">// If the user wants to redo
  const redone = await manager.redoLastTurn();
  if (redone) {
    console.log('Redone to:', redone.description);
  }
} else {
  console.log('Not in a Git repository, ghost snapshots are disabled.');
}

Integration: The GhostSnapshotManager is primarily used for features inspired by OpenAI Codex CLI, as indicated by codex-inspired-features.test.ts.

4. Checkpoint Versioning (CheckpointVersioning)

The CheckpointVersioning system provides a more advanced, Git-like version control layer on top of the basic Checkpoint concept. It allows for named versions, branches, tags, and diffing capabilities.

Purpose:

How it Works:

Key API:

Usage Example:

import { getCheckpointVersioning } from './checkpoint-versioning.js';
import { CheckpointManager, getCheckpointManager } from './checkpoint-manager.js';

const versioning = getCheckpointVersioning();
const checkpointManager = getCheckpointManager(); class="hl-cmt">// CheckpointVersioning uses Checkpoint objects

await versioning.load(); class="hl-cmt">// Load previous state

class="hl-cmt">// Create a base checkpoint
const initialCp = checkpointManager.createCheckpoint('Initial project setup');
const v1 = versioning.createVersion(initialCp, { name: 'v1.0', description: 'First stable version' });
versioning.createTag(v1.id, 'release-1.0');

class="hl-cmt">// Create a new branch for a feature
versioning.createBranch('feature/new-ui', v1.id);
versioning.switchBranch('feature/new-ui');

class="hl-cmt">// ... make changes, create more checkpoints ...
const featureCp = checkpointManager.createCheckpoint('Added new UI component');
const v2 = versioning.createVersion(featureCp, { description: 'New UI component added' });

class="hl-cmt">// Diff between versions
const diffResult = versioning.diff(v1.id, v2.id);
console.log('Diff:', diffResult);

class="hl-cmt">// Checkout a previous version
await versioning.checkout(v1.id);

await versioning.save(); class="hl-cmt">// Save current state

Integration: The CheckpointVersioning module is tested by checkpoint-versioning.test.ts, indicating its role in providing advanced version control features.

Module Architecture Overview

The src/checkpoints module is designed with distinct responsibilities for each manager. While CheckpointVersioning wraps Checkpoint objects, the managers generally operate independently, each providing a specialized form of state management.

graph TD
    subgraph Checkpoints Module
        A[CheckpointManager] -->|Manages in-memory| B(Checkpoint[])
        A -->|Uses| C(fs, path)
        A -->|Emits events| D(EventEmitter)

        E[PersistentCheckpointManager] -->|Manages on disk| F(Checkpoint files in ~/.codebuddy/history)
        E -->|Uses| C
        E -->|Uses| G(crypto for project hashing)
        E -->|Emits events| D

        H[GhostSnapshotManager] -->|Manages via Git| I(Git refs/codebuddy/ghost)
        H -->|Uses| J(child_process.execFile for 'git' commands)
        H -->|Emits events| D

        K[CheckpointVersioning] -->|Manages version graph| L(Version Map)
        K -->|Wraps| B
        K -->|Uses| M(fs-extra, crypto)
        K -->|Persists to| N(.codebuddy/versions/versions.json)
        K -->|Emits events| D
    end

    style B fill:#f9f,stroke:#333,stroke-width:2px
    style F fill:#f9f,stroke:#333,stroke-width:2px
    style I fill:#f9f,stroke:#333,stroke-width:2px
    style L fill:#f9f,stroke:#333,stroke-width:2px

Singleton Access

Each checkpoint manager provides a singleton instance via a get...Manager() function (e.g., getCheckpointManager(), getPersistentCheckpointManager()). This ensures that only one instance of each manager exists throughout the application's lifecycle, maintaining a consistent state. A corresponding reset...Manager() function is available for testing or explicit cleanup.

When to Use Which Manager