@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.
- package/.claude/agents/generated/churn-analyst.md +53 -0
- package/.claude/agents/generated/code-reviewer.md +55 -0
- package/.claude/agents/generated/code-validator.md +57 -0
- package/.claude/agents/generated/complexity-scanner.md +56 -0
- package/.claude/agents/generated/devbot-orchestrator.md +58 -0
- package/.claude/agents/generated/devbot-planner.md +63 -0
- package/.claude/agents/generated/impact-assessor.md +54 -0
- package/.claude/commands/mastermind/master.md +88 -24
- package/.claude/helpers/control-start.cjs +60 -1
- package/.claude/helpers/event-logger.cjs +43 -2
- package/.claude/helpers/handlers/capture-handler.cjs +336 -0
- package/.claude/helpers/handlers/route-handler.cjs +20 -13
- package/.claude/helpers/handlers/session-restore-handler.cjs +14 -8
- package/.claude/helpers/hook-handler.cjs +57 -1
- package/.claude/helpers/intelligence.cjs +129 -57
- package/.claude/helpers/memory-palace.cjs +461 -0
- package/.claude/helpers/memory.cjs +134 -15
- package/.claude/helpers/metrics-db.mjs +87 -0
- package/.claude/helpers/router.cjs +296 -41
- package/.claude/helpers/session.cjs +107 -32
- package/.claude/helpers/statusline.cjs +138 -2
- package/.claude/helpers/toggle-statusline.cjs +73 -0
- package/.claude/helpers/token-tracker.cjs +934 -0
- package/.claude/helpers/utils/monograph.cjs +39 -4
- package/.claude/helpers/utils/telemetry.cjs +3 -3
- package/.claude/skills/mastermind/createorg.md +227 -16
- package/.claude/skills/mastermind/idea.md +15 -3
- package/.claude/skills/mastermind/runorg.md +2 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +96 -4
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/index.js +2 -0
- package/dist/src/commands/org.d.ts +4 -0
- package/dist/src/commands/org.d.ts.map +1 -0
- package/dist/src/commands/org.js +93 -0
- package/dist/src/commands/org.js.map +1 -0
- package/dist/src/mcp-tools/memory-tools.js +6 -6
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.js +329 -37
- package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
- package/dist/src/mcp-tools/session-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/session-tools.js +9 -10
- package/dist/src/mcp-tools/session-tools.js.map +1 -1
- package/dist/src/mcp-tools/task-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/task-tools.js +7 -8
- package/dist/src/mcp-tools/task-tools.js.map +1 -1
- package/dist/src/mcp-tools/types.d.ts +1 -0
- package/dist/src/mcp-tools/types.d.ts.map +1 -1
- package/dist/src/mcp-tools/types.js +49 -0
- package/dist/src/mcp-tools/types.js.map +1 -1
- package/dist/src/services/worker-daemon.d.ts.map +1 -1
- package/dist/src/services/worker-daemon.js +295 -5
- package/dist/src/services/worker-daemon.js.map +1 -1
- package/dist/src/transfer/serialization/cfp.js +1 -1
- package/dist/src/transfer/serialization/cfp.js.map +1 -1
- package/dist/src/ui/dashboard.html +2235 -178
- package/dist/src/ui/orgs.html +1 -0
- package/dist/src/ui/server.mjs +532 -133
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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) => {
|
|
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,
|
|
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
|
|
12
|
-
const
|
|
13
|
-
const
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
var _trajectory = [];
|
|
26
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MiB guard
|
|
27
|
+
const RING_BUFFER_MAX = 50;
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
|
45
|
+
function safeReadLines(filePath) {
|
|
26
46
|
try {
|
|
27
|
-
if (fs.existsSync(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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 (
|
|
46
|
-
|
|
47
|
-
var
|
|
48
|
-
|
|
49
|
-
|
|
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]
|
|
55
|
-
(top.suggestion ? ' — ' + top.suggestion : '');
|
|
102
|
+
return '[INTELLIGENCE] ' + (top.summary || top.content || top.id || 'context match');
|
|
56
103
|
}
|
|
57
104
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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,
|
|
164
|
+
module.exports = { init, getContext, recordEdit, consolidate, feedback, stats, logTrajectory, storePattern };
|