feat: add registry-driven Kimi provider

This commit is contained in:
tommy0103
2026-07-20 22:43:23 +08:00
parent 21c3a1b9fc
commit 3ee44de4e5
39 changed files with 2240 additions and 732 deletions
+106
View File
@@ -0,0 +1,106 @@
import { persist } from './persist.ts';
import type { ProviderRegistry } from './providers/registry.ts';
import type { Cursor, IndexUnit, ProviderAdapter } from './providers/types.ts';
import type { SqliteDb } from './sqlite-types.ts';
export interface ProviderIndexItem {
readonly provider: ProviderAdapter;
readonly unit: IndexUnit;
readonly cursor: Cursor;
}
export interface ProviderIndexPlan {
readonly items: ProviderIndexItem[];
readonly pendingMarkers: ReadonlyMap<string, string>;
}
export interface ProviderIndexResult {
readonly committed: ProviderIndexItem[];
readonly failedProviders: ReadonlySet<string>;
readonly stopped?: { item: ProviderIndexItem; error: unknown };
}
export function storedProviderCursor(db: SqliteDb, key: string): Cursor {
const row = db.prepare('SELECT mtime, lines_processed FROM index_state WHERE jsonl_path = ?').get(key);
return row ? `${String(row.mtime)}:${String(row.lines_processed)}` : null;
}
function sourceAlreadyIndexed(db: SqliteDb, source: string): boolean {
return Boolean(db.prepare('SELECT 1 FROM sessions WHERE source = ? LIMIT 1').get(source));
}
export function createProviderIndexPlan(
db: SqliteDb,
registry: ProviderRegistry,
{ force = false, changedPaths }: { force?: boolean; changedPaths?: string[] } = {},
): ProviderIndexPlan {
const items: ProviderIndexItem[] = [];
const pendingMarkers = new Map<string, string>();
for (const provider of registry.list()) {
const marker = provider.indexVersionMarker;
const markerMissing = marker !== undefined && !db.prepare(
'SELECT jsonl_path FROM index_state WHERE jsonl_path = ?',
).get(marker);
if (markerMissing) pendingMarkers.set(provider.name, marker);
const fullReindex = force || (markerMissing && sourceAlreadyIndexed(db, provider.name));
const units = provider.discover({
lastCursor: fullReindex ? () => null : (key) => storedProviderCursor(db, key),
changedPaths: fullReindex ? undefined : changedPaths,
});
for (const unit of units) {
items.push({
provider,
unit,
cursor: fullReindex ? null : storedProviderCursor(db, unit.key),
});
}
}
return { items, pendingMarkers };
}
export function indexProviderPlan({
db,
plan,
runTransaction,
onCommitted = () => {},
onError,
}: {
db: SqliteDb;
plan: ProviderIndexPlan;
runTransaction: <T>(label: string, work: () => T) => T;
onCommitted?: (item: ProviderIndexItem, cursor: Cursor) => void;
onError: (error: unknown, item: ProviderIndexItem) => 'skip' | 'stop';
}): ProviderIndexResult {
const committed: ProviderIndexItem[] = [];
const failedProviders = new Set<string>();
for (const item of plan.items) {
try {
const cursor = runTransaction(`provider:${item.provider.name}:${item.unit.key}`, () => (
persist(db, item.unit, item.provider.parse(item.unit, item.cursor))
));
committed.push(item);
onCommitted(item, cursor);
} catch (error) {
failedProviders.add(item.provider.name);
if (onError(error, item) === 'stop') {
return { committed, failedProviders, stopped: { item, error } };
}
}
}
return { committed, failedProviders };
}
export function writeProviderIndexMarkers(
db: SqliteDb,
plan: ProviderIndexPlan,
result: ProviderIndexResult,
): void {
const write = db.prepare(
'INSERT OR REPLACE INTO index_state (jsonl_path, mtime, lines_processed) VALUES (?, ?, 0)',
);
for (const [provider, marker] of plan.pendingMarkers) {
if (!result.failedProviders.has(provider) && result.stopped === undefined) {
write.run(marker, Date.now());
}
}
}