openai-cli-unofficial
Version:
A powerful OpenAI CLI Coding Agent built with TypeScript
223 lines • 8.66 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckpointService = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const uuid_1 = require("uuid");
class CheckpointService {
constructor() {
this.currentTaskId = null;
this.currentTaskDescription = null;
const projectRoot = process.cwd();
this.checkpointDir = path.join(projectRoot, '.openai-cli', 'checkpoints');
this.manifestPath = path.join(this.checkpointDir, 'manifest.json');
this.initialize();
}
static getInstance() {
if (!CheckpointService.instance) {
CheckpointService.instance = new CheckpointService();
}
return CheckpointService.instance;
}
initialize() {
try {
if (!fs.existsSync(this.checkpointDir)) {
fs.mkdirSync(this.checkpointDir, { recursive: true });
}
if (!fs.existsSync(this.manifestPath)) {
this.saveManifest({ checkpoints: [] });
}
this.loadManifest();
}
catch (error) {
console.error('Failed to initialize CheckpointService:', error);
this.manifest = { checkpoints: [] };
}
}
loadManifest() {
try {
const data = fs.readFileSync(this.manifestPath, 'utf-8');
this.manifest = JSON.parse(data);
}
catch (error) {
this.manifest = { checkpoints: [] };
}
}
saveManifest(manifest) {
try {
fs.writeFileSync(this.manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');
this.manifest = manifest;
}
catch (error) {
console.error('Failed to save checkpoint manifest:', error);
}
}
setCurrentTask(taskId, description) {
this.currentTaskId = taskId;
this.currentTaskDescription = description;
}
clearCurrentTask() {
this.currentTaskId = null;
this.currentTaskDescription = null;
}
async createCheckpoint(originalPath) {
if (!this.currentTaskId)
return;
// 在每次写入操作前,从磁盘重新加载清单,确保数据是最新的
this.loadManifest();
const absoluteOriginalPath = path.resolve(originalPath);
const existing = this.manifest.checkpoints.find(c => c.originalPath === absoluteOriginalPath && c.taskId === this.currentTaskId);
if (existing)
return;
if (!fs.existsSync(absoluteOriginalPath)) {
return this.recordCreate(originalPath);
}
try {
const checkpointId = (0, uuid_1.v4)();
const backupFileName = `${path.basename(originalPath)}.${checkpointId}.bak`;
const checkpointPath = path.join(this.checkpointDir, backupFileName);
fs.copyFileSync(absoluteOriginalPath, checkpointPath);
const newCheckpoint = {
id: checkpointId,
taskId: this.currentTaskId,
timestamp: new Date().toISOString(),
originalPath: absoluteOriginalPath,
checkpointPath: checkpointPath,
type: 'edit',
description: this.currentTaskDescription || 'N/A',
};
const newManifest = { ...this.manifest };
newManifest.checkpoints.push(newCheckpoint);
this.saveManifest(newManifest);
}
catch (error) {
console.error(`Failed to create checkpoint for ${originalPath}:`, error);
}
}
async recordCreate(originalPath) {
if (!this.currentTaskId)
return;
// 在每次写入操作前,从磁盘重新加载清单,确保数据是最新的
this.loadManifest();
const absoluteOriginalPath = path.resolve(originalPath);
const existing = this.manifest.checkpoints.find(c => c.originalPath === absoluteOriginalPath && c.taskId === this.currentTaskId);
if (existing)
return;
try {
const checkpointId = (0, uuid_1.v4)();
const newCheckpoint = {
id: checkpointId,
taskId: this.currentTaskId,
timestamp: new Date().toISOString(),
originalPath: absoluteOriginalPath,
type: 'create',
description: this.currentTaskDescription || 'N/A',
};
const newManifest = { ...this.manifest };
newManifest.checkpoints.push(newCheckpoint);
this.saveManifest(newManifest);
}
catch (error) {
console.error(`Failed to record creation for ${originalPath}:`, error);
}
}
getCheckpoints() {
this.loadManifest();
return this.manifest.checkpoints;
}
getCheckpointsByTask() {
const tasks = new Map();
const checkpoints = this.getCheckpoints();
for (const cp of checkpoints) {
if (!tasks.has(cp.taskId)) {
tasks.set(cp.taskId, []);
}
tasks.get(cp.taskId).push(cp);
}
return tasks;
}
async restoreByTask(taskId) {
this.loadManifest();
const checkpointsForTask = this.manifest.checkpoints.filter(c => c.taskId === taskId);
if (checkpointsForTask.length === 0) {
console.log(`No checkpoints found for task ID: ${taskId}`);
return false;
}
let success = true;
for (const checkpoint of checkpointsForTask.reverse()) {
try {
if (checkpoint.type === 'edit' && checkpoint.checkpointPath) {
if (fs.existsSync(checkpoint.checkpointPath)) {
fs.copyFileSync(checkpoint.checkpointPath, checkpoint.originalPath);
console.log(`Restored: ${checkpoint.originalPath}`);
}
}
else if (checkpoint.type === 'create') {
if (fs.existsSync(checkpoint.originalPath)) {
fs.unlinkSync(checkpoint.originalPath);
console.log(`Deleted: ${checkpoint.originalPath}`);
}
}
}
catch (error) {
console.error(`Failed to restore ${checkpoint.originalPath} for task ${taskId}:`, error);
success = false;
}
}
if (success) {
// Remove restored checkpoints from manifest
const newManifest = {
...this.manifest,
checkpoints: this.manifest.checkpoints.filter(c => c.taskId !== taskId),
};
this.saveManifest(newManifest);
}
return success;
}
async clearAllCheckpoints() {
try {
if (fs.existsSync(this.checkpointDir)) {
fs.rmSync(this.checkpointDir, { recursive: true, force: true });
}
this.initialize(); // Re-create empty dir and manifest
}
catch (error) {
console.error('Failed to clear all checkpoints:', error);
}
}
}
exports.CheckpointService = CheckpointService;
//# sourceMappingURL=checkpoint.js.map