@monoes/monomindcli 1.12.0 → 1.14.0

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.
Files changed (61) hide show
  1. package/.claude/agents/generated/churn-analyst.md +53 -0
  2. package/.claude/agents/generated/code-reviewer.md +55 -0
  3. package/.claude/agents/generated/code-validator.md +57 -0
  4. package/.claude/agents/generated/complexity-scanner.md +56 -0
  5. package/.claude/agents/generated/devbot-orchestrator.md +58 -0
  6. package/.claude/agents/generated/devbot-planner.md +63 -0
  7. package/.claude/agents/generated/impact-assessor.md +54 -0
  8. package/.claude/commands/mastermind/master.md +88 -24
  9. package/.claude/helpers/control-start.cjs +60 -1
  10. package/.claude/helpers/event-logger.cjs +43 -2
  11. package/.claude/helpers/handlers/capture-handler.cjs +336 -0
  12. package/.claude/helpers/handlers/route-handler.cjs +20 -13
  13. package/.claude/helpers/handlers/session-restore-handler.cjs +14 -8
  14. package/.claude/helpers/hook-handler.cjs +57 -1
  15. package/.claude/helpers/intelligence.cjs +129 -57
  16. package/.claude/helpers/memory-palace.cjs +461 -0
  17. package/.claude/helpers/memory.cjs +134 -15
  18. package/.claude/helpers/metrics-db.mjs +87 -0
  19. package/.claude/helpers/router.cjs +296 -41
  20. package/.claude/helpers/session.cjs +107 -32
  21. package/.claude/helpers/statusline.cjs +138 -2
  22. package/.claude/helpers/toggle-statusline.cjs +73 -0
  23. package/.claude/helpers/token-tracker.cjs +934 -0
  24. package/.claude/helpers/utils/monograph.cjs +39 -4
  25. package/.claude/helpers/utils/telemetry.cjs +3 -3
  26. package/.claude/skills/mastermind/createorg.md +227 -16
  27. package/.claude/skills/mastermind/idea.md +15 -3
  28. package/.claude/skills/mastermind/runorg.md +2 -1
  29. package/dist/src/commands/doctor.d.ts.map +1 -1
  30. package/dist/src/commands/doctor.js +96 -4
  31. package/dist/src/commands/doctor.js.map +1 -1
  32. package/dist/src/commands/index.js +2 -0
  33. package/dist/src/commands/org.d.ts +4 -0
  34. package/dist/src/commands/org.d.ts.map +1 -0
  35. package/dist/src/commands/org.js +93 -0
  36. package/dist/src/commands/org.js.map +1 -0
  37. package/dist/src/mcp-tools/memory-tools.js +6 -6
  38. package/dist/src/mcp-tools/memory-tools.js.map +1 -1
  39. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  40. package/dist/src/mcp-tools/monograph-tools.js +329 -37
  41. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  42. package/dist/src/mcp-tools/session-tools.d.ts.map +1 -1
  43. package/dist/src/mcp-tools/session-tools.js +9 -10
  44. package/dist/src/mcp-tools/session-tools.js.map +1 -1
  45. package/dist/src/mcp-tools/task-tools.d.ts.map +1 -1
  46. package/dist/src/mcp-tools/task-tools.js +7 -8
  47. package/dist/src/mcp-tools/task-tools.js.map +1 -1
  48. package/dist/src/mcp-tools/types.d.ts +1 -0
  49. package/dist/src/mcp-tools/types.d.ts.map +1 -1
  50. package/dist/src/mcp-tools/types.js +49 -0
  51. package/dist/src/mcp-tools/types.js.map +1 -1
  52. package/dist/src/services/worker-daemon.d.ts.map +1 -1
  53. package/dist/src/services/worker-daemon.js +295 -5
  54. package/dist/src/services/worker-daemon.js.map +1 -1
  55. package/dist/src/transfer/serialization/cfp.js +1 -1
  56. package/dist/src/transfer/serialization/cfp.js.map +1 -1
  57. package/dist/src/ui/dashboard.html +2235 -178
  58. package/dist/src/ui/orgs.html +1 -0
  59. package/dist/src/ui/server.mjs +532 -133
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +1 -1
@@ -907,6 +907,60 @@ function getHILPending() {
907
907
  return { pending };
908
908
  }
909
909
 
