claude-flow 3.38.19 → 3.38.20

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.
@@ -552,6 +552,68 @@ function getLocalSecurity(cliSecurity) {
552
552
  return base;
553
553
  }
554
554
 
555
+ // Cached pattern count. The store is routinely >10MB (14.5MB / 1277 patterns on
556
+ // the machine this was diagnosed on, costing 53ms to read+parse), and the
557
+ // statusline re-renders on every prompt, so the parse is keyed on the file's
558
+ // mtime+size and reused until the store actually changes.
559
+ const PATTERN_COUNT_CACHE = path.join(os.tmpdir(), 'ruflo-statusline-patterns-' + require('crypto').createHash('md5').update(CWD).digest('hex').slice(0, 8) + '.json');
560
+
561
+ function countPatternsCached(file) {
562
+ let stat;
563
+ try { stat = fs.statSync(file); } catch { return 0; }
564
+ const key = stat.mtimeMs + ':' + stat.size;
565
+
566
+ try {
567
+ const memo = JSON.parse(fs.readFileSync(PATTERN_COUNT_CACHE, 'utf-8'));
568
+ if (memo && memo[file] && memo[file].key === key) return memo[file].count;
569
+ } catch { /* no memo yet, or unreadable — fall through and recount */ }
570
+
571
+ let count = 0;
572
+ try {
573
+ const raw = JSON.parse(fs.readFileSync(file, 'utf-8'));
574
+ if (Array.isArray(raw)) count = raw.length;
575
+ else if (raw && Array.isArray(raw.patterns)) count = raw.patterns.length;
576
+ else if (raw && typeof raw === 'object') count = Object.keys(raw).length;
577
+ } catch { return 0; }
578
+
579
+ try {
580
+ let memo = {};
581
+ try { memo = JSON.parse(fs.readFileSync(PATTERN_COUNT_CACHE, 'utf-8')) || {}; } catch { /* start fresh */ }
582
+ memo[file] = { key, count };
583
+ fs.writeFileSync(PATTERN_COUNT_CACHE, JSON.stringify(memo));
584
+ } catch { /* cache is an optimisation, never a requirement */ }
585
+
586
+ return count;
587
+ }
588
+
589
+ // `system` is nominally CLI-populated, but the pattern store is on disk, so a
590
+ // dead CLI must not render as "no learning". Without this, every candidate in
591
+ // resolveCliBinCandidates() failing (a source-only marketplace checkout, or an
592
+ // npx fetch that dies in a workspace root) silently degraded the brain to a
593
+ // hardcoded 0% while the overlaid segments beside it kept showing live data —
594
+ // indistinguishable from a genuine zero. Same reasoning as getLocalAgentDB(),
595
+ // which had to start reading locally after the statusline reported "Vectors 0"
596
+ // on a database holding thousands.
597
+ function getLocalIntelligence(current) {
598
+ const base = (current && typeof current === 'object') ? current : {};
599
+ if (typeof base.intelligencePct === 'number' && base.intelligencePct > 0) return base;
600
+
601
+ for (const file of [
602
+ path.join(CWD, '.claude-flow', 'neural', 'patterns.json'),
603
+ path.join(os.homedir(), '.claude-flow', 'neural', 'patterns.json'),
604
+ ]) {
605
+ const n = countPatternsCached(file);
606
+ if (n > 0) {
607
+ base.intelligencePct = Math.min(100, Math.floor(n / 10));
608
+ return base;
609
+ }
610
+ }
611
+
612
+ // No CLI value and no local store: unknown, which is not the same as zero.
613
+ base.intelligencePct = null;
614
+ return base;
615
+ }
616
+
555
617
  // Overlay every locally-derived block onto the CLI data (mutates in place).
