@sesamespace/hivemind 0.8.12 → 0.10.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.
- package/README.md +2 -1
- package/config/default.toml +18 -0
- package/dist/{chunk-NCJW2AOK.js → chunk-BHCDOHSK.js} +3 -3
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-OVRYYS5I.js → chunk-DPLCEMEC.js} +2 -2
- package/dist/{chunk-XQZU3ULO.js → chunk-FBQBBAPZ.js} +2 -2
- package/dist/{chunk-XBJGLZ7V.js → chunk-FK6WYXRM.js} +79 -2
- package/dist/chunk-FK6WYXRM.js.map +1 -0
- package/dist/{chunk-LJHJGDKY.js → chunk-ICSJNKI6.js} +62 -2
- package/dist/chunk-ICSJNKI6.js.map +1 -0
- package/dist/{chunk-HDYEAKN5.js → chunk-IXBIAX76.js} +4 -34
- package/dist/chunk-IXBIAX76.js.map +1 -0
- package/dist/{chunk-OG6GPQDK.js → chunk-M3A2WRXM.js} +1765 -189
- package/dist/chunk-M3A2WRXM.js.map +1 -0
- package/dist/commands/fleet.js +4 -3
- package/dist/commands/init.js +4 -3
- package/dist/commands/service.js +1 -0
- package/dist/commands/start.js +4 -3
- package/dist/commands/upgrade.js +2 -1
- package/dist/commands/watchdog.js +4 -3
- package/dist/dashboard.html +873 -131
- package/dist/index.js +14 -5
- package/dist/main.js +376 -7
- package/dist/main.js.map +1 -1
- package/dist/start.js +2 -1
- package/dist/start.js.map +1 -1
- package/install.sh +162 -0
- package/package.json +24 -23
- package/packages/memory/Cargo.lock +6480 -0
- package/packages/memory/Cargo.toml +21 -0
- package/packages/memory/src/src/context.rs +179 -0
- package/packages/memory/src/src/embeddings.rs +51 -0
- package/packages/memory/src/src/main.rs +887 -0
- package/packages/memory/src/src/promotion.rs +808 -0
- package/packages/memory/src/src/scoring.rs +142 -0
- package/packages/memory/src/src/store.rs +460 -0
- package/packages/memory/src/src/tasks.rs +321 -0
- package/.pnpmrc.json +0 -1
- package/DASHBOARD-PLAN.md +0 -206
- package/MEMORY-ENHANCEMENT-PLAN.md +0 -211
- package/TOOL-USE-DESIGN.md +0 -173
- package/dist/chunk-HDYEAKN5.js.map +0 -1
- package/dist/chunk-LJHJGDKY.js.map +0 -1
- package/dist/chunk-OG6GPQDK.js.map +0 -1
- package/dist/chunk-XBJGLZ7V.js.map +0 -1
- package/docs/TOOL-PARITY-PLAN.md +0 -191
- package/src/memory/dashboard-integration.ts +0 -295
- package/src/memory/index.ts +0 -187
- package/src/memory/performance-test.ts +0 -208
- package/src/memory/processors/agent-sync.ts +0 -312
- package/src/memory/processors/command-learner.ts +0 -298
- package/src/memory/processors/memory-api-client.ts +0 -105
- package/src/memory/processors/message-flow-integration.ts +0 -168
- package/src/memory/processors/research-digester.ts +0 -204
- package/test-caitlin-access.md +0 -11
- /package/dist/{chunk-NCJW2AOK.js.map → chunk-BHCDOHSK.js.map} +0 -0
- /package/dist/{chunk-OVRYYS5I.js.map → chunk-DPLCEMEC.js.map} +0 -0
- /package/dist/{chunk-XQZU3ULO.js.map → chunk-FBQBBAPZ.js.map} +0 -0
package/README.md
CHANGED
package/config/default.toml
CHANGED
|
@@ -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
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Watchdog
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IXBIAX76.js";
|
|
4
4
|
import {
|
|
5
5
|
defaultSentinelConfig,
|
|
6
6
|
loadConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-M3A2WRXM.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-
|
|
79
|
+
//# sourceMappingURL=chunk-BHCDOHSK.js.map
|
|
@@ -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
|
startPipeline
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-M3A2WRXM.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-
|
|
69
|
+
//# sourceMappingURL=chunk-DPLCEMEC.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FleetManager
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IXBIAX76.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-
|
|
186
|
+
//# sourceMappingURL=chunk-FBQBBAPZ.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SesameClient,
|
|
3
3
|
getClaudeCodeOAuthToken
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-M3A2WRXM.js";
|
|
5
5
|
|
|
6
6
|
// packages/cli/src/commands/init.ts
|
|
7
7
|
import { resolve, dirname } from "path";
|
|
@@ -242,6 +242,83 @@ api_key = "${sesameApiKey}"
|
|
|
242
242
|
await installOllama();
|
|
243
243
|
await pullEmbeddingModel();
|
|
244
244
|
await downloadMemoryDaemon();
|
|
245
|
+
console.log("\n\u2192 Setting up Claude Code session logging...");
|
|
246
|
+
try {
|
|
247
|
+
const claudeDir = resolve(homedir(), ".claude");
|
|
248
|
+
const claudeMd = resolve(claudeDir, "CLAUDE.md");
|
|
249
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
250
|
+
const sessionLoggingInstructions = `# Claude Code \u2014 Global Instructions
|
|
251
|
+
|
|
252
|
+
## Session Logging
|
|
253
|
+
|
|
254
|
+
Before completing any session, write a \`.session-log.json\` file in the project root with the following structure:
|
|
255
|
+
|
|
256
|
+
\`\`\`json
|
|
257
|
+
{
|
|
258
|
+
"timestamp": "<ISO-8601>",
|
|
259
|
+
"summary": "One paragraph describing what was done and why",
|
|
260
|
+
"decisions": [
|
|
261
|
+
{
|
|
262
|
+
"topic": "Short label",
|
|
263
|
+
"choice": "What was chosen",
|
|
264
|
+
"rationale": "Why this over alternatives",
|
|
265
|
+
"alternatives_considered": ["alt1", "alt2"]
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
"patterns": [
|
|
269
|
+
{
|
|
270
|
+
"pattern": "Description of a coding pattern or convention",
|
|
271
|
+
"scope": "project-wide | file-specific | language-general"
|
|
272
|
+
}
|
|
273
|
+
],
|
|
274
|
+
"gotchas": [
|
|
275
|
+
{
|
|
276
|
+
"issue": "What went wrong or was tricky",
|
|
277
|
+
"resolution": "How it was fixed or worked around",
|
|
278
|
+
"prevention": "How to avoid it next time"
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
"files_changed": [
|
|
282
|
+
{
|
|
283
|
+
"path": "relative/path/to/file",
|
|
284
|
+
"action": "created | modified | deleted",
|
|
285
|
+
"purpose": "Why this file was changed"
|
|
286
|
+
}
|
|
287
|
+
]
|
|
288
|
+
}
|
|
289
|
+
\`\`\`
|
|
290
|
+
|
|
291
|
+
Rules:
|
|
292
|
+
- Always create this file, even for small changes
|
|
293
|
+
- Omit empty arrays (e.g. if no gotchas, leave out the key)
|
|
294
|
+
- Be specific in decisions and gotchas \u2014 these help future sessions
|
|
295
|
+
- The file is gitignored and consumed by tooling, not humans
|
|
296
|
+
`;
|
|
297
|
+
if (existsSync(claudeMd)) {
|
|
298
|
+
const existing = readFileSync(claudeMd, "utf-8");
|
|
299
|
+
if (!existing.includes("Session Logging")) {
|
|
300
|
+
writeFileSync(claudeMd, existing + "\n" + sessionLoggingInstructions);
|
|
301
|
+
console.log(" \u2713 Appended session logging to existing CLAUDE.md");
|
|
302
|
+
} else {
|
|
303
|
+
console.log(" \u2713 CLAUDE.md already has session logging");
|
|
304
|
+
}
|
|
305
|
+
} else {
|
|
306
|
+
writeFileSync(claudeMd, sessionLoggingInstructions);
|
|
307
|
+
console.log(` \u2713 Created ${claudeMd}`);
|
|
308
|
+
}
|
|
309
|
+
const globalGitignore = resolve(homedir(), ".gitignore_global");
|
|
310
|
+
const gitignoreContent = existsSync(globalGitignore) ? readFileSync(globalGitignore, "utf-8") : "";
|
|
311
|
+
if (!gitignoreContent.includes(".session-log.json")) {
|
|
312
|
+
writeFileSync(globalGitignore, gitignoreContent + "\n.session-log.json\n");
|
|
313
|
+
try {
|
|
314
|
+
execSync(`git config --global core.excludesfile "${globalGitignore}"`, { stdio: "ignore" });
|
|
315
|
+
} catch {
|
|
316
|
+
}
|
|
317
|
+
console.log(" \u2713 Added .session-log.json to global gitignore");
|
|
318
|
+
}
|
|
319
|
+
} catch (err) {
|
|
320
|
+
console.log(` ! Claude Code setup skipped: ${err.message}`);
|
|
321
|
+
}
|
|
245
322
|
console.log(`
|
|
246
323
|
\u2713 Hivemind initialized for ${config.agentName}!
|
|
247
324
|
|
|
@@ -359,4 +436,4 @@ Options:
|
|
|
359
436
|
export {
|
|
360
437
|
runInitCommand
|
|
361
438
|
};
|
|
362
|
-
//# sourceMappingURL=chunk-
|
|
439
|
+
//# sourceMappingURL=chunk-FK6WYXRM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../packages/cli/src/commands/init.ts"],"sourcesContent":["import { resolve, dirname } from \"path\";\nimport { existsSync, writeFileSync, mkdirSync, readFileSync, copyFileSync, realpathSync, chmodSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { fileURLToPath } from \"url\";\nimport { execSync } from \"child_process\";\nimport { SesameClient } from \"@sesamespace/sdk\";\nimport { getClaudeCodeOAuthToken } from \"@hivemind/runtime\";\nimport { homedir, arch, platform } from \"os\";\n\nconst HIVEMIND_DIR = resolve(process.env.HIVEMIND_HOME || resolve(homedir(), \"hivemind\"));\nconst CONFIG_DIR = resolve(HIVEMIND_DIR, \"config\");\nconst WORKSPACE_DIR = resolve(HIVEMIND_DIR, \"workspace\");\nconst BIN_DIR = resolve(HIVEMIND_DIR, \"bin\");\nconst DATA_DIR = resolve(HIVEMIND_DIR, \"data\");\nconst ENV_FILE = resolve(HIVEMIND_DIR, \".env\");\nconst LOCAL_TOML = resolve(CONFIG_DIR, \"local.toml\");\nconst MEMORY_BIN = resolve(BIN_DIR, \"hivemind-memory\");\n\nconst RELEASES_BASE_URL = \"https://sesame-hivemind-releases.s3.amazonaws.com\";\nconst EMBEDDING_MODEL = \"nomic-embed-text\";\n\nconst VAULT_CONFIG_NAME = \"hivemind-config\";\n\ninterface ProvisioningConfig {\n agentName: string;\n agentHandle: string;\n agentId: string;\n personality?: string;\n llmApiKey?: string;\n llmBaseUrl?: string;\n llmModel?: string;\n llmProvider?: 'openai' | 'anthropic';\n fleetRole?: string;\n channels: Array<{ id: string; name: string | null; kind: string }>;\n}\n\nasync function prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport async function runInitCommand(args: string[]): Promise<void> {\n const nonInteractive = args.includes(\"--yes\") || args.includes(\"-y\") || args.includes(\"--non-interactive\");\n const filteredArgs = args.filter((a) => ![\"--yes\", \"-y\", \"--non-interactive\", \"--help\", \"-h\"].includes(a));\n let sesameApiKey = filteredArgs[0];\n\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n printHelp();\n return;\n }\n\n console.log(`\n ╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗\n ╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║\n ╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝\n Agent Initialization\n`);\n\n // --- Step 1: Get Sesame API key ---\n // Check existing config if no key provided\n if (!sesameApiKey) {\n // Try .env file\n if (existsSync(ENV_FILE)) {\n try {\n const envContent = readFileSync(ENV_FILE, \"utf-8\");\n const match = envContent.match(/^SESAME_API_KEY=(.+)$/m);\n if (match && match[1].trim()) {\n sesameApiKey = match[1].trim();\n console.log(\" ✓ Found existing API key in .env\");\n }\n } catch {}\n }\n // Try local.toml\n if (!sesameApiKey && existsSync(LOCAL_TOML)) {\n try {\n const tomlContent = readFileSync(LOCAL_TOML, \"utf-8\");\n const match = tomlContent.match(/api_key\\s*=\\s*\"([^\"]+)\"/);\n if (match && match[1].trim()) {\n sesameApiKey = match[1].trim();\n console.log(\" ✓ Found existing API key in local.toml\");\n }\n } catch {}\n }\n // Try environment variable\n if (!sesameApiKey && process.env.SESAME_API_KEY) {\n sesameApiKey = process.env.SESAME_API_KEY;\n console.log(\" ✓ Using API key from SESAME_API_KEY env var\");\n }\n }\n if (!sesameApiKey) {\n sesameApiKey = await prompt(\" Sesame API key: \");\n }\n if (!sesameApiKey) {\n console.error(\"Error: Sesame API key is required\");\n process.exit(1);\n }\n\n // --- Step 2: Connect to Sesame and fetch manifest ---\n console.log(\"\\n→ Connecting to Sesame...\");\n const sdk = new SesameClient({\n apiUrl: \"https://api.sesame.space\",\n wsUrl: \"wss://ws.sesame.space\",\n apiKey: sesameApiKey,\n });\n\n let config: ProvisioningConfig;\n try {\n const manifest = await sdk.getManifest();\n console.log(` ✓ Authenticated as ${manifest.agent.handle} (${manifest.agent.id})`);\n console.log(` ✓ Workspace: ${manifest.workspace.name}`);\n console.log(` ✓ Channels: ${manifest.channels.length}`);\n for (const ch of manifest.channels) {\n console.log(` - ${ch.name || ch.id} (${ch.kind})`);\n }\n\n config = {\n agentName: manifest.agent.handle,\n agentHandle: manifest.agent.handle,\n agentId: manifest.agent.id,\n channels: manifest.channels.map((ch) => ({\n id: ch.id,\n name: ch.name,\n kind: ch.kind,\n })),\n };\n\n // --- Step 3: Check vault for config ---\n console.log(\"\\n→ Checking vault for provisioning config...\");\n try {\n const vaultResp = await sdk.listVaultItems() as any;\n const items = vaultResp.items || vaultResp.data || [];\n const configItem = items.find((i: any) => i.name === VAULT_CONFIG_NAME);\n\n if (configItem) {\n console.log(` ✓ Found ${VAULT_CONFIG_NAME} vault item`);\n const revealResp = await sdk.revealItem(configItem.id) as any;\n const fields = revealResp.data?.fields || revealResp.fields || revealResp.data || {};\n\n config.llmApiKey = fields.llm_api_key || fields.openrouter_api_key;\n config.llmBaseUrl = fields.llm_base_url;\n config.llmModel = fields.llm_model;\n config.personality = fields.agent_personality || fields.personality;\n config.fleetRole = fields.fleet_role;\n\n // Detect Anthropic API key from vault — sets provider + base_url automatically\n if (!config.llmApiKey && fields.anthropic_api_key) {\n config.llmApiKey = fields.anthropic_api_key;\n config.llmProvider = 'anthropic';\n if (!config.llmBaseUrl) config.llmBaseUrl = 'https://api.anthropic.com';\n }\n\n if (config.llmApiKey) console.log(` ✓ LLM API key loaded from vault${config.llmProvider === 'anthropic' ? ' (Anthropic)' : ''}`);\n if (config.llmModel) console.log(` ✓ LLM model: ${config.llmModel}`);\n if (config.personality) console.log(` ✓ Personality: ${config.personality.slice(0, 60)}...`);\n if (config.fleetRole) console.log(` ✓ Fleet role: ${config.fleetRole}`);\n } else {\n console.log(\" ! No hivemind-config vault item found\");\n console.log(\" ! Will prompt for LLM API key instead\");\n }\n } catch (err) {\n console.log(` ! Could not read vault: ${(err as Error).message}`);\n }\n } catch (err) {\n console.error(`\\n ✗ Failed to connect to Sesame: ${(err as Error).message}`);\n console.error(\" Check your API key and try again.\");\n process.exit(1);\n } finally {\n sdk.disconnect();\n }\n\n // --- Step 3.5: Try Claude Code OAuth if no API key from vault ---\n if (!config.llmApiKey) {\n const oauthToken = getClaudeCodeOAuthToken();\n if (oauthToken) {\n // Don't store the token — it expires. Configure provider so it's read from keychain at runtime.\n config.llmProvider = 'anthropic';\n config.llmBaseUrl = 'https://api.anthropic.com';\n if (!config.llmModel) config.llmModel = 'claude-sonnet-4-20250514';\n console.log(' ✓ Claude Max subscription detected (via Claude Code OAuth)');\n console.log(' ✓ Configuring provider=anthropic — token read from keychain at runtime');\n }\n }\n\n // --- Step 4: Prompt for anything missing ---\n if (!config.llmApiKey && !config.llmProvider) {\n console.log(\" ! No LLM API key found in vault — set LLM_API_KEY in .env after init\");\n }\n\n // --- Step 5: Write config files ---\n console.log(\"\\n→ Writing configuration...\");\n\n mkdirSync(CONFIG_DIR, { recursive: true });\n mkdirSync(WORKSPACE_DIR, { recursive: true });\n\n // Copy default.toml from installed package if not present\n const defaultToml = resolve(CONFIG_DIR, \"default.toml\");\n if (!existsSync(defaultToml)) {\n // Resolve from the hivemind binary location\n // process.argv[1] may be a symlink, so resolve it first\n const realBin = realpathSync(process.argv[1]);\n // realBin is <pkg>/dist/main.js, so ../config/ gets us to <pkg>/config/\n const packageConfigDir = resolve(dirname(realBin), \"..\", \"config\");\n const packageDefault = resolve(packageConfigDir, \"default.toml\");\n if (existsSync(packageDefault)) {\n copyFileSync(packageDefault, defaultToml);\n console.log(` ✓ ${defaultToml}`);\n // Also copy team charter if available\n const packageCharter = resolve(packageConfigDir, \"TEAM-CHARTER.md\");\n const localCharter = resolve(CONFIG_DIR, \"TEAM-CHARTER.md\");\n if (existsSync(packageCharter) && !existsSync(localCharter)) {\n copyFileSync(packageCharter, localCharter);\n console.log(` ✓ ${localCharter}`);\n }\n } else {\n console.log(` ! default.toml not found in package — you may need to copy it manually`);\n }\n }\n\n // Write workspace identity files\n const soulPath = resolve(WORKSPACE_DIR, \"SOUL.md\");\n if (!existsSync(soulPath)) {\n const personality = config.personality || \"A helpful, capable agent.\";\n writeFileSync(soulPath, `# SOUL.md — Who You Are\n\n${personality}\n\n---\n\n_This file defines your personality and values. Edit it to evolve who you are._\n`);\n console.log(` ✓ ${soulPath}`);\n }\n\n const identityPath = resolve(WORKSPACE_DIR, \"IDENTITY.md\");\n if (!existsSync(identityPath)) {\n writeFileSync(identityPath, `# IDENTITY.md\n\n- **Name:** ${config.agentName}\n- **Handle:** ${config.agentHandle}\n- **Agent ID:** ${config.agentId}\n`);\n console.log(` ✓ ${identityPath}`);\n }\n\n // Write local.toml (overrides)\n const llmLines: string[] = [];\n if (config.llmModel || config.llmProvider || config.llmBaseUrl) {\n llmLines.push('[llm]');\n if (config.llmProvider) llmLines.push(`provider = \"${config.llmProvider}\"`);\n if (config.llmBaseUrl) llmLines.push(`base_url = \"${config.llmBaseUrl}\"`);\n if (config.llmModel) llmLines.push(`model = \"${config.llmModel}\"`);\n } else {\n llmLines.push('# [llm] using defaults');\n }\n\n const localToml = `# Generated by hivemind init — ${new Date().toISOString()}\n# Overrides config/default.toml with agent-specific settings\n\n[agent]\nname = \"${config.agentName}\"\n${config.personality ? `personality = \"${config.personality.replace(/\"/g, '\\\\\"')}\"` : \"# personality = (using default)\"}\nworkspace = \"workspace\"\n\n${llmLines.join('\\n')}\n\n[sesame]\napi_key = \"${sesameApiKey}\"\n`;\n\n writeFileSync(LOCAL_TOML, localToml);\n console.log(` ✓ ${LOCAL_TOML}`);\n\n // Write .env\n const envLines = [\n `# Hivemind Agent — ${config.agentName}`,\n `# Generated by hivemind init — ${new Date().toISOString()}`,\n `SESAME_API_KEY=${sesameApiKey}`,\n ];\n if (config.llmProvider === 'anthropic') {\n envLines.push(`ANTHROPIC_API_KEY=${config.llmApiKey || \"\"}`);\n } else {\n envLines.push(`LLM_API_KEY=${config.llmApiKey || \"\"}`);\n }\n envLines.push(`AGENT_NAME=${config.agentName}`, '');\n const envContent = envLines.join('\\n');\n\n writeFileSync(ENV_FILE, envContent, { mode: 0o600 });\n console.log(` ✓ ${ENV_FILE} (chmod 600)`);\n\n // --- Step 6: Install memory infrastructure ---\n console.log(\"\\n→ Setting up memory system...\");\n mkdirSync(BIN_DIR, { recursive: true });\n mkdirSync(DATA_DIR, { recursive: true });\n\n await installOllama();\n await pullEmbeddingModel();\n await downloadMemoryDaemon();\n\n // --- Step 7: Set up Claude Code session logging ---\n console.log(\"\\n→ Setting up Claude Code session logging...\");\n try {\n const claudeDir = resolve(homedir(), \".claude\");\n const claudeMd = resolve(claudeDir, \"CLAUDE.md\");\n mkdirSync(claudeDir, { recursive: true });\n\n const sessionLoggingInstructions = `# Claude Code — Global Instructions\n\n## Session Logging\n\nBefore completing any session, write a \\`.session-log.json\\` file in the project root with the following structure:\n\n\\`\\`\\`json\n{\n \"timestamp\": \"<ISO-8601>\",\n \"summary\": \"One paragraph describing what was done and why\",\n \"decisions\": [\n {\n \"topic\": \"Short label\",\n \"choice\": \"What was chosen\",\n \"rationale\": \"Why this over alternatives\",\n \"alternatives_considered\": [\"alt1\", \"alt2\"]\n }\n ],\n \"patterns\": [\n {\n \"pattern\": \"Description of a coding pattern or convention\",\n \"scope\": \"project-wide | file-specific | language-general\"\n }\n ],\n \"gotchas\": [\n {\n \"issue\": \"What went wrong or was tricky\",\n \"resolution\": \"How it was fixed or worked around\",\n \"prevention\": \"How to avoid it next time\"\n }\n ],\n \"files_changed\": [\n {\n \"path\": \"relative/path/to/file\",\n \"action\": \"created | modified | deleted\",\n \"purpose\": \"Why this file was changed\"\n }\n ]\n}\n\\`\\`\\`\n\nRules:\n- Always create this file, even for small changes\n- Omit empty arrays (e.g. if no gotchas, leave out the key)\n- Be specific in decisions and gotchas — these help future sessions\n- The file is gitignored and consumed by tooling, not humans\n`;\n\n if (existsSync(claudeMd)) {\n const existing = readFileSync(claudeMd, \"utf-8\");\n if (!existing.includes(\"Session Logging\")) {\n writeFileSync(claudeMd, existing + \"\\n\" + sessionLoggingInstructions);\n console.log(\" ✓ Appended session logging to existing CLAUDE.md\");\n } else {\n console.log(\" ✓ CLAUDE.md already has session logging\");\n }\n } else {\n writeFileSync(claudeMd, sessionLoggingInstructions);\n console.log(` ✓ Created ${claudeMd}`);\n }\n\n // Add .session-log.json to global gitignore\n const globalGitignore = resolve(homedir(), \".gitignore_global\");\n const gitignoreContent = existsSync(globalGitignore) ? readFileSync(globalGitignore, \"utf-8\") : \"\";\n if (!gitignoreContent.includes(\".session-log.json\")) {\n writeFileSync(globalGitignore, gitignoreContent + \"\\n.session-log.json\\n\");\n try {\n execSync(`git config --global core.excludesfile \"${globalGitignore}\"`, { stdio: \"ignore\" });\n } catch {}\n console.log(\" ✓ Added .session-log.json to global gitignore\");\n }\n } catch (err) {\n console.log(` ! Claude Code setup skipped: ${(err as Error).message}`);\n }\n\n // --- Done ---\n console.log(`\n ✓ Hivemind initialized for ${config.agentName}!\n\n To start the agent:\n hivemind start\n\n To install as a service:\n hivemind service install\n\n Agent ID: ${config.agentId}\n Channels: ${config.channels.map((c) => c.name || c.id).join(\", \")}\n Fleet role: ${config.fleetRole || \"standalone\"}\n`);\n}\n\n// --- Memory infrastructure helpers ---\n\nasync function installOllama(): Promise<void> {\n try {\n execSync(\"which ollama\", { stdio: \"ignore\" });\n const version = execSync(\"ollama --version\", { encoding: \"utf-8\" }).trim();\n console.log(` ✓ Ollama already installed (${version})`);\n return;\n } catch {}\n\n console.log(\" → Installing Ollama...\");\n try {\n // Try Homebrew first (macOS)\n execSync(\"which brew\", { stdio: \"ignore\" });\n execSync(\"brew install ollama\", { stdio: \"inherit\" });\n console.log(\" ✓ Ollama installed via Homebrew\");\n } catch {\n // Fall back to official installer\n try {\n execSync(\"curl -fsSL https://ollama.com/install.sh | sh\", { stdio: \"inherit\" });\n console.log(\" ✓ Ollama installed via installer script\");\n } catch (err) {\n console.error(` ✗ Failed to install Ollama: ${(err as Error).message}`);\n console.error(\" ! Install manually: https://ollama.com/download\");\n console.error(\" ! Memory system will not work without Ollama\");\n }\n }\n}\n\nasync function pullEmbeddingModel(): Promise<void> {\n console.log(` → Pulling embedding model (${EMBEDDING_MODEL})...`);\n try {\n // Ensure ollama is running\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n } catch {\n // Start ollama serve in background\n console.log(\" → Starting Ollama server...\");\n execSync(\"ollama serve &\", { stdio: \"ignore\", shell: \"/bin/sh\" });\n // Wait for it to be ready\n for (let i = 0; i < 15; i++) {\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n break;\n } catch {\n execSync(\"sleep 1\");\n }\n }\n }\n\n execSync(`ollama pull ${EMBEDDING_MODEL}`, { stdio: \"inherit\" });\n console.log(` ✓ ${EMBEDDING_MODEL} model ready`);\n } catch (err) {\n console.error(` ✗ Failed to pull model: ${(err as Error).message}`);\n console.error(` ! Run manually: ollama pull ${EMBEDDING_MODEL}`);\n }\n}\n\nasync function downloadMemoryDaemon(): Promise<void> {\n if (existsSync(MEMORY_BIN)) {\n console.log(` ✓ Memory daemon already installed at ${MEMORY_BIN}`);\n return;\n }\n\n const osArch = arch();\n const osPlatform = platform();\n\n if (osPlatform !== \"darwin\") {\n console.log(` ! Memory daemon pre-built binaries only available for macOS currently`);\n console.log(` ! Build from source: cd packages/memory && cargo build --release`);\n return;\n }\n\n const artifactName = osArch === \"arm64\"\n ? \"hivemind-memory-darwin-arm64\"\n : \"hivemind-memory-darwin-x64\";\n\n console.log(` → Downloading memory daemon (${artifactName})...`);\n try {\n // Get latest version from S3\n const latestJson = execSync(\n `curl -sf \"${RELEASES_BASE_URL}/latest.json\"`,\n { encoding: \"utf-8\" },\n );\n const { version } = JSON.parse(latestJson);\n const url = `${RELEASES_BASE_URL}/v${version}/${artifactName}`;\n\n execSync(\n `curl -fSL -o \"${MEMORY_BIN}\" \"${url}\"`,\n { stdio: \"inherit\" },\n );\n chmodSync(MEMORY_BIN, 0o755);\n console.log(` ✓ Memory daemon installed at ${MEMORY_BIN} (v${version})`);\n } catch (err) {\n console.error(` ✗ Failed to download memory daemon: ${(err as Error).message}`);\n console.error(\" ! Build from source: cd packages/memory && cargo build --release\");\n console.error(` ! Then copy to: ${MEMORY_BIN}`);\n }\n}\n\nfunction printHelp(): void {\n console.log(`hivemind init — Initialize a Hivemind agent from Sesame\n\nUsage: hivemind init [sesame-api-key]\n\nThe API key can also be passed as the first argument.\n\nWhat it does:\n 1. Connects to Sesame and fetches agent identity\n 2. Reads provisioning config from Sesame vault (if available)\n 3. Writes config/local.toml and .env\n 4. Installs Ollama + embedding model for memory\n 5. Downloads pre-built memory daemon binary\n\nOptions:\n -h, --help Show this help\n`);\n}\n"],"mappings":"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","names":["resolve","envContent"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// packages/cli/src/commands/upgrade.ts
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
3
|
import { resolve } from "path";
|
|
4
|
-
import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
5
6
|
var PACKAGE_NAME = "@sesamespace/hivemind";
|
|
6
7
|
var STOP_FLAG_FILE = "/tmp/hivemind-agent.stopped";
|
|
7
8
|
function getCurrentVersion() {
|
|
@@ -106,10 +107,69 @@ async function runUpgradeCommand(args) {
|
|
|
106
107
|
unlinkSync(STOP_FLAG_FILE);
|
|
107
108
|
} catch {
|
|
108
109
|
}
|
|
110
|
+
console.log("\n\u2192 Ensuring Claude Code session logging...");
|
|
111
|
+
try {
|
|
112
|
+
setupClaudeSessionLogging();
|
|
113
|
+
console.log(" \u2713 Claude Code session logging configured");
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.log(` ! Skipped: ${err.message}`);
|
|
116
|
+
}
|
|
109
117
|
const newVersion = getCurrentVersion();
|
|
110
118
|
console.log(`
|
|
111
119
|
\u2713 Upgrade complete: ${info.current} \u2192 ${newVersion}`);
|
|
112
120
|
}
|
|
121
|
+
function setupClaudeSessionLogging() {
|
|
122
|
+
const claudeDir = resolve(homedir(), ".claude");
|
|
123
|
+
const claudeMd = resolve(claudeDir, "CLAUDE.md");
|
|
124
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
125
|
+
const marker = "## Session Logging";
|
|
126
|
+
const instructions = `# Claude Code \u2014 Global Instructions
|
|
127
|
+
|
|
128
|
+
## Session Logging
|
|
129
|
+
|
|
130
|
+
Before completing any session, write a \`.session-log.json\` file in the project root with the following structure:
|
|
131
|
+
|
|
132
|
+
\`\`\`json
|
|
133
|
+
{
|
|
134
|
+
"timestamp": "<ISO-8601>",
|
|
135
|
+
"summary": "One paragraph describing what was done and why",
|
|
136
|
+
"decisions": [
|
|
137
|
+
{ "topic": "Short label", "choice": "What was chosen", "rationale": "Why", "alternatives_considered": [] }
|
|
138
|
+
],
|
|
139
|
+
"patterns": [
|
|
140
|
+
{ "pattern": "Description of pattern or convention", "scope": "project-wide | file-specific | language-general" }
|
|
141
|
+
],
|
|
142
|
+
"gotchas": [
|
|
143
|
+
{ "issue": "What went wrong", "resolution": "How it was fixed", "prevention": "How to avoid next time" }
|
|
144
|
+
],
|
|
145
|
+
"files_changed": [
|
|
146
|
+
{ "path": "relative/path", "action": "created | modified | deleted", "purpose": "Why changed" }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
\`\`\`
|
|
150
|
+
|
|
151
|
+
Rules:
|
|
152
|
+
- Always create this file, even for small changes
|
|
153
|
+
- Omit empty arrays; be specific in decisions and gotchas
|
|
154
|
+
- The file is gitignored and consumed by tooling, not humans
|
|
155
|
+
`;
|
|
156
|
+
if (existsSync(claudeMd)) {
|
|
157
|
+
const existing = readFileSync(claudeMd, "utf-8");
|
|
158
|
+
if (existing.includes(marker)) return;
|
|
159
|
+
writeFileSync(claudeMd, existing + "\n" + instructions);
|
|
160
|
+
} else {
|
|
161
|
+
writeFileSync(claudeMd, instructions);
|
|
162
|
+
}
|
|
163
|
+
const globalGitignore = resolve(homedir(), ".gitignore_global");
|
|
164
|
+
const content = existsSync(globalGitignore) ? readFileSync(globalGitignore, "utf-8") : "";
|
|
165
|
+
if (!content.includes(".session-log.json")) {
|
|
166
|
+
writeFileSync(globalGitignore, content + "\n.session-log.json\n");
|
|
167
|
+
try {
|
|
168
|
+
execSync(`git config --global core.excludesfile "${globalGitignore}"`, { stdio: "ignore" });
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
113
173
|
function printHelp() {
|
|
114
174
|
console.log(`hivemind upgrade \u2014 Upgrade the Hivemind agent runtime
|
|
115
175
|
|
|
@@ -134,4 +194,4 @@ Examples:
|
|
|
134
194
|
export {
|
|
135
195
|
runUpgradeCommand
|
|
136
196
|
};
|
|
137
|
-
//# sourceMappingURL=chunk-
|
|
197
|
+
//# sourceMappingURL=chunk-ICSJNKI6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../packages/cli/src/commands/upgrade.ts"],"sourcesContent":["import { execSync } from \"child_process\";\nimport { resolve } from \"path\";\nimport { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from \"fs\";\nimport { homedir } from \"os\";\n\nconst PACKAGE_NAME = \"@sesamespace/hivemind\";\nconst STOP_FLAG_FILE = \"/tmp/hivemind-agent.stopped\";\n\ninterface VersionInfo {\n current: string;\n latest: string;\n updateAvailable: boolean;\n}\n\nfunction getCurrentVersion(): string {\n try {\n // Check the installed package version\n const output = execSync(`npm ls -g ${PACKAGE_NAME} --json 2>/dev/null`, { encoding: \"utf-8\" });\n const parsed = JSON.parse(output);\n const deps = parsed.dependencies?.[PACKAGE_NAME];\n if (deps?.version) return deps.version;\n } catch {\n // Fallback: read from the package.json in the hivemind dir\n }\n\n const hivemindHome = process.env.HIVEMIND_HOME || resolve(process.env.HOME || \"~\", \"hivemind\");\n const pkgPath = resolve(hivemindHome, \"node_modules\", PACKAGE_NAME, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n return JSON.parse(readFileSync(pkgPath, \"utf-8\")).version;\n } catch {\n // fall through\n }\n }\n\n return \"unknown\";\n}\n\nfunction getLatestVersion(target?: string): string {\n try {\n const tag = target || \"latest\";\n const output = execSync(`npm view ${PACKAGE_NAME}@${tag} version 2>/dev/null`, { encoding: \"utf-8\" });\n return output.trim();\n } catch {\n throw new Error(\"Failed to check npm registry for latest version\");\n }\n}\n\nasync function checkVersion(target?: string): Promise<VersionInfo> {\n const current = getCurrentVersion();\n const latest = target || getLatestVersion();\n return {\n current,\n latest,\n updateAvailable: current !== latest && current !== \"unknown\",\n };\n}\n\nexport async function runUpgradeCommand(args: string[]): Promise<void> {\n const checkOnly = args.includes(\"--check\") || args.includes(\"-c\");\n const force = args.includes(\"--force\") || args.includes(\"-f\");\n const dryRun = args.includes(\"--dry-run\") || args.includes(\"-n\");\n\n // Target version (optional positional arg)\n const targetVersion = args.find((a) => !a.startsWith(\"-\"));\n\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n printHelp();\n return;\n }\n\n console.log(`\n ╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗\n ╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║\n ╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝\n Agent Upgrade\n`);\n\n // --- Check versions ---\n console.log(\"→ Checking versions...\");\n const info = await checkVersion(targetVersion);\n console.log(` Current: ${info.current}`);\n console.log(` Latest: ${info.latest}`);\n\n if (!info.updateAvailable && !force) {\n console.log(\"\\n ✓ Already up to date!\");\n return;\n }\n\n if (info.updateAvailable) {\n console.log(`\\n ⬆ Update available: ${info.current} → ${info.latest}`);\n }\n\n if (checkOnly) {\n return;\n }\n\n // --- Perform upgrade ---\n const target = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;\n\n if (dryRun) {\n console.log(`\\n→ [dry-run] Would run: npm install -g ${target}`);\n console.log(\"→ [dry-run] Would restart the agent service\");\n return;\n }\n\n console.log(`\\n→ Installing ${target}...`);\n try {\n execSync(`npm install -g ${target}`, { stdio: \"inherit\" });\n console.log(\" ✓ Package updated\");\n } catch (err) {\n console.error(` ✗ npm install failed: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // --- Restart agent ---\n // Write stop flag so the watchdog doesn't race us during restart\n writeFileSync(STOP_FLAG_FILE, String(Date.now()));\n\n console.log(\"\\n→ Restarting agent...\");\n try {\n // Try launchctl first (macOS service)\n const plistName = \"com.hivemind.agent\";\n execSync(`launchctl list ${plistName} 2>/dev/null`, { encoding: \"utf-8\" });\n // Service exists — restart it\n execSync(`launchctl kickstart -k gui/$(id -u)/${plistName}`, { stdio: \"inherit\" });\n console.log(\" ✓ Agent restarted via launchd\");\n } catch {\n // No launchd service — try finding and restarting the process\n try {\n execSync(\"pkill -f 'hivemind start'\", { stdio: \"inherit\" });\n console.log(\" ✓ Old process killed\");\n console.log(\" ! Start the agent manually: hivemind start\");\n } catch {\n console.log(\" ! No running agent found — start manually: hivemind start\");\n }\n }\n\n // Remove stop flag so watchdog resumes monitoring\n try { unlinkSync(STOP_FLAG_FILE); } catch {}\n\n // --- Post-upgrade: ensure Claude Code session logging is set up ---\n console.log(\"\\n→ Ensuring Claude Code session logging...\");\n try {\n setupClaudeSessionLogging();\n console.log(\" ✓ Claude Code session logging configured\");\n } catch (err) {\n console.log(` ! Skipped: ${(err as Error).message}`);\n }\n\n // --- Verify ---\n const newVersion = getCurrentVersion();\n console.log(`\\n ✓ Upgrade complete: ${info.current} → ${newVersion}`);\n}\n\nfunction setupClaudeSessionLogging(): void {\n const claudeDir = resolve(homedir(), \".claude\");\n const claudeMd = resolve(claudeDir, \"CLAUDE.md\");\n mkdirSync(claudeDir, { recursive: true });\n\n const marker = \"## Session Logging\";\n const instructions = `# Claude Code — Global Instructions\n\n## Session Logging\n\nBefore completing any session, write a \\`.session-log.json\\` file in the project root with the following structure:\n\n\\`\\`\\`json\n{\n \"timestamp\": \"<ISO-8601>\",\n \"summary\": \"One paragraph describing what was done and why\",\n \"decisions\": [\n { \"topic\": \"Short label\", \"choice\": \"What was chosen\", \"rationale\": \"Why\", \"alternatives_considered\": [] }\n ],\n \"patterns\": [\n { \"pattern\": \"Description of pattern or convention\", \"scope\": \"project-wide | file-specific | language-general\" }\n ],\n \"gotchas\": [\n { \"issue\": \"What went wrong\", \"resolution\": \"How it was fixed\", \"prevention\": \"How to avoid next time\" }\n ],\n \"files_changed\": [\n { \"path\": \"relative/path\", \"action\": \"created | modified | deleted\", \"purpose\": \"Why changed\" }\n ]\n}\n\\`\\`\\`\n\nRules:\n- Always create this file, even for small changes\n- Omit empty arrays; be specific in decisions and gotchas\n- The file is gitignored and consumed by tooling, not humans\n`;\n\n if (existsSync(claudeMd)) {\n const existing = readFileSync(claudeMd, \"utf-8\");\n if (existing.includes(marker)) return; // already set up\n writeFileSync(claudeMd, existing + \"\\n\" + instructions);\n } else {\n writeFileSync(claudeMd, instructions);\n }\n\n // Global gitignore\n const globalGitignore = resolve(homedir(), \".gitignore_global\");\n const content = existsSync(globalGitignore) ? readFileSync(globalGitignore, \"utf-8\") : \"\";\n if (!content.includes(\".session-log.json\")) {\n writeFileSync(globalGitignore, content + \"\\n.session-log.json\\n\");\n try { execSync(`git config --global core.excludesfile \"${globalGitignore}\"`, { stdio: \"ignore\" }); } catch {}\n }\n}\n\nfunction printHelp(): void {\n console.log(`hivemind upgrade — Upgrade the Hivemind agent runtime\n\nUsage: hivemind upgrade [version] [options]\n\nArguments:\n version Target version (default: latest)\n\nOptions:\n -c, --check Check for updates only (don't install)\n -f, --force Force reinstall even if up to date\n -n, --dry-run Show what would happen without doing it\n -h, --help Show this help\n\nExamples:\n hivemind upgrade # Upgrade to latest\n hivemind upgrade 0.3.0 # Upgrade to specific version\n hivemind upgrade --check # Just check if update available\n`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,37 +5,9 @@ import {
|
|
|
5
5
|
HEALTH_TIMEOUT_MS,
|
|
6
6
|
PRIMARY_ROUTES,
|
|
7
7
|
SesameClient2 as SesameClient,
|
|
8
|
-
WORKER_ROUTES
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// packages/runtime/src/logger.ts
|
|
12
|
-
var LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
13
|
-
var currentLevel = process.env.HIVEMIND_LOG_LEVEL || "info";
|
|
14
|
-
function setLogLevel(level) {
|
|
15
|
-
currentLevel = level;
|
|
16
|
-
}
|
|
17
|
-
function createLogger(component) {
|
|
18
|
-
const log2 = (level, msg, data) => {
|
|
19
|
-
if (LEVELS[level] < LEVELS[currentLevel]) return;
|
|
20
|
-
const entry = {
|
|
21
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22
|
-
level,
|
|
23
|
-
component,
|
|
24
|
-
msg,
|
|
25
|
-
...data
|
|
26
|
-
};
|
|
27
|
-
const line = JSON.stringify(entry);
|
|
28
|
-
if (level === "error") console.error(line);
|
|
29
|
-
else if (level === "warn") console.warn(line);
|
|
30
|
-
else console.log(line);
|
|
31
|
-
};
|
|
32
|
-
return {
|
|
33
|
-
debug: (msg, data) => log2("debug", msg, data),
|
|
34
|
-
info: (msg, data) => log2("info", msg, data),
|
|
35
|
-
warn: (msg, data) => log2("warn", msg, data),
|
|
36
|
-
error: (msg, data) => log2("error", msg, data)
|
|
37
|
-
};
|
|
38
|
-
}
|
|
8
|
+
WORKER_ROUTES,
|
|
9
|
+
createLogger
|
|
10
|
+
} from "./chunk-M3A2WRXM.js";
|
|
39
11
|
|
|
40
12
|
// packages/runtime/src/watchdog.ts
|
|
41
13
|
import { execSync } from "child_process";
|
|
@@ -1117,12 +1089,10 @@ var PrimaryMemorySync = class {
|
|
|
1117
1089
|
};
|
|
1118
1090
|
|
|
1119
1091
|
export {
|
|
1120
|
-
setLogLevel,
|
|
1121
|
-
createLogger,
|
|
1122
1092
|
Watchdog,
|
|
1123
1093
|
PrimaryClient,
|
|
1124
1094
|
FleetManager,
|
|
1125
1095
|
WorkerMemorySync,
|
|
1126
1096
|
PrimaryMemorySync
|
|
1127
1097
|
};
|
|
1128
|
-
//# sourceMappingURL=chunk-
|
|
1098
|
+
//# sourceMappingURL=chunk-IXBIAX76.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"]}
|