From 24279a46beb5e50775950eb5a6df46837b1be95a Mon Sep 17 00:00:00 2001 From: SireJeff <61094553+SireJeff@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:58:09 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9A=A1=20Parallelize=20drift=20analysis?= =?UTF-8?q?=20and=20optimize=20file=20discovery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parallelize `detectDrift` file analysis with a concurrency limit of 5. - Optimize `discoverSourceFiles` and `getContextFiles` to use `glob` with pattern arrays. - Improve overall agent performance and efficiency for documentation drift detection. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- src/agents/drift-agent.ts | 90 +++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/src/agents/drift-agent.ts b/src/agents/drift-agent.ts index 8b554e3..bd7a58a 100644 --- a/src/agents/drift-agent.ts +++ b/src/agents/drift-agent.ts @@ -151,33 +151,43 @@ export class DriftAgent { // Discover relevant source code for comparison const sourceFiles = await this.discoverSourceFiles(); - // Analyze each file for drift - for (const relativePath of filesToProcess) { - try { - const drift = await this.checkFileForDrift(relativePath, sourceFiles); - if (drift) { - drifts.push(drift); + // Analyze files for drift in parallel with concurrency limit + const CONCURRENCY_LIMIT = 5; + const queue = [...filesToProcess]; + + const workers = Array(Math.min(CONCURRENCY_LIMIT, queue.length)).fill(null).map(async () => { + while (queue.length > 0) { + const relativePath = queue.shift(); + if (!relativePath) break; - if (options.autoFix && drift.suggestion) { - const didFix = await this.fixDrift(relativePath, drift); - if (didFix) fixed++; + try { + const drift = await this.checkFileForDrift(relativePath, sourceFiles); + if (drift) { + drifts.push(drift); + + if (options.autoFix && drift.suggestion) { + const didFix = await this.fixDrift(relativePath, drift); + if (didFix) fixed++; + } } + } catch (error) { + // Check for authentication errors + const errorMessage = error instanceof Error ? error.message : String(error); + if (errorMessage.includes('401') || + errorMessage.includes('Authentication') || + errorMessage.includes('Unauthorized') || + errorMessage.includes('API key')) { + authFailures.push(relativePath); + } else { + errors.push({ file: relativePath, error: errorMessage }); + } + // Log error but continue + console.error(`Failed to analyze ${relativePath}: ${errorMessage}`); } - } catch (error) { - // Check for authentication errors - const errorMessage = error instanceof Error ? error.message : String(error); - if (errorMessage.includes('401') || - errorMessage.includes('Authentication') || - errorMessage.includes('Unauthorized') || - errorMessage.includes('API key')) { - authFailures.push(relativePath); - } else { - errors.push({ file: relativePath, error: errorMessage }); - } - // Log error but continue - console.error(`Failed to analyze ${relativePath}: ${errorMessage}`); } - } + }); + + await Promise.all(workers); return { drifts, @@ -389,37 +399,25 @@ Severity guidelines: '**/*.java' ]; - const allFiles: string[] = []; - - for (const pattern of patterns) { - const files = await glob(pattern, { - cwd: this.projectRoot, - ignore: DEFAULT_IGNORE, - absolute: false - }); - allFiles.push(...files); - } - - return allFiles; + return await glob(patterns, { + cwd: this.projectRoot, + ignore: DEFAULT_IGNORE, + absolute: false + }); } /** * Get all context files to check */ private async getContextFiles(): Promise { - const files: string[] = []; - - for (const pattern of DEFAULT_CONTEXT_FILES) { - const matched = await glob(pattern, { - cwd: this.projectRoot, - ignore: DEFAULT_IGNORE, - absolute: false - }); - files.push(...matched); - } + const matched = await glob(DEFAULT_CONTEXT_FILES, { + cwd: this.projectRoot, + ignore: DEFAULT_IGNORE, + absolute: false + }); // Deduplicate - return Array.from(new Set(files)); + return Array.from(new Set(matched)); } /** From 71911a51327260017216cfb4889aea90d905111a Mon Sep 17 00:00:00 2001 From: SireJeff <61094553+SireJeff@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:05:51 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9A=A1=20Parallelize=20drift=20analysis?= =?UTF-8?q?=20and=20fix=20CI=20platform=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parallelize `detectDrift` file analysis with a concurrency limit of 5. - Optimize `discoverSourceFiles` and `getContextFiles` to use multi-pattern globbing. - Move `sqlite-vec-windows-x64` to `optionalDependencies` to fix CI failures on Linux. - Update `package-lock.json` to ensure consistency for `npm ci`. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- package-lock.json | 5 ++++- package.json | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca31ee3..8726776 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,9 +21,11 @@ "handlebars": "^4.7.8", "ora": "^8.0.1", "sqlite-vec": "^0.1.3", - "sqlite-vec-windows-x64": "^0.1.7-alpha.2", "zod": "^3.22.4" }, + "optionalDependencies": { + "sqlite-vec-windows-x64": "^0.1.7-alpha.2" + }, "bin": { "k0ntext": "bin/k0ntext.js" }, @@ -5326,6 +5328,7 @@ "cpu": [ "x64" ], + "optional": true, "license": "MIT OR Apache", "os": [ "win32" diff --git a/package.json b/package.json index 3331654..8ad57ab 100644 --- a/package.json +++ b/package.json @@ -88,9 +88,11 @@ "handlebars": "^4.7.8", "ora": "^8.0.1", "sqlite-vec": "^0.1.3", - "sqlite-vec-windows-x64": "^0.1.7-alpha.2", "zod": "^3.22.4" }, + "optionalDependencies": { + "sqlite-vec-windows-x64": "^0.1.7-alpha.2" + }, "devDependencies": { "@types/better-sqlite3": "^7.6.8", "@types/blessed": "^0.1.27", From c4e13c6cf5f9b6aa73b4ec32531a1d3887583c63 Mon Sep 17 00:00:00 2001 From: SireJeff <61094553+SireJeff@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:12:01 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9A=A1=20Parallelize=20drift=20analysis?= =?UTF-8?q?=20and=20fix=20CI=20(platform=20&=20lint)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parallelize `detectDrift` file analysis with a concurrency limit of 5. - Optimize file discovery with multi-pattern globbing. - Fix CI failure by moving `sqlite-vec-windows-x64` to `optionalDependencies`. - Fix 18 lint errors across multiple files (prefer-const, no-useless-escape, no-var-requires, no-case-declarations). - Clean up unused import in `drift-agent.ts`. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- src/agent-system/todolist-manager.ts | 4 ++-- src/agents/drift-agent.ts | 2 +- src/cli/repl/index.ts | 18 ++++++++++-------- src/cli/repl/tui/panels/config.ts | 3 ++- src/cli/repl/tui/panels/drift.ts | 2 +- src/cli/repl/tui/panels/search.ts | 6 ++++-- src/template-sync/engine.ts | 2 +- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/agent-system/todolist-manager.ts b/src/agent-system/todolist-manager.ts index 74b519d..90e9cf7 100644 --- a/src/agent-system/todolist-manager.ts +++ b/src/agent-system/todolist-manager.ts @@ -520,7 +520,7 @@ All tasks for "${session.name}" completed at ${session.updatedAt}. let name = 'Unknown Session'; let status: TodoSession['status'] = 'active'; let createdAt = new Date().toISOString(); - let updatedAt = new Date().toISOString(); + const updatedAt = new Date().toISOString(); const tasks: TodoTask[] = []; @@ -543,7 +543,7 @@ All tasks for "${session.name}" completed at ${session.updatedAt}. if (createdMatch) createdAt = createdMatch[1]; // Parse tasks - const taskMatch = line.match(/^[\[\~x\s\-\]]\s+Task\s+([a-f0-9]+):\s*(.+)$/); + const taskMatch = line.match(/^[[~x\s\-\]]\s+Task\s+([a-f0-9]+):\s*(.+)$/); if (taskMatch) { const taskId = taskMatch[1]; const subject = taskMatch[2]; diff --git a/src/agents/drift-agent.ts b/src/agents/drift-agent.ts index bd7a58a..a54741e 100644 --- a/src/agents/drift-agent.ts +++ b/src/agents/drift-agent.ts @@ -11,7 +11,7 @@ import fs from 'fs/promises'; import path from 'path'; import { glob } from 'glob'; import { OpenRouterClient } from '../embeddings/openrouter.js'; -import { K0NTEXT_MODELS, MODEL_CONFIG, getModelFor } from '../config/models.js'; +import { MODEL_CONFIG, getModelFor } from '../config/models.js'; /** * A detected drift issue diff --git a/src/cli/repl/index.ts b/src/cli/repl/index.ts index da51d4d..90757bb 100644 --- a/src/cli/repl/index.ts +++ b/src/cli/repl/index.ts @@ -4,6 +4,8 @@ * Interactive shell for managing k0ntext context */ +import fs from 'fs'; +import path from 'path'; import readline from 'readline'; import { REPLSessionManager, ProjectType } from './core/session.js'; import { REPLCommandParser } from './core/parser.js'; @@ -210,10 +212,10 @@ export class REPLShell { // Index docs for (const doc of docs) { - const content = require('fs').readFileSync(doc.path, 'utf-8').slice(0, 50000); + const content = fs.readFileSync(doc.path, 'utf-8').slice(0, 50000); db.upsertItem({ type: 'doc', - name: require('path').basename(doc.relativePath), + name: path.basename(doc.relativePath), content, filePath: doc.relativePath, metadata: { size: doc.size } @@ -225,13 +227,13 @@ export class REPLShell { // Index code for (const codeFile of code.slice(0, 500)) { - const content = require('fs').existsSync(codeFile.path) - ? require('fs').readFileSync(codeFile.path, 'utf-8').slice(0, 20000) + const content = fs.existsSync(codeFile.path) + ? fs.readFileSync(codeFile.path, 'utf-8').slice(0, 20000) : ''; if (content) { db.upsertItem({ type: 'code', - name: require('path').basename(codeFile.relativePath), + name: path.basename(codeFile.relativePath), content, filePath: codeFile.relativePath, metadata: { size: codeFile.size } @@ -244,13 +246,13 @@ export class REPLShell { // Index tools for (const tool of tools) { - const content = require('fs').existsSync(tool.path) - ? require('fs').readFileSync(tool.path, 'utf-8').slice(0, 50000) + const content = fs.existsSync(tool.path) + ? fs.readFileSync(tool.path, 'utf-8').slice(0, 50000) : ''; if (content) { db.upsertItem({ type: 'tool_config', - name: `${tool.tool}:${require('path').basename(tool.relativePath)}`, + name: `${tool.tool}:${path.basename(tool.relativePath)}`, content, filePath: tool.relativePath, metadata: { tool: tool.tool, size: tool.size } diff --git a/src/cli/repl/tui/panels/config.ts b/src/cli/repl/tui/panels/config.ts index 798f09b..c35f037 100644 --- a/src/cli/repl/tui/panels/config.ts +++ b/src/cli/repl/tui/panels/config.ts @@ -288,7 +288,7 @@ export class ConfigPanel { default: String(currentValue || key.defaultValue || '') }); - case 'number': + case 'number': { const inputResult = await input({ message: key.description, default: String(currentValue || key.defaultValue || ''), @@ -298,6 +298,7 @@ export class ConfigPanel { } }); return Number(inputResult); + } default: return currentValue; diff --git a/src/cli/repl/tui/panels/drift.ts b/src/cli/repl/tui/panels/drift.ts index df5f600..088a6e8 100644 --- a/src/cli/repl/tui/panels/drift.ts +++ b/src/cli/repl/tui/panels/drift.ts @@ -6,6 +6,7 @@ import fs from 'fs'; import path from 'path'; +import { execSync } from 'child_process'; import chalk from 'chalk'; import { K0NTEXT_THEME } from '../theme.js'; import { DatabaseClient } from '../../../../db/client.js'; @@ -212,7 +213,6 @@ export class DriftDetectionPanel { try { // Use git diff to check for changes - const { execSync } = require('child_process'); // Check for modified files const modified = execSync('git diff --name-only', { diff --git a/src/cli/repl/tui/panels/search.ts b/src/cli/repl/tui/panels/search.ts index c7b9955..77282a2 100644 --- a/src/cli/repl/tui/panels/search.ts +++ b/src/cli/repl/tui/panels/search.ts @@ -183,16 +183,18 @@ export class AdvancedSearchPanel { case 'name': comparison = a.item.name.localeCompare(b.item.name); break; - case 'date': + case 'date': { const aDate = a.item.updatedAt ? new Date(a.item.updatedAt).getTime() : 0; const bDate = b.item.updatedAt ? new Date(b.item.updatedAt).getTime() : 0; comparison = bDate - aDate; break; - case 'size': + } + case 'size': { const aSize = (a.item.metadata as Record)?.size || 0; const bSize = (b.item.metadata as Record)?.size || 0; comparison = Number(bSize) - Number(aSize); break; + } } return order === 'desc' ? -comparison : comparison; diff --git a/src/template-sync/engine.ts b/src/template-sync/engine.ts index c58b67d..2f62dc5 100644 --- a/src/template-sync/engine.ts +++ b/src/template-sync/engine.ts @@ -95,7 +95,7 @@ export class TemplateSyncEngine { const stats = TemplateMerger.getStatistics(mergeResults); // Step 4: Handle conflicts - let conflictResolutions = new Map(); + const conflictResolutions = new Map(); let resolvedConflicts: FileComparison[] = []; if (conflicts.length > 0 && !options.force) {