@monoes/monomindcli 1.10.5 → 1.10.7
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.
|
@@ -659,13 +659,31 @@ function getAgentDBStats() {
|
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
// Graphify knowledge graph stats
|
|
662
|
+
// Sources, in priority order:
|
|
663
|
+
// 1. .monomind/graph/stats.json — explicit cached stats
|
|
664
|
+
// 2. .monomind/monograph.db — live SQLite (read counts via sqlite3)
|
|
665
|
+
// 3. .monomind/graph/graph.json — legacy JSON dump
|
|
662
666
|
function getGraphifyStats() {
|
|
663
667
|
const statsPath = path.join(CWD, '.monomind', 'graph', 'stats.json');
|
|
668
|
+
const dbPath = path.join(CWD, '.monomind', 'monograph.db');
|
|
664
669
|
const graphPath = path.join(CWD, '.monomind', 'graph', 'graph.json');
|
|
670
|
+
|
|
665
671
|
try {
|
|
666
672
|
const s = readJSON(statsPath);
|
|
667
673
|
if (s && s.nodes !== undefined) return { nodes: s.nodes, edges: s.edges || 0, exists: true };
|
|
668
674
|
} catch { /* ignore */ }
|
|
675
|
+
|
|
676
|
+
// Live monograph.db — single SQLite call, strict 1s timeout
|
|
677
|
+
try {
|
|
678
|
+
if (fs.existsSync(dbPath)) {
|
|
679
|
+
const out = safeExec(`sqlite3 "${dbPath}" "SELECT (SELECT COUNT(*) FROM nodes), (SELECT COUNT(*) FROM edges);"`, 1000);
|
|
680
|
+
if (out) {
|
|
681
|
+
const [n, e] = out.split('|').map(v => parseInt(v, 10) || 0);
|
|
682
|
+
if (n > 0) return { nodes: n, edges: e, exists: true };
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
} catch { /* ignore */ }
|
|
686
|
+
|
|
669
687
|
try {
|
|
670
688
|
const stat = safeStat(graphPath);
|
|
671
689
|
if (stat && stat.size < 10 * 1024 * 1024) {
|
|
@@ -678,6 +696,78 @@ function getGraphifyStats() {
|
|
|
678
696
|
return { nodes: 0, edges: 0, exists: false };
|
|
679
697
|
}
|
|
680
698
|
|
|
699
|
+
// Graph freshness — compare graph build time against most recent commit
|
|
700
|
+
// Returns: { commitsBehind, stale } where stale = >5 commits or never built
|
|
701
|
+
function getGraphFreshness() {
|
|
702
|
+
const lockPath = path.join(CWD, '.monomind', 'graph', '.rebuild-lock');
|
|
703
|
+
const dbPath = path.join(CWD, '.monomind', 'monograph.db');
|
|
704
|
+
|
|
705
|
+
let buildMs = 0;
|
|
706
|
+
try {
|
|
707
|
+
const lockStat = safeStat(lockPath);
|
|
708
|
+
const dbStat = safeStat(dbPath);
|
|
709
|
+
buildMs = Math.max(lockStat?.mtimeMs || 0, dbStat?.mtimeMs || 0);
|
|
710
|
+
} catch { /* ignore */ }
|
|
711
|
+
if (!buildMs) return { commitsBehind: -1, stale: true, fresh: false };
|
|
712
|
+
|
|
713
|
+
// Count commits since the graph was last built
|
|
714
|
+
const buildIso = new Date(buildMs).toISOString();
|
|
715
|
+
const out = safeExec(`git rev-list --count --since='${buildIso}' HEAD 2>/dev/null`, 1500);
|
|
716
|
+
const commitsBehind = parseInt(out, 10) || 0;
|
|
717
|
+
return {
|
|
718
|
+
commitsBehind,
|
|
719
|
+
stale: commitsBehind > 5,
|
|
720
|
+
fresh: commitsBehind === 0,
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Active loops — scan .monomind/loops/*.json
|
|
725
|
+
// Filters: skip *-hil*.json, skip stale (>6h since lastRunAt)
|
|
726
|
+
function getLoopStatus() {
|
|
727
|
+
const loopsDir = path.join(CWD, '.monomind', 'loops');
|
|
728
|
+
if (!fs.existsSync(loopsDir)) return { count: 0, loops: [] };
|
|
729
|
+
const STALE_MS = 6 * 60 * 60 * 1000;
|
|
730
|
+
const now = Date.now();
|
|
731
|
+
let loops = [];
|
|
732
|
+
try {
|
|
733
|
+
const files = fs.readdirSync(loopsDir).filter(f =>
|
|
734
|
+
f.endsWith('.json') && !f.includes('-hil') && !f.endsWith('.stop'));
|
|
735
|
+
for (const f of files) {
|
|
736
|
+
const d = readJSON(path.join(loopsDir, f));
|
|
737
|
+
if (!d || !d.command) continue;
|
|
738
|
+
const last = d.lastRunAt || d.nextRunAt || d.startedAt || 0;
|
|
739
|
+
if (last && (now - last) > STALE_MS) continue;
|
|
740
|
+
loops.push({
|
|
741
|
+
cmd: d.command.replace(/^\//,''),
|
|
742
|
+
type: d.type || 'repeat',
|
|
743
|
+
rep: d.currentRep || 0,
|
|
744
|
+
max: d.maxReps || 0,
|
|
745
|
+
status: d.status || 'running',
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
} catch { /* ignore */ }
|
|
749
|
+
return { count: loops.length, loops };
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// HIL pending — count <id>-hil.md files with no human response yet
|
|
753
|
+
function getHILPending() {
|
|
754
|
+
const loopsDir = path.join(CWD, '.monomind', 'loops');
|
|
755
|
+
if (!fs.existsSync(loopsDir)) return { pending: 0 };
|
|
756
|
+
let pending = 0;
|
|
757
|
+
try {
|
|
758
|
+
const files = fs.readdirSync(loopsDir).filter(f => f.endsWith('-hil.md'));
|
|
759
|
+
for (const f of files) {
|
|
760
|
+
try {
|
|
761
|
+
const txt = fs.readFileSync(path.join(loopsDir, f), 'utf-8');
|
|
762
|
+
// A response is a line starting with "> " followed by non-whitespace
|
|
763
|
+
const answered = /^[ \t]*>[ \t]+\S/m.test(txt);
|
|
764
|
+
if (!answered) pending++;
|
|
765
|
+
} catch { /* ignore */ }
|
|
766
|
+
}
|
|
767
|
+
} catch { /* ignore */ }
|
|
768
|
+
return { pending };
|
|
769
|
+
}
|
|
770
|
+
|
|
681
771
|
// Memory Palace stats — drawers.jsonl + kg.json (the real persistent memory)
|
|
682
772
|
function getMemoryPalaceStats() {
|
|
683
773
|
const palaceDir = path.join(CWD, '.monomind', 'palace');
|
|
@@ -1112,158 +1202,68 @@ function generateDashboard() {
|
|
|
1112
1202
|
lines.push(hdr);
|
|
1113
1203
|
lines.push(SEP);
|
|
1114
1204
|
|
|
1115
|
-
// ── Row 1:
|
|
1116
|
-
|
|
1117
|
-
? `${x.teal}📚 ${x.bold}${knowledge.chunks}${x.reset}${x.slate} chunks${x.reset}`
|
|
1118
|
-
: `${x.slate}📚 no chunks${x.reset}`;
|
|
1119
|
-
|
|
1120
|
-
const skillStr = knowledge.skills > 0
|
|
1121
|
-
? ` ${x.mint}✦ ${knowledge.skills} skills${x.reset}`
|
|
1122
|
-
: '';
|
|
1123
|
-
|
|
1124
|
-
const patStr = progress.patternsLearned > 0
|
|
1125
|
-
? `${x.gold}${progress.patternsLearned >= 1000 ? (progress.patternsLearned / 1000).toFixed(1) + 'k' : progress.patternsLearned} patterns${x.reset}`
|
|
1126
|
-
: `${x.slate}0 patterns${x.reset}`;
|
|
1127
|
-
|
|
1128
|
-
const gf = getGraphifyStats();
|
|
1129
|
-
const gfStr = gf.exists
|
|
1130
|
-
? `${x.sky}🔗 ${x.bold}${gf.nodes}${x.reset}${x.slate} nodes · ${x.reset}${x.sky}${x.bold}${gf.edges}${x.reset}${x.slate} edges${x.reset}`
|
|
1131
|
-
: `${x.slate}🔗 no graph${x.reset}`;
|
|
1132
|
-
|
|
1133
|
-
lines.push(
|
|
1134
|
-
`${x.purple}💡 INTEL${x.reset} ` +
|
|
1135
|
-
`${knowStr}${skillStr} ${DIV} ` +
|
|
1136
|
-
`${patStr} ${DIV} ` +
|
|
1137
|
-
gfStr
|
|
1138
|
-
);
|
|
1139
|
-
lines.push(SEP);
|
|
1140
|
-
|
|
1141
|
-
// ── Row 2: Agents & Triggers ──────────────────────────────────
|
|
1142
|
-
const agentCol = swarm.activeAgents > 0 ? x.green : x.slate;
|
|
1143
|
-
const hookCol = hooks.enabled > 0 ? x.mint : x.slate;
|
|
1144
|
-
|
|
1145
|
-
// Triggers (Task 32)
|
|
1146
|
-
const trigStr = triggers.triggers > 0
|
|
1147
|
-
? `${x.mint}🎯 ${x.bold}${triggers.triggers}${x.reset}${x.slate} triggers · ${triggers.agents} agents${x.reset}`
|
|
1148
|
-
: `${x.slate}🎯 no triggers${x.reset}`;
|
|
1149
|
-
|
|
1150
|
-
// Active agent badge
|
|
1151
|
-
let agentBadge;
|
|
1205
|
+
// ── Row 1: Active agent + Loop status ────────────────────────
|
|
1206
|
+
let agentStr;
|
|
1152
1207
|
if (activeAgent) {
|
|
1153
1208
|
const isExtras = activeAgent.slug === 'extras' || activeAgent.name === 'Extras';
|
|
1154
1209
|
if (isExtras && activeAgent.extrasMatches && activeAgent.extrasMatches.length > 0) {
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const badgeParts = specialists.map(s => `${x.sky}👤 ${x.bold}${s.name}${x.reset}`);
|
|
1158
|
-
agentBadge = badgeParts.join(`${x.slate} ${x.reset}`);
|
|
1210
|
+
const specialists = activeAgent.extrasMatches.slice(0, 3).map(s => s.name).join(', ');
|
|
1211
|
+
agentStr = `${x.sky}👤 ${x.bold}${specialists}${x.reset}`;
|
|
1159
1212
|
} else if (isExtras) {
|
|
1160
|
-
|
|
1161
|
-
agentBadge = `${x.slate}👤 no agent routed${x.reset}`;
|
|
1213
|
+
agentStr = `${x.slate}👤 no agent routed${x.reset}`;
|
|
1162
1214
|
} else {
|
|
1163
1215
|
const col = activeAgent.activated ? x.green : x.sky;
|
|
1164
|
-
const mark = activeAgent.activated ?
|
|
1216
|
+
const mark = activeAgent.activated ? `${col}${x.bold}● ACTIVE${x.reset} ` : '';
|
|
1165
1217
|
const conf = activeAgent.activated ? '' : ` ${x.slate}${(activeAgent.confidence * 100).toFixed(0)}%${x.reset}`;
|
|
1166
|
-
|
|
1167
|
-
agentBadge = mark
|
|
1168
|
-
? `${col}${x.bold}${mark}${x.reset} ${col}👤 ${x.bold}${activeAgent.name}${x.reset}${cat}${conf}`
|
|
1169
|
-
: `${col}👤 ${x.bold}${activeAgent.name}${x.reset}${cat}${conf}`;
|
|
1218
|
+
agentStr = `${mark}${col}👤 ${x.bold}${activeAgent.name}${x.reset}${conf}`;
|
|
1170
1219
|
}
|
|
1171
1220
|
} else {
|
|
1172
|
-
|
|
1221
|
+
agentStr = `${x.slate}👤 no agent routed${x.reset}`;
|
|
1173
1222
|
}
|
|
1174
1223
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
)
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const cveStatus = security.totalCves === 0
|
|
1192
|
-
? (security.status === 'NONE' ? `${x.slate}not scanned${x.reset}` : `${x.green}✔ clean${x.reset}`)
|
|
1193
|
-
: `${x.coral}${security.cvesFixed}/${security.totalCves} fixed${x.reset}`;
|
|
1194
|
-
|
|
1195
|
-
lines.push(
|
|
1196
|
-
`${x.purple}🛡️ SECURITY${x.reset} ` +
|
|
1197
|
-
`${sec.col}${sec.label}${x.reset} ${DIV} ` +
|
|
1198
|
-
`CVE ${cveStatus}`
|
|
1199
|
-
);
|
|
1200
|
-
lines.push(SEP);
|
|
1201
|
-
|
|
1202
|
-
// ── Row 4: Memory & Tests ─────────────────────────────────────
|
|
1203
|
-
const testCol = tests.testFiles > 0 ? x.green : x.slate;
|
|
1204
|
-
const memCol = system.memoryMB > 200 ? x.orange : x.sky;
|
|
1205
|
-
|
|
1206
|
-
// Auto-memory files display
|
|
1207
|
-
const memFileCol = autoMem.count > 0 ? x.purple : x.slate;
|
|
1208
|
-
const memFileStr = autoMem.count > 0
|
|
1209
|
-
? `${memFileCol}${x.bold}${autoMem.count}${x.reset}${x.slate} memories${x.reset}`
|
|
1210
|
-
: `${x.slate}no memories${x.reset}`;
|
|
1211
|
-
const memTypeOrder = ['handoff', 'user', 'feedback', 'project', 'reference'];
|
|
1212
|
-
const typeColors = { user: x.sky, feedback: x.gold, project: x.teal, reference: x.violet, handoff: x.coral };
|
|
1213
|
-
const typeParts = memTypeOrder
|
|
1214
|
-
.filter(t => autoMem.byType[t] > 0)
|
|
1215
|
-
.map(t => `${typeColors[t] || x.slate}${autoMem.byType[t]}${t.slice(0,1)}${x.reset}`);
|
|
1216
|
-
const kgStr = typeParts.length > 0 ? ` ${typeParts.join(' ')}` : '';
|
|
1217
|
-
|
|
1218
|
-
// Total memory size (palace + agentdb)
|
|
1219
|
-
const totalSizeKB = agentdb.dbSizeKB + palace.palaceSizeKB;
|
|
1220
|
-
const sizeDisp = totalSizeKB >= 1024
|
|
1221
|
-
? `${(totalSizeKB / 1024).toFixed(1)} MB` : `${totalSizeKB} KB`;
|
|
1222
|
-
|
|
1223
|
-
// HNSW tag only meaningful if vectors exist
|
|
1224
|
-
const vecTotal = agentdb.vectorCount;
|
|
1225
|
-
const hnswTag = agentdb.hasHnsw ? ` ${x.green}⚡ HNSW${x.reset}` : '';
|
|
1226
|
-
|
|
1227
|
-
const chips = [];
|
|
1228
|
-
if (integration.mcpServers.total > 0) {
|
|
1229
|
-
const mc = integration.mcpServers.enabled === integration.mcpServers.total ? x.green
|
|
1230
|
-
: integration.mcpServers.enabled > 0 ? x.gold : x.coral;
|
|
1231
|
-
chips.push(`${mc}MCP ${integration.mcpServers.enabled}/${integration.mcpServers.total}${x.reset}`);
|
|
1224
|
+
const loopState = getLoopStatus();
|
|
1225
|
+
let loopStr;
|
|
1226
|
+
if (loopState.count > 0) {
|
|
1227
|
+
const parts = loopState.loops.slice(0, 2).map(l => {
|
|
1228
|
+
const status = l.status === 'hil:pending'
|
|
1229
|
+
? `${x.coral}⏳ HIL${x.reset}`
|
|
1230
|
+
: `${x.green}⟳${x.reset}`;
|
|
1231
|
+
const tag = l.type === 'tillend'
|
|
1232
|
+
? `${x.bold}${l.cmd}${x.reset}${x.slate} run ${l.rep}${x.reset}`
|
|
1233
|
+
: `${x.bold}${l.cmd}${x.reset}${x.slate} ${l.rep}/${l.max}${x.reset}`;
|
|
1234
|
+
return `${status} ${tag}`;
|
|
1235
|
+
});
|
|
1236
|
+
loopStr = `${x.gold}🔄${x.reset} ${parts.join(`${x.slate} · ${x.reset}`)}`;
|
|
1237
|
+
if (loopState.count > 2) loopStr += `${x.slate} +${loopState.count - 2} more${x.reset}`;
|
|
1238
|
+
} else {
|
|
1239
|
+
loopStr = `${x.slate}🔄 no active loops${x.reset}`;
|
|
1232
1240
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
const integStr = chips.length ? chips.join(' ') : `${x.slate}none${x.reset}`;
|
|
1236
|
-
|
|
1237
|
-
lines.push(
|
|
1238
|
-
`${x.teal}🗄️ MEMORY${x.reset} ` +
|
|
1239
|
-
`${memFileStr}${kgStr}${hnswTag} ${DIV} ` +
|
|
1240
|
-
`${x.white}${sizeDisp}${x.reset} ${DIV} ` +
|
|
1241
|
-
`${testCol}🧪 ${tests.testFiles} test files${x.reset} ${DIV} ` +
|
|
1242
|
-
integStr
|
|
1243
|
-
);
|
|
1241
|
+
|
|
1242
|
+
lines.push(`${x.purple}🤖 AGENT${x.reset} ${agentStr} ${DIV} ${loopStr}`);
|
|
1244
1243
|
lines.push(SEP);
|
|
1245
1244
|
|
|
1246
|
-
// ── Row
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1245
|
+
// ── Row 2: Graph freshness + Pending HIL ─────────────────────
|
|
1246
|
+
const gf = getGraphifyStats();
|
|
1247
|
+
const freshness = getGraphFreshness();
|
|
1248
|
+
let graphStr;
|
|
1249
|
+
if (gf.exists) {
|
|
1250
|
+
const nodesFmt = gf.nodes >= 1000 ? `${(gf.nodes / 1000).toFixed(0)}k` : `${gf.nodes}`;
|
|
1251
|
+
const freshTag = freshness.fresh
|
|
1252
|
+
? `${x.green}● fresh${x.reset}`
|
|
1253
|
+
: freshness.stale
|
|
1254
|
+
? `${x.coral}● ${freshness.commitsBehind} commits stale${x.reset}`
|
|
1255
|
+
: `${x.gold}● ${freshness.commitsBehind} behind${x.reset}`;
|
|
1256
|
+
graphStr = `${x.sky}🔗 ${x.bold}${nodesFmt}${x.reset}${x.slate} nodes${x.reset} ${freshTag}`;
|
|
1252
1257
|
} else {
|
|
1253
|
-
|
|
1258
|
+
graphStr = `${x.slate}🔗 no graph${x.reset}`;
|
|
1254
1259
|
}
|
|
1255
1260
|
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
lines.push(
|
|
1262
|
-
`${x.slate}📋 CONTEXT${x.reset} ` +
|
|
1263
|
-
`${siStr} ${DIV} ` +
|
|
1264
|
-
`${x.dim}💾 ${system.memoryMB} MB RAM${x.reset}` +
|
|
1265
|
-
monthStr
|
|
1266
|
-
);
|
|
1261
|
+
const hil = getHILPending();
|
|
1262
|
+
const hilStr = hil.pending > 0
|
|
1263
|
+
? `${x.coral}✨ ${x.bold}${hil.pending}${x.reset}${x.coral} HIL pending${x.reset}`
|
|
1264
|
+
: `${x.slate}✨ no pending HIL${x.reset}`;
|
|
1265
|
+
|
|
1266
|
+
lines.push(`${x.teal}🧠 CONTEXT${x.reset} ${graphStr} ${DIV} ${hilStr}`);
|
|
1267
1267
|
|
|
1268
1268
|
return lines.join('\n');
|
|
1269
1269
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusline-generator.d.ts","sourceRoot":"","sources":["../../../src/init/statusline-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"statusline-generator.d.ts","sourceRoot":"","sources":["../../../src/init/statusline-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAonCrE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CA8BnE"}
|
|
@@ -828,6 +828,105 @@ function getTriggerStats() {
|
|
|
828
828
|
} catch { return { triggers: 0, agents: 0 }; }
|
|
829
829
|
}
|
|
830
830
|
|
|
831
|
+
// Graph freshness — compare last build time vs commits since
|
|
832
|
+
function getGraphFreshness() {
|
|
833
|
+
const lockPath = path.join(CWD, '.monomind', 'graph', '.rebuild-lock');
|
|
834
|
+
const dbPath = path.join(CWD, '.monomind', 'monograph.db');
|
|
835
|
+
let buildMs = 0;
|
|
836
|
+
try {
|
|
837
|
+
const lockStat = safeStat(lockPath);
|
|
838
|
+
const dbStat = safeStat(dbPath);
|
|
839
|
+
buildMs = Math.max(lockStat?.mtimeMs || 0, dbStat?.mtimeMs || 0);
|
|
840
|
+
} catch { /* ignore */ }
|
|
841
|
+
if (!buildMs) return { commitsBehind: -1, stale: true, fresh: false };
|
|
842
|
+
const buildIso = new Date(buildMs).toISOString();
|
|
843
|
+
const out = safeExec(\`git rev-list --count --since='\${buildIso}' HEAD 2>/dev/null\`, 1500);
|
|
844
|
+
const commitsBehind = parseInt(out, 10) || 0;
|
|
845
|
+
return { commitsBehind, stale: commitsBehind > 5, fresh: commitsBehind === 0 };
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Active loops — scan .monomind/loops/*.json, skip stale (>6h)
|
|
849
|
+
function getLoopStatus() {
|
|
850
|
+
const loopsDir = path.join(CWD, '.monomind', 'loops');
|
|
851
|
+
if (!fs.existsSync(loopsDir)) return { count: 0, loops: [] };
|
|
852
|
+
const STALE_MS = 6 * 60 * 60 * 1000;
|
|
853
|
+
const now = Date.now();
|
|
854
|
+
const loops = [];
|
|
855
|
+
try {
|
|
856
|
+
const files = fs.readdirSync(loopsDir).filter(f =>
|
|
857
|
+
f.endsWith('.json') && !f.includes('-hil') && !f.endsWith('.stop'));
|
|
858
|
+
for (const f of files) {
|
|
859
|
+
const d = readJSON(path.join(loopsDir, f));
|
|
860
|
+
if (!d || !d.command) continue;
|
|
861
|
+
const last = d.lastRunAt || d.nextRunAt || d.startedAt || 0;
|
|
862
|
+
if (last && (now - last) > STALE_MS) continue;
|
|
863
|
+
loops.push({
|
|
864
|
+
cmd: String(d.command).replace(/^\\//,''),
|
|
865
|
+
type: d.type || 'repeat',
|
|
866
|
+
rep: d.currentRep || 0,
|
|
867
|
+
max: d.maxReps || 0,
|
|
868
|
+
status: d.status || 'running',
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
} catch { /* ignore */ }
|
|
872
|
+
return { count: loops.length, loops };
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// HIL pending — count <id>-hil.md files with no human response yet
|
|
876
|
+
function getHILPending() {
|
|
877
|
+
const loopsDir = path.join(CWD, '.monomind', 'loops');
|
|
878
|
+
if (!fs.existsSync(loopsDir)) return { pending: 0 };
|
|
879
|
+
let pending = 0;
|
|
880
|
+
try {
|
|
881
|
+
const files = fs.readdirSync(loopsDir).filter(f => f.endsWith('-hil.md'));
|
|
882
|
+
for (const f of files) {
|
|
883
|
+
try {
|
|
884
|
+
const txt = fs.readFileSync(path.join(loopsDir, f), 'utf-8');
|
|
885
|
+
const answered = /^[ \\t]*>[ \\t]+\\S/m.test(txt);
|
|
886
|
+
if (!answered) pending++;
|
|
887
|
+
} catch { /* ignore */ }
|
|
888
|
+
}
|
|
889
|
+
} catch { /* ignore */ }
|
|
890
|
+
return { pending };
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// Monograph knowledge graph stats
|
|
894
|
+
// Sources, in priority order:
|
|
895
|
+
// 1. .monomind/graph/stats.json — explicit cached stats
|
|
896
|
+
// 2. .monomind/monograph.db — live SQLite (read counts via sqlite3)
|
|
897
|
+
// 3. .monomind/graph/graph.json — legacy JSON dump
|
|
898
|
+
function getGraphifyStats() {
|
|
899
|
+
const statsPath = path.join(CWD, '.monomind', 'graph', 'stats.json');
|
|
900
|
+
const dbPath = path.join(CWD, '.monomind', 'monograph.db');
|
|
901
|
+
const graphPath = path.join(CWD, '.monomind', 'graph', 'graph.json');
|
|
902
|
+
|
|
903
|
+
try {
|
|
904
|
+
const s = readJSON(statsPath);
|
|
905
|
+
if (s && s.nodes !== undefined) return { nodes: s.nodes, edges: s.edges || 0, exists: true };
|
|
906
|
+
} catch { /* ignore */ }
|
|
907
|
+
|
|
908
|
+
try {
|
|
909
|
+
if (fs.existsSync(dbPath)) {
|
|
910
|
+
const out = safeExec(\`sqlite3 "\${dbPath}" "SELECT (SELECT COUNT(*) FROM nodes), (SELECT COUNT(*) FROM edges);"\`, 1000);
|
|
911
|
+
if (out) {
|
|
912
|
+
const [n, e] = out.split('|').map(v => parseInt(v, 10) || 0);
|
|
913
|
+
if (n > 0) return { nodes: n, edges: e, exists: true };
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
} catch { /* ignore */ }
|
|
917
|
+
|
|
918
|
+
try {
|
|
919
|
+
const stat = safeStat(graphPath);
|
|
920
|
+
if (stat && stat.size < 10 * 1024 * 1024) {
|
|
921
|
+
const g = JSON.parse(fs.readFileSync(graphPath, 'utf-8'));
|
|
922
|
+
const nodes = Array.isArray(g.nodes) ? g.nodes.length : 0;
|
|
923
|
+
const edges = (Array.isArray(g.edges) ? g.edges : (Array.isArray(g.links) ? g.links : [])).length;
|
|
924
|
+
return { nodes, edges, exists: true };
|
|
925
|
+
}
|
|
926
|
+
} catch { /* ignore */ }
|
|
927
|
+
return { nodes: 0, edges: 0, exists: false };
|
|
928
|
+
}
|
|
929
|
+
|
|
831
930
|
function getSIBudget() {
|
|
832
931
|
const SI_LIMIT = 1500;
|
|
833
932
|
const siPath = path.join(CWD, '.agents', 'shared_instructions.md');
|
|
@@ -942,137 +1041,60 @@ function generateDashboard() {
|
|
|
942
1041
|
lines.push(hdr);
|
|
943
1042
|
lines.push(SEP);
|
|
944
1043
|
|
|
945
|
-
// ── Row 1:
|
|
946
|
-
|
|
947
|
-
const intellBar = blockBar(system.intelligencePct, 100, 6);
|
|
948
|
-
|
|
949
|
-
// Knowledge (Task 28)
|
|
950
|
-
const knowStr = knowledge.chunks > 0
|
|
951
|
-
? \`\${x.teal}📚 \${x.bold}\${knowledge.chunks}\${x.reset}\${x.slate} chunks\${x.reset}\`
|
|
952
|
-
: \`\${x.slate}📚 no chunks\${x.reset}\`;
|
|
953
|
-
|
|
954
|
-
// Skills (Task 45)
|
|
955
|
-
const skillStr = knowledge.skills > 0
|
|
956
|
-
? \` \${x.mint}✦ \${knowledge.skills} skills\${x.reset}\`
|
|
957
|
-
: '';
|
|
958
|
-
|
|
959
|
-
// Patterns
|
|
960
|
-
const patStr = progress.patternsLearned > 0
|
|
961
|
-
? \`\${x.gold}\${progress.patternsLearned >= 1000 ? (progress.patternsLearned / 1000).toFixed(1) + 'k' : progress.patternsLearned} patterns\${x.reset}\`
|
|
962
|
-
: \`\${x.slate}0 patterns\${x.reset}\`;
|
|
963
|
-
|
|
964
|
-
lines.push(
|
|
965
|
-
\`\${x.purple}💡 INTEL\${x.reset} \` +
|
|
966
|
-
\`\${intellCol}\${intellBar} \${x.bold}\${system.intelligencePct}%\${x.reset} \${DIV} \` +
|
|
967
|
-
\`\${knowStr}\${skillStr} \${DIV} \` +
|
|
968
|
-
patStr
|
|
969
|
-
);
|
|
970
|
-
lines.push(SEP);
|
|
971
|
-
|
|
972
|
-
// ── Row 2: Agents & Triggers ──────────────────────────────────
|
|
973
|
-
const agentCol = swarm.activeAgents > 0 ? x.green : x.slate;
|
|
974
|
-
const hookCol = hooks.enabled > 0 ? x.mint : x.slate;
|
|
975
|
-
|
|
976
|
-
// Triggers (Task 32)
|
|
977
|
-
const trigStr = triggers.triggers > 0
|
|
978
|
-
? \`\${x.mint}🎯 \${x.bold}\${triggers.triggers}\${x.reset}\${x.slate} triggers · \${triggers.agents} agents\${x.reset}\`
|
|
979
|
-
: \`\${x.slate}🎯 no triggers\${x.reset}\`;
|
|
980
|
-
|
|
981
|
-
// Active agent badge
|
|
982
|
-
let agentBadge;
|
|
1044
|
+
// ── Row 1: Active agent + Loop status ────────────────────────
|
|
1045
|
+
let agentStr;
|
|
983
1046
|
if (activeAgent) {
|
|
984
1047
|
const col = activeAgent.activated ? x.green : x.sky;
|
|
985
|
-
const mark = activeAgent.activated ?
|
|
1048
|
+
const mark = activeAgent.activated ? \`\${col}\${x.bold}● ACTIVE\${x.reset} \` : '';
|
|
986
1049
|
const conf = activeAgent.activated ? '' : \` \${x.slate}\${(activeAgent.confidence * 100).toFixed(0)}%\${x.reset}\`;
|
|
987
|
-
|
|
988
|
-
agentBadge = \`\${col}\${x.bold}\${mark}\${x.reset} \${col}👤 \${x.bold}\${activeAgent.name}\${x.reset}\${cat}\${conf}\`;
|
|
1050
|
+
agentStr = \`\${mark}\${col}👤 \${x.bold}\${activeAgent.name}\${x.reset}\${conf}\`;
|
|
989
1051
|
} else {
|
|
990
|
-
|
|
1052
|
+
agentStr = \`\${x.slate}👤 no agent routed\${x.reset}\`;
|
|
991
1053
|
}
|
|
992
1054
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
const dddCol = pctColor(progress.dddProgress);
|
|
1011
|
-
const dddBar = blockBar(progress.dddProgress, 100, 5);
|
|
1012
|
-
|
|
1013
|
-
const cveStatus = security.totalCves === 0
|
|
1014
|
-
? (security.status === 'NONE' ? \`\${x.slate}not scanned\${x.reset}\` : \`\${x.green}✔ clean\${x.reset}\`)
|
|
1015
|
-
: \`\${x.coral}\${security.cvesFixed}/\${security.totalCves} fixed\${x.reset}\`;
|
|
1016
|
-
|
|
1017
|
-
lines.push(
|
|
1018
|
-
\`\${x.purple}🧩 ARCH\${x.reset} \` +
|
|
1019
|
-
\`\${adrStr} \${DIV} \` +
|
|
1020
|
-
\`DDD \${dddBar} \${dddCol}\${x.bold}\${progress.dddProgress}%\${x.reset} \${DIV} \` +
|
|
1021
|
-
\`🛡️ \${sec.col}\${sec.label}\${x.reset} \${DIV} \` +
|
|
1022
|
-
\`CVE \${cveStatus}\`
|
|
1023
|
-
);
|
|
1024
|
-
lines.push(SEP);
|
|
1025
|
-
|
|
1026
|
-
// ── Row 4: Memory & Tests ─────────────────────────────────────
|
|
1027
|
-
const vecCol = agentdb.vectorCount > 0 ? x.green : x.slate;
|
|
1028
|
-
const hnswTag = agentdb.hasHnsw && agentdb.vectorCount > 0 ? \` \${x.green}⚡ HNSW\${x.reset}\` : '';
|
|
1029
|
-
const sizeDisp = agentdb.dbSizeKB >= 1024
|
|
1030
|
-
? \`\${(agentdb.dbSizeKB / 1024).toFixed(1)} MB\` : \`\${agentdb.dbSizeKB} KB\`;
|
|
1031
|
-
const testCol = tests.testFiles > 0 ? x.green : x.slate;
|
|
1032
|
-
const memCol = system.memoryMB > 200 ? x.orange : x.sky;
|
|
1033
|
-
|
|
1034
|
-
const chips = [];
|
|
1035
|
-
if (integration.mcpServers.total > 0) {
|
|
1036
|
-
const mc = integration.mcpServers.enabled === integration.mcpServers.total ? x.green
|
|
1037
|
-
: integration.mcpServers.enabled > 0 ? x.gold : x.coral;
|
|
1038
|
-
chips.push(\`\${mc}MCP \${integration.mcpServers.enabled}/\${integration.mcpServers.total}\${x.reset}\`);
|
|
1055
|
+
const loopState = getLoopStatus();
|
|
1056
|
+
let loopStr;
|
|
1057
|
+
if (loopState.count > 0) {
|
|
1058
|
+
const parts = loopState.loops.slice(0, 2).map(l => {
|
|
1059
|
+
const status = l.status === 'hil:pending'
|
|
1060
|
+
? \`\${x.coral}⏳ HIL\${x.reset}\`
|
|
1061
|
+
: \`\${x.green}⟳\${x.reset}\`;
|
|
1062
|
+
const tag = l.type === 'tillend'
|
|
1063
|
+
? \`\${x.bold}\${l.cmd}\${x.reset}\${x.slate} run \${l.rep}\${x.reset}\`
|
|
1064
|
+
: \`\${x.bold}\${l.cmd}\${x.reset}\${x.slate} \${l.rep}/\${l.max}\${x.reset}\`;
|
|
1065
|
+
return \`\${status} \${tag}\`;
|
|
1066
|
+
});
|
|
1067
|
+
loopStr = \`\${x.gold}🔄\${x.reset} \${parts.join(\`\${x.slate} · \${x.reset}\`)}\`;
|
|
1068
|
+
if (loopState.count > 2) loopStr += \`\${x.slate} +\${loopState.count - 2} more\${x.reset}\`;
|
|
1069
|
+
} else {
|
|
1070
|
+
loopStr = \`\${x.slate}🔄 no active loops\${x.reset}\`;
|
|
1039
1071
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
const integStr = chips.length ? chips.join(' ') : \`\${x.slate}none\${x.reset}\`;
|
|
1043
|
-
|
|
1044
|
-
lines.push(
|
|
1045
|
-
\`\${x.teal}🗄️ MEMORY\${x.reset} \` +
|
|
1046
|
-
\`\${vecCol}\${x.bold}\${agentdb.vectorCount}\${x.reset}\${x.slate} vectors\${x.reset}\${hnswTag} \${DIV} \` +
|
|
1047
|
-
\`\${x.white}\${sizeDisp}\${x.reset} \${DIV} \` +
|
|
1048
|
-
\`\${testCol}🧪 \${tests.testFiles} test files\${x.reset} \${DIV} \` +
|
|
1049
|
-
integStr
|
|
1050
|
-
);
|
|
1072
|
+
|
|
1073
|
+
lines.push(\`\${x.purple}🤖 AGENT\${x.reset} \${agentStr} \${DIV} \${loopStr}\`);
|
|
1051
1074
|
lines.push(SEP);
|
|
1052
1075
|
|
|
1053
|
-
// ── Row
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1076
|
+
// ── Row 2: Graph freshness + Pending HIL ─────────────────────
|
|
1077
|
+
const gf = getGraphifyStats();
|
|
1078
|
+
const freshness = getGraphFreshness();
|
|
1079
|
+
let graphStr;
|
|
1080
|
+
if (gf.exists) {
|
|
1081
|
+
const nodesFmt = gf.nodes >= 1000 ? \`\${(gf.nodes / 1000).toFixed(0)}k\` : \`\${gf.nodes}\`;
|
|
1082
|
+
const freshTag = freshness.fresh
|
|
1083
|
+
? \`\${x.green}● fresh\${x.reset}\`
|
|
1084
|
+
: freshness.stale
|
|
1085
|
+
? \`\${x.coral}● \${freshness.commitsBehind} commits stale\${x.reset}\`
|
|
1086
|
+
: \`\${x.gold}● \${freshness.commitsBehind} behind\${x.reset}\`;
|
|
1087
|
+
graphStr = \`\${x.sky}🔗 \${x.bold}\${nodesFmt}\${x.reset}\${x.slate} nodes\${x.reset} \${freshTag}\`;
|
|
1059
1088
|
} else {
|
|
1060
|
-
|
|
1089
|
+
graphStr = \`\${x.slate}🔗 no graph\${x.reset}\`;
|
|
1061
1090
|
}
|
|
1062
1091
|
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
lines.push(
|
|
1071
|
-
\`\${x.slate}📋 CONTEXT\${x.reset} \` +
|
|
1072
|
-
\`\${siStr} \${DIV} \` +
|
|
1073
|
-
\`\${x.teal}🏗 \${domBar} \${domCol}\${x.bold}\${progress.domainsCompleted}\${x.reset}\${x.slate}/\${x.reset}\${x.white}\${progress.totalDomains}\${x.reset} domains \${DIV} \` +
|
|
1074
|
-
\`\${x.dim}💾 \${system.memoryMB} MB RAM\${x.reset}\`
|
|
1075
|
-
);
|
|
1092
|
+
const hil = getHILPending();
|
|
1093
|
+
const hilStr = hil.pending > 0
|
|
1094
|
+
? \`\${x.coral}✨ \${x.bold}\${hil.pending}\${x.reset}\${x.coral} HIL pending\${x.reset}\`
|
|
1095
|
+
: \`\${x.slate}✨ no pending HIL\${x.reset}\`;
|
|
1096
|
+
|
|
1097
|
+
lines.push(\`\${x.teal}🧠 CONTEXT\${x.reset} \${graphStr} \${DIV} \${hilStr}\`);
|
|
1076
1098
|
|
|
1077
1099
|
return lines.join('\\n');
|
|
1078
1100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusline-generator.js","sourceRoot":"","sources":["../../../src/init/statusline-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAoB;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;eAuBM,SAAS
|
|
1
|
+
{"version":3,"file":"statusline-generator.js","sourceRoot":"","sources":["../../../src/init/statusline-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAoB;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;eAuBM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0lCvB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IACzD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QAChC,OAAO,sCAAsC,CAAC;IAChD,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;CAwBR,CAAC;AACF,CAAC"}
|