@sesamespace/hivemind 0.2.0 → 0.3.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/PLANNING.md +383 -0
- package/TASKS.md +60 -0
- package/install.sh +187 -0
- package/npm-package.json +28 -0
- package/package.json +13 -20
- package/packages/cli/package.json +23 -0
- package/{dist/chunk-DVR2KBL7.js → packages/cli/src/commands/fleet.ts} +50 -30
- package/packages/cli/src/commands/init.ts +230 -0
- package/{dist/chunk-MBS5A6BZ.js → packages/cli/src/commands/service.ts} +51 -42
- package/{dist/chunk-RNK5Q5GR.js → packages/cli/src/commands/start.ts} +12 -14
- package/{dist/main.js → packages/cli/src/main.ts} +12 -18
- package/packages/cli/tsconfig.json +8 -0
- package/packages/memory/Cargo.lock +6480 -0
- package/packages/memory/Cargo.toml +21 -0
- package/packages/memory/src/context.rs +179 -0
- package/packages/memory/src/embeddings.rs +51 -0
- package/packages/memory/src/main.rs +626 -0
- package/packages/memory/src/promotion.rs +637 -0
- package/packages/memory/src/scoring.rs +131 -0
- package/packages/memory/src/store.rs +460 -0
- package/packages/memory/src/tasks.rs +321 -0
- package/packages/runtime/package.json +24 -0
- package/packages/runtime/src/__tests__/fleet-integration.test.ts +235 -0
- package/packages/runtime/src/__tests__/fleet.test.ts +207 -0
- package/packages/runtime/src/__tests__/integration.test.ts +434 -0
- package/packages/runtime/src/agent.ts +255 -0
- package/packages/runtime/src/config.ts +130 -0
- package/packages/runtime/src/context.ts +192 -0
- package/packages/runtime/src/fleet/fleet-manager.ts +399 -0
- package/packages/runtime/src/fleet/memory-sync.ts +362 -0
- package/packages/runtime/src/fleet/primary-client.ts +285 -0
- package/packages/runtime/src/fleet/worker-protocol.ts +158 -0
- package/packages/runtime/src/fleet/worker-server.ts +246 -0
- package/packages/runtime/src/index.ts +57 -0
- package/packages/runtime/src/llm-client.ts +65 -0
- package/packages/runtime/src/memory-client.ts +309 -0
- package/packages/runtime/src/pipeline.ts +151 -0
- package/packages/runtime/src/prompt.ts +173 -0
- package/packages/runtime/src/sesame.ts +174 -0
- package/{dist/start.js → packages/runtime/src/start.ts} +7 -9
- package/packages/runtime/src/task-engine.ts +113 -0
- package/packages/runtime/src/worker.ts +339 -0
- package/packages/runtime/tsconfig.json +8 -0
- package/pnpm-workspace.yaml +2 -0
- package/run-aidan.sh +23 -0
- package/scripts/bootstrap.sh +196 -0
- package/scripts/build-npm.sh +94 -0
- package/scripts/com.hivemind.agent.plist +44 -0
- package/scripts/com.hivemind.memory.plist +31 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +28 -0
- package/dist/chunk-2I2O6X5D.js +0 -1408
- package/dist/chunk-2I2O6X5D.js.map +0 -1
- package/dist/chunk-DVR2KBL7.js.map +0 -1
- package/dist/chunk-MBS5A6BZ.js.map +0 -1
- package/dist/chunk-NVJ424TB.js +0 -731
- package/dist/chunk-NVJ424TB.js.map +0 -1
- package/dist/chunk-RNK5Q5GR.js.map +0 -1
- package/dist/chunk-XNOWVLXD.js +0 -160
- package/dist/chunk-XNOWVLXD.js.map +0 -1
- package/dist/commands/fleet.js +0 -9
- package/dist/commands/fleet.js.map +0 -1
- package/dist/commands/init.js +0 -7
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/service.js +0 -7
- package/dist/commands/service.js.map +0 -1
- package/dist/commands/start.js +0 -9
- package/dist/commands/start.js.map +0 -1
- package/dist/index.js +0 -41
- package/dist/index.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/start.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sesamespace/hivemind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Cognitive architecture for AI agents with multi-layered memory",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"config",
|
|
13
|
-
"README.md"
|
|
14
|
-
],
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@iarna/toml": "^2.2.5",
|
|
17
|
-
"@sesamespace/sdk": "^0.1.6",
|
|
18
|
-
"ws": "^8.18.0"
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "pnpm -r build",
|
|
7
|
+
"typecheck": "pnpm -r typecheck",
|
|
8
|
+
"lint": "pnpm -r lint",
|
|
9
|
+
"test": "pnpm -r test"
|
|
19
10
|
},
|
|
20
11
|
"engines": {
|
|
21
|
-
"node": ">=20.0.0"
|
|
12
|
+
"node": ">=20.0.0",
|
|
13
|
+
"pnpm": ">=9.0.0"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@sesamespace/sdk": "^0.1.6"
|
|
22
17
|
},
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "https://github.com/baileydavis2026/hivemind"
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"tsup": "^8.5.1"
|
|
27
20
|
}
|
|
28
21
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hivemind/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"hivemind": "dist/main.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"dev": "tsx src/main.ts",
|
|
13
|
+
"test": "echo \"No tests yet\""
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@hivemind/runtime": "workspace:*"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^20.14.0",
|
|
20
|
+
"tsx": "^4.16.0",
|
|
21
|
+
"typescript": "^5.5.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,40 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
+
*/
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 "—";
|
|
8
18
|
if (seconds < 60) return `${seconds}s`;
|
|
9
19
|
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
10
20
|
const h = Math.floor(seconds / 3600);
|
|
11
|
-
const m = Math.floor(seconds % 3600 / 60);
|
|
21
|
+
const m = Math.floor((seconds % 3600) / 60);
|
|
12
22
|
return `${h}h ${m}m`;
|
|
13
23
|
}
|
|
14
|
-
|
|
24
|
+
|
|
25
|
+
function formatHealth(status: string): string {
|
|
15
26
|
switch (status) {
|
|
16
|
-
case "healthy":
|
|
17
|
-
|
|
18
|
-
case "
|
|
19
|
-
|
|
20
|
-
case "unreachable":
|
|
21
|
-
return "DOWN";
|
|
22
|
-
default:
|
|
23
|
-
return status.toUpperCase();
|
|
27
|
+
case "healthy": return "OK";
|
|
28
|
+
case "degraded": return "DEGRADED";
|
|
29
|
+
case "unreachable": return "DOWN";
|
|
30
|
+
default: return status.toUpperCase();
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
|
-
|
|
33
|
+
|
|
34
|
+
function printDashboard(dashboard: FleetDashboard): void {
|
|
27
35
|
console.log("\n=== Hivemind Fleet ===\n");
|
|
28
36
|
console.log(`Workers: ${dashboard.total_workers} (${dashboard.healthy} healthy, ${dashboard.degraded} degraded, ${dashboard.unreachable} unreachable)`);
|
|
29
37
|
console.log(`Contexts assigned: ${dashboard.total_contexts}`);
|
|
38
|
+
|
|
30
39
|
if (dashboard.unassigned_contexts.length > 0) {
|
|
31
40
|
console.log(`Unassigned contexts: ${dashboard.unassigned_contexts.join(", ")}`);
|
|
32
41
|
}
|
|
42
|
+
|
|
33
43
|
console.log("");
|
|
44
|
+
|
|
34
45
|
if (dashboard.workers.length === 0) {
|
|
35
46
|
console.log("No workers registered. Use 'fleet add-worker <url>' to add one.");
|
|
36
47
|
return;
|
|
37
48
|
}
|
|
49
|
+
|
|
50
|
+
// Table header
|
|
38
51
|
const cols = { id: 12, url: 30, health: 8, activity: 10, contexts: 25, task: 20, uptime: 8 };
|
|
39
52
|
const header = [
|
|
40
53
|
"ID".padEnd(cols.id),
|
|
@@ -43,38 +56,44 @@ function printDashboard(dashboard) {
|
|
|
43
56
|
"ACTIVITY".padEnd(cols.activity),
|
|
44
57
|
"CONTEXTS".padEnd(cols.contexts),
|
|
45
58
|
"TASK".padEnd(cols.task),
|
|
46
|
-
"UPTIME".padEnd(cols.uptime)
|
|
59
|
+
"UPTIME".padEnd(cols.uptime),
|
|
47
60
|
].join(" ");
|
|
48
61
|
console.log(header);
|
|
49
62
|
console.log("-".repeat(header.length));
|
|
63
|
+
|
|
50
64
|
for (const w of dashboard.workers) {
|
|
51
65
|
const row = [
|
|
52
66
|
w.id.padEnd(cols.id),
|
|
53
67
|
w.url.slice(0, cols.url).padEnd(cols.url),
|
|
54
68
|
formatHealth(w.health).padEnd(cols.health),
|
|
55
69
|
w.activity.padEnd(cols.activity),
|
|
56
|
-
(w.contexts.join(", ") || "
|
|
57
|
-
(w.current_task ?? "
|
|
58
|
-
formatUptime(w.uptime_seconds).padEnd(cols.uptime)
|
|
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),
|
|
59
73
|
].join(" ");
|
|
60
74
|
console.log(row);
|
|
61
75
|
}
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
|
|
77
|
+
console.log(`\nGenerated: ${dashboard.generated_at}`);
|
|
64
78
|
}
|
|
65
|
-
|
|
79
|
+
|
|
80
|
+
export async function runFleetCommand(args: string[]): Promise<void> {
|
|
66
81
|
const subcommand = args[0];
|
|
82
|
+
|
|
67
83
|
if (!subcommand) {
|
|
68
84
|
printUsage();
|
|
69
85
|
process.exit(1);
|
|
70
86
|
}
|
|
87
|
+
|
|
71
88
|
const fleet = new FleetManager();
|
|
89
|
+
|
|
72
90
|
switch (subcommand) {
|
|
73
91
|
case "status": {
|
|
74
92
|
const dashboard = await fleet.getDashboard();
|
|
75
93
|
printDashboard(dashboard);
|
|
76
94
|
break;
|
|
77
95
|
}
|
|
96
|
+
|
|
78
97
|
case "add-worker": {
|
|
79
98
|
const url = args[1];
|
|
80
99
|
if (!url) {
|
|
@@ -95,6 +114,7 @@ async function runFleetCommand(args) {
|
|
|
95
114
|
}
|
|
96
115
|
break;
|
|
97
116
|
}
|
|
117
|
+
|
|
98
118
|
case "remove-worker": {
|
|
99
119
|
const workerId = args[1];
|
|
100
120
|
if (!workerId) {
|
|
@@ -110,6 +130,7 @@ async function runFleetCommand(args) {
|
|
|
110
130
|
}
|
|
111
131
|
break;
|
|
112
132
|
}
|
|
133
|
+
|
|
113
134
|
case "assign": {
|
|
114
135
|
const workerId = args[1];
|
|
115
136
|
const context = args[2];
|
|
@@ -126,6 +147,7 @@ async function runFleetCommand(args) {
|
|
|
126
147
|
}
|
|
127
148
|
break;
|
|
128
149
|
}
|
|
150
|
+
|
|
129
151
|
case "migrate": {
|
|
130
152
|
const context = args[1];
|
|
131
153
|
const toWorker = args[2];
|
|
@@ -142,6 +164,7 @@ async function runFleetCommand(args) {
|
|
|
142
164
|
}
|
|
143
165
|
break;
|
|
144
166
|
}
|
|
167
|
+
|
|
145
168
|
case "discover": {
|
|
146
169
|
const urls = args.slice(1);
|
|
147
170
|
if (urls.length === 0) {
|
|
@@ -160,13 +183,15 @@ async function runFleetCommand(args) {
|
|
|
160
183
|
}
|
|
161
184
|
break;
|
|
162
185
|
}
|
|
186
|
+
|
|
163
187
|
default:
|
|
164
188
|
console.error(`Unknown fleet subcommand: ${subcommand}`);
|
|
165
189
|
printUsage();
|
|
166
190
|
process.exit(1);
|
|
167
191
|
}
|
|
168
192
|
}
|
|
169
|
-
|
|
193
|
+
|
|
194
|
+
function printUsage(): void {
|
|
170
195
|
console.log(`
|
|
171
196
|
Usage: hivemind fleet <command> [args]
|
|
172
197
|
|
|
@@ -179,8 +204,3 @@ Commands:
|
|
|
179
204
|
discover <url1> [url2] ... Probe URLs for workers
|
|
180
205
|
`.trim());
|
|
181
206
|
}
|
|
182
|
-
|
|
183
|
-
export {
|
|
184
|
-
runFleetCommand
|
|
185
|
-
};
|
|
186
|
-
//# sourceMappingURL=chunk-DVR2KBL7.js.map
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { resolve, dirname } from "path";
|
|
2
|
+
import { existsSync, writeFileSync, mkdirSync, readFileSync } from "fs";
|
|
3
|
+
import { createInterface } from "readline";
|
|
4
|
+
import { SesameClient } from "@sesamespace/sdk";
|
|
5
|
+
|
|
6
|
+
const HIVEMIND_DIR = resolve(process.env.HIVEMIND_HOME || ".");
|
|
7
|
+
const CONFIG_DIR = resolve(HIVEMIND_DIR, "config");
|
|
8
|
+
const WORKSPACE_DIR = resolve(HIVEMIND_DIR, "workspace");
|
|
9
|
+
const ENV_FILE = resolve(HIVEMIND_DIR, ".env");
|
|
10
|
+
const LOCAL_TOML = resolve(CONFIG_DIR, "local.toml");
|
|
11
|
+
|
|
12
|
+
const VAULT_CONFIG_NAME = "hivemind-config";
|
|
13
|
+
|
|
14
|
+
interface ProvisioningConfig {
|
|
15
|
+
agentName: string;
|
|
16
|
+
agentHandle: string;
|
|
17
|
+
agentId: string;
|
|
18
|
+
personality?: string;
|
|
19
|
+
llmApiKey?: string;
|
|
20
|
+
llmBaseUrl?: string;
|
|
21
|
+
llmModel?: string;
|
|
22
|
+
fleetRole?: string;
|
|
23
|
+
channels: Array<{ id: string; name: string | null; kind: string }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function prompt(question: string): Promise<string> {
|
|
27
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
rl.question(question, (answer) => {
|
|
30
|
+
rl.close();
|
|
31
|
+
resolve(answer.trim());
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function runInitCommand(args: string[]): Promise<void> {
|
|
37
|
+
const nonInteractive = args.includes("--yes") || args.includes("-y") || args.includes("--non-interactive");
|
|
38
|
+
const filteredArgs = args.filter((a) => !["--yes", "-y", "--non-interactive", "--help", "-h"].includes(a));
|
|
39
|
+
let sesameApiKey = filteredArgs[0];
|
|
40
|
+
|
|
41
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
42
|
+
printHelp();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(`
|
|
47
|
+
╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗
|
|
48
|
+
╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║
|
|
49
|
+
╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝
|
|
50
|
+
Agent Initialization
|
|
51
|
+
`);
|
|
52
|
+
|
|
53
|
+
// --- Step 1: Get Sesame API key ---
|
|
54
|
+
if (!sesameApiKey) {
|
|
55
|
+
sesameApiKey = await prompt(" Sesame API key: ");
|
|
56
|
+
}
|
|
57
|
+
if (!sesameApiKey) {
|
|
58
|
+
console.error("Error: Sesame API key is required");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- Step 2: Connect to Sesame and fetch manifest ---
|
|
63
|
+
console.log("\n→ Connecting to Sesame...");
|
|
64
|
+
const sdk = new SesameClient({
|
|
65
|
+
apiUrl: "https://api.sesame.space",
|
|
66
|
+
wsUrl: "wss://ws.sesame.space",
|
|
67
|
+
apiKey: sesameApiKey,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
let config: ProvisioningConfig;
|
|
71
|
+
try {
|
|
72
|
+
const manifest = await sdk.getManifest();
|
|
73
|
+
console.log(` ✓ Authenticated as ${manifest.agent.handle} (${manifest.agent.id})`);
|
|
74
|
+
console.log(` ✓ Workspace: ${manifest.workspace.name}`);
|
|
75
|
+
console.log(` ✓ Channels: ${manifest.channels.length}`);
|
|
76
|
+
for (const ch of manifest.channels) {
|
|
77
|
+
console.log(` - ${ch.name || ch.id} (${ch.kind})`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
config = {
|
|
81
|
+
agentName: manifest.agent.handle,
|
|
82
|
+
agentHandle: manifest.agent.handle,
|
|
83
|
+
agentId: manifest.agent.id,
|
|
84
|
+
channels: manifest.channels.map((ch) => ({
|
|
85
|
+
id: ch.id,
|
|
86
|
+
name: ch.name,
|
|
87
|
+
kind: ch.kind,
|
|
88
|
+
})),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// --- Step 3: Check vault for config ---
|
|
92
|
+
console.log("\n→ Checking vault for provisioning config...");
|
|
93
|
+
try {
|
|
94
|
+
const vaultResp = await sdk.listVaultItems() as any;
|
|
95
|
+
const items = vaultResp.items || vaultResp.data || [];
|
|
96
|
+
const configItem = items.find((i: any) => i.name === VAULT_CONFIG_NAME);
|
|
97
|
+
|
|
98
|
+
if (configItem) {
|
|
99
|
+
console.log(` ✓ Found ${VAULT_CONFIG_NAME} vault item`);
|
|
100
|
+
const revealResp = await sdk.revealItem(configItem.id) as any;
|
|
101
|
+
const fields = revealResp.fields || revealResp.data || {};
|
|
102
|
+
|
|
103
|
+
config.llmApiKey = fields.llm_api_key || fields.openrouter_api_key;
|
|
104
|
+
config.llmBaseUrl = fields.llm_base_url;
|
|
105
|
+
config.llmModel = fields.llm_model;
|
|
106
|
+
config.personality = fields.agent_personality || fields.personality;
|
|
107
|
+
config.fleetRole = fields.fleet_role;
|
|
108
|
+
|
|
109
|
+
if (config.llmApiKey) console.log(" ✓ LLM API key loaded from vault");
|
|
110
|
+
if (config.personality) console.log(` ✓ Personality: ${config.personality.slice(0, 60)}...`);
|
|
111
|
+
if (config.fleetRole) console.log(` ✓ Fleet role: ${config.fleetRole}`);
|
|
112
|
+
} else {
|
|
113
|
+
console.log(" ! No hivemind-config vault item found");
|
|
114
|
+
console.log(" ! Will prompt for LLM API key instead");
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.log(` ! Could not read vault: ${(err as Error).message}`);
|
|
118
|
+
}
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error(`\n ✗ Failed to connect to Sesame: ${(err as Error).message}`);
|
|
121
|
+
console.error(" Check your API key and try again.");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
} finally {
|
|
124
|
+
sdk.disconnect();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// --- Step 4: Prompt for anything missing (skip in non-interactive mode) ---
|
|
128
|
+
if (!config.llmApiKey && !nonInteractive) {
|
|
129
|
+
config.llmApiKey = await prompt("\n OpenRouter API key: ");
|
|
130
|
+
} else if (!config.llmApiKey) {
|
|
131
|
+
console.log(" ! No LLM API key found in vault — set LLM_API_KEY in .env after init");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!nonInteractive) {
|
|
135
|
+
const nameOverride = await prompt(` Agent name [${config.agentName}]: `);
|
|
136
|
+
if (nameOverride) config.agentName = nameOverride;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- Step 5: Write config files ---
|
|
140
|
+
console.log("\n→ Writing configuration...");
|
|
141
|
+
|
|
142
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
143
|
+
mkdirSync(WORKSPACE_DIR, { recursive: true });
|
|
144
|
+
|
|
145
|
+
// Write workspace identity files
|
|
146
|
+
const soulPath = resolve(WORKSPACE_DIR, "SOUL.md");
|
|
147
|
+
if (!existsSync(soulPath)) {
|
|
148
|
+
const personality = config.personality || "A helpful, capable agent.";
|
|
149
|
+
writeFileSync(soulPath, `# SOUL.md — Who You Are
|
|
150
|
+
|
|
151
|
+
${personality}
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
_This file defines your personality and values. Edit it to evolve who you are._
|
|
156
|
+
`);
|
|
157
|
+
console.log(` ✓ ${soulPath}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const identityPath = resolve(WORKSPACE_DIR, "IDENTITY.md");
|
|
161
|
+
if (!existsSync(identityPath)) {
|
|
162
|
+
writeFileSync(identityPath, `# IDENTITY.md
|
|
163
|
+
|
|
164
|
+
- **Name:** ${config.agentName}
|
|
165
|
+
- **Handle:** ${config.agentHandle}
|
|
166
|
+
- **Agent ID:** ${config.agentId}
|
|
167
|
+
`);
|
|
168
|
+
console.log(` ✓ ${identityPath}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Write local.toml (overrides)
|
|
172
|
+
const localToml = `# Generated by hivemind init — ${new Date().toISOString()}
|
|
173
|
+
# Overrides config/default.toml with agent-specific settings
|
|
174
|
+
|
|
175
|
+
[agent]
|
|
176
|
+
name = "${config.agentName}"
|
|
177
|
+
${config.personality ? `personality = "${config.personality.replace(/"/g, '\\"')}"` : "# personality = (using default)"}
|
|
178
|
+
workspace = "workspace"
|
|
179
|
+
|
|
180
|
+
${config.llmModel ? `[llm]\nmodel = "${config.llmModel}"` : "# [llm] using defaults"}
|
|
181
|
+
${config.llmBaseUrl ? `# base_url = "${config.llmBaseUrl}"` : ""}
|
|
182
|
+
`;
|
|
183
|
+
|
|
184
|
+
writeFileSync(LOCAL_TOML, localToml);
|
|
185
|
+
console.log(` ✓ ${LOCAL_TOML}`);
|
|
186
|
+
|
|
187
|
+
// Write .env
|
|
188
|
+
const envContent = `# Hivemind Agent — ${config.agentName}
|
|
189
|
+
# Generated by hivemind init — ${new Date().toISOString()}
|
|
190
|
+
SESAME_API_KEY=${sesameApiKey}
|
|
191
|
+
LLM_API_KEY=${config.llmApiKey || ""}
|
|
192
|
+
AGENT_NAME=${config.agentName}
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
writeFileSync(ENV_FILE, envContent, { mode: 0o600 });
|
|
196
|
+
console.log(` ✓ ${ENV_FILE} (chmod 600)`);
|
|
197
|
+
|
|
198
|
+
// --- Done ---
|
|
199
|
+
console.log(`
|
|
200
|
+
✓ Hivemind initialized for ${config.agentName}!
|
|
201
|
+
|
|
202
|
+
To start the agent:
|
|
203
|
+
./start.sh
|
|
204
|
+
|
|
205
|
+
To start in background:
|
|
206
|
+
nohup ./start.sh > /tmp/hivemind.log 2>&1 &
|
|
207
|
+
|
|
208
|
+
Agent ID: ${config.agentId}
|
|
209
|
+
Channels: ${config.channels.map((c) => c.name || c.id).join(", ")}
|
|
210
|
+
Fleet role: ${config.fleetRole || "standalone"}
|
|
211
|
+
`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function printHelp(): void {
|
|
215
|
+
console.log(`hivemind init — Initialize a Hivemind agent from Sesame
|
|
216
|
+
|
|
217
|
+
Usage: hivemind init [sesame-api-key]
|
|
218
|
+
|
|
219
|
+
The API key can also be passed as the first argument.
|
|
220
|
+
|
|
221
|
+
What it does:
|
|
222
|
+
1. Connects to Sesame and fetches agent identity
|
|
223
|
+
2. Reads provisioning config from Sesame vault (if available)
|
|
224
|
+
3. Prompts for any missing configuration
|
|
225
|
+
4. Writes config/local.toml and .env
|
|
226
|
+
|
|
227
|
+
Options:
|
|
228
|
+
-h, --help Show this help
|
|
229
|
+
`);
|
|
230
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// packages/cli/src/commands/service.ts
|
|
2
1
|
import { resolve } from "path";
|
|
3
2
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
4
3
|
import { execSync } from "child_process";
|
|
5
4
|
import { homedir } from "os";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
async function runServiceCommand(args) {
|
|
5
|
+
|
|
6
|
+
const LAUNCH_AGENTS_DIR = resolve(homedir(), "Library/LaunchAgents");
|
|
7
|
+
const AGENT_LABEL = "com.hivemind.agent";
|
|
8
|
+
const MEMORY_LABEL = "com.hivemind.memory";
|
|
9
|
+
|
|
10
|
+
export async function runServiceCommand(args: string[]): Promise<void> {
|
|
12
11
|
const subcommand = args[0];
|
|
12
|
+
|
|
13
13
|
switch (subcommand) {
|
|
14
14
|
case "install":
|
|
15
15
|
await installServices(args.slice(1));
|
|
@@ -32,85 +32,95 @@ async function runServiceCommand(args) {
|
|
|
32
32
|
break;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
async function installServices(_args: string[]): Promise<void> {
|
|
36
37
|
const hivemindHome = process.env.HIVEMIND_HOME || process.cwd();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+
console.log(`\n→ Installing launchd services for ${hivemindHome}\n`);
|
|
40
|
+
|
|
40
41
|
mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });
|
|
42
|
+
|
|
43
|
+
// Find plist templates
|
|
41
44
|
const scriptDirs = [
|
|
42
45
|
resolve(hivemindHome, "scripts"),
|
|
43
|
-
resolve(dirname(dirname(dirname(fileURLToPath(import.meta.url)))), "scripts")
|
|
46
|
+
resolve(dirname(dirname(dirname(fileURLToPath(import.meta.url)))), "scripts"),
|
|
44
47
|
];
|
|
48
|
+
|
|
45
49
|
for (const label of [MEMORY_LABEL, AGENT_LABEL]) {
|
|
46
50
|
const plistFile = `${label}.plist`;
|
|
47
51
|
let templatePath = "";
|
|
52
|
+
|
|
48
53
|
for (const dir of scriptDirs) {
|
|
49
54
|
const p = resolve(dir, plistFile);
|
|
50
|
-
if (existsSync(p)) {
|
|
51
|
-
templatePath = p;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
55
|
+
if (existsSync(p)) { templatePath = p; break; }
|
|
54
56
|
}
|
|
57
|
+
|
|
55
58
|
if (!templatePath) {
|
|
56
|
-
console.error(`
|
|
59
|
+
console.error(` ✗ Template not found: ${plistFile}`);
|
|
57
60
|
continue;
|
|
58
61
|
}
|
|
62
|
+
|
|
59
63
|
let content = readFileSync(templatePath, "utf-8");
|
|
60
64
|
content = content.replace(/__HIVEMIND_HOME__/g, hivemindHome);
|
|
65
|
+
|
|
61
66
|
const destPath = resolve(LAUNCH_AGENTS_DIR, plistFile);
|
|
62
67
|
writeFileSync(destPath, content);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} catch {
|
|
66
|
-
}
|
|
68
|
+
|
|
69
|
+
// Unload if already loaded, then load
|
|
70
|
+
try { execSync(`launchctl unload ${destPath} 2>/dev/null`); } catch {}
|
|
67
71
|
execSync(`launchctl load ${destPath}`);
|
|
68
|
-
|
|
72
|
+
|
|
73
|
+
console.log(` ✓ ${label} installed and started`);
|
|
69
74
|
}
|
|
75
|
+
|
|
70
76
|
console.log("\n Services will auto-start on boot.\n");
|
|
71
77
|
}
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
|
|
79
|
+
async function uninstallServices(): Promise<void> {
|
|
80
|
+
console.log("\n→ Uninstalling launchd services\n");
|
|
81
|
+
|
|
74
82
|
for (const label of [AGENT_LABEL, MEMORY_LABEL]) {
|
|
75
83
|
const plistPath = resolve(LAUNCH_AGENTS_DIR, `${label}.plist`);
|
|
76
84
|
if (existsSync(plistPath)) {
|
|
77
|
-
try {
|
|
78
|
-
execSync(`launchctl unload ${plistPath} 2>/dev/null`);
|
|
79
|
-
} catch {
|
|
80
|
-
}
|
|
85
|
+
try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}
|
|
81
86
|
const { unlinkSync } = await import("fs");
|
|
82
87
|
unlinkSync(plistPath);
|
|
83
|
-
console.log(`
|
|
88
|
+
console.log(` ✓ ${label} uninstalled`);
|
|
84
89
|
} else {
|
|
85
90
|
console.log(` - ${label} not installed`);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
console.log("");
|
|
89
94
|
}
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
|
|
96
|
+
function showStatus(): void {
|
|
97
|
+
console.log("\n→ Service status\n");
|
|
92
98
|
for (const label of [MEMORY_LABEL, AGENT_LABEL]) {
|
|
93
99
|
try {
|
|
94
100
|
const out = execSync(`launchctl list ${label} 2>/dev/null`, { encoding: "utf-8" });
|
|
95
101
|
const pidMatch = out.match(/"PID"\s*=\s*(\d+)/);
|
|
96
102
|
const pid = pidMatch ? pidMatch[1] : "unknown";
|
|
97
|
-
console.log(`
|
|
103
|
+
console.log(` ✓ ${label}: running (PID ${pid})`);
|
|
98
104
|
} catch {
|
|
99
105
|
console.log(` - ${label}: not running`);
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
console.log("");
|
|
103
109
|
}
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
|
|
111
|
+
function showLogs(which?: string): void {
|
|
112
|
+
const logFile = which === "memory"
|
|
113
|
+
? "/tmp/hivemind-memory.log"
|
|
114
|
+
: "/tmp/hivemind-agent.log";
|
|
106
115
|
try {
|
|
107
116
|
execSync(`tail -30 ${logFile}`, { stdio: "inherit" });
|
|
108
117
|
} catch {
|
|
109
118
|
console.error(`No log file at ${logFile}`);
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
|
|
122
|
+
function printHelp(): void {
|
|
123
|
+
console.log(`hivemind service — Manage launchd services
|
|
114
124
|
|
|
115
125
|
Usage: hivemind service <subcommand>
|
|
116
126
|
|
|
@@ -121,12 +131,11 @@ Subcommands:
|
|
|
121
131
|
logs [agent|memory] Show recent logs
|
|
122
132
|
|
|
123
133
|
Services:
|
|
124
|
-
com.hivemind.memory
|
|
125
|
-
com.hivemind.agent
|
|
134
|
+
com.hivemind.memory — Memory daemon (Rust, port 3434)
|
|
135
|
+
com.hivemind.agent — Agent runtime (Node.js, Sesame)
|
|
126
136
|
`);
|
|
127
137
|
}
|
|
128
138
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
};
|
|
132
|
-
//# sourceMappingURL=chunk-MBS5A6BZ.js.map
|
|
139
|
+
// Helpers for ESM
|
|
140
|
+
import { fileURLToPath } from "url";
|
|
141
|
+
import { dirname } from "path";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
startPipeline
|
|
3
|
-
} from "./chunk-2I2O6X5D.js";
|
|
4
|
-
|
|
5
|
-
// packages/cli/src/commands/start.ts
|
|
6
1
|
import { resolve } from "path";
|
|
7
2
|
import { existsSync } from "fs";
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import { startPipeline } from "@hivemind/runtime";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_CONFIG = "config/default.toml";
|
|
6
|
+
|
|
7
|
+
export async function runStartCommand(args: string[]): Promise<void> {
|
|
10
8
|
let configPath = DEFAULT_CONFIG;
|
|
9
|
+
|
|
10
|
+
// Parse args
|
|
11
11
|
for (let i = 0; i < args.length; i++) {
|
|
12
12
|
if ((args[i] === "--config" || args[i] === "-c") && args[i + 1]) {
|
|
13
13
|
configPath = args[++i];
|
|
@@ -20,15 +20,18 @@ async function runStartCommand(args) {
|
|
|
20
20
|
process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
|
|
23
24
|
const resolved = resolve(configPath);
|
|
24
25
|
if (!existsSync(resolved)) {
|
|
25
26
|
console.error(`Config not found: ${resolved}`);
|
|
26
27
|
process.exit(1);
|
|
27
28
|
}
|
|
29
|
+
|
|
28
30
|
await startPipeline(resolved);
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
|
|
33
|
+
function printHelp(): void {
|
|
34
|
+
console.log(`hivemind start — Start the Hivemind agent
|
|
32
35
|
|
|
33
36
|
Usage: hivemind start [options]
|
|
34
37
|
|
|
@@ -37,8 +40,3 @@ Options:
|
|
|
37
40
|
-h, --help Show this help
|
|
38
41
|
`);
|
|
39
42
|
}
|
|
40
|
-
|
|
41
|
-
export {
|
|
42
|
-
runStartCommand
|
|
43
|
-
};
|
|
44
|
-
//# sourceMappingURL=chunk-RNK5Q5GR.js.map
|