910
+ // Active org runs — scan .monomind/orgs/*/runs/*.jsonl for recent activity
911
+ // Also checks .git/monomind/orgs/ (git-safe path used by mastermind orgs).
912
+ // An org is "active" if it has an events file modified within the last 10 minutes.
913
+ function getActiveOrgs() {
914
+ // Try git-common-dir path first (mastermind orgs store run files there)
915
+ let orgsDir = path.join(CWD, '.monomind', 'orgs');
916
+ try {
917
+ const gitCommon = safeExec('git rev-parse --git-common-dir 2>/dev/null', 1000);
918
+ if (gitCommon) {
919
+ const candidate = path.isAbsolute(gitCommon)
920
+ ? path.join(gitCommon, 'monomind', 'orgs')
921
+ : path.join(CWD, gitCommon, 'monomind', 'orgs');
922
+ if (fs.existsSync(candidate)) orgsDir = candidate;
923
+ }
924
+ } catch { /* use default */ }
925
+ if (!fs.existsSync(orgsDir)) return { count: 0, orgs: [] };
926
+ const STALE_MS = 10 * 60 * 1000; // 10 min
927
+ const now = Date.now();
928
+ const active = [];
929
+ try {
930
+ const orgNames = fs.readdirSync(orgsDir).filter(f => !f.startsWith('.'));
931
+ for (const orgName of orgNames.slice(0, 20)) {
932
+ const runsDir = path.join(orgsDir, orgName, 'runs');
933
+ if (!fs.existsSync(runsDir)) continue;
934
+ try {
935
+ const files = fs.readdirSync(runsDir).filter(f => f.endsWith('.jsonl'));
936
+ if (!files.length) continue;
937
+ files.sort();
938
+ const latest = files[files.length - 1];
939
+ const stat = safeStat(path.join(runsDir, latest));
940
+ if (!stat) continue;
941
+ const age = now - stat.mtimeMs;
942
+ if (age < STALE_MS) {
943
+ // Check last event type to determine if still running
944
+ let isRunning = true;
945
+ try {
946
+ const MAX_RUN = 512 * 1024; // 512 KiB
947
+ if (stat.size <= MAX_RUN) {
948
+ const raw = fs.readFileSync(path.join(runsDir, latest), 'utf-8');
949
+ const lines = raw.trim().split('\n').filter(Boolean);
950
+ if (lines.length) {
951
+ const lastEv = JSON.parse(lines[lines.length - 1]);
952
+ if (lastEv.type === 'run:complete' || lastEv.type === 'org:complete') isRunning = false;
953
+ }
954
+ }
955
+ } catch { /* treat as running */ }
956
+ active.push({ name: orgName, runId: latest.replace('.jsonl', ''), ageMs: age, running: isRunning });
957
+ }
958
+ } catch { /* skip */ }
959
+ }
960
+ } catch { /* ignore */ }
961
+ return { count: active.length, orgs: active };
962
+ }
963
+
910
964
  // Monograph knowledge graph stats
911
965
  // Sources, in priority order:
912
966
  // 1. .monomind/graph/stats.json — explicit cached stats
@@ -960,6 +1014,36 @@ function getSIBudget() {
960
1014
  } catch { return null; }
961
1015
  }
962
1016
 
1017
+ // Token cost summary — reads cached .monomind/metrics/token-summary.json (no JSONL scanning).
1018
+ // Returns null if file absent, stale (cachedAt is not today in UTC), or cost is zero.
1019
+ // All costs are aggregated across ALL Claude Code projects, not just this repo.
1020
+ function getTokenCostSummary() {
1021
+ const summaryPath = path.join(CWD, '.monomind', 'metrics', 'token-summary.json');
1022
+ const d = readJSON(summaryPath);
1023
+ if (!d) return null;
1024
+
1025
+ // Staleness guard: only show "today" figures when cachedAt is today (UTC)
1026
+ const todayUtc = new Date().toISOString().slice(0, 10); // "YYYY-MM-DD"
1027
+ const cachedDate = (d.cachedAt || '').slice(0, 10);
1028
+ const isFresh = cachedDate === todayUtc;
1029
+
1030
+ const todayCost = isFresh ? (d.todayCost || 0) : 0;
1031
+ const monthCost = d.monthCost || 0;
1032
+ const todayCalls = isFresh ? (d.todayCalls || 0) : 0;
1033
+
1034
+ if (monthCost === 0 && todayCost === 0) return null;
1035
+
1036
+ return { todayCost, monthCost, todayCalls, isFresh };
1037
+ }
1038
+
1039
+ // Format a dollar amount compactly: $0.0023, $1.23, $228.87
1040
+ function fmtCost(n) {
1041
+ if (n >= 100) return '$' + n.toFixed(0);
1042
+ if (n >= 1) return '$' + n.toFixed(2);
1043
+ if (n >= 0.01) return '$' + n.toFixed(3);
1044
+ return '$' + n.toFixed(4);
1045
+ }
1046
+
963
1047
  // ── Single-line statusline (compact) ─────────────────────────────
