@sesamespace/hivemind 0.8.11 → 0.8.13

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.
@@ -0,0 +1,267 @@
1
+ # Auto-Debug Agent — Design Doc
2
+
3
+ ## Vision
4
+
5
+ A Hivemind background processor that watches agent logs, detects errors, diagnoses root causes, and submits fixes as PRs — creating a self-healing codebase. Any fleet agent (e.g. Caitlin) can run this processor to continuously improve the system while using it.
6
+
7
+ ## How It Works
8
+
9
+ ```
10
+ Logs → Detect → Deduplicate → Diagnose → Fix → PR → Verify
11
+ ```
12
+
13
+ ### 1. Log Watcher (`log-watcher` processor)
14
+
15
+ Tails all Hivemind log files:
16
+ - `/tmp/hivemind-agent.log`
17
+ - `/tmp/hivemind-error.log`
18
+ - `/tmp/hivemind-watchdog.log`
19
+ - `/tmp/hivemind-memory.log`
20
+ - `/tmp/hivemind-memory-error.log`
21
+
22
+ **Detection rules:**
23
+ - Stack traces (multiline, starts with `Error:` or `at ...`)
24
+ - Uncaught exceptions / unhandled rejections
25
+ - Repeated warnings (same message 3+ times in 5 min)
26
+ - Process crashes (exit codes ≠ 0)
27
+ - Health check failures logged by watchdog
28
+ - Memory daemon errors
29
+ - Sesame connection failures
30
+
31
+ **Output:** `ErrorEvent` objects with:
32
+ ```typescript
33
+ interface ErrorEvent {
34
+ id: string; // hash of normalized stack trace
35
+ timestamp: Date;
36
+ source: "agent" | "watchdog" | "memory";
37
+ level: "error" | "crash" | "repeated-warning";
38
+ message: string;
39
+ stackTrace?: string;
40
+ logFile: string;
41
+ lineNumber: number;
42
+ occurrences: number; // count within dedup window
43
+ context: string[]; // surrounding log lines (±10)
44
+ }
45
+ ```
46
+
47
+ ### 2. Deduplication & Prioritization
48
+
49
+ Not every error deserves a PR. The processor maintains a local error registry:
50
+
51
+ ```typescript
52
+ interface ErrorRegistry {
53
+ // key: error id (normalized stack hash)
54
+ errors: Map<string, {
55
+ firstSeen: Date;
56
+ lastSeen: Date;
57
+ totalOccurrences: number;
58
+ status: "new" | "investigating" | "fix-submitted" | "resolved" | "wont-fix";
59
+ prUrl?: string;
60
+ severity: number; // 0-10, auto-calculated
61
+ }>;
62
+ }
63
+ ```
64
+
65
+ **Severity scoring:**
66
+ - Crash/uncaught exception: +5
67
+ - Occurs on every startup: +3
68
+ - Frequency (>10/hour): +2
69
+ - Affects Sesame connectivity: +2
70
+ - Memory daemon related: +1
71
+ - Already has a PR open: -10 (skip)
72
+ - Marked wont-fix: -10 (skip)
73
+
74
+ **Threshold:** Only investigate errors with severity ≥ 3.
75
+
76
+ ### 3. Diagnosis Engine
77
+
78
+ When an error crosses the threshold, the processor:
79
+
80
+ 1. **Locate source:** Parse stack trace → map to source files in the repo
81
+ 2. **Gather context:** Use `code-indexer` data to understand the file, function, and dependencies
82
+ 3. **Check git blame:** Was this recently changed? By whom?
83
+ 4. **Search for related:** Query `task-tracker` for related tasks, check if a fix is already in progress
84
+ 5. **Build diagnosis prompt:** Assemble all context into a structured prompt for the agent's LLM
85
+
86
+ The diagnosis is done by the agent itself (not a separate LLM call) — it feeds into the agent's normal message processing as an internal task.
87
+
88
+ ### 4. Fix Generation
89
+
90
+ Once diagnosed, the agent:
91
+
92
+ 1. Creates a feature branch: `auto-fix/{error-id-short}`
93
+ 2. Makes the code change
94
+ 3. Runs `tsup` to verify build
95
+ 4. Runs tests if available
96
+ 5. Commits with a structured message:
97
+ ```
98
+ fix(auto-debug): {short description}
99
+
100
+ Error: {original error message}
101
+ Occurrences: {count} over {timespan}
102
+ Source: {log file}
103
+
104
+ Root cause: {diagnosis}
105
+
106
+ Auto-generated by hivemind auto-debug processor
107
+ ```
108
+ 6. Pushes branch and opens PR
109
+
110
+ ### 5. PR Template
111
+
112
+ ```markdown
113
+ ## 🤖 Auto-Debug Fix
114
+
115
+ **Error:** `{error message}`
116
+ **Source:** `{file}:{line}`
117
+ **Frequency:** {count} occurrences over {timespan}
118
+ **Severity:** {score}/10
119
+
120
+ ### Diagnosis
121
+ {LLM-generated root cause analysis}
122
+
123
+ ### Fix
124
+ {Description of what changed and why}
125
+
126
+ ### Log Sample
127
+ ```
128
+ {relevant log lines}
129
+ ```
130
+
131
+ ### Verification
132
+ - [ ] Build passes (`tsup`)
133
+ - [ ] Error no longer reproduces (monitored for 30 min post-deploy)
134
+
135
+ ---
136
+ *Auto-generated by hivemind auto-debug processor. Review before merging.*
137
+ ```
138
+
139
+ ### 6. Post-Fix Monitoring
140
+
141
+ After a PR is merged and deployed:
142
+ - Watch for the same error ID in logs
143
+ - If it doesn't recur within 1 hour → mark as `resolved`
144
+ - If it recurs → reopen with additional context, bump severity
145
+
146
+ ## Architecture
147
+
148
+ ### Processor Class
149
+
150
+ ```typescript
151
+ class LogWatcher extends BackgroundProcess {
152
+ name = "log-watcher";
153
+ interval = 10_000; // check every 10s
154
+
155
+ private tailPositions: Map<string, number>; // track file offsets
156
+ private errorRegistry: ErrorRegistry;
157
+ private activeBranches: Set<string>;
158
+
159
+ async run(context: ProcessContext): Promise<ProcessResult> {
160
+ // 1. Read new log lines since last position
161
+ const newLines = this.readNewLines();
162
+
163
+ // 2. Detect errors
164
+ const errors = this.detectErrors(newLines);
165
+
166
+ // 3. Deduplicate and score
167
+ const actionable = this.processErrors(errors);
168
+
169
+ // 4. For high-severity new errors, queue investigation
170
+ for (const error of actionable) {
171
+ await this.queueInvestigation(error, context);
172
+ }
173
+
174
+ return { itemsProcessed: newLines.length, errors: [] };
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Integration Points
180
+
181
+ - **code-indexer:** Provides file/function context for diagnosis
182
+ - **task-tracker:** Tracks fix progress, prevents duplicate work
183
+ - **agent-sync:** In fleet mode, coordinates so multiple agents don't fix the same bug
184
+ - **Sesame:** Posts status updates to a designated channel (e.g. `#hivemind-debug`)
185
+ - **GitHub:** Opens PRs via `gh` CLI
186
+
187
+ ### Fleet Coordination
188
+
189
+ When multiple agents run this processor:
190
+ 1. Error registry is shared via Sesame vault or a shared memory namespace
191
+ 2. Lock mechanism: first agent to claim an error ID owns the investigation
192
+ 3. Other agents provide additional log samples if they see the same error
193
+ 4. Any agent can review/approve another agent's PR
194
+
195
+ ## Configuration
196
+
197
+ ```toml
198
+ [processors.log-watcher]
199
+ enabled = true
200
+ interval_ms = 10_000
201
+ severity_threshold = 3
202
+ log_files = [
203
+ "/tmp/hivemind-agent.log",
204
+ "/tmp/hivemind-error.log",
205
+ "/tmp/hivemind-watchdog.log",
206
+ "/tmp/hivemind-memory.log",
207
+ ]
208
+ auto_pr = true # false = diagnose only, don't submit PRs
209
+ repo = "baileydavis2026/hivemind"
210
+ branch_prefix = "auto-fix"
211
+ notify_channel = "hivemind-debug" # Sesame channel for status updates
212
+ max_concurrent_fixes = 2 # don't overwhelm with PRs
213
+ cooldown_minutes = 30 # min time between PRs for same error class
214
+ ```
215
+
216
+ ## Safety & Guardrails
217
+
218
+ 1. **Human review required:** PRs are never auto-merged. A human must approve.
219
+ 2. **Scope limits:** Auto-debug only touches files in the Hivemind repo, never system files or other projects.
220
+ 3. **Rate limiting:** Max 2 concurrent fix branches, 30-min cooldown per error class.
221
+ 4. **Severity gating:** Only acts on errors above threshold — ignores transient/cosmetic issues.
222
+ 5. **Rollback awareness:** If a fix introduces new errors, the processor detects this and comments on the PR.
223
+ 6. **No secrets in PRs:** Log context is sanitized (API keys, tokens stripped) before inclusion in PR descriptions.
224
+
225
+ ## Implementation Plan
226
+
227
+ ### Phase 1: Log Watcher (detection only)
228
+ - Implement `LogWatcher` processor
229
+ - Error detection, deduplication, registry
230
+ - Sesame channel notifications for new errors
231
+ - Dashboard integration (error list view)
232
+
233
+ ### Phase 2: Diagnosis
234
+ - Stack trace → source mapping
235
+ - Integration with code-indexer for context
236
+ - LLM-powered root cause analysis
237
+ - Diagnosis reports posted to Sesame
238
+
239
+ ### Phase 3: Auto-Fix PRs
240
+ - Branch creation, code changes, PR submission
241
+ - Build verification
242
+ - Post-merge monitoring
243
+ - Fleet coordination (error locking)
244
+
245
+ ### Phase 4: Learning
246
+ - Track fix success rate per error pattern
247
+ - Build pattern library (common fixes for common errors)
248
+ - Skip LLM for known patterns → direct fix
249
+ - Feed insights back to MEMORY-ENHANCEMENT-PLAN
250
+
251
+ ## Success Metrics
252
+
253
+ - **Detection rate:** % of real errors caught vs. total errors in logs
254
+ - **False positive rate:** % of investigations that led to wont-fix
255
+ - **Fix success rate:** % of merged PRs that resolved the error
256
+ - **Time to fix:** From first error occurrence to PR merged
257
+ - **Regression rate:** % of fixes that introduced new errors
258
+
259
+ ## Why This Works
260
+
261
+ The fastest path to a bug-free system is having the system's own users (agents) fix bugs as they encounter them. Every agent running Hivemind becomes a contributor to Hivemind's stability. The more agents deployed, the faster bugs are found and fixed. It's a flywheel:
262
+
263
+ ```
264
+ More agents → More log coverage → More bugs found → More fixes → More stable → More agents
265
+ ```
266
+
267
+ This is the software equivalent of an immune system — the codebase develops antibodies to its own failure modes.
@@ -45,6 +45,24 @@ health_port = 9484
45
45
  pid_file = "/tmp/hivemind-agent.pid"
