Makelore 2.0 initial clean snapshot

This commit is contained in:
inman
2026-07-29 17:22:35 +08:00
commit b8ca3f8eea
694 changed files with 139782 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
import { createHash } from 'node:crypto';
import path from 'node:path';
export interface OpencodeProject {
id: string;
path: string;
name: string;
createdAt: string;
updatedAt: string;
lastOpenedAt: string;
}
export interface ProjectStoreData {
projects: Record<string, OpencodeProject>;
activeProjectId: string | null;
}
export type ProjectStoreChange =
| { type: 'upsert'; project: OpencodeProject }
| { type: 'remove'; projectId: string };
export type ProjectStoreListener = (change: ProjectStoreChange) => void;
export interface ProjectStorage {
read(): Promise<ProjectStoreData | undefined>;
write(data: ProjectStoreData): Promise<void>;
}
export interface ProjectKeyValueStore {
get(key: string): unknown;
set(key: string, value: ProjectStoreData): unknown;
}
export type OpencodeProjectStore = ReturnType<typeof createProjectStore>;
const DEFAULT_PROJECT_STORE_KEY = 'projects';
export function normalizeProjectPath(input: string): string {
const normalized = path.normalize(path.resolve(input.trim()));
return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
}
export function getProjectIdForPath(input: string): string {
const hash = createHash('sha256').update(normalizeProjectPath(input)).digest('hex');
return `prj_${hash.slice(0, 16)}`;
}
export function createMemoryProjectStorage(initial?: ProjectStoreData): ProjectStorage {
let stored = initial ? structuredClone(initial) : undefined;
return {
async read() {
return stored ? structuredClone(stored) : undefined;
},
async write(data) {
stored = structuredClone(data);
},
};
}
export function createProjectStorageFromStore(
store: ProjectKeyValueStore,
key = DEFAULT_PROJECT_STORE_KEY,
): ProjectStorage {
return {
async read() {
const data = store.get(key);
return data ? structuredClone(data) as ProjectStoreData : undefined;
},
async write(data) {
store.set(key, structuredClone(data));
},
};
}
export async function createElectronProjectStorage(): Promise<ProjectStorage> {
const Store = (await import('electron-store')).default;
const store = new Store<{ projects?: ProjectStoreData }>({
name: 'opencode-projects',
});
return createProjectStorageFromStore(store);
}
function createEmptyData(): ProjectStoreData {
return {
projects: {},
activeProjectId: null,
};
}
async function readData(storage: ProjectStorage): Promise<ProjectStoreData> {
return (await storage.read()) ?? createEmptyData();
}
export function createProjectStore(storage: ProjectStorage) {
const listeners = new Set<ProjectStoreListener>();
function emit(change: ProjectStoreChange): void {
for (const listener of listeners) {
try {
listener(change);
} catch {
// An observer must not break project persistence for other callers.
}
}
}
async function upsertProjectRecord(
input: string,
options?: { activate?: boolean },
): Promise<OpencodeProject> {
const data = await readData(storage);
const normalizedPath = normalizeProjectPath(input);
const id = getProjectIdForPath(normalizedPath);
const now = new Date().toISOString();
const existing = data.projects[id];
const project: OpencodeProject = existing
? {
...existing,
path: normalizedPath,
name: path.basename(normalizedPath),
updatedAt: now,
lastOpenedAt: now,
}
: {
id,
path: normalizedPath,
name: path.basename(normalizedPath),
createdAt: now,
updatedAt: now,
lastOpenedAt: now,
};
data.projects[id] = project;
if (options?.activate) {
data.activeProjectId = id;
}
await storage.write(data);
emit({ type: 'upsert', project });
return project;
}
return {
async openFolder(input: string): Promise<OpencodeProject> {
return await upsertProjectRecord(input, { activate: true });
},
async rememberProject(input: string): Promise<OpencodeProject> {
return await upsertProjectRecord(input, { activate: false });
},
async listProjects(): Promise<OpencodeProject[]> {
const data = await readData(storage);
return Object.values(data.projects).sort((left, right) =>
right.lastOpenedAt.localeCompare(left.lastOpenedAt),
);
},
async getActiveProject(): Promise<OpencodeProject | null> {
const data = await readData(storage);
return data.activeProjectId ? data.projects[data.activeProjectId] ?? null : null;
},
async setActiveProject(projectId: string | null): Promise<OpencodeProject | null> {
const data = await readData(storage);
data.activeProjectId = projectId && data.projects[projectId] ? projectId : null;
await storage.write(data);
return data.activeProjectId ? data.projects[data.activeProjectId] : null;
},
async removeProject(projectId: string): Promise<void> {
const data = await readData(storage);
delete data.projects[projectId];
if (data.activeProjectId === projectId) {
data.activeProjectId = null;
}
await storage.write(data);
emit({ type: 'remove', projectId });
},
subscribe(listener: ProjectStoreListener): () => void {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
},
};
}