@sesamespace/hivemind 0.5.4 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.github/workflows/memory-release.yml +89 -0
  2. package/config/default.toml +12 -0
  3. package/data/lancedb/contexts.lance/_transactions/0-c4755ab9-b604-4d90-851f-0491f3cbcbce.txn +2 -0
  4. package/data/lancedb/contexts.lance/_versions/1.manifest +0 -0
  5. package/data/lancedb/episode_access.lance/_transactions/0-407a6366-0dca-490a-868b-ea63bee3b40c.txn +2 -0
  6. package/data/lancedb/episode_access.lance/_versions/1.manifest +0 -0
  7. package/data/lancedb/episode_cooccurrence.lance/_transactions/0-0e103c7f-29d7-4f09-8100-505c076f01ae.txn +1 -0
  8. package/data/lancedb/episode_cooccurrence.lance/_versions/1.manifest +0 -0
  9. package/data/lancedb/episodes.lance/_transactions/0-e678cbac-792b-4a9d-a457-17b0d4d23607.txn +1 -0
  10. package/data/lancedb/episodes.lance/_versions/1.manifest +0 -0
  11. package/data/lancedb/l3_knowledge.lance/_transactions/0-cdb3561f-3a59-4e15-bded-e93c5f9a50e3.txn +1 -0
  12. package/data/lancedb/l3_knowledge.lance/_versions/1.manifest +0 -0
  13. package/data/lancedb/tasks.lance/_transactions/0-d1cf10ec-1eb8-48b4-bbbe-34b3a1083664.txn +4 -0
  14. package/data/lancedb/tasks.lance/_versions/1.manifest +0 -0
  15. package/dist/{chunk-MHDLSAJ3.js → chunk-2OIRJFI5.js} +14 -30
  16. package/dist/chunk-2OIRJFI5.js.map +1 -0
  17. package/dist/chunk-7D4SUZUM.js +38 -0
  18. package/dist/chunk-7D4SUZUM.js.map +1 -0
  19. package/dist/chunk-LRK64BAK.js +3601 -0
  20. package/dist/chunk-LRK64BAK.js.map +1 -0
  21. package/dist/chunk-MBS5A6BZ.js +132 -0
  22. package/dist/chunk-MBS5A6BZ.js.map +1 -0
  23. package/dist/{chunk-LNV373IF.js → chunk-OQ272HKA.js} +3 -28
  24. package/dist/chunk-OQ272HKA.js.map +1 -0
  25. package/dist/{chunk-CGSXJVSS.js → chunk-RXCV57H3.js} +2 -2
  26. package/dist/{chunk-S3RVZBPZ.js → chunk-YEOAEJ62.js} +2 -2
  27. package/dist/commands/fleet.js +4 -3
  28. package/dist/commands/init.js +2 -1
  29. package/dist/commands/service.js +2 -1
  30. package/dist/commands/start.js +4 -3
  31. package/dist/commands/upgrade.js +1 -0
  32. package/dist/index.js +3 -2
  33. package/dist/main.js +7 -6
  34. package/dist/main.js.map +1 -1
  35. package/dist/start.js +2 -1
  36. package/dist/start.js.map +1 -1
  37. package/package.json +1 -1
  38. package/PLANNING.md +0 -383
  39. package/TASKS.md +0 -60
  40. package/dist/chunk-LNV373IF.js.map +0 -1
  41. package/dist/chunk-MHDLSAJ3.js.map +0 -1
  42. package/dist/chunk-PPQGQHXJ.js +0 -151
  43. package/dist/chunk-PPQGQHXJ.js.map +0 -1
  44. package/dist/chunk-YHRGEWAZ.js +0 -2326
  45. package/dist/chunk-YHRGEWAZ.js.map +0 -1
  46. package/install.sh +0 -120
  47. package/npm-package.json +0 -26
  48. package/packages/cli/package.json +0 -23
  49. package/packages/cli/src/commands/fleet.ts +0 -206
  50. package/packages/cli/src/commands/init.ts +0 -252
  51. package/packages/cli/src/commands/service.ts +0 -159
  52. package/packages/cli/src/commands/start.ts +0 -78
  53. package/packages/cli/src/commands/upgrade.ts +0 -158
  54. package/packages/cli/src/main.ts +0 -64
  55. package/packages/cli/tsconfig.json +0 -8
  56. package/packages/memory/Cargo.lock +0 -6480
  57. package/packages/memory/Cargo.toml +0 -21
  58. package/packages/memory/src/context.rs +0 -179
  59. package/packages/memory/src/embeddings.rs +0 -51
  60. package/packages/memory/src/main.rs +0 -626
  61. package/packages/memory/src/promotion.rs +0 -637
  62. package/packages/memory/src/scoring.rs +0 -131
  63. package/packages/memory/src/store.rs +0 -460
  64. package/packages/memory/src/tasks.rs +0 -321
  65. package/packages/runtime/package.json +0 -24
  66. package/packages/runtime/src/__tests__/fleet-integration.test.ts +0 -235
  67. package/packages/runtime/src/__tests__/fleet.test.ts +0 -207
  68. package/packages/runtime/src/__tests__/integration.test.ts +0 -434
  69. package/packages/runtime/src/agent.ts +0 -255
  70. package/packages/runtime/src/config.ts +0 -130
  71. package/packages/runtime/src/context.ts +0 -192
  72. package/packages/runtime/src/fleet/fleet-manager.ts +0 -399
  73. package/packages/runtime/src/fleet/memory-sync.ts +0 -362
  74. package/packages/runtime/src/fleet/primary-client.ts +0 -285
  75. package/packages/runtime/src/fleet/worker-protocol.ts +0 -158
  76. package/packages/runtime/src/fleet/worker-server.ts +0 -246
  77. package/packages/runtime/src/index.ts +0 -57
  78. package/packages/runtime/src/llm-client.ts +0 -65
  79. package/packages/runtime/src/memory-client.ts +0 -309
  80. package/packages/runtime/src/pipeline.ts +0 -187
  81. package/packages/runtime/src/prompt.ts +0 -173
  82. package/packages/runtime/src/sesame.ts +0 -226
  83. package/packages/runtime/src/start.ts +0 -20
  84. package/packages/runtime/src/task-engine.ts +0 -113
  85. package/packages/runtime/src/worker.ts +0 -339
  86. package/packages/runtime/tsconfig.json +0 -8
  87. package/pnpm-workspace.yaml +0 -2
  88. package/run-aidan.sh +0 -23
  89. package/scripts/bootstrap.sh +0 -196
  90. package/scripts/build-npm.sh +0 -92
  91. package/scripts/com.hivemind.agent.plist +0 -44
  92. package/scripts/com.hivemind.memory.plist +0 -31
  93. package/tsconfig.json +0 -22
  94. package/tsup.config.ts +0 -27
  95. /package/dist/{chunk-CGSXJVSS.js.map → chunk-RXCV57H3.js.map} +0 -0
  96. /package/dist/{chunk-S3RVZBPZ.js.map → chunk-YEOAEJ62.js.map} +0 -0
