@sesamespace/hivemind 0.3.1 → 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
|
@@ -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 ──
|