46
46
  stop_flag_file = "/tmp/hivemind-agent.stopped"
47
47
 
48
+ # Auto-debug — watches logs, diagnoses errors, optionally opens fix PRs
49
+ [auto_debug]
50
+ enabled = false # opt-in: not all agents have GitHub access
51
+ log_files = [
52
+ "/tmp/hivemind-agent.log",
53
+ "/tmp/hivemind-error.log",
54
+ "/tmp/hivemind-watchdog.log",
55
+ "/tmp/hivemind-memory.log",
56
+ "/tmp/hivemind-memory-error.log",
57
+ ]
58
+ severity_threshold = 3
59
+ auto_pr = false # requires gh CLI and repo access
60
+ # repo = "baileydavis2026/hivemind"
61
+ branch_prefix = "auto-fix"
62
+ max_concurrent_fixes = 2
63
+ cooldown_minutes = 30
64
+ # notify_channel = "" # Sesame channel ID for error notifications
65
+
48
66
  # Worker mode — set enabled = true to run as a fleet worker
49
67
  [worker]
50
68
  enabled = false
@@ -5,8 +5,9 @@ import {
5
5
  HEALTH_TIMEOUT_MS,
6
6
  PRIMARY_ROUTES,
7
7
  SesameClient2 as SesameClient,
8
- WORKER_ROUTES
9
- } from "./chunk-OG6GPQDK.js";
8
+ WORKER_ROUTES,
9
+ createLogger
10
+ } from "./chunk-ZM7RK5YV.js";
10
11
 
11
12
  // packages/runtime/src/watchdog.ts
12
13
  import { execSync } from "child_process";
@@ -14,6 +15,7 @@ import { readFileSync, existsSync, unlinkSync } from "fs";
14
15
  import { resolve, dirname } from "path";
15
16
  import { fileURLToPath } from "url";
16
17
  import { get as httpGet } from "http";
18
+ var log = createLogger("watchdog");
17
19
  var WATCHDOG_VERSION = "unknown";