@@ -1,206 +0,0 @@
1
- /**
2
- * CLI commands for fleet management.
3
- *
4
- * Usage:
5
- * hivemind fleet status — Show fleet dashboard
6
- * hivemind fleet add-worker <url> — Register a worker by URL
7
- * hivemind fleet remove-worker <worker-id> — Remove a worker from the fleet
8
- * hivemind fleet assign <worker-id> <context> — Assign a context to a worker
9
- * hivemind fleet migrate <context> <worker-id> — Migrate a context to another worker
10
- * hivemind fleet discover <url1> [url2] ... — Probe URLs for workers
11
- */
12
-
13
- import { FleetManager } from "@hivemind/runtime";
14
- import type { FleetDashboard, WorkerSummary } from "@hivemind/runtime";
15
-
16
- function formatUptime(seconds: number | null): string {
17
- if (seconds == null) return "—";
18
- if (seconds < 60) return `${seconds}s`;
19
- if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
20
- const h = Math.floor(seconds / 3600);
21
- const m = Math.floor((seconds % 3600) / 60);
22
- return `${h}h ${m}m`;
23
- }
24
-
25
- function formatHealth(status: string): string {
26
- switch (status) {
27
- case "healthy": return "OK";
28
- case "degraded": return "DEGRADED";
29
- case "unreachable": return "DOWN";
30
- default: return status.toUpperCase();
31
- }
32
- }
33
-
34
- function printDashboard(dashboard: FleetDashboard): void {
35
- console.log("\n=== Hivemind Fleet ===\n");
36
- console.log(`Workers: ${dashboard.total_workers} (${dashboard.healthy} healthy, ${dashboard.degraded} degraded, ${dashboard.unreachable} unreachable)`);
37
- console.log(`Contexts assigned: ${dashboard.total_contexts}`);
38
-
39
- if (dashboard.unassigned_contexts.length > 0) {
40
- console.log(`Unassigned contexts: ${dashboard.unassigned_contexts.join(", ")}`);
41
- }
42
-
43
- console.log("");
44
-
45
- if (dashboard.workers.length === 0) {
46
- console.log("No workers registered. Use 'fleet add-worker <url>' to add one.");
47
- return;
48
- }
49
-
50
- // Table header
51
- const cols = { id: 12, url: 30, health: 8, activity: 10, contexts: 25, task: 20, uptime: 8 };
52
- const header = [
53
- "ID".padEnd(cols.id),
54
- "URL".padEnd(cols.url),
55
- "HEALTH".padEnd(cols.health),
56
- "ACTIVITY".padEnd(cols.activity),
57
- "CONTEXTS".padEnd(cols.contexts),
58
- "TASK".padEnd(cols.task),
59
- "UPTIME".padEnd(cols.uptime),
60
- ].join(" ");
61
- console.log(header);
62
- console.log("-".repeat(header.length));
63
-
64
- for (const w of dashboard.workers) {
65
- const row = [
66
- w.id.padEnd(cols.id),
67
- w.url.slice(0, cols.url).padEnd(cols.url),
68
- formatHealth(w.health).padEnd(cols.health),
69
- w.activity.padEnd(cols.activity),
70
- (w.contexts.join(", ") || "—").slice(0, cols.contexts).padEnd(cols.contexts),
71
- (w.current_task ?? "—").slice(0, cols.task).padEnd(cols.task),
72
- formatUptime(w.uptime_seconds).padEnd(cols.uptime),
73
- ].join(" ");
74
- console.log(row);
75
- }
76
-
77
- console.log(`\nGenerated: ${dashboard.generated_at}`);
78
- }
79
-
80
- export async function runFleetCommand(args: string[]): Promise<void> {
81
- const subcommand = args[0];
82
-
83
- if (!subcommand) {
84
- printUsage();
85
- process.exit(1);
86
- }
87
-
88
- const fleet = new FleetManager();
89
-
90
- switch (subcommand) {
91
- case "status": {
92
- const dashboard = await fleet.getDashboard();
93
- printDashboard(dashboard);
94
- break;
95
- }
96
-
97
- case "add-worker": {
98
- const url = args[1];
99
- if (!url) {
100
- console.error("Usage: hivemind fleet add-worker <url>");
101
- process.exit(1);
102
- }
103
- try {
104
- const worker = await fleet.addWorker(url);
105
- console.log(`Worker registered: ${worker.id}`);
106
- console.log(` URL: ${worker.url}`);
107
- console.log(` Max contexts: ${worker.capabilities.max_contexts}`);
108
- console.log(` Ollama: ${worker.capabilities.has_ollama ? "yes" : "no"}`);
109
- console.log(` Memory daemon: ${worker.capabilities.has_memory_daemon ? "yes" : "no"}`);
110
- } catch (err) {
111
- const msg = err instanceof Error ? err.message : String(err);
112
- console.error(`Failed to add worker: ${msg}`);
113
- process.exit(1);
114
- }
115
- break;
116
- }
117
-
118
- case "remove-worker": {
119
- const workerId = args[1];
120
- if (!workerId) {
121
- console.error("Usage: hivemind fleet remove-worker <worker-id>");
122
- process.exit(1);
123
- }
124
- const removed = await fleet.removeWorker(workerId);
125
- if (removed) {
126
- console.log(`Worker ${workerId} removed.`);
127
- } else {
128
- console.error(`Worker ${workerId} not found.`);
129
- process.exit(1);
130
- }
131
- break;
132
- }
133
-
134
- case "assign": {
135
- const workerId = args[1];
136
- const context = args[2];
137
- if (!workerId || !context) {
138
- console.error("Usage: hivemind fleet assign <worker-id> <context>");
139
- process.exit(1);
140
- }
141
- const result = await fleet.assignContext(workerId, context);
142
- if (result.accepted) {
143
- console.log(`Context '${context}' assigned to ${workerId}.`);
144
- } else {
145
- console.error(`Assignment rejected: ${result.reason}`);
146
- process.exit(1);
147
- }
148
- break;
149
- }
150
-
151
- case "migrate": {
152
- const context = args[1];
153
- const toWorker = args[2];
154
- if (!context || !toWorker) {
155
- console.error("Usage: hivemind fleet migrate <context> <worker-id>");
156
- process.exit(1);
157
- }
158
- const result = await fleet.migrateContext(context, toWorker);
159
- if (result.success) {
160
- console.log(`Context '${context}' migrated: ${result.from_worker} -> ${result.to_worker}`);
161
- } else {
162
- console.error(`Migration failed: ${result.reason}`);
163
- process.exit(1);
164
- }
165
- break;
166
- }
167
-
168
- case "discover": {
169
- const urls = args.slice(1);
170
- if (urls.length === 0) {
171
- console.error("Usage: hivemind fleet discover <url1> [url2] ...");
172
- process.exit(1);
173
- }
174
- console.log(`Probing ${urls.length} URL(s)...`);
175
- const found = await fleet.discoverWorkers(urls);
176
- if (found.length === 0) {
177
- console.log("No workers found.");
178
- } else {
179
- console.log(`Found ${found.length} worker(s):`);
180
- for (const url of found) {
181
- console.log(` ${url}`);
182
- }
183
- }
184
- break;
185
- }
186
-
187
- default:
188
- console.error(`Unknown fleet subcommand: ${subcommand}`);
189
- printUsage();
190
- process.exit(1);
191
- }
192
- }
193
-
194
- function printUsage(): void {
195
- console.log(`
196
- Usage: hivemind fleet <command> [args]
197
-
198
- Commands:
199
- status Show fleet dashboard
200
- add-worker <url> Register a worker by URL
201
- remove-worker <worker-id> Remove a worker from the fleet
202
- assign <worker-id> <context> Assign a context to a worker
203
- migrate <context> <worker-id> Migrate a context to another worker
204
- discover <url1> [url2] ... Probe URLs for workers
205
- `.trim());
206
- }
@@ -1,252 +0,0 @@
1
- import { resolve, dirname } from "path";
2
- import { existsSync, writeFileSync, mkdirSync, readFileSync, copyFileSync, realpathSync } from "fs";
3
- import { createInterface } from "readline";
4
- import { fileURLToPath } from "url";
5
- import { SesameClient } from "@sesamespace/sdk";
6
- import { homedir } from "os";
7
-
8
- const HIVEMIND_DIR = resolve(process.env.HIVEMIND_HOME || resolve(homedir(), "hivemind"));
9
- const CONFIG_DIR = resolve(HIVEMIND_DIR, "config");
10
- const WORKSPACE_DIR = resolve(HIVEMIND_DIR, "workspace");
11
- const ENV_FILE = resolve(HIVEMIND_DIR, ".env");
12
- const LOCAL_TOML = resolve(CONFIG_DIR, "local.toml");
13
-
14
- const VAULT_CONFIG_NAME = "hivemind-config";
15
-
16
- interface ProvisioningConfig {
17
- agentName: string;
18
- agentHandle: string;
19
- agentId: string;
20
- personality?: string;
21
- llmApiKey?: string;
22
- llmBaseUrl?: string;
23
- llmModel?: string;
24
- fleetRole?: string;
25
- channels: Array<{ id: string; name: string | null; kind: string }>;
26
- }
27
-
28
- async function prompt(question: string): Promise<string> {
29
- const rl = createInterface({ input: process.stdin, output: process.stdout });
30
- return new Promise((resolve) => {
31
- rl.question(question, (answer) => {
32
- rl.close();
33
- resolve(answer.trim());
34
- });
35
- });
36
- }
37
-
38
- export async function runInitCommand(args: string[]): Promise<void> {
39
- const nonInteractive = args.includes("--yes") || args.includes("-y") || args.includes("--non-interactive");
40
- const filteredArgs = args.filter((a) => !["--yes", "-y", "--non-interactive", "--help", "-h"].includes(a));
41
- let sesameApiKey = filteredArgs[0];
42
-
43
- if (args.includes("--help") || args.includes("-h")) {
44
- printHelp();
45
- return;
46
- }
47
-
48
- console.log(`
49
- ╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗
50
- ╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║
51
- ╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝
52
- Agent Initialization
53
- `);
54
-
55
- // --- Step 1: Get Sesame API key ---
56
- if (!sesameApiKey) {
57
- sesameApiKey = await prompt(" Sesame API key: ");
58
- }
59
- if (!sesameApiKey) {
60
- console.error("Error: Sesame API key is required");
61
- process.exit(1);
62
- }
63
-
64
- // --- Step 2: Connect to Sesame and fetch manifest ---
65
- console.log("\n→ Connecting to Sesame...");
66
- const sdk = new SesameClient({
67
- apiUrl: "https://api.sesame.space",
68
- wsUrl: "wss://ws.sesame.space",
69
- apiKey: sesameApiKey,
70
- });
71
-
72
- let config: ProvisioningConfig;
73
- try {
74
- const manifest = await sdk.getManifest();
75
- console.log(` ✓ Authenticated as ${manifest.agent.handle} (${manifest.agent.id})`);
76
- console.log(` ✓ Workspace: ${manifest.workspace.name}`);
77
- console.log(` ✓ Channels: ${manifest.channels.length}`);
78
- for (const ch of manifest.channels) {
79
- console.log(` - ${ch.name || ch.id} (${ch.kind})`);
80
- }
81
-
82
- config = {
83
- agentName: manifest.agent.handle,
84
- agentHandle: manifest.agent.handle,
85
- agentId: manifest.agent.id,
86
- channels: manifest.channels.map((ch) => ({
87
- id: ch.id,
88
- name: ch.name,
89
- kind: ch.kind,
90
- })),
91
- };
92
-
93
- // --- Step 3: Check vault for config ---
94
- console.log("\n→ Checking vault for provisioning config...");
95
- try {
96
- const vaultResp = await sdk.listVaultItems() as any;
97
- const items = vaultResp.items || vaultResp.data || [];
98
- const configItem = items.find((i: any) => i.name === VAULT_CONFIG_NAME);
99
-
100
- if (configItem) {
101
- console.log(` ✓ Found ${VAULT_CONFIG_NAME} vault item`);
102
- const revealResp = await sdk.revealItem(configItem.id) as any;
103
- const fields = revealResp.fields || revealResp.data || {};
104
-
105
- config.llmApiKey = fields.llm_api_key || fields.openrouter_api_key;
106
- config.llmBaseUrl = fields.llm_base_url;
107
- config.llmModel = fields.llm_model;
108
- config.personality = fields.agent_personality || fields.personality;
109
- config.fleetRole = fields.fleet_role;
110
-
111
- if (config.llmApiKey) console.log(" ✓ LLM API key loaded from vault");
112
- if (config.personality) console.log(` ✓ Personality: ${config.personality.slice(0, 60)}...`);
113
- if (config.fleetRole) console.log(` ✓ Fleet role: ${config.fleetRole}`);
114
- } else {
115
- console.log(" ! No hivemind-config vault item found");
116
- console.log(" ! Will prompt for LLM API key instead");
117
- }
118
- } catch (err) {
119
- console.log(` ! Could not read vault: ${(err as Error).message}`);
120
- }
121
- } catch (err) {
122
- console.error(`\n ✗ Failed to connect to Sesame: ${(err as Error).message}`);
123
- console.error(" Check your API key and try again.");
124
- process.exit(1);
125
- } finally {
126
- sdk.disconnect();
127
- }
128
-
129
- // --- Step 4: Prompt for anything missing ---
130
- if (!config.llmApiKey) {
131
- console.log(" ! No LLM API key found in vault — set LLM_API_KEY in .env after init");
132
- }
133
-
134
- // --- Step 5: Write config files ---
135
- console.log("\n→ Writing configuration...");
136
-
137
- mkdirSync(CONFIG_DIR, { recursive: true });
138
- mkdirSync(WORKSPACE_DIR, { recursive: true });
139
-
140
- // Copy default.toml from installed package if not present
141
- const defaultToml = resolve(CONFIG_DIR, "default.toml");
142
- if (!existsSync(defaultToml)) {
143
- // Resolve from the hivemind binary location
144
- // process.argv[1] may be a symlink, so resolve it first
145
- const realBin = realpathSync(process.argv[1]);
146
- // realBin is <pkg>/dist/main.js, so ../config/ gets us to <pkg>/config/
147
- const packageConfigDir = resolve(dirname(realBin), "..", "config");
148
- const packageDefault = resolve(packageConfigDir, "default.toml");
149
- if (existsSync(packageDefault)) {
150
- copyFileSync(packageDefault, defaultToml);
151
- console.log(` ✓ ${defaultToml}`);
152
- // Also copy team charter if available
153
- const packageCharter = resolve(packageConfigDir, "TEAM-CHARTER.md");
154
- const localCharter = resolve(CONFIG_DIR, "TEAM-CHARTER.md");
155
- if (existsSync(packageCharter) && !existsSync(localCharter)) {
156
- copyFileSync(packageCharter, localCharter);
157
- console.log(` ✓ ${localCharter}`);
158
- }
159
- } else {
160
- console.log(` ! default.toml not found in package — you may need to copy it manually`);
161
- }
162
- }
163
-
164
- // Write workspace identity files
165
- const soulPath = resolve(WORKSPACE_DIR, "SOUL.md");
166
- if (!existsSync(soulPath)) {
167
- const personality = config.personality || "A helpful, capable agent.";
168
- writeFileSync(soulPath, `# SOUL.md — Who You Are
169
-
170
- ${personality}
171
-
172
- ---
173
-
174
- _This file defines your personality and values. Edit it to evolve who you are._
175
- `);
176
- console.log(` ✓ ${soulPath}`);
177
- }
178
-
179
- const identityPath = resolve(WORKSPACE_DIR, "IDENTITY.md");
180
- if (!existsSync(identityPath)) {
181
- writeFileSync(identityPath, `# IDENTITY.md
182
-
183
- - **Name:** ${config.agentName}
184
- - **Handle:** ${config.agentHandle}
185
- - **Agent ID:** ${config.agentId}
186
- `);
187
- console.log(` ✓ ${identityPath}`);
188
- }
189
-
190
- // Write local.toml (overrides)
191
- const localToml = `# Generated by hivemind init — ${new Date().toISOString()}
192
- # Overrides config/default.toml with agent-specific settings
193
-
194
- [agent]
195
- name = "${config.agentName}"
196
- ${config.personality ? `personality = "${config.personality.replace(/"/g, '\\"')}"` : "# personality = (using default)"}
197
- workspace = "workspace"
198
-
199
- ${config.llmModel ? `[llm]\nmodel = "${config.llmModel}"` : "# [llm] using defaults"}
200
- ${config.llmBaseUrl ? `# base_url = "${config.llmBaseUrl}"` : ""}
201
-
202
- [sesame]
203
- api_key = "${sesameApiKey}"
204
- `;
205
-
206
- writeFileSync(LOCAL_TOML, localToml);
207
- console.log(` ✓ ${LOCAL_TOML}`);
208
-
209
- // Write .env
210
- const envContent = `# Hivemind Agent — ${config.agentName}
211
- # Generated by hivemind init — ${new Date().toISOString()}
212
- SESAME_API_KEY=${sesameApiKey}
213
- LLM_API_KEY=${config.llmApiKey || ""}
214
- AGENT_NAME=${config.agentName}
215
- `;
216
-
217
- writeFileSync(ENV_FILE, envContent, { mode: 0o600 });
218
- console.log(` ✓ ${ENV_FILE} (chmod 600)`);
219
-
220
- // --- Done ---
221
- console.log(`
222
- ✓ Hivemind initialized for ${config.agentName}!
223
-
224
- To start the agent:
225
- hivemind start
226
-
227
- To install as a service:
228
- hivemind service install
229
-
230
- Agent ID: ${config.agentId}
231
- Channels: ${config.channels.map((c) => c.name || c.id).join(", ")}
232
- Fleet role: ${config.fleetRole || "standalone"}
233
- `);
234
- }
235
-
236
- function printHelp(): void {
237
- console.log(`hivemind init — Initialize a Hivemind agent from Sesame
238
-
239
- Usage: hivemind init [sesame-api-key]
240
-
241
- The API key can also be passed as the first argument.
242
-
243
- What it does:
244
- 1. Connects to Sesame and fetches agent identity
245
- 2. Reads provisioning config from Sesame vault (if available)
246
- 3. Prompts for any missing configuration
247
- 4. Writes config/local.toml and .env
248
-
249
- Options:
250
- -h, --help Show this help
251
- `);
252
- }
@@ -1,159 +0,0 @@
1
- import { resolve } from "path";
2
- import { writeFileSync, existsSync, unlinkSync, mkdirSync } from "fs";
3
- import { execSync } from "child_process";
4
- import { homedir } from "os";
5
-
6
- const LAUNCH_AGENTS_DIR = resolve(homedir(), "Library/LaunchAgents");
7
- const AGENT_LABEL = "com.hivemind.agent";
8
-
9
- function getHivemindHome(): string {
10
- return process.env.HIVEMIND_HOME || resolve(homedir(), "hivemind");
11
- }
12
-
13
- function getHivemindBin(): string {
14
- // Try to find the hivemind binary
15
- try {
16
- const which = execSync("which hivemind", { encoding: "utf-8" }).trim();
17
- if (which) return which;
18
- } catch {}
19
- // Fallback to process.argv[1] (the script being run)
20
- return process.argv[1] || "hivemind";
21
- }
22
-
23
- function generatePlist(hivemindHome: string, hivemindBin: string): string {
24
- return `<?xml version="1.0" encoding="UTF-8"?>
25
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
26
- <plist version="1.0">
27
- <dict>
28
- <key>Label</key>
29
- <string>${AGENT_LABEL}</string>
30
- <key>ProgramArguments</key>
31
- <array>
32
- <string>${hivemindBin}</string>
33
- <string>start</string>
34
- </array>
35
- <key>WorkingDirectory</key>
36
- <string>${hivemindHome}</string>
37
- <key>EnvironmentVariables</key>
38
- <dict>
39
- <key>PATH</key>
40
- <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
41
- <key>HIVEMIND_HOME</key>
42
- <string>${hivemindHome}</string>
43
- </dict>
44
- <key>RunAtLoad</key>
45
- <true/>
46
- <key>KeepAlive</key>
47
- <true/>
48
- <key>StandardOutPath</key>
49
- <string>/tmp/hivemind-agent.log</string>
50
- <key>StandardErrorPath</key>
51
- <string>/tmp/hivemind-error.log</string>
52
- <key>ThrottleInterval</key>
53
- <integer>5</integer>
54
- </dict>
55
- </plist>`;
56
- }
57
-
58
- export async function runServiceCommand(args: string[]): Promise<void> {
59
- const subcommand = args[0];
60
-
61
- switch (subcommand) {
62
- case "install":
63
- await installService();
64
- break;
65
- case "uninstall":
66
- await uninstallService();
67
- break;
68
- case "status":
69
- showStatus();
70
- break;
71
- case "logs":
72
- showLogs(args[1]);
73
- break;
74
- default:
75
- printHelp();
76
- if (subcommand) {
77
- console.error(`Unknown subcommand: ${subcommand}`);
78
- process.exit(1);
79
- }
80
- break;
81
- }
82
- }
83
-
84
- async function installService(): Promise<void> {
85
- const hivemindHome = getHivemindHome();
86
- const hivemindBin = getHivemindBin();
87
-
88
- console.log(`\n→ Installing launchd service for ${hivemindHome}\n`);
89
- console.log(` Binary: ${hivemindBin}`);
90
-
91
- mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });
92
-
93
- const plistContent = generatePlist(hivemindHome, hivemindBin);
94
- const destPath = resolve(LAUNCH_AGENTS_DIR, `${AGENT_LABEL}.plist`);
95
-
96
- // Unload if already loaded
97
- try { execSync(`launchctl unload ${destPath} 2>/dev/null`); } catch {}
98
-
99
- writeFileSync(destPath, plistContent);
100
- execSync(`launchctl load ${destPath}`);
101
-
102
- console.log(` ✓ ${AGENT_LABEL} installed and started`);
103
- console.log("\n Service will auto-start on boot.");
104
- console.log(" Logs: /tmp/hivemind-agent.log, /tmp/hivemind-error.log\n");
105
- }
106
-
107
- async function uninstallService(): Promise<void> {
108
- console.log("\n→ Uninstalling launchd service\n");
109
-
110
- const plistPath = resolve(LAUNCH_AGENTS_DIR, `${AGENT_LABEL}.plist`);
111
- if (existsSync(plistPath)) {
112
- try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}
113
- unlinkSync(plistPath);
114
- console.log(` ✓ ${AGENT_LABEL} uninstalled`);
115
- } else {
116
- console.log(` - ${AGENT_LABEL} not installed`);
117
- }
118
- console.log("");
119
- }
120
-
121
- function showStatus(): void {
122
- console.log("\n→ Service status\n");
123
- try {
124
- const out = execSync(`launchctl list ${AGENT_LABEL} 2>/dev/null`, { encoding: "utf-8" });
125
- const pidMatch = out.match(/"PID"\s*=\s*(\d+)/);
126
- const pid = pidMatch ? pidMatch[1] : "unknown";
127
- console.log(` ✓ ${AGENT_LABEL}: running (PID ${pid})`);
128
- } catch {
129
- console.log(` - ${AGENT_LABEL}: not running`);
130
- }
131
- console.log("");
132
- }
133
-
134
- function showLogs(which?: string): void {
135
- const logFile = which === "error"
136
- ? "/tmp/hivemind-error.log"
137
- : "/tmp/hivemind-agent.log";
138
- try {
139
- execSync(`tail -30 ${logFile}`, { stdio: "inherit" });
140
- } catch {
141
- console.error(`No log file at ${logFile}`);
142
- }
143
- }
144
-
145
- function printHelp(): void {
146
- console.log(`hivemind service — Manage launchd service
147
-
148
- Usage: hivemind service <subcommand>
149
-
150
- Subcommands:
151
- install Install and start launchd service (survives reboots)
152
- uninstall Stop and remove launchd service
153
- status Show service status
154
- logs [agent|error] Show recent logs
155
-
156
- Service:
157
- com.hivemind.agent — Agent runtime (Node.js, Sesame)
158
- `);
159
- }
@@ -1,78 +0,0 @@
1
- import { resolve } from "path";
2
- import { existsSync, readFileSync } from "fs";
3
- import { homedir } from "os";
4
- import { startPipeline } from "@hivemind/runtime";
5
-
6
- const DEFAULT_CONFIG = "config/default.toml";
7
-
8
- /**
9
- * Load .env file from HIVEMIND_HOME, setting any missing env vars.
10
- * Simple KEY=VALUE parser — no dotenv dependency needed.
11
- */
12
- function loadEnvFile(dir: string): void {
13
- const envPath = resolve(dir, ".env");
14
- if (!existsSync(envPath)) return;
15
-
16
- try {
17
- const content = readFileSync(envPath, "utf-8");
18
- for (const line of content.split("\n")) {
19
- const trimmed = line.trim();
20
- if (!trimmed || trimmed.startsWith("#")) continue;
21
- const eqIdx = trimmed.indexOf("=");
22
- if (eqIdx < 1) continue;
23
- const key = trimmed.slice(0, eqIdx).trim();
24
- let value = trimmed.slice(eqIdx + 1).trim();
25
- // Strip surrounding quotes
26
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
27
- value = value.slice(1, -1);
28
- }
29
- // Don't overwrite existing env vars
30
- if (!(key in process.env)) {
31
- process.env[key] = value;
32
- }
33
- }
34
- } catch {
35
- // Silently ignore read errors
36
- }
37
- }
38
-
39
- export async function runStartCommand(args: string[]): Promise<void> {
40
- // Load .env from HIVEMIND_HOME before anything else
41
- const hivemindHome = process.env.HIVEMIND_HOME || resolve(homedir(), "hivemind");
42
- loadEnvFile(hivemindHome);
43
-
44
- let configPath = DEFAULT_CONFIG;
45
-
46
- // Parse args
47
- for (let i = 0; i < args.length; i++) {
48
- if ((args[i] === "--config" || args[i] === "-c") && args[i + 1]) {
49
- configPath = args[++i];
50
- } else if (args[i] === "--help" || args[i] === "-h") {
51
- printHelp();
52
- return;
53
- } else {
54
- console.error(`Unknown argument: ${args[i]}`);
55
- printHelp();
56
- process.exit(1);
57
- }
58
- }
59
-
60
- const resolved = resolve(configPath);
61
- if (!existsSync(resolved)) {
62
- console.error(`Config not found: ${resolved}`);
63
- process.exit(1);
64
- }
65
-
66
- await startPipeline(resolved);
67
- }
68
-
69
- function printHelp(): void {
70
- console.log(`hivemind start — Start the Hivemind agent
71
-
72
- Usage: hivemind start [options]
73
-
74
- Options:
75
- -c, --config <path> Config file (default: config/default.toml)
76
- -h, --help Show this help
77
- `);
78
- }