mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-16 18:25:17 +02:00
fixes
This commit is contained in:
parent
3cdcafdf97
commit
3ccdbb614c
6 changed files with 68 additions and 5 deletions
|
|
@ -96,4 +96,4 @@ ensureWelcomeFile();
|
|||
// Initialize version history repo (async, fire-and-forget on startup)
|
||||
import('../knowledge/version_history.js').then(m => m.initRepo()).catch(err => {
|
||||
console.error('[VersionHistory] Failed to init repo:', err);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ export * as watcher from './workspace/watcher.js';
|
|||
export { initConfigs } from './config/initConfigs.js';
|
||||
|
||||
// Knowledge version history
|
||||
export * as versionHistory from './knowledge/version_history.js';
|
||||
export * as versionHistory from './knowledge/version_history.js';
|
||||
|
|
|
|||
|
|
@ -5,6 +5,21 @@ import { WorkDir } from '../config/config.js';
|
|||
|
||||
const KNOWLEDGE_DIR = path.join(WorkDir, 'knowledge');
|
||||
|
||||
// Simple promise-based mutex to serialize commits
|
||||
let commitLock: Promise<void> = Promise.resolve();
|
||||
|
||||
// Commit listeners for notifying other layers (e.g. renderer refresh)
|
||||
type CommitListener = () => void;
|
||||
const commitListeners: CommitListener[] = [];
|
||||
|
||||
export function onCommit(listener: CommitListener): () => void {
|
||||
commitListeners.push(listener);
|
||||
return () => {
|
||||
const idx = commitListeners.indexOf(listener);
|
||||
if (idx >= 0) commitListeners.splice(idx, 1);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a git repo in the knowledge directory if one doesn't exist.
|
||||
* Stages all existing .md files and makes an initial commit.
|
||||
|
|
@ -66,8 +81,22 @@ function getAllMdFiles(baseDir: string, relDir: string): string[] {
|
|||
|
||||
/**
|
||||
* Stage all changes to .md files and commit. No-op if nothing changed.
|
||||
* Serialized via a promise lock to prevent concurrent git index corruption.
|
||||
*/
|
||||
export async function commitAll(message: string, authorName: string): Promise<void> {
|
||||
const prev = commitLock;
|
||||
let resolve: () => void;
|
||||
commitLock = new Promise(r => { resolve = r; });
|
||||
|
||||
await prev;
|
||||
try {
|
||||
await commitAllInner(message, authorName);
|
||||
} finally {
|
||||
resolve!();
|
||||
}
|
||||
}
|
||||
|
||||
async function commitAllInner(message: string, authorName: string): Promise<void> {
|
||||
const matrix = await git.statusMatrix({ fs, dir: KNOWLEDGE_DIR });
|
||||
|
||||
let hasChanges = false;
|
||||
|
|
@ -98,6 +127,10 @@ export async function commitAll(message: string, authorName: string): Promise<vo
|
|||
message,
|
||||
author: { name: authorName, email: 'local' },
|
||||
});
|
||||
|
||||
for (const listener of commitListeners) {
|
||||
try { listener(); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
export interface CommitInfo {
|
||||
|
|
@ -107,9 +140,12 @@ export interface CommitInfo {
|
|||
author: string;
|
||||
}
|
||||
|
||||
const MAX_FILE_HISTORY = 50;
|
||||
|
||||
/**
|
||||
* Get commit history for a specific file.
|
||||
* Returns commits where the file content changed, most recent first.
|
||||
* Capped at MAX_FILE_HISTORY entries.
|
||||
*/
|
||||
export async function getFileHistory(knowledgeRelPath: string): Promise<CommitInfo[]> {
|
||||
// Normalize path separators for git (always forward slashes)
|
||||
|
|
@ -128,6 +164,8 @@ export async function getFileHistory(knowledgeRelPath: string): Promise<CommitIn
|
|||
|
||||
// Walk through commits and check if file changed between consecutive commits
|
||||
for (let i = 0; i < commits.length; i++) {
|
||||
if (result.length >= MAX_FILE_HISTORY) break;
|
||||
|
||||
const commit = commits[i]!;
|
||||
const parentCommit = commits[i + 1]; // undefined for the first (oldest) commit
|
||||
|
||||
|
|
|
|||
|
|
@ -417,6 +417,10 @@ const ipcSchemas = {
|
|||
req: z.object({ path: RelPath, oid: z.string() }),
|
||||
res: z.object({ ok: z.literal(true) }),
|
||||
},
|
||||
'knowledge:didCommit': {
|
||||
req: z.object({}),
|
||||
res: z.null(),
|
||||
},
|
||||
// Search channels
|
||||
'search:query': {
|
||||
req: z.object({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue