monomind 2.1.0 → 2.1.3
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/README.md +74 -92
- package/package.json +3 -3
- package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +24 -10
- package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +29 -0
- package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +35 -23
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +21 -0
- package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
- package/packages/@monomind/cli/README.md +74 -92
- package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
- package/packages/@monomind/cli/dist/src/commands/org.js +46 -29
- package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/init/executor.js +30 -6
- package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +5 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +28 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +3 -1
- package/packages/@monomind/cli/dist/src/orgrt/broker.js +8 -3
- package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +17 -1
- package/packages/@monomind/cli/dist/src/orgrt/daemon.js +115 -21
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +41 -8
- package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
- package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
- package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +3 -2
- package/packages/@monomind/cli/dist/src/orgrt/server.js +7 -40
- package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +10 -1
- package/packages/@monomind/cli/dist/src/orgrt/session.js +24 -1
- package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +8 -8
- package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +52 -52
- package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
- package/packages/@monomind/cli/dist/src/output.js +10 -2
- package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +203 -9
- package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
- package/packages/@monomind/cli/dist/src/ui/orgs.html +21 -52
- package/packages/@monomind/cli/dist/src/ui/server.mjs +42 -6
- package/packages/@monomind/cli/package.json +12 -16
- package/packages/@monomind/cli/dist/src/orgrt/live.html +0 -56
|
@@ -9,6 +9,9 @@ import { collectAll, getWatchPaths, collectProject, collectSessions, collectSwar
|
|
|
9
9
|
import { addSseClient, removeSseClient, broadcast, getSseClientCount, closeSseClients, addMmClient, removeMmClient, broadcastMm, getMmClientCount } from './sse-manager.mjs';
|
|
10
10
|
|
|
11
11
|
const JSONL_SIZE_CAP = 10 * 1024 * 1024; // 10 MB — skip files larger than this in /api/graph
|
|
12
|
+
// Session id format for data/sessions/<id>.jsonl persistence — no path traversal (".."), starts
|
|
13
|
+
// with a word char, rest is word chars/dot/dash. Shared by every session-id-accepting endpoint.
|
|
14
|
+
const SESSION_ID_RE = /^(?!.*\.\.)[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/;
|
|
12
15
|
const buildDocsState = new Map();
|
|
13
16
|
|
|
14
17
|
// Pricing per token (mirrors token-tracker.cjs FALLBACK_PRICING)
|
|
@@ -608,10 +611,26 @@ function bindServer(server, port) {
|
|
|
608
611
|
* uses a greedy BFS over the real filesystem to find the correct path.
|
|
609
612
|
* Falls back to cwd in session files, then to direct slug replacement.
|
|
610
613
|
*/
|
|
614
|
+
const _slugPathCache = new Map();
|
|
615
|
+
|
|
611
616
|
function resolveSlugToPath(slug, projDir) {
|
|
612
|
-
|
|
617
|
+
if (_slugPathCache.has(slug)) return _slugPathCache.get(slug);
|
|
618
|
+
const resolved = _resolveSlugToPathUncached(slug, projDir);
|
|
619
|
+
_slugPathCache.set(slug, resolved);
|
|
620
|
+
return resolved;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function _resolveSlugToPathUncached(slug, projDir) {
|
|
624
|
+
// 1. Try filesystem BFS (most reliable). Branching is O(2^hyphens) in the
|
|
625
|
+
// worst case (a slug with N hyphens can require exploring both "new path
|
|
626
|
+
// segment" and "hyphen is part of this segment's name" at each of the N
|
|
627
|
+
// positions) — bound total exploration so a slug with many hyphens (e.g.
|
|
628
|
+
// a UUID-embedded temp/scratchpad dir) can't hang the event loop.
|
|
613
629
|
const parts = slug.replace(/^-/, '').split('-');
|
|
630
|
+
const MAX_CALLS = 20000;
|
|
631
|
+
let calls = 0;
|
|
614
632
|
function tryPaths(idx, current) {
|
|
633
|
+
if (++calls > MAX_CALLS) return null;
|
|
615
634
|
if (idx === parts.length) return fs.existsSync(current) ? current : null;
|
|
616
635
|
// Option A: next part is a new path component
|
|
617
636
|
const asDir = path.join(current, parts[idx]);
|
|
@@ -690,7 +709,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
690
709
|
// Extracted from the request dispatcher to reduce cyclomatic complexity.
|
|
691
710
|
// Handles POST /api/mastermind/event: parses body, enriches with runId/session,
|
|
692
711
|
// persists to JSONL files, broadcasts to SSE clients, returns {ok:true}.
|
|
693
|
-
async function handleMastermindEvent(req, res) {
|
|
712
|
+
async function handleMastermindEvent(req, res, corsOrigin) {
|
|
694
713
|
let body = '';
|
|
695
714
|
for await (const chunk of req) { body += chunk; if (body.length > 2097152) { req.destroy(); break; } }
|
|
696
715
|
let event = {};
|
|
@@ -887,7 +906,7 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
887
906
|
// Format: data/sessions/<sessionId>.jsonl + data/sessions/_index.json
|
|
888
907
|
try {
|
|
889
908
|
const _sid = String(event.session || '').trim();
|
|
890
|
-
if (_sid.length > 0 && _sid.length <= 128 &&
|
|
909
|
+
if (_sid.length > 0 && _sid.length <= 128 && SESSION_ID_RE.test(_sid)) {
|
|
891
910
|
const sessDir = path.join(dataDir, 'sessions');
|
|
892
911
|
fs.mkdirSync(sessDir, { recursive: true });
|
|
893
912
|
// Append event to per-session JSONL (O(1), no read)
|
|
@@ -5397,7 +5416,7 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5397
5416
|
// ------------------------------------------------- Mastermind event system
|
|
5398
5417
|
// POST /api/mastermind/event — ingest event from mastermind skill
|
|
5399
5418
|
if (req.method === 'POST' && url === '/api/mastermind/event') {
|
|
5400
|
-
return handleMastermindEvent(req, res);
|
|
5419
|
+
return handleMastermindEvent(req, res, corsOrigin);
|
|
5401
5420
|
}
|
|
5402
5421
|
|
|
5403
5422
|
// GET /api/mastermind-stream — SSE for real-time events
|
|
@@ -5449,7 +5468,7 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5449
5468
|
const top = idx.slice(0, limitParam);
|
|
5450
5469
|
for (const entry of top) {
|
|
5451
5470
|
const _sid = String(entry.id || '').trim();
|
|
5452
|
-
if (!_sid ||
|
|
5471
|
+
if (!_sid || !SESSION_ID_RE.test(_sid)) continue;
|
|
5453
5472
|
let events = [];
|
|
5454
5473
|
try {
|
|
5455
5474
|
const jl = fs.readFileSync(path.join(sessDir, `${_sid}.jsonl`), 'utf8');
|
|
@@ -5557,6 +5576,23 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5557
5576
|
return;
|
|
5558
5577
|
}
|
|
5559
5578
|
|
|
5579
|
+
// ------------------------------------------------ GET /orgs-files.js
|
|
5580
|
+
// Files-tab + diff-view script, split out of orgs.html (see orgs.html's
|
|
5581
|
+
// script-src comment). Not a generic static handler — this UI serves each
|
|
5582
|
+
// sibling asset via its own hardcoded route, same as GET /orgs above.
|
|
5583
|
+
if (req.method === 'GET' && url === '/orgs-files.js') {
|
|
5584
|
+
try {
|
|
5585
|
+
const jsPath = path.join(__dirname, 'orgs-files.js');
|
|
5586
|
+
const js = fs.readFileSync(jsPath, 'utf8');
|
|
5587
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript; charset=utf-8' });
|
|
5588
|
+
res.end(js);
|
|
5589
|
+
} catch (err) {
|
|
5590
|
+
res.writeHead(404);
|
|
5591
|
+
res.end(`orgs-files.js not found: ${err.message}`);
|
|
5592
|
+
}
|
|
5593
|
+
return;
|
|
5594
|
+
}
|
|
5595
|
+
|
|
5560
5596
|
// GET /api/mastermind/loops — list all active loop state files
|
|
5561
5597
|
if (req.method === 'GET' && url === '/api/mastermind/loops') {
|
|
5562
5598
|
try {
|
|
@@ -6193,7 +6229,7 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
6193
6229
|
const _migIndex = [];
|
|
6194
6230
|
for (const sess of (_migOld || [])) {
|
|
6195
6231
|
const _msid = String(sess.id || '').trim();
|
|
6196
|
-
if (!_msid ||
|
|
6232
|
+
if (!_msid || !SESSION_ID_RE.test(_msid)) continue;
|
|
6197
6233
|
// Write per-session JSONL
|
|
6198
6234
|
const _mEvts = (sess.events || []);
|
|
6199
6235
|
const _mLines = _mEvts.map(e => JSON.stringify(e)).join('\n');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monoes/monomindcli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Monomind
|
|
5
|
+
"description": "CLI engine for Monomind — an open-source MCP server that extends Claude Code with a codebase knowledge graph (tree-sitter + SQLite), persistent memory, multi-agent task coordination, and session hooks. MIT licensed, fully local.",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"types": "dist/src/index.d.ts",
|
|
8
8
|
"sideEffects": false,
|
|
@@ -27,21 +27,17 @@
|
|
|
27
27
|
"claude",
|
|
28
28
|
"claude-code",
|
|
29
29
|
"anthropic",
|
|
30
|
-
"ai-agents",
|
|
31
|
-
"multi-agent",
|
|
32
|
-
"swarm",
|
|
33
30
|
"mcp",
|
|
34
31
|
"model-context-protocol",
|
|
35
|
-
"
|
|
32
|
+
"knowledge-graph",
|
|
33
|
+
"tree-sitter",
|
|
34
|
+
"code-analysis",
|
|
35
|
+
"ai-agents",
|
|
36
|
+
"multi-agent",
|
|
36
37
|
"cli",
|
|
37
|
-
"orchestration",
|
|
38
|
-
"automation",
|
|
39
38
|
"developer-tools",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"embeddings",
|
|
43
|
-
"self-learning",
|
|
44
|
-
"enterprise"
|
|
39
|
+
"open-source",
|
|
40
|
+
"local-first"
|
|
45
41
|
],
|
|
46
42
|
"author": {
|
|
47
43
|
"name": "nokhodian",
|
|
@@ -83,8 +79,8 @@
|
|
|
83
79
|
"README.md"
|
|
84
80
|
],
|
|
85
81
|
"scripts": {
|
|
86
|
-
"build": "tsc && mkdir -p dist/src/browser/dashboard && cp src/browser/dashboard/ui.html dist/src/browser/dashboard/ui.html
|
|
87
|
-
"build:loose": "tsc --noEmitOnError false || true && mkdir -p dist/src/browser/dashboard && cp src/browser/dashboard/ui.html dist/src/browser/dashboard/ui.html
|
|
82
|
+
"build": "tsc && mkdir -p dist/src/browser/dashboard && cp src/browser/dashboard/ui.html dist/src/browser/dashboard/ui.html",
|
|
83
|
+
"build:loose": "tsc --noEmitOnError false || true && mkdir -p dist/src/browser/dashboard && cp src/browser/dashboard/ui.html dist/src/browser/dashboard/ui.html",
|
|
88
84
|
"test": "vitest run",
|
|
89
85
|
"test:pattern-store": "npx tsx src/transfer/store/tests/standalone-test.ts",
|
|
90
86
|
"prepublishOnly": "cp ../../../README.md ./README.md",
|
|
@@ -92,7 +88,7 @@
|
|
|
92
88
|
"publish:all": "./scripts/publish.sh"
|
|
93
89
|
},
|
|
94
90
|
"devDependencies": {
|
|
95
|
-
"typescript": "^
|
|
91
|
+
"typescript": "^7.0.2",
|
|
96
92
|
"vitest": "^4.1.4"
|
|
97
93
|
},
|
|
98
94
|
"dependencies": {
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<!-- packages/@monomind/cli/src/orgrt/live.html -->
|
|
2
|
-
<!doctype html>
|
|
3
|
-
<html><head><meta charset="utf-8"><title>org live</title>
|
|
4
|
-
<style>
|
|
5
|
-
:root { color-scheme: dark; }
|
|
6
|
-
body { margin:0; font:13px/1.5 ui-monospace,monospace; background:#0d1117; color:#e6edf3;
|
|
7
|
-
display:grid; grid-template-columns:220px 1fr 1fr; grid-template-rows:auto 1fr 1fr; gap:1px; height:100vh; }
|
|
8
|
-
header { grid-column:1/4; padding:8px 14px; background:#161b22; font-weight:700; }
|
|
9
|
-
section { background:#161b22; overflow:auto; padding:10px; }
|
|
10
|
-
h2 { font-size:11px; text-transform:uppercase; letter-spacing:.1em; color:#7d8590; margin:0 0 8px; }
|
|
11
|
-
#agents { grid-row:2/4; }
|
|
12
|
-
.agent { padding:6px 8px; border-left:3px solid #2f81f7; margin-bottom:6px; background:#0d1117; }
|
|
13
|
-
.agent small { color:#7d8590; display:block; }
|
|
14
|
-
.row { padding:4px 6px; border-bottom:1px solid #21262d; word-break:break-word; }
|
|
15
|
-
.from { color:#2f81f7; font-weight:700; } .to { color:#a371f7; }
|
|
16
|
-
.deny { color:#f85149; } .allow { color:#3fb950; } .xorg { color:#d29922; font-weight:700; }
|
|
17
|
-
.ts { color:#484f58; font-size:11px; margin-right:6px; }
|
|
18
|
-
</style></head>
|
|
19
|
-
<body>
|
|
20
|
-
<header>org live — <span id="conn">connecting…</span></header>
|
|
21
|
-
<section id="agents"><h2>Agents</h2><div id="agents-list"></div></section>
|
|
22
|
-
<section id="chat"><h2>Chats & Messages</h2><div id="chat-list"></div></section>
|
|
23
|
-
<section id="tools"><h2>Tool Activity & Assets</h2><div id="tools-list"></div></section>
|
|
24
|
-
<script>
|
|
25
|
-
const $ = id => document.getElementById(id);
|
|
26
|
-
const fmt = ts => new Date(ts).toLocaleTimeString();
|
|
27
|
-
const add = (listId, html, cap = 500) => {
|
|
28
|
-
const el = document.createElement('div'); el.className = 'row'; el.innerHTML = html;
|
|
29
|
-
const list = $(listId); list.prepend(el);
|
|
30
|
-
while (list.children.length > cap) list.lastChild.remove();
|
|
31
|
-
};
|
|
32
|
-
const esc = s => String(s ?? '').replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'}[c]));
|
|
33
|
-
const decisionClass = d => (d === 'allow' || d === 'deny') ? d : 'unknown';
|
|
34
|
-
function render(e) {
|
|
35
|
-
const t = `<span class="ts">${fmt(e.ts)}</span>`;
|
|
36
|
-
if (e.type === 'chat') add('chat-list', `${t}<span class="from">${esc(e.org)}/${esc(e.from)}</span>: ${esc(e.msg)}`);
|
|
37
|
-
else if (e.type === 'message') add('chat-list', `${t}<span class="from">${esc(e.from)}</span> → <span class="to">${esc(e.to)}</span> [${esc(e.subject||'')}] ${esc(e.msg)}`);
|
|
38
|
-
else if (e.type === 'xorg') add('chat-list', `${t}<span class="xorg">⇄ ${esc(e.from)} → ${esc(e.to)}</span> [${esc(e.subject||'')}] ${esc(e.msg)}`);
|
|
39
|
-
else if (e.type === 'tool') add('tools-list', `${t}<span class="from">${esc(e.from)}</span> ${esc(e.tool)} <span class="${decisionClass(e.decision)}">${esc(e.decision)}</span>${e.reason ? ' — ' + esc(e.reason) : ''}`);
|
|
40
|
-
else if (e.type === 'asset') add('tools-list', `${t}<span class="from">${esc(e.from)}</span> 📄 <b>${esc(e.path)}</b>`);
|
|
41
|
-
else if (e.type === 'status' || e.type === 'usage') add('tools-list', `${t}<i>${esc(e.org)}/${esc(e.from ?? 'org')}: ${esc(e.msg ?? JSON.stringify(e.data))}</i>`);
|
|
42
|
-
}
|
|
43
|
-
async function refreshAgents() {
|
|
44
|
-
const orgs = await fetch('/api/orgs').then(r => r.json()).catch(() => []);
|
|
45
|
-
$('agents-list').innerHTML = orgs.map(o =>
|
|
46
|
-
`<div class="agent"><b>${esc(o.name)}</b><small>${esc(o.run)}</small>` +
|
|
47
|
-
o.agents.map(a => `<div>${a.closed ? '⚫' : '🟢'} ${esc(a.id)} <small>${esc(a.usage)} tok</small></div>`).join('') +
|
|
48
|
-
`</div>`).join('') || '<i>no running orgs</i>';
|
|
49
|
-
}
|
|
50
|
-
const ws = new WebSocket(`ws://${location.host}/ws`);
|
|
51
|
-
ws.onopen = () => { $('conn').textContent = 'live'; refreshAgents(); };
|
|
52
|
-
ws.onclose = () => { $('conn').textContent = 'disconnected'; };
|
|
53
|
-
ws.onmessage = ev => { render(JSON.parse(ev.data)); };
|
|
54
|
-
setInterval(refreshAgents, 5000);
|
|
55
|
-
</script>
|
|
56
|
-
</body></html>
|