@monoes/monomindcli 1.6.0 → 1.6.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.
@@ -4,9 +4,17 @@
4
4
  * Tool definitions for agent lifecycle management with file persistence.
5
5
  * Includes model routing integration for intelligent model selection.
6
6
  */
7
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
7
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { getProjectCwd } from './types.js';
10
+ function logEvent(kind, data) {
11
+ try {
12
+ const dir = join(getProjectCwd(), '.monomind', 'swarm');
13
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
14
+ const event = { ts: new Date().toISOString(), source: 'mcp', kind, ...data };
15
+ appendFileSync(join(dir, 'events.jsonl'), JSON.stringify(event) + '\n');
16
+ } catch { }
17
+ }
10
18
  // Storage paths
11
19
  const STORAGE_DIR = '.monomind';
12
20
  const AGENT_DIR = 'agents';
@@ -189,6 +197,7 @@ export const agentTools = [
189
197
  register(agentId, sandbox);
190
198
  }
191
199
  catch { /* optional — @monoes/security may not be installed */ }
200
+ logEvent('agent.spawn', { agentId, agentType, model: routingResult.model, routedBy: routingResult.routedBy, domain: input.domain, task });
192
201
  // Include Agent Booster routing info if applicable
193
202
  const response = {
194
203
  success: true,
@@ -228,8 +237,10 @@ export const agentTools = [
228
237
  const store = loadAgentStore();
229
238
  const agentId = input.agentId;
230
239
  if (store.agents[agentId]) {
240
+ const agentType = store.agents[agentId].agentType;
231
241
  store.agents[agentId].status = 'terminated';
232
242
  saveAgentStore(store);
243
+ logEvent('agent.terminate', { agentId, agentType });
233
244
  // Task 46: AgentSandboxing — clean up sandbox on termination
234
245
  try {
235
246
  const { cleanup } = await import('@monoes/security');
@@ -3,10 +3,18 @@
3
3
  *
4
4
  * Tool definitions for collective intelligence and swarm coordination.
5
5
  */
6
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
6
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
8
  import { getProjectCwd } from './types.js';
9
9
  import { weightedTally } from '../consensus/vote-signer.js';
10
+ function logEvent(kind, data) {
11
+ try {
12
+ const dir = join(getProjectCwd(), '.monomind', 'swarm');
13
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
14
+ const event = { ts: new Date().toISOString(), source: 'mcp', kind, ...data };
15
+ appendFileSync(join(dir, 'events.jsonl'), JSON.stringify(event) + '\n');
16
+ } catch { }
17
+ }
10
18
  // Storage paths
11
19
  const STORAGE_DIR = '.monomind';
12
20
  const HIVE_DIR = 'hive-mind';
@@ -190,6 +198,9 @@ export const hiveMindTools = [
190
198
  }
191
199
  saveAgentStore(agentStore);
192
200
  saveHiveState(state);
201
+ for (const w of spawnedWorkers) {
202
+ logEvent('hive.spawn', { agentId: w.agentId, role: w.role, agentType });
203
+ }
193
204
  return {
194
205
  success: true,
195
206
  spawned: count,
@@ -224,6 +235,7 @@ export const hiveMindTools = [
224
235
  term: 1,
225
236
  };
226
237
  saveHiveState(state);
238
+ logEvent('hive.init', { hiveId, topology: state.topology, consensus: input.consensus || 'byzantine', queenId });
227
239
  return {
228
240
  success: true,
229
241
  hiveId,
@@ -464,6 +476,7 @@ export const hiveMindTools = [
464
476
  };
465
477
  state.consensus.pending.push(proposal);
466
478
  saveHiveState(state);
479
+ logEvent('hive.consensus.propose', { proposalId, type: proposal.type, strategy, proposedBy: proposal.proposedBy, totalNodes });
467
480
  return {
468
481
  action,
469
482
  proposalId,
@@ -585,9 +598,11 @@ export const hiveMindTools = [
585
598
  // Try to resolve
586
599
  const resolution = divergenceGateOpen ? tryResolveProposal(proposal, totalNodes) : null;
587
600
  let resolved = false;
601
+ logEvent('hive.consensus.vote', { proposalId: proposal.proposalId, voterId, vote: voteValue, strategy: proposalStrategy, votesFor, votesAgainst });
588
602
  if (resolution !== null) {
589
603
  resolved = true;
590
604
  proposal.status = resolution;
605
+ logEvent('hive.consensus.resolved', { proposalId: proposal.proposalId, result: resolution, strategy: proposalStrategy, votesFor, votesAgainst });
591
606
  state.consensus.history.push({
592
607
  proposalId: proposal.proposalId,
593
608
  type: proposal.type,
@@ -735,6 +750,7 @@ export const hiveMindTools = [
735
750
  // Keep only last 100 broadcasts
736
751
  state.sharedMemory.broadcasts = messages.slice(-100);
737
752
  saveHiveState(state);
753
+ logEvent('hive.broadcast', { messageId, fromId: input.fromId || 'system', message: input.message, priority: input.priority || 'normal', recipients: state.workers.length });
738
754
  return {
739
755
  success: true,
740
756
  messageId,
@@ -784,6 +800,7 @@ export const hiveMindTools = [
784
800
  // Reset hive state
785
801
  const shutdownTime = new Date().toISOString();
786
802
  const previousQueen = state.queen?.agentId;
803
+ logEvent('hive.shutdown', { workersTerminated: workerCount, previousQueen, graceful, pendingConsensus, topology: state.topology });
787
804
  state.initialized = false;
788
805
  state.queen = undefined;
789
806
  state.workers = [];
@@ -2,9 +2,17 @@
2
2
  * Hooks MCP Tools
3
3
  * Provides intelligent hooks functionality via MCP protocol
4
4
  */
5
- import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync } from 'fs';
5
+ import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync, appendFileSync } from 'fs';
6
6
  import { dirname, join, resolve } from 'path';
7
7
  import { getProjectCwd } from './types.js';
8
+ function logEvent(kind, data) {
9
+ try {
10
+ const dir = join(getProjectCwd(), '.monomind', 'swarm');
11
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
12
+ const event = { ts: new Date().toISOString(), source: 'hook', kind, ...data };
13
+ appendFileSync(join(dir, 'events.jsonl'), JSON.stringify(event) + '\n');
14
+ } catch { }
15
+ }
8
16
  // Real vector search functions - lazy loaded to avoid circular imports
9
17
  let searchEntriesFn = null;
10
18
  async function getRealSearchFunction() {
@@ -1094,6 +1102,7 @@ export const hooksPreTask = {
1094
1102
  }
1095
1103
  }
1096
1104
  catch { /* non-critical */ }
1105
+ logEvent('task.start', { taskId, description: description?.slice(0, 200), complexity, suggestedAgent: suggestion.agents[0], modelTier: modelRouting?.tier });
1097
1106
  return {
1098
1107
  taskId,
1099
1108
  description,
@@ -1256,6 +1265,7 @@ export const hooksPostTask = {
1256
1265
  storeAs: 'heuristics',
1257
1266
  note: 'Spawn agents sequentially: Diagnoser → Critics in parallel → Aggregator',
1258
1267
  } : { needed: false };
1268
+ logEvent('task.end', { taskId, success, duration, agent, quality, task: taskText?.slice(0, 200) });
1259
1269
  return {
1260
1270
  taskId,
1261
1271
  success,
@@ -4,9 +4,17 @@
4
4
  * Tool definitions for swarm coordination with file-based state persistence.
5
5
  * Replaces previous stub implementations with real state tracking.
6
6
  */
7
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { getProjectCwd } from './types.js';
10
+ function logEvent(kind, data) {
11
+ try {
12
+ const dir = join(getProjectCwd(), '.monomind', 'swarm');
13
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
14
+ const event = { ts: new Date().toISOString(), source: 'mcp', kind, ...data };
15
+ appendFileSync(join(dir, 'events.jsonl'), JSON.stringify(event) + '\n');
16
+ } catch { }
17
+ }
10
18
  // Swarm state persistence
11
19
  const SWARM_DIR = '.monomind/swarm';
12
20
  const SWARM_STATE_FILE = 'swarm-state.json';
@@ -88,6 +96,7 @@ export const swarmTools = [
88
96
  const store = loadSwarmStore();
89
97
  store.swarms[swarmId] = swarmState;
90
98
  saveSwarmStore(store);
99
+ logEvent('swarm.init', { swarmId, topology, strategy, maxAgents, config: swarmState.config });
91
100
  return {
92
101
  success: true,
93
102
  swarmId,
@@ -195,6 +204,7 @@ export const swarmTools = [
195
204
  target.status = 'terminated';
196
205
  target.updatedAt = new Date().toISOString();
197
206
  saveSwarmStore(store);
207
+ logEvent('swarm.shutdown', { swarmId: target.swarmId, topology: target.topology, agentCount: target.agents.length, graceful: input.graceful ?? true });
198
208
  return {
199
209
  success: true,
200
210
  swarmId: target.swarmId,
@@ -119,16 +119,104 @@ function collectSessions(projectDir) {
119
119
  };
120
120
  }
121
121
 
122
+ const _appendedSwarmIds = new Set();
123
+
122
124
  function collectSwarm(projectDir) {
123
125
  const base = path.join(projectDir, '.monomind');
126
+ const state = readJSON(path.join(base, 'swarm', 'swarm-state.json')) || {};
127
+ const dotSwarmState = readJSON(path.join(projectDir, '.swarm', 'state.json')) || {};
128
+ const merged = { ...dotSwarmState, ...state };
129
+
130
+ const terminalStatuses = ['stopped', 'terminated', 'completed', 'error'];
131
+ const swarmId = merged.swarmId || merged.id;
132
+ if (swarmId && terminalStatuses.includes(merged.status) && !_appendedSwarmIds.has(swarmId)) {
133
+ _appendedSwarmIds.add(swarmId);
134
+ const agents = (merged.agents || merged.agentPlan || []).map(a => ({
135
+ id: a.id || a.type || a.role,
136
+ type: a.type || a.role || '?',
137
+ role: a.role || 'worker',
138
+ tasksCompleted: a.tasksCompleted || a.count || 0,
139
+ tasksFailed: a.tasksFailed || 0,
140
+ messageCount: a.messageCount || 0,
141
+ utilization: a.utilization || 0,
142
+ }));
143
+ const entry = {
144
+ swarmId,
145
+ topology: merged.topology || '—',
146
+ consensus: merged.consensus || '—',
147
+ strategy: merged.strategy || '—',
148
+ status: merged.status,
149
+ agents,
150
+ messages: merged.messages || [],
151
+ errors: merged.errors || [],
152
+ findings: merged.findings || [],
153
+ taskCount: merged.taskCount || 0,
154
+ completedTasks: merged.completedTasks || 0,
155
+ failedTasks: merged.failedTasks || 0,
156
+ startedAt: merged.startedAt || merged.createdAt || new Date().toISOString(),
157
+ endedAt: merged.stoppedAt || merged.endedAt || new Date().toISOString(),
158
+ durationMs: 0,
159
+ };
160
+ if (entry.startedAt && entry.endedAt) {
161
+ entry.durationMs = new Date(entry.endedAt).getTime() - new Date(entry.startedAt).getTime();
162
+ }
163
+ try { appendSwarmHistory(projectDir, entry); } catch {}
164
+ }
165
+
124
166
  return {
125
- state: readJSON(path.join(base, 'swarm', 'swarm-state.json')) || {},
167
+ state: merged,
126
168
  activity: readJSON(path.join(base, 'metrics', 'swarm-activity.json')) || {},
127
169
  suggestion: {},
128
- config: readJSON(path.join(base, 'swarm-config.json')) || {}
170
+ config: readJSON(path.join(base, 'swarm-config.json')) || {},
129
171
  };
130
172
  }
131
173
 
174
+ function collectSwarmHistory(projectDir) {
175
+ const historyPath = path.join(projectDir, '.monomind', 'swarm', 'history.jsonl');
176
+ return readJSONL(historyPath).reverse(); // newest-first
177
+ }
178
+
179
+ function appendSwarmHistory(projectDir, entry) {
180
+ const dir = path.join(projectDir, '.monomind', 'swarm');
181
+ if (!fs.existsSync(dir)) {
182
+ fs.mkdirSync(dir, { recursive: true });
183
+ }
184
+ const historyPath = path.join(dir, 'history.jsonl');
185
+ fs.appendFileSync(historyPath, JSON.stringify(entry) + '\n');
186
+ }
187
+
188
+ function collectSwarmEvents(projectDir, opts = {}) {
189
+ const eventsPath = path.join(projectDir, '.monomind', 'swarm', 'events.jsonl');
190
+ const events = readJSONL(eventsPath, opts.last || null);
191
+ if (opts.swarmId) return events.filter(e => e.swarmId === opts.swarmId);
192
+ if (opts.agentId) return events.filter(e => e.agentId === opts.agentId);
193
+ return events;
194
+ }
195
+
196
+ function getSwarmDataSize(projectDir) {
197
+ const dir = path.join(projectDir, '.monomind', 'swarm');
198
+ let totalBytes = 0;
199
+ let fileCount = 0;
200
+ const files = ['history.jsonl', 'events.jsonl'];
201
+ for (const f of files) {
202
+ const stat = fileStat(path.join(dir, f));
203
+ if (stat) { totalBytes += stat.size; fileCount++; }
204
+ }
205
+ return { totalBytes, fileCount, humanSize: totalBytes < 1024 ? totalBytes + ' B' : totalBytes < 1048576 ? (totalBytes / 1024).toFixed(1) + ' KB' : (totalBytes / 1048576).toFixed(1) + ' MB' };
206
+ }
207
+
208
+ function cleanSwarmData(projectDir) {
209
+ const dir = path.join(projectDir, '.monomind', 'swarm');
210
+ const files = ['history.jsonl', 'events.jsonl'];
211
+ let removed = 0;
212
+ for (const f of files) {
213
+ const fp = path.join(dir, f);
214
+ try { fs.unlinkSync(fp); removed++; } catch {}
215
+ }
216
+ _appendedSwarmIds.clear();
217
+ return { removed, files };
218
+ }
219
+
132
220
  function collectAgents(projectDir) {
133
221
  const base = path.join(projectDir, '.monomind');
134
222
  const regsDir = path.join(base, 'agents', 'registrations');
@@ -420,12 +508,12 @@ export function collectAllProjects() {
420
508
  // Last activity = most recent session mtime
421
509
  const lastActivity = sessions.length ? sessions[0].mtime : null;
422
510
 
423
- // Read memory palace if available
424
- let drawerCount = 0;
511
+ // Count auto-memory files from ~/.claude/projects/<slug>/memory/
512
+ let memoryCount = 0;
425
513
  try {
426
- const drawersPath = path.join(diskPath, '.monomind', 'palace', 'drawers.jsonl');
427
- if (fs.existsSync(drawersPath)) {
428
- drawerCount = fs.readFileSync(drawersPath, 'utf8').split('\n').filter(Boolean).length;
514
+ const memDir = path.join(os.homedir(), '.claude', 'projects', slug, 'memory');
515
+ if (fs.existsSync(memDir)) {
516
+ memoryCount = fs.readdirSync(memDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md').length;
429
517
  }
430
518
  } catch {}
431
519
 
@@ -437,7 +525,7 @@ export function collectAllProjects() {
437
525
  sessionCount: sessions.length,
438
526
  sessions: sessions.slice(0, 5), // top 5 most recent
439
527
  lastActivity,
440
- drawerCount,
528
+ memoryCount,
441
529
  totalSize: sessions.reduce((sum, s) => sum + (s.size || 0), 0),
442
530
  });
443
531
  }
@@ -473,7 +561,7 @@ export function collectAll(projectDir) {
473
561
  };
474
562
  }
475
563
 
476
- export { collectProject, collectSessions, collectSwarm, collectAgents, collectTokens, collectHooks, collectKnowledge, collectMetrics, collectMemory, collectMemoryFiles, collectSystem };
564
+ export { collectProject, collectSessions, collectSwarm, collectSwarmHistory, appendSwarmHistory, collectSwarmEvents, getSwarmDataSize, cleanSwarmData, collectAgents, collectTokens, collectHooks, collectKnowledge, collectMetrics, collectMemory, collectMemoryFiles, collectSystem };
477
565
 
478
566
  export function getWatchPaths(projectDir) {
479
567
  const resolvedDir = path.resolve(projectDir);
@@ -483,6 +571,7 @@ export function getWatchPaths(projectDir) {
483
571
  return [
484
572
  // Swarm
485
573
  path.join(m, 'swarm', 'swarm-state.json'),
574
+ path.join(m, 'swarm', 'history.jsonl'),
486
575
  path.join(m, 'swarm-config.json'),
487
576
  // Metrics
488
577
  path.join(m, 'metrics', 'swarm-activity.json'),