/** * Statusline script section: system/ADR/hooks/agent/memory/test/integration/ * session collectors plus the 256-colour palette and render helpers. * Spliced verbatim into generateStatuslineScript() output. */ export declare const STATUSLINE_METRICS_SECTION = "// System metrics (uses process.memoryUsage() \u2014 no shell spawn)\nfunction getSystemMetrics() {\n const memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);\n const learning = getLearningStats();\n const memoryStats = getMemoryStats();\n\n // Intelligence from learning.json\n const learningData = readJSON(path.join(CWD, '.monomind', 'metrics', 'learning.json'));\n let intelligencePct = 0;\n let contextPct = 0;\n\n if (learningData?.intelligence?.score !== undefined) {\n intelligencePct = Math.min(100, Math.floor(learningData.intelligence.score));\n } else {\n // Use actual vector/entry counts \u2014 2000 entries = 100%\n const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 20)) : 0;\n const fromVectors = memoryStats.vectorCount > 0 ? Math.min(100, Math.floor(memoryStats.vectorCount / 20)) : 0;\n intelligencePct = Math.max(fromPatterns, fromVectors);\n }\n\n // Maturity fallback (pure fs checks, no git exec)\n if (intelligencePct === 0) {\n let score = 0;\n if (fs.existsSync(path.join(CWD, '.claude'))) score += 15;\n const srcDirs = ['src', 'lib', 'app', 'packages', 'v1'];\n for (const d of srcDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 15; break; } }\n const testDirs = ['tests', 'test', '__tests__', 'spec'];\n for (const d of testDirs) { if (fs.existsSync(path.join(CWD, d))) { score += 10; break; } }\n const cfgFiles = ['package.json', 'tsconfig.json', 'pyproject.toml', 'Cargo.toml', 'go.mod'];\n for (const f of cfgFiles) { if (fs.existsSync(path.join(CWD, f))) { score += 5; break; } }\n intelligencePct = Math.min(100, score);\n }\n\n if (learningData?.sessions?.total !== undefined) {\n contextPct = Math.min(100, learningData.sessions.total * 5);\n } else {\n contextPct = Math.min(100, Math.floor(learning.sessions * 5));\n }\n\n // Sub-agents from file metrics (no ps aux)\n let subAgents = 0;\n const activityData = readJSON(path.join(CWD, '.monomind', 'metrics', 'monoswarm-activity.json'));\n if (activityData?.processes?.estimated_agents) {\n subAgents = activityData.processes.estimated_agents;\n }\n\n return { memoryMB, contextPct, intelligencePct, subAgents };\n}\n\n// ADR status (count files only \u2014 don't read contents)\nfunction getADRStatus() {\n // Count actual ADR files first \u2014 compliance JSON may be stale\n const adrPaths = [\n path.join(CWD, 'packages', 'implementation', 'adrs'),\n path.join(CWD, 'docs', 'adrs'),\n path.join(CWD, '.monomind', 'adrs'),\n ];\n\n for (const adrPath of adrPaths) {\n try {\n if (fs.existsSync(adrPath)) {\n const files = fs.readdirSync(adrPath).filter(f =>\n f.endsWith('.md') && (f.startsWith('ADR-') || f.startsWith('adr-') || /^\\d{4}-/.test(f))\n );\n // Report actual count \u2014 don't guess compliance without reading files\n return { count: files.length, implemented: files.length, compliance: 0 };\n }\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); /* ignore */ }\n }\n\n return { count: 0, implemented: 0, compliance: 0 };\n}\n\n// Hooks status (shared settings cache)\nfunction getHooksStatus() {\n let enabled = 0;\n let total = 0;\n const settings = getSettings();\n\n if (settings?.hooks) {\n for (const category of Object.keys(settings.hooks)) {\n const matchers = settings.hooks[category];\n if (!Array.isArray(matchers)) continue;\n for (const matcher of matchers) {\n const hooks = matcher?.hooks;\n if (Array.isArray(hooks)) {\n total += hooks.length;\n enabled += hooks.length;\n }\n }\n }\n }\n\n try {\n const hooksDir = path.join(CWD, '.claude', 'hooks');\n if (fs.existsSync(hooksDir)) {\n const hookFiles = fs.readdirSync(hooksDir).filter(f => f.endsWith('.js') || f.endsWith('.sh')).length;\n total = Math.max(total, hookFiles);\n enabled = Math.max(enabled, hookFiles);\n }\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); /* ignore */ }\n\n return { enabled, total };\n}\n\n// Active agent \u2014 reads last routing result persisted by hook-handler\nfunction getActiveAgent() {\n const routeFile = path.join(CWD, '.monomind', 'last-route.json');\n try {\n const routeStat = safeStat(routeFile);\n if (!routeStat || routeStat.size > MAX_JSON_READ_BYTES) return null;\n const data = JSON.parse(fs.readFileSync(routeFile, 'utf-8'));\n if (!data || !data.agent) return null;\n\n // Stale after 30 minutes (session likely changed)\n const age = Date.now() - new Date(data.updatedAt || 0).getTime();\n if (age > 30 * 60 * 1000) return null;\n\n // Prefer display name if set (from load-agent), else format the slug\n const displayName = data.name || data.agent\n .replace(/-/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase());\n\n return {\n slug: data.agent,\n name: displayName,\n category: data.category || null,\n confidence: data.confidence || 0,\n activated: data.activated || false, // true = manually loaded extras agent\n };\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); return null; }\n}\n\n// Memory (SQLite) stats \u2014 count real entries\nfunction getMemoryStats() {\n let vectorCount = 0;\n let dbSizeKB = 0;\n let namespaces = 0;\n let hasHnsw = false;\n\n // 1. Count real entries from auto-memory-store.json\n const storePath = path.join(CWD, '.monomind', 'data', 'auto-memory-store.json');\n const storeStat = safeStat(storePath);\n if (storeStat && storeStat.size <= MAX_JSON_READ_BYTES) {\n dbSizeKB += storeStat.size / 1024;\n try {\n const store = JSON.parse(fs.readFileSync(storePath, 'utf-8'));\n if (Array.isArray(store)) vectorCount += store.length;\n else if (store?.entries) vectorCount += store.entries.length;\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); /* fall back to size estimate */ }\n }\n\n // 2. Count entries from ranked-context.json\n const rankedPath = path.join(CWD, '.monomind', 'data', 'ranked-context.json');\n try {\n const ranked = readJSON(rankedPath);\n if (ranked?.entries?.length > vectorCount) vectorCount = ranked.entries.length;\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); /* ignore */ }\n\n // 3. Add DB file sizes\n const dbFiles = [\n path.join(CWD, 'data', 'memory.db'),\n path.join(CWD, '.monomind', 'memory.db'),\n path.join(CWD, '.swarm', 'memory.db'),\n ];\n for (const f of dbFiles) {\n const stat = safeStat(f);\n if (stat) {\n dbSizeKB += stat.size / 1024;\n namespaces++;\n }\n }\n\n // 4. Check for graph data\n const graphPath = path.join(CWD, 'data', 'memory.graph');\n const graphStat = safeStat(graphPath);\n if (graphStat) dbSizeKB += graphStat.size / 1024;\n\n // 5. HNSW index\n const hnswPaths = [\n path.join(CWD, '.swarm', 'hnsw.index'),\n path.join(CWD, '.monomind', 'hnsw.index'),\n ];\n for (const p of hnswPaths) {\n const stat = safeStat(p);\n if (stat) {\n hasHnsw = true;\n break;\n }\n }\n\n // HNSW is available if memory package is present\n if (!hasHnsw) {\n const memPkgPaths = [\n path.join(CWD, 'packages', '@monomind', 'memory', 'dist'),\n path.join(CWD, 'node_modules', '@monomind', 'memory'),\n ];\n for (const p of memPkgPaths) {\n if (fs.existsSync(p)) { hasHnsw = true; break; }\n }\n }\n\n return { vectorCount, dbSizeKB: Math.floor(dbSizeKB), namespaces, hasHnsw };\n}\n\n// Test stats (count files only \u2014 NO reading file contents)\nfunction getTestStats() {\n let testFiles = 0;\n\n function countTestFiles(dir, depth = 0) {\n if (depth > 6) return;\n try {\n if (!fs.existsSync(dir)) return;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {\n countTestFiles(path.join(dir, entry.name), depth + 1);\n } else if (entry.isFile()) {\n const n = entry.name;\n if (n.includes('.test.') || n.includes('.spec.') || n.includes('_test.') || n.includes('_spec.')) {\n testFiles++;\n }\n }\n }\n } catch (err) { if (process.env.MONOMIND_DEBUG) console.error('[statusline]', err); /* ignore */ }\n }\n\n // Scan all source directories\n for (const d of ['tests', 'test', '__tests__', 'src', 'v1']) {\n countTestFiles(path.join(CWD, d));\n }\n\n // Estimate ~4 test cases per file (avoids reading every file)\n return { testFiles, testCases: testFiles * 4 };\n}\n\n// Integration status (shared settings + file checks)\nfunction getIntegrationStatus() {\n const mcpServers = { total: 0, enabled: 0 };\n const settings = getSettings();\n\n if (settings?.mcpServers && typeof settings.mcpServers === 'object') {\n const servers = Object.keys(settings.mcpServers);\n mcpServers.total = servers.length;\n mcpServers.enabled = settings.enabledMcpjsonServers\n ? settings.enabledMcpjsonServers.filter(s => servers.includes(s)).length\n : servers.length;\n }\n\n // Fallback: .mcp.json\n if (mcpServers.total === 0) {\n const mcpConfig = readJSON(path.join(CWD, '.mcp.json'))\n || readJSON(path.join(os.homedir(), '.claude', 'mcp.json'));\n if (mcpConfig?.mcpServers) {\n const s = Object.keys(mcpConfig.mcpServers);\n mcpServers.total = s.length;\n mcpServers.enabled = s.length;\n }\n }\n\n const hasDatabase = ['.swarm/memory.db', '.monomind/memory.db', 'data/memory.db']\n .some(p => fs.existsSync(path.join(CWD, p)));\n const hasApi = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);\n\n return { mcpServers, hasDatabase, hasApi };\n}\n\n// Session stats (pure file reads)\nfunction getSessionStats() {\n for (const p of ['.monomind/session.json', '.claude/session.json']) {\n const data = readJSON(path.join(CWD, p));\n if (data?.startTime) {\n const diffMs = Date.now() - new Date(data.startTime).getTime();\n const mins = Math.floor(diffMs / 60000);\n const duration = mins < 60 ? `${mins}m` : `${Math.floor(mins / 60)}h${mins % 60}m`;\n return { duration };\n }\n }\n return { duration: '' };\n}\n\n// \u2500\u2500\u2500 Extended 256-color palette \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst x = {\n // Backgrounds (used sparingly for labels)\n bgPurple: '\\x1b[48;5;55m',\n bgTeal: '\\x1b[48;5;23m',\n bgReset: '\\x1b[49m',\n // Foregrounds\n purple: '\\x1b[38;5;141m', // soft lavender-purple (brand)\n violet: '\\x1b[38;5;99m', // deeper purple\n teal: '\\x1b[38;5;51m', // bright teal\n mint: '\\x1b[38;5;120m', // soft green\n gold: '\\x1b[38;5;220m', // warm gold\n orange: '\\x1b[38;5;208m', // alert orange\n coral: '\\x1b[38;5;203m', // error red-pink\n sky: '\\x1b[38;5;117m', // soft blue\n rose: '\\x1b[38;5;218m', // warm pink\n slate: '\\x1b[38;5;245m', // neutral grey\n white: '\\x1b[38;5;255m', // bright white\n green: '\\x1b[38;5;82m', // vivid green\n red: '\\x1b[38;5;196m', // vivid red\n yellow: '\\x1b[38;5;226m', // vivid yellow\n // Shared\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n reset: '\\x1b[0m',\n};\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// Block progress bar: \u25B0\u25B0\u25B0\u25B1\u25B1 (5 blocks)\nfunction blockBar(current, total, width = 5) {\n const filled = Math.min(width, Math.round((current / Math.max(total, 1)) * width));\n return '\\u25B0'.repeat(filled) + `${x.slate}\\u25B1${x.reset}`.repeat(width - filled);\n}\n\n// Health dot: \u25CF colored by status\nfunction dot(ok) {\n if (ok === 'good') return `${x.green}\u25CF${x.reset}`;\n if (ok === 'warn') return `${x.gold}\u25CF${x.reset}`;\n if (ok === 'error') return `${x.coral}\u25CF${x.reset}`;\n return `${x.slate}\u25CF${x.reset}`; // 'none'\n}\n\n// Pill badge: [ LABEL ] with background\nfunction badge(label, color) {\n return `${color}[${label}]${x.reset}`;\n}\n\n// Divider character\nconst DIV = `${x.slate}\u2502${x.reset}`;\nconst SEP = `${x.slate}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${x.reset}`;\n\n// Pct \u2192 color\nfunction pctColor(pct) {\n if (pct >= 75) return x.green;\n if (pct >= 40) return x.gold;\n if (pct > 0) return x.orange;\n return x.slate;\n}\n\n// Security status \u2192 label + color\nfunction secBadge(status) {\n if (status === 'CLEAN') return { label: '\u2714 CLEAN', col: x.green };\n if (status === 'STALE') return { label: '\u27F3 STALE', col: x.gold };\n if (status === 'IN_PROGRESS') return { label: '\u27F3 RUNNING', col: x.sky };\n if (status === 'SCANNED') return { label: '\u2714 SCANNED', col: x.mint };\n if (status === 'PENDING') return { label: '\u23F8 PENDING', col: x.gold };\n return { label: '\u2716 NONE', col: x.slate };\n}\n\n"; //# sourceMappingURL=statusline-script-metrics.d.ts.map