556
618
  function applyLocalOverlays(data) {
557
619
  data.adrs = getLocalADRCount();
@@ -562,6 +624,7 @@ function applyLocalOverlays(data) {
562
624
  // Security overlay: recompute freshness from disk on every render so cached
563
625
  // CLI JSON can never freeze the pill at PENDING. See getLocalSecurity() above.
564
626
  data.security = getLocalSecurity(data.security);
627
+ data.system = getLocalIntelligence(data.system);
565
628
  return data;
566
629
  }
567
630
 
@@ -575,7 +638,7 @@ function buildLocalFallback() {
575
638
  v3Progress: { domainsCompleted: 0, totalDomains: 5, dddProgress: 0, patternsLearned: 0, sessionsCompleted: 0 },
576
639
  security: { status: 'NONE', findings: 0, cvesFixed: 0, totalCves: 0 },
577
640
  swarm: { activeAgents: 0, maxAgents: CONFIG.maxAgents, coordinationActive: false },
578
- system: { memoryMB: memMB, contextPct: 0, intelligencePct: 0, subAgents: 0 },
641
+ system: { memoryMB: memMB, contextPct: 0, intelligencePct: null, subAgents: 0 },
579
642
  lastUpdated: new Date().toISOString(),
580
643
  });
581
644
  }
@@ -979,7 +1042,11 @@ function generateStatusline() {
979
1042
  const activeAgents = swarm.activeAgents || 0;
980
1043
  const maxAgents = swarm.maxAgents || CONFIG.maxAgents;
981
1044
  const coordinationActive = swarm.coordinationActive || false;
982
- const intelligencePct = system.intelligencePct || 0;
1045
+ // null/undefined means "no source answered", which must not collapse to 0 --
1046
+ // that is exactly the ambiguity this segment used to present.
1047
+ const intelligencePct = (typeof system.intelligencePct === 'number')
1048
+ ? system.intelligencePct
1049
+ : null;
983
1050
  const memoryMB = system.memoryMB || 0;
984
1051
  const subAgents = system.subAgents || 0;
985
1052
  const findings = Math.max(0, security.findings || 0);
@@ -1035,14 +1102,14 @@ function generateStatusline() {
1035
1102
  // do next; diagnostic detail moves to `ruflo status --verbose`.
1036
1103
  const agentsColor = activeAgents > 0 ? c.brightGreen : c.dim;
1037
1104
  const hooksColor = hooksEnabled > 0 ? c.brightGreen : c.dim;
1038
- const intellColor = intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
1105
+ const intellColor = intelligencePct === null ? c.dim : intelligencePct >= 80 ? c.brightGreen : intelligencePct >= 40 ? c.brightYellow : c.dim;
1039
1106
  const swarmInd = coordinationActive ? c.brightGreen + '◉' + c.reset + ' ' : c.dim + '○' + c.reset + ' ';
1040
1107
  const healthAllGreen = (secStatus === 'CLEAN' || secStatus === 'NONE') && findings === 0;
1041
1108
  const opsParts = [];
1042
1109
  opsParts.push(c.cyan + 'Swarm ' + swarmInd + agentsColor + activeAgents + c.reset + '/' + c.brightWhite + maxAgents + c.reset);
1043
1110
  if (subAgents > 0) opsParts.push(c.brightPurple + '👥 ' + subAgents + c.reset);
1044
1111
  opsParts.push(c.cyan + 'Hooks ' + hooksColor + hooksEnabled + c.reset + '/' + c.brightWhite + hooksTotal + c.reset);
1045
- opsParts.push(intellColor + '🧠 ' + intelligencePct + '%' + c.reset);
1112
+ opsParts.push(intellColor + '🧠 ' + (intelligencePct === null ? '—' : intelligencePct + '%') + c.reset);
1046
1113
  opsParts.push(c.brightCyan + '💾 ' + memoryMB + 'MB' + c.reset);
1047
1114
  // Health: one glyph when green, terse copy when there's something to act on.
1048
1115
  if (healthAllGreen) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.38.19",
3
+ "version": "3.38.20",
4
4
  "workspaces": [
5
5
  "v3/@claude-flow/codex",
6
6
  "v3/@claude-flow/plugin-agent-federation",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "generation": 5,
4
- "generatedAt": "2026-08-22T16:29:46.759Z",
5
- "gitSha": "127a6546",
4
+ "generatedAt": "2026-08-24T19:34:50.132Z",
5
+ "gitSha": "a0b39b9d",
6
6
  "catalog": {
7
7
  "agents": 165,
8
8
  "tools": 397,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.38.19",
3
+ "version": "3.38.20",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",