refactor: make root path for configurations
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
SUPERMEMORY_API_KEY=
|
||||
|
||||
BRAINDB_PATH=./braindb.json
|
||||
BRAINBOX_ROOT_PATH=./brainbox-data
|
||||
|
||||
OPENROUTER_API_KEY=
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,6 +27,9 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# brainbox data
|
||||
brainbox-data/
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { config } from "@/config";
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
export interface BrainItem {
|
||||
brainId: string;
|
||||
@@ -7,51 +8,90 @@ export interface BrainItem {
|
||||
displayName: string;
|
||||
baseSystemPrompt: string;
|
||||
}
|
||||
export type BrainDB = Record<string, BrainItem>;
|
||||
export type BrainList = BrainItem[];
|
||||
|
||||
// Layout:
|
||||
// <root>/brains.json — BrainItem[] index, mirror
|
||||
// <root>/<brainId>/brain.json — BrainItem per brain, source of truth
|
||||
|
||||
export class BrainDBManager {
|
||||
constructor(private readonly braindbPath: string = config.braindbPath) {}
|
||||
constructor(private readonly root: string = config.brainboxRoot) {}
|
||||
|
||||
private get db() {
|
||||
return readFile(this.braindbPath, { encoding: "utf-8" }).then(
|
||||
(content) => {
|
||||
return JSON.parse(content) as BrainDB;
|
||||
},
|
||||
private brainDir(brainId: string): string {
|
||||
return join(this.root, brainId);
|
||||
}
|
||||
|
||||
private brainFile(brainId: string): string {
|
||||
return join(this.brainDir(brainId), "brain.json");
|
||||
}
|
||||
|
||||
private indexFile(): string {
|
||||
return join(this.root, "brains.json");
|
||||
}
|
||||
|
||||
private async readIndex(): Promise<BrainList> {
|
||||
try {
|
||||
const content = await readFile(this.indexFile(), { encoding: "utf-8" });
|
||||
return JSON.parse(content) as BrainList;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private async writeIndex(list: BrainList): Promise<void> {
|
||||
await mkdir(this.root, { recursive: true });
|
||||
await writeFile(
|
||||
this.indexFile(),
|
||||
JSON.stringify(list, null, 2),
|
||||
{ encoding: "utf-8" },
|
||||
);
|
||||
}
|
||||
|
||||
private async writeDb(db: BrainDB) {
|
||||
await writeFile(this.braindbPath, JSON.stringify(db), {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
private async writeBrain(brain: BrainItem): Promise<void> {
|
||||
await mkdir(this.brainDir(brain.brainId), { recursive: true });
|
||||
await writeFile(
|
||||
this.brainFile(brain.brainId),
|
||||
JSON.stringify(brain, null, 2),
|
||||
{ encoding: "utf-8" },
|
||||
);
|
||||
}
|
||||
|
||||
async loadBrain(brainId: string): Promise<BrainItem | undefined> {
|
||||
const brainOrNot = (await this.db)[brainId];
|
||||
return brainOrNot;
|
||||
try {
|
||||
const content = await readFile(this.brainFile(brainId), {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
return JSON.parse(content) as BrainItem;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async saveBrain(brainId: string, brain: BrainItem) {
|
||||
const db = await this.db;
|
||||
db[brainId] = brain;
|
||||
await this.writeDb(db);
|
||||
async saveBrain(brainId: string, brain: BrainItem): Promise<void> {
|
||||
await this.writeBrain(brain);
|
||||
const list = await this.readIndex();
|
||||
const idx = list.findIndex((b) => b.brainId === brainId);
|
||||
if (idx >= 0) list[idx] = brain;
|
||||
else list.push(brain);
|
||||
await this.writeIndex(list);
|
||||
}
|
||||
|
||||
async listBrain() {
|
||||
return Object.entries(await this.db).map(
|
||||
([_, { brainId, displayName }]) => ({ brainId, displayName }),
|
||||
);
|
||||
async listBrain(): Promise<Array<{ brainId: string; displayName: string }>> {
|
||||
const list = await this.readIndex();
|
||||
return list.map(({ brainId, displayName }) => ({ brainId, displayName }));
|
||||
}
|
||||
|
||||
async deleteBrain(brainId: string) {
|
||||
const db = await this.db;
|
||||
delete db[brainId];
|
||||
await this.writeDb(db);
|
||||
async deleteBrain(brainId: string): Promise<void> {
|
||||
await rm(this.brainDir(brainId), { recursive: true, force: true });
|
||||
const list = await this.readIndex();
|
||||
const filtered = list.filter((b) => b.brainId !== brainId);
|
||||
if (filtered.length === list.length) return;
|
||||
await this.writeIndex(filtered);
|
||||
}
|
||||
|
||||
async isBrainAvailable(brainId: string) {
|
||||
return brainId in (await this.db);
|
||||
async isBrainAvailable(brainId: string): Promise<boolean> {
|
||||
return (await this.loadBrain(brainId)) !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const brainManager = new BrainDBManager();
|
||||
export const brainManager = new BrainDBManager();
|
||||
@@ -4,7 +4,7 @@ import { join } from "path";
|
||||
export interface Config {
|
||||
openrouterApiKey: string;
|
||||
supermemoryApiKey: string;
|
||||
braindbPath: string;
|
||||
brainboxRoot: string;
|
||||
}
|
||||
|
||||
const openrouterApiKey = process.env["OPENROUTER_API_KEY"];
|
||||
@@ -13,13 +13,13 @@ if (!openrouterApiKey) throw new Error("OPENROUTER_API_KEY is missing");
|
||||
const supermemoryApiKey = process.env["SUPERMEMORY_API_KEY"];
|
||||
if (!supermemoryApiKey) throw new Error("SUPERMEMORY_API_KEY is missing");
|
||||
|
||||
const braindbPath = join(
|
||||
const brainboxRoot = join(
|
||||
process.cwd(),
|
||||
process.env["BRAINDB_PATH"] ?? "brainbox.json",
|
||||
process.env["BRAINBOX_ROOT_PATH"] ?? "brainbox-data",
|
||||
);
|
||||
|
||||
export const config: Config = {
|
||||
openrouterApiKey,
|
||||
supermemoryApiKey,
|
||||
braindbPath,
|
||||
brainboxRoot,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user