@sesamespace/hivemind 0.12.2 → 0.12.4

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.
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  Watchdog
3
- } from "./chunk-ZAPHLG7V.js";
3
+ } from "./chunk-FIHSUSBJ.js";
4
4
  import {
5
5
  defaultSentinelConfig,
6
6
  loadConfig
7
- } from "./chunk-R7RHYYOM.js";
7
+ } from "./chunk-PGLO6WA5.js";
8
8
 
9
9
  // packages/cli/src/commands/watchdog.ts
10
10
  import { resolve } from "path";
@@ -76,4 +76,4 @@ Options:
76
76
  export {
77
77
  runWatchdogCommand
78
78
  };
79
- //# sourceMappingURL=chunk-3F7M2BPR.js.map
79
+ //# sourceMappingURL=chunk-TJBUZUVY.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startPipeline
3
- } from "./chunk-R7RHYYOM.js";
3
+ } from "./chunk-PGLO6WA5.js";
4
4
 
5
5
  // packages/cli/src/commands/start.ts
6
6
  import { resolve } from "path";
@@ -66,4 +66,4 @@ Options:
66
66
  export {
67
67
  runStartCommand
68
68
  };
69
- //# sourceMappingURL=chunk-SNW6Z2W4.js.map
69
+ //# sourceMappingURL=chunk-XW4AQDZA.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SesameClient,
3
3
  getClaudeCodeOAuthToken
4
- } from "./chunk-R7RHYYOM.js";
4
+ } from "./chunk-PGLO6WA5.js";
5
5
 
6
6
  // packages/cli/src/commands/init.ts
7
7
  import { resolve, dirname } from "path";
@@ -436,4 +436,4 @@ Options:
436
436
  export {
437
437
  runInitCommand
438
438
  };
439
- //# sourceMappingURL=chunk-ZI4AN7GT.js.map
439
+ //# sourceMappingURL=chunk-YDK3Z5IW.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runFleetCommand
3
- } from "../chunk-EJM4KCCY.js";
4
- import "../chunk-ZAPHLG7V.js";
5
- import "../chunk-R7RHYYOM.js";
3
+ } from "../chunk-J3WGHS5W.js";
4
+ import "../chunk-FIHSUSBJ.js";
5
+ import "../chunk-PGLO6WA5.js";
6
6
  import "../chunk-DGUM43GV.js";
7
7
  export {
8
8
  runFleetCommand
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runInitCommand
3
- } from "../chunk-ZI4AN7GT.js";
4
- import "../chunk-ZAPHLG7V.js";
5
- import "../chunk-R7RHYYOM.js";
3
+ } from "../chunk-YDK3Z5IW.js";
4
+ import "../chunk-FIHSUSBJ.js";
5
+ import "../chunk-PGLO6WA5.js";
6
6
  import "../chunk-DGUM43GV.js";
7
7
  export {
8
8
  runInitCommand
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runStartCommand
3
- } from "../chunk-SNW6Z2W4.js";
4
- import "../chunk-ZAPHLG7V.js";
5
- import "../chunk-R7RHYYOM.js";
3
+ } from "../chunk-XW4AQDZA.js";
4
+ import "../chunk-FIHSUSBJ.js";
5
+ import "../chunk-PGLO6WA5.js";
6
6
  import "../chunk-DGUM43GV.js";
7
7
  export {
8
8
  runStartCommand
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runWatchdogCommand
3
- } from "../chunk-3F7M2BPR.js";
4
- import "../chunk-ZAPHLG7V.js";
5
- import "../chunk-R7RHYYOM.js";
3
+ } from "../chunk-TJBUZUVY.js";
4
+ import "../chunk-FIHSUSBJ.js";
5
+ import "../chunk-PGLO6WA5.js";
6
6
  import "../chunk-DGUM43GV.js";
7
7
  export {
8
8
  runWatchdogCommand
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  PrimaryMemorySync,
5
5
  Watchdog,
6
6
  WorkerMemorySync
7
- } from "./chunk-ZAPHLG7V.js";
7
+ } from "./chunk-FIHSUSBJ.js";
8
8
  import {
9
9
  Agent,
10
10
  AutoDebugger,
@@ -34,7 +34,7 @@ import {
34
34
  setLogLevel,
35
35
  startPipeline,
36
36
  startWorker
37
- } from "./chunk-R7RHYYOM.js";
37
+ } from "./chunk-PGLO6WA5.js";
38
38
  import "./chunk-DGUM43GV.js";
