Skip to main content
ClaudeWave
Skill122 estrellas del repoactualizado 26d ago

file-tracker

Log all file changes (write, edit, delete) to a SQLite database for debugging and audit. Use when: (1) Tracking code changes, (2) Debugging issues, (3) Auditing file modifications, or (4) The user asks to track file changes.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/besoeasy/open-skills /tmp/file-tracker && cp -r /tmp/file-tracker/skills/file-tracker ~/.claude/skills/file-tracker
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# File Tracker

Log every file change (write, edit, delete) to a SQLite database for debugging, audit trails, and version history tracking. Works with any file operation system or code editor.

## When to use

- Tracking file modifications during development
- Creating audit trails for file changes
- Debugging what files were modified and when
- Building version history without git
- User asks to track or review file changes

## Required tools / APIs

- Python standard library (sqlite3, datetime, os)
- Any programming language with SQLite support

No external APIs or services required.

## Database Schema

```sql
CREATE TABLE IF NOT EXISTS file_changes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  timestamp TEXT NOT NULL,
  action TEXT NOT NULL,              -- 'write', 'edit', 'delete', 'rename'
  file_path TEXT NOT NULL,
  old_content TEXT,                  -- for edits/deletes
  new_content TEXT,                  -- for writes/edits
  file_size INTEGER,                 -- size in bytes
  metadata TEXT,                     -- JSON: user, session_id, etc.
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_file_path ON file_changes(file_path);
CREATE INDEX idx_timestamp ON file_changes(timestamp);
CREATE INDEX idx_action ON file_changes(action);

-- Automatic purge: delete records older than 1 year
DELETE FROM file_changes WHERE created_at < datetime('now', '-1 year');
```

**Fields:**
- `id` - Auto-incrementing primary key
- `timestamp` - ISO 8601 timestamp of the change
- `action` - Type of operation: 'write', 'edit', 'delete', 'rename'
- `file_path` - Absolute or relative path to the file
- `old_content` - Previous content (for edits) or deleted content (for deletes)
- `new_content` - New content (for writes/edits)
- `file_size` - File size in bytes after operation
- `metadata` - JSON field for additional context (user, session, tools)
- `created_at` - Database insertion timestamp

## Basic Implementation

### Python

**Initialize database:**

```python
import sqlite3
from datetime import datetime
from pathlib import Path
import json
import os

# Configure database path (customize as needed)
DB_PATH = Path.home() / ".file_tracker" / "changes.db"

def init_db():
    """Initialize database and create tables."""
    DB_PATH.parent.mkdir(parents=True, exist_ok=True)
    conn = sqlite3.connect(str(DB_PATH))
    conn.execute("""
        CREATE TABLE IF NOT EXISTS file_changes (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT NOT NULL,
            action TEXT NOT NULL,
            file_path TEXT NOT NULL,
            old_content TEXT,
            new_content TEXT,
            file_size INTEGER,
            metadata TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    """)
    conn.execute("CREATE INDEX IF NOT EXISTS idx_file_path ON file_changes(file_path)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_timestamp ON file_changes(timestamp)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_action ON file_changes(action)")
    conn.commit()
    conn.close()

def purge_old_changes():
    """Delete file change records older than 1 year to keep the database size sane."""
    conn = sqlite3.connect(str(DB_PATH))
    conn.execute("DELETE FROM file_changes WHERE created_at < datetime('now', '-1 year')")
    conn.commit()
    conn.close()

# Initialize on import and purge old records
init_db()
purge_old_changes()
```

**Log file changes:**

```python
def log_file_change(
    action: str,
    file_path: str,
    old_content: str = None,
    new_content: str = None,
    metadata: dict = None
):
    """Log a file change to the database."""
    conn = sqlite3.connect(str(DB_PATH))
    try:
        # Get file size if file exists
        file_size = None
        if os.path.exists(file_path) and action != "delete":
            file_size = os.path.getsize(file_path)

        conn.execute(
            """INSERT INTO file_changes
               (timestamp, action, file_path, old_content, new_content, file_size, metadata)
               VALUES (?, ?, ?, ?, ?, ?, ?)""",
            (
                datetime.utcnow().isoformat(),
                action,
                file_path,
                old_content[:5000] if old_content else None,  # Truncate large content
                new_content[:5000] if new_content else None,
                file_size,
                json.dumps(metadata) if metadata else None
            )
        )
        conn.commit()
    finally:
        conn.close()

# Usage examples
log_file_change("write", "/path/to/file.py", new_content="print('Hello')")
log_file_change("edit", "/path/to/file.py", old_content="print('Hello')", new_content="print('Hi')")
log_file_change("delete", "/path/to/file.py", old_content="print('Hi')")
log_file_change("write", "/path/to/config.json", new_content='{"key": "value"}',
                metadata={"user": "john", "session": "sess_123"})
```

**Tracked file operations:**

```python
def tracked_write(file_path: str, content: str, metadata: dict = None):
    """Write file and log the change."""
    with open(file_path, 'w') as f:
        f.write(content)
    log_file_change("write", file_path, new_content=content, metadata=metadata)

def tracked_edit(file_path: str, old_content: str, new_content: str, metadata: dict = None):
    """Edit file and log the change."""
    with open(file_path, 'w') as f:
        f.write(new_content)
    log_file_change("edit", file_path, old_content=old_content,
                    new_content=new_content, metadata=metadata)

def tracked_delete(file_path: str, metadata: dict = None):
    """Delete file and log the change."""
    with open(file_path, 'r') as f:
        old_content = f.read()
    os.remove(file_path)
    log_file_change("delete", file_path, old_content=old_content, metadata=metadata)

# Usage
tracked_write("example.txt", "Hello, World!")
tracked_edit("example.txt", "Hello, World!", "Hello, Python!")
tracked_delete("example.txt")
```

**Query