@sesamespace/hivemind 0.5.3 → 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.
- package/.github/workflows/memory-release.yml +89 -0
- package/config/default.toml +12 -0
- package/data/lancedb/contexts.lance/_transactions/0-c4755ab9-b604-4d90-851f-0491f3cbcbce.txn +2 -0
- package/data/lancedb/contexts.lance/_versions/1.manifest +0 -0
- package/data/lancedb/episode_access.lance/_transactions/0-407a6366-0dca-490a-868b-ea63bee3b40c.txn +2 -0
- package/data/lancedb/episode_access.lance/_versions/1.manifest +0 -0
- package/data/lancedb/episode_cooccurrence.lance/_transactions/0-0e103c7f-29d7-4f09-8100-505c076f01ae.txn +1 -0
- package/data/lancedb/episode_cooccurrence.lance/_versions/1.manifest +0 -0
- package/data/lancedb/episodes.lance/_transactions/0-e678cbac-792b-4a9d-a457-17b0d4d23607.txn +1 -0
- package/data/lancedb/episodes.lance/_versions/1.manifest +0 -0
- package/data/lancedb/l3_knowledge.lance/_transactions/0-cdb3561f-3a59-4e15-bded-e93c5f9a50e3.txn +1 -0
- package/data/lancedb/l3_knowledge.lance/_versions/1.manifest +0 -0
- package/data/lancedb/tasks.lance/_transactions/0-d1cf10ec-1eb8-48b4-bbbe-34b3a1083664.txn +4 -0
- package/data/lancedb/tasks.lance/_versions/1.manifest +0 -0
- package/dist/{chunk-HGNVCCYG.js → chunk-2OIRJFI5.js} +14 -31
- package/dist/chunk-2OIRJFI5.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-LRK64BAK.js +3601 -0
- package/dist/chunk-LRK64BAK.js.map +1 -0
- package/dist/chunk-MBS5A6BZ.js +132 -0
- package/dist/chunk-MBS5A6BZ.js.map +1 -0
- package/dist/{chunk-LNV373IF.js → chunk-OQ272HKA.js} +3 -28
- package/dist/chunk-OQ272HKA.js.map +1 -0
- package/dist/{chunk-CGSXJVSS.js → chunk-RXCV57H3.js} +2 -2
- package/dist/{chunk-S3RVZBPZ.js → chunk-YEOAEJ62.js} +2 -2
- package/dist/commands/fleet.js +4 -3
- package/dist/commands/init.js +2 -1
- package/dist/commands/service.js +2 -1
- package/dist/commands/start.js +4 -3
- package/dist/commands/upgrade.js +1 -0
- package/dist/index.js +3 -2
- package/dist/main.js +7 -6
- package/dist/main.js.map +1 -1
- package/dist/start.js +2 -1
- package/dist/start.js.map +1 -1
- package/package.json +1 -1
- package/PLANNING.md +0 -383
- package/TASKS.md +0 -60
- package/dist/chunk-HGNVCCYG.js.map +0 -1
- package/dist/chunk-LNV373IF.js.map +0 -1
- package/dist/chunk-PPQGQHXJ.js +0 -151
- package/dist/chunk-PPQGQHXJ.js.map +0 -1
- package/dist/chunk-YHRGEWAZ.js +0 -2326
- package/dist/chunk-YHRGEWAZ.js.map +0 -1
- package/install.sh +0 -120
- package/npm-package.json +0 -26
- package/packages/cli/package.json +0 -23
- package/packages/cli/src/commands/fleet.ts +0 -206
- package/packages/cli/src/commands/init.ts +0 -253
- package/packages/cli/src/commands/service.ts +0 -159
- package/packages/cli/src/commands/start.ts +0 -78
- package/packages/cli/src/commands/upgrade.ts +0 -158
- package/packages/cli/src/main.ts +0 -64
- package/packages/cli/tsconfig.json +0 -8
- package/packages/memory/Cargo.lock +0 -6480
- package/packages/memory/Cargo.toml +0 -21
- package/packages/memory/src/context.rs +0 -179
- package/packages/memory/src/embeddings.rs +0 -51
- package/packages/memory/src/main.rs +0 -626
- package/packages/memory/src/promotion.rs +0 -637
- package/packages/memory/src/scoring.rs +0 -131
- package/packages/memory/src/store.rs +0 -460
- package/packages/memory/src/tasks.rs +0 -321
- package/packages/runtime/package.json +0 -24
- package/packages/runtime/src/__tests__/fleet-integration.test.ts +0 -235
- package/packages/runtime/src/__tests__/fleet.test.ts +0 -207
- package/packages/runtime/src/__tests__/integration.test.ts +0 -434
- package/packages/runtime/src/agent.ts +0 -255
- package/packages/runtime/src/config.ts +0 -130
- package/packages/runtime/src/context.ts +0 -192
- package/packages/runtime/src/fleet/fleet-manager.ts +0 -399
- package/packages/runtime/src/fleet/memory-sync.ts +0 -362
- package/packages/runtime/src/fleet/primary-client.ts +0 -285
- package/packages/runtime/src/fleet/worker-protocol.ts +0 -158
- package/packages/runtime/src/fleet/worker-server.ts +0 -246
- package/packages/runtime/src/index.ts +0 -57
- package/packages/runtime/src/llm-client.ts +0 -65
- package/packages/runtime/src/memory-client.ts +0 -309
- package/packages/runtime/src/pipeline.ts +0 -187
- package/packages/runtime/src/prompt.ts +0 -173
- package/packages/runtime/src/sesame.ts +0 -226
- package/packages/runtime/src/start.ts +0 -20
- package/packages/runtime/src/task-engine.ts +0 -113
- package/packages/runtime/src/worker.ts +0 -339
- package/packages/runtime/tsconfig.json +0 -8
- package/pnpm-workspace.yaml +0 -2
- package/run-aidan.sh +0 -23
- package/scripts/bootstrap.sh +0 -196
- package/scripts/build-npm.sh +0 -92
- package/scripts/com.hivemind.agent.plist +0 -44
- package/scripts/com.hivemind.memory.plist +0 -31
- package/tsconfig.json +0 -22
- package/tsup.config.ts +0 -27
- /package/dist/{chunk-CGSXJVSS.js.map → chunk-RXCV57H3.js.map} +0 -0
- /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,253 +0,0 @@
|
|
|
1
|
-
import { resolve, dirname } from "path";
|
|
2
|
-
import { existsSync, writeFileSync, mkdirSync, readFileSync, copyFileSync } 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 { realpathSync } = await import("fs");
|
|
146
|
-
const realBin = realpathSync(process.argv[1]);
|
|
147
|
-
// realBin is <pkg>/dist/main.js, so ../config/ gets us to <pkg>/config/
|
|
148
|
-
const packageConfigDir = resolve(dirname(realBin), "..", "config");
|
|
149
|
-
const packageDefault = resolve(packageConfigDir, "default.toml");
|
|
150
|
-
if (existsSync(packageDefault)) {
|
|
151
|
-
copyFileSync(packageDefault, defaultToml);
|
|
152
|
-
console.log(` ✓ ${defaultToml}`);
|
|
153
|
-
// Also copy team charter if available
|
|
154
|
-
const packageCharter = resolve(packageConfigDir, "TEAM-CHARTER.md");
|
|
155
|
-
const localCharter = resolve(CONFIG_DIR, "TEAM-CHARTER.md");
|
|
156
|
-
if (existsSync(packageCharter) && !existsSync(localCharter)) {
|
|
157
|
-
copyFileSync(packageCharter, localCharter);
|
|
158
|
-
console.log(` ✓ ${localCharter}`);
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
console.log(` ! default.toml not found in package — you may need to copy it manually`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Write workspace identity files
|
|
166
|
-
const soulPath = resolve(WORKSPACE_DIR, "SOUL.md");
|
|
167
|
-
if (!existsSync(soulPath)) {
|
|
168
|
-
const personality = config.personality || "A helpful, capable agent.";
|
|
169
|
-
writeFileSync(soulPath, `# SOUL.md — Who You Are
|
|
170
|
-
|
|
171
|
-
${personality}
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
_This file defines your personality and values. Edit it to evolve who you are._
|
|
176
|
-
`);
|
|
177
|
-
console.log(` ✓ ${soulPath}`);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const identityPath = resolve(WORKSPACE_DIR, "IDENTITY.md");
|
|
181
|
-
if (!existsSync(identityPath)) {
|
|
182
|
-
writeFileSync(identityPath, `# IDENTITY.md
|
|
183
|
-
|
|
184
|
-
- **Name:** ${config.agentName}
|
|
185
|
-
- **Handle:** ${config.agentHandle}
|
|
186
|
-
- **Agent ID:** ${config.agentId}
|
|
187
|
-
`);
|
|
188
|
-
console.log(` ✓ ${identityPath}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Write local.toml (overrides)
|
|
192
|
-
const localToml = `# Generated by hivemind init — ${new Date().toISOString()}
|
|
193
|
-
# Overrides config/default.toml with agent-specific settings
|
|
194
|
-
|
|
195
|
-
[agent]
|
|
196
|
-
name = "${config.agentName}"
|
|
197
|
-
${config.personality ? `personality = "${config.personality.replace(/"/g, '\\"')}"` : "# personality = (using default)"}
|
|
198
|
-
workspace = "workspace"
|
|
199
|
-
|
|
200
|
-
${config.llmModel ? `[llm]\nmodel = "${config.llmModel}"` : "# [llm] using defaults"}
|
|
201
|
-
${config.llmBaseUrl ? `# base_url = "${config.llmBaseUrl}"` : ""}
|
|
202
|
-
|
|
203
|
-
[sesame]
|
|
204
|
-
api_key = "${sesameApiKey}"
|
|
205
|
-
`;
|
|
206
|
-
|
|
207
|
-
writeFileSync(LOCAL_TOML, localToml);
|
|
208
|
-
console.log(` ✓ ${LOCAL_TOML}`);
|
|
209
|
-
|
|
210
|
-
// Write .env
|
|
211
|
-
const envContent = `# Hivemind Agent — ${config.agentName}
|
|
212
|
-
# Generated by hivemind init — ${new Date().toISOString()}
|
|
213
|
-
SESAME_API_KEY=${sesameApiKey}
|
|
214
|
-
LLM_API_KEY=${config.llmApiKey || ""}
|
|
215
|
-
AGENT_NAME=${config.agentName}
|
|
216
|
-
`;
|
|
217
|
-
|
|
218
|
-
writeFileSync(ENV_FILE, envContent, { mode: 0o600 });
|
|
219
|
-
console.log(` ✓ ${ENV_FILE} (chmod 600)`);
|
|
220
|
-
|
|
221
|
-
// --- Done ---
|
|
222
|
-
console.log(`
|
|
223
|
-
✓ Hivemind initialized for ${config.agentName}!
|
|
224
|
-
|
|
225
|
-
To start the agent:
|
|
226
|
-
hivemind start
|
|
227
|
-
|
|
228
|
-
To install as a service:
|
|
229
|
-
hivemind service install
|
|
230
|
-
|
|
231
|
-
Agent ID: ${config.agentId}
|
|
232
|
-
Channels: ${config.channels.map((c) => c.name || c.id).join(", ")}
|
|
233
|
-
Fleet role: ${config.fleetRole || "standalone"}
|
|
234
|
-
`);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function printHelp(): void {
|
|
238
|
-
console.log(`hivemind init — Initialize a Hivemind agent from Sesame
|
|
239
|
-
|
|
240
|
-
Usage: hivemind init [sesame-api-key]
|
|
241
|
-
|
|
242
|
-
The API key can also be passed as the first argument.
|
|
243
|
-
|
|
244
|
-
What it does:
|
|
245
|
-
1. Connects to Sesame and fetches agent identity
|
|
246
|
-
2. Reads provisioning config from Sesame vault (if available)
|
|
247
|
-
3. Prompts for any missing configuration
|
|
248
|
-
4. Writes config/local.toml and .env
|
|
249
|
-
|
|
250
|
-
Options:
|
|
251
|
-
-h, --help Show this help
|
|
252
|
-
`);
|
|
253
|
-
}
|
|
@@ -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
|
-
}
|