@sesamespace/hivemind 0.10.0 → 0.11.0

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 (48) 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-BHCDOHSK.js → chunk-LYL5GG2F.js} +3 -3
  11. package/dist/{chunk-M3A2WRXM.js → chunk-OB6OXLPC.js} +430 -2
  12. package/dist/chunk-OB6OXLPC.js.map +1 -0
  13. package/dist/{chunk-DPLCEMEC.js → chunk-ZA4NWNS6.js} +2 -2
  14. package/dist/commands/fleet.js +3 -3
  15. package/dist/commands/init.js +3 -3
  16. package/dist/commands/start.js +3 -3
  17. package/dist/commands/watchdog.js +3 -3
  18. package/dist/dashboard.html +100 -60
  19. package/dist/index.js +2 -2
  20. package/dist/main.js +6 -6
  21. package/dist/start.js +1 -1
  22. package/docs/TOOL-PARITY-PLAN.md +191 -0
  23. package/package.json +23 -24
  24. package/src/memory/dashboard-integration.ts +295 -0
  25. package/src/memory/index.ts +187 -0
  26. package/src/memory/performance-test.ts +208 -0
  27. package/src/memory/processors/agent-sync.ts +312 -0
  28. package/src/memory/processors/command-learner.ts +298 -0
  29. package/src/memory/processors/memory-api-client.ts +105 -0
  30. package/src/memory/processors/message-flow-integration.ts +168 -0
  31. package/src/memory/processors/research-digester.ts +204 -0
  32. package/test-caitlin-access.md +11 -0
  33. package/dist/chunk-M3A2WRXM.js.map +0 -1
  34. package/install.sh +0 -162
  35. package/packages/memory/Cargo.lock +0 -6480
  36. package/packages/memory/Cargo.toml +0 -21
  37. package/packages/memory/src/src/context.rs +0 -179
  38. package/packages/memory/src/src/embeddings.rs +0 -51
  39. package/packages/memory/src/src/main.rs +0 -887
  40. package/packages/memory/src/src/promotion.rs +0 -808
  41. package/packages/memory/src/src/scoring.rs +0 -142
  42. package/packages/memory/src/src/store.rs +0 -460
  43. package/packages/memory/src/src/tasks.rs +0 -321
  44. /package/dist/{chunk-FBQBBAPZ.js.map → chunk-4C6B2AMB.js.map} +0 -0
  45. /package/dist/{chunk-FK6WYXRM.js.map → chunk-4YXOQGQC.js.map} +0 -0
  46. /package/dist/{chunk-IXBIAX76.js.map → chunk-K6KL2VD6.js.map} +0 -0
  47. /package/dist/{chunk-BHCDOHSK.js.map → chunk-LYL5GG2F.js.map} +0 -0
  48. /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.