@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
@@ -99,17 +99,33 @@ const [,, command, ...args] = process.argv;
99
99
  // Read stdin — Claude Code sends hook data as JSON via stdin
100
100
  // Uses a timeout to prevent hanging when stdin is in an ambiguous state
101
101
  // (not TTY, not a proper pipe) which happens with Claude Code hook invocations.
102
+ // Hard cap at 1 MiB: a legitimate hook payload (tool name + input) is at most
103
+ // a few KB; anything larger is either a bug or an adversarial OOM attempt.
104
+ const MAX_STDIN_BYTES = 1 * 1024 * 1024; // 1 MiB
102
105
  async function readStdin() {
103
106
  if (process.stdin.isTTY) return '';
104
107
  return new Promise((resolve) => {
105
108
  let data = '';
109
+ let byteCount = 0;
110
+ let truncated = false;
106
111
  const timer = setTimeout(() => {
107
112
  process.stdin.removeAllListeners();
108
113
  process.stdin.pause();
109
114
  resolve(data);
110
115
  }, 500);
111
116
  process.stdin.setEncoding('utf8');
112
- process.stdin.on('data', (chunk) => { data += chunk; });
117
+ process.stdin.on('data', (chunk) => {
118
+ if (truncated) return;
119
+ byteCount += Buffer.byteLength(chunk, 'utf8');
120
+ if (byteCount > MAX_STDIN_BYTES) {
121
+ truncated = true;
122
+ process.stdin.pause();
123
+ clearTimeout(timer);
124
+ resolve(''); // discard oversized input to prevent OOM
125
+ return;
126
+ }
127
+ data += chunk;
128
+ });
113
129
  process.stdin.on('end', () => { clearTimeout(timer); resolve(data); });
114
130
  process.stdin.on('error', () => { clearTimeout(timer); resolve(data); });
115
131
  process.stdin.resume();
@@ -288,6 +304,46 @@ const handlers = {
288
304
  var tool = hCtx.toolName || '';
289
305
  if (tool === 'Grep') _recordGraphTelemetry('grep_call');
290
306
  else if (tool === 'Glob') _recordGraphTelemetry('glob_call');
307
+
308
+ // Monograph symbol hint: when the Grep pattern looks like a plain symbol name
309
+ // (no regex metacharacters), look it up directly in the graph index and print
310
+ // the file:line so the LLM may skip or narrow the Grep.
311
+ // Session-level cache prevents repeated identical DB lookups across Grep bursts.
312
+ try {
313
+ var grepPattern = (typeof toolInput === 'object' && toolInput !== null)
314
+ ? (toolInput.pattern || toolInput.query || '')
315
+ : '';
316
+ // Only attempt lookup for clean identifiers — skip regexes and paths
317
+ var isCleanSymbol = grepPattern.length >= 3 && grepPattern.length <= 80
318
+ && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(grepPattern);
319
+ if (isCleanSymbol) {
320
+ if (!hCtx._preSearchCache) hCtx._preSearchCache = {};
321
+ var cacheKey = 'presearch:' + grepPattern;
322
+ if (!(cacheKey in hCtx._preSearchCache)) {
323
+ var db = _openMonographDb();
324
+ var hint = null;
325
+ if (db) {
326
+ try {
327
+ var row = db.prepare(
328
+ 'SELECT n.name, n.label, n.file_path, n.start_line FROM nodes n ' +
329
+ 'WHERE n.name = ? AND n.label NOT IN (\'Concept\',\'Community\',\'Folder\') ' +
330
+ 'AND n.file_path IS NOT NULL LIMIT 1'
331
+ ).get(grepPattern);
332
+ if (row) {
333
+ hint = row.file_path + (row.start_line != null ? ':' + row.start_line : '');
334
+ }
335
+ } catch (e) { /* non-fatal */ }
336
+ }
337
+ hCtx._preSearchCache[cacheKey] = hint;
338
+ }
339
+ var cachedHint = hCtx._preSearchCache[cacheKey];
340
+ if (cachedHint) {
341
+ // Use the correct MCP tool name — monograph_context does not exist;
342
+ // the callable tool is mcp__monomind__monograph_query
343
+ console.log('[MONOGRAPH_HINT] ' + grepPattern + ' found at ' + cachedHint + ' — use mcp__monomind__monograph_query instead of Grep for better results');
344
+ }
345
+ }
346
+ } catch (e) { /* non-fatal — telemetry always proceeds */ }
291
347
  },
292
348
 
293
349
  'post-graph-tool': () => {
@@ -1,92 +1,164 @@
1
1
  'use strict';
2
2
  /**
3
3
  * Intelligence context module for hook-handler.cjs
4
- * Provides context injection, trajectory logging, and feedback recording.
4
+ * Provides context injection, trajectory logging, feedback recording,
5
+ * edit tracking, consolidation, and stats.
6
+ *
7
+ * Data directory: $CLAUDE_PROJECT_DIR/.monomind/data/
8
+ * auto-memory-store.json — persisted memory entries
9
+ * ranked-context.json — ranked view written by init()
10
+ * pending-insights.jsonl — pending entries to consolidate
11
+ * intelligence-outcomes.jsonl — feedback records
5
12
  */
6
13
 
7
14
  const path = require('path');
8
15
  const fs = require('fs');
9
16
 
17
+ // Resolve base dir at require-time so tests can inject CLAUDE_PROJECT_DIR
18
+ // per fresh require() call.
10
19
  const CWD = process.env.CLAUDE_PROJECT_DIR || process.cwd();
11
- const INTEL_DIR = path.join(CWD, '.monomind', 'intelligence');
12
- const PATTERNS_FILE = path.join(INTEL_DIR, 'patterns.json');
13
- const TRAJECTORY_FILE = path.join(INTEL_DIR, 'trajectory.json');
20
+ const DATA_DIR = path.join(CWD, '.monomind', 'data');
21
+ const STORE_FILE = path.join(DATA_DIR, 'auto-memory-store.json');
22
+ const RANKED_FILE = path.join(DATA_DIR, 'ranked-context.json');
23
+ const PENDING_FILE = path.join(DATA_DIR, 'pending-insights.jsonl');
24
+ const OUTCOMES_FILE = path.join(DATA_DIR, 'intelligence-outcomes.jsonl');
14
25
 
15
- var _initialized = false;
16
- var _patterns = [];
17
- var _trajectory = [];
26
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MiB guard
27
+ const RING_BUFFER_MAX = 50;
18
28
 
19
- function ensureDir() {
20
- try { fs.mkdirSync(INTEL_DIR, { recursive: true }); } catch (_) {}
29
+ var _entries = []; // deduplicated memory entries loaded from store
30
+ var _recentEdits = []; // ring buffer of recently edited paths
31
+
32
+ function ensureDataDir() {
33
+ try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch (_) {}
21
34
  }
22
35
 
23
- var MAX_PATTERNS_SIZE = 10 * 1024 * 1024; // 10 MiB guard
36
+ function safeReadJson(filePath) {
37
+ try {
38
+ if (!fs.existsSync(filePath)) return null;
39
+ var st = fs.statSync(filePath);
40
+ if (st.size > MAX_FILE_SIZE) return null;
41
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
42
+ } catch (_) { return null; }
43
+ }
24
44
 
25
- function loadPatterns() {
45
+ function safeReadLines(filePath) {
26
46
  try {
27
- if (fs.existsSync(PATTERNS_FILE)) {
28
- var st = fs.statSync(PATTERNS_FILE);
29
- if (st.size > MAX_PATTERNS_SIZE) { _patterns = []; return; }
30
- _patterns = JSON.parse(fs.readFileSync(PATTERNS_FILE, 'utf-8'));
31
- }
32
- } catch (_) { _patterns = []; }
47
+ if (!fs.existsSync(filePath)) return [];
48
+ var st = fs.statSync(filePath);
49
+ if (st.size > MAX_FILE_SIZE) return [];
50
+ return fs.readFileSync(filePath, 'utf-8')
51
+ .split('\n')
52
+ .filter(function(l) { return l.trim().length > 0; });
53
+ } catch (_) { return []; }
33
54
  }
34
55
 
56
+ // ── init ───────────────────────────────────────────────────────────────────────
57
+
35
58
  function init() {
36
- if (_initialized) return { ok: true, patternCount: _patterns.length };
37
- ensureDir();
38
- loadPatterns();
39
- _initialized = true;
40
- return { ok: true, patternCount: _patterns.length };
59
+ ensureDataDir();
60
+
61
+ // Load entries from store, deduplicate by id
62
+ var raw = safeReadJson(STORE_FILE);
63
+ var arr = Array.isArray(raw) ? raw : [];
64
+ var seen = new Set();
65
+ _entries = arr.filter(function(e) {
66
+ var key = e && e.id ? String(e.id) : null;
67
+ if (!key) return true;
68
+ if (seen.has(key)) return false;
69
+ seen.add(key);
70
+ return true;
71
+ });
72
+
73
+ // Write ranked-context.json (sorted by confidence desc) with version envelope
74
+ var ranked = _entries.slice().sort(function(a, b) {
75
+ return (b.confidence || 0) - (a.confidence || 0);
76
+ });
77
+ try {
78
+ fs.writeFileSync(RANKED_FILE, JSON.stringify({ version: 1, entries: ranked }, null, 2), 'utf-8');
79
+ } catch (_) {}
80
+
81
+ return { nodes: _entries.length, edges: 0 };
41
82
  }
42
83
 
84
+ // ── getContext ─────────────────────────────────────────────────────────────────
85
+
43
86
  function getContext(prompt) {
44
- if (!prompt || typeof prompt !== 'string') return null;
45
- if (!_initialized) init();
46
- // Match patterns against prompt
47
- var matches = _patterns.filter(function(p) {
48
- return p.keywords && p.keywords.some(function(kw) {
49
- return prompt.toLowerCase().includes(kw.toLowerCase());
50
- });
87
+ if (!prompt || typeof prompt !== 'string' || prompt.trim() === '') return null;
88
+ if (_entries.length === 0) return null;
89
+
90
+ var promptWords = prompt.toLowerCase().split(/\W+/).filter(Boolean);
91
+ var promptSet = new Set(promptWords);
92
+
93
+ var matches = _entries.filter(function(e) {
94
+ var content = ((e.content || '') + ' ' + (e.summary || '')).toLowerCase();
95
+ var words = content.split(/\W+/).filter(Boolean);
96
+ return words.some(function(w) { return promptSet.has(w); });
51
97
  });
98
+
52
99
  if (matches.length === 0) return null;
100
+
53
101
  var top = matches[0];
54
- return '[INTELLIGENCE] Pattern match: ' + (top.name || top.id || 'pattern') +
55
- (top.suggestion ? ' — ' + top.suggestion : '');
102
+ return '[INTELLIGENCE] ' + (top.summary || top.content || top.id || 'context match');
56
103
  }
57
104
 
58
- function logTrajectory(step) {
59
- ensureDir();
60
- _trajectory.push(Object.assign({ ts: new Date().toISOString() }, step || {}));
61
- // Flush every 10 steps to avoid excessive writes
62
- if (_trajectory.length % 10 === 0) {
63
- try {
64
- fs.writeFileSync(TRAJECTORY_FILE, JSON.stringify(_trajectory.slice(-200), null, 2), 'utf-8');
65
- } catch (_) {}
105
+ // ── recordEdit ────────────────────────────────────────────────────────────────
106
+
107
+ function recordEdit(filePath) {
108
+ _recentEdits.push({ path: String(filePath || ''), ts: Date.now() });
109
+ if (_recentEdits.length > RING_BUFFER_MAX) {
110
+ _recentEdits = _recentEdits.slice(-RING_BUFFER_MAX);
66
111
  }
67
112
  }
68
113
 
114
+ // ── consolidate ───────────────────────────────────────────────────────────────
115
+
116
+ function consolidate() {
117
+ ensureDataDir();
118
+ var lines = safeReadLines(PENDING_FILE);
119
+ var count = lines.length;
120
+
121
+ // Clear the pending file
122
+ try { fs.writeFileSync(PENDING_FILE, '', 'utf-8'); } catch (_) {}
123
+
124
+ return { entries: count, edges: 0, newEntries: count };
125
+ }
126
+
127
+ // ── feedback ──────────────────────────────────────────────────────────────────
128
+
69
129
  function feedback(success) {
70
- // Record outcome for last trajectory step
71
- if (_trajectory.length > 0) {
72
- _trajectory[_trajectory.length - 1].outcome = success ? 'success' : 'failure';
73
- }
74
- // Persist
75
- ensureDir();
76
- try {
77
- fs.writeFileSync(TRAJECTORY_FILE, JSON.stringify(_trajectory.slice(-200), null, 2), 'utf-8');
78
- } catch (_) {}
130
+ ensureDataDir();
131
+ var record = JSON.stringify({
132
+ ts: Date.now(),
133
+ success: !!success,
134
+ context: null,
135
+ recentEdits: _recentEdits.slice(),
136
+ }) + '\n';
137
+ try { fs.appendFileSync(OUTCOMES_FILE, record, 'utf-8'); } catch (_) {}
138
+ }
139
+
140
+ // ── stats ─────────────────────────────────────────────────────────────────────
141
+
142
+ function stats(asJson) {
143
+ var result = {
144
+ entries: _entries.length,
145
+ recentEdits: _recentEdits.length,
146
+ pending: safeReadLines(PENDING_FILE).length,
147
+ };
148
+ if (asJson) return JSON.stringify(result);
149
+ return result;
150
+ }
151
+
152
+ // ── legacy ────────────────────────────────────────────────────────────────────
153
+
154
+ function logTrajectory(step) {
155
+ // no-op stub for backward compatibility
156
+ void step;
79
157
  }
80
158
 
81
159
  function storePattern(pattern) {
82
- ensureDir();
83
- loadPatterns();
84
- var safeId = String(pattern.id || '').slice(0, 256);
85
- _patterns = _patterns.filter(function(p) { return p.id !== safeId; });
86
- _patterns.push(Object.assign({ storedAt: new Date().toISOString() }, pattern, { id: safeId }));
87
- try {
88
- fs.writeFileSync(PATTERNS_FILE, JSON.stringify(_patterns.slice(-500), null, 2), 'utf-8');
89
- } catch (_) {}
160
+ // no-op stub for backward compatibility
161
+ void pattern;
90
162
  }
91
163
 
92
- module.exports = { init, getContext, logTrajectory, feedback, storePattern };
164
+ module.exports = { init, getContext, recordEdit, consolidate, feedback, stats, logTrajectory, storePattern };