@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.
- package/.pnpmrc.json +1 -0
- package/AUTO-DEBUG-DESIGN.md +267 -0
- package/AUTOMATIC-MEMORY-MANAGEMENT.md +109 -0
- package/DASHBOARD-PLAN.md +206 -0
- package/MEMORY-ENHANCEMENT-PLAN.md +211 -0
- package/TOOL-USE-DESIGN.md +173 -0
- package/dist/{chunk-FBQBBAPZ.js → chunk-4C6B2AMB.js} +2 -2
- package/dist/{chunk-FK6WYXRM.js → chunk-4YXOQGQC.js} +2 -2
- package/dist/{chunk-IXBIAX76.js → chunk-K6KL2VD6.js} +2 -2
- package/dist/{chunk-IJRAVHQC.js → chunk-LWJCKTQP.js} +51 -11
- package/dist/chunk-LWJCKTQP.js.map +1 -0
- package/dist/{chunk-BHCDOHSK.js → chunk-LYL5GG2F.js} +3 -3
- package/dist/{chunk-M3A2WRXM.js → chunk-OB6OXLPC.js} +430 -2
- package/dist/chunk-OB6OXLPC.js.map +1 -0
- package/dist/{chunk-DPLCEMEC.js → chunk-ZA4NWNS6.js} +2 -2
- package/dist/commands/fleet.js +3 -3
- package/dist/commands/init.js +3 -3
- package/dist/commands/service.js +1 -1
- package/dist/commands/start.js +3 -3
- package/dist/commands/watchdog.js +3 -3
- package/dist/dashboard.html +100 -60
- package/dist/index.js +2 -2
- package/dist/main.js +7 -7
- package/dist/start.js +1 -1
- package/docs/TOOL-PARITY-PLAN.md +191 -0
- package/package.json +23 -24
- package/src/memory/dashboard-integration.ts +295 -0
- package/src/memory/index.ts +187 -0
- package/src/memory/performance-test.ts +208 -0
- package/src/memory/processors/agent-sync.ts +312 -0
- package/src/memory/processors/command-learner.ts +298 -0
- package/src/memory/processors/memory-api-client.ts +105 -0
- package/src/memory/processors/message-flow-integration.ts +168 -0
- package/src/memory/processors/research-digester.ts +204 -0
- package/test-caitlin-access.md +11 -0
- package/dist/chunk-IJRAVHQC.js.map +0 -1
- package/dist/chunk-M3A2WRXM.js.map +0 -1
- package/install.sh +0 -162
- package/packages/memory/Cargo.lock +0 -6480
- package/packages/memory/Cargo.toml +0 -21
- package/packages/memory/src/src/context.rs +0 -179
- package/packages/memory/src/src/embeddings.rs +0 -51
- package/packages/memory/src/src/main.rs +0 -887
- package/packages/memory/src/src/promotion.rs +0 -808
- package/packages/memory/src/src/scoring.rs +0 -142
- package/packages/memory/src/src/store.rs +0 -460
- package/packages/memory/src/src/tasks.rs +0 -321
- /package/dist/{chunk-FBQBBAPZ.js.map → chunk-4C6B2AMB.js.map} +0 -0
- /package/dist/{chunk-FK6WYXRM.js.map → chunk-4YXOQGQC.js.map} +0 -0
- /package/dist/{chunk-IXBIAX76.js.map → chunk-K6KL2VD6.js.map} +0 -0
- /package/dist/{chunk-BHCDOHSK.js.map → chunk-LYL5GG2F.js.map} +0 -0
- /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":[]}
|