@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,6 +1,6 @@
1
1
  {
2
2
  "name": "@sesamespace/hivemind",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Cognitive architecture for AI agents with multi-layered memory",
5
5
  "scripts": {
6
6
  "build": "pnpm -r build",
@@ -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 ──