39
39
  export {
40
40
  Agent,
package/dist/main.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runInitCommand
4
- } from "./chunk-ZI4AN7GT.js";
4
+ } from "./chunk-YDK3Z5IW.js";
5
5
  import {
6
6
  runStartCommand
7
- } from "./chunk-SNW6Z2W4.js";
7
+ } from "./chunk-XW4AQDZA.js";
8
8
  import {
9
9
  runFleetCommand
10
- } from "./chunk-EJM4KCCY.js";
10
+ } from "./chunk-J3WGHS5W.js";
11
11
  import {
12
12
  runServiceCommand
13
13
  } from "./chunk-6QZDXOMW.js";
@@ -16,9 +16,9 @@ import {
16
16
  } from "./chunk-ICSJNKI6.js";
17
17
  import {
18
18
  runWatchdogCommand
19
- } from "./chunk-3F7M2BPR.js";
20
- import "./chunk-ZAPHLG7V.js";
21
- import "./chunk-R7RHYYOM.js";
19
+ } from "./chunk-TJBUZUVY.js";
20
+ import "./chunk-FIHSUSBJ.js";
21
+ import "./chunk-PGLO6WA5.js";
22
22
  import "./chunk-DGUM43GV.js";
23
23
 
24
24
  // packages/cli/src/commands/session.ts
package/dist/start.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  loadConfig,
4
4
  startPipeline,
5
5
  startWorker
6
- } from "./chunk-R7RHYYOM.js";
6
+ } from "./chunk-PGLO6WA5.js";
7
7
  import "./chunk-DGUM43GV.js";
8
8
 
9
9
  // packages/runtime/src/start.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sesamespace/hivemind",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "description": "Cognitive architecture for AI agents with multi-layered memory",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Test Suite for Claude Code Integration
