monomind 2.0.0 → 2.0.1
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 +11 -12
- package/package.json +2 -2
- package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +10 -0
- package/packages/@monomind/cli/README.md +11 -12
- package/packages/@monomind/cli/dist/src/browser/dashboard/server.js +71 -12
- package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +4 -4
- package/packages/@monomind/cli/dist/src/commands/browse-workflow.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +18 -18
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +12 -12
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +847 -0
- package/packages/@monomind/cli/dist/src/orgrt/types.js +51 -0
- package/packages/@monomind/cli/dist/src/parser.js +31 -5
- package/packages/@monomind/cli/dist/src/ui/collector.mjs +69 -44
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +112 -25
- package/packages/@monomind/cli/dist/src/ui/orgs.html +54 -0
- package/packages/@monomind/cli/dist/src/ui/server.mjs +87 -12
- package/packages/@monomind/cli/package.json +3 -2
- package/packages/@monomind/cli/dist/src/consensus/vote-signer.d.ts +0 -36
- package/packages/@monomind/cli/dist/src/consensus/vote-signer.js +0 -88
|
@@ -171,11 +171,12 @@ function pathToSections(filename) {
|
|
|
171
171
|
if (f.includes('registry') || f.includes('registrations')) return ['agents'];
|
|
172
172
|
if (f.includes('route') || f.includes('worker-dispatch')) return ['hooks'];
|
|
173
173
|
if (f.includes('chunk') || f.includes('skills')) return ['knowledge'];
|
|
174
|
-
if (f.includes('memory
|
|
175
|
-
f.includes('monovector.db') || f.includes('ranked-context') ||
|
|
174
|
+
if (f.includes('auto-memory-store') || f.includes('episodes.jsonl') ||
|
|
176
175
|
(f.includes('/memory/') && f.endsWith('.md'))) return ['memory', 'sessions'];
|
|
177
176
|
if (f.includes('palace') || f.includes('drawers') || f.includes('identity')) return ['memory', 'sessions'];
|
|
178
|
-
if (f.includes('
|
|
177
|
+
if (f.includes('consolidation')) return ['metrics', 'memory'];
|
|
178
|
+
if (f.includes('ddd') || f.includes('audit') || f.includes('codebase-map') ||
|
|
179
|
+
f.includes('security-audit') || f.includes('performance')) return ['metrics'];
|
|
179
180
|
if (f.endsWith('.jsonl') || f.includes('sessions')) return ['sessions'];
|
|
180
181
|
return ['sessions', 'swarm', 'agents', 'tokens', 'hooks'];
|
|
181
182
|
}
|
|
@@ -1403,7 +1404,8 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1403
1404
|
const adrs = [];
|
|
1404
1405
|
for (const { path: adrDir, group } of adrDirs) {
|
|
1405
1406
|
if (!fs.existsSync(adrDir)) continue;
|
|
1406
|
-
|
|
1407
|
+
// Skip AppleDouble junk ('._*') — exFAT volumes litter these and they aren't real ADRs
|
|
1408
|
+
const files = fs.readdirSync(adrDir).filter(f => f.endsWith('.md') && !f.startsWith('._') && f !== 'README.md' && f !== 'v3-adrs.md' && f !== 'SECURITY-REVIEW-SUMMARY.md');
|
|
1407
1409
|
for (const fname of files.sort()) {
|
|
1408
1410
|
const resolvedGroup = /^ADR-G/i.test(fname) ? 'guidance' : 'implementation';
|
|
1409
1411
|
try {
|
|
@@ -1621,10 +1623,26 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1621
1623
|
});
|
|
1622
1624
|
}
|
|
1623
1625
|
|
|
1624
|
-
//
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1626
|
+
// Real v2 memory sources: auto-memory pattern store + episodic log
|
|
1627
|
+
let patterns = 0, patternsUpdated = null;
|
|
1628
|
+
try {
|
|
1629
|
+
const store = JSON.parse(fs.readFileSync(path.join(d, '.monomind', 'data', 'auto-memory-store.json'), 'utf8'));
|
|
1630
|
+
if (Array.isArray(store)) {
|
|
1631
|
+
patterns = store.length;
|
|
1632
|
+
for (const e of store) {
|
|
1633
|
+
if (e && typeof e.ts === 'number' && (!patternsUpdated || e.ts > patternsUpdated)) patternsUpdated = e.ts;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
} catch {}
|
|
1637
|
+
|
|
1638
|
+
let episodes = 0, lastEpisode = null;
|
|
1639
|
+
try {
|
|
1640
|
+
const lines = fs.readFileSync(path.join(d, '.monomind', 'episodic', 'episodes.jsonl'), 'utf8').split('\n').filter(Boolean);
|
|
1641
|
+
episodes = lines.length;
|
|
1642
|
+
if (lines.length) {
|
|
1643
|
+
try { const last = JSON.parse(lines[lines.length - 1]); lastEpisode = last.ts || last.timestamp || null; } catch {}
|
|
1644
|
+
}
|
|
1645
|
+
} catch {}
|
|
1628
1646
|
|
|
1629
1647
|
const stats = {
|
|
1630
1648
|
total,
|
|
@@ -1633,9 +1651,15 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
|
|
|
1633
1651
|
ns: Object.keys(byType).length,
|
|
1634
1652
|
size,
|
|
1635
1653
|
byType,
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1654
|
+
patterns,
|
|
1655
|
+
patternsUpdated,
|
|
1656
|
+
episodes,
|
|
1657
|
+
lastEpisode,
|
|
1658
|
+
memoryFiles: total,
|
|
1659
|
+
// Legacy keys (v1 backends removed in v2) — kept false for frontend backward-safety
|
|
1660
|
+
hnsw: false,
|
|
1661
|
+
agentdb: false,
|
|
1662
|
+
rvf: false,
|
|
1639
1663
|
lastWrite,
|
|
1640
1664
|
memDir,
|
|
1641
1665
|
};
|
|
@@ -3476,7 +3500,9 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
3476
3500
|
if (req.method === 'GET' && url.startsWith('/api/token-usage')) {
|
|
3477
3501
|
try {
|
|
3478
3502
|
const qs = new URL(req.url, 'http://localhost').searchParams;
|
|
3479
|
-
|
|
3503
|
+
// Frontend sends ?range=..., older callers use ?period=... — accept both
|
|
3504
|
+
const _periodRaw = qs.get('period') || qs.get('range');
|
|
3505
|
+
const period = ['today','week','30days','month'].includes(_periodRaw) ? _periodRaw : 'today';
|
|
3480
3506
|
const dir = path.resolve(qs.get('dir') || projectDir || process.cwd());
|
|
3481
3507
|
const trackerPath = path.join(dir, '.claude', 'helpers', 'token-tracker.cjs');
|
|
3482
3508
|
const fallback = () => {
|
|
@@ -5625,6 +5651,33 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5625
5651
|
return;
|
|
5626
5652
|
}
|
|
5627
5653
|
|
|
5654
|
+
// ------------------------------------------------- GET /api/playbooks
|
|
5655
|
+
// List playbook definitions from <dir>/.monomind/playbooks/*.json.
|
|
5656
|
+
// (Previously only POST was registered, so GET /api/playbooks?dir=... fell
|
|
5657
|
+
// through to the 404 handler.)
|
|
5658
|
+
if (req.method === 'GET' && url === '/api/playbooks') {
|
|
5659
|
+
try {
|
|
5660
|
+
const qp = new URL(req.url, 'http://localhost').searchParams;
|
|
5661
|
+
const dir = qp.get('dir') || projectDir || process.cwd();
|
|
5662
|
+
const playbookDir = path.join(path.resolve(dir), '.monomind', 'playbooks');
|
|
5663
|
+
const result = [];
|
|
5664
|
+
if (fs.existsSync(playbookDir)) {
|
|
5665
|
+
const files = fs.readdirSync(playbookDir).filter(f => f.endsWith('.json') && !f.startsWith('._'));
|
|
5666
|
+
for (const file of files) {
|
|
5667
|
+
try {
|
|
5668
|
+
const fpath = path.join(playbookDir, file);
|
|
5669
|
+
const def = JSON.parse(fs.readFileSync(fpath, 'utf8'));
|
|
5670
|
+
const stat = fs.statSync(fpath);
|
|
5671
|
+
result.push({ ...def, id: def.id || file.replace('.json', ''), file, modifiedAt: stat.mtimeMs });
|
|
5672
|
+
} catch (_) {}
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
|
|
5676
|
+
res.end(JSON.stringify(result));
|
|
5677
|
+
} catch (e) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: e.message })); }
|
|
5678
|
+
return;
|
|
5679
|
+
}
|
|
5680
|
+
|
|
5628
5681
|
// ------------------------------------------------- POST /api/playbooks
|
|
5629
5682
|
// Save a playbook definition to .monomind/playbooks/<id>.json
|
|
5630
5683
|
if (req.method === 'POST' && url === '/api/playbooks') {
|
|
@@ -5685,6 +5738,28 @@ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{col
|
|
|
5685
5738
|
return;
|
|
5686
5739
|
}
|
|
5687
5740
|
|
|
5741
|
+
// ------------------------------------------------- GET /api/org-coverage
|
|
5742
|
+
// Audit coverage report written by the audit loop to .monomind/audit/coverage.json
|
|
5743
|
+
if (req.method === 'GET' && url === '/api/org-coverage') {
|
|
5744
|
+
try {
|
|
5745
|
+
const qp = new URL(req.url, 'http://localhost').searchParams;
|
|
5746
|
+
const dir = path.resolve(qp.get('dir') || projectDir || process.cwd());
|
|
5747
|
+
const covPath = path.join(dir, '.monomind', 'audit', 'coverage.json');
|
|
5748
|
+
if (!fs.existsSync(covPath)) {
|
|
5749
|
+
res.writeHead(404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
5750
|
+
res.end('{}');
|
|
5751
|
+
return;
|
|
5752
|
+
}
|
|
5753
|
+
const coverage = JSON.parse(fs.readFileSync(covPath, 'utf8'));
|
|
5754
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
|
|
5755
|
+
res.end(JSON.stringify(coverage));
|
|
5756
|
+
} catch (e) {
|
|
5757
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
5758
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
5759
|
+
}
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
|
|
5688
5763
|
// ------------------------------------------------- GET /api/workflow-runs
|
|
5689
5764
|
if (req.method === 'GET' && url === '/api/workflow-runs') {
|
|
5690
5765
|
// Reads from ~/.monomind/browse-runs.json written by the monobrowse dashboard server.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monoes/monomindcli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Monomind CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -92,7 +92,8 @@
|
|
|
92
92
|
"vitest": "^4.1.4"
|
|
93
93
|
},
|
|
94
94
|
"dependencies": {
|
|
95
|
-
"@
|
|
95
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.207",
|
|
96
|
+
"@monoes/monobrowse": "^1.0.3",
|
|
96
97
|
"@monoes/monograph": "^1.4.0",
|
|
97
98
|
"@noble/ed25519": "^2.1.0",
|
|
98
99
|
"mammoth": "^1.12.0",
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VoteSigner (Task 36)
|
|
3
|
-
*
|
|
4
|
-
* HMAC-SHA256 signing and verification for consensus votes.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Derive a signing key from a swarmId and session secret using HMAC-SHA256.
|
|
8
|
-
*/
|
|
9
|
-
export declare function deriveSigningKey(swarmId: string, sessionSecret: string): Buffer;
|
|
10
|
-
export declare function signVote(agentId: string, vote: unknown, decisionId: string, key: Buffer): string;
|
|
11
|
-
/**
|
|
12
|
-
* CP-WBFT: Compute confidence-weighted vote tally.
|
|
13
|
-
*
|
|
14
|
-
* Each agent's vote is scaled by its confidence score (derived from a probe query)
|
|
15
|
-
* before tallying. Agents that fail the probe receive weight 0.
|
|
16
|
-
* Tolerates up to 85.7% Byzantine fault rate across topologies.
|
|
17
|
-
*
|
|
18
|
-
* Source: https://arxiv.org/abs/2511.10400 (CP-WBFT — AAAI 2026)
|
|
19
|
-
*/
|
|
20
|
-
export declare function weightedTally(votes: Array<{
|
|
21
|
-
agentId: string;
|
|
22
|
-
vote: boolean;
|
|
23
|
-
confidence: number;
|
|
24
|
-
}>): {
|
|
25
|
-
approved: number;
|
|
26
|
-
rejected: number;
|
|
27
|
-
weightedApproval: number;
|
|
28
|
-
weightedRejection: number;
|
|
29
|
-
quorum: boolean;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Verify a vote signature using constant-time comparison.
|
|
33
|
-
* Returns true when the signature is valid.
|
|
34
|
-
*/
|
|
35
|
-
export declare function verifyVote(agentId: string, vote: unknown, decisionId: string, signature: string, key: Buffer): boolean;
|
|
36
|
-
//# sourceMappingURL=vote-signer.d.ts.map
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VoteSigner (Task 36)
|
|
3
|
-
*
|
|
4
|
-
* HMAC-SHA256 signing and verification for consensus votes.
|
|
5
|
-
*/
|
|
6
|
-
import { createHmac, timingSafeEqual } from 'crypto';
|
|
7
|
-
/** Max depth for canonicalize() to prevent stack overflow on deeply nested objects. */
|
|
8
|
-
const MAX_CANONICALIZE_DEPTH = 32;
|
|
9
|
-
/** Cap string inputs to prevent OOM when hashing very long strings. */
|
|
10
|
-
const MAX_INPUT_LEN = 1024;
|
|
11
|
-
/** Cap votes array to prevent OOM in weightedTally. */
|
|
12
|
-
const MAX_VOTES = 1000;
|
|
13
|
-
/**
|
|
14
|
-
* Derive a signing key from a swarmId and session secret using HMAC-SHA256.
|
|
15
|
-
*/
|
|
16
|
-
export function deriveSigningKey(swarmId, sessionSecret) {
|
|
17
|
-
return createHmac('sha256', sessionSecret.slice(0, MAX_INPUT_LEN)).update(swarmId.slice(0, MAX_INPUT_LEN)).digest();
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Sign a vote, producing a hex-encoded HMAC-SHA256 signature.
|
|
21
|
-
*/
|
|
22
|
-
function canonicalize(val, depth = 0) {
|
|
23
|
-
// Guard against deeply-nested objects that would overflow the call stack.
|
|
24
|
-
if (depth > MAX_CANONICALIZE_DEPTH)
|
|
25
|
-
return '"[MaxDepth]"';
|
|
26
|
-
if (val === null || typeof val !== 'object')
|
|
27
|
-
return JSON.stringify(val);
|
|
28
|
-
if (Array.isArray(val))
|
|
29
|
-
return '[' + val.map(item => canonicalize(item, depth + 1)).join(',') + ']';
|
|
30
|
-
const sorted = Object.keys(val).sort().map(k => JSON.stringify(k) + ':' + canonicalize(val[k], depth + 1));
|
|
31
|
-
return '{' + sorted.join(',') + '}';
|
|
32
|
-
}
|
|
33
|
-
export function signVote(agentId, vote, decisionId, key) {
|
|
34
|
-
// Cap string fields to prevent OOM when hashing attacker-supplied inputs.
|
|
35
|
-
const safeAgentId = agentId.slice(0, MAX_INPUT_LEN);
|
|
36
|
-
const safeDecisionId = decisionId.slice(0, MAX_INPUT_LEN);
|
|
37
|
-
const payload = JSON.stringify({ agentId: safeAgentId, vote: canonicalize(vote), decisionId: safeDecisionId });
|
|
38
|
-
return createHmac('sha256', key).update(payload).digest('hex');
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* CP-WBFT: Compute confidence-weighted vote tally.
|
|
42
|
-
*
|
|
43
|
-
* Each agent's vote is scaled by its confidence score (derived from a probe query)
|
|
44
|
-
* before tallying. Agents that fail the probe receive weight 0.
|
|
45
|
-
* Tolerates up to 85.7% Byzantine fault rate across topologies.
|
|
46
|
-
*
|
|
47
|
-
* Source: https://arxiv.org/abs/2511.10400 (CP-WBFT — AAAI 2026)
|
|
48
|
-
*/
|
|
49
|
-
export function weightedTally(votes) {
|
|
50
|
-
// Cap votes array to prevent OOM from an oversized input.
|
|
51
|
-
const safeVotes = votes.length > MAX_VOTES ? votes.slice(0, MAX_VOTES) : votes;
|
|
52
|
-
let weightedApproval = 0;
|
|
53
|
-
let weightedRejection = 0;
|
|
54
|
-
let totalWeight = 0;
|
|
55
|
-
for (const { vote, confidence } of safeVotes) {
|
|
56
|
-
const w = Math.max(0, Math.min(1, confidence)); // clamp to [0,1]
|
|
57
|
-
totalWeight += w;
|
|
58
|
-
if (vote) {
|
|
59
|
-
weightedApproval += w;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
weightedRejection += w;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
approved: safeVotes.filter(v => v.vote).length,
|
|
67
|
-
rejected: safeVotes.filter(v => !v.vote).length,
|
|
68
|
-
weightedApproval,
|
|
69
|
-
weightedRejection,
|
|
70
|
-
quorum: totalWeight > 0 && weightedApproval / totalWeight > 0.5,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Verify a vote signature using constant-time comparison.
|
|
75
|
-
* Returns true when the signature is valid.
|
|
76
|
-
*/
|
|
77
|
-
export function verifyVote(agentId, vote, decisionId, signature, key) {
|
|
78
|
-
// Guard: odd-length or non-hex signature string causes Buffer.from to throw.
|
|
79
|
-
if (!/^[0-9a-fA-F]{64}$/.test(signature))
|
|
80
|
-
return false;
|
|
81
|
-
const expected = signVote(agentId, vote, decisionId, key);
|
|
82
|
-
const sigBuf = Buffer.from(signature, 'hex');
|
|
83
|
-
const expBuf = Buffer.from(expected, 'hex');
|
|
84
|
-
if (sigBuf.length !== expBuf.length)
|
|
85
|
-
return false;
|
|
86
|
-
return timingSafeEqual(sigBuf, expBuf);
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=vote-signer.js.map
|