monomind 2.5.4 → 2.5.5
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 +10 -3
- package/package.json +1 -1
- package/packages/@monomind/cli/.claude/commands/mastermind/topology.md +121 -0
- package/packages/@monomind/cli/.claude/commands/mastermind.md +121 -102
- package/packages/@monomind/cli/.claude/helpers/control-start.cjs +22 -2
- package/packages/@monomind/cli/.claude/helpers/control-stop.cjs +95 -0
- package/packages/@monomind/cli/.claude/helpers/graphify-freshen.cjs +6 -0
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +13 -5
- package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +33 -10
- package/packages/@monomind/cli/.claude/helpers/utils/system-pressure.cjs +46 -0
- package/packages/@monomind/cli/.claude/settings.json +448 -0
- package/packages/@monomind/cli/README.md +10 -3
- package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/agent-ops.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/cleanup.js +53 -1
- package/packages/@monomind/cli/dist/src/commands/config.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/hooks.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/index.js +4 -0
- package/packages/@monomind/cli/dist/src/commands/init-wizard.js +3 -3
- package/packages/@monomind/cli/dist/src/commands/init.js +2 -2
- package/packages/@monomind/cli/dist/src/commands/mcp.js +2 -2
- package/packages/@monomind/cli/dist/src/commands/memory-admin.js +8 -7
- package/packages/@monomind/cli/dist/src/commands/memory-list.js +2 -2
- package/packages/@monomind/cli/dist/src/commands/memory.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/memory.js +4 -4
- package/packages/@monomind/cli/dist/src/commands/neural-core.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/performance.js +8 -9
- package/packages/@monomind/cli/dist/src/commands/status.js +2 -2
- package/packages/@monomind/cli/dist/src/commands/swarm.js +1 -1
- package/packages/@monomind/cli/dist/src/index.js +1 -1
- package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +2 -2
- package/packages/@monomind/cli/dist/src/init/executor.js +13 -6
- package/packages/@monomind/cli/dist/src/init/helpers-generator.js +66 -3
- package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.js +1 -1
- package/packages/@monomind/cli/dist/src/init/statusline-generator.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/init/statusline-generator.js +2 -2
- package/packages/@monomind/cli/dist/src/init/types.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/knowledge/document-pipeline.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/knowledge/document-pipeline.js +3 -3
- package/packages/@monomind/cli/dist/src/mcp-client.d.ts +13 -51
- package/packages/@monomind/cli/dist/src/mcp-client.js +79 -134
- package/packages/@monomind/cli/dist/src/mcp-server.js +4 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.js +45 -19
- package/packages/@monomind/cli/dist/src/mcp-tools/guidance-tools.js +1 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +1 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +22 -9
- package/packages/@monomind/cli/dist/src/mcp-tools/neural-tools.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/neural-tools.js +3 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +1 -1
- package/packages/@monomind/cli/dist/src/memory/embedding-operations.js +2 -2
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +53 -26
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +2 -2
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +7 -3
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +24 -10
- package/packages/@monomind/cli/dist/src/memory/memory-crud.js +2 -2
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +6 -6
- package/packages/@monomind/cli/dist/src/memory/memory-read.js +4 -4
- package/packages/@monomind/cli/dist/src/orgrt/daemon.js +12 -6
- package/packages/@monomind/cli/dist/src/orgrt/mailbox.d.ts +1 -0
- package/packages/@monomind/cli/dist/src/orgrt/mailbox.js +4 -0
- package/packages/@monomind/cli/dist/src/orgrt/policy.js +1 -1
- package/packages/@monomind/cli/dist/src/orgrt/server.js +25 -0
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +327 -611
- package/packages/@monomind/cli/dist/src/ui/server.mjs +165 -22
- package/packages/@monomind/cli/package.json +1 -1
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Thin wrapper for calling MCP tools from CLI commands.
|
|
5
5
|
* Implements ADR-005: MCP-First API Design - CLI as thin wrapper around MCP tools
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Tool modules are lazy-loaded on first use to avoid pulling ~300 tools'
|
|
8
|
+
* transitive dependencies into the heap at import time.
|
|
9
9
|
*/
|
|
10
10
|
import type { MCPTool } from './mcp-tools/types.js';
|
|
11
11
|
export declare function isToolDisabled(toolName: string, cwd?: string): boolean;
|
|
@@ -19,76 +19,38 @@ export declare class MCPClientError extends Error {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Call an MCP tool by name with input parameters
|
|
22
|
-
*
|
|
23
|
-
* @param toolName - Name of the MCP tool (e.g., 'agent_spawn', 'swarm_init')
|
|
24
|
-
* @param input - Input parameters for the tool
|
|
25
|
-
* @param context - Optional tool context
|
|
26
|
-
* @returns Promise resolving to tool result
|
|
27
|
-
* @throws {MCPClientError} If tool not found or execution fails
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Spawn an agent
|
|
32
|
-
* const result = await callMCPTool('agent_spawn', {
|
|
33
|
-
* agentType: 'coder',
|
|
34
|
-
* priority: 'normal'
|
|
35
|
-
* });
|
|
36
|
-
*
|
|
37
|
-
* // Initialize swarm
|
|
38
|
-
* const swarm = await callMCPTool('swarm_init', {
|
|
39
|
-
* topology: 'hierarchical-mesh',
|
|
40
|
-
* maxAgents: 15
|
|
41
|
-
* });
|
|
42
|
-
* ```
|
|
43
22
|
*/
|
|
44
23
|
export declare function callMCPTool<T = unknown>(toolName: string, input?: Record<string, unknown>, context?: Record<string, unknown>): Promise<T>;
|
|
45
24
|
/**
|
|
46
25
|
* Get tool metadata by name
|
|
47
|
-
*
|
|
48
|
-
* @param toolName - Name of the MCP tool
|
|
49
|
-
* @returns Tool metadata or undefined if not found
|
|
50
26
|
*/
|
|
51
|
-
export declare function getToolMetadata(toolName: string): Omit<MCPTool, 'handler'> | undefined
|
|
27
|
+
export declare function getToolMetadata(toolName: string): Promise<Omit<MCPTool, 'handler'> | undefined>;
|
|
52
28
|
/**
|
|
53
|
-
* List all available MCP tools
|
|
54
|
-
*
|
|
55
|
-
* @param category - Optional category filter
|
|
56
|
-
* @returns Array of tool metadata
|
|
29
|
+
* List all available MCP tools (loads all categories on first call)
|
|
57
30
|
*/
|
|
58
|
-
export declare function listMCPTools(category?: string): Array<Omit<MCPTool, 'handler'> & {
|
|
31
|
+
export declare function listMCPTools(category?: string): Promise<Array<Omit<MCPTool, 'handler'> & {
|
|
59
32
|
enabled: boolean;
|
|
60
|
-
}
|
|
33
|
+
}>>;
|
|
61
34
|
/**
|
|
62
35
|
* Return all registered tools including their handler functions, excluding
|
|
63
|
-
* any disabled via `mcp toggle`.
|
|
64
|
-
* with the HTTP/WS MCP server, so a disabled tool is never exposed to
|
|
65
|
-
* external MCP clients after the next server start.
|
|
36
|
+
* any disabled via `mcp toggle`. Loads all categories on first call.
|
|
66
37
|
*/
|
|
67
|
-
export declare function getAllMCPTools(): MCPTool[]
|
|
38
|
+
export declare function getAllMCPTools(): Promise<MCPTool[]>;
|
|
68
39
|
/**
|
|
69
|
-
* Check if an MCP tool exists
|
|
70
|
-
*
|
|
71
|
-
* @param toolName - Name of the MCP tool
|
|
72
|
-
* @returns True if tool exists
|
|
40
|
+
* Check if an MCP tool exists (checks loaded categories + known prefixes)
|
|
73
41
|
*/
|
|
74
|
-
export declare function hasTool(toolName: string): boolean
|
|
42
|
+
export declare function hasTool(toolName: string): Promise<boolean>;
|
|
75
43
|
/**
|
|
76
44
|
* Get all tool categories
|
|
77
|
-
*
|
|
78
|
-
* @returns Array of unique categories
|
|
79
45
|
*/
|
|
80
|
-
export declare function getToolCategories(): string[]
|
|
46
|
+
export declare function getToolCategories(): Promise<string[]>;
|
|
81
47
|
/**
|
|
82
48
|
* Validate tool input against schema
|
|
83
|
-
*
|
|
84
|
-
* @param toolName - Name of the MCP tool
|
|
85
|
-
* @param input - Input to validate
|
|
86
|
-
* @returns Validation result with errors if any
|
|
87
49
|
*/
|
|
88
|
-
export declare function validateToolInput(toolName: string, input: Record<string, unknown>): {
|
|
50
|
+
export declare function validateToolInput(toolName: string, input: Record<string, unknown>): Promise<{
|
|
89
51
|
valid: boolean;
|
|
90
52
|
errors?: string[];
|
|
91
|
-
}
|
|
53
|
+
}>;
|
|
92
54
|
declare const _default: {
|
|
93
55
|
callMCPTool: typeof callMCPTool;
|
|
94
56
|
getToolMetadata: typeof getToolMetadata;
|
|
@@ -4,51 +4,16 @@
|
|
|
4
4
|
* Thin wrapper for calling MCP tools from CLI commands.
|
|
5
5
|
* Implements ADR-005: MCP-First API Design - CLI as thin wrapper around MCP tools
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Tool modules are lazy-loaded on first use to avoid pulling ~300 tools'
|
|
8
|
+
* transitive dependencies into the heap at import time.
|
|
9
9
|
*/
|
|
10
10
|
import { existsSync, readFileSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
-
// Import MCP tool handlers from local package
|
|
13
|
-
import { agentTools } from './mcp-tools/agent-tools.js';
|
|
14
|
-
import { swarmTools } from './mcp-tools/swarm-tools.js';
|
|
15
|
-
import { memoryTools } from './mcp-tools/memory-tools.js';
|
|
16
|
-
import { configTools } from './mcp-tools/config-tools.js';
|
|
17
|
-
import { hooksTools } from './mcp-tools/hooks-tools.js';
|
|
18
|
-
import { taskTools } from './mcp-tools/task-tools.js';
|
|
19
|
-
import { sessionTools } from './mcp-tools/session-tools.js';
|
|
20
|
-
import { hiveMindTools } from './mcp-tools/hive-mind-tools.js';
|
|
21
|
-
import { analyzeTools } from './mcp-tools/analyze-tools.js';
|
|
22
|
-
import { embeddingsTools } from './mcp-tools/embeddings-tools.js';
|
|
23
|
-
import { claimsTools } from './mcp-tools/claims-tools.js';
|
|
24
|
-
import { securityTools } from './mcp-tools/security-tools.js';
|
|
25
|
-
import { transferTools } from './mcp-tools/transfer-tools.js';
|
|
26
|
-
// V2 Compatibility tools
|
|
27
|
-
import { systemTools } from './mcp-tools/system-tools.js';
|
|
28
|
-
import { terminalTools } from './mcp-tools/terminal-tools.js';
|
|
29
|
-
import { neuralTools } from './mcp-tools/neural-tools.js';
|
|
30
|
-
import { performanceTools } from './mcp-tools/performance-tools.js';
|
|
31
|
-
import { githubTools } from './mcp-tools/github-tools.js';
|
|
32
|
-
import { daaTools } from './mcp-tools/daa-tools.js';
|
|
33
|
-
import { browserTools } from './mcp-tools/browser-tools.js';
|
|
34
|
-
import { guidanceTools } from './mcp-tools/guidance-tools.js';
|
|
35
|
-
import { autopilotTools } from './mcp-tools/autopilot-tools.js';
|
|
36
|
-
// Knowledge graph tools (graphify — deprecated shims + monograph native)
|
|
37
|
-
import { graphifyTools } from './mcp-tools/graphify-tools.js';
|
|
38
|
-
import { monographTools } from './mcp-tools/monograph-tools.js';
|
|
39
|
-
// Coverage-aware routing tools
|
|
40
|
-
import { coverageRouterTools } from './monovector/coverage-tools.js';
|
|
41
|
-
// Quality and Coherence core tools
|
|
42
|
-
import { qualityTools } from './mcp-tools/quality-tools.js';
|
|
43
|
-
import { coherenceTools } from './mcp-tools/coherence-tools.js';
|
|
44
|
-
// Second Brain knowledge tools
|
|
45
|
-
import { knowledgeTools } from './mcp-tools/knowledge-tools.js';
|
|
46
12
|
/**
|
|
47
13
|
* MCP Tool Registry
|
|
48
|
-
* Maps tool names to their handler functions
|
|
14
|
+
* Maps tool names to their handler functions — populated lazily per category.
|
|
49
15
|
*/
|
|
50
16
|
const TOOL_REGISTRY = new Map();
|
|
51
|
-
// Register all tools — refuse silent overrides without an explicit override flag.
|
|
52
17
|
function registerTools(tools, options = {}) {
|
|
53
18
|
for (const tool of tools) {
|
|
54
19
|
if (TOOL_REGISTRY.has(tool.name) && !options.override) {
|
|
@@ -57,46 +22,59 @@ function registerTools(tools, options = {}) {
|
|
|
57
22
|
TOOL_REGISTRY.set(tool.name, tool);
|
|
58
23
|
}
|
|
59
24
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
25
|
+
const CATEGORY_LOADERS = {
|
|
26
|
+
agent: async () => (await import('./mcp-tools/agent-tools.js')).agentTools,
|
|
27
|
+
swarm: async () => (await import('./mcp-tools/swarm-tools.js')).swarmTools,
|
|
28
|
+
memory: async () => (await import('./mcp-tools/memory-tools.js')).memoryTools,
|
|
29
|
+
config: async () => (await import('./mcp-tools/config-tools.js')).configTools,
|
|
30
|
+
hooks: async () => (await import('./mcp-tools/hooks-tools.js')).hooksTools,
|
|
31
|
+
task: async () => (await import('./mcp-tools/task-tools.js')).taskTools,
|
|
32
|
+
session: async () => (await import('./mcp-tools/session-tools.js')).sessionTools,
|
|
33
|
+
'hive-mind': async () => (await import('./mcp-tools/hive-mind-tools.js')).hiveMindTools,
|
|
34
|
+
analyze: async () => (await import('./mcp-tools/analyze-tools.js')).analyzeTools,
|
|
35
|
+
embeddings: async () => (await import('./mcp-tools/embeddings-tools.js')).embeddingsTools,
|
|
36
|
+
claims: async () => (await import('./mcp-tools/claims-tools.js')).claimsTools,
|
|
37
|
+
monofence: async () => (await import('./mcp-tools/security-tools.js')).securityTools,
|
|
38
|
+
transfer: async () => (await import('./mcp-tools/transfer-tools.js')).transferTools,
|
|
39
|
+
system: async () => (await import('./mcp-tools/system-tools.js')).systemTools,
|
|
40
|
+
terminal: async () => (await import('./mcp-tools/terminal-tools.js')).terminalTools,
|
|
41
|
+
neural: async () => (await import('./mcp-tools/neural-tools.js')).neuralTools,
|
|
42
|
+
performance: async () => (await import('./mcp-tools/performance-tools.js')).performanceTools,
|
|
43
|
+
github: async () => (await import('./mcp-tools/github-tools.js')).githubTools,
|
|
44
|
+
daa: async () => (await import('./mcp-tools/daa-tools.js')).daaTools,
|
|
45
|
+
browser: async () => (await import('./mcp-tools/browser-tools.js')).browserTools,
|
|
46
|
+
guidance: async () => (await import('./mcp-tools/guidance-tools.js')).guidanceTools,
|
|
47
|
+
autopilot: async () => (await import('./mcp-tools/autopilot-tools.js')).autopilotTools,
|
|
48
|
+
monograph: async () => (await import('./mcp-tools/monograph-tools.js')).monographTools,
|
|
49
|
+
graphify: async () => (await import('./mcp-tools/graphify-tools.js')).graphifyTools,
|
|
50
|
+
coverage: async () => (await import('./monovector/coverage-tools.js')).coverageRouterTools,
|
|
51
|
+
quality: async () => (await import('./mcp-tools/quality-tools.js')).qualityTools,
|
|
52
|
+
coherence: async () => (await import('./mcp-tools/coherence-tools.js')).coherenceTools,
|
|
53
|
+
knowledge: async () => (await import('./mcp-tools/knowledge-tools.js')).knowledgeTools,
|
|
54
|
+
// system-tools.ts also exports tools with mcp_ and config_ prefixes
|
|
55
|
+
mcp: async () => (await import('./mcp-tools/system-tools.js')).systemTools,
|
|
56
|
+
};
|
|
57
|
+
const loadedCategories = new Set();
|
|
58
|
+
async function ensureCategory(category) {
|
|
59
|
+
if (loadedCategories.has(category))
|
|
60
|
+
return;
|
|
61
|
+
const loader = CATEGORY_LOADERS[category];
|
|
62
|
+
if (!loader)
|
|
63
|
+
return;
|
|
64
|
+
loadedCategories.add(category);
|
|
65
|
+
registerTools(await loader(), { override: true });
|
|
66
|
+
}
|
|
67
|
+
function categoryFromToolName(name) {
|
|
68
|
+
const idx = name.indexOf('_');
|
|
69
|
+
return idx > 0 ? name.slice(0, idx) : name;
|
|
70
|
+
}
|
|
71
|
+
let _allLoaded = false;
|
|
72
|
+
async function ensureAllLoaded() {
|
|
73
|
+
if (_allLoaded)
|
|
74
|
+
return;
|
|
75
|
+
_allLoaded = true;
|
|
76
|
+
await Promise.all(Object.keys(CATEGORY_LOADERS).map(cat => ensureCategory(cat)));
|
|
77
|
+
}
|
|
100
78
|
/**
|
|
101
79
|
* Disabled-tools registry (`mcp toggle`)
|
|
102
80
|
*
|
|
@@ -136,30 +114,11 @@ export class MCPClientError extends Error {
|
|
|
136
114
|
}
|
|
137
115
|
/**
|
|
138
116
|
* Call an MCP tool by name with input parameters
|
|
139
|
-
*
|
|
140
|
-
* @param toolName - Name of the MCP tool (e.g., 'agent_spawn', 'swarm_init')
|
|
141
|
-
* @param input - Input parameters for the tool
|
|
142
|
-
* @param context - Optional tool context
|
|
143
|
-
* @returns Promise resolving to tool result
|
|
144
|
-
* @throws {MCPClientError} If tool not found or execution fails
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* ```typescript
|
|
148
|
-
* // Spawn an agent
|
|
149
|
-
* const result = await callMCPTool('agent_spawn', {
|
|
150
|
-
* agentType: 'coder',
|
|
151
|
-
* priority: 'normal'
|
|
152
|
-
* });
|
|
153
|
-
*
|
|
154
|
-
* // Initialize swarm
|
|
155
|
-
* const swarm = await callMCPTool('swarm_init', {
|
|
156
|
-
* topology: 'hierarchical-mesh',
|
|
157
|
-
* maxAgents: 15
|
|
158
|
-
* });
|
|
159
|
-
* ```
|
|
160
117
|
*/
|
|
161
118
|
export async function callMCPTool(toolName, input = {}, context) {
|
|
162
|
-
//
|
|
119
|
+
// Lazy-load the tool's category if not yet loaded
|
|
120
|
+
const cat = categoryFromToolName(toolName);
|
|
121
|
+
await ensureCategory(cat);
|
|
163
122
|
const tool = TOOL_REGISTRY.get(toolName);
|
|
164
123
|
if (!tool) {
|
|
165
124
|
throw new MCPClientError(`MCP tool not found: ${toolName}`, toolName);
|
|
@@ -168,27 +127,22 @@ export async function callMCPTool(toolName, input = {}, context) {
|
|
|
168
127
|
throw new MCPClientError(`MCP tool '${toolName}' is disabled. Re-enable with: mcp toggle --enable ${toolName}`, toolName);
|
|
169
128
|
}
|
|
170
129
|
try {
|
|
171
|
-
// Call the tool handler
|
|
172
130
|
const result = await tool.handler(input, context);
|
|
173
131
|
return result;
|
|
174
132
|
}
|
|
175
133
|
catch (error) {
|
|
176
|
-
// Wrap and re-throw with context
|
|
177
134
|
throw new MCPClientError(`Failed to execute MCP tool '${toolName}': ${error instanceof Error ? error.message : String(error)}`, toolName, error instanceof Error ? error : undefined);
|
|
178
135
|
}
|
|
179
136
|
}
|
|
180
137
|
/**
|
|
181
138
|
* Get tool metadata by name
|
|
182
|
-
*
|
|
183
|
-
* @param toolName - Name of the MCP tool
|
|
184
|
-
* @returns Tool metadata or undefined if not found
|
|
185
139
|
*/
|
|
186
|
-
export function getToolMetadata(toolName) {
|
|
140
|
+
export async function getToolMetadata(toolName) {
|
|
141
|
+
const cat = categoryFromToolName(toolName);
|
|
142
|
+
await ensureCategory(cat);
|
|
187
143
|
const tool = TOOL_REGISTRY.get(toolName);
|
|
188
|
-
if (!tool)
|
|
144
|
+
if (!tool)
|
|
189
145
|
return undefined;
|
|
190
|
-
}
|
|
191
|
-
// Return everything except the handler function
|
|
192
146
|
return {
|
|
193
147
|
name: tool.name,
|
|
194
148
|
description: tool.description,
|
|
@@ -201,12 +155,10 @@ export function getToolMetadata(toolName) {
|
|
|
201
155
|
};
|
|
202
156
|
}
|
|
203
157
|
/**
|
|
204
|
-
* List all available MCP tools
|
|
205
|
-
*
|
|
206
|
-
* @param category - Optional category filter
|
|
207
|
-
* @returns Array of tool metadata
|
|
158
|
+
* List all available MCP tools (loads all categories on first call)
|
|
208
159
|
*/
|
|
209
|
-
export function listMCPTools(category) {
|
|
160
|
+
export async function listMCPTools(category) {
|
|
161
|
+
await ensureAllLoaded();
|
|
210
162
|
const tools = Array.from(TOOL_REGISTRY.values());
|
|
211
163
|
const disabled = loadDisabledTools();
|
|
212
164
|
const filtered = category
|
|
@@ -226,45 +178,39 @@ export function listMCPTools(category) {
|
|
|
226
178
|
}
|
|
227
179
|
/**
|
|
228
180
|
* Return all registered tools including their handler functions, excluding
|
|
229
|
-
* any disabled via `mcp toggle`.
|
|
230
|
-
* with the HTTP/WS MCP server, so a disabled tool is never exposed to
|
|
231
|
-
* external MCP clients after the next server start.
|
|
181
|
+
* any disabled via `mcp toggle`. Loads all categories on first call.
|
|
232
182
|
*/
|
|
233
|
-
export function getAllMCPTools() {
|
|
183
|
+
export async function getAllMCPTools() {
|
|
184
|
+
await ensureAllLoaded();
|
|
234
185
|
const disabled = loadDisabledTools();
|
|
235
186
|
return Array.from(TOOL_REGISTRY.values()).filter(t => !disabled.has(t.name));
|
|
236
187
|
}
|
|
237
188
|
/**
|
|
238
|
-
* Check if an MCP tool exists
|
|
239
|
-
*
|
|
240
|
-
* @param toolName - Name of the MCP tool
|
|
241
|
-
* @returns True if tool exists
|
|
189
|
+
* Check if an MCP tool exists (checks loaded categories + known prefixes)
|
|
242
190
|
*/
|
|
243
|
-
export function hasTool(toolName) {
|
|
191
|
+
export async function hasTool(toolName) {
|
|
192
|
+
const cat = categoryFromToolName(toolName);
|
|
193
|
+
await ensureCategory(cat);
|
|
244
194
|
return TOOL_REGISTRY.has(toolName);
|
|
245
195
|
}
|
|
246
196
|
/**
|
|
247
197
|
* Get all tool categories
|
|
248
|
-
*
|
|
249
|
-
* @returns Array of unique categories
|
|
250
198
|
*/
|
|
251
|
-
export function getToolCategories() {
|
|
199
|
+
export async function getToolCategories() {
|
|
200
|
+
await ensureAllLoaded();
|
|
252
201
|
const categories = new Set();
|
|
253
202
|
TOOL_REGISTRY.forEach(tool => {
|
|
254
|
-
if (tool.category)
|
|
203
|
+
if (tool.category)
|
|
255
204
|
categories.add(tool.category);
|
|
256
|
-
}
|
|
257
205
|
});
|
|
258
206
|
return Array.from(categories).sort();
|
|
259
207
|
}
|
|
260
208
|
/**
|
|
261
209
|
* Validate tool input against schema
|
|
262
|
-
*
|
|
263
|
-
* @param toolName - Name of the MCP tool
|
|
264
|
-
* @param input - Input to validate
|
|
265
|
-
* @returns Validation result with errors if any
|
|
266
210
|
*/
|
|
267
|
-
export function validateToolInput(toolName, input) {
|
|
211
|
+
export async function validateToolInput(toolName, input) {
|
|
212
|
+
const cat = categoryFromToolName(toolName);
|
|
213
|
+
await ensureCategory(cat);
|
|
268
214
|
const tool = TOOL_REGISTRY.get(toolName);
|
|
269
215
|
if (!tool) {
|
|
270
216
|
return {
|
|
@@ -272,7 +218,6 @@ export function validateToolInput(toolName, input) {
|
|
|
272
218
|
errors: [`Tool '${toolName}' not found`],
|
|
273
219
|
};
|
|
274
220
|
}
|
|
275
|
-
// Basic validation - check required fields
|
|
276
221
|
const schema = tool.inputSchema;
|
|
277
222
|
const errors = [];
|
|
278
223
|
if (schema.required && Array.isArray(schema.required)) {
|
|
@@ -405,6 +405,7 @@ export class MCPServerManager extends EventEmitter {
|
|
|
405
405
|
process.stdin.on('end', () => { void shutdown('stdin closed'); });
|
|
406
406
|
process.on('SIGINT', () => { void shutdown('Received SIGINT'); });
|
|
407
407
|
process.on('SIGTERM', () => { void shutdown('Received SIGTERM'); });
|
|
408
|
+
process.on('SIGHUP', () => { void shutdown('Received SIGHUP'); });
|
|
408
409
|
// Mark as ready immediately for stdio
|
|
409
410
|
this.emit('ready');
|
|
410
411
|
}
|
|
@@ -437,7 +438,7 @@ export class MCPServerManager extends EventEmitter {
|
|
|
437
438
|
},
|
|
438
439
|
};
|
|
439
440
|
case 'tools/list':
|
|
440
|
-
const tools = listMCPTools();
|
|
441
|
+
const tools = await listMCPTools();
|
|
441
442
|
return {
|
|
442
443
|
jsonrpc: '2.0',
|
|
443
444
|
id: message.id,
|
|
@@ -484,7 +485,7 @@ export class MCPServerManager extends EventEmitter {
|
|
|
484
485
|
};
|
|
485
486
|
}
|
|
486
487
|
}
|
|
487
|
-
if (!hasTool(toolName)) {
|
|
488
|
+
if (!await hasTool(toolName)) {
|
|
488
489
|
return {
|
|
489
490
|
jsonrpc: '2.0',
|
|
490
491
|
id: message.id,
|
|
@@ -709,7 +710,7 @@ export class MCPServerManager extends EventEmitter {
|
|
|
709
710
|
// Without this the server only exposes its 4 built-in tools.
|
|
710
711
|
try {
|
|
711
712
|
const { getAllMCPTools } = await import('./mcp-client.js');
|
|
712
|
-
const registered = mcpServer.registerTools(getAllMCPTools());
|
|
713
|
+
const registered = mcpServer.registerTools(await getAllMCPTools());
|
|
713
714
|
console.error(`[monomind-mcp] HTTP/WS server registered ${registered.registered} tools`);
|
|
714
715
|
}
|
|
715
716
|
catch (e) {
|
|
@@ -5,24 +5,21 @@
|
|
|
5
5
|
* Sessions are keyed by session ID; each maps to a persistent CDP connection
|
|
6
6
|
* on the configured port (default: MONOBROWSE_CDP_PORT env var or 9222).
|
|
7
7
|
*/
|
|
8
|
-
const MAX_BROWSER_SESSIONS =
|
|
9
|
-
const SESSION_TTL_MS =
|
|
8
|
+
const MAX_BROWSER_SESSIONS = 5;
|
|
9
|
+
const SESSION_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
10
10
|
// Session registry for multi-session support (sessionId → connection)
|
|
11
11
|
const browserSessions = new Map();
|
|
12
12
|
const connectionCache = new Map();
|
|
13
|
-
function pruneExpiredSessions() {
|
|
13
|
+
async function pruneExpiredSessions() {
|
|
14
14
|
const cutoff = Date.now() - SESSION_TTL_MS;
|
|
15
|
+
const port = Number(process.env['MONOBROWSE_CDP_PORT'] ?? 9222);
|
|
15
16
|
for (const [id, info] of browserSessions) {
|
|
16
17
|
if (new Date(info.lastActivity).getTime() < cutoff) {
|
|
17
18
|
browserSessions.delete(id);
|
|
18
19
|
const conn = connectionCache.get(id);
|
|
19
|
-
if (conn) {
|
|
20
|
-
try {
|
|
21
|
-
conn.client.close();
|
|
22
|
-
}
|
|
23
|
-
catch { /* ignore */ }
|
|
24
|
-
}
|
|
25
20
|
connectionCache.delete(id);
|
|
21
|
+
if (conn)
|
|
22
|
+
await closeTarget(conn, port);
|
|
26
23
|
}
|
|
27
24
|
}
|
|
28
25
|
}
|
|
@@ -40,7 +37,9 @@ async function getConnection(sessionId) {
|
|
|
40
37
|
return conn;
|
|
41
38
|
}
|
|
42
39
|
catch {
|
|
40
|
+
const port = Number(process.env['MONOBROWSE_CDP_PORT'] ?? 9222);
|
|
43
41
|
connectionCache.delete(sessionId);
|
|
42
|
+
await closeTarget(conn, port);
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
const port = Number(process.env['MONOBROWSE_CDP_PORT'] ?? 9222);
|
|
@@ -50,16 +49,34 @@ async function getConnection(sessionId) {
|
|
|
50
49
|
connectionCache.set(sessionId, conn);
|
|
51
50
|
return conn;
|
|
52
51
|
}
|
|
53
|
-
function releaseConnection(sessionId) {
|
|
52
|
+
async function releaseConnection(sessionId) {
|
|
54
53
|
const conn = connectionCache.get(sessionId);
|
|
54
|
+
connectionCache.delete(sessionId);
|
|
55
|
+
browserSessions.delete(sessionId);
|
|
55
56
|
if (conn) {
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
const port = Number(process.env['MONOBROWSE_CDP_PORT'] ?? 9222);
|
|
58
|
+
// Close the actual Chrome tab — just closing the WebSocket leaves the
|
|
59
|
+
// renderer process alive and consuming ~250MB+ RAM each. Awaited (not
|
|
60
|
+
// fire-and-forget) so a burst of session churn can't pile up concurrent
|
|
61
|
+
// in-flight closes and leak renderers when one fails silently.
|
|
62
|
+
await closeTarget(conn, port);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function closeTarget(conn, port) {
|
|
66
|
+
try {
|
|
67
|
+
// Get the target ID for this session so we can close the tab
|
|
68
|
+
const result = await conn.client.send('Target.getTargetInfo', {}, conn.cdpSessionId);
|
|
69
|
+
const targetId = result?.targetInfo?.targetId;
|
|
70
|
+
if (targetId) {
|
|
71
|
+
// Close via HTTP endpoint — works even if the CDP session is stale
|
|
72
|
+
await fetch(`http://127.0.0.1:${port}/json/close/${encodeURIComponent(targetId)}`, { method: 'GET' });
|
|
58
73
|
}
|
|
59
|
-
catch { /* ignore */ }
|
|
60
74
|
}
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
catch { /* best-effort */ }
|
|
76
|
+
try {
|
|
77
|
+
conn.client.close();
|
|
78
|
+
}
|
|
79
|
+
catch { /* ignore */ }
|
|
63
80
|
}
|
|
64
81
|
function ok(data = {}) {
|
|
65
82
|
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
@@ -195,13 +212,22 @@ export const browserTools = [
|
|
|
195
212
|
catch (e) {
|
|
196
213
|
return fail(e.message);
|
|
197
214
|
}
|
|
198
|
-
pruneExpiredSessions();
|
|
215
|
+
await pruneExpiredSessions();
|
|
199
216
|
if (!browserSessions.has(sessionId)) {
|
|
217
|
+
// Refuse new sessions when system memory is critical
|
|
218
|
+
try {
|
|
219
|
+
const os = await import('node:os');
|
|
220
|
+
const freeRatio = os.freemem() / os.totalmem();
|
|
221
|
+
if (freeRatio < 0.10) {
|
|
222
|
+
return fail(`System memory critical (${Math.round(freeRatio * 100)}% free). Close existing browser sessions first.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch { /* non-critical */ }
|
|
200
226
|
if (browserSessions.size >= MAX_BROWSER_SESSIONS) {
|
|
201
227
|
const oldest = [...browserSessions.entries()]
|
|
202
228
|
.sort((a, b) => a[1].lastActivity.localeCompare(b[1].lastActivity))[0];
|
|
203
229
|
if (oldest)
|
|
204
|
-
releaseConnection(oldest[0]);
|
|
230
|
+
await releaseConnection(oldest[0]);
|
|
205
231
|
}
|
|
206
232
|
browserSessions.set(sessionId, {
|
|
207
233
|
sessionId,
|
|
@@ -332,7 +358,7 @@ export const browserTools = [
|
|
|
332
358
|
catch (e) {
|
|
333
359
|
return fail(e.message);
|
|
334
360
|
}
|
|
335
|
-
releaseConnection(sessionId);
|
|
361
|
+
await releaseConnection(sessionId);
|
|
336
362
|
return ok({ session: sessionId });
|
|
337
363
|
},
|
|
338
364
|
},
|
|
@@ -1075,7 +1101,7 @@ export const browserTools = [
|
|
|
1075
1101
|
tags: ['session'],
|
|
1076
1102
|
inputSchema: { type: 'object', properties: {} },
|
|
1077
1103
|
handler: async () => {
|
|
1078
|
-
pruneExpiredSessions();
|
|
1104
|
+
await pruneExpiredSessions();
|
|
1079
1105
|
const sessions = Array.from(browserSessions.values());
|
|
1080
1106
|
return ok({ sessions, count: sessions.length });
|
|
1081
1107
|
},
|
|
@@ -76,7 +76,7 @@ const CAPABILITY_CATALOG = {
|
|
|
76
76
|
},
|
|
77
77
|
'memory-knowledge': {
|
|
78
78
|
name: 'Memory & Knowledge',
|
|
79
|
-
description: 'Persistent memory with ANN vector search,
|
|
79
|
+
description: 'Persistent memory with ANN vector search, SQLite storage, and embeddings.',
|
|
80
80
|
tools: ['memory_store', 'memory_retrieve', 'memory_search', 'memory_list', 'memory_delete', 'memory_init', 'memory_export', 'memory_import', 'memory_stats', 'memory_compact', 'memory_namespace'],
|
|
81
81
|
commands: ['memory store', 'memory retrieve', 'memory search', 'memory list', 'memory delete', 'memory init'],
|
|
82
82
|
agents: ['swarm-memory-manager', 'v1-memory-specialist'],
|
|
@@ -803,7 +803,7 @@ export const hiveMindTools = [
|
|
|
803
803
|
tags: [proposal.type, proposalStrategy || 'raft', proposal.status],
|
|
804
804
|
});
|
|
805
805
|
}
|
|
806
|
-
catch { /*
|
|
806
|
+
catch { /* SQLite memory backend not available — JSON store is primary */ }
|
|
807
807
|
// Persist consensus audit record — uses MONOMIND_SESSION_SECRET when
|
|
808
808
|
// set, otherwise a per-project generated-and-persisted secret so the
|
|
809
809
|
// audit trail is populated by default (see getOrCreateSessionSecret).
|
|
@@ -1106,7 +1106,7 @@ export const hiveMindTools = [
|
|
|
1106
1106
|
namespace: 'hive-memory',
|
|
1107
1107
|
});
|
|
1108
1108
|
}
|
|
1109
|
-
catch { /*
|
|
1109
|
+
catch { /* SQLite memory backend not available */ }
|
|
1110
1110
|
return {
|
|
1111
1111
|
action,
|
|
1112
1112
|
key,
|
|
@@ -428,7 +428,7 @@ export const hooksPatternStore = {
|
|
|
428
428
|
controller,
|
|
429
429
|
implementation: controller === 'lancedb' ? 'lancedb-controller' : (storeResult.success ? 'real-hnsw-indexed' : 'memory-only'),
|
|
430
430
|
note: controller === 'lancedb'
|
|
431
|
-
? 'Pattern stored via
|
|
431
|
+
? 'Pattern stored via SQLite-backed memory bridge with HNSW indexing'
|
|
432
432
|
: (storeResult.success ? 'Pattern stored with vector embedding for semantic search' : (storeResult.error || 'Store function unavailable')),
|
|
433
433
|
};
|
|
434
434
|
},
|
|
@@ -479,7 +479,7 @@ export const hooksPatternSearch = {
|
|
|
479
479
|
})),
|
|
480
480
|
searchTimeMs: 0,
|
|
481
481
|
backend: 'lancedb',
|
|
482
|
-
note: 'Results from
|
|
482
|
+
note: 'Results from SQLite-backed memory bridge',
|
|
483
483
|
};
|
|
484
484
|
}
|
|
485
485
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { validateInput } from '../utils/input-guards.js';
|
|
5
5
|
const knowledgeIngest = {
|
|
6
6
|
name: 'knowledge_ingest',
|
|
7
|
-
description: 'Ingest documents into the Second Brain knowledge base. Accepts a file or directory path. Extracts text, chunks, embeds, and stores in
|
|
7
|
+
description: 'Ingest documents into the Second Brain knowledge base. Accepts a file or directory path. Extracts text, chunks, embeds, and stores in SQLite for semantic search.',
|
|
8
8
|
category: 'knowledge',
|
|
9
9
|
tags: ['documents', 'ingest', 'second-brain'],
|
|
10
10
|
inputSchema: {
|
|
@@ -51,7 +51,7 @@ function readGroupConfig(configPath) {
|
|
|
51
51
|
* Compute whether a repo's monograph index is stale relative to HEAD, the
|
|
52
52
|
* same way monograph_staleness does: compare the last indexed commit hash
|
|
53
53
|
* against `git rev-list --count <lastCommit>..HEAD`. Mirrors the threshold
|
|
54
|
-
* used by monograph-tools.ts (STALENESS_THRESHOLD =
|
|
54
|
+
* used by monograph-tools.ts (STALENESS_THRESHOLD = 3).
|
|
55
55
|
*/
|
|
56
56
|
function isRepoStale(db, repoPath) {
|
|
57
57
|
try {
|
|
@@ -63,7 +63,7 @@ function isRepoStale(db, repoPath) {
|
|
|
63
63
|
const out = execSync(`git rev-list --count ${lastCommit}..HEAD`, {
|
|
64
64
|
cwd: repoPath, encoding: 'utf-8',
|
|
65
65
|
}).trim();
|
|
66
|
-
return parseInt(out, 10) >
|
|
66
|
+
return parseInt(out, 10) > 3;
|
|
67
67
|
}
|
|
68
68
|
catch {
|
|
69
69
|
return false;
|