964
1048
  function generateStatusline() {
965
1049
  const git = getGitInfo();
@@ -995,9 +1079,24 @@ function generateStatusline() {
995
1079
  parts.push(`${col}${icon} ${x.bold}${activeAgent.name}${x.reset}`);
996
1080
  }
997
1081
 
998
- // Intelligence
1082
+ // Active org runs — high signal for users tracking autonomous orgs
1083
+ const orgStatus = getActiveOrgs();
1084
+ if (orgStatus.count > 0) {
1085
+ const runningOrgs = orgStatus.orgs.filter(o => o.running);
1086
+ const doneOrgs = orgStatus.orgs.filter(o => !o.running);
1087
+ if (runningOrgs.length > 0) {
1088
+ const names = runningOrgs.slice(0, 2).map(o => o.name).join(', ');
1089
+ parts.push(`${x.green}🏛 ${x.bold}${names}${x.reset}${runningOrgs.length > 2 ? ` +${runningOrgs.length - 2}` : ''}`);
1090
+ } else if (doneOrgs.length > 0) {
1091
+ parts.push(`${x.slate}🏛 ${doneOrgs[0].name} done${x.reset}`);
1092
+ }
1093
+ }
1094
+
1095
+ // Intelligence — only show when non-trivial (>15%) to avoid misleading 0%/noise
999
1096
  const ic = pctColor(system.intelligencePct);
1000
- parts.push(`${ic}💡 ${system.intelligencePct}%${x.reset}`);
1097
+ if (system.intelligencePct > 15) {
1098
+ parts.push(`${ic}💡 ${system.intelligencePct}%${x.reset}`);
1099
+ }
1001
1100
 
1002
1101
  // Knowledge chunks (Task 28) — show when populated
1003
1102
  if (knowledge.chunks > 0) {
@@ -1019,6 +1118,17 @@ function generateStatusline() {
1019
1118
  parts.push(`${x.mint}⚡ ${hooks.enabled}h${x.reset}`);
1020
1119
  }
1021
1120
 
1121
+ // Token cost — today's spend across all projects (from cached summary)
1122
+ const tokenCost = getTokenCostSummary();
1123
+ if (tokenCost) {
1124
+ if (tokenCost.isFresh && tokenCost.todayCost > 0) {
1125
+ const col = tokenCost.todayCost > 50 ? x.coral : tokenCost.todayCost > 10 ? x.gold : x.mint;
1126
+ parts.push(`${col}${fmtCost(tokenCost.todayCost)} today${x.reset}`);
1127
+ } else if (tokenCost.monthCost > 0) {
1128
+ parts.push(`${x.slate}${fmtCost(tokenCost.monthCost)} mo${x.reset}`);
1129
+ }
1130
+ }
1131
+
1022
1132
  return parts.join(` ${DIV} `);
1023
1133
  }
1024
1134
 
@@ -1061,6 +1171,17 @@ function generateDashboard() {
1061
1171
  hdr += ` ${DIV} 🤖 ${x.violet}${x.bold}${modelName}${x.reset}`;
1062
1172
  if (session.duration) hdr += ` ${x.dim}⏱ ${session.duration}${x.reset}`;
1063
1173
 
1174
+ // Token cost in dashboard header — today's spend (all projects)
1175
+ const tokenCost = getTokenCostSummary();
1176
+ if (tokenCost) {
1177
+ if (tokenCost.isFresh && tokenCost.todayCost > 0) {
1178
+ const col = tokenCost.todayCost > 50 ? x.coral : tokenCost.todayCost > 10 ? x.gold : x.mint;
1179
+ hdr += ` ${DIV} ${col}${fmtCost(tokenCost.todayCost)} today${x.reset}${x.dim} · ${fmtCost(tokenCost.monthCost)} mo${x.reset}`;
1180
+ } else if (tokenCost.monthCost > 0) {
1181
+ hdr += ` ${DIV} ${x.slate}${fmtCost(tokenCost.monthCost)} mo${x.reset}`;
1182
+ }
1183
+ }
1184
+
1064
1185
  lines.push(hdr);
1065
1186
  lines.push(SEP);
1066
1187
 
@@ -1139,6 +1260,20 @@ function generateDashboard() {
1139
1260
 
1140
1261
  lines.push(`${x.teal}🧠 CONTEXT${x.reset} ${graphStr} ${DIV} ${hilStr}`);
1141
1262
 
1263
+ // ── Row 3: Active org runs ───────────────────────────────────
1264
+ const orgStatus = getActiveOrgs();
1265
+ if (orgStatus.count > 0) {
1266
+ lines.push(SEP);
1267
+ const orgParts = orgStatus.orgs.slice(0, 5).map(o => {
1268
+ const ageMin = Math.floor(o.ageMs / 60000);
1269
+ const ageFmt = ageMin < 1 ? 'just now' : ageMin < 60 ? `${ageMin}m ago` : `${Math.floor(ageMin / 60)}h ago`;
1270
+ const col = o.running ? x.green : x.slate;
1271
+ const dot2 = o.running ? `${x.green}●${x.reset}` : `${x.slate}◌${x.reset}`;
1272
+ return `${dot2} ${col}${x.bold}${o.name}${x.reset} ${x.dim}${ageFmt}${x.reset}`;
1273
+ });
1274
+ lines.push(`${x.purple}🏛 ORGS${x.reset} ${orgParts.join(` ${DIV} `)}`);
1275
+ }
1276
+
1142
1277
  return lines.join('\n');
1143
1278
  }
1144
1279
 
@@ -1156,6 +1291,7 @@ function generateJSON() {
1156
1291
  agentdb: getAgentDBStats(),
1157
1292
  tests: getTestStats(),
1158
1293
  git: { modified: git.modified, untracked: git.untracked, staged: git.staged, ahead: git.ahead, behind: git.behind },
1294
+ tokenCost: getTokenCostSummary(),
1159
1295
  lastUpdated: new Date().toISOString(),
1160
1296
  };
1161
1297
  }
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ /**
4
+ * toggle-statusline.cjs — Toggle or set the monomind statusline display mode.
5
+ *
6
+ * Modes: full | compact
7
+ * Storage: $CLAUDE_PROJECT_DIR/.monomind/statusline-mode.txt
8
+ *
9
+ * Usage:
10
+ * node toggle-statusline.cjs # toggle current mode
11
+ * node toggle-statusline.cjs --get # print current mode
12
+ * node toggle-statusline.cjs --set <mode> # set mode (full|compact)
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ const CWD = process.env.CLAUDE_PROJECT_DIR || process.cwd();
19
+ const MODE_FILE = path.join(CWD, '.monomind', 'statusline-mode.txt');
20
+ const VALID_MODES = ['full', 'compact'];
21
+
22
+ function ensureDir() {
23
+ try { fs.mkdirSync(path.dirname(MODE_FILE), { recursive: true }); } catch (_) {}
24
+ }
25
+
26
+ function readMode() {
27
+ try {
28
+ if (!fs.existsSync(MODE_FILE)) return 'full';
29
+ var val = fs.readFileSync(MODE_FILE, 'utf-8').trim();
30
+ return VALID_MODES.includes(val) ? val : 'full';
31
+ } catch (_) {
32
+ return 'full';
33
+ }
34
+ }
35
+
36
+ function writeMode(mode) {
37
+ ensureDir();
38
+ fs.writeFileSync(MODE_FILE, mode, 'utf-8');
39
+ }
40
+
41
+ function printUsage() {
42
+ process.stderr.write(
43
+ 'Usage: toggle-statusline.cjs [--get | --set <full|compact>]\n' +
44
+ ' (no args) toggle between full and compact\n' +
45
+ ' --get print current mode\n' +
46
+ ' --set <mode> set mode to full or compact\n'
47
+ );
48
+ }
49
+
50
+ var args = process.argv.slice(2);
51
+
52
+ if (args[0] === '--get') {
53
+ process.stdout.write(readMode() + '\n');
54
+ process.exit(0);
55
+ }
56
+
57
+ if (args[0] === '--set') {
58
+ var newMode = args[1];
59
+ if (!newMode || !VALID_MODES.includes(newMode)) {
60
+ printUsage();
61
+ process.exit(1);
62
+ }
63
+ writeMode(newMode);
64
+ process.stdout.write('statusline mode → ' + newMode + '\n');
65
+ process.exit(0);
66
+ }
67
+
68
+ // No args: toggle
69
+ var current = readMode();
70
+ var toggled = current === 'full' ? 'compact' : 'full';
71
+ writeMode(toggled);
72
+ process.stdout.write('statusline mode → ' + toggled + ' (was: ' + current + ')\n');
73
+ process.exit(0);