18
20
  try {
19
21
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -28,6 +30,7 @@ var Watchdog = class {
28
30
  sesameConfig = null;
29
31
  pollTimer = null;
30
32
  consecutiveFailures = 0;
33
+ memoryConsecutiveFailures = 0;
31
34
  restartCount = 0;
32
35
  lastStartTime = 0;
33
36
  running = false;
@@ -40,15 +43,15 @@ var Watchdog = class {
40
43
  }
41
44
  async start() {
42
45
  this.running = true;
43
- console.log(`[watchdog] Starting watchdog v${WATCHDOG_VERSION} (pid ${process.pid})`);
44
- console.log(`[watchdog] Monitoring agent health on port ${this.config.health_port}`);
45
- console.log(`[watchdog] Poll interval: ${this.config.poll_interval_ms}ms, grace period: ${this.config.agent_startup_grace_ms}ms`);
46
+ log.info(`Starting watchdog v${WATCHDOG_VERSION}`, { pid: process.pid });
47
+ log.info(`Monitoring agent health on port ${this.config.health_port}`);
48
+ log.info(`Poll interval: ${this.config.poll_interval_ms}ms, grace period: ${this.config.agent_startup_grace_ms}ms`);
46
49
  if (this.sesameConfig) {
47
50
  await this.connectSesame();
48
51
  }
49
52
  this.lastStartTime = Date.now();
50
53
  this.pollTimer = setInterval(() => this.healthCheck(), this.config.poll_interval_ms);
51
- console.log("[watchdog] Health monitoring active");
54
+ log.info("Health monitoring active");
52
55
  }
53
56
  stop() {
54
57
  this.running = false;
@@ -59,25 +62,25 @@ var Watchdog = class {
59
62
  if (this.sesame) {
60
63
  this.sesame.disconnect();
61
64
  }
62
- console.log("[watchdog] Stopped");
65
+ log.info("Stopped");
63
66
  }
64
67
  async connectSesame() {
65
68
  if (!this.sesameConfig) return;
66
69
  this.sesame = new SesameClient(this.sesameConfig);
67
70
  this.sesame.onUpgrade(async (req) => {
68
- console.log(`[watchdog] Upgrade requested: ${req.packageName}@${req.targetVersion} (by ${req.requestedBy})`);
71
+ log.info(`Upgrade requested: ${req.packageName}@${req.targetVersion}`, { requestedBy: req.requestedBy });
69
72
  await this.handleUpgrade(req.packageName, req.targetVersion);
70
73
  });
71
74
  this.sesame.onRestart(async (req) => {
72
- console.log(`[watchdog] Restart requested by ${req.requestedBy}`);
75
+ log.info("Restart requested", { requestedBy: req.requestedBy });
73
76
  await this.handleRestart();
74
77
  });
75
78
  try {
76
79
  await this.sesame.connect();
77
- console.log("[watchdog] Sesame connected (control events only)");
80
+ log.info("Sesame connected (control events only)");
78
81
  } catch (err) {
79
- console.error("[watchdog] Sesame connection failed:", err.message);
80
- console.warn("[watchdog] Continuing without Sesame \u2014 health monitoring still active");
82
+ log.error("Sesame connection failed", { error: err.message });
83
+ log.warn("Continuing without Sesame \u2014 health monitoring still active");
81
84
  this.sesame = null;
82
85
  }
83
86
  }
@@ -92,20 +95,64 @@ var Watchdog = class {
92
95
  const health = await this.fetchHealth();
93
96
  if (health.status === "ok" && health.sesame_connected) {
94
97
  if (this.consecutiveFailures > 0) {
95
- console.log("[watchdog] Agent recovered, resetting failure count");
98
+ log.info("Agent recovered, resetting failure count");
96
99
  }
97
100
  this.consecutiveFailures = 0;
98
101
  this.restartCount = 0;
99
102
  } else {
100
103
  this.consecutiveFailures++;
101
- console.warn(`[watchdog] Agent degraded (${this.consecutiveFailures} consecutive): status=${health.status}, sesame=${health.sesame_connected}`);
104
+ log.warn(`Agent degraded (${this.consecutiveFailures} consecutive)`, { status: health.status, sesame: health.sesame_connected });
102
105
  this.maybeRestart();
103
106
  }
104
107
  } catch {
105
108
  this.consecutiveFailures++;
106
- console.warn(`[watchdog] Agent unreachable (${this.consecutiveFailures} consecutive failures)`);
109
+ log.warn(`Agent unreachable (${this.consecutiveFailures} consecutive failures)`);
107
110
  this.maybeRestart();
108
111
  }
112
+ await this.memoryHealthCheck();
113
+ }
114
+ async memoryHealthCheck() {
115
+ try {
116
+ await new Promise((resolve2, reject) => {
117
+ const req = httpGet(
118
+ "http://127.0.0.1:3434/health",
119
+ { timeout: 5e3 },
120
+ (res) => {
121
+ let data = "";
122
+ res.on("data", (chunk) => data += chunk);
123
+ res.on("end", () => {
124
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
125
+ resolve2();
126
+ } else {
127
+ reject(new Error(`Memory health returned ${res.statusCode}`));
128
+ }
129
+ });
130
+ }
131
+ );
132
+ req.on("error", reject);
133
+ req.on("timeout", () => {
134
+ req.destroy();
135
+ reject(new Error("Memory health check timed out"));
136
+ });
137
+ });
138
+ if (this.memoryConsecutiveFailures > 0) {
139
+ log.info("Memory daemon recovered", { previousFailures: this.memoryConsecutiveFailures });
140
+ }
141
+ this.memoryConsecutiveFailures = 0;
142
+ } catch (err) {
143
+ this.memoryConsecutiveFailures++;
144
+ log.warn(`Memory daemon unhealthy (${this.memoryConsecutiveFailures} consecutive)`, { error: err.message });
145
+ if (this.memoryConsecutiveFailures >= 3) {
146
+ log.warn("Memory daemon down for 3+ checks, attempting restart");
147
+ try {
148
+ const uid = execSync("id -u", { encoding: "utf-8" }).trim();
149
+ execSync(`launchctl kickstart gui/${uid}/com.hivemind.memory`, { timeout: 1e4 });
150
+ log.info("Memory daemon restart initiated via launchctl");
151
+ } catch (restartErr) {
152
+ log.error("Failed to restart memory daemon", { error: restartErr.message });
153
+ }
154
+ }
155
+ }
109
156
  }
110
157
  fetchHealth() {
111
158
  return new Promise((resolve2, reject) => {
@@ -148,7 +195,7 @@ var Watchdog = class {
148
195
  return;
149
196
  }
150
197
  }
151
- console.log(`[watchdog] Restarting agent (attempt ${this.restartCount + 1})`);
198
+ log.info(`Restarting agent (attempt ${this.restartCount + 1})`);
152
199
  this.restartAgent();
153
200
  }
154
201
  // ── Agent Lifecycle ──
@@ -1048,4 +1095,4 @@ export {
1048
1095
  WorkerMemorySync,
1049
1096
  PrimaryMemorySync
1050
1097
  };
1051
- //# sourceMappingURL=chunk-A5LMEJIN.js.map
1098
+ //# sourceMappingURL=chunk-4Y7A25UG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/runtime/src/watchdog.ts","../packages/runtime/src/fleet/primary-client.ts","../packages/runtime/src/fleet/fleet-manager.ts","../packages/runtime/src/fleet/memory-sync.ts"],"sourcesContent":["import { execSync } from \"child_process\";\r\nimport { readFileSync, existsSync, unlinkSync } from \"fs\";\r\nimport { resolve, dirname } from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\nimport { get as httpGet } from \"http\";\r\nimport { SesameClient } from \"./sesame.js\";\r\nimport type { SesameConfig, SentinelConfig } from \"./config.js\";\r\nimport type { HealthStatus } from \"./health.js\";\r\nimport { HEALTH_PATH } from \"./health.js\";\r\nimport { createLogger } from \"./logger.js\";\r\n\r\nconst log = createLogger(\"watchdog\");\r\n\r\n// Read version at module load time\r\nlet WATCHDOG_VERSION = \"unknown\";\r\ntry {\r\n const __dirname = dirname(fileURLToPath(import.meta.url));\r\n const pkg = JSON.parse(readFileSync(resolve(__dirname, \"../package.json\"), \"utf-8\"));\r\n WATCHDOG_VERSION = pkg.version ?? \"unknown\";\r\n} catch {\r\n // give up\r\n}\r\n\r\nconst AGENT_LABEL = \"com.hivemind.agent\";\r\n\r\nexport class Watchdog {\r\n private config: SentinelConfig;\r\n private sesame: SesameClient | null = null;\r\n private sesameConfig: SesameConfig | null = null;\r\n private pollTimer: ReturnType<typeof setInterval> | null = null;\r\n private consecutiveFailures = 0;\r\n private memoryConsecutiveFailures = 0;\r\n private restartCount = 0;\r\n private lastStartTime = 0;\r\n private running = false;\r\n private upgradeInProgress = false;\r\n\r\n constructor(config: SentinelConfig, sesameConfig?: SesameConfig) {\r\n this.config = config;\r\n if (sesameConfig?.api_key) {\r\n this.sesameConfig = sesameConfig;\r\n }\r\n }\r\n\r\n async start(): Promise<void> {\r\n this.running = true;\r\n log.info(`Starting watchdog v${WATCHDOG_VERSION}`, { pid: process.pid });\r\n log.info(`Monitoring agent health on port ${this.config.health_port}`);\r\n log.info(`Poll interval: ${this.config.poll_interval_ms}ms, grace period: ${this.config.agent_startup_grace_ms}ms`);\r\n\r\n // Connect to Sesame for control events\r\n if (this.sesameConfig) {\r\n await this.connectSesame();\r\n }\r\n\r\n // Record current time as start reference (assume agent is already running or about to start)\r\n this.lastStartTime = Date.now();\r\n\r\n // Start health monitoring loop\r\n this.pollTimer = setInterval(() => this.healthCheck(), this.config.poll_interval_ms);\r\n log.info(\"Health monitoring active\");\r\n }\r\n\r\n stop(): void {\r\n this.running = false;\r\n if (this.pollTimer) {\r\n clearInterval(this.pollTimer);\r\n this.pollTimer = null;\r\n }\r\n if (this.sesame) {\r\n this.sesame.disconnect();\r\n }\r\n log.info(\"Stopped\");\r\n }\r\n\r\n private async connectSesame(): Promise<void> {\r\n if (!this.sesameConfig) return;\r\n\r\n this.sesame = new SesameClient(this.sesameConfig);\r\n\r\n this.sesame.onUpgrade(async (req) => {\r\n log.info(`Upgrade requested: ${req.packageName}@${req.targetVersion}`, { requestedBy: req.requestedBy });\r\n await this.handleUpgrade(req.packageName, req.targetVersion);\r\n });\r\n\r\n this.sesame.onRestart(async (req) => {\r\n log.info(\"Restart requested\", { requestedBy: req.requestedBy });\r\n await this.handleRestart();\r\n });\r\n\r\n try {\r\n await this.sesame.connect();\r\n log.info(\"Sesame connected (control events only)\");\r\n } catch (err) {\r\n log.error(\"Sesame connection failed\", { error: (err as Error).message });\r\n log.warn(\"Continuing without Sesame — health monitoring still active\");\r\n this.sesame = null;\r\n }\r\n }\r\n\r\n // ── Health Monitoring ──\r\n\r\n private async healthCheck(): Promise<void> {\r\n if (!this.running || this.upgradeInProgress) return;\r\n\r\n // Grace period after start/restart\r\n const elapsed = Date.now() - this.lastStartTime;\r\n if (elapsed < this.config.agent_startup_grace_ms) {\r\n return;\r\n }\r\n\r\n try {\r\n const health = await this.fetchHealth();\r\n\r\n if (health.status === \"ok\" && health.sesame_connected) {\r\n // Healthy — reset counters\r\n if (this.consecutiveFailures > 0) {\r\n log.info(\"Agent recovered, resetting failure count\");\r\n }\r\n this.consecutiveFailures = 0;\r\n this.restartCount = 0;\r\n } else {\r\n // Degraded — count as failure\r\n this.consecutiveFailures++;\r\n log.warn(`Agent degraded (${this.consecutiveFailures} consecutive)`, { status: health.status, sesame: health.sesame_connected });\r\n this.maybeRestart();\r\n }\r\n } catch {\r\n // Unreachable — count as failure\r\n this.consecutiveFailures++;\r\n log.warn(`Agent unreachable (${this.consecutiveFailures} consecutive failures)`);\r\n this.maybeRestart();\r\n }\r\n\r\n // Also check memory daemon health\r\n await this.memoryHealthCheck();\r\n }\r\n\r\n private async memoryHealthCheck(): Promise<void> {\r\n try {\r\n await new Promise<void>((resolve, reject) => {\r\n const req = httpGet(\r\n \"http://127.0.0.1:3434/health\",\r\n { timeout: 5_000 },\r\n (res) => {\r\n let data = \"\";\r\n res.on(\"data\", (chunk) => (data += chunk));\r\n res.on(\"end\", () => {\r\n if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Memory health returned ${res.statusCode}`));\r\n }\r\n });\r\n },\r\n );\r\n req.on(\"error\", reject);\r\n req.on(\"timeout\", () => { req.destroy(); reject(new Error(\"Memory health check timed out\")); });\r\n });\r\n\r\n if (this.memoryConsecutiveFailures > 0) {\r\n log.info(\"Memory daemon recovered\", { previousFailures: this.memoryConsecutiveFailures });\r\n }\r\n this.memoryConsecutiveFailures = 0;\r\n } catch (err) {\r\n this.memoryConsecutiveFailures++;\r\n log.warn(`Memory daemon unhealthy (${this.memoryConsecutiveFailures} consecutive)`, { error: (err as Error).message });\r\n\r\n if (this.memoryConsecutiveFailures >= 3) {\r\n log.warn(\"Memory daemon down for 3+ checks, attempting restart\");\r\n try {\r\n const uid = execSync(\"id -u\", { encoding: \"utf-8\" }).trim();\r\n execSync(`launchctl kickstart gui/${uid}/com.hivemind.memory`, { timeout: 10_000 });\r\n log.info(\"Memory daemon restart initiated via launchctl\");\r\n } catch (restartErr) {\r\n log.error(\"Failed to restart memory daemon\", { error: (restartErr as Error).message });\r\n }\r\n }\r\n }\r\n }\r\n\r\n private fetchHealth(): Promise<HealthStatus> {\r\n return new Promise((resolve, reject) => {\r\n const req = httpGet(\r\n `http://127.0.0.1:${this.config.health_port}${HEALTH_PATH}`,\r\n { timeout: this.config.health_timeout_ms },\r\n (res) => {\r\n let data = \"\";\r\n res.on(\"data\", (chunk) => (data += chunk));\r\n res.on(\"end\", () => {\r\n try {\r\n resolve(JSON.parse(data) as HealthStatus);\r\n } catch {\r\n reject(new Error(\"Invalid JSON from health endpoint\"));\r\n }\r\n });\r\n },\r\n );\r\n req.on(\"error\", reject);\r\n req.on(\"timeout\", () => {\r\n req.destroy();\r\n reject(new Error(\"Health check timed out\"));\r\n });\r\n });\r\n }\r\n\r\n private maybeRestart(): void {\r\n // Check stop flag\r\n if (existsSync(this.config.stop_flag_file)) {\r\n console.log(\"[watchdog] Stop flag exists, skipping restart\");\r\n return;\r\n }\r\n\r\n // Need 2+ consecutive failures before restarting\r\n if (this.consecutiveFailures < 2) return;\r\n\r\n // Check backoff\r\n if (this.restartCount >= this.config.max_restart_attempts) {\r\n const backoff = Math.min(\r\n this.config.backoff_base_ms * Math.pow(2, this.restartCount - this.config.max_restart_attempts),\r\n this.config.backoff_max_ms,\r\n );\r\n const timeSinceStart = Date.now() - this.lastStartTime;\r\n if (timeSinceStart < backoff) {\r\n console.warn(`[watchdog] Backoff active (${Math.round(backoff / 1000)}s), skipping restart`);\r\n return;\r\n }\r\n }\r\n\r\n log.info(`Restarting agent (attempt ${this.restartCount + 1})`);\r\n this.restartAgent();\r\n }\r\n\r\n // ── Agent Lifecycle ──\r\n\r\n private async stopAgent(): Promise<boolean> {\r\n const pid = this.readAgentPid();\r\n if (!pid) {\r\n console.log(\"[watchdog] No PID file found, agent may not be running\");\r\n return true;\r\n }\r\n\r\n // Send SIGTERM\r\n try {\r\n process.kill(pid, \"SIGTERM\");\r\n console.log(`[watchdog] Sent SIGTERM to agent (pid ${pid})`);\r\n } catch {\r\n // Process already gone\r\n console.log(`[watchdog] Agent (pid ${pid}) already stopped`);\r\n return true;\r\n }\r\n\r\n // Poll for exit (10s timeout)\r\n const deadline = Date.now() + 10_000;\r\n while (Date.now() < deadline) {\r\n await sleep(500);\r\n if (!this.isProcessRunning(pid)) {\r\n console.log(`[watchdog] Agent (pid ${pid}) stopped cleanly`);\r\n return true;\r\n }\r\n }\r\n\r\n // Escalate to SIGKILL\r\n console.warn(`[watchdog] Agent (pid ${pid}) did not stop, sending SIGKILL`);\r\n try {\r\n process.kill(pid, \"SIGKILL\");\r\n } catch {\r\n // Already gone\r\n }\r\n await sleep(1000);\r\n return !this.isProcessRunning(pid);\r\n }\r\n\r\n private startAgentViaLaunchd(): void {\r\n // Remove stop flag if present (watchdog-initiated restarts should not be blocked)\r\n try { unlinkSync(this.config.stop_flag_file); } catch { /* not present */ }\r\n\r\n const uid = execSync(\"id -u\", { encoding: \"utf-8\" }).trim();\r\n try {\r\n execSync(`launchctl kickstart gui/${uid}/${AGENT_LABEL}`, { timeout: 10_000 });\r\n console.log(\"[watchdog] Agent started via launchctl\");\r\n } catch (err) {\r\n console.error(\"[watchdog] launchctl kickstart failed:\", (err as Error).message);\r\n }\r\n this.lastStartTime = Date.now();\r\n this.consecutiveFailures = 0;\r\n }\r\n\r\n private restartAgent(): void {\r\n this.restartCount++;\r\n this.stopAgent().then(() => {\r\n this.startAgentViaLaunchd();\r\n });\r\n }\r\n\r\n // ── Upgrade Flow ──\r\n\r\n private async handleUpgrade(packageName: string, targetVersion: string): Promise<void> {\r\n if (this.upgradeInProgress) {\r\n console.warn(\"[watchdog] Upgrade already in progress, ignoring\");\r\n return;\r\n }\r\n this.upgradeInProgress = true;\r\n\r\n try {\r\n // 1. Record current version\r\n const oldVersion = this.getCurrentInstalledVersion(packageName);\r\n console.log(`[watchdog] Current version: ${oldVersion}`);\r\n\r\n // 2. Update presence\r\n this.sesame?.updatePresence(\"working\", { detail: `Upgrading to ${targetVersion}`, emoji: \"⬆️\" });\r\n\r\n // 3. Stop agent\r\n console.log(\"[watchdog] Stopping agent for upgrade...\");\r\n await this.stopAgent();\r\n\r\n // 4. Run npm install\r\n const target = targetVersion === \"latest\" ? packageName : `${packageName}@${targetVersion}`;\r\n console.log(`[watchdog] Running: npm install -g ${target}`);\r\n\r\n try {\r\n execSync(`npm install -g ${target}`, { stdio: \"inherit\", timeout: 120_000 });\r\n console.log(\"[watchdog] Package updated successfully\");\r\n } catch (err) {\r\n // Install failed — restart agent with old version\r\n console.error(`[watchdog] npm install failed: ${(err as Error).message}`);\r\n this.sesame?.updatePresence(\"online\", { detail: \"Upgrade failed — npm install error\", emoji: \"❌\" });\r\n this.startAgentViaLaunchd();\r\n await this.waitForHealthy(30_000);\r\n return;\r\n }\r\n\r\n // 5. Start agent with new version\r\n this.sesame?.updatePresence(\"working\", { detail: \"Restarting after upgrade\", emoji: \"🔄\" });\r\n this.startAgentViaLaunchd();\r\n\r\n // 6. Wait for health\r\n const healthy = await this.waitForHealthy(30_000);\r\n\r\n if (healthy) {\r\n console.log(\"[watchdog] Agent healthy after upgrade\");\r\n this.sesame?.updatePresence(\"online\", { detail: `Upgraded to ${targetVersion}`, emoji: \"🟢\" });\r\n } else {\r\n // Rollback\r\n console.error(\"[watchdog] Agent unhealthy after upgrade — rolling back\");\r\n await this.stopAgent();\r\n\r\n if (oldVersion && oldVersion !== \"unknown\") {\r\n console.log(`[watchdog] Rolling back to ${packageName}@${oldVersion}`);\r\n try {\r\n execSync(`npm install -g ${packageName}@${oldVersion}`, { stdio: \"inherit\", timeout: 120_000 });\r\n } catch (rollbackErr) {\r\n console.error(\"[watchdog] Rollback install failed:\", (rollbackErr as Error).message);\r\n }\r\n }\r\n\r\n this.startAgentViaLaunchd();\r\n this.sesame?.updatePresence(\"online\", { detail: \"Upgrade failed — rolled back\", emoji: \"❌\" });\r\n }\r\n\r\n // 7. Self-update check: if watchdog binary version differs from installed package\r\n this.checkSelfUpdate();\r\n } finally {\r\n this.upgradeInProgress = false;\r\n }\r\n }\r\n\r\n // ── Restart Flow ──\r\n\r\n private async handleRestart(): Promise<void> {\r\n this.sesame?.updatePresence(\"working\", { detail: \"Restarting...\", emoji: \"🔄\" });\r\n\r\n await this.stopAgent();\r\n this.startAgentViaLaunchd();\r\n\r\n const healthy = await this.waitForHealthy(30_000);\r\n if (healthy) {\r\n console.log(\"[watchdog] Agent restarted successfully\");\r\n this.sesame?.updatePresence(\"online\", { emoji: \"🟢\" });\r\n } else {\r\n console.error(\"[watchdog] Agent unhealthy after restart\");\r\n this.sesame?.updatePresence(\"online\", { detail: \"Restart completed (agent unhealthy)\", emoji: \"⚠️\" });\r\n }\r\n }\r\n\r\n // ── Utilities ──\r\n\r\n private readAgentPid(): number | null {\r\n try {\r\n const raw = readFileSync(this.config.pid_file, \"utf-8\").trim();\r\n const pid = parseInt(raw, 10);\r\n return isNaN(pid) ? null : pid;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private isProcessRunning(pid: number): boolean {\r\n try {\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n private async waitForHealthy(timeoutMs: number): Promise<boolean> {\r\n const deadline = Date.now() + timeoutMs;\r\n while (Date.now() < deadline) {\r\n await sleep(2_000);\r\n try {\r\n const health = await this.fetchHealth();\r\n if (health.status === \"ok\" && health.sesame_connected) {\r\n return true;\r\n }\r\n } catch {\r\n // not ready yet\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n private getCurrentInstalledVersion(packageName: string): string {\r\n try {\r\n const out = execSync(`npm ls -g ${packageName} --depth=0 --json 2>/dev/null`, { encoding: \"utf-8\" });\r\n const parsed = JSON.parse(out);\r\n return parsed.dependencies?.[packageName]?.version ?? \"unknown\";\r\n } catch {\r\n return \"unknown\";\r\n }\r\n }\r\n\r\n private checkSelfUpdate(): void {\r\n try {\r\n const __dirname = dirname(fileURLToPath(import.meta.url));\r\n const pkg = JSON.parse(readFileSync(resolve(__dirname, \"../package.json\"), \"utf-8\"));\r\n const installedVersion = pkg.version ?? \"unknown\";\r\n\r\n if (installedVersion !== WATCHDOG_VERSION) {\r\n console.log(`[watchdog] Binary version (${WATCHDOG_VERSION}) differs from installed (${installedVersion})`);\r\n console.log(\"[watchdog] Exiting for self-update — launchd will restart with new binary\");\r\n process.exit(0);\r\n }\r\n } catch {\r\n // Can't check — continue running\r\n }\r\n }\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n","/**\n * Primary-side client for managing Workers.\n *\n * The Primary uses this to:\n * - Track registered workers\n * - Poll worker health\n * - Assign/unassign contexts to workers\n * - Collect status reports\n */\n\nimport type {\n WorkerInfo,\n WorkerRegistrationRequest,\n WorkerRegistrationResponse,\n WorkerHealthResponse,\n WorkerHealthStatus,\n WorkerStatus,\n WorkerStatusReport,\n ContextAssignRequest,\n ContextAssignResponse,\n SyncPushRequest,\n SyncPushResponse,\n SyncPullRequest,\n SyncPullResponse,\n} from \"./worker-protocol.js\";\n\nimport {\n PRIMARY_ROUTES,\n WORKER_ROUTES,\n DEFAULT_HEALTH_INTERVAL_MS,\n HEALTH_TIMEOUT_MS,\n} from \"./worker-protocol.js\";\n\nexport class PrimaryClient {\n private workers: Map<string, WorkerInfo> = new Map();\n private healthTimer: ReturnType<typeof setInterval> | null = null;\n private nextId = 1;\n private onSyncPullCallback: ((req: SyncPullRequest) => Promise<SyncPullResponse>) | null = null;\n\n /** All registered workers. */\n getWorkers(): WorkerInfo[] {\n return Array.from(this.workers.values());\n }\n\n /** Get a single worker by ID. */\n getWorker(workerId: string): WorkerInfo | undefined {\n return this.workers.get(workerId);\n }\n\n /** Find which worker owns a context, if any. */\n findWorkerForContext(contextName: string): WorkerInfo | undefined {\n for (const w of this.workers.values()) {\n if (w.assigned_contexts.includes(contextName)) return w;\n }\n return undefined;\n }\n\n // --- Registration (called when Worker POSTs to Primary) ---\n\n handleRegistration(req: WorkerRegistrationRequest): WorkerRegistrationResponse {\n const id = `worker-${this.nextId++}`;\n const now = new Date().toISOString();\n\n const info: WorkerInfo = {\n id,\n url: req.url,\n capabilities: req.capabilities,\n assigned_contexts: [],\n registered_at: now,\n last_heartbeat: now,\n };\n\n this.workers.set(id, info);\n return { worker_id: id, registered_at: now };\n }\n\n /** Remove a worker from the registry. */\n deregister(workerId: string): boolean {\n return this.workers.delete(workerId);\n }\n\n // --- Health Checking ---\n\n /** Poll a single worker's health endpoint. */\n async checkHealth(workerId: string): Promise<WorkerHealthResponse | null> {\n const worker = this.workers.get(workerId);\n if (!worker) return null;\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);\n\n const resp = await fetch(`${worker.url}${WORKER_ROUTES.health}`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (!resp.ok) {\n this.markUnreachable(workerId);\n return null;\n }\n\n const health = (await resp.json()) as WorkerHealthResponse;\n worker.last_heartbeat = new Date().toISOString();\n return health;\n } catch {\n this.markUnreachable(workerId);\n return null;\n }\n }\n\n /** Poll all workers and return their statuses. */\n async checkAllHealth(): Promise<Map<string, WorkerHealthStatus>> {\n const results = new Map<string, WorkerHealthStatus>();\n\n const checks = Array.from(this.workers.keys()).map(async (id) => {\n const health = await this.checkHealth(id);\n results.set(id, health?.status ?? \"unreachable\");\n });\n\n await Promise.all(checks);\n return results;\n }\n\n /** Start periodic health polling. */\n startHealthPolling(intervalMs = DEFAULT_HEALTH_INTERVAL_MS): void {\n this.stopHealthPolling();\n this.healthTimer = setInterval(() => {\n this.checkAllHealth().catch(() => {});\n }, intervalMs);\n }\n\n /** Stop periodic health polling. */\n stopHealthPolling(): void {\n if (this.healthTimer) {\n clearInterval(this.healthTimer);\n this.healthTimer = null;\n }\n }\n\n // --- Context Assignment ---\n\n /** Assign a context to a worker. */\n async assignContext(\n workerId: string,\n contextName: string,\n contextDescription = \"\",\n ): Promise<ContextAssignResponse> {\n const worker = this.workers.get(workerId);\n if (!worker) {\n return { context_name: contextName, accepted: false, reason: \"Worker not found\" };\n }\n\n if (worker.assigned_contexts.length >= worker.capabilities.max_contexts) {\n return { context_name: contextName, accepted: false, reason: \"Worker at capacity\" };\n }\n\n const body: ContextAssignRequest = {\n context_name: contextName,\n context_description: contextDescription,\n };\n\n try {\n const resp = await fetch(`${worker.url}${WORKER_ROUTES.assign}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n const text = await resp.text();\n return { context_name: contextName, accepted: false, reason: `Worker rejected: ${text}` };\n }\n\n const result = (await resp.json()) as ContextAssignResponse;\n\n if (result.accepted) {\n worker.assigned_contexts.push(contextName);\n }\n\n return result;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { context_name: contextName, accepted: false, reason: `Request failed: ${msg}` };\n }\n }\n\n /** Unassign a context from a worker. */\n async unassignContext(workerId: string, contextName: string): Promise<boolean> {\n const worker = this.workers.get(workerId);\n if (!worker) return false;\n\n try {\n const resp = await fetch(`${worker.url}${WORKER_ROUTES.unassign(contextName)}`, {\n method: \"DELETE\",\n });\n\n if (resp.ok) {\n worker.assigned_contexts = worker.assigned_contexts.filter((c) => c !== contextName);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n }\n\n // --- Status Collection ---\n\n /** Handle an incoming status report from a Worker. */\n handleStatusReport(workerId: string, report: WorkerStatusReport): WorkerStatus | null {\n const worker = this.workers.get(workerId);\n if (!worker) return null;\n\n worker.last_heartbeat = new Date().toISOString();\n\n return {\n worker_id: workerId,\n activity: report.activity,\n current_context: report.current_context,\n current_task: report.current_task,\n error: report.error,\n reported_at: new Date().toISOString(),\n };\n }\n\n // --- Memory Sync ---\n\n /** Register a handler for incoming sync pull requests from Workers. */\n onSyncPull(cb: (req: SyncPullRequest) => Promise<SyncPullResponse>): void {\n this.onSyncPullCallback = cb;\n }\n\n /** Handle an incoming sync pull (Worker sends L3 knowledge to Primary). */\n async handleSyncPull(req: SyncPullRequest): Promise<SyncPullResponse> {\n if (!this.onSyncPullCallback) {\n return { accepted: 0, rejected: req.entries.length };\n }\n return this.onSyncPullCallback(req);\n }\n\n /** Push Global context updates to a specific worker. */\n async pushSyncToWorker(workerId: string, payload: SyncPushRequest): Promise<SyncPushResponse | null> {\n const worker = this.workers.get(workerId);\n if (!worker) return null;\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);\n\n const resp = await fetch(`${worker.url}${WORKER_ROUTES.syncPush}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (!resp.ok) return null;\n return (await resp.json()) as SyncPushResponse;\n } catch {\n return null;\n }\n }\n\n /** Push Global context updates to all registered workers. */\n async pushSyncToAll(payload: SyncPushRequest): Promise<Map<string, SyncPushResponse | null>> {\n const results = new Map<string, SyncPushResponse | null>();\n\n const pushes = Array.from(this.workers.keys()).map(async (id) => {\n const result = await this.pushSyncToWorker(id, payload);\n results.set(id, result);\n });\n\n await Promise.all(pushes);\n return results;\n }\n\n // --- Internal ---\n\n private markUnreachable(workerId: string): void {\n // Worker stays registered but health is tracked via last_heartbeat staleness.\n // Fleet manager (Phase 3.3) will decide when to evict.\n }\n}\n","/**\n * Fleet Manager — high-level orchestration layer on top of PrimaryClient.\n *\n * Provides:\n * - Worker provisioning (register by URL)\n * - Context assignment and migration between workers\n * - Aggregate fleet status / dashboard data\n * - Worker discovery and removal\n */\n\nimport { PrimaryClient } from \"./primary-client.js\";\nimport {\n WORKER_ROUTES,\n HEALTH_TIMEOUT_MS,\n} from \"./worker-protocol.js\";\nimport type {\n WorkerInfo,\n WorkerHealthResponse,\n WorkerHealthStatus,\n WorkerCapabilities,\n ContextAssignResponse,\n WorkerStatus,\n WorkerActivity,\n} from \"./worker-protocol.js\";\n\n// --- Dashboard Types ---\n\nexport interface WorkerSummary {\n id: string;\n url: string;\n health: WorkerHealthStatus;\n contexts: string[];\n current_task: string | null;\n activity: WorkerActivity;\n uptime_seconds: number | null;\n capabilities: WorkerCapabilities;\n last_heartbeat: string;\n}\n\nexport interface FleetDashboard {\n total_workers: number;\n healthy: number;\n degraded: number;\n unreachable: number;\n total_contexts: number;\n workers: WorkerSummary[];\n unassigned_contexts: string[];\n generated_at: string;\n}\n\nexport interface MigrationResult {\n context_name: string;\n from_worker: string;\n to_worker: string;\n success: boolean;\n reason?: string;\n}\n\nexport class FleetManager {\n private primary: PrimaryClient;\n private latestHealth: Map<string, WorkerHealthResponse> = new Map();\n private latestStatus: Map<string, WorkerStatus> = new Map();\n private knownContexts: Set<string> = new Set();\n\n constructor(primary?: PrimaryClient) {\n this.primary = primary ?? new PrimaryClient();\n }\n\n getPrimary(): PrimaryClient {\n return this.primary;\n }\n\n // --- Worker Provisioning ---\n\n /**\n * Register a new worker by URL. Probes the worker's health endpoint\n * to discover capabilities, then registers it with the Primary.\n */\n async addWorker(url: string): Promise<WorkerInfo> {\n // Normalise trailing slash\n const baseUrl = url.replace(/\\/+$/, \"\");\n\n // Probe worker health to discover capabilities\n const capabilities = await this.probeWorker(baseUrl);\n\n const reg = this.primary.handleRegistration({ url: baseUrl, capabilities });\n\n const worker = this.primary.getWorker(reg.worker_id);\n if (!worker) {\n throw new Error(\"Worker registered but not found in registry\");\n }\n\n return worker;\n }\n\n /** Remove a worker from the fleet, unassigning its contexts first. */\n async removeWorker(workerId: string): Promise<boolean> {\n const worker = this.primary.getWorker(workerId);\n if (!worker) return false;\n\n // Unassign all contexts from this worker\n for (const ctx of [...worker.assigned_contexts]) {\n await this.primary.unassignContext(workerId, ctx);\n }\n\n return this.primary.deregister(workerId);\n }\n\n // --- Context Assignment ---\n\n /** Assign a context to a specific worker. */\n async assignContext(\n workerId: string,\n contextName: string,\n description = \"\",\n ): Promise<ContextAssignResponse> {\n const result = await this.primary.assignContext(workerId, contextName, description);\n if (result.accepted) {\n this.knownContexts.add(contextName);\n }\n return result;\n }\n\n /** Migrate a context from one worker to another. */\n async migrateContext(\n contextName: string,\n toWorkerId: string,\n ): Promise<MigrationResult> {\n const fromWorker = this.primary.findWorkerForContext(contextName);\n\n if (!fromWorker) {\n // Context isn't assigned anywhere — just assign to target\n const resp = await this.primary.assignContext(toWorkerId, contextName);\n return {\n context_name: contextName,\n from_worker: \"(none)\",\n to_worker: toWorkerId,\n success: resp.accepted,\n reason: resp.accepted ? undefined : resp.reason,\n };\n }\n\n if (fromWorker.id === toWorkerId) {\n return {\n context_name: contextName,\n from_worker: fromWorker.id,\n to_worker: toWorkerId,\n success: false,\n reason: \"Context already assigned to this worker\",\n };\n }\n\n // Assign to new worker first, then unassign from old\n const assignResult = await this.primary.assignContext(toWorkerId, contextName);\n if (!assignResult.accepted) {\n return {\n context_name: contextName,\n from_worker: fromWorker.id,\n to_worker: toWorkerId,\n success: false,\n reason: assignResult.reason ?? \"Target worker rejected assignment\",\n };\n }\n\n await this.primary.unassignContext(fromWorker.id, contextName);\n\n return {\n context_name: contextName,\n from_worker: fromWorker.id,\n to_worker: toWorkerId,\n success: true,\n };\n }\n\n // --- Status & Health ---\n\n /** Refresh health for all workers. */\n async refreshHealth(): Promise<void> {\n const workers = this.primary.getWorkers();\n\n const checks = workers.map(async (w) => {\n const health = await this.primary.checkHealth(w.id);\n if (health) {\n this.latestHealth.set(w.id, health);\n } else {\n // Mark unreachable but keep stale data\n this.latestHealth.set(w.id, {\n worker_id: w.id,\n status: \"unreachable\",\n uptime_seconds: 0,\n assigned_contexts: w.assigned_contexts,\n active_context: null,\n memory_daemon_ok: false,\n ollama_ok: false,\n });\n }\n });\n\n await Promise.all(checks);\n }\n\n /** Record a status report (called when worker POSTs status to Primary). */\n recordStatus(workerId: string, status: WorkerStatus): void {\n this.latestStatus.set(workerId, status);\n }\n\n /** Get the full fleet dashboard. */\n async getDashboard(): Promise<FleetDashboard> {\n await this.refreshHealth();\n\n const workers = this.primary.getWorkers();\n let healthy = 0;\n let degraded = 0;\n let unreachable = 0;\n let totalContexts = 0;\n\n const workerSummaries: WorkerSummary[] = workers.map((w) => {\n const health = this.latestHealth.get(w.id);\n const status = this.latestStatus.get(w.id);\n\n const healthStatus: WorkerHealthStatus = health?.status ?? \"unreachable\";\n if (healthStatus === \"healthy\") healthy++;\n else if (healthStatus === \"degraded\") degraded++;\n else unreachable++;\n\n totalContexts += w.assigned_contexts.length;\n\n return {\n id: w.id,\n url: w.url,\n health: healthStatus,\n contexts: w.assigned_contexts,\n current_task: status?.current_task ?? null,\n activity: status?.activity ?? \"idle\",\n uptime_seconds: health?.uptime_seconds ?? null,\n capabilities: w.capabilities,\n last_heartbeat: w.last_heartbeat,\n };\n });\n\n // Determine unassigned contexts\n const assignedContexts = new Set(workers.flatMap((w) => w.assigned_contexts));\n const unassigned = [...this.knownContexts].filter((c) => !assignedContexts.has(c));\n\n return {\n total_workers: workers.length,\n healthy,\n degraded,\n unreachable,\n total_contexts: totalContexts,\n workers: workerSummaries,\n unassigned_contexts: unassigned,\n generated_at: new Date().toISOString(),\n };\n }\n\n /** Get a quick status summary without refreshing health. */\n getStatusSnapshot(): FleetDashboard {\n const workers = this.primary.getWorkers();\n let healthy = 0;\n let degraded = 0;\n let unreachable = 0;\n let totalContexts = 0;\n\n const workerSummaries: WorkerSummary[] = workers.map((w) => {\n const health = this.latestHealth.get(w.id);\n const status = this.latestStatus.get(w.id);\n\n const healthStatus: WorkerHealthStatus = health?.status ?? \"unreachable\";\n if (healthStatus === \"healthy\") healthy++;\n else if (healthStatus === \"degraded\") degraded++;\n else unreachable++;\n\n totalContexts += w.assigned_contexts.length;\n\n return {\n id: w.id,\n url: w.url,\n health: healthStatus,\n contexts: w.assigned_contexts,\n current_task: status?.current_task ?? null,\n activity: status?.activity ?? \"idle\",\n uptime_seconds: health?.uptime_seconds ?? null,\n capabilities: w.capabilities,\n last_heartbeat: w.last_heartbeat,\n };\n });\n\n const assignedContexts = new Set(workers.flatMap((w) => w.assigned_contexts));\n const unassigned = [...this.knownContexts].filter((c) => !assignedContexts.has(c));\n\n return {\n total_workers: workers.length,\n healthy,\n degraded,\n unreachable,\n total_contexts: totalContexts,\n workers: workerSummaries,\n unassigned_contexts: unassigned,\n generated_at: new Date().toISOString(),\n };\n }\n\n // --- Worker Discovery ---\n\n /**\n * Scan a list of candidate URLs for workers. Returns the URLs\n * that responded to a health probe. Useful for auto-detecting\n * workers on a local network.\n */\n async discoverWorkers(candidateUrls: string[]): Promise<string[]> {\n const found: string[] = [];\n\n const probes = candidateUrls.map(async (url) => {\n const baseUrl = url.replace(/\\/+$/, \"\");\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);\n\n const resp = await fetch(`${baseUrl}${WORKER_ROUTES.health}`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (resp.ok) {\n found.push(baseUrl);\n }\n } catch {\n // Not reachable, skip\n }\n });\n\n await Promise.all(probes);\n return found;\n }\n\n /**\n * Scan a subnet-style range for workers. Generates URLs for\n * a base IP with ports and probes them.\n * Example: scanSubnet(\"192.168.1\", [10, 11, 12], 3100)\n */\n async scanSubnet(\n baseIp: string,\n hostIds: number[],\n port: number,\n ): Promise<string[]> {\n const urls = hostIds.map((id) => `http://${baseIp}.${id}:${port}`);\n return this.discoverWorkers(urls);\n }\n\n /** Track a context name so it appears in unassigned lists. */\n registerContext(contextName: string): void {\n this.knownContexts.add(contextName);\n }\n\n /** Start health polling (delegates to PrimaryClient). */\n startHealthPolling(intervalMs?: number): void {\n this.primary.startHealthPolling(intervalMs);\n }\n\n /** Stop health polling. */\n stopHealthPolling(): void {\n this.primary.stopHealthPolling();\n }\n\n // --- Internal ---\n\n private async probeWorker(baseUrl: string): Promise<WorkerCapabilities> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);\n\n const resp = await fetch(`${baseUrl}${WORKER_ROUTES.health}`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (resp.ok) {\n const health = (await resp.json()) as WorkerHealthResponse;\n return {\n max_contexts: health.assigned_contexts.length + 4, // assume capacity\n has_ollama: health.ollama_ok,\n has_memory_daemon: health.memory_daemon_ok,\n available_models: [],\n };\n }\n } catch {\n // Fall through to defaults\n }\n\n // Return default capabilities if probe fails\n return {\n max_contexts: 4,\n has_ollama: false,\n has_memory_daemon: false,\n available_models: [],\n };\n }\n}\n","/**\n * Cross-machine memory sync.\n *\n * Workers periodically push key L3 knowledge back to the Primary.\n * Primary can push Global context updates (L3 + L2 episodes) to workers.\n *\n * Conflict resolution:\n * - L3: last-write-wins (compared by updated_at timestamp)\n * - L2: append-only (episodes are never overwritten, only added)\n *\n * Sync protocol:\n * POST /sync/pull — Worker sends L3 knowledge to Primary\n * POST /sync/push — Primary sends Global context updates to Worker\n */\n\nimport type { MemoryClient, L3Entry, Episode } from \"../memory-client.js\";\nimport type { PrimaryClient } from \"./primary-client.js\";\nimport type { WorkerServer } from \"./worker-server.js\";\nimport type {\n SyncPullRequest,\n SyncPullResponse,\n SyncPushRequest,\n SyncPushResponse,\n SyncL3Entry,\n SyncL2Episode,\n} from \"./worker-protocol.js\";\nimport { DEFAULT_SYNC_INTERVAL_MS, HEALTH_TIMEOUT_MS, PRIMARY_ROUTES } from \"./worker-protocol.js\";\n\n// --- Helpers ---\n\nfunction l3ToSync(entry: L3Entry): SyncL3Entry {\n return {\n id: entry.id,\n source_episode_id: entry.source_episode_id,\n context_name: entry.context_name,\n content: entry.content,\n promoted_at: entry.promoted_at,\n access_count: entry.access_count,\n connection_density: entry.connection_density,\n updated_at: entry.promoted_at,\n };\n}\n\nfunction episodeToSync(ep: Episode): SyncL2Episode {\n return {\n id: ep.id,\n timestamp: ep.timestamp,\n context_name: ep.context_name,\n role: ep.role,\n content: ep.content,\n };\n}\n\n// --- MemorySync (Worker side) ---\n\nexport interface WorkerSyncOptions {\n workerId: string;\n primaryUrl: string;\n memory: MemoryClient;\n server: WorkerServer;\n syncIntervalMs?: number;\n}\n\n/**\n * Worker-side memory sync. Periodically sends L3 knowledge from assigned\n * contexts back to the Primary, and accepts Global context pushes.\n */\nexport class WorkerMemorySync {\n private workerId: string;\n private primaryUrl: string;\n private memory: MemoryClient;\n private syncTimer: ReturnType<typeof setInterval> | null = null;\n private syncIntervalMs: number;\n private knownL2Ids: Set<string> = new Set();\n private knownL3Ids: Map<string, string> = new Map(); // id -> updated_at\n\n constructor(opts: WorkerSyncOptions) {\n this.workerId = opts.workerId;\n this.primaryUrl = opts.primaryUrl;\n this.memory = opts.memory;\n this.syncIntervalMs = opts.syncIntervalMs ?? DEFAULT_SYNC_INTERVAL_MS;\n\n // Register handler for incoming Global context pushes from Primary\n opts.server.onSyncPush((req) => this.handlePush(req));\n }\n\n /** Start periodic sync (Worker -> Primary). */\n start(contextNames: () => string[]): void {\n this.stop();\n this.syncTimer = setInterval(() => {\n this.pullTowardsPrimary(contextNames()).catch((err) => {\n console.warn(\"[sync] Pull cycle failed:\", (err as Error).message);\n });\n }, this.syncIntervalMs);\n }\n\n /** Stop periodic sync. */\n stop(): void {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = null;\n }\n }\n\n /**\n * Pull L3 knowledge from all assigned contexts and send to Primary.\n * Called periodically by the sync timer.\n */\n async pullTowardsPrimary(contextNames: string[]): Promise<void> {\n for (const contextName of contextNames) {\n try {\n const entries = await this.memory.getL3Knowledge(contextName);\n if (entries.length === 0) continue;\n\n const syncEntries = entries.map(l3ToSync);\n\n const req: SyncPullRequest = {\n worker_id: this.workerId,\n context_name: contextName,\n entries: syncEntries,\n };\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);\n\n const resp = await fetch(`${this.primaryUrl}${PRIMARY_ROUTES.syncPull}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(req),\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (resp.ok) {\n const result = (await resp.json()) as SyncPullResponse;\n if (result.accepted > 0) {\n console.log(`[sync] Pushed ${result.accepted} L3 entries from \"${contextName}\" to Primary`);\n }\n }\n } catch {\n // Primary unreachable — will retry next interval\n }\n }\n }\n\n /**\n * Handle an incoming push of Global context updates from the Primary.\n * L3: last-write-wins. L2: append-only.\n */\n async handlePush(req: SyncPushRequest): Promise<SyncPushResponse> {\n let l3Accepted = 0;\n let l2Appended = 0;\n\n // Process L3 entries with last-write-wins\n for (const entry of req.entries) {\n const existing = this.knownL3Ids.get(entry.id);\n if (existing && existing >= entry.updated_at) {\n // Local version is same or newer — skip\n continue;\n }\n\n // Store in local memory daemon (the memory daemon's L3 store handles upsert)\n try {\n // Store as an episode in the global context so the worker has access\n await this.memory.storeEpisode({\n context_name: entry.context_name,\n role: \"system\",\n content: entry.content,\n });\n this.knownL3Ids.set(entry.id, entry.updated_at);\n l3Accepted++;\n } catch {\n // Non-fatal — entry will be retried on next push\n }\n }\n\n // Process L2 episodes as append-only\n for (const episode of req.episodes) {\n if (this.knownL2Ids.has(episode.id)) {\n continue; // Already stored\n }\n\n try {\n await this.memory.storeEpisode({\n context_name: episode.context_name,\n role: episode.role,\n content: episode.content,\n });\n this.knownL2Ids.add(episode.id);\n l2Appended++;\n } catch {\n // Non-fatal\n }\n }\n\n if (l3Accepted > 0 || l2Appended > 0) {\n console.log(`[sync] Received push: ${l3Accepted} L3 accepted, ${l2Appended} L2 appended`);\n }\n\n return { l3_accepted: l3Accepted, l2_appended: l2Appended };\n }\n\n getSyncIntervalMs(): number {\n return this.syncIntervalMs;\n }\n}\n\n// --- PrimaryMemorySync ---\n\nexport interface PrimarySyncOptions {\n primary: PrimaryClient;\n memory: MemoryClient;\n syncIntervalMs?: number;\n}\n\n/**\n * Primary-side memory sync. Handles incoming L3 pulls from workers and\n * can push Global context updates out to all workers.\n */\nexport class PrimaryMemorySync {\n private primary: PrimaryClient;\n private memory: MemoryClient;\n private syncIntervalMs: number;\n private pushTimer: ReturnType<typeof setInterval> | null = null;\n private l3Store: Map<string, SyncL3Entry> = new Map(); // id -> latest entry\n private lastPushAt: string = new Date(0).toISOString();\n\n constructor(opts: PrimarySyncOptions) {\n this.primary = opts.primary;\n this.memory = opts.memory;\n this.syncIntervalMs = opts.syncIntervalMs ?? DEFAULT_SYNC_INTERVAL_MS;\n\n // Register handler for incoming L3 pulls from workers\n this.primary.onSyncPull((req) => this.handlePull(req));\n }\n\n /**\n * Handle an incoming pull — Worker sending L3 knowledge to Primary.\n * Uses last-write-wins for conflict resolution.\n */\n async handlePull(req: SyncPullRequest): Promise<SyncPullResponse> {\n let accepted = 0;\n let rejected = 0;\n\n for (const entry of req.entries) {\n const existing = this.l3Store.get(entry.id);\n\n if (existing && existing.updated_at >= entry.updated_at) {\n // Primary has same or newer version — reject\n rejected++;\n continue;\n }\n\n // Accept the entry — store locally\n this.l3Store.set(entry.id, entry);\n\n // Persist to Primary's memory daemon\n try {\n await this.memory.storeEpisode({\n context_name: entry.context_name,\n role: \"system\",\n content: entry.content,\n });\n } catch {\n // Non-fatal — the in-memory store is the source of truth for sync\n }\n\n accepted++;\n }\n\n if (accepted > 0) {\n console.log(\n `[sync] Accepted ${accepted} L3 entries from worker \"${req.worker_id}\" context \"${req.context_name}\"`,\n );\n }\n\n return { accepted, rejected };\n }\n\n /**\n * Push Global context updates to all workers.\n * Fetches current Global L3 knowledge and recent L2 episodes,\n * then pushes to every registered worker.\n */\n async pushGlobalToAll(): Promise<Map<string, SyncPushResponse | null>> {\n // Gather Global context L3 knowledge\n let l3Entries: SyncL3Entry[] = [];\n try {\n const knowledge = await this.memory.getL3Knowledge(\"global\");\n l3Entries = knowledge.map(l3ToSync);\n } catch {\n // Memory daemon may not have global context yet\n }\n\n // Gather recent Global L2 episodes (append-only)\n let l2Episodes: SyncL2Episode[] = [];\n try {\n const episodes = await this.memory.getContext(\"global\");\n // Only send episodes newer than last push\n l2Episodes = episodes\n .filter((ep) => ep.timestamp > this.lastPushAt)\n .map(episodeToSync);\n } catch {\n // Memory daemon may not have global context yet\n }\n\n if (l3Entries.length === 0 && l2Episodes.length === 0) {\n return new Map();\n }\n\n const payload: SyncPushRequest = {\n entries: l3Entries,\n episodes: l2Episodes,\n };\n\n this.lastPushAt = new Date().toISOString();\n\n const results = await this.primary.pushSyncToAll(payload);\n\n let totalL3 = 0;\n let totalL2 = 0;\n for (const resp of results.values()) {\n if (resp) {\n totalL3 += resp.l3_accepted;\n totalL2 += resp.l2_appended;\n }\n }\n\n if (totalL3 > 0 || totalL2 > 0) {\n console.log(`[sync] Pushed Global updates: ${totalL3} L3, ${totalL2} L2 across ${results.size} workers`);\n }\n\n return results;\n }\n\n /** Start periodic Global push to all workers. */\n startPushLoop(): void {\n this.stopPushLoop();\n this.pushTimer = setInterval(() => {\n this.pushGlobalToAll().catch((err) => {\n console.warn(\"[sync] Push cycle failed:\", (err as Error).message);\n });\n }, this.syncIntervalMs);\n }\n\n /** Stop periodic push. */\n stopPushLoop(): void {\n if (this.pushTimer) {\n clearInterval(this.pushTimer);\n this.pushTimer = null;\n }\n }\n\n /** Get all synced L3 entries the Primary has received. */\n getSyncedEntries(): SyncL3Entry[] {\n return Array.from(this.l3Store.values());\n }\n\n getSyncIntervalMs(): number {\n return this.syncIntervalMs;\n }\n}\n"],"mappings":"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","names":["resolve"]}
@@ -0,0 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
11
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  FleetManager
3
- } from "./chunk-A5LMEJIN.js";
3
+ } from "./chunk-4Y7A25UG.js";
4
4
 
5
5
  // packages/cli/src/commands/fleet.ts
6
6
  function formatUptime(seconds) {
@@ -183,4 +183,4 @@ Commands:
183
183
  export {
184
184
  runFleetCommand
185
185
  };
186
- //# sourceMappingURL=chunk-SMUG64N7.js.map
186
+ //# sourceMappingURL=chunk-HTLHMXAL.js.map