@sesamespace/hivemind 0.10.0 → 0.11.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.
Files changed (52) hide show
  1. package/.pnpmrc.json +1 -0
  2. package/AUTO-DEBUG-DESIGN.md +267 -0
  3. package/AUTOMATIC-MEMORY-MANAGEMENT.md +109 -0
  4. package/DASHBOARD-PLAN.md +206 -0
  5. package/MEMORY-ENHANCEMENT-PLAN.md +211 -0
  6. package/TOOL-USE-DESIGN.md +173 -0
  7. package/dist/{chunk-FBQBBAPZ.js → chunk-4C6B2AMB.js} +2 -2
  8. package/dist/{chunk-FK6WYXRM.js → chunk-4YXOQGQC.js} +2 -2
  9. package/dist/{chunk-IXBIAX76.js → chunk-K6KL2VD6.js} +2 -2
  10. package/dist/{chunk-IJRAVHQC.js → chunk-LWJCKTQP.js} +51 -11
  11. package/dist/chunk-LWJCKTQP.js.map +1 -0
  12. package/dist/{chunk-BHCDOHSK.js → chunk-LYL5GG2F.js} +3 -3
  13. package/dist/{chunk-M3A2WRXM.js → chunk-OB6OXLPC.js} +430 -2
  14. package/dist/chunk-OB6OXLPC.js.map +1 -0
  15. package/dist/{chunk-DPLCEMEC.js → chunk-ZA4NWNS6.js} +2 -2
  16. package/dist/commands/fleet.js +3 -3
  17. package/dist/commands/init.js +3 -3
  18. package/dist/commands/service.js +1 -1
  19. package/dist/commands/start.js +3 -3
  20. package/dist/commands/watchdog.js +3 -3
  21. package/dist/dashboard.html +100 -60
  22. package/dist/index.js +2 -2
  23. package/dist/main.js +7 -7
  24. package/dist/start.js +1 -1
  25. package/docs/TOOL-PARITY-PLAN.md +191 -0
  26. package/package.json +23 -24
  27. package/src/memory/dashboard-integration.ts +295 -0
  28. package/src/memory/index.ts +187 -0
  29. package/src/memory/performance-test.ts +208 -0
  30. package/src/memory/processors/agent-sync.ts +312 -0
  31. package/src/memory/processors/command-learner.ts +298 -0
  32. package/src/memory/processors/memory-api-client.ts +105 -0
  33. package/src/memory/processors/message-flow-integration.ts +168 -0
  34. package/src/memory/processors/research-digester.ts +204 -0
  35. package/test-caitlin-access.md +11 -0
  36. package/dist/chunk-IJRAVHQC.js.map +0 -1
  37. package/dist/chunk-M3A2WRXM.js.map +0 -1
  38. package/install.sh +0 -162
  39. package/packages/memory/Cargo.lock +0 -6480
  40. package/packages/memory/Cargo.toml +0 -21
  41. package/packages/memory/src/src/context.rs +0 -179
  42. package/packages/memory/src/src/embeddings.rs +0 -51
  43. package/packages/memory/src/src/main.rs +0 -887
  44. package/packages/memory/src/src/promotion.rs +0 -808
  45. package/packages/memory/src/src/scoring.rs +0 -142
  46. package/packages/memory/src/src/store.rs +0 -460
  47. package/packages/memory/src/src/tasks.rs +0 -321
  48. /package/dist/{chunk-FBQBBAPZ.js.map → chunk-4C6B2AMB.js.map} +0 -0
  49. /package/dist/{chunk-FK6WYXRM.js.map → chunk-4YXOQGQC.js.map} +0 -0
  50. /package/dist/{chunk-IXBIAX76.js.map → chunk-K6KL2VD6.js.map} +0 -0
  51. /package/dist/{chunk-BHCDOHSK.js.map → chunk-LYL5GG2F.js.map} +0 -0
  52. /package/dist/{chunk-DPLCEMEC.js.map → chunk-ZA4NWNS6.js.map} +0 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Integrates memory processors with the agent's message flow
