@sesamespace/hivemind 0.3.0 → 0.4.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/package.json
CHANGED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import { existsSync, readFileSync } from "fs";
|
|
4
|
+
|
|
5
|
+
const PACKAGE_NAME = "@sesamespace/hivemind";
|
|
6
|
+
|
|
7
|
+
interface VersionInfo {
|
|
8
|
+
current: string;
|
|
9
|
+
latest: string;
|
|
10
|
+
updateAvailable: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getCurrentVersion(): string {
|
|
14
|
+
try {
|
|
15
|
+
// Check the installed package version
|
|
16
|
+
const output = execSync(`npm ls -g ${PACKAGE_NAME} --json 2>/dev/null`, { encoding: "utf-8" });
|
|
17
|
+
const parsed = JSON.parse(output);
|
|
18
|
+
const deps = parsed.dependencies?.[PACKAGE_NAME];
|
|
19
|
+
if (deps?.version) return deps.version;
|
|
20
|
+
} catch {
|
|
21
|
+
// Fallback: read from the package.json in the hivemind dir
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const hivemindHome = process.env.HIVEMIND_HOME || resolve(process.env.HOME || "~", "hivemind");
|
|
25
|
+
const pkgPath = resolve(hivemindHome, "node_modules", PACKAGE_NAME, "package.json");
|
|
26
|
+
if (existsSync(pkgPath)) {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
|
|
29
|
+
} catch {
|
|
30
|
+
// fall through
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return "unknown";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getLatestVersion(target?: string): string {
|
|
38
|
+
try {
|
|
39
|
+
const tag = target || "latest";
|
|
40
|
+
const output = execSync(`npm view ${PACKAGE_NAME}@${tag} version 2>/dev/null`, { encoding: "utf-8" });
|
|
41
|
+
return output.trim();
|
|
42
|
+
} catch {
|
|
43
|
+
throw new Error("Failed to check npm registry for latest version");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function checkVersion(target?: string): Promise<VersionInfo> {
|
|
48
|
+
const current = getCurrentVersion();
|
|
49
|
+
const latest = target || getLatestVersion();
|
|
50
|
+
return {
|
|
51
|
+
current,
|
|
52
|
+
latest,
|
|
53
|
+
updateAvailable: current !== latest && current !== "unknown",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function runUpgradeCommand(args: string[]): Promise<void> {
|
|
58
|
+
const checkOnly = args.includes("--check") || args.includes("-c");
|
|
59
|
+
const force = args.includes("--force") || args.includes("-f");
|
|
60
|
+
const dryRun = args.includes("--dry-run") || args.includes("-n");
|
|
61
|
+
|
|
62
|
+
// Target version (optional positional arg)
|
|
63
|
+
const targetVersion = args.find((a) => !a.startsWith("-"));
|
|
64
|
+
|
|
65
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
66
|
+
printHelp();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(`
|
|
71
|
+
╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗
|
|
72
|
+
╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║
|
|
73
|
+
╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝
|
|
74
|
+
Agent Upgrade
|
|
75
|
+
`);
|
|
76
|
+
|
|
77
|
+
// --- Check versions ---
|
|
78
|
+
console.log("→ Checking versions...");
|
|
79
|
+
const info = await checkVersion(targetVersion);
|
|
80
|
+
console.log(` Current: ${info.current}`);
|
|
81
|
+
console.log(` Latest: ${info.latest}`);
|
|
82
|
+
|
|
83
|
+
if (!info.updateAvailable && !force) {
|
|
84
|
+
console.log("\n ✓ Already up to date!");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (info.updateAvailable) {
|
|
89
|
+
console.log(`\n ⬆ Update available: ${info.current} → ${info.latest}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (checkOnly) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// --- Perform upgrade ---
|
|
97
|
+
const target = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
|
|
98
|
+
|
|
99
|
+
if (dryRun) {
|
|
100
|
+
console.log(`\n→ [dry-run] Would run: npm install -g ${target}`);
|
|
101
|
+
console.log("→ [dry-run] Would restart the agent service");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log(`\n→ Installing ${target}...`);
|
|
106
|
+
try {
|
|
107
|
+
execSync(`npm install -g ${target}`, { stdio: "inherit" });
|
|
108
|
+
console.log(" ✓ Package updated");
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(` ✗ npm install failed: ${(err as Error).message}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// --- Restart agent ---
|
|
115
|
+
console.log("\n→ Restarting agent...");
|
|
116
|
+
try {
|
|
117
|
+
// Try launchctl first (macOS service)
|
|
118
|
+
const plistName = "com.hivemind.agent";
|
|
119
|
+
execSync(`launchctl list ${plistName} 2>/dev/null`, { encoding: "utf-8" });
|
|
120
|
+
// Service exists — restart it
|
|
121
|
+
execSync(`launchctl kickstart -k gui/$(id -u)/${plistName}`, { stdio: "inherit" });
|
|
122
|
+
console.log(" ✓ Agent restarted via launchd");
|
|
123
|
+
} catch {
|
|
124
|
+
// No launchd service — try finding and restarting the process
|
|
125
|
+
try {
|
|
126
|
+
execSync("pkill -f 'hivemind start'", { stdio: "inherit" });
|
|
127
|
+
console.log(" ✓ Old process killed");
|
|
128
|
+
console.log(" ! Start the agent manually: hivemind start");
|
|
129
|
+
} catch {
|
|
130
|
+
console.log(" ! No running agent found — start manually: hivemind start");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --- Verify ---
|
|
135
|
+
const newVersion = getCurrentVersion();
|
|
136
|
+
console.log(`\n ✓ Upgrade complete: ${info.current} → ${newVersion}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function printHelp(): void {
|
|
140
|
+
console.log(`hivemind upgrade — Upgrade the Hivemind agent runtime
|
|
141
|
+
|
|
142
|
+
Usage: hivemind upgrade [version] [options]
|
|
143
|
+
|
|
144
|
+
Arguments:
|
|
145
|
+
version Target version (default: latest)
|
|
146
|
+
|
|
147
|
+
Options:
|
|
148
|
+
-c, --check Check for updates only (don't install)
|
|
149
|
+
-f, --force Force reinstall even if up to date
|
|
150
|
+
-n, --dry-run Show what would happen without doing it
|
|
151
|
+
-h, --help Show this help
|
|
152
|
+
|
|
153
|
+
Examples:
|
|
154
|
+
hivemind upgrade # Upgrade to latest
|
|
155
|
+
hivemind upgrade 0.3.0 # Upgrade to specific version
|
|
156
|
+
hivemind upgrade --check # Just check if update available
|
|
157
|
+
`);
|
|
158
|
+
}
|
package/packages/cli/src/main.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { runFleetCommand } from "./commands/fleet.js";
|
|
|
4
4
|
import { runStartCommand } from "./commands/start.js";
|
|
5
5
|
import { runInitCommand } from "./commands/init.js";
|
|
6
6
|
import { runServiceCommand } from "./commands/service.js";
|
|
7
|
+
import { runUpgradeCommand } from "./commands/upgrade.js";
|
|
7
8
|
|
|
8
9
|
const [command, ...args] = process.argv.slice(2);
|
|
9
10
|
|
|
@@ -36,14 +37,22 @@ switch (command) {
|
|
|
36
37
|
});
|
|
37
38
|
break;
|
|
38
39
|
|
|
40
|
+
case "upgrade":
|
|
41
|
+
runUpgradeCommand(args).catch((err) => {
|
|
42
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
break;
|
|
46
|
+
|
|
39
47
|
default:
|
|
40
|
-
console.log(`hivemind cli v0.
|
|
48
|
+
console.log(`hivemind cli v0.3.0
|
|
41
49
|
|
|
42
50
|
Usage: hivemind <command> [args]
|
|
43
51
|
|
|
44
52
|
Commands:
|
|
45
53
|
init Initialize agent from Sesame API key
|
|
46
54
|
start Start the Hivemind agent
|
|
55
|
+
upgrade Upgrade the Hivemind runtime
|
|
47
56
|
service Manage launchd services (install/uninstall/status/logs)
|
|
48
57
|
fleet Manage the worker fleet
|
|
49
58
|
`);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
1
2
|
import { Agent } from "./agent.js";
|
|
2
3
|
import type { HivemindConfig } from "./config.js";
|
|
3
4
|
import { loadConfig } from "./config.js";
|
|
4
5
|
import { SesameClient } from "./sesame.js";
|
|
6
|
+
import type { UpgradeRequest } from "./sesame.js";
|
|
5
7
|
import { MemoryClient } from "./memory-client.js";
|
|
6
8
|
|
|
7
9
|
export async function startPipeline(configPath: string): Promise<void> {
|
|
@@ -53,6 +55,40 @@ async function startSesameLoop(config: HivemindConfig, agent: Agent): Promise<vo
|
|
|
53
55
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
54
56
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
55
57
|
|
|
58
|
+
// ── Native upgrade handler (no LLM involved) ──
|
|
59
|
+
sesame.onUpgrade(async (req: UpgradeRequest) => {
|
|
60
|
+
console.log(`[hivemind] Upgrade requested: ${req.packageName}@${req.targetVersion} (by ${req.requestedBy})`);
|
|
61
|
+
sesame.updatePresence("working", { detail: `Upgrading to ${req.targetVersion}`, emoji: "⬆️" });
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const target = req.targetVersion === "latest"
|
|
65
|
+
? req.packageName
|
|
66
|
+
: `${req.packageName}@${req.targetVersion}`;
|
|
67
|
+
|
|
68
|
+
console.log(`[hivemind] Running: npm install -g ${target}`);
|
|
69
|
+
execSync(`npm install -g ${target}`, { stdio: "inherit", timeout: 120_000 });
|
|
70
|
+
console.log("[hivemind] Package updated successfully");
|
|
71
|
+
|
|
72
|
+
// Send confirmation message to the requesting human's DM
|
|
73
|
+
// (For now, log it — we'd need the human's channel ID for a proper message)
|
|
74
|
+
console.log(`[hivemind] Upgrade to ${req.targetVersion} complete. Restarting...`);
|
|
75
|
+
|
|
76
|
+
sesame.updatePresence("working", { detail: "Restarting after upgrade", emoji: "🔄" });
|
|
77
|
+
|
|
78
|
+
// Graceful restart — try launchd kickstart, fall back to process.exit
|
|
79
|
+
try {
|
|
80
|
+
execSync("launchctl kickstart -k gui/$(id -u)/com.hivemind.agent", { timeout: 10_000 });
|
|
81
|
+
} catch {
|
|
82
|
+
// If launchd isn't managing us, just exit (the wrapper script will restart)
|
|
83
|
+
console.log("[hivemind] Exiting for restart...");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(`[hivemind] Upgrade failed: ${(err as Error).message}`);
|
|
88
|
+
sesame.updatePresence("online", { detail: "Upgrade failed", emoji: "❌" });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
56
92
|
sesame.onMessage(async (msg) => {
|
|
57
93
|
if (shuttingDown) return;
|
|
58
94
|
console.log(`[sesame] ${msg.author.handle} (${msg.channelKind}): ${msg.content}`);
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { SesameClient as SesameSDK } from "@sesamespace/sdk";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { resolve, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
2
6
|
import type { SesameConfig } from "./config.js";
|
|
3
7
|
|
|
8
|
+
// Read version at module load time
|
|
9
|
+
let RUNTIME_VERSION = "unknown";
|
|
10
|
+
try {
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
|
|
13
|
+
RUNTIME_VERSION = pkg.version ?? "unknown";
|
|
14
|
+
} catch {
|
|
15
|
+
// give up
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
export interface SesameMessage {
|
|
5
19
|
id: string;
|
|
6
20
|
channelId: string;
|
|
@@ -14,6 +28,14 @@ export interface SesameMessage {
|
|
|
14
28
|
}
|
|
15
29
|
|
|
16
30
|
type MessageHandler = (message: SesameMessage) => void | Promise<void>;
|
|
31
|
+
type UpgradeHandler = (event: UpgradeRequest) => void | Promise<void>;
|
|
32
|
+
|
|
33
|
+
export interface UpgradeRequest {
|
|
34
|
+
targetVersion: string;
|
|
35
|
+
packageName: string;
|
|
36
|
+
requestedBy: string;
|
|
37
|
+
requestId: string;
|
|
38
|
+
}
|
|
17
39
|
|
|
18
40
|
interface ChannelInfo {
|
|
19
41
|
kind: "dm" | "group" | "topic";
|
|
@@ -24,6 +46,7 @@ export class SesameClient {
|
|
|
24
46
|
private config: SesameConfig;
|
|
25
47
|
private sdk: SesameSDK;
|
|
26
48
|
private messageHandler: MessageHandler | null = null;
|
|
49
|
+
private upgradeHandler: UpgradeHandler | null = null;
|
|
27
50
|
private agentId: string | null = null;
|
|
28
51
|
private channels: Map<string, ChannelInfo> = new Map();
|
|
29
52
|
private typingIntervals: Map<string, ReturnType<typeof setInterval>> = new Map();
|
|
@@ -41,6 +64,10 @@ export class SesameClient {
|
|
|
41
64
|
this.messageHandler = handler;
|
|
42
65
|
}
|
|
43
66
|
|
|
67
|
+
onUpgrade(handler: UpgradeHandler): void {
|
|
68
|
+
this.upgradeHandler = handler;
|
|
69
|
+
}
|
|
70
|
+
|
|
44
71
|
async connect(): Promise<void> {
|
|
45
72
|
const manifest = await this.sdk.getManifest();
|
|
46
73
|
this.agentId = manifest.agent.id;
|
|
@@ -56,6 +83,24 @@ export class SesameClient {
|
|
|
56
83
|
// Set presence to online
|
|
57
84
|
this.updatePresence("online", { emoji: "🟢" });
|
|
58
85
|
|
|
86
|
+
// Listen for upgrade.request control events
|
|
87
|
+
this.sdk.on("upgrade.request", (event: any) => {
|
|
88
|
+
console.log(`[sesame] Upgrade request received: ${event.packageName}@${event.targetVersion}`);
|
|
89
|
+
if (this.upgradeHandler) {
|
|
90
|
+
this.upgradeHandler({
|
|
91
|
+
targetVersion: event.targetVersion,
|
|
92
|
+
packageName: event.packageName,
|
|
93
|
+
requestedBy: event.requestedBy,
|
|
94
|
+
requestId: event.requestId,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Listen for generic control events
|
|
100
|
+
this.sdk.on("control", (event: any) => {
|
|
101
|
+
console.log(`[sesame] Control event: ${event.action}`, event.payload);
|
|
102
|
+
});
|
|
103
|
+
|
|
59
104
|
// Listen for message events
|
|
60
105
|
this.sdk.on("message", (event: any) => {
|
|
61
106
|
const msg = event.data || event.message || event;
|
|
@@ -83,6 +128,13 @@ export class SesameClient {
|
|
|
83
128
|
|
|
84
129
|
await this.sdk.connect();
|
|
85
130
|
console.log("[sesame] WebSocket connected");
|
|
131
|
+
|
|
132
|
+
// Report runtime metadata
|
|
133
|
+
const ws = (this.sdk as any).ws;
|
|
134
|
+
if (ws?.readyState === 1) {
|
|
135
|
+
ws.send(JSON.stringify({ type: "meta", runtime: "hivemind", version: RUNTIME_VERSION }));
|
|
136
|
+
console.log(`[sesame] Reported version: hivemind@${RUNTIME_VERSION}`);
|
|
137
|
+
}
|
|
86
138
|
}
|
|
87
139
|
|
|
88
140
|
// ── Typing Indicators ──
|