refactor: remove handbook sync state and related functionality
This commit is contained in:
@@ -4,8 +4,6 @@ import { Trash2, Edit2, Save, X, RefreshCw, AlertCircle, Plus, Link as LinkIcon
|
||||
import * as db from '../../lib/db';
|
||||
import { callLLM } from '../../lib/llm';
|
||||
import { EMIT_GRAPH_ACTIONS_TOOL } from '../../lib/llmTools';
|
||||
import { analyzeHandbookDelta } from '../../lib/extractionPipeline';
|
||||
import { getRepoFolder, getFileContent } from '../../lib/githubService';
|
||||
import Button from '../ui/Button';
|
||||
import SuggestionsQueue from './SuggestionsQueue';
|
||||
|
||||
@@ -20,10 +18,6 @@ const KnowledgeGraph = () => {
|
||||
const [analyzeError, setAnalyzeError] = useState(null);
|
||||
const [newRelData, setNewRelData] = useState({ target: '', type: 'related_to' });
|
||||
|
||||
const [isSyncing, setIsSyncing] = useState(false);
|
||||
const [syncResult, setSyncResult] = useState(null);
|
||||
const [syncError, setSyncError] = useState(null);
|
||||
const [syncProgress, setSyncProgress] = useState(null);
|
||||
|
||||
const [topics, setTopics] = useState([]);
|
||||
const [relations, setRelations] = useState([]);
|
||||
@@ -237,87 +231,6 @@ const KnowledgeGraph = () => {
|
||||
)));
|
||||
};
|
||||
|
||||
const syncHandbook = async () => {
|
||||
setIsSyncing(true);
|
||||
setSyncError(null);
|
||||
setSyncResult(null);
|
||||
|
||||
try {
|
||||
const files = await getRepoFolder('respellion', 'employee-handbook', 'docs');
|
||||
const syncStates = await db.getHandbookSyncStates();
|
||||
|
||||
const added = [];
|
||||
const modified = [];
|
||||
const unchanged = [];
|
||||
|
||||
files.forEach(file => {
|
||||
const state = syncStates.find(s => s.path === file.path);
|
||||
if (!state) {
|
||||
added.push(file);
|
||||
} else if (state.sha !== file.sha) {
|
||||
modified.push(file);
|
||||
} else {
|
||||
unchanged.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
setSyncResult({ added, modified, unchanged, failed: [] });
|
||||
|
||||
const filesToProcess = [...added, ...modified];
|
||||
if (filesToProcess.length > 0) {
|
||||
const total = filesToProcess.length;
|
||||
let done = 0;
|
||||
const failed = [];
|
||||
setSyncProgress(`Processing 0 of ${total} files...`);
|
||||
|
||||
// Run files in parallel with bounded concurrency. The extractionLimiter
|
||||
// inside analyzeHandbookDelta still governs the actual API request rate;
|
||||
// parallelism here just hides GitHub fetch latency and overlaps with the
|
||||
// limiter's spacing instead of waiting serially.
|
||||
const CONCURRENCY = 4;
|
||||
const queue = filesToProcess.slice();
|
||||
|
||||
async function worker() {
|
||||
while (queue.length > 0) {
|
||||
const file = queue.shift();
|
||||
if (!file) return;
|
||||
try {
|
||||
const rawContent = await getFileContent('respellion', 'employee-handbook', file.path);
|
||||
// Skip near-empty files — they only burn an LLM call to extract nothing.
|
||||
if (rawContent.trim().length < 50) {
|
||||
await db.updateHandbookSyncState(file.path, file.sha);
|
||||
} else {
|
||||
await analyzeHandbookDelta(rawContent, file.path);
|
||||
await db.updateHandbookSyncState(file.path, file.sha);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to process file:', file.path, err);
|
||||
failed.push({ path: file.path, message: err?.message || String(err) });
|
||||
} finally {
|
||||
done++;
|
||||
setSyncProgress(`Processing ${done} of ${total} files (${failed.length} failed)...`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(Array.from({ length: Math.min(CONCURRENCY, total) }, worker));
|
||||
|
||||
setSyncResult({ added, modified, unchanged, failed });
|
||||
setSyncProgress(
|
||||
failed.length === 0
|
||||
? 'Sync Complete! Click "Analyze & Optimize Graph" above to clean up and merge.'
|
||||
: `Sync finished with ${failed.length} failure(s). See console for details.`
|
||||
);
|
||||
reloadKb();
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
setSyncError(e.message || 'Failed to check GitHub for updates.');
|
||||
} finally {
|
||||
setIsSyncing(false);
|
||||
setTimeout(() => setSyncProgress(null), 10000); // Clear progress after 10s
|
||||
}
|
||||
};
|
||||
|
||||
const analyzeGraph = async () => {
|
||||
if (!confirm('This will send the entire graph to the AI to evaluate content, merge duplicates, and create new logical relations. This may take a moment. Proceed?')) return;
|
||||
@@ -466,43 +379,6 @@ ${JSON.stringify({ topics: compactTopics, relations: compactRelations })}`;
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
onClick={syncHandbook}
|
||||
disabled={isSyncing}
|
||||
variant="outline"
|
||||
className="w-full flex justify-center items-center gap-2"
|
||||
>
|
||||
<RefreshCw size={16} className={isSyncing ? "animate-spin" : ""} />
|
||||
{isSyncing ? 'Checking for updates...' : 'Sync Employee Handbook'}
|
||||
</Button>
|
||||
{syncError && (
|
||||
<p className="mt-2 text-xs text-red-600 flex items-start gap-1">
|
||||
<AlertCircle size={14} className="shrink-0 mt-0.5" />
|
||||
{syncError}
|
||||
</p>
|
||||
)}
|
||||
{syncResult && (
|
||||
<div className="mt-2 text-xs text-fg-muted space-y-1 p-2 bg-bg rounded">
|
||||
<p className="font-medium text-fg">GitHub Sync Status:</p>
|
||||
<p>Added files: {syncResult.added.length}</p>
|
||||
<p>Modified files: {syncResult.modified.length}</p>
|
||||
<p>Unchanged: {syncResult.unchanged.length}</p>
|
||||
{syncResult.failed?.length > 0 && (
|
||||
<p className="text-red-600">Failed: {syncResult.failed.length}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{syncProgress && (
|
||||
<div className="mt-2 text-xs text-teal p-2 bg-teal/10 border border-teal/20 rounded">
|
||||
<p className="font-medium flex items-center gap-2">
|
||||
{syncProgress !== 'Sync Complete!' && <RefreshCw size={12} className="animate-spin" />}
|
||||
{syncProgress}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* R42 chatbot suggestions queue */}
|
||||
|
||||
Reference in New Issue
Block a user