3
+ */
4
+
5
+ import { EventEmitter } from 'events';
6
+ import { MemoryAPIClient } from './memory-api-client';
7
+ import { ProcessManager } from './background-processor';
8
+ import { CodeIndexer } from './code-indexer';
9
+ import { TaskTracker } from './task-tracker';
10
+ import { ContextManager } from './context-manager';
11
+
12
+ export interface AgentMessage {
13
+ role: 'user' | 'assistant' | 'system';
14
+ content: string;
15
+ timestamp: Date;
16
+ context?: string;
17
+ metadata?: Record<string, any>;
18
+ }
19
+
20
+ export interface MessageFlowConfig {
21
+ memoryURL?: string;
22
+ context?: string;
23
+ workspaceRoot: string;
24
+ maxContextTokens?: number;
25
+ }
26
+
27
+ export class MessageFlowIntegration extends EventEmitter {
28
+ private memoryClient: MemoryAPIClient;
29
+ private processManager: ProcessManager;
30
+ private contextManager: ContextManager;
31
+ private taskTracker: TaskTracker;
32
+ private codeIndexer: CodeIndexer;
33
+
34
+ constructor(config: MessageFlowConfig) {
35
+ super();
36
+
37
+ // Initialize memory client
38
+ this.memoryClient = new MemoryAPIClient(
39
+ config.memoryURL || 'http://localhost:3434',
40
+ config.context || 'global'
41
+ );
42
+
43
+ // Initialize processors
44
+ this.processManager = new ProcessManager();
45
+ this.codeIndexer = new CodeIndexer(config.workspaceRoot);
46
+ this.taskTracker = new TaskTracker();
47
+
48
+ // Initialize context manager
49
+ this.contextManager = new ContextManager(
50
+ this.memoryClient,
51
+ this.processManager,
52
+ config.maxContextTokens || 8000
53
+ );
54
+
55
+ // Register processors
56
+ this.processManager.register('code-indexer', this.codeIndexer);
57
+ this.processManager.register('task-tracker', this.taskTracker);
58
+
59
+ // Set up event listeners
60
+ this.setupEventListeners();
61
+ }
62
+
63
+ private setupEventListeners(): void {
64
+ // Forward errors
65
+ this.memoryClient.on('error', (error) => {
66
+ this.emit('error', { source: 'memory-client', error });
67
+ });
68
+
69
+ this.processManager.on('processor-error', (data) => {
70
+ this.emit('error', { source: 'processor', ...data });
71
+ });
72
+
73
+ // Track file access from messages
74
+ this.on('message', (message: AgentMessage) => {
75
+ if (message.role === 'assistant') {
76
+ this.extractFileReferences(message.content);
77
+ }
78
+ });
79
+ }
80
+
81
+ private extractFileReferences(content: string): void {
82
+ // Extract file paths from message content
83
+ const filePathRegex = /(?:\/[\w.-]+)+(?:\.[\w]+)?/g;
84
+ const matches = content.match(filePathRegex) || [];
85
+
86
+ for (const match of matches) {
87
+ if (match.includes('.') && !match.includes('http')) {
88
+ this.codeIndexer.trackAccess(match);
89
+ }
90
+ }
91
+ }
92
+
93
+ async start(): Promise<void> {
94
+ // Check memory daemon health
95
+ const isHealthy = await this.memoryClient.health();
96
+ if (!isHealthy) {
97
+ throw new Error('Memory daemon is not responding');
98
+ }
99
+
100
+ // Start background processors
101
+ await this.processManager.startAll();
102
+
103
+ this.emit('started');
104
+ }
105
+
106
+ async stop(): Promise<void> {
107
+ await this.processManager.stopAll();
108
+ this.emit('stopped');
109
+ }
110
+
111
+ /**
112
+ * Process an incoming message and return enriched context
113
+ */
114
+ async processMessage(message: AgentMessage): Promise<string> {
115
+ // Store the message in memory
116
+ await this.memoryClient.store(
117
+ `${message.role}: ${message.content}`,
118
+ {
119
+ timestamp: message.timestamp.toISOString(),
120
+ context: message.context,
121
+ ...message.metadata
122
+ }
123
+ );
124
+
125
+ // Update task tracker
126
+ if (message.role === 'user') {
127
+ await this.taskTracker.processMessage(message.content, 'user');
128
+ } else if (message.role === 'assistant') {
129
+ await this.taskTracker.processMessage(message.content, 'assistant');
130
+ }
131
+
132
+ // Build context for the next response
133
+ const context = await this.contextManager.buildContext(message.content);
134
+
135
+ this.emit('context-built', {
136
+ message,
137
+ contextLength: context.length,
138
+ sections: this.contextManager['contextSections'].length // Track what was included
139
+ });
140
+
141
+ return context;
142
+ }
143
+
144
+ /**
145
+ * Get current state of all processors
146
+ */
147
+ async getState(): Promise<Record<string, any>> {
148
+ const stats = await this.memoryClient.getStats();
149
+ const tasks = await this.taskTracker.getActiveTasks();
150
+ const workingSet = await this.codeIndexer.getWorkingSet();
151
+
152
+ return {
153
+ memory: stats,
154
+ tasks: tasks.map(t => ({
155
+ description: t.description,
156
+ state: t.state,
157
+ startTime: t.startTime,
158
+ lastUpdate: t.lastUpdate
159
+ })),
160
+ workingSet: workingSet.map(f => ({
161
+ path: f.path,
162
+ accessCount: f.accessCount,
163
+ lastAccessed: f.lastAccessed
164
+ })),
165
+ processors: this.processManager['processors'].size
166
+ };
167
+ }
168
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Research Digester - Extracts and indexes key information from web pages and documents
3
+ */
4
+
5
+ import { BackgroundProcessor } from './background-processor';
6
+ import { EventEmitter } from 'events';
7
+ import * as crypto from 'crypto';
8
+
9
+ export interface ResearchEntry {
10
+ id: string;
11
+ url?: string;
12
+ title: string;
13
+ summary: string;
14
+ keyPoints: string[];
15
+ relatedTopics: string[];
16
+ timestamp: Date;
17
+ sourceType: 'web' | 'pdf' | 'markdown' | 'other';
18
+ content?: string; // Full content for reference
19
+ }
20
+
21
+ export class ResearchDigester extends BackgroundProcessor {
22
+ private research: Map<string, ResearchEntry> = new Map();
23
+ private topicIndex: Map<string, Set<string>> = new Map(); // topic -> research IDs
24
+ private recentQueue: string[] = []; // URLs/content to process
25
+
26
+ constructor() {
27
+ super('research-digester', 30000); // Process every 30 seconds
28
+ }
29
+
30
+ async process(): Promise<void> {
31
+ // Process any queued research
32
+ while (this.recentQueue.length > 0) {
33
+ const item = this.recentQueue.shift();
34
+ if (item) {
35
+ await this.digestContent(item);
36
+ }
37
+ }
38
+
39
+ // Emit current research state
40
+ this.emit('research-updated', {
41
+ totalEntries: this.research.size,
42
+ topics: Array.from(this.topicIndex.keys())
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Queue content for digestion
48
+ */
49
+ async addContent(content: string, metadata: {
50
+ url?: string;
51
+ title?: string;
52
+ sourceType?: ResearchEntry['sourceType'];
53
+ } = {}): Promise<void> {
54
+ this.recentQueue.push(JSON.stringify({ content, metadata }));
55
+ }
56
+
57
+ private async digestContent(item: string): Promise<void> {
58
+ try {
59
+ const { content, metadata } = JSON.parse(item);
60
+
61
+ // Extract key information
62
+ const entry: ResearchEntry = {
63
+ id: crypto.randomBytes(8).toString('hex'),
64
+ url: metadata.url,
65
+ title: metadata.title || this.extractTitle(content),
66
+ summary: this.extractSummary(content),
67
+ keyPoints: this.extractKeyPoints(content),
68
+ relatedTopics: this.extractTopics(content),
69
+ timestamp: new Date(),
70
+ sourceType: metadata.sourceType || 'other',
71
+ content: content.substring(0, 5000) // Store first 5k chars
72
+ };
73
+
74
+ // Store the entry
75
+ this.research.set(entry.id, entry);
76
+
77
+ // Index by topics
78
+ for (const topic of entry.relatedTopics) {
79
+ if (!this.topicIndex.has(topic)) {
80
+ this.topicIndex.set(topic, new Set());
81
+ }
82
+ this.topicIndex.get(topic)!.add(entry.id);
83
+ }
84
+
85
+ this.emit('research-digested', entry);
86
+ } catch (error) {
87
+ this.emit('error', { error, item });
88
+ }
89
+ }
90
+
91
+ private extractTitle(content: string): string {
92
+ // Look for markdown headers or first significant line
93
+ const lines = content.split('\n');
94
+ for (const line of lines) {
95
+ const trimmed = line.trim();
96
+ if (trimmed.startsWith('#')) {
97
+ return trimmed.replace(/^#+\s*/, '');
98
+ }
99
+ if (trimmed.length > 10 && trimmed.length < 100) {
100
+ return trimmed;
101
+ }
102
+ }
103
+ return 'Untitled Research';
104
+ }
105
+
106
+ private extractSummary(content: string): string {
107
+ // Get first meaningful paragraph
108
+ const paragraphs = content.split(/\n\n+/);
109
+ for (const para of paragraphs) {
110
+ const trimmed = para.trim();
111
+ if (trimmed.length > 50 && !trimmed.startsWith('#')) {
112
+ return trimmed.substring(0, 200) + '...';
113
+ }
114
+ }
115
+ return content.substring(0, 200) + '...';
116
+ }
117
+
118
+ private extractKeyPoints(content: string): string[] {
119
+ const keyPoints: string[] = [];
120
+ const lines = content.split('\n');
121
+
122
+ for (const line of lines) {
123
+ const trimmed = line.trim();
124
+ // Look for bullet points, numbered lists, or key phrases
125
+ if (trimmed.match(/^[-*•]\s+/) || trimmed.match(/^\d+\.\s+/)) {
126
+ keyPoints.push(trimmed.replace(/^[-*•\d.]\s+/, ''));
127
+ }
128
+ // Look for sentences with key indicator words
129
+ if (trimmed.match(/\b(important|key|critical|essential|must|should|note)\b/i)) {
130
+ keyPoints.push(trimmed);
131
+ }
132
+ }
133
+
134
+ // Limit to top 10 key points
135
+ return keyPoints.slice(0, 10);
136
+ }
137
+
138
+ private extractTopics(content: string): string[] {
139
+ const topics = new Set<string>();
140
+
141
+ // Common technical topics
142
+ const topicPatterns = [
143
+ /\b(typescript|javascript|python|rust|go)\b/gi,
144
+ /\b(react|vue|angular|svelte)\b/gi,
145
+ /\b(docker|kubernetes|k8s)\b/gi,
146
+ /\b(api|rest|graphql|grpc)\b/gi,
147
+ /\b(database|sql|nosql|postgres|mysql|mongodb)\b/gi,
148
+ /\b(ai|ml|machine learning|llm|gpt)\b/gi,
149
+ /\b(memory|context|embedding|vector)\b/gi,
150
+ /\b(git|github|version control)\b/gi,
151
+ /\b(testing|ci|cd|deployment)\b/gi,
152
+ /\b(security|auth|authentication|authorization)\b/gi
153
+ ];
154
+
155
+ for (const pattern of topicPatterns) {
156
+ const matches = content.match(pattern);
157
+ if (matches) {
158
+ matches.forEach(match => topics.add(match.toLowerCase()));
159
+ }
160
+ }
161
+
162
+ return Array.from(topics).slice(0, 5); // Top 5 topics
163
+ }
164
+
165
+ /**
166
+ * Search research by topic or content
167
+ */
168
+ async search(query: string): Promise<ResearchEntry[]> {
169
+ const results: ResearchEntry[] = [];
170
+ const queryLower = query.toLowerCase();
171
+
172
+ // Search by topic
173
+ if (this.topicIndex.has(queryLower)) {
174
+ const ids = this.topicIndex.get(queryLower)!;
175
+ for (const id of ids) {
176
+ const entry = this.research.get(id);
177
+ if (entry) results.push(entry);
178
+ }
179
+ }
180
+
181
+ // Search in content
182
+ for (const entry of this.research.values()) {
183
+ if (entry.title.toLowerCase().includes(queryLower) ||
184
+ entry.summary.toLowerCase().includes(queryLower) ||
185
+ entry.keyPoints.some(kp => kp.toLowerCase().includes(queryLower))) {
186
+ if (!results.includes(entry)) {
187
+ results.push(entry);
188
+ }
189
+ }
190
+ }
191
+
192
+ // Sort by recency
193
+ return results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
194
+ }
195
+
196
+ /**
197
+ * Get recent research entries
198
+ */
199
+ async getRecent(limit: number = 10): Promise<ResearchEntry[]> {
200
+ return Array.from(this.research.values())
201
+ .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
202
+ .slice(0, limit);
203
+ }
204
+ }
@@ -0,0 +1,11 @@
1
+ # Test File - Caitlin Access
2
+
3
+ Created by Caitlin on 2026-03-01 to test GitHub write access.
4
+
5
+ This demonstrates that I can:
6
+ - Access the Hivemind repository
7
+ - Create files
8
+ - Commit changes
9
+ - Push to GitHub
10
+
11
+ This file can be safely deleted after testing is complete.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../packages/cli/src/commands/service.ts"],"sourcesContent":["import { resolve } from \"path\";\nimport { writeFileSync, existsSync, unlinkSync, mkdirSync } from \"fs\";\nimport { execSync } from \"child_process\";\nimport { homedir } from \"os\";\n\nconst LAUNCH_AGENTS_DIR = resolve(homedir(), \"Library/LaunchAgents\");\nconst AGENT_LABEL = \"com.hivemind.agent\";\nconst WATCHDOG_LABEL = \"com.hivemind.watchdog\";\nconst MEMORY_LABEL = \"com.hivemind.memory\";\nconst STOP_FLAG_FILE = \"/tmp/hivemind-agent.stopped\";\n\nfunction getHivemindHome(): string {\n return process.env.HIVEMIND_HOME || resolve(homedir(), \"hivemind\");\n}\n\nfunction getHivemindBin(): string {\n // Try to find the hivemind binary\n try {\n const which = execSync(\"which hivemind\", { encoding: \"utf-8\" }).trim();\n if (which) return which;\n } catch {}\n // Fallback to process.argv[1] (the script being run)\n return process.argv[1] || \"hivemind\";\n}\n\nfunction generateMemoryPlist(hivemindHome: string): string {\n const memoryBin = resolve(hivemindHome, \"bin\", \"hivemind-memory\");\n const dbPath = resolve(hivemindHome, \"data\", \"lancedb\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${MEMORY_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${memoryBin}</string>\n </array>\n <key>WorkingDirectory</key>\n <string>${hivemindHome}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>PORT</key>\n <string>3434</string>\n <key>DB_PATH</key>\n <string>${dbPath}</string>\n <key>OLLAMA_URL</key>\n <string>http://localhost:11434</string>\n <key>EMBEDDING_MODEL</key>\n <string>nomic-embed-text</string>\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>/tmp/hivemind-memory.log</string>\n <key>StandardErrorPath</key>\n <string>/tmp/hivemind-memory-error.log</string>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>`;\n}\n\nfunction generateWatchdogPlist(hivemindHome: string, hivemindBin: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${WATCHDOG_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${hivemindBin}</string>\n <string>watchdog</string>\n </array>\n <key>WorkingDirectory</key>\n <string>${hivemindHome}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>PATH</key>\n <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>\n <key>HIVEMIND_HOME</key>\n <string>${hivemindHome}</string>\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>/tmp/hivemind-watchdog.log</string>\n <key>StandardErrorPath</key>\n <string>/tmp/hivemind-watchdog-error.log</string>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>`;\n}\n\nfunction generatePlist(hivemindHome: string, hivemindBin: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${AGENT_LABEL}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${hivemindBin}</string>\n <string>start</string>\n </array>\n <key>WorkingDirectory</key>\n <string>${hivemindHome}</string>\n <key>EnvironmentVariables</key>\n <dict>\n <key>PATH</key>\n <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>\n <key>HIVEMIND_HOME</key>\n <string>${hivemindHome}</string>\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <false/>\n <key>StandardOutPath</key>\n <string>/tmp/hivemind-agent.log</string>\n <key>StandardErrorPath</key>\n <string>/tmp/hivemind-error.log</string>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>`;\n}\n\nexport async function runServiceCommand(args: string[]): Promise<void> {\n const subcommand = args[0];\n\n switch (subcommand) {\n case \"install\":\n await installService();\n break;\n case \"uninstall\":\n await uninstallService();\n break;\n case \"stop\":\n stopService();\n break;\n case \"start\":\n startService();\n break;\n case \"status\":\n showStatus();\n break;\n case \"logs\":\n showLogs(args[1]);\n break;\n default:\n printHelp();\n if (subcommand) {\n console.error(`Unknown subcommand: ${subcommand}`);\n process.exit(1);\n }\n break;\n }\n}\n\nasync function installService(): Promise<void> {\n const hivemindHome = getHivemindHome();\n const hivemindBin = getHivemindBin();\n const memoryBin = resolve(hivemindHome, \"bin\", \"hivemind-memory\");\n\n console.log(`\\n→ Installing launchd services for ${hivemindHome}\\n`);\n console.log(` Agent binary: ${hivemindBin}`);\n console.log(` Memory binary: ${memoryBin}`);\n\n mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });\n\n // --- Memory daemon service ---\n if (existsSync(memoryBin)) {\n const memoryPlist = generateMemoryPlist(hivemindHome);\n const memoryDest = resolve(LAUNCH_AGENTS_DIR, `${MEMORY_LABEL}.plist`);\n try { execSync(`launchctl unload ${memoryDest} 2>/dev/null`); } catch {}\n writeFileSync(memoryDest, memoryPlist);\n execSync(`launchctl load ${memoryDest}`);\n console.log(` ✓ ${MEMORY_LABEL} installed and started`);\n } else {\n console.log(` ! Memory daemon not found at ${memoryBin} — skipping`);\n console.log(` ! Run 'hivemind init' to download it`);\n }\n\n // --- Ollama service (ensure running) ---\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n console.log(\" ✓ Ollama already running\");\n } catch {\n try {\n execSync(\"brew services start ollama 2>/dev/null\", { stdio: \"ignore\" });\n console.log(\" ✓ Ollama started via brew services\");\n } catch {\n console.log(\" ! Ollama not running — start manually: ollama serve\");\n }\n }\n\n // --- Watchdog service ---\n const watchdogPlist = generateWatchdogPlist(hivemindHome, hivemindBin);\n const watchdogDest = resolve(LAUNCH_AGENTS_DIR, `${WATCHDOG_LABEL}.plist`);\n try { execSync(`launchctl unload ${watchdogDest} 2>/dev/null`); } catch {}\n writeFileSync(watchdogDest, watchdogPlist);\n execSync(`launchctl load ${watchdogDest}`);\n console.log(` ✓ ${WATCHDOG_LABEL} installed and started`);\n\n // --- Agent service (KeepAlive: false — watchdog manages restarts) ---\n const plistContent = generatePlist(hivemindHome, hivemindBin);\n const destPath = resolve(LAUNCH_AGENTS_DIR, `${AGENT_LABEL}.plist`);\n try { execSync(`launchctl unload ${destPath} 2>/dev/null`); } catch {}\n writeFileSync(destPath, plistContent);\n execSync(`launchctl load ${destPath}`);\n console.log(` ✓ ${AGENT_LABEL} installed and started`);\n\n console.log(\"\\n Services will auto-start on boot.\");\n console.log(\" Logs:\");\n console.log(\" Agent: /tmp/hivemind-agent.log\");\n console.log(\" Watchdog: /tmp/hivemind-watchdog.log\");\n console.log(\" Memory: /tmp/hivemind-memory.log\\n\");\n}\n\nasync function uninstallService(): Promise<void> {\n console.log(\"\\n→ Uninstalling launchd services\\n\");\n\n for (const label of [AGENT_LABEL, WATCHDOG_LABEL, MEMORY_LABEL]) {\n const plistPath = resolve(LAUNCH_AGENTS_DIR, `${label}.plist`);\n if (existsSync(plistPath)) {\n try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}\n unlinkSync(plistPath);\n console.log(` ✓ ${label} uninstalled`);\n } else {\n console.log(` - ${label} not installed`);\n }\n }\n\n // Clean up stop flag if present\n try { unlinkSync(STOP_FLAG_FILE); } catch {}\n console.log(\"\");\n}\n\nfunction stopService(): void {\n console.log(\"\\n→ Stopping agent\\n\");\n\n // Write stop flag so watchdog doesn't restart\n writeFileSync(STOP_FLAG_FILE, String(Date.now()));\n console.log(` ✓ Stop flag written (${STOP_FLAG_FILE})`);\n\n // Stop agent via launchctl\n try {\n const uid = execSync(\"id -u\", { encoding: \"utf-8\" }).trim();\n execSync(`launchctl kill SIGTERM gui/${uid}/${AGENT_LABEL} 2>/dev/null`);\n console.log(` ✓ ${AGENT_LABEL} stopped`);\n } catch {\n console.log(` - ${AGENT_LABEL} was not running`);\n }\n\n console.log(\" Watchdog will NOT restart the agent while stop flag exists.\");\n console.log(\" Use 'hivemind service start' to resume.\\n\");\n}\n\nfunction startService(): void {\n console.log(\"\\n→ Starting agent\\n\");\n\n // Remove stop flag\n try {\n unlinkSync(STOP_FLAG_FILE);\n console.log(` ✓ Stop flag removed (${STOP_FLAG_FILE})`);\n } catch {\n console.log(\" - No stop flag present\");\n }\n\n // Start agent via launchctl\n try {\n const uid = execSync(\"id -u\", { encoding: \"utf-8\" }).trim();\n execSync(`launchctl kickstart gui/${uid}/${AGENT_LABEL}`);\n console.log(` ✓ ${AGENT_LABEL} started`);\n } catch (err) {\n console.error(` ! Failed to start agent: ${(err as Error).message}`);\n }\n console.log(\"\");\n}\n\nfunction showStatus(): void {\n console.log(\"\\n→ Service status\\n\");\n for (const label of [AGENT_LABEL, WATCHDOG_LABEL, MEMORY_LABEL]) {\n try {\n const out = execSync(`launchctl list ${label} 2>/dev/null`, { encoding: \"utf-8\" });\n const pidMatch = out.match(/\"PID\"\\s*=\\s*(\\d+)/);\n const pid = pidMatch ? pidMatch[1] : \"unknown\";\n console.log(` ✓ ${label}: running (PID ${pid})`);\n } catch {\n console.log(` - ${label}: not running`);\n }\n }\n\n // Check Ollama\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n console.log(\" ✓ ollama: running\");\n } catch {\n console.log(\" - ollama: not running\");\n }\n console.log(\"\");\n}\n\nfunction showLogs(which?: string): void {\n const logMap: Record<string, string> = {\n agent: \"/tmp/hivemind-agent.log\",\n error: \"/tmp/hivemind-error.log\",\n watchdog: \"/tmp/hivemind-watchdog.log\",\n memory: \"/tmp/hivemind-memory.log\",\n };\n const logFile = logMap[which || \"agent\"] || logMap.agent;\n try {\n execSync(`tail -30 ${logFile}`, { stdio: \"inherit\" });\n } catch {\n console.error(`No log file at ${logFile}`);\n }\n}\n\nfunction printHelp(): void {\n console.log(`hivemind service — Manage launchd services\n\nUsage: hivemind service <subcommand>\n\nSubcommands:\n install Install and start all launchd services (survives reboots)\n uninstall Stop and remove all launchd services\n stop Stop agent (watchdog will not restart it)\n start Start agent (removes stop flag)\n status Show service status\n logs [agent|watchdog|memory|error] Show recent logs\n\nServices:\n com.hivemind.watchdog — Watchdog daemon (health monitoring, restart/upgrade orchestration)\n com.hivemind.agent — Agent runtime (Node.js, Sesame) — managed by watchdog\n com.hivemind.memory — Memory daemon (LanceDB + Ollama embeddings)\n`);\n}\n"],"mappings":"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","names":[]}