file-tracker
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFile 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.
将每一次文件变更(写入、编辑、删除)记录到SQLite数据库,用于调试、审计追踪和版本历史记录。可与任何文件操作系统或代码编辑器配合使用。
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
- 开发过程中追踪文件修改
- 创建文件变更的审计追踪记录
- 调试哪些文件在何时被修改
- 无需Git即可构建版本历史
- 用户要求追踪或查看文件变更
Required tools / APIs
所需工具/API
- Python standard library (sqlite3, datetime, os)
- Any programming language with SQLite support
No external APIs or services required.
- Python标准库(sqlite3、datetime、os)
- 任何支持SQLite的编程语言
无需外部API或服务。
Database Schema
数据库 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:
- - Auto-incrementing primary key
id - - ISO 8601 timestamp of the change
timestamp - - Type of operation: 'write', 'edit', 'delete', 'rename'
action - - Absolute or relative path to the file
file_path - - Previous content (for edits) or deleted content (for deletes)
old_content - - New content (for writes/edits)
new_content - - File size in bytes after operation
file_size - - JSON field for additional context (user, session, tools)
metadata - - Database insertion timestamp
created_at
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');字段说明:
- - 自增主键
id - - 变更的ISO 8601时间戳
timestamp - - 操作类型:'write'、'edit'、'delete'、'rename'
action - - 文件的绝对或相对路径
file_path - - 之前的内容(用于编辑操作)或已删除的内容(用于删除操作)
old_content - - 新内容(用于写入/编辑操作)
new_content - - 操作后的文件大小(字节)
file_size - - JSON字段,用于存储额外上下文(用户、会话、工具等)
metadata - - 数据库插入时间戳
created_at
Basic Implementation
基础实现
Python
Python
Initialize database:
python
import sqlite3
from datetime import datetime
from pathlib import Path
import json
import os初始化数据库:
python
import sqlite3
from datetime import datetime
from pathlib import Path
import json
import osConfigure database path (customize as needed)
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()
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
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()init_db()
purge_old_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
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)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"})
**追踪的文件操作:**
```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
Usage
tracked_write("example.txt", "Hello, World!")
tracked_edit("example.txt", "Hello, World!", "Hello, Python!")
tracked_delete("example.txt")
**Query file history:**
```python
def get_file_history(file_path: str, limit: int = 20):
"""Get change history for a specific file."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, old_content, new_content, file_size
FROM file_changes
WHERE file_path = ?
ORDER BY timestamp DESC
LIMIT ?""",
(file_path, limit)
)
results = cursor.fetchall()
conn.close()
return results
def get_recent_changes(limit: int = 50):
"""Get recent file changes across all files."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, file_path, file_size
FROM file_changes
ORDER BY timestamp DESC
LIMIT ?""",
(limit,)
)
results = cursor.fetchall()
conn.close()
return results
def search_file_changes(pattern: str):
"""Search for files matching a pattern."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, file_path
FROM file_changes
WHERE file_path LIKE ?
ORDER BY timestamp DESC""",
(f"%{pattern}%",)
)
results = cursor.fetchall()
conn.close()
return results
def get_changes_by_action(action: str, limit: int = 50):
"""Get all changes of a specific type (write, edit, delete)."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, file_path, file_size
FROM file_changes
WHERE action = ?
ORDER BY timestamp DESC
LIMIT ?""",
(action, limit)
)
results = cursor.fetchall()
conn.close()
return resultstracked_write("example.txt", "Hello, World!")
tracked_edit("example.txt", "Hello, World!", "Hello, Python!")
tracked_delete("example.txt")
**查询文件历史:**
```python
def get_file_history(file_path: str, limit: int = 20):
"""Get change history for a specific file."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, old_content, new_content, file_size
FROM file_changes
WHERE file_path = ?
ORDER BY timestamp DESC
LIMIT ?""",
(file_path, limit)
)
results = cursor.fetchall()
conn.close()
return results
def get_recent_changes(limit: int = 50):
"""Get recent file changes across all files."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, file_path, file_size
FROM file_changes
ORDER BY timestamp DESC
LIMIT ?""",
(limit,)
)
results = cursor.fetchall()
conn.close()
return results
def search_file_changes(pattern: str):
"""Search for files matching a pattern."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, action, file_path
FROM file_changes
WHERE file_path LIKE ?
ORDER BY timestamp DESC""",
(f"%{pattern}%",)
)
results = cursor.fetchall()
conn.close()
return results
def get_changes_by_action(action: str, limit: int = 50):
"""Get all changes of a specific type (write, edit, delete)."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"""SELECT timestamp, file_path, file_size
FROM file_changes
WHERE action = ?
ORDER BY timestamp DESC
LIMIT ?""",
(action, limit)
)
results = cursor.fetchall()
conn.close()
return resultsUsage
Usage
history = get_file_history("/path/to/file.py")
for change in history:
print(f"[{change['timestamp']}] {change['action']}: {change['file_size']} bytes")
recent = get_recent_changes(10)
print(f"Last {len(recent)} file changes")
edits = get_changes_by_action("edit", limit=20)
print(f"Found {len(edits)} file edits")
undefinedhistory = get_file_history("/path/to/file.py")
for change in history:
print(f"[{change['timestamp']}] {change['action']}: {change['file_size']} bytes")
recent = get_recent_changes(10)
print(f"Last {len(recent)} file changes")
edits = get_changes_by_action("edit", limit=20)
print(f"Found {len(edits)} file edits")
undefinedNode.js
Node.js
javascript
import sqlite3 from "sqlite3";
import { promisify } from "util";
import path from "path";
import os from "os";
import fs from "fs/promises";
const DB_PATH = path.join(os.homedir(), ".file_tracker", "changes.db");
// Initialize database
const db = new sqlite3.Database(DB_PATH);
const run = promisify(db.run.bind(db));
const all = promisify(db.all.bind(db));
await run(`
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
)
`);
// Log file change
async function logFileChange(action, filePath, oldContent = null, newContent = null, metadata = null) {
let fileSize = null;
try {
if (action !== "delete") {
const stats = await fs.stat(filePath);
fileSize = stats.size;
}
} catch (err) {
// File might not exist
}
await run(
`INSERT INTO file_changes (timestamp, action, file_path, old_content, new_content, file_size, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[
new Date().toISOString(),
action,
filePath,
oldContent,
newContent,
fileSize,
metadata ? JSON.stringify(metadata) : null,
]
);
}
// Tracked file operations
async function trackedWrite(filePath, content, metadata = null) {
await fs.writeFile(filePath, content);
await logFileChange("write", filePath, null, content, metadata);
}
async function trackedEdit(filePath, oldContent, newContent, metadata = null) {
await fs.writeFile(filePath, newContent);
await logFileChange("edit", filePath, oldContent, newContent, metadata);
}
// Query history
async function getFileHistory(filePath, limit = 20) {
return await all(
`SELECT timestamp, action, old_content, new_content, file_size
FROM file_changes
WHERE file_path = ?
ORDER BY timestamp DESC
LIMIT ?`,
[filePath, limit]
);
}
// Usage
await trackedWrite("example.txt", "Hello, World!");
const history = await getFileHistory("example.txt");
console.log(history);javascript
import sqlite3 from "sqlite3";
import { promisify } from "util";
import path from "path";
import os from "os";
import fs from "fs/promises";
const DB_PATH = path.join(os.homedir(), ".file_tracker", "changes.db");
// Initialize database
const db = new sqlite3.Database(DB_PATH);
const run = promisify(db.run.bind(db));
const all = promisify(db.all.bind(db));
await run(`
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
)
`);
// Log file change
async function logFileChange(action, filePath, oldContent = null, newContent = null, metadata = null) {
let fileSize = null;
try {
if (action !== "delete") {
const stats = await fs.stat(filePath);
fileSize = stats.size;
}
} catch (err) {
// File might not exist
}
await run(
`INSERT INTO file_changes (timestamp, action, file_path, old_content, new_content, file_size, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[
new Date().toISOString(),
action,
filePath,
oldContent,
newContent,
fileSize,
metadata ? JSON.stringify(metadata) : null,
]
);
}
// Tracked file operations
async function trackedWrite(filePath, content, metadata = null) {
await fs.writeFile(filePath, content);
await logFileChange("write", filePath, null, content, metadata);
}
async function trackedEdit(filePath, oldContent, newContent, metadata = null) {
await fs.writeFile(filePath, newContent);
await logFileChange("edit", filePath, oldContent, newContent, metadata);
}
// Query history
async function getFileHistory(filePath, limit = 20) {
return await all(
`SELECT timestamp, action, old_content, new_content, file_size
FROM file_changes
WHERE file_path = ?
ORDER BY timestamp DESC
LIMIT ?`,
[filePath, limit]
);
}
// Usage
await trackedWrite("example.txt", "Hello, World!");
const history = await getFileHistory("example.txt");
console.log(history);Bash Quick Queries
Bash 快速查询
bash
undefinedbash
undefinedView recent file changes
View recent file changes
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action, file_path FROM file_changes ORDER BY timestamp DESC LIMIT 20"
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action, file_path FROM file_changes ORDER BY timestamp DESC LIMIT 20"
Get history for a specific file
Get history for a specific file
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action FROM file_changes WHERE file_path='/path/to/file' ORDER BY timestamp DESC"
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action FROM file_changes WHERE file_path='/path/to/file' ORDER BY timestamp DESC"
Count changes by action type
Count changes by action type
sqlite3 ~/.file_tracker/changes.db "SELECT action, COUNT(*) as count FROM file_changes GROUP BY action"
sqlite3 ~/.file_tracker/changes.db "SELECT action, COUNT(*) as count FROM file_changes GROUP BY action"
Find all Python file changes
Find all Python file changes
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action, file_path FROM file_changes WHERE file_path LIKE '%.py' ORDER BY timestamp DESC"
sqlite3 ~/.file_tracker/changes.db "SELECT timestamp, action, file_path FROM file_changes WHERE file_path LIKE '%.py' ORDER BY timestamp DESC"
Export file history to JSON
Export file history to JSON
sqlite3 -json ~/.file_tracker/changes.db "SELECT * FROM file_changes WHERE file_path='/path/to/file' ORDER BY timestamp ASC" > file_history.json
undefinedsqlite3 -json ~/.file_tracker/changes.db "SELECT * FROM file_changes WHERE file_path='/path/to/file' ORDER BY timestamp ASC" > file_history.json
undefinedIntegration Examples
集成示例
Context Manager Pattern
上下文管理器模式
python
class FileChangeTracker:
"""Context manager to automatically track file changes."""
def __init__(self, file_path: str, action: str = "edit", metadata: dict = None):
self.file_path = file_path
self.action = action
self.metadata = metadata
self.old_content = None
def __enter__(self):
if os.path.exists(self.file_path):
with open(self.file_path, 'r') as f:
self.old_content = f.read()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None: # No exception
new_content = None
if os.path.exists(self.file_path):
with open(self.file_path, 'r') as f:
new_content = f.read()
log_file_change(
self.action,
self.file_path,
old_content=self.old_content,
new_content=new_content,
metadata=self.metadata
)python
class FileChangeTracker:
"""Context manager to automatically track file changes."""
def __init__(self, file_path: str, action: str = "edit", metadata: dict = None):
self.file_path = file_path
self.action = action
self.metadata = metadata
self.old_content = None
def __enter__(self):
if os.path.exists(self.file_path):
with open(self.file_path, 'r') as f:
self.old_content = f.read()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None: # No exception
new_content = None
if os.path.exists(self.file_path):
with open(self.file_path, 'r') as f:
new_content = f.read()
log_file_change(
self.action,
self.file_path,
old_content=self.old_content,
new_content=new_content,
metadata=self.metadata
)Usage
Usage
with FileChangeTracker("config.json", action="edit"):
# Modify file
with open("config.json", 'w') as f:
f.write('{"updated": true}')
with FileChangeTracker("config.json", action="edit"):
# Modify file
with open("config.json", 'w') as f:
f.write('{"updated": true}')
Change is automatically logged on exit
Change is automatically logged on exit
undefinedundefinedDecorator Pattern
装饰器模式
python
def track_file_operation(action: str):
"""Decorator to track file operations."""
def decorator(func):
def wrapper(file_path, *args, **kwargs):
# Read old content if file exists
old_content = None
if os.path.exists(file_path) and action in ["edit", "delete"]:
with open(file_path, 'r') as f:
old_content = f.read()
# Execute operation
result = func(file_path, *args, **kwargs)
# Read new content
new_content = None
if os.path.exists(file_path) and action in ["write", "edit"]:
with open(file_path, 'r') as f:
new_content = f.read()
# Log change
log_file_change(action, file_path, old_content, new_content)
return result
return wrapper
return decoratorpython
def track_file_operation(action: str):
"""Decorator to track file operations."""
def decorator(func):
def wrapper(file_path, *args, **kwargs):
# Read old content if file exists
old_content = None
if os.path.exists(file_path) and action in ["edit", "delete"]:
with open(file_path, 'r') as f:
old_content = f.read()
# Execute operation
result = func(file_path, *args, **kwargs)
# Read new content
new_content = None
if os.path.exists(file_path) and action in ["write", "edit"]:
with open(file_path, 'r') as f:
new_content = f.read()
# Log change
log_file_change(action, file_path, old_content, new_content)
return result
return wrapper
return decoratorUsage
Usage
@track_file_operation("write")
def create_file(path, content):
with open(path, 'w') as f:
f.write(content)
@track_file_operation("edit")
def update_file(path, new_content):
with open(path, 'w') as f:
f.write(new_content)
undefined@track_file_operation("write")
def create_file(path, content):
with open(path, 'w') as f:
f.write(content)
@track_file_operation("edit")
def update_file(path, new_content):
with open(path, 'w') as f:
f.write(new_content)
undefinedAgent Prompt
Agent 提示词
text
You have file change tracking capability. All file operations are logged to a SQLite database.
When user asks to:
- Review file change history
- Track what files were modified
- Find when a file was changed
- Audit file operations
Use the SQLite database at ~/.file_tracker/changes.db with this schema:
- file_changes table (id, timestamp, action, file_path, old_content, new_content, file_size, metadata)
After performing file operations (write, edit, delete), always log them:
- Write: log_file_change("write", file_path, new_content=content)
- Edit: log_file_change("edit", file_path, old_content=old, new_content=new)
- Delete: log_file_change("delete", file_path, old_content=content)
Query examples:
1. File history: SELECT * FROM file_changes WHERE file_path = ? ORDER BY timestamp DESC
2. Recent changes: SELECT * FROM file_changes ORDER BY timestamp DESC LIMIT 50
3. Search files: SELECT * FROM file_changes WHERE file_path LIKE '%pattern%'
Always log file operations for audit trail and debugging purposes.text
You have file change tracking capability. All file operations are logged to a SQLite database.
When user asks to:
- Review file change history
- Track what files were modified
- Find when a file was changed
- Audit file operations
Use the SQLite database at ~/.file_tracker/changes.db with this schema:
- file_changes table (id, timestamp, action, file_path, old_content, new_content, file_size, metadata)
After performing file operations (write, edit, delete), always log them:
- Write: log_file_change("write", file_path, new_content=content)
- Edit: log_file_change("edit", file_path, old_content=old, new_content=new)
- Delete: log_file_change("delete", file_path, old_content=content)
Query examples:
1. File history: SELECT * FROM file_changes WHERE file_path = ? ORDER BY timestamp DESC
2. Recent changes: SELECT * FROM file_changes ORDER BY timestamp DESC LIMIT 50
3. Search files: SELECT * FROM file_changes WHERE file_path LIKE '%pattern%'
Always log file operations for audit trail and debugging purposes.Best Practices
最佳实践
- Truncate large content (e.g., 5000 chars) to avoid database bloat
- Use indexes on file_path, timestamp, and action for fast queries
- Store full paths for clarity and uniqueness
- Log metadata (user, session) for context
- Regular cleanup of old entries to manage database size
- Privacy: avoid storing sensitive file content
- Compression: consider compressing old_content/new_content for large text files
- 截断大内容(例如5000字符),避免数据库膨胀
- 使用索引,对file_path、timestamp和action字段建立索引以加快查询
- 存储完整路径,确保清晰性和唯一性
- 记录元数据(用户、会话)以获取上下文信息
- 定期清理旧条目,控制数据库大小
- 隐私保护:避免存储敏感文件内容
- 压缩:对于大文本文件,考虑压缩old_content/new_content字段
Troubleshooting
故障排除
Database getting too large:
- Truncate old entries:
DELETE FROM file_changes WHERE timestamp < '2024-01-01' - Run VACUUM:
sqlite3 changes.db "VACUUM" - Limit content stored (already truncated to 5000 chars)
Missing file changes:
- Ensure log_file_change() is called after every file operation
- Check file permissions for database writes
- Verify DB_PATH is accessible
Query performance slow:
- Ensure indexes exist (file_path, timestamp, action)
- Use LIMIT on queries
- Consider archiving old entries
数据库过大:
- 删除旧条目:
DELETE FROM file_changes WHERE timestamp < '2024-01-01' - 执行VACUUM命令:
sqlite3 changes.db "VACUUM" - 限制存储的内容(已默认截断为5000字符)
文件变更记录缺失:
- 确保每次文件操作后都调用了log_file_change()
- 检查数据库写入的文件权限
- 验证DB_PATH路径是否可访问
查询性能缓慢:
- 确保已建立索引(file_path、timestamp、action)
- 在查询中使用LIMIT限制结果数量
- 考虑归档旧条目
See also
另请参阅
- ../chat-logger/SKILL.md — Log chat messages
- ../generate-report/SKILL.md — Generate HTML reports
- ../chat-logger/SKILL.md — 记录聊天消息
- ../generate-report/SKILL.md — 生成HTML报告