agentcrumbs
Version:
Debug mode for any agent.
152 lines • 4.78 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrumbStore = void 0;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const node_os_1 = __importDefault(require("node:os"));
const DEFAULT_BASE = node_path_1.default.join(node_os_1.default.homedir(), ".agentcrumbs");
const DEFAULT_FILE = "crumbs.jsonl";
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB before rotation
class CrumbStore {
filePath;
fd;
constructor(dir) {
const storeDir = dir ?? DEFAULT_BASE;
if (!node_fs_1.default.existsSync(storeDir)) {
node_fs_1.default.mkdirSync(storeDir, { recursive: true });
}
this.filePath = node_path_1.default.join(storeDir, DEFAULT_FILE);
}
static forApp(app, baseDir) {
const base = baseDir ?? DEFAULT_BASE;
return new CrumbStore(node_path_1.default.join(base, app));
}
static listApps(baseDir) {
const base = baseDir ?? DEFAULT_BASE;
try {
const entries = node_fs_1.default.readdirSync(base, { withFileTypes: true });
return entries
.filter((e) => e.isDirectory())
.map((e) => e.name)
.sort();
}
catch {
return [];
}
}
static readAllApps(baseDir) {
const apps = CrumbStore.listApps(baseDir);
const allCrumbs = [];
for (const app of apps) {
const store = CrumbStore.forApp(app, baseDir);
allCrumbs.push(...store.readAll());
}
// Also read legacy flat file if it exists
const base = baseDir ?? DEFAULT_BASE;
const legacyPath = node_path_1.default.join(base, DEFAULT_FILE);
try {
if (node_fs_1.default.existsSync(legacyPath)) {
const legacy = new CrumbStore(base);
const legacyCrumbs = legacy.readAll();
// Tag legacy crumbs missing app field
for (const crumb of legacyCrumbs) {
if (!crumb.app)
crumb.app = "unknown";
allCrumbs.push(crumb);
}
}
}
catch {
// ignore
}
allCrumbs.sort((a, b) => a.ts.localeCompare(b.ts));
return allCrumbs;
}
ensureFd() {
if (this.fd === undefined) {
this.fd = node_fs_1.default.openSync(this.filePath, "a");
}
return this.fd;
}
append(crumb) {
const line = JSON.stringify(crumb) + "\n";
node_fs_1.default.writeSync(this.ensureFd(), line);
this.maybeRotate();
}
appendRaw(line) {
node_fs_1.default.writeSync(this.ensureFd(), line.endsWith("\n") ? line : line + "\n");
this.maybeRotate();
}
maybeRotate() {
try {
const stat = node_fs_1.default.fstatSync(this.ensureFd());
if (stat.size > MAX_FILE_SIZE) {
this.rotate();
}
}
catch {
// ignore
}
}
rotate() {
if (this.fd !== undefined) {
node_fs_1.default.closeSync(this.fd);
this.fd = undefined;
}
const rotated = this.filePath + ".1";
try {
if (node_fs_1.default.existsSync(rotated))
node_fs_1.default.unlinkSync(rotated);
node_fs_1.default.renameSync(this.filePath, rotated);
}
catch {
// ignore rotation errors
}
}
getFilePath() {
return this.filePath;
}
readAll() {
try {
const content = node_fs_1.default.readFileSync(this.filePath, "utf-8");
return content
.split("\n")
.filter(Boolean)
.map((line) => {
try {
return JSON.parse(line);
}
catch {
return null;
}
})
.filter((c) => c !== null);
}
catch {
return [];
}
}
clear() {
if (this.fd !== undefined) {
node_fs_1.default.closeSync(this.fd);
this.fd = undefined;
}
try {
node_fs_1.default.writeFileSync(this.filePath, "");
}
catch {
// ignore
}
}
close() {
if (this.fd !== undefined) {
node_fs_1.default.closeSync(this.fd);
this.fd = undefined;
}
}
}
exports.CrumbStore = CrumbStore;
//# sourceMappingURL=store.js.map