3
+ *
4
+ * Tests the bidirectional context bridge, memory storage,
5
+ * and real-time notification systems.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach } from "@jest/globals";
9
+ import { ClaudeContextBridge } from "../packages/runtime/src/tools/context-bridge.js";
10
+ import { ClaudeNotifier } from "../packages/runtime/src/tools/claude-notifier.js";
11
+ import { MemoryClient } from "../packages/runtime/src/memory-client.js";
12
+ import { Logger } from "../packages/runtime/src/logger.js";
13
+ import { writeFileSync, unlinkSync, existsSync } from "fs";
14
+ import { join } from "path";
15
+ import { homedir } from "os";
16
+
17
+ describe("Claude Code Integration", () => {
18
+ let contextBridge: ClaudeContextBridge;
19
+ let memoryClient: MemoryClient;
20
+ let logger: Logger;
21
+ let workspaceDir: string;
22
+ let sessionLogPath: string;
23
+
24
+ beforeEach(async () => {
25
+ // Set up test environment
26
+ workspaceDir = "/tmp/test-workspace";
27
+ sessionLogPath = join(homedir(), ".claude", "session.log");
28
+
29
+ // Create mock implementations
30
+ logger = {
31
+ info: jest.fn(),
32
+ warn: jest.fn(),
33
+ error: jest.fn(),
34
+ debug: jest.fn(),
35
+ } as any;
36
+
37
+ memoryClient = {
38
+ search: jest.fn().mockResolvedValue([]),
39
+ storeEpisode: jest.fn().mockResolvedValue({}),
40
+ } as any;
41
+
42
+ // Create context bridge
43
+ contextBridge = new ClaudeContextBridge({
44
+ workspaceDir,
45
+ memoryClient,
46
+ logger,
47
+ });
48
+
49
+ await contextBridge.initialize();
50
+ });
51
+
52
+ afterEach(() => {
53
+ contextBridge.destroy();
54
+ // Clean up test files
55
+ if (existsSync(sessionLogPath)) {
56
+ unlinkSync(sessionLogPath);
57
+ }
58
+ });
59
+
60
+ describe("Context Preparation", () => {
61
+ it("should prepare context with all fields", async () => {
62
+ const context = {
63
+ goal: "Fix authentication bug",
64
+ requirements: ["Must support OAuth", "Handle token refresh"],
65
+ recentErrors: ["401 Unauthorized on /api/user"],
66
+ relevantPatterns: ["Use middleware for auth"],
67
+ workingFiles: ["src/auth.ts", "src/middleware.ts"],
68
+ knownConstraints: ["JWT tokens expire after 1 hour"],
69
+ };
70
+
71
+ await contextBridge.prepareContext(context);
72
+
73
+ const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
74
+ expect(existsSync(contextFile)).toBe(true);
75
+
76
+ const content = require('fs').readFileSync(contextFile, 'utf-8');
77
+ expect(content).toContain("Fix authentication bug");
78
+ expect(content).toContain("Must support OAuth");
79
+ expect(content).toContain("401 Unauthorized");
80
+ expect(content).toContain("Use middleware for auth");
81
+ expect(content).toContain("src/auth.ts");
82
+ expect(content).toContain("JWT tokens expire after 1 hour");
83
+ });
84
+
85
+ it("should include memory search results", async () => {
86
+ // Mock memory search
87
+ (memoryClient.search as jest.Mock).mockResolvedValue([
88
+ { content: "Previous auth implementation used Passport.js" },
89
+ { content: "Refresh tokens stored in Redis" },
90
+ ]);
91
+
92
+ await contextBridge.prepareContext({ goal: "Implement authentication" });
93
+
94
+ expect(memoryClient.search).toHaveBeenCalledWith("Implement authentication", "global", 5);
95
+
96
+ const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
97
+ const content = require('fs').readFileSync(contextFile, 'utf-8');
98
+ expect(content).toContain("Previous auth implementation used Passport.js");
99
+ expect(content).toContain("Refresh tokens stored in Redis");
100
+ });
101
+ });
102
+
103
+ describe("Session Log Monitoring", () => {
104
+ it("should detect and process DISCOVERY entries", (done) => {
105
+ contextBridge.on('insight', ({ type, content }) => {
106
+ expect(type).toBe('DISCOVERY');
107
+ expect(content).toBe('Found JWT validation in middleware');
108
+ done();
109
+ });
110
+
111
+ // Simulate Claude writing to session log
112
+ setTimeout(() => {
113
+ writeFileSync(sessionLogPath, "DISCOVERY: Found JWT validation in middleware\n", { flag: 'a' });
114
+ }, 100);
115
+ });
116
+
117
+ it("should detect and process NEED entries", (done) => {
118
+ contextBridge.on('context-request', (need) => {
119
+ expect(need).toBe('Database schema for users table');
120
+ done();
121
+ });
122
+
123
+ setTimeout(() => {
124
+ writeFileSync(sessionLogPath, "NEED: Database schema for users table\n", { flag: 'a' });
125
+ }, 100);
126
+ });
127
+
128
+ it("should store PATTERN entries in memory", (done) => {
129
+ contextBridge.on('insight', async ({ type }) => {
130
+ if (type === 'PATTERN') {
131
+ // Give it time to store
132
+ setTimeout(() => {
133
+ expect(memoryClient.storeEpisode).toHaveBeenCalledWith({
134
+ context_name: "claude-code-insights",
135
+ role: "system",
136
+ content: "PATTERN: Always validate JWT in middleware",
137
+ metadata: expect.objectContaining({
138
+ type: "PATTERN",
139
+ source: "claude-code",
140
+ }),
141
+ });
142
+ done();
143
+ }, 100);
144
+ }
145
+ });
146
+
147
+ setTimeout(() => {
148
+ writeFileSync(sessionLogPath, "PATTERN: Always validate JWT in middleware\n", { flag: 'a' });
149
+ }, 100);
150
+ });
151
+
152
+ it("should deduplicate identical patterns", async () => {
153
+ // Write the same pattern twice
154
+ writeFileSync(sessionLogPath, "PATTERN: Use async/await for DB calls\n");
155
+ await new Promise(resolve => setTimeout(resolve, 600));
156
+ writeFileSync(sessionLogPath, "PATTERN: Use async/await for DB calls\n", { flag: 'a' });
157
+ await new Promise(resolve => setTimeout(resolve, 600));
158
+
159
+ // Should only store once
160
+ expect(memoryClient.storeEpisode).toHaveBeenCalledTimes(1);
161
+ });
162
+ });
163
+
164
+ describe("Real-time Context Injection", () => {
165
+ it("should append context when Claude needs it", async () => {
166
+ // Mock memory search for additional context
167
+ (memoryClient.search as jest.Mock).mockResolvedValue([
168
+ { content: "Users table has columns: id, email, password_hash, created_at" },
169
+ ]);
170
+
171
+ // Prepare initial context
172
+ await contextBridge.prepareContext({ goal: "Fix user query" });
173
+
174
+ // Simulate Claude needing more info
175
+ writeFileSync(sessionLogPath, "NEED: Database schema\n", { flag: 'a' });
176
+
177
+ // Wait for processing
178
+ await new Promise(resolve => setTimeout(resolve, 600));
179
+
180
+ // Check that context was appended
181
+ const contextFile = join(workspaceDir, "CLAUDE_CONTEXT.md");
182
+ const content = require('fs').readFileSync(contextFile, 'utf-8');
183
+ expect(content).toContain("Additional Context");
184
+ expect(content).toContain("You asked about: Database schema");
185
+ expect(content).toContain("Users table has columns");
186
+ });
187
+ });
188
+
189
+ describe("Session Summary", () => {
190
+ it("should retrieve categorized insights", async () => {
191
+ // Mock memory with various insight types
192
+ (memoryClient.search as jest.Mock).mockResolvedValue([
193
+ { content: "DISCOVERY: Auth uses JWT with RS256" },
194
+ { content: "PATTERN: Validate tokens in middleware" },
195
+ { content: "ERROR: Missing JWKS endpoint" },
196
+ { content: "COMPLETE: Implemented token refresh" },
197
+ { content: "NEED: Public key for verification" },
198
+ ]);
199
+
200
+ const summary = await contextBridge.getSessionSummary();
201
+
202
+ expect(summary.discoveries).toContain("Auth uses JWT with RS256");
203
+ expect(summary.patterns).toContain("Validate tokens in middleware");
204
+ expect(summary.errors).toContain("Missing JWKS endpoint");
205
+ expect(summary.completions).toContain("Implemented token refresh");
206
+ expect(summary.needs).toContain("Public key for verification");
207
+ });
208
+ });
209
+
210
+ describe("Notification System", () => {
211
+ it("should emit urgent events for NEED requests", (done) => {
212
+ const notifier = new ClaudeNotifier({
213
+ logger,
214
+ contextBridge,
215
+ onNeed: async (need) => {
216
+ expect(need).toBe("API documentation");
217
+ done();
218
+ },
219
+ });
220
+
221
+ // Simulate Claude needing something
222
+ writeFileSync(sessionLogPath, "NEED: API documentation\n", { flag: 'a' });
223
+ });
224
+
225
+ it("should handle critical errors", (done) => {
226
+ const notifier = new ClaudeNotifier({
227
+ logger,
228
+ contextBridge,
229
+ onError: async (error) => {
230
+ expect(error).toBe("Cannot find module 'auth'");
231
+ done();
232
+ },
233
+ });
234
+
235
+ writeFileSync(sessionLogPath, "ERROR: Cannot find module 'auth'\n", { flag: 'a' });
236
+ });
237
+
238
+ it("should create urgent events", (done) => {
239
+ const notifier = new ClaudeNotifier({
240
+ logger,
241
+ contextBridge,
242
+ });
243
+
244
+ notifier.on('urgent-event', (event) => {
245
+ expect(event.type).toBe("immediate");
246
+ expect(event.text).toContain("[Claude Code Urgent]");
247
+ expect(event.text).toContain("Missing database credentials");
248
+ done();
249
+ });
250
+
251
+ notifier.createUrgentEvent("Missing database credentials", "test-channel");
252
+ });
253
+ });
254
+
255
+ describe("End-to-End Integration", () => {
256
+ it("should handle a complete Claude Code session", async () => {
257
+ // Prepare context
258
+ await contextBridge.prepareContext({
259
+ goal: "Implement user authentication",
260
+ requirements: ["Support JWT", "Handle refresh tokens"],
261
+ });
262
+
263
+ // Simulate Claude Code session
264
+ const sessionLog = [
265
+ "DISCOVERY: Found existing Passport.js setup",
266
+ "PATTERN: Use httpOnly cookies for refresh tokens",
267
+ "NEED: Redis connection details",
268
+ "ERROR: Redis connection failed",
269
+ "COMPLETE: Implemented JWT authentication",
270
+ ];
271
+
272
+ for (const line of sessionLog) {
273
+ writeFileSync(sessionLogPath, line + "\n", { flag: 'a' });
274
+ await new Promise(resolve => setTimeout(resolve, 100));
275
+ }
276
+
277
+ // Wait for processing
278
+ await new Promise(resolve => setTimeout(resolve, 1000));
279
+
280
+ // Verify memory storage
281
+ const storeEpisodeCalls = (memoryClient.storeEpisode as jest.Mock).mock.calls;
282
+ expect(storeEpisodeCalls.length).toBeGreaterThanOrEqual(2);
283
+
284
+ // Verify discoveries and patterns were stored
285
+ const storedContent = storeEpisodeCalls.map(call => call[0].content);
286
+ expect(storedContent).toContain("DISCOVERY: Found existing Passport.js setup");
287
+ expect(storedContent).toContain("PATTERN: Use httpOnly cookies for refresh tokens");
288
+
289
+ // Get session summary
290
+ const summary = await contextBridge.getSessionSummary();
291
+ expect(summary.discoveries.length).toBeGreaterThan(0);
292
+ expect(summary.patterns.length).toBeGreaterThan(0);
293
+ expect(summary.errors.length).toBeGreaterThan(0);
294
+ expect(summary.completions.length).toBeGreaterThan(0);
295
+ });
296
+ });
297
+ });
298
+
299
+ describe("Test Suite Requirements", () => {
300
+ it("should cover all critical functionality", () => {
301
+ const testCategories = [
302
+ "Context Preparation",
303
+ "Session Log Monitoring",
304
+ "Real-time Context Injection",
305
+ "Session Summary",
306
+ "Notification System",
307
+ "End-to-End Integration"
308
+ ];
309
+
310
+ const criticalFeatures = [
311
+ "Prepare context with memory search",
312
+ "Monitor session log in real-time",
313
+ "Store discoveries and patterns",
314
+ "Deduplicate patterns",
315
+ "Inject context on NEED",
316
+ "Emit notifications for urgent needs",
317
+ "Generate session summaries",
318
+ "Handle complete sessions"
319
+ ];
320
+
321
+ // This test just documents what we're testing
322
+ expect(testCategories.length).toBeGreaterThanOrEqual(6);
323
+ expect(criticalFeatures.length).toBeGreaterThanOrEqual(8);
324
+ });
325
+ });
package/.session-log.json DELETED
@@ -1,58 +0,0 @@
1
- {
2
- "timestamp": "2026-03-10T00:00:00Z",
3
- "summary": "Fixed stale PID reporting in `hivemind service status` by rewriting showStatus() to parse PIDs from `launchctl list` output instead of PID files. Added kickstart recovery for KeepAlive services (memory, watchdog). Removed hardcoded wrapper scripts from git tracking and added them to .gitignore since they are generated dynamically during `hivemind service install`.",
4
- "decisions": [
5
- {
6
- "topic": "PID source",
7
- "choice": "Parse PID from launchctl list output using regex",
8
- "rationale": "launchctl is the authoritative source for launchd-managed process PIDs; PID files go stale when launchd restarts a crashed process",
9
- "alternatives_considered": ["Keep PID file approach with periodic refresh", "Use ps/pgrep to find processes"]
10
- },
11
- {
12
- "topic": "Stale service recovery",
13
- "choice": "Auto-kickstart KeepAlive services (memory, watchdog) but not agent",
14
- "rationale": "Agent is managed by watchdog, so kickstarting it from status would bypass watchdog's coordination",
15
- "alternatives_considered": ["Kickstart all services", "Only report status without recovery"]
16
- }
17
- ],
18
- "patterns": [
19
- {
20
- "pattern": "Wrapper scripts in bin/ are generated dynamically during `hivemind service install` with correct local paths — never commit them",
21
- "scope": "project-wide"
22
- }
23
- ],
24
- "gotchas": [
25
- {
26
- "issue": "Wrapper scripts had hardcoded paths from another developer's machine committed to git",
27
- "resolution": "Removed from git tracking with `git rm --cached`, added bin/*-wrapper.sh to .gitignore",
28
- "prevention": "The .gitignore entry will prevent future accidental commits"
29
- }
30
- ],
31
- "files_changed": [
32
- {
33
- "path": "packages/cli/src/commands/service.ts",
34
- "action": "modified",
35
- "purpose": "Rewrote showStatus() to use launchctl as PID source with kickstart recovery"
36
- },
37
- {
38
- "path": ".gitignore",
39
- "action": "modified",
40
- "purpose": "Added bin/*-wrapper.sh pattern"
41
- },
42
- {
43
- "path": "bin/agent-wrapper.sh",
44
- "action": "deleted",
45
- "purpose": "Removed hardcoded wrapper script from git tracking"
46
- },
47
- {
48
- "path": "bin/memory-wrapper.sh",
49
- "action": "deleted",
50
- "purpose": "Removed hardcoded wrapper script from git tracking"
51
- },
52
- {
53
- "path": "bin/watchdog-wrapper.sh",
54
- "action": "deleted",
55
- "purpose": "Removed hardcoded wrapper script from git tracking"
56
- }
57
- ]
58
- }