claude-flow 2.7.34 → 2.7.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/bin/claude-flow +1 -1
- package/dist/src/cli/help-formatter.js +0 -5
- package/dist/src/cli/init/index.js +55 -33
- package/dist/src/cli/init/index.js.map +1 -1
- package/dist/src/cli/simple-cli.js +182 -172
- package/dist/src/cli/simple-cli.js.map +1 -1
- package/dist/src/core/DatabaseManager.js +39 -9
- package/dist/src/core/DatabaseManager.js.map +1 -1
- package/dist/src/core/version.js +1 -1
- package/dist/src/utils/error-recovery.js +215 -0
- package/dist/src/utils/error-recovery.js.map +1 -0
- package/dist/src/utils/metrics-reader.js +10 -0
- package/dist/src/utils/metrics-reader.js.map +1 -1
- package/docs/AUTOMATIC_ERROR_RECOVERY_v2.7.35.md +321 -0
- package/docs/CONFIRMATION_AUTOMATIC_ERROR_RECOVERY.md +384 -0
- package/docs/DOCKER_TEST_RESULTS_v2.7.35.md +305 -0
- package/docs/features/automatic-error-recovery.md +333 -0
- package/docs/github-issues/README.md +88 -0
- package/docs/github-issues/wsl-enotempty-automatic-recovery.md +470 -0
- package/docs/troubleshooting/wsl-better-sqlite3-error.md +239 -0
- package/package.json +1 -1
- package/scripts/create-github-issue.sh +64 -0
- package/scripts/test-docker-wsl.sh +198 -0
- package/src/cli/init/index.ts +72 -42
- package/src/core/DatabaseManager.ts +55 -9
- package/src/utils/error-recovery.ts +325 -0
|
@@ -5,29 +5,59 @@ export class DatabaseManager {
|
|
|
5
5
|
dbType;
|
|
6
6
|
dbPath;
|
|
7
7
|
initialized = false;
|
|
8
|
+
retryCount = 0;
|
|
9
|
+
maxRetries = 3;
|
|
8
10
|
constructor(dbType = 'sqlite', dbPath){
|
|
9
11
|
this.dbType = dbType;
|
|
10
12
|
this.dbPath = dbPath || this.getDefaultPath();
|
|
11
13
|
if (this.dbType === 'sqlite') {
|
|
12
|
-
|
|
13
|
-
this.provider = new SQLiteProvider(this.dbPath);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
console.warn('SQLite not available, falling back to JSON storage:', error);
|
|
16
|
-
this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));
|
|
17
|
-
this.dbType = 'json';
|
|
18
|
-
}
|
|
14
|
+
this.provider = this.initializeSQLiteWithRecovery();
|
|
19
15
|
} else {
|
|
20
16
|
this.provider = new JSONProvider(this.dbPath);
|
|
21
17
|
}
|
|
22
18
|
}
|
|
19
|
+
initializeSQLiteWithRecovery() {
|
|
20
|
+
try {
|
|
21
|
+
return new SQLiteProvider(this.dbPath);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
24
|
+
if (errorMsg.includes('ENOTEMPTY') || errorMsg.includes('better-sqlite3')) {
|
|
25
|
+
console.warn('⚠️ SQLite initialization failed due to npm cache error');
|
|
26
|
+
console.warn(' Will attempt automatic recovery during initialize()');
|
|
27
|
+
} else {
|
|
28
|
+
console.warn('SQLite not available, falling back to JSON storage:', error);
|
|
29
|
+
}
|
|
30
|
+
this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));
|
|
31
|
+
this.dbType = 'json';
|
|
32
|
+
return this.provider;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
23
35
|
getDefaultPath() {
|
|
24
36
|
const baseDir = path.join(process.cwd(), '.claude-flow');
|
|
25
37
|
return this.dbType === 'sqlite' ? path.join(baseDir, 'database.sqlite') : path.join(baseDir, 'database.json');
|
|
26
38
|
}
|
|
27
39
|
async initialize() {
|
|
28
40
|
await fs.ensureDir(path.dirname(this.dbPath));
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
try {
|
|
42
|
+
await this.provider.initialize();
|
|
43
|
+
this.initialized = true;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (this.dbType === 'json') {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
49
|
+
if (this.retryCount < this.maxRetries) {
|
|
50
|
+
console.warn(`⚠️ Database initialization failed (attempt ${this.retryCount + 1}/${this.maxRetries})`);
|
|
51
|
+
console.warn(` Error: ${errorMsg}`);
|
|
52
|
+
console.log('🔄 Switching to JSON storage as fallback...');
|
|
53
|
+
this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));
|
|
54
|
+
this.dbType = 'json';
|
|
55
|
+
this.retryCount++;
|
|
56
|
+
await this.initialize();
|
|
57
|
+
} else {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
31
61
|
}
|
|
32
62
|
async store(key, value, namespace = 'default') {
|
|
33
63
|
if (!this.initialized) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/DatabaseManager.ts"],"sourcesContent":["/**\n * DatabaseManager - Manages SQLite and JSON fallback storage\n * Provides a unified interface for persistent data storage with automatic fallback\n */\n\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport { IDatabaseProvider } from '../types/interfaces.js';\n\nexport class DatabaseManager implements IDatabaseProvider {\n private provider: IDatabaseProvider;\n private dbType: 'sqlite' | 'json';\n private dbPath: string;\n private initialized: boolean = false;\n\n constructor(dbType: 'sqlite' | 'json' = 'sqlite', dbPath?: string) {\n this.dbType = dbType;\n this.dbPath = dbPath || this.getDefaultPath();\n\n // Try SQLite first, fallback to JSON if needed\n if (this.dbType === 'sqlite') {\n try {\n this.provider = new SQLiteProvider(this.dbPath);\n } catch (error) {\n console.warn('SQLite not available, falling back to JSON storage:', error);\n this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));\n this.dbType = 'json';\n }\n } else {\n this.provider = new JSONProvider(this.dbPath);\n }\n }\n\n private getDefaultPath(): string {\n const baseDir = path.join(process.cwd(), '.claude-flow');\n return this.dbType === 'sqlite'\n ? path.join(baseDir, 'database.sqlite')\n : path.join(baseDir, 'database.json');\n }\n\n async initialize(): Promise<void> {\n await fs.ensureDir(path.dirname(this.dbPath));\n await this.provider.initialize();\n this.initialized = true;\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.store(key, value, namespace);\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.retrieve(key, namespace);\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.delete(key, namespace);\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.list(namespace);\n }\n\n async close(): Promise<void> {\n if (this.provider) {\n await this.provider.close();\n }\n this.initialized = false;\n }\n\n getDatabaseType(): 'sqlite' | 'json' {\n return this.dbType;\n }\n\n getDatabasePath(): string {\n return this.dbPath;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // Specialized methods for common operations\n async storeJSON(key: string, data: object, namespace?: string): Promise<void> {\n await this.store(key, JSON.stringify(data), namespace);\n }\n\n async retrieveJSON(key: string, namespace?: string): Promise<object | null> {\n const data = await this.retrieve(key, namespace);\n if (!data) return null;\n try {\n return typeof data === 'string' ? JSON.parse(data) : data;\n } catch {\n return null;\n }\n }\n\n async exists(key: string, namespace?: string): Promise<boolean> {\n const data = await this.retrieve(key, namespace);\n return data !== null && data !== undefined;\n }\n\n async clear(namespace?: string): Promise<void> {\n const keys = await this.list(namespace);\n await Promise.all(keys.map(key => this.delete(key, namespace)));\n }\n}\n\n/**\n * SQLite implementation\n */\nclass SQLiteProvider implements IDatabaseProvider {\n private db: any;\n private dbPath: string;\n\n constructor(dbPath: string) {\n this.dbPath = dbPath;\n // Dynamic import to handle optional dependency\n try {\n const Database = require('better-sqlite3');\n this.db = new Database(dbPath);\n } catch (error) {\n throw new Error('better-sqlite3 not available. Install with: npm install better-sqlite3');\n }\n }\n\n async initialize(): Promise<void> {\n // Create tables\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS storage (\n namespace TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at INTEGER DEFAULT (strftime('%s', 'now')),\n updated_at INTEGER DEFAULT (strftime('%s', 'now')),\n PRIMARY KEY (namespace, key)\n )\n `);\n\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_storage_namespace ON storage(namespace);\n CREATE INDEX IF NOT EXISTS idx_storage_created_at ON storage(created_at);\n `);\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO storage (namespace, key, value, updated_at)\n VALUES (?, ?, ?, strftime('%s', 'now'))\n `);\n\n const serializedValue = typeof value === 'string' ? value : JSON.stringify(value);\n stmt.run(namespace, key, serializedValue);\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n const stmt = this.db.prepare('SELECT value FROM storage WHERE namespace = ? AND key = ?');\n const row = stmt.get(namespace, key);\n\n if (!row) return null;\n\n try {\n return JSON.parse(row.value);\n } catch {\n return row.value;\n }\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n const stmt = this.db.prepare('DELETE FROM storage WHERE namespace = ? AND key = ?');\n const result = stmt.run(namespace, key);\n return result.changes > 0;\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n const stmt = this.db.prepare('SELECT key FROM storage WHERE namespace = ? ORDER BY key');\n const rows = stmt.all(namespace);\n return rows.map((row: any) => row.key);\n }\n\n async close(): Promise<void> {\n if (this.db) {\n this.db.close();\n }\n }\n}\n\n/**\n * JSON file-based implementation\n */\nclass JSONProvider implements IDatabaseProvider {\n private data: Record<string, Record<string, any>> = {};\n private dbPath: string;\n\n constructor(dbPath: string) {\n this.dbPath = dbPath;\n }\n\n async initialize(): Promise<void> {\n try {\n if (await fs.pathExists(this.dbPath)) {\n const content = await fs.readJSON(this.dbPath);\n this.data = content || {};\n }\n } catch (error) {\n console.warn('Failed to load JSON database, starting fresh:', error);\n this.data = {};\n }\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n if (!this.data[namespace]) {\n this.data[namespace] = {};\n }\n\n this.data[namespace][key] = value;\n await this.persist();\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n if (!this.data[namespace]) {\n return null;\n }\n return this.data[namespace][key] || null;\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n if (!this.data[namespace] || !(key in this.data[namespace])) {\n return false;\n }\n\n delete this.data[namespace][key];\n await this.persist();\n return true;\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n if (!this.data[namespace]) {\n return [];\n }\n return Object.keys(this.data[namespace]).sort();\n }\n\n async close(): Promise<void> {\n await this.persist();\n }\n\n private async persist(): Promise<void> {\n try {\n await fs.ensureDir(path.dirname(this.dbPath));\n await fs.writeJSON(this.dbPath, this.data, { spaces: 2 });\n } catch (error) {\n console.error('Failed to persist JSON database:', error);\n }\n }\n}"],"names":["fs","path","DatabaseManager","provider","dbType","dbPath","initialized","getDefaultPath","SQLiteProvider","error","console","warn","JSONProvider","replace","baseDir","join","process","cwd","initialize","ensureDir","dirname","store","key","value","namespace","retrieve","delete","list","close","getDatabaseType","getDatabasePath","isInitialized","storeJSON","data","JSON","stringify","retrieveJSON","parse","exists","undefined","clear","keys","Promise","all","map","db","Database","require","Error","exec","stmt","prepare","serializedValue","run","row","get","result","changes","rows","pathExists","content","readJSON","persist","Object","sort","writeJSON","spaces"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/DatabaseManager.ts"],"sourcesContent":["/**\n * DatabaseManager - Manages SQLite and JSON fallback storage\n * Provides a unified interface for persistent data storage with automatic fallback\n */\n\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport { IDatabaseProvider } from '../types/interfaces.js';\n\nexport class DatabaseManager implements IDatabaseProvider {\n private provider: IDatabaseProvider;\n private dbType: 'sqlite' | 'json';\n private dbPath: string;\n private initialized: boolean = false;\n private retryCount: number = 0;\n private maxRetries: number = 3;\n\n constructor(dbType: 'sqlite' | 'json' = 'sqlite', dbPath?: string) {\n this.dbType = dbType;\n this.dbPath = dbPath || this.getDefaultPath();\n\n // Try SQLite first, fallback to JSON if needed\n if (this.dbType === 'sqlite') {\n this.provider = this.initializeSQLiteWithRecovery();\n } else {\n this.provider = new JSONProvider(this.dbPath);\n }\n }\n\n /**\n * Initialize SQLite with automatic error recovery\n */\n private initializeSQLiteWithRecovery(): IDatabaseProvider {\n try {\n return new SQLiteProvider(this.dbPath);\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n // Check if it's an npm cache error\n if (errorMsg.includes('ENOTEMPTY') || errorMsg.includes('better-sqlite3')) {\n console.warn('⚠️ SQLite initialization failed due to npm cache error');\n console.warn(' Will attempt automatic recovery during initialize()');\n } else {\n console.warn('SQLite not available, falling back to JSON storage:', error);\n }\n\n // Fallback to JSON for now\n this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));\n this.dbType = 'json';\n return this.provider;\n }\n }\n\n private getDefaultPath(): string {\n const baseDir = path.join(process.cwd(), '.claude-flow');\n return this.dbType === 'sqlite'\n ? path.join(baseDir, 'database.sqlite')\n : path.join(baseDir, 'database.json');\n }\n\n async initialize(): Promise<void> {\n await fs.ensureDir(path.dirname(this.dbPath));\n\n try {\n await this.provider.initialize();\n this.initialized = true;\n } catch (error) {\n // If JSON provider failed, just propagate the error\n if (this.dbType === 'json') {\n throw error;\n }\n\n // For SQLite errors, attempt recovery\n const errorMsg = error instanceof Error ? error.message : String(error);\n if (this.retryCount < this.maxRetries) {\n console.warn(`⚠️ Database initialization failed (attempt ${this.retryCount + 1}/${this.maxRetries})`);\n console.warn(` Error: ${errorMsg}`);\n\n // Attempt to recover by switching to JSON\n console.log('🔄 Switching to JSON storage as fallback...');\n this.provider = new JSONProvider(this.dbPath.replace('.sqlite', '.json'));\n this.dbType = 'json';\n this.retryCount++;\n\n // Retry initialization with JSON provider\n await this.initialize();\n } else {\n throw error;\n }\n }\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.store(key, value, namespace);\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.retrieve(key, namespace);\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.delete(key, namespace);\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n if (!this.initialized) {\n await this.initialize();\n }\n return this.provider.list(namespace);\n }\n\n async close(): Promise<void> {\n if (this.provider) {\n await this.provider.close();\n }\n this.initialized = false;\n }\n\n getDatabaseType(): 'sqlite' | 'json' {\n return this.dbType;\n }\n\n getDatabasePath(): string {\n return this.dbPath;\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // Specialized methods for common operations\n async storeJSON(key: string, data: object, namespace?: string): Promise<void> {\n await this.store(key, JSON.stringify(data), namespace);\n }\n\n async retrieveJSON(key: string, namespace?: string): Promise<object | null> {\n const data = await this.retrieve(key, namespace);\n if (!data) return null;\n try {\n return typeof data === 'string' ? JSON.parse(data) : data;\n } catch {\n return null;\n }\n }\n\n async exists(key: string, namespace?: string): Promise<boolean> {\n const data = await this.retrieve(key, namespace);\n return data !== null && data !== undefined;\n }\n\n async clear(namespace?: string): Promise<void> {\n const keys = await this.list(namespace);\n await Promise.all(keys.map(key => this.delete(key, namespace)));\n }\n}\n\n/**\n * SQLite implementation\n */\nclass SQLiteProvider implements IDatabaseProvider {\n private db: any;\n private dbPath: string;\n\n constructor(dbPath: string) {\n this.dbPath = dbPath;\n // Dynamic import to handle optional dependency\n try {\n const Database = require('better-sqlite3');\n this.db = new Database(dbPath);\n } catch (error) {\n throw new Error('better-sqlite3 not available. Install with: npm install better-sqlite3');\n }\n }\n\n async initialize(): Promise<void> {\n // Create tables\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS storage (\n namespace TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at INTEGER DEFAULT (strftime('%s', 'now')),\n updated_at INTEGER DEFAULT (strftime('%s', 'now')),\n PRIMARY KEY (namespace, key)\n )\n `);\n\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_storage_namespace ON storage(namespace);\n CREATE INDEX IF NOT EXISTS idx_storage_created_at ON storage(created_at);\n `);\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO storage (namespace, key, value, updated_at)\n VALUES (?, ?, ?, strftime('%s', 'now'))\n `);\n\n const serializedValue = typeof value === 'string' ? value : JSON.stringify(value);\n stmt.run(namespace, key, serializedValue);\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n const stmt = this.db.prepare('SELECT value FROM storage WHERE namespace = ? AND key = ?');\n const row = stmt.get(namespace, key);\n\n if (!row) return null;\n\n try {\n return JSON.parse(row.value);\n } catch {\n return row.value;\n }\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n const stmt = this.db.prepare('DELETE FROM storage WHERE namespace = ? AND key = ?');\n const result = stmt.run(namespace, key);\n return result.changes > 0;\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n const stmt = this.db.prepare('SELECT key FROM storage WHERE namespace = ? ORDER BY key');\n const rows = stmt.all(namespace);\n return rows.map((row: any) => row.key);\n }\n\n async close(): Promise<void> {\n if (this.db) {\n this.db.close();\n }\n }\n}\n\n/**\n * JSON file-based implementation\n */\nclass JSONProvider implements IDatabaseProvider {\n private data: Record<string, Record<string, any>> = {};\n private dbPath: string;\n\n constructor(dbPath: string) {\n this.dbPath = dbPath;\n }\n\n async initialize(): Promise<void> {\n try {\n if (await fs.pathExists(this.dbPath)) {\n const content = await fs.readJSON(this.dbPath);\n this.data = content || {};\n }\n } catch (error) {\n console.warn('Failed to load JSON database, starting fresh:', error);\n this.data = {};\n }\n }\n\n async store(key: string, value: any, namespace: string = 'default'): Promise<void> {\n if (!this.data[namespace]) {\n this.data[namespace] = {};\n }\n\n this.data[namespace][key] = value;\n await this.persist();\n }\n\n async retrieve(key: string, namespace: string = 'default'): Promise<any> {\n if (!this.data[namespace]) {\n return null;\n }\n return this.data[namespace][key] || null;\n }\n\n async delete(key: string, namespace: string = 'default'): Promise<boolean> {\n if (!this.data[namespace] || !(key in this.data[namespace])) {\n return false;\n }\n\n delete this.data[namespace][key];\n await this.persist();\n return true;\n }\n\n async list(namespace: string = 'default'): Promise<string[]> {\n if (!this.data[namespace]) {\n return [];\n }\n return Object.keys(this.data[namespace]).sort();\n }\n\n async close(): Promise<void> {\n await this.persist();\n }\n\n private async persist(): Promise<void> {\n try {\n await fs.ensureDir(path.dirname(this.dbPath));\n await fs.writeJSON(this.dbPath, this.data, { spaces: 2 });\n } catch (error) {\n console.error('Failed to persist JSON database:', error);\n }\n }\n}"],"names":["fs","path","DatabaseManager","provider","dbType","dbPath","initialized","retryCount","maxRetries","getDefaultPath","initializeSQLiteWithRecovery","JSONProvider","SQLiteProvider","error","errorMsg","Error","message","String","includes","console","warn","replace","baseDir","join","process","cwd","initialize","ensureDir","dirname","log","store","key","value","namespace","retrieve","delete","list","close","getDatabaseType","getDatabasePath","isInitialized","storeJSON","data","JSON","stringify","retrieveJSON","parse","exists","undefined","clear","keys","Promise","all","map","db","Database","require","exec","stmt","prepare","serializedValue","run","row","get","result","changes","rows","pathExists","content","readJSON","persist","Object","sort","writeJSON","spaces"],"mappings":"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"}
|
package/dist/src/core/version.js
CHANGED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import * as fs from 'fs-extra';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
export function isNpmCacheError(error) {
|
|
6
|
+
const errorStr = error?.message || String(error);
|
|
7
|
+
return errorStr.includes('ENOTEMPTY') && (errorStr.includes('npm') || errorStr.includes('npx') || errorStr.includes('_npx')) || errorStr.includes('better-sqlite3');
|
|
8
|
+
}
|
|
9
|
+
export function isWSL() {
|
|
10
|
+
if (process.platform !== 'linux') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const release = fs.readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
15
|
+
return release.includes('microsoft') || release.includes('wsl');
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function cleanNpmCache() {
|
|
21
|
+
const homeDir = os.homedir();
|
|
22
|
+
const npxCacheDir = path.join(homeDir, '.npm', '_npx');
|
|
23
|
+
try {
|
|
24
|
+
console.log('🧹 Cleaning npm cache...');
|
|
25
|
+
try {
|
|
26
|
+
execSync('npm cache clean --force', {
|
|
27
|
+
stdio: 'pipe'
|
|
28
|
+
});
|
|
29
|
+
console.log('✅ npm cache cleaned');
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.warn('⚠️ npm cache clean failed, continuing...');
|
|
32
|
+
}
|
|
33
|
+
if (await fs.pathExists(npxCacheDir)) {
|
|
34
|
+
console.log(`🗑️ Removing npx cache: ${npxCacheDir}`);
|
|
35
|
+
await fs.remove(npxCacheDir);
|
|
36
|
+
console.log('✅ npx cache removed');
|
|
37
|
+
}
|
|
38
|
+
if (isWSL()) {
|
|
39
|
+
const npmDir = path.join(homeDir, '.npm');
|
|
40
|
+
if (await fs.pathExists(npmDir)) {
|
|
41
|
+
try {
|
|
42
|
+
execSync(`chmod -R 755 "${npmDir}"`, {
|
|
43
|
+
stdio: 'pipe'
|
|
44
|
+
});
|
|
45
|
+
console.log('✅ npm directory permissions fixed');
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.warn('⚠️ Permission fix failed, continuing...');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
action: 'cache-cleanup',
|
|
54
|
+
message: 'npm/npx cache cleaned successfully',
|
|
55
|
+
recovered: true
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
action: 'cache-cleanup',
|
|
61
|
+
message: `Failed to clean cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
62
|
+
recovered: false
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function retryWithRecovery(fn, options = {}) {
|
|
67
|
+
const { maxRetries = 3, delay = 1000, onRetry, cleanupFn } = options;
|
|
68
|
+
let lastError;
|
|
69
|
+
for(let attempt = 1; attempt <= maxRetries; attempt++){
|
|
70
|
+
try {
|
|
71
|
+
return await fn();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
lastError = error;
|
|
74
|
+
if (isNpmCacheError(error)) {
|
|
75
|
+
console.log(`\n⚠️ Detected npm cache error (attempt ${attempt}/${maxRetries})`);
|
|
76
|
+
const recovery = await cleanNpmCache();
|
|
77
|
+
if (recovery.success) {
|
|
78
|
+
console.log('✅ Cache cleaned, retrying...\n');
|
|
79
|
+
if (cleanupFn) {
|
|
80
|
+
await cleanupFn();
|
|
81
|
+
}
|
|
82
|
+
const backoffDelay = delay * Math.pow(2, attempt - 1);
|
|
83
|
+
await new Promise((resolve)=>setTimeout(resolve, backoffDelay));
|
|
84
|
+
continue;
|
|
85
|
+
} else {
|
|
86
|
+
console.error('❌ Cache cleanup failed:', recovery.message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (onRetry && attempt < maxRetries) {
|
|
90
|
+
onRetry(attempt, lastError);
|
|
91
|
+
await new Promise((resolve)=>setTimeout(resolve, delay));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (attempt === maxRetries) {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Operation failed after ${maxRetries} attempts. ` + `Last error: ${lastError?.message || 'Unknown error'}`);
|
|
100
|
+
}
|
|
101
|
+
export async function recoverWSLErrors() {
|
|
102
|
+
if (!isWSL()) {
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
action: 'wsl-check',
|
|
106
|
+
message: 'Not running on WSL, no recovery needed',
|
|
107
|
+
recovered: false
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
console.log('🔍 Detected WSL environment, applying fixes...');
|
|
111
|
+
try {
|
|
112
|
+
const homeDir = os.homedir();
|
|
113
|
+
const cwd = process.cwd();
|
|
114
|
+
if (cwd.startsWith('/mnt/')) {
|
|
115
|
+
console.warn('⚠️ WARNING: Running from Windows filesystem (/mnt/)');
|
|
116
|
+
console.warn(' For best results, run from WSL filesystem (e.g., ~/projects/)');
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
execSync('which gcc', {
|
|
120
|
+
stdio: 'pipe'
|
|
121
|
+
});
|
|
122
|
+
} catch {
|
|
123
|
+
console.warn('⚠️ build-essential not found. Install with:');
|
|
124
|
+
console.warn(' sudo apt-get update && sudo apt-get install -y build-essential python3');
|
|
125
|
+
}
|
|
126
|
+
return await cleanNpmCache();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
action: 'wsl-recovery',
|
|
131
|
+
message: `WSL recovery failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
132
|
+
recovered: false
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function verifyBetterSqlite3() {
|
|
137
|
+
try {
|
|
138
|
+
require.resolve('better-sqlite3');
|
|
139
|
+
return true;
|
|
140
|
+
} catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export async function installBetterSqlite3WithRecovery() {
|
|
145
|
+
console.log('📦 Installing better-sqlite3...');
|
|
146
|
+
return retryWithRecovery(async ()=>{
|
|
147
|
+
execSync('npm install better-sqlite3 --no-save', {
|
|
148
|
+
stdio: 'inherit',
|
|
149
|
+
cwd: process.cwd()
|
|
150
|
+
});
|
|
151
|
+
if (await verifyBetterSqlite3()) {
|
|
152
|
+
return {
|
|
153
|
+
success: true,
|
|
154
|
+
action: 'install-sqlite',
|
|
155
|
+
message: 'better-sqlite3 installed successfully',
|
|
156
|
+
recovered: true
|
|
157
|
+
};
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error('Installation completed but module not found');
|
|
160
|
+
}
|
|
161
|
+
}, {
|
|
162
|
+
maxRetries: 3,
|
|
163
|
+
delay: 2000,
|
|
164
|
+
onRetry: (attempt, error)=>{
|
|
165
|
+
console.log(`⚠️ Install attempt ${attempt} failed: ${error.message}`);
|
|
166
|
+
console.log('🔄 Cleaning cache and retrying...');
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
export async function recoverInitErrors(error) {
|
|
171
|
+
console.log('\n🚨 Error detected during initialization');
|
|
172
|
+
console.log(` Error: ${error?.message || String(error)}\n`);
|
|
173
|
+
if (isWSL()) {
|
|
174
|
+
console.log('🔧 Applying WSL-specific fixes...');
|
|
175
|
+
const wslRecovery = await recoverWSLErrors();
|
|
176
|
+
if (!wslRecovery.success) {
|
|
177
|
+
return wslRecovery;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (isNpmCacheError(error)) {
|
|
181
|
+
console.log('🔧 Detected npm cache error, attempting recovery...');
|
|
182
|
+
const cacheRecovery = await cleanNpmCache();
|
|
183
|
+
if (!cacheRecovery.success) {
|
|
184
|
+
return cacheRecovery;
|
|
185
|
+
}
|
|
186
|
+
if (!await verifyBetterSqlite3()) {
|
|
187
|
+
console.log('🔧 better-sqlite3 missing, attempting reinstall...');
|
|
188
|
+
return await installBetterSqlite3WithRecovery();
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
success: true,
|
|
192
|
+
action: 'error-recovery',
|
|
193
|
+
message: 'Cache cleaned and dependencies verified',
|
|
194
|
+
recovered: true
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
success: false,
|
|
199
|
+
action: 'error-recovery',
|
|
200
|
+
message: `Unable to automatically recover from error: ${error?.message || String(error)}`,
|
|
201
|
+
recovered: false
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
export const errorRecovery = {
|
|
205
|
+
isNpmCacheError,
|
|
206
|
+
isWSL,
|
|
207
|
+
cleanNpmCache,
|
|
208
|
+
retryWithRecovery,
|
|
209
|
+
recoverWSLErrors,
|
|
210
|
+
verifyBetterSqlite3,
|
|
211
|
+
installBetterSqlite3WithRecovery,
|
|
212
|
+
recoverInitErrors
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=error-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/error-recovery.ts"],"sourcesContent":["/**\n * Error Recovery Utilities\n * Automatic error detection and recovery for common installation issues\n */\n\nimport { execSync } from 'child_process';\nimport * as fs from 'fs-extra';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface RecoveryResult {\n success: boolean;\n action: string;\n message: string;\n recovered: boolean;\n}\n\nexport interface RetryOptions {\n maxRetries?: number;\n delay?: number;\n onRetry?: (attempt: number, error: Error) => void;\n cleanupFn?: () => Promise<void>;\n}\n\n/**\n * Detect if an error is the ENOTEMPTY npm cache error\n */\nexport function isNpmCacheError(error: any): boolean {\n const errorStr = error?.message || String(error);\n return (\n errorStr.includes('ENOTEMPTY') &&\n (errorStr.includes('npm') || errorStr.includes('npx') || errorStr.includes('_npx'))\n ) || errorStr.includes('better-sqlite3');\n}\n\n/**\n * Detect if running on WSL (Windows Subsystem for Linux)\n */\nexport function isWSL(): boolean {\n if (process.platform !== 'linux') {\n return false;\n }\n\n try {\n const release = fs.readFileSync('/proc/version', 'utf8').toLowerCase();\n return release.includes('microsoft') || release.includes('wsl');\n } catch {\n return false;\n }\n}\n\n/**\n * Clean npm and npx cache directories\n */\nexport async function cleanNpmCache(): Promise<RecoveryResult> {\n const homeDir = os.homedir();\n const npxCacheDir = path.join(homeDir, '.npm', '_npx');\n\n try {\n console.log('🧹 Cleaning npm cache...');\n\n // Clean npm cache\n try {\n execSync('npm cache clean --force', { stdio: 'pipe' });\n console.log('✅ npm cache cleaned');\n } catch (error) {\n console.warn('⚠️ npm cache clean failed, continuing...');\n }\n\n // Remove npx cache directory\n if (await fs.pathExists(npxCacheDir)) {\n console.log(`🗑️ Removing npx cache: ${npxCacheDir}`);\n await fs.remove(npxCacheDir);\n console.log('✅ npx cache removed');\n }\n\n // Fix permissions on WSL\n if (isWSL()) {\n const npmDir = path.join(homeDir, '.npm');\n if (await fs.pathExists(npmDir)) {\n try {\n execSync(`chmod -R 755 \"${npmDir}\"`, { stdio: 'pipe' });\n console.log('✅ npm directory permissions fixed');\n } catch (error) {\n console.warn('⚠️ Permission fix failed, continuing...');\n }\n }\n }\n\n return {\n success: true,\n action: 'cache-cleanup',\n message: 'npm/npx cache cleaned successfully',\n recovered: true\n };\n } catch (error) {\n return {\n success: false,\n action: 'cache-cleanup',\n message: `Failed to clean cache: ${error instanceof Error ? error.message : String(error)}`,\n recovered: false\n };\n }\n}\n\n/**\n * Automatic retry with exponential backoff and error recovery\n */\nexport async function retryWithRecovery<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxRetries = 3,\n delay = 1000,\n onRetry,\n cleanupFn\n } = options;\n\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n\n // Check if it's a recoverable error\n if (isNpmCacheError(error)) {\n console.log(`\\n⚠️ Detected npm cache error (attempt ${attempt}/${maxRetries})`);\n\n // Attempt automatic recovery\n const recovery = await cleanNpmCache();\n if (recovery.success) {\n console.log('✅ Cache cleaned, retrying...\\n');\n\n // Run custom cleanup if provided\n if (cleanupFn) {\n await cleanupFn();\n }\n\n // Exponential backoff\n const backoffDelay = delay * Math.pow(2, attempt - 1);\n await new Promise(resolve => setTimeout(resolve, backoffDelay));\n\n continue; // Retry\n } else {\n console.error('❌ Cache cleanup failed:', recovery.message);\n }\n }\n\n // Call retry callback\n if (onRetry && attempt < maxRetries) {\n onRetry(attempt, lastError);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n // Last attempt failed\n if (attempt === maxRetries) {\n break;\n }\n }\n }\n\n // All retries exhausted\n throw new Error(\n `Operation failed after ${maxRetries} attempts. ` +\n `Last error: ${lastError?.message || 'Unknown error'}`\n );\n}\n\n/**\n * WSL-specific error recovery\n */\nexport async function recoverWSLErrors(): Promise<RecoveryResult> {\n if (!isWSL()) {\n return {\n success: true,\n action: 'wsl-check',\n message: 'Not running on WSL, no recovery needed',\n recovered: false\n };\n }\n\n console.log('🔍 Detected WSL environment, applying fixes...');\n\n try {\n const homeDir = os.homedir();\n\n // Check if running from Windows mount\n const cwd = process.cwd();\n if (cwd.startsWith('/mnt/')) {\n console.warn('⚠️ WARNING: Running from Windows filesystem (/mnt/)');\n console.warn(' For best results, run from WSL filesystem (e.g., ~/projects/)');\n }\n\n // Ensure build tools are available\n try {\n execSync('which gcc', { stdio: 'pipe' });\n } catch {\n console.warn('⚠️ build-essential not found. Install with:');\n console.warn(' sudo apt-get update && sudo apt-get install -y build-essential python3');\n }\n\n // Clean cache with WSL-specific handling\n return await cleanNpmCache();\n } catch (error) {\n return {\n success: false,\n action: 'wsl-recovery',\n message: `WSL recovery failed: ${error instanceof Error ? error.message : String(error)}`,\n recovered: false\n };\n }\n}\n\n/**\n * Verify better-sqlite3 installation\n */\nexport async function verifyBetterSqlite3(): Promise<boolean> {\n try {\n require.resolve('better-sqlite3');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Install better-sqlite3 with retry and error recovery\n */\nexport async function installBetterSqlite3WithRecovery(): Promise<RecoveryResult> {\n console.log('📦 Installing better-sqlite3...');\n\n return retryWithRecovery(\n async () => {\n execSync('npm install better-sqlite3 --no-save', {\n stdio: 'inherit',\n cwd: process.cwd()\n });\n\n // Verify installation\n if (await verifyBetterSqlite3()) {\n return {\n success: true,\n action: 'install-sqlite',\n message: 'better-sqlite3 installed successfully',\n recovered: true\n };\n } else {\n throw new Error('Installation completed but module not found');\n }\n },\n {\n maxRetries: 3,\n delay: 2000,\n onRetry: (attempt, error) => {\n console.log(`⚠️ Install attempt ${attempt} failed: ${error.message}`);\n console.log('🔄 Cleaning cache and retrying...');\n }\n }\n );\n}\n\n/**\n * Comprehensive error recovery for initialization\n */\nexport async function recoverInitErrors(error: any): Promise<RecoveryResult> {\n console.log('\\n🚨 Error detected during initialization');\n console.log(` Error: ${error?.message || String(error)}\\n`);\n\n // WSL-specific recovery\n if (isWSL()) {\n console.log('🔧 Applying WSL-specific fixes...');\n const wslRecovery = await recoverWSLErrors();\n if (!wslRecovery.success) {\n return wslRecovery;\n }\n }\n\n // npm cache error recovery\n if (isNpmCacheError(error)) {\n console.log('🔧 Detected npm cache error, attempting recovery...');\n const cacheRecovery = await cleanNpmCache();\n if (!cacheRecovery.success) {\n return cacheRecovery;\n }\n\n // Try to reinstall better-sqlite3\n if (!await verifyBetterSqlite3()) {\n console.log('🔧 better-sqlite3 missing, attempting reinstall...');\n return await installBetterSqlite3WithRecovery();\n }\n\n return {\n success: true,\n action: 'error-recovery',\n message: 'Cache cleaned and dependencies verified',\n recovered: true\n };\n }\n\n // Generic error handling\n return {\n success: false,\n action: 'error-recovery',\n message: `Unable to automatically recover from error: ${error?.message || String(error)}`,\n recovered: false\n };\n}\n\n/**\n * Export utility functions\n */\nexport const errorRecovery = {\n isNpmCacheError,\n isWSL,\n cleanNpmCache,\n retryWithRecovery,\n recoverWSLErrors,\n verifyBetterSqlite3,\n installBetterSqlite3WithRecovery,\n recoverInitErrors\n};\n"],"names":["execSync","fs","path","os","isNpmCacheError","error","errorStr","message","String","includes","isWSL","process","platform","release","readFileSync","toLowerCase","cleanNpmCache","homeDir","homedir","npxCacheDir","join","console","log","stdio","warn","pathExists","remove","npmDir","success","action","recovered","Error","retryWithRecovery","fn","options","maxRetries","delay","onRetry","cleanupFn","lastError","attempt","recovery","backoffDelay","Math","pow","Promise","resolve","setTimeout","recoverWSLErrors","cwd","startsWith","verifyBetterSqlite3","require","installBetterSqlite3WithRecovery","recoverInitErrors","wslRecovery","cacheRecovery","errorRecovery"],"mappings":"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"}
|
|
@@ -166,4 +166,14 @@ export class MetricsReader {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
//# sourceMappingURL=metrics-reader.js.map processCount: 0,
|
|
170
|
+
orchestratorRunning: false,
|
|
171
|
+
port: null,
|
|
172
|
+
connections: 0
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
export { MetricsReader };
|
|
178
|
+
|
|
169
179
|
//# sourceMappingURL=metrics-reader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/metrics-reader.ts"],"sourcesContent":["import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\ninterface SystemMetrics {\n timestamp: number;\n memoryTotal: number;\n memoryUsed: number;\n memoryFree: number;\n memoryUsagePercent: number;\n memoryEfficiency: number;\n cpuCount: number;\n cpuLoad: number;\n platform: string;\n uptime: number;\n}\n\ninterface TaskMetric {\n id: string;\n type: string;\n success: boolean;\n duration: number;\n timestamp: number;\n metadata: Record<string, any>;\n}\n\ninterface PerformanceMetrics {\n startTime: number;\n totalTasks: number;\n successfulTasks: number;\n failedTasks: number;\n totalAgents: number;\n activeAgents: number;\n neuralEvents: number;\n}\n\ninterface Agent {\n id: string;\n name: string;\n type: string;\n status: 'active' | 'idle' | 'busy';\n activeTasks: number;\n lastActivity?: number;\n}\n\ninterface SessionData {\n id: string;\n startTime: number;\n endTime?: number;\n agents: Agent[];\n tasks: any[];\n status: 'active' | 'completed' | 'paused';\n}\n\ninterface MCPServerStatus {\n running: boolean;\n processCount: number;\n orchestratorRunning: boolean;\n port: number | null;\n connections: number;\n}\n\nexport class MetricsReader {\n private metricsDir = '.claude-flow/metrics';\n private sessionsDir = '.claude-flow/sessions';\n\n async getSystemMetrics(): Promise<SystemMetrics | null> {\n try {\n const filePath = path.join(this.metricsDir, 'system-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n const metrics: SystemMetrics[] = JSON.parse(content);\n \n // Return the most recent metric\n return metrics.length > 0 ? metrics[metrics.length - 1] : null;\n } catch (error) {\n return null;\n }\n }\n\n async getTaskMetrics(): Promise<TaskMetric[]> {\n try {\n const filePath = path.join(this.metricsDir, 'task-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getPerformanceMetrics(): Promise<PerformanceMetrics | null> {\n try {\n const filePath = path.join(this.metricsDir, 'performance.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getActiveAgents(): Promise<Agent[]> {\n try {\n // First check performance metrics for agent count\n const perfMetrics = await this.getPerformanceMetrics();\n \n // Also check session files for more detailed agent info\n const sessionFiles = await this.getSessionFiles();\n const agents: Agent[] = [];\n \n for (const file of sessionFiles) {\n try {\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', file), 'utf8');\n const sessionData = JSON.parse(content);\n \n if (sessionData.agents && Array.isArray(sessionData.agents)) {\n agents.push(...sessionData.agents);\n }\n } catch {\n // Skip invalid session files\n }\n }\n \n // If no agents found in sessions, create mock agents based on performance metrics\n if (agents.length === 0 && perfMetrics) {\n const activeCount = perfMetrics.activeAgents || 0;\n const totalCount = perfMetrics.totalAgents || 0;\n \n for (let i = 0; i < totalCount; i++) {\n agents.push({\n id: `agent-${i + 1}`,\n name: `Agent ${i + 1}`,\n type: i === 0 ? 'orchestrator' : 'worker',\n status: i < activeCount ? 'active' : 'idle',\n activeTasks: i < activeCount ? 1 : 0,\n lastActivity: Date.now() - (i * 1000)\n });\n }\n }\n \n return agents;\n } catch (error) {\n return [];\n }\n }\n\n async getSessionStatus(): Promise<SessionData | null> {\n try {\n const sessionFiles = await this.getSessionFiles();\n \n if (sessionFiles.length === 0) {\n return null;\n }\n \n // Get the most recent session\n const mostRecentFile = sessionFiles[sessionFiles.length - 1];\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', mostRecentFile), 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getRecentTasks(limit: number = 10): Promise<any[]> {\n try {\n const taskMetrics = await this.getTaskMetrics();\n \n // Sort by timestamp descending and take the limit\n return taskMetrics\n .sort((a, b) => b.timestamp - a.timestamp)\n .slice(0, limit)\n .map(task => ({\n id: task.id,\n type: task.type,\n status: task.success ? 'completed' : 'failed',\n startTime: task.timestamp - task.duration,\n endTime: task.timestamp,\n duration: task.duration\n }));\n } catch (error) {\n return [];\n }\n }\n\n async getOverallHealth(): Promise<'healthy' | 'warning' | 'error'> {\n try {\n const systemMetrics = await this.getSystemMetrics();\n const perfMetrics = await this.getPerformanceMetrics();\n \n if (!systemMetrics && !perfMetrics) {\n return 'error';\n }\n \n // Check memory usage\n if (systemMetrics && systemMetrics.memoryUsagePercent > 90) {\n return 'error';\n }\n \n if (systemMetrics && systemMetrics.memoryUsagePercent > 75) {\n return 'warning';\n }\n \n // Check CPU load\n if (systemMetrics && systemMetrics.cpuLoad > 0.8) {\n return 'warning';\n }\n \n // Check task failure rate\n if (perfMetrics && perfMetrics.totalTasks > 0) {\n const failureRate = perfMetrics.failedTasks / perfMetrics.totalTasks;\n if (failureRate > 0.5) {\n return 'error';\n }\n if (failureRate > 0.2) {\n return 'warning';\n }\n }\n \n return 'healthy';\n } catch (error) {\n return 'error';\n }\n }\n\n private async getSessionFiles(): Promise<string[]> {\n try {\n const files = await fs.readdir(path.join(this.sessionsDir, 'pair'));\n return files.filter(f => f.endsWith('.json')).sort();\n } catch (error) {\n return [];\n }\n }\n\n async getMCPServerStatus(): Promise<MCPServerStatus> {\n try {\n // Check if MCP server process is running\n const { stdout } = await execAsync('ps aux | grep -E \"mcp-server\\\\.js|claude-flow mcp start\" | grep -v grep | wc -l');\n const processCount = parseInt(stdout.trim(), 10);\n \n // Check for orchestrator running\n const { stdout: orchestratorOut } = await execAsync('ps aux | grep -E \"claude-flow start\" | grep -v grep | wc -l');\n const orchestratorRunning = parseInt(orchestratorOut.trim(), 10) > 0;\n \n // Determine status\n const isRunning = processCount > 0;\n \n // Try to get port from process (default is 3000)\n let port: number | null = 3000;\n try {\n const { stdout: portOut } = await execAsync('lsof -i :3000 2>/dev/null | grep LISTEN | wc -l');\n if (parseInt(portOut.trim(), 10) === 0) {\n // If port 3000 not listening, check other common ports\n port = null;\n }\n } catch {\n // lsof might not be available or port not in use\n }\n \n return {\n running: isRunning,\n processCount,\n orchestratorRunning,\n port,\n connections: processCount > 0 ? Math.max(1, processCount - 1) : 0 // Estimate connections\n };\n } catch (error) {\n // Fallback if commands fail\n return {\n running: false,\n processCount: 0,\n orchestratorRunning: false,\n port: null,\n connections: 0\n };\n }\n }\n}"],"names":["fs","path","exec","promisify","execAsync","MetricsReader","metricsDir","sessionsDir","getSystemMetrics","filePath","join","content","readFile","metrics","JSON","parse","length","error","getTaskMetrics","getPerformanceMetrics","getActiveAgents","perfMetrics","sessionFiles","getSessionFiles","agents","file","sessionData","Array","isArray","push","activeCount","activeAgents","totalCount","totalAgents","i","id","name","type","status","activeTasks","lastActivity","Date","now","getSessionStatus","mostRecentFile","getRecentTasks","limit","taskMetrics","sort","a","b","timestamp","slice","map","task","success","startTime","duration","endTime","getOverallHealth","systemMetrics","memoryUsagePercent","cpuLoad","totalTasks","failureRate","failedTasks","files","readdir","filter","f","endsWith","getMCPServerStatus","stdout","processCount","parseInt","trim","orchestratorOut","orchestratorRunning","isRunning","port","portOut","running","connections","Math","max"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/metrics-reader.js"],"sourcesContent":["import { promises as fs } from 'fs';\nimport path from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\nclass MetricsReader {\n constructor() {\n this.metricsDir = '.claude-flow/metrics';\n this.sessionsDir = '.claude-flow/sessions';\n }\n\n async getSystemMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'system-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n const metrics = JSON.parse(content);\n \n // Return the most recent metric\n return metrics.length > 0 ? metrics[metrics.length - 1] : null;\n } catch (error) {\n return null;\n }\n }\n\n async getTaskQueue() {\n try {\n const queueFile = '.claude-flow/tasks/queue.json';\n const content = await fs.readFile(queueFile, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getTaskMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'task-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getPerformanceMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'performance.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getActiveAgents() {\n try {\n const agents = [];\n \n // Check for agents in the .claude-flow/agents directory\n const agentsDir = '.claude-flow/agents';\n try {\n const agentFiles = await fs.readdir(agentsDir);\n for (const file of agentFiles) {\n if (file.endsWith('.json')) {\n try {\n const content = await fs.readFile(path.join(agentsDir, file), 'utf8');\n const agent = JSON.parse(content);\n agents.push(agent);\n } catch {\n // Skip invalid agent files\n }\n }\n }\n } catch {\n // Agents directory doesn't exist yet\n }\n \n // If no agents found in directory, check session files\n if (agents.length === 0) {\n const sessionFiles = await this.getSessionFiles();\n for (const file of sessionFiles) {\n try {\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', file), 'utf8');\n const sessionData = JSON.parse(content);\n \n if (sessionData.agents && Array.isArray(sessionData.agents)) {\n agents.push(...sessionData.agents);\n }\n } catch {\n // Skip invalid session files\n }\n }\n }\n \n return agents;\n } catch (error) {\n return [];\n }\n }\n\n async getSessionStatus() {\n try {\n const sessionFiles = await this.getSessionFiles();\n \n if (sessionFiles.length === 0) {\n return null;\n }\n \n // Get the most recent session\n const mostRecentFile = sessionFiles[sessionFiles.length - 1];\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', mostRecentFile), 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getRecentTasks(limit = 10) {\n try {\n const taskMetrics = await this.getTaskMetrics();\n \n // Sort by timestamp descending and take the limit\n return taskMetrics\n .sort((a, b) => b.timestamp - a.timestamp)\n .slice(0, limit)\n .map(task => ({\n id: task.id,\n type: task.type,\n status: task.success ? 'completed' : 'failed',\n startTime: task.timestamp - task.duration,\n endTime: task.timestamp,\n duration: task.duration\n }));\n } catch (error) {\n return [];\n }\n }\n\n async getOverallHealth() {\n try {\n const systemMetrics = await this.getSystemMetrics();\n const perfMetrics = await this.getPerformanceMetrics();\n \n if (!systemMetrics && !perfMetrics) {\n return 'error';\n }\n \n // Check memory usage\n if (systemMetrics && systemMetrics.memoryUsagePercent > 90) {\n return 'error';\n }\n \n if (systemMetrics && systemMetrics.memoryUsagePercent > 75) {\n return 'warning';\n }\n \n // Check CPU load\n if (systemMetrics && systemMetrics.cpuLoad > 0.8) {\n return 'warning';\n }\n \n // Check task failure rate\n if (perfMetrics && perfMetrics.totalTasks > 0) {\n const failureRate = perfMetrics.failedTasks / perfMetrics.totalTasks;\n if (failureRate > 0.5) {\n return 'error';\n }\n if (failureRate > 0.2) {\n return 'warning';\n }\n }\n \n return 'healthy';\n } catch (error) {\n return 'error';\n }\n }\n\n async getSessionFiles() {\n try {\n const files = await fs.readdir(path.join(this.sessionsDir, 'pair'));\n return files.filter(f => f.endsWith('.json')).sort();\n } catch (error) {\n return [];\n }\n }\n\n async getMCPServerStatus() {\n try {\n // Check if MCP server process is running (including flow-nexus and other MCP variants)\n const { stdout } = await execAsync('ps aux | grep -E \"mcp\" | grep -v grep | wc -l');\n const processCount = parseInt(stdout.trim(), 10);\n \n // Check for orchestrator running\n const { stdout: orchestratorOut } = await execAsync('ps aux | grep -E \"claude-flow start\" | grep -v grep | wc -l');\n const orchestratorRunning = parseInt(orchestratorOut.trim(), 10) > 0;\n \n // Determine status\n const isRunning = processCount > 0;\n \n // Try to get port from process (default is 3000)\n let port = 3000;\n try {\n const { stdout: portOut } = await execAsync('lsof -i :3000 2>/dev/null | grep LISTEN | wc -l');\n if (parseInt(portOut.trim(), 10) === 0) {\n // If port 3000 not listening, check other common ports\n port = null;\n }\n } catch {\n // lsof might not be available or port not in use\n }\n \n return {\n running: isRunning,\n processCount,\n orchestratorRunning,\n port,\n connections: processCount > 0 ? Math.max(1, processCount - 1) : 0 // Estimate connections\n };\n } catch (error) {\n // Fallback if commands fail\n return {\n running: false,\n processCount: 0,\n orchestratorRunning: false,\n port: null,\n connections: 0\n };\n }\n }\n}\n\nexport { MetricsReader };"],"names":["promises","fs","path","exec","promisify","execAsync","MetricsReader","metricsDir","sessionsDir","getSystemMetrics","filePath","join","content","readFile","metrics","JSON","parse","length","error","getTaskQueue","queueFile","getTaskMetrics","getPerformanceMetrics","getActiveAgents","agents","agentsDir","agentFiles","readdir","file","endsWith","agent","push","sessionFiles","getSessionFiles","sessionData","Array","isArray","getSessionStatus","mostRecentFile","getRecentTasks","limit","taskMetrics","sort","a","b","timestamp","slice","map","task","id","type","status","success","startTime","duration","endTime","getOverallHealth","systemMetrics","perfMetrics","memoryUsagePercent","cpuLoad","totalTasks","failureRate","failedTasks","files","filter","f","getMCPServerStatus","stdout","processCount","parseInt","trim","orchestratorOut","orchestratorRunning","isRunning","port","portOut","running","connections","Math","max"],"mappings":"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"}AG,KAAK;gBAChD,OAAO;YACT;YAGA,IAAIzC,eAAeA,YAAY0C,UAAU,GAAG,GAAG;gBAC7C,MAAMC,cAAc3C,YAAY4C,WAAW,GAAG5C,YAAY0C,UAAU;gBACpE,IAAIC,cAAc,KAAK;oBACrB,OAAO;gBACT;gBACA,IAAIA,cAAc,KAAK;oBACrB,OAAO;gBACT;YACF;YAEA,OAAO;QACT,EAAE,OAAO/C,OAAO;YACd,OAAO;QACT;IACF;IAEA,MAAcM,kBAAqC;QACjD,IAAI;YACF,MAAM2C,QAAQ,MAAMlE,GAAGmE,OAAO,CAAClE,KAAKS,IAAI,CAAC,IAAI,CAACH,WAAW,EAAE;YAC3D,OAAO2D,MAAME,MAAM,CAACC,CAAAA,IAAKA,EAAEC,QAAQ,CAAC,UAAUtB,IAAI;QACpD,EAAE,OAAO/B,OAAO;YACd,OAAO,EAAE;QACX;IACF;IAEA,MAAMsD,qBAA+C;QACnD,IAAI;YAEF,MAAM,EAAEC,MAAM,EAAE,GAAG,MAAMpE,UAAU;YACnC,MAAMqE,eAAeC,SAASF,OAAOG,IAAI,IAAI;YAG7C,MAAM,EAAEH,QAAQI,eAAe,EAAE,GAAG,MAAMxE,UAAU;YACpD,MAAMyE,sBAAsBH,SAASE,gBAAgBD,IAAI,IAAI,MAAM;YAGnE,MAAMG,YAAYL,eAAe;YAGjC,IAAIM,OAAsB;YAC1B,IAAI;gBACF,MAAM,EAAEP,QAAQQ,OAAO,EAAE,GAAG,MAAM5E,UAAU;gBAC5C,IAAIsE,SAASM,QAAQL,IAAI,IAAI,QAAQ,GAAG;oBAEtCI,OAAO;gBACT;YACF,EAAE,OAAM,CAER;YAEA,OAAO;gBACLE,SAASH;gBACTL;gBACAI;gBACAE;gBACAG,aAAaT,eAAe,IAAIU,KAAKC,GAAG,CAAC,GAAGX,eAAe,KAAK;YAClE;QACF,EAAE,OAAOxD,OAAO;YAEd,OAAO;gBACLgE,SAAS;gBACTR,cAAc;gBACdI,qBAAqB;gBACrBE,MAAM;gBACNG,aAAa;YACf;QACF;IACF;AACF"}
|