monomind 2.0.3 → 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 +11 -7
- package/packages/@monomind/cli/.claude/helpers/control-start.cjs +13 -20
- package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +109 -6
- package/packages/@monomind/cli/.claude/helpers/graphify-freshen.cjs +19 -17
- package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +60 -28
- package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +99 -28
- package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +27 -9
- package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +18 -9
- package/packages/@monomind/cli/.claude/helpers/handlers/loops-status-handler.cjs +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +33 -4
- package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +75 -45
- package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +0 -12
- package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +53 -22
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +75 -4
- package/packages/@monomind/cli/.claude/helpers/intelligence.cjs +94 -15
- package/packages/@monomind/cli/.claude/helpers/session.cjs +6 -1
- package/packages/@monomind/cli/.claude/helpers/statusline.cjs +10 -10
- package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +3 -3
- package/packages/@monomind/cli/.claude/helpers/utils/agent-registrations.cjs +41 -0
- package/packages/@monomind/cli/.claude/helpers/utils/fs-helpers.cjs +183 -0
- package/packages/@monomind/cli/.claude/helpers/utils/micro-agents.cjs +10 -6
- package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
- package/packages/@monomind/cli/.claude/helpers/utils/telemetry.cjs +35 -19
- package/packages/@monomind/cli/README.md +74 -92
- package/packages/@monomind/cli/bin/cli.js +10 -1
- package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/commands/agent-ops.js +9 -15
- package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/cleanup.js +20 -4
- package/packages/@monomind/cli/dist/src/commands/completions.js +66 -261
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
- package/packages/@monomind/cli/dist/src/commands/doctor.js +7 -2
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +7 -0
- package/packages/@monomind/cli/dist/src/commands/index.js +3 -0
- package/packages/@monomind/cli/dist/src/commands/mcp.js +11 -6
- package/packages/@monomind/cli/dist/src/commands/memory-admin.js +12 -6
- package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +6 -13
- package/packages/@monomind/cli/dist/src/commands/monograph.js +3 -3
- package/packages/@monomind/cli/dist/src/commands/org.d.ts +3 -1
- package/packages/@monomind/cli/dist/src/commands/org.js +321 -127
- package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/start.js +142 -37
- package/packages/@monomind/cli/dist/src/commands/tokens.js +21 -3
- package/packages/@monomind/cli/dist/src/config-adapter.js +37 -17
- package/packages/@monomind/cli/dist/src/index.js +64 -28
- package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +44 -11
- package/packages/@monomind/cli/dist/src/init/executor.js +93 -55
- package/packages/@monomind/cli/dist/src/mcp-client.d.ts +8 -3
- package/packages/@monomind/cli/dist/src/mcp-client.js +37 -3
- package/packages/@monomind/cli/dist/src/mcp-server.js +8 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.d.ts +20 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +10 -5
- 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/github-tools.js +30 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/graphify-tools.js +11 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +56 -35
- package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +9 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +56 -14
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +88 -41
- 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/mcp-tools/swarm-tools.js +6 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/types.d.ts +20 -0
- package/packages/@monomind/cli/dist/src/mcp-tools/types.js +36 -1
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.d.ts +13 -1
- package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +66 -14
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +99 -3
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +20 -0
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +26 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.js +73 -0
- 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 +46 -0
- package/packages/@monomind/cli/dist/src/orgrt/daemon.js +201 -18
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.d.ts +10 -5
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +138 -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/provider.js +1 -0
- package/packages/@monomind/cli/dist/src/orgrt/scheduler.d.ts +13 -0
- package/packages/@monomind/cli/dist/src/orgrt/scheduler.js +48 -0
- package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/orgrt/server.js +39 -0
- 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.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +108 -0
- 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 +22 -7
- package/packages/@monomind/cli/dist/src/parser.d.ts +32 -0
- package/packages/@monomind/cli/dist/src/parser.js +130 -5
- package/packages/@monomind/cli/dist/src/routing/embed-worker.js +13 -1
- package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +31 -0
- package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +21 -0
- package/packages/@monomind/cli/dist/src/services/config-file-manager.js +60 -7
- package/packages/@monomind/cli/dist/src/services/crash-reporter.js +2 -1
- package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +243 -49
- package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
- package/packages/@monomind/cli/dist/src/ui/orgs.html +79 -11
- package/packages/@monomind/cli/dist/src/ui/server.mjs +346 -139
- package/packages/@monomind/cli/dist/src/utils/input-guards.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/utils/input-guards.js +39 -5
- package/packages/@monomind/cli/package.json +15 -15
|
@@ -69,8 +69,8 @@ export declare const CoherenceInputSchema: z.ZodObject<{
|
|
|
69
69
|
vectors: z.ZodArray<z.ZodArray<z.ZodNumber, "many">, "many">;
|
|
70
70
|
threshold: z.ZodDefault<z.ZodNumber>;
|
|
71
71
|
}, "strip", z.ZodTypeAny, {
|
|
72
|
-
threshold: number;
|
|
73
72
|
vectors: number[][];
|
|
73
|
+
threshold: number;
|
|
74
74
|
}, {
|
|
75
75
|
vectors: number[][];
|
|
76
76
|
threshold?: number | undefined;
|
|
@@ -98,10 +98,10 @@ export declare const SpectralInputSchema: z.ZodObject<{
|
|
|
98
98
|
analyzeType: z.ZodDefault<z.ZodEnum<["stability", "clustering", "connectivity"]>>;
|
|
99
99
|
}, "strip", z.ZodTypeAny, {
|
|
100
100
|
matrix: number[][];
|
|
101
|
-
analyzeType: "
|
|
101
|
+
analyzeType: "clustering" | "connectivity" | "stability";
|
|
102
102
|
}, {
|
|
103
103
|
matrix: number[][];
|
|
104
|
-
analyzeType?: "
|
|
104
|
+
analyzeType?: "clustering" | "connectivity" | "stability" | undefined;
|
|
105
105
|
}>;
|
|
106
106
|
export type SpectralInput = z.infer<typeof SpectralInputSchema>;
|
|
107
107
|
export interface SpectralResult {
|
|
@@ -150,15 +150,15 @@ export declare const CausalInputSchema: z.ZodObject<{
|
|
|
150
150
|
nodes: string[];
|
|
151
151
|
edges: [string, string][];
|
|
152
152
|
};
|
|
153
|
-
outcome: string;
|
|
154
153
|
intervention: string;
|
|
154
|
+
outcome: string;
|
|
155
155
|
}, {
|
|
156
156
|
graph: {
|
|
157
157
|
nodes: string[];
|
|
158
158
|
edges: [string, string][];
|
|
159
159
|
};
|
|
160
|
-
outcome: string;
|
|
161
160
|
intervention: string;
|
|
161
|
+
outcome: string;
|
|
162
162
|
}>;
|
|
163
163
|
export type CausalInput = z.infer<typeof CausalInputSchema>;
|
|
164
164
|
export interface CausalResult {
|
|
@@ -185,13 +185,13 @@ export declare const AgentStateSchema: z.ZodObject<{
|
|
|
185
185
|
}, "strip", z.ZodTypeAny, {
|
|
186
186
|
agentId: string;
|
|
187
187
|
embedding: number[];
|
|
188
|
-
metadata?: Record<string, unknown> | undefined;
|
|
189
188
|
vote?: string | undefined;
|
|
189
|
+
metadata?: Record<string, unknown> | undefined;
|
|
190
190
|
}, {
|
|
191
191
|
agentId: string;
|
|
192
192
|
embedding: number[];
|
|
193
|
-
metadata?: Record<string, unknown> | undefined;
|
|
194
193
|
vote?: string | undefined;
|
|
194
|
+
metadata?: Record<string, unknown> | undefined;
|
|
195
195
|
}>;
|
|
196
196
|
export type AgentState = z.infer<typeof AgentStateSchema>;
|
|
197
197
|
export declare const ConsensusInputSchema: z.ZodObject<{
|
|
@@ -203,29 +203,29 @@ export declare const ConsensusInputSchema: z.ZodObject<{
|
|
|
203
203
|
}, "strip", z.ZodTypeAny, {
|
|
204
204
|
agentId: string;
|
|
205
205
|
embedding: number[];
|
|
206
|
-
metadata?: Record<string, unknown> | undefined;
|
|
207
206
|
vote?: string | undefined;
|
|
207
|
+
metadata?: Record<string, unknown> | undefined;
|
|
208
208
|
}, {
|
|
209
209
|
agentId: string;
|
|
210
210
|
embedding: number[];
|
|
211
|
-
metadata?: Record<string, unknown> | undefined;
|
|
212
211
|
vote?: string | undefined;
|
|
212
|
+
metadata?: Record<string, unknown> | undefined;
|
|
213
213
|
}>, "many">;
|
|
214
214
|
threshold: z.ZodDefault<z.ZodNumber>;
|
|
215
215
|
}, "strip", z.ZodTypeAny, {
|
|
216
|
-
threshold: number;
|
|
217
216
|
agentStates: {
|
|
218
217
|
agentId: string;
|
|
219
218
|
embedding: number[];
|
|
220
|
-
metadata?: Record<string, unknown> | undefined;
|
|
221
219
|
vote?: string | undefined;
|
|
220
|
+
metadata?: Record<string, unknown> | undefined;
|
|
222
221
|
}[];
|
|
222
|
+
threshold: number;
|
|
223
223
|
}, {
|
|
224
224
|
agentStates: {
|
|
225
225
|
agentId: string;
|
|
226
226
|
embedding: number[];
|
|
227
|
-
metadata?: Record<string, unknown> | undefined;
|
|
228
227
|
vote?: string | undefined;
|
|
228
|
+
metadata?: Record<string, unknown> | undefined;
|
|
229
229
|
}[];
|
|
230
230
|
threshold?: number | undefined;
|
|
231
231
|
}>;
|
|
@@ -247,11 +247,11 @@ export declare const SimplexSchema: z.ZodObject<{
|
|
|
247
247
|
vertices: z.ZodArray<z.ZodNumber, "many">;
|
|
248
248
|
dimension: z.ZodNumber;
|
|
249
249
|
}, "strip", z.ZodTypeAny, {
|
|
250
|
-
dimension: number;
|
|
251
250
|
vertices: number[];
|
|
252
|
-
}, {
|
|
253
251
|
dimension: number;
|
|
252
|
+
}, {
|
|
254
253
|
vertices: number[];
|
|
254
|
+
dimension: number;
|
|
255
255
|
}>;
|
|
256
256
|
export type Simplex = z.infer<typeof SimplexSchema>;
|
|
257
257
|
export declare const SimplicialComplexSchema: z.ZodObject<{
|
|
@@ -260,25 +260,25 @@ export declare const SimplicialComplexSchema: z.ZodObject<{
|
|
|
260
260
|
vertices: z.ZodArray<z.ZodNumber, "many">;
|
|
261
261
|
dimension: z.ZodNumber;
|
|
262
262
|
}, "strip", z.ZodTypeAny, {
|
|
263
|
-
dimension: number;
|
|
264
263
|
vertices: number[];
|
|
265
|
-
}, {
|
|
266
264
|
dimension: number;
|
|
265
|
+
}, {
|
|
267
266
|
vertices: number[];
|
|
267
|
+
dimension: number;
|
|
268
268
|
}>, "many">>;
|
|
269
269
|
maxDimension: z.ZodDefault<z.ZodNumber>;
|
|
270
270
|
}, "strip", z.ZodTypeAny, {
|
|
271
271
|
vertices: number[][];
|
|
272
|
-
maxDimension: number;
|
|
273
272
|
simplices?: {
|
|
274
|
-
dimension: number;
|
|
275
273
|
vertices: number[];
|
|
274
|
+
dimension: number;
|
|
276
275
|
}[] | undefined;
|
|
276
|
+
maxDimension: number;
|
|
277
277
|
}, {
|
|
278
278
|
vertices: number[][];
|
|
279
279
|
simplices?: {
|
|
280
|
-
dimension: number;
|
|
281
280
|
vertices: number[];
|
|
281
|
+
dimension: number;
|
|
282
282
|
}[] | undefined;
|
|
283
283
|
maxDimension?: number | undefined;
|
|
284
284
|
}>;
|
|
@@ -290,43 +290,43 @@ export declare const TopologyInputSchema: z.ZodObject<{
|
|
|
290
290
|
vertices: z.ZodArray<z.ZodNumber, "many">;
|
|
291
291
|
dimension: z.ZodNumber;
|
|
292
292
|
}, "strip", z.ZodTypeAny, {
|
|
293
|
-
dimension: number;
|
|
294
293
|
vertices: number[];
|
|
295
|
-
}, {
|
|
296
294
|
dimension: number;
|
|
295
|
+
}, {
|
|
297
296
|
vertices: number[];
|
|
297
|
+
dimension: number;
|
|
298
298
|
}>, "many">>;
|
|
299
299
|
maxDimension: z.ZodDefault<z.ZodNumber>;
|
|
300
300
|
}, "strip", z.ZodTypeAny, {
|
|
301
301
|
vertices: number[][];
|
|
302
|
-
maxDimension: number;
|
|
303
302
|
simplices?: {
|
|
304
|
-
dimension: number;
|
|
305
303
|
vertices: number[];
|
|
304
|
+
dimension: number;
|
|
306
305
|
}[] | undefined;
|
|
306
|
+
maxDimension: number;
|
|
307
307
|
}, {
|
|
308
308
|
vertices: number[][];
|
|
309
309
|
simplices?: {
|
|
310
|
-
dimension: number;
|
|
311
310
|
vertices: number[];
|
|
311
|
+
dimension: number;
|
|
312
312
|
}[] | undefined;
|
|
313
313
|
maxDimension?: number | undefined;
|
|
314
314
|
}>;
|
|
315
315
|
}, "strip", z.ZodTypeAny, {
|
|
316
316
|
complex: {
|
|
317
317
|
vertices: number[][];
|
|
318
|
-
maxDimension: number;
|
|
319
318
|
simplices?: {
|
|
320
|
-
dimension: number;
|
|
321
319
|
vertices: number[];
|
|
320
|
+
dimension: number;
|
|
322
321
|
}[] | undefined;
|
|
322
|
+
maxDimension: number;
|
|
323
323
|
};
|
|
324
324
|
}, {
|
|
325
325
|
complex: {
|
|
326
326
|
vertices: number[][];
|
|
327
327
|
simplices?: {
|
|
328
|
-
dimension: number;
|
|
329
328
|
vertices: number[];
|
|
329
|
+
dimension: number;
|
|
330
330
|
}[] | undefined;
|
|
331
331
|
maxDimension?: number | undefined;
|
|
332
332
|
};
|
|
@@ -362,27 +362,27 @@ export declare const MemoryGateInputSchema: z.ZodObject<{
|
|
|
362
362
|
reject: z.ZodDefault<z.ZodNumber>;
|
|
363
363
|
warn: z.ZodDefault<z.ZodNumber>;
|
|
364
364
|
}, "strip", z.ZodTypeAny, {
|
|
365
|
-
warn: number;
|
|
366
365
|
reject: number;
|
|
366
|
+
warn: number;
|
|
367
367
|
}, {
|
|
368
|
-
warn?: number | undefined;
|
|
369
368
|
reject?: number | undefined;
|
|
369
|
+
warn?: number | undefined;
|
|
370
370
|
}>>;
|
|
371
371
|
}, "strip", z.ZodTypeAny, {
|
|
372
372
|
key: string;
|
|
373
373
|
value?: unknown;
|
|
374
374
|
existingVectors?: number[][] | undefined;
|
|
375
375
|
thresholds?: {
|
|
376
|
-
warn: number;
|
|
377
376
|
reject: number;
|
|
377
|
+
warn: number;
|
|
378
378
|
} | undefined;
|
|
379
379
|
}, {
|
|
380
380
|
key: string;
|
|
381
381
|
value?: unknown;
|
|
382
382
|
existingVectors?: number[][] | undefined;
|
|
383
383
|
thresholds?: {
|
|
384
|
-
warn?: number | undefined;
|
|
385
384
|
reject?: number | undefined;
|
|
385
|
+
warn?: number | undefined;
|
|
386
386
|
} | undefined;
|
|
387
387
|
}>;
|
|
388
388
|
export type MemoryGateInput = z.infer<typeof MemoryGateInputSchema>;
|
|
@@ -60,6 +60,18 @@ function runSafe(cmd, args, cwd) {
|
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
/** Run a `gh` command and preserve the real failure reason instead of collapsing to null. */
|
|
64
|
+
function runSafeResult(cmd, args, cwd) {
|
|
65
|
+
try {
|
|
66
|
+
const stdout = execFileSync(cmd, args, { encoding: 'utf-8', timeout: 15000, cwd: cwd || getProjectCwd(), stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
67
|
+
return { ok: true, stdout };
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
const e = err;
|
|
71
|
+
const stderr = e.stderr ? String(e.stderr).trim() : '';
|
|
72
|
+
return { ok: false, error: stderr || e.message || 'gh command failed' };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
63
75
|
/** Check if gh CLI is available */
|
|
64
76
|
function hasGhCli() {
|
|
65
77
|
return run('gh --version') !== null;
|
|
@@ -216,7 +228,11 @@ export const githubTools = [
|
|
|
216
228
|
}
|
|
217
229
|
// Fallback: local store
|
|
218
230
|
const prId = `pr-${Date.now()}`;
|
|
219
|
-
|
|
231
|
+
// Locally-assigned PR number, independent of the timestamp-based key —
|
|
232
|
+
// monotonic within this store so lookups by number are unambiguous.
|
|
233
|
+
const existingNumbers = Object.values(store.prs).map(p => p.number || 0);
|
|
234
|
+
const nextNumber = existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1;
|
|
235
|
+
const pr = { id: prId, number: nextNumber, title, status: 'open', branch: headBranch, baseBranch, createdAt: new Date().toISOString() };
|
|
220
236
|
store.prs[prId] = pr;
|
|
221
237
|
saveGitHubStore(store);
|
|
222
238
|
return { success: true, source: 'local-store', action: 'created', pullRequest: pr };
|
|
@@ -241,13 +257,17 @@ export const githubTools = [
|
|
|
241
257
|
if (!prNumber)
|
|
242
258
|
return { success: false, error: 'prNumber is required and must be a positive integer for merge.' };
|
|
243
259
|
if (gh) {
|
|
244
|
-
|
|
245
|
-
|
|
260
|
+
// gh CLI is actually installed — trust its real exit status. A genuine
|
|
261
|
+
// failure (branch protection, conflicts, auth) must be reported as a
|
|
262
|
+
// failure, not silently swallowed into the local-store simulation.
|
|
263
|
+
const result = runSafeResult('gh', ['pr', 'merge', String(prNumber), '--merge']);
|
|
264
|
+
if (result.ok) {
|
|
246
265
|
return { success: true, _real: true, action: 'merged', prNumber, mergedAt: new Date().toISOString() };
|
|
247
266
|
}
|
|
267
|
+
return { success: false, error: result.error };
|
|
248
268
|
}
|
|
249
|
-
// Fallback: local store
|
|
250
|
-
const prKey = Object.keys(store.prs).find(k => k.
|
|
269
|
+
// Fallback: local store (only reached when gh CLI is not installed at all)
|
|
270
|
+
const prKey = Object.keys(store.prs).find(k => store.prs[k].number === prNumber);
|
|
251
271
|
if (prKey && store.prs[prKey]) {
|
|
252
272
|
store.prs[prKey].status = 'merged';
|
|
253
273
|
saveGitHubStore(store);
|
|
@@ -259,12 +279,14 @@ export const githubTools = [
|
|
|
259
279
|
if (!prNumber)
|
|
260
280
|
return { success: false, error: 'prNumber is required and must be a positive integer for close.' };
|
|
261
281
|
if (gh) {
|
|
262
|
-
const result =
|
|
263
|
-
if (result
|
|
282
|
+
const result = runSafeResult('gh', ['pr', 'close', String(prNumber)]);
|
|
283
|
+
if (result.ok) {
|
|
264
284
|
return { success: true, _real: true, action: 'closed', prNumber, closedAt: new Date().toISOString() };
|
|
265
285
|
}
|
|
286
|
+
return { success: false, error: result.error };
|
|
266
287
|
}
|
|
267
|
-
|
|
288
|
+
// Fallback: local store (only reached when gh CLI is not installed at all)
|
|
289
|
+
const prKey = Object.keys(store.prs).find(k => store.prs[k].number === prNumber);
|
|
268
290
|
if (prKey && store.prs[prKey]) {
|
|
269
291
|
store.prs[prKey].status = 'closed';
|
|
270
292
|
saveGitHubStore(store);
|
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
* All graphify_* tools are deprecated. They proxy to monograph_* tools.
|
|
5
5
|
* Will be removed in next major release.
|
|
6
6
|
*/
|
|
7
|
-
import { allMonographTools } from './monograph-tools.js';
|
|
7
|
+
import { allMonographTools, monographTools } from './monograph-tools.js';
|
|
8
|
+
// Advanced monograph tools are gated behind MONOGRAPH_MCP_ADVANCED=1 (see
|
|
9
|
+
// monograph-tools.ts). Shims that target an advanced-tier tool must be gated
|
|
10
|
+
// the same way, otherwise they re-expose advanced tools under a different
|
|
11
|
+
// name regardless of the flag. `monographTools` is the already-gated export
|
|
12
|
+
// (core-only unless MONOGRAPH_MCP_ADVANCED=1); a target is "advanced" if it's
|
|
13
|
+
// present in allMonographTools but absent from monographTools.
|
|
14
|
+
const exposedMonographNames = new Set(monographTools.map(t => t.name));
|
|
8
15
|
function findMonographTool(name) {
|
|
9
16
|
const tool = allMonographTools.find(t => t.name === name);
|
|
10
17
|
if (!tool)
|
|
@@ -12,6 +19,8 @@ function findMonographTool(name) {
|
|
|
12
19
|
return tool;
|
|
13
20
|
}
|
|
14
21
|
function shimTool(graphifyName, monographName, paramMap) {
|
|
22
|
+
if (!exposedMonographNames.has(monographName))
|
|
23
|
+
return null;
|
|
15
24
|
const target = findMonographTool(monographName);
|
|
16
25
|
return {
|
|
17
26
|
name: graphifyName,
|
|
@@ -44,6 +53,6 @@ export const graphifyTools = [
|
|
|
44
53
|
shimTool('graphify_report', 'monograph_report'),
|
|
45
54
|
// Bug fix: graphify_health previously referenced `files.length` (ReferenceError) — now delegates cleanly
|
|
46
55
|
shimTool('graphify_health', 'monograph_health'),
|
|
47
|
-
];
|
|
56
|
+
].filter((t) => t !== null);
|
|
48
57
|
export default graphifyTools;
|
|
49
58
|
//# sourceMappingURL=graphify-tools.js.map
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
import { existsSync, readFileSync, statSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
|
|
14
14
|
import { randomBytes } from 'node:crypto';
|
|
15
15
|
import { join } from 'node:path';
|
|
16
|
-
import { getProjectCwd } from './types.js';
|
|
16
|
+
import { getProjectCwd, getMonomindDataRoot, migrateLegacyStoreFile } from './types.js';
|
|
17
17
|
import { weightedTally } from '../consensus/tally.js';
|
|
18
|
+
// Reuse agent-tools.ts's hardened store loader (50MB size cap + __proto__
|
|
19
|
+
// rejection) instead of maintaining a second, weaker copy that reads the
|
|
20
|
+
// same physical file — see loadAgentStore export note there.
|
|
21
|
+
import { loadAgentStore } from './agent-tools.js';
|
|
18
22
|
// Storage paths
|
|
19
23
|
const STORAGE_DIR = '.monomind';
|
|
20
24
|
const HIVE_DIR = 'hive-mind';
|
|
@@ -92,7 +96,7 @@ function tryResolveProposal(proposal, totalNodes) {
|
|
|
92
96
|
return null;
|
|
93
97
|
}
|
|
94
98
|
function getHiveDir() {
|
|
95
|
-
return join(
|
|
99
|
+
return join(getMonomindDataRoot(), HIVE_DIR);
|
|
96
100
|
}
|
|
97
101
|
function getHivePath() {
|
|
98
102
|
return join(getHiveDir(), HIVE_FILE);
|
|
@@ -107,6 +111,7 @@ const MAX_HIVE_STATE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
|
107
111
|
function loadHiveState() {
|
|
108
112
|
try {
|
|
109
113
|
const path = getHivePath();
|
|
114
|
+
migrateLegacyStoreFile(path, join(HIVE_DIR, HIVE_FILE));
|
|
110
115
|
if (existsSync(path) && statSync(path).size <= MAX_HIVE_STATE_BYTES) {
|
|
111
116
|
const data = readFileSync(path, 'utf-8');
|
|
112
117
|
return JSON.parse(data);
|
|
@@ -176,21 +181,10 @@ function getOrCreateSessionSecret() {
|
|
|
176
181
|
}
|
|
177
182
|
}
|
|
178
183
|
// Import agent store helpers for spawn functionality
|
|
179
|
-
import { existsSync as agentStoreExists,
|
|
180
|
-
// Canonical agent store path matches agent-tools.ts: .monomind/agents/store.json
|
|
181
|
-
function loadAgentStore() {
|
|
182
|
-
const storePath = join(getProjectCwd(), '.monomind', 'agents', 'store.json');
|
|
183
|
-
try {
|
|
184
|
-
if (agentStoreExists(storePath)) {
|
|
185
|
-
return JSON.parse(readAgentStore(storePath, 'utf-8'));
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
catch { /* ignore */ }
|
|
189
|
-
return { agents: {} };
|
|
190
|
-
}
|
|
184
|
+
import { existsSync as agentStoreExists, writeFileSync as writeAgentStore, mkdirSync as mkdirAgentStore } from 'node:fs';
|
|
191
185
|
const HIVE_RESERVED_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
192
186
|
function saveAgentStore(store) {
|
|
193
|
-
const storeDir = join(
|
|
187
|
+
const storeDir = join(getMonomindDataRoot(), 'agents');
|
|
194
188
|
if (!agentStoreExists(storeDir)) {
|
|
195
189
|
mkdirAgentStore(storeDir, { recursive: true });
|
|
196
190
|
}
|
|
@@ -284,6 +278,10 @@ export const hiveMindTools = [
|
|
|
284
278
|
properties: {
|
|
285
279
|
topology: { type: 'string', enum: ['mesh', 'hierarchical', 'ring', 'star'], description: 'Network topology' },
|
|
286
280
|
queenId: { type: 'string', description: 'Initial queen agent ID' },
|
|
281
|
+
consensus: { type: 'string', enum: ['byzantine', 'bft', 'raft', 'quorum'], description: 'Consensus strategy to govern hive-mind_consensus propose/vote (gossip/crdt are planned but not implemented and fall back to byzantine). Default: byzantine.' },
|
|
282
|
+
maxAgents: { type: 'number', description: 'Maximum number of agents in the hive. Default: 15.' },
|
|
283
|
+
persist: { type: 'boolean', description: 'Whether to persist hive state to disk. Default: true.' },
|
|
284
|
+
memoryBackend: { type: 'string', description: 'Shared memory backend for the hive. Default: hybrid.' },
|
|
287
285
|
},
|
|
288
286
|
},
|
|
289
287
|
handler: async (input) => {
|
|
@@ -294,32 +292,34 @@ export const hiveMindTools = [
|
|
|
294
292
|
const queenId = typeof rawQueenId === 'string' && rawQueenId.length > MAX_QUEEN_ID_LEN
|
|
295
293
|
? rawQueenId.slice(0, MAX_QUEEN_ID_LEN) : rawQueenId;
|
|
296
294
|
const now = new Date().toISOString();
|
|
295
|
+
// Validate consensus strategy: gossip and crdt are planned but not implemented
|
|
296
|
+
const SUPPORTED_CONSENSUS = ['byzantine', 'bft', 'raft', 'quorum'];
|
|
297
|
+
const PLANNED_CONSENSUS = ['gossip', 'crdt'];
|
|
298
|
+
const requestedConsensus = input.consensus || 'byzantine';
|
|
299
|
+
const consensusWarning = PLANNED_CONSENSUS.includes(requestedConsensus)
|
|
300
|
+
? `Strategy "${requestedConsensus}" is planned but not yet implemented; defaulting to "byzantine".`
|
|
301
|
+
: undefined;
|
|
302
|
+
const effectiveConsensus = PLANNED_CONSENSUS.includes(requestedConsensus)
|
|
303
|
+
? 'byzantine'
|
|
304
|
+
: (SUPPORTED_CONSENSUS.includes(requestedConsensus) ? requestedConsensus : 'byzantine');
|
|
297
305
|
const state = {
|
|
298
306
|
initialized: true,
|
|
299
307
|
hiveId,
|
|
300
308
|
topology: input.topology || 'mesh',
|
|
301
309
|
queen: { agentId: queenId, electedAt: now, term: 1 },
|
|
302
310
|
workers: [],
|
|
311
|
+
// Persist the chosen strategy on the hive state so hive-mind_consensus
|
|
312
|
+
// propose/vote default to it instead of silently using 'raft'.
|
|
313
|
+
// 'byzantine' is the CLI-facing name; the internal ConsensusStrategy type uses 'bft'.
|
|
314
|
+
consensusStrategy: (effectiveConsensus === 'byzantine' ? 'bft' : effectiveConsensus),
|
|
303
315
|
consensus: { pending: [], history: [] },
|
|
304
316
|
sharedMemory: {},
|
|
305
317
|
createdAt: now,
|
|
306
318
|
updatedAt: now,
|
|
307
319
|
};
|
|
308
|
-
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
const PLANNED_CONSENSUS = ['gossip', 'crdt'];
|
|
312
|
-
const requestedConsensus = input.consensus || 'byzantine';
|
|
313
|
-
const consensusWarning = PLANNED_CONSENSUS.includes(requestedConsensus)
|
|
314
|
-
? `Strategy "${requestedConsensus}" is planned but not yet implemented; defaulting to "byzantine".`
|
|
315
|
-
: undefined;
|
|
316
|
-
const effectiveConsensus = PLANNED_CONSENSUS.includes(requestedConsensus)
|
|
317
|
-
? 'byzantine'
|
|
318
|
-
: (SUPPORTED_CONSENSUS.includes(requestedConsensus) ? requestedConsensus : 'byzantine');
|
|
319
|
-
// Persist the chosen strategy on the hive state so hive-mind_consensus
|
|
320
|
-
// propose/vote default to it instead of silently using 'raft'.
|
|
321
|
-
// 'byzantine' is the CLI-facing name; the internal ConsensusStrategy type uses 'bft'.
|
|
322
|
-
state.consensusStrategy = (effectiveConsensus === 'byzantine' ? 'bft' : effectiveConsensus);
|
|
320
|
+
// Single write — a prior version of this handler saved state twice
|
|
321
|
+
// (once before setting consensusStrategy, once after), which was
|
|
322
|
+
// redundant.
|
|
323
323
|
saveHiveState(state);
|
|
324
324
|
return {
|
|
325
325
|
success: true,
|
|
@@ -357,7 +357,8 @@ export const hiveMindTools = [
|
|
|
357
357
|
// Load agent store once for all workers
|
|
358
358
|
const agentStore = loadAgentStore();
|
|
359
359
|
// Compute real task metrics from task store
|
|
360
|
-
const taskStorePath = join(
|
|
360
|
+
const taskStorePath = join(getMonomindDataRoot(), 'tasks', 'store.json');
|
|
361
|
+
migrateLegacyStoreFile(taskStorePath, join('tasks', 'store.json'));
|
|
361
362
|
let pendingTaskCount = 0;
|
|
362
363
|
let activeTaskCount = 0;
|
|
363
364
|
let completedTaskCount = 0;
|
|
@@ -382,7 +383,14 @@ export const hiveMindTools = [
|
|
|
382
383
|
hiveId: state.hiveId ?? `hive-${state.createdAt ? new Date(state.createdAt).getTime() : Date.now()}`,
|
|
383
384
|
status: state.initialized ? 'active' : 'offline',
|
|
384
385
|
topology: state.topology,
|
|
385
|
-
|
|
386
|
+
// Reflect the strategy actually chosen at hive-mind_init (persisted
|
|
387
|
+
// as state.consensusStrategy so it "actually governs voting" — see
|
|
388
|
+
// the field's doc comment) instead of hardcoding a default that
|
|
389
|
+
// ignored what was configured. 'bft' is the internal name for the
|
|
390
|
+
// CLI-facing 'byzantine' strategy.
|
|
391
|
+
consensus: state.consensusStrategy
|
|
392
|
+
? (state.consensusStrategy === 'bft' ? 'byzantine' : state.consensusStrategy)
|
|
393
|
+
: 'byzantine',
|
|
386
394
|
queen: state.queen ? {
|
|
387
395
|
id: state.queen.agentId,
|
|
388
396
|
agentId: state.queen.agentId,
|
|
@@ -398,7 +406,11 @@ export const hiveMindTools = [
|
|
|
398
406
|
id: w,
|
|
399
407
|
type: agent?.agentType || 'worker',
|
|
400
408
|
status: agent?.status || 'unknown',
|
|
401
|
-
|
|
409
|
+
// AgentRecord has no currentTask field — always null. Kept in the
|
|
410
|
+
// response shape for API stability; was already dead before this
|
|
411
|
+
// (the previous `as unknown as Record<string, unknown>` cast hid
|
|
412
|
+
// that `agent?.currentTask` never matched a real field).
|
|
413
|
+
currentTask: null,
|
|
402
414
|
tasksCompleted: agent?.taskCount || 0,
|
|
403
415
|
};
|
|
404
416
|
}),
|
|
@@ -729,9 +741,18 @@ export const hiveMindTools = [
|
|
|
729
741
|
confidence: 1.0, // uniform until confidence-probe is wired
|
|
730
742
|
}));
|
|
731
743
|
const cpwbftTally = weightedTally(weightedVotes);
|
|
732
|
-
// O-Information gate: defer resolution if we haven't seen enough divergent rounds
|
|
744
|
+
// O-Information gate: defer resolution if we haven't seen enough divergent rounds.
|
|
745
|
+
// BUT: if every expected voter has already cast a vote (electorate
|
|
746
|
+
// exhausted), no more votes can ever arrive to produce a divergent
|
|
747
|
+
// round — a unanimous first-round vote would otherwise deadlock the
|
|
748
|
+
// proposal permanently since divergenceRoundsSeen only increments on
|
|
749
|
+
// disagreement. Treat electorate exhaustion as a terminal condition
|
|
750
|
+
// that opens the gate regardless of divergence.
|
|
751
|
+
const totalVotesCast = Object.keys(proposal.votes).length;
|
|
752
|
+
const electorateExhausted = totalNodes > 0 && totalVotesCast >= totalNodes;
|
|
733
753
|
const divergenceGateOpen = !proposal.minDivergenceRounds
|
|
734
|
-
|| (proposal.divergenceRoundsSeen ?? 0) >= proposal.minDivergenceRounds
|
|
754
|
+
|| (proposal.divergenceRoundsSeen ?? 0) >= proposal.minDivergenceRounds
|
|
755
|
+
|| electorateExhausted;
|
|
735
756
|
// Try to resolve
|
|
736
757
|
const resolution = divergenceGateOpen ? tryResolveProposal(proposal, totalNodes) : null;
|
|
737
758
|
let resolved = false;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Knowledge Tools — Second Brain document ingest and search
|
|
3
3
|
*/
|
|
4
|
+
import { validateInput } from '../utils/input-guards.js';
|
|
4
5
|
const knowledgeIngest = {
|
|
5
6
|
name: 'knowledge_ingest',
|
|
6
7
|
description: 'Ingest documents into the Second Brain knowledge base. Accepts a file or directory path. Extracts text, chunks, embeds, and stores in LanceDB for semantic search.',
|
|
@@ -15,10 +16,17 @@ const knowledgeIngest = {
|
|
|
15
16
|
required: ['path'],
|
|
16
17
|
},
|
|
17
18
|
handler: async (input) => {
|
|
19
|
+
const pathCheck = validateInput(input.path, { type: 'path' });
|
|
20
|
+
if (!pathCheck.valid) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: pathCheck.error }) }],
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
18
26
|
const { ingestDocument, ingestDirectory } = await import('../knowledge/document-pipeline.js');
|
|
19
27
|
const fs = await import('node:fs');
|
|
20
28
|
const pathMod = await import('node:path');
|
|
21
|
-
const target = pathMod.resolve(
|
|
29
|
+
const target = pathMod.resolve(pathCheck.sanitized);
|
|
22
30
|
const scope = String(input.scope || 'shared');
|
|
23
31
|
try {
|
|
24
32
|
const stat = fs.statSync(target);
|
|
@@ -6,26 +6,67 @@
|
|
|
6
6
|
* moved to the real package.
|
|
7
7
|
*/
|
|
8
8
|
import { join, resolve, relative } from 'path';
|
|
9
|
-
import { existsSync,
|
|
10
|
-
import {
|
|
9
|
+
import { existsSync, statSync } from 'fs';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { openDb, closeDb, countNodes, parseGroupConfig } from '@monoes/monograph';
|
|
12
|
+
import { getProjectCwd } from './types.js';
|
|
13
|
+
import { realOrResolved } from '../utils/input-guards.js';
|
|
14
|
+
// ── Group config reader ───────────────────────────────────────────────────────
|
|
11
15
|
const MAX_GROUP_CONFIG_BYTES = 1 * 1024 * 1024; // 1 MB
|
|
16
|
+
/**
|
|
17
|
+
* Read repos from a group.yaml config (the real group config format used by
|
|
18
|
+
* monograph_group_query / monograph_group_sync / monograph_group_list — see
|
|
19
|
+
* @monoes/monograph's groups/group-config.ts).
|
|
20
|
+
*
|
|
21
|
+
* Throws on an out-of-bounds or oversized path instead of silently returning
|
|
22
|
+
* an empty list, so callers can distinguish "no groups configured" from
|
|
23
|
+
* "your repoPath was rejected".
|
|
24
|
+
*/
|
|
12
25
|
function readGroupConfig(configPath) {
|
|
13
26
|
if (!existsSync(configPath))
|
|
14
27
|
return [];
|
|
28
|
+
// Guard: only allow paths within the project cwd to prevent traversal to
|
|
29
|
+
// /etc/passwd etc. Uses getProjectCwd() (honors MONOMIND_CWD) rather than
|
|
30
|
+
// process.cwd(), which is trivially bypassed when the MCP server runs with
|
|
31
|
+
// cwd "/".
|
|
32
|
+
// realOrResolved resolves symlinks (walking up to the longest existing
|
|
33
|
+
// ancestor) so a link that's lexically inside projectCwd but physically
|
|
34
|
+
// points outside it can't bypass this containment check — same guard
|
|
35
|
+
// input-guards.ts's validatePath uses, applied here against getProjectCwd()
|
|
36
|
+
// instead of process.cwd() since that's the whole reason this check isn't
|
|
37
|
+
// just a direct call to validateInput({type:'path'}).
|
|
38
|
+
const projectCwd = realOrResolved(getProjectCwd());
|
|
39
|
+
const resolved = realOrResolved(resolve(configPath));
|
|
40
|
+
const rel = relative(projectCwd, resolved);
|
|
41
|
+
if (rel.startsWith('..') || resolve(rel) === resolve('/')) {
|
|
42
|
+
throw new Error(`Rejected group config path outside project directory: ${resolved} (project cwd: ${projectCwd})`);
|
|
43
|
+
}
|
|
44
|
+
// OOM guard: skip files larger than 1 MB
|
|
45
|
+
if (statSync(configPath).size > MAX_GROUP_CONFIG_BYTES) {
|
|
46
|
+
throw new Error(`Group config file too large (> ${MAX_GROUP_CONFIG_BYTES} bytes): ${configPath}`);
|
|
47
|
+
}
|
|
48
|
+
return parseGroupConfig(configPath).repos;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compute whether a repo's monograph index is stale relative to HEAD, the
|
|
52
|
+
* same way monograph_staleness does: compare the last indexed commit hash
|
|
53
|
+
* against `git rev-list --count <lastCommit>..HEAD`. Mirrors the threshold
|
|
54
|
+
* used by monograph-tools.ts (STALENESS_THRESHOLD = 10).
|
|
55
|
+
*/
|
|
56
|
+
function isRepoStale(db, repoPath) {
|
|
15
57
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return JSON.parse(raw);
|
|
58
|
+
const meta = (db.prepare("SELECT value FROM index_meta WHERE key = 'last_commit_hash'").get()
|
|
59
|
+
?? db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get());
|
|
60
|
+
const lastCommit = meta?.value;
|
|
61
|
+
if (!lastCommit || !/^[0-9a-f]{7,40}$/i.test(lastCommit))
|
|
62
|
+
return false;
|
|
63
|
+
const out = execSync(`git rev-list --count ${lastCommit}..HEAD`, {
|
|
64
|
+
cwd: repoPath, encoding: 'utf-8',
|
|
65
|
+
}).trim();
|
|
66
|
+
return parseInt(out, 10) > 10;
|
|
26
67
|
}
|
|
27
68
|
catch {
|
|
28
|
-
return
|
|
69
|
+
return false;
|
|
29
70
|
}
|
|
30
71
|
}
|
|
31
72
|
// ── getGroupContracts ─────────────────────────────────────────────────────────
|
|
@@ -74,11 +115,12 @@ export async function getGroupStatus(configPath) {
|
|
|
74
115
|
const nc = countNodes(db);
|
|
75
116
|
const contracts = db.prepare("SELECT COUNT(*) as n FROM nodes WHERE label = 'Route'").get();
|
|
76
117
|
const meta = db.prepare("SELECT value FROM index_meta WHERE key IN ('ua_last_commit','lastCommit') LIMIT 1").get();
|
|
118
|
+
const stale = isRepoStale(db, repoPath);
|
|
77
119
|
closeDb(db);
|
|
78
120
|
groups.push({
|
|
79
121
|
name,
|
|
80
122
|
indexed: nc > 0,
|
|
81
|
-
stale
|
|
123
|
+
stale,
|
|
82
124
|
contractCount: contracts?.n ?? 0,
|
|
83
125
|
...(meta?.value ? { lastSync: meta.value } : {}),
|
|
84
126
|
});
|