@sesamespace/hivemind 0.12.5 → 0.12.7

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.
@@ -3049,7 +3049,7 @@ var SesameClient = class {
3049
3049
  * Connect to the real-time WebSocket gateway.
3050
3050
  */
3051
3051
  connect() {
3052
- return new Promise((resolve21, reject) => {
3052
+ return new Promise((resolve22, reject) => {
3053
3053
  try {
3054
3054
  this.ws = new WebSocket(`${this.config.wsUrl}/v1/connect`);
3055
3055
  this.ws.on("open", () => {
@@ -3063,7 +3063,7 @@ var SesameClient = class {
3063
3063
  this.authenticated = true;
3064
3064
  this.startHeartbeat(event.heartbeatIntervalMs ?? 3e4);
3065
3065
  this.sendReplay();
3066
- resolve21();
3066
+ resolve22();
3067
3067
  return;
3068
3068
  }
3069
3069
  if (event.type === "pong")
@@ -3249,6 +3249,10 @@ var SesameClient2 = class {
3249
3249
  agentId = null;
3250
3250
  channels = /* @__PURE__ */ new Map();
3251
3251
  typingIntervals = /* @__PURE__ */ new Map();
3252
+ /** Messages held briefly to allow streaming edits to replace initial fragments */
3253
+ pendingMessages = /* @__PURE__ */ new Map();
3254
+ /** How long to wait for streaming edits before delivering (ms) */
3255
+ MESSAGE_HOLD_MS = 3e3;
3252
3256
  constructor(config) {
3253
3257
  this.config = config;
3254
3258
  this.sdk = new SesameClient({
@@ -3305,8 +3309,9 @@ var SesameClient2 = class {
3305
3309
  if (senderId === this.agentId) return;
3306
3310
  if (!this.messageHandler || !msg.content) return;
3307
3311
  const channelInfo = this.channels.get(msg.channelId);
3308
- this.messageHandler({
3309
- id: msg.id || "unknown",
3312
+ const messageId = msg.id || "unknown";
3313
+ const sesameMsg = {
3314
+ id: messageId,
3310
3315
  channelId: msg.channelId || "unknown",
3311
3316
  channelKind: channelInfo?.kind || "dm",
3312
3317
  content: msg.content,
@@ -3315,7 +3320,52 @@ var SesameClient2 = class {
3315
3320
  handle: msg.senderHandle || msg.metadata?.senderHandle || "unknown"
3316
3321
  },
3317
3322
  timestamp: msg.createdAt || (/* @__PURE__ */ new Date()).toISOString()
3318
- });
3323
+ };
3324
+ const existing = this.pendingMessages.get(messageId);
3325
+ if (existing && !existing.delivered) {
3326
+ existing.message = sesameMsg;
3327
+ return;
3328
+ }
3329
+ const pending = {
3330
+ message: sesameMsg,
3331
+ delivered: false,
3332
+ timer: setTimeout(() => {
3333
+ const p = this.pendingMessages.get(messageId);
3334
+ if (p && !p.delivered && this.messageHandler) {
3335
+ p.delivered = true;
3336
+ this.messageHandler(p.message);
3337
+ }
3338
+ this.pendingMessages.delete(messageId);
3339
+ }, this.MESSAGE_HOLD_MS)
3340
+ };
3341
+ this.pendingMessages.set(messageId, pending);
3342
+ });
3343
+ this.sdk.on("message.edited", (event) => {
3344
+ const msg = event.data || event.message || event;
3345
+ const senderId = msg.senderId || msg.sender?.id;
3346
+ if (senderId === this.agentId) return;
3347
+ if (event.streaming) return;
3348
+ const messageId = msg.id || "unknown";
3349
+ const channelInfo = this.channels.get(msg.channelId);
3350
+ const updatedMsg = {
3351
+ id: messageId,
3352
+ channelId: msg.channelId || "unknown",
3353
+ channelKind: channelInfo?.kind || "dm",
3354
+ content: msg.content,
3355
+ author: {
3356
+ id: senderId || "unknown",
3357
+ handle: msg.senderHandle || msg.metadata?.senderHandle || "unknown"
3358
+ },
3359
+ timestamp: msg.updatedAt || msg.createdAt || (/* @__PURE__ */ new Date()).toISOString()
3360
+ };
3361
+ const pending = this.pendingMessages.get(messageId);
3362
+ if (pending && !pending.delivered) {
3363
+ pending.message = updatedMsg;
3364
+ return;
3365
+ }
3366
+ if (this.messageHandler && msg.content) {
3367
+ this.messageHandler(updatedMsg);
3368
+ }
3319
3369
  });
3320
3370
  await this.sdk.connect();
3321
3371
  console.log("[sesame] WebSocket connected");
@@ -4225,12 +4275,12 @@ var LogWatcher = class extends BackgroundProcess {
4225
4275
  }
4226
4276
  savePositions() {
4227
4277
  try {
4228
- const { mkdirSync: mkdirSync16, writeFileSync: writeFileSync10 } = __require("fs");
4229
- const { dirname: dirname9 } = __require("path");
4230
- const dir = dirname9(this.positionsFile);
4231
- if (!existsSync7(dir)) mkdirSync16(dir, { recursive: true });
4278
+ const { mkdirSync: mkdirSync17, writeFileSync: writeFileSync11 } = __require("fs");
4279
+ const { dirname: dirname10 } = __require("path");
4280
+ const dir = dirname10(this.positionsFile);
4281
+ if (!existsSync7(dir)) mkdirSync17(dir, { recursive: true });
4232
4282
  const data = Object.fromEntries(this.tailPositions);
4233
- writeFileSync10(this.positionsFile, JSON.stringify(data));
4283
+ writeFileSync11(this.positionsFile, JSON.stringify(data));
4234
4284
  } catch (err) {
4235
4285
  log2.warn("failed to save tail positions", {
4236
4286
  error: err.message
@@ -4750,10 +4800,10 @@ function parseQuery(url) {
4750
4800
  return params;
4751
4801
  }
4752
4802
  function readBody(req) {
4753
- return new Promise((resolve21, reject) => {
4803
+ return new Promise((resolve22, reject) => {
4754
4804
  const chunks = [];
4755
4805
  req.on("data", (chunk) => chunks.push(chunk));
4756
- req.on("end", () => resolve21(Buffer.concat(chunks).toString()));
4806
+ req.on("end", () => resolve22(Buffer.concat(chunks).toString()));
4757
4807
  req.on("error", reject);
4758
4808
  });
4759
4809
  }
@@ -5178,13 +5228,13 @@ function registerFileTools(registry, workspaceDir) {
5178
5228
  required: []
5179
5229
  },
5180
5230
  async (params) => {
5181
- const { readdirSync: readdirSync5, statSync: statSync5 } = await import("fs");
5231
+ const { readdirSync: readdirSync6, statSync: statSync5 } = await import("fs");
5182
5232
  const dirPath = params.path ? resolvePath(workspaceDir, params.path) : workspaceDir;
5183
5233
  if (!existsSync10(dirPath)) {
5184
5234
  return `Error: Directory not found: ${dirPath}`;
5185
5235
  }
5186
5236
  try {
5187
- const entries = readdirSync5(dirPath);
5237
+ const entries = readdirSync6(dirPath);
5188
5238
  const results = [];
5189
5239
  for (const entry of entries) {
5190
5240
  if (entry.startsWith(".")) continue;
@@ -7898,7 +7948,7 @@ function registerCodingAgentTools(registry, workspaceDir, contextBridge) {
7898
7948
  contextBridge.on("error-encountered", errorHandler);
7899
7949
  }
7900
7950
  try {
7901
- const output = await new Promise((resolve21, reject) => {
7951
+ const output = await new Promise((resolve22, reject) => {
7902
7952
  const child = exec2(command, {
7903
7953
  cwd,
7904
7954
  timeout: timeoutSeconds * 1e3,
@@ -7915,7 +7965,7 @@ function registerCodingAgentTools(registry, workspaceDir, contextBridge) {
7915
7965
  error.stderr = stderr;
7916
7966
  reject(error);
7917
7967
  } else {
7918
- resolve21(stdout);
7968
+ resolve22(stdout);
7919
7969
  }
7920
7970
  });
7921
7971
  child.stdin?.end();
@@ -7966,6 +8016,9 @@ ${output || err.message}`;
7966
8016
  if (contextBridge && errorHandler) {
7967
8017
  contextBridge.off("error-encountered", errorHandler);
7968
8018
  }
8019
+ if (contextBridge) {
8020
+ contextBridge.cleanupContextFile();
8021
+ }
7969
8022
  }
7970
8023
  }
7971
8024
  );
@@ -8633,12 +8686,12 @@ Path: ${skillDir}`;
8633
8686
  }
8634
8687
 
8635
8688
  // packages/runtime/src/pipeline.ts
8636
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3 } from "fs";
8637
- import { resolve as resolve20, dirname as dirname8 } from "path";
8689
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, unlinkSync as unlinkSync4 } from "fs";
8690
+ import { resolve as resolve21, dirname as dirname9 } from "path";
8638
8691
  import { fileURLToPath as fileURLToPath3 } from "url";
8639
8692
 
8640
8693
  // packages/runtime/src/tools/context-bridge.ts
8641
- import { writeFileSync as writeFileSync8, readFileSync as readFileSync15, statSync as statSync4, existsSync as existsSync20, mkdirSync as mkdirSync15, openSync, readSync, closeSync } from "fs";
8694
+ import { writeFileSync as writeFileSync8, readFileSync as readFileSync15, statSync as statSync4, existsSync as existsSync20, mkdirSync as mkdirSync15, openSync, readSync, closeSync, readdirSync as readdirSync5, unlinkSync as unlinkSync3 } from "fs";
8642
8695
  import { createHash as createHash2 } from "crypto";
8643
8696
  import { join as join8 } from "path";
8644
8697
  import { homedir } from "os";
@@ -8649,16 +8702,20 @@ var ClaudeContextBridge = class extends EventEmitter2 {
8649
8702
  logger;
8650
8703
  sessionLogPath;
8651
8704
  contextFilePath;
8705
+ sessionArchiveDir;
8652
8706
  watchInterval = null;
8653
8707
  lastLogSize = 0;
8654
8708
  seenPatterns = /* @__PURE__ */ new Set();
8709
+ currentSessionId;
8655
8710
  constructor(config) {
8656
8711
  super();
8657
8712
  this.workspaceDir = config.workspaceDir;
8658
8713
  this.memoryClient = config.memoryClient;
8659
8714
  this.logger = config.logger;
8660
8715
  this.sessionLogPath = join8(homedir(), ".claude", "session.log");
8661
- this.contextFilePath = join8(this.workspaceDir, "CLAUDE_CONTEXT.md");
8716
+ this.sessionArchiveDir = join8(homedir(), ".claude", "sessions");
8717
+ this.contextFilePath = join8(this.workspaceDir, ".claude-context-current.md");
8718
+ this.currentSessionId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8662
8719
  }
8663
8720
  /**
8664
8721
  * Initialize the context bridge
@@ -8668,10 +8725,49 @@ var ClaudeContextBridge = class extends EventEmitter2 {
8668
8725
  if (!existsSync20(claudeDir)) {
8669
8726
  mkdirSync15(claudeDir, { recursive: true });
8670
8727
  }
8728
+ if (!existsSync20(this.sessionArchiveDir)) {
8729
+ mkdirSync15(this.sessionArchiveDir, { recursive: true });
8730
+ }
8731
+ await this.archiveSessionLog();
8671
8732
  await this.setupClaudeSettings();
8672
8733
  this.startLogMonitoring();
8673
8734
  this.logger.info("Claude context bridge initialized");
8674
8735
  }
8736
+ /**
8737
+ * Archive previous session log if it exists
8738
+ */
8739
+ async archiveSessionLog() {
8740
+ if (existsSync20(this.sessionLogPath)) {
8741
+ const stats = statSync4(this.sessionLogPath);
8742
+ if (stats.size > 0) {
8743
+ const archivePath = join8(this.sessionArchiveDir, `${this.currentSessionId}.log`);
8744
+ const content = readFileSync15(this.sessionLogPath, "utf-8");
8745
+ writeFileSync8(archivePath, content);
8746
+ writeFileSync8(this.sessionLogPath, "");
8747
+ this.logger.info("Archived previous session log", { path: archivePath });
8748
+ this.cleanupOldArchives();
8749
+ }
8750
+ }
8751
+ }
8752
+ /**
8753
+ * Clean up old session archives, keeping only the most recent ones
8754
+ */
8755
+ cleanupOldArchives() {
8756
+ try {
8757
+ const files = readdirSync5(this.sessionArchiveDir).filter((f) => f.endsWith(".log")).map((f) => ({
8758
+ name: f,
8759
+ path: join8(this.sessionArchiveDir, f),
8760
+ mtime: statSync4(join8(this.sessionArchiveDir, f)).mtime
8761
+ })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
8762
+ const toDelete = files.slice(10);
8763
+ for (const file of toDelete) {
8764
+ unlinkSync3(file.path);
8765
+ this.logger.debug("Deleted old session archive", { file: file.name });
8766
+ }
8767
+ } catch (err) {
8768
+ this.logger.warn("Failed to cleanup old archives", { error: String(err) });
8769
+ }
8770
+ }
8675
8771
  /**
8676
8772
  * Configure Claude Code to report insights via workspace CLAUDE.md
8677
8773
  */
@@ -8686,7 +8782,7 @@ When working on tasks, please report significant findings by writing to the sess
8686
8782
  - When you find reusable solutions: echo "PATTERN: [approach]" >> ~/.claude/session.log
8687
8783
  - When you encounter errors: echo "ERROR: [error details]" >> ~/.claude/session.log
8688
8784
 
8689
- Always check CLAUDE_CONTEXT.md in the workspace for task context and requirements.`;
8785
+ Always check .claude-context-current.md in the workspace for task context and requirements.`;
8690
8786
  const claudeMdPath = join8(this.workspaceDir, "CLAUDE.md");
8691
8787
  writeFileSync8(claudeMdPath, instructions);
8692
8788
  this.logger.info("Claude workspace CLAUDE.md configured for context bridge");
@@ -8940,6 +9036,15 @@ ${memories.join("\n\n")}
8940
9036
  };
8941
9037
  }
8942
9038
  }
9039
+ /**
9040
+ * Clean up just the context file (for use after a session)
9041
+ */
9042
+ cleanupContextFile() {
9043
+ if (existsSync20(this.contextFilePath)) {
9044
+ unlinkSync3(this.contextFilePath);
9045
+ this.logger.info("Cleaned up context file");
9046
+ }
9047
+ }
8943
9048
  /**
8944
9049
  * Clean up resources
8945
9050
  */
@@ -8950,6 +9055,7 @@ ${memories.join("\n\n")}
8950
9055
  }
8951
9056
  this.seenPatterns.clear();
8952
9057
  this.removeAllListeners();
9058
+ this.cleanupContextFile();
8953
9059
  }
8954
9060
  };
8955
9061
  async function createContextBridge(config) {
@@ -8958,11 +9064,609 @@ async function createContextBridge(config) {
8958
9064
  return bridge;
8959
9065
  }
8960
9066
 
9067
+ // packages/runtime/src/sesame-sync.ts
9068
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync9, existsSync as existsSync21, mkdirSync as mkdirSync16 } from "fs";
9069
+ import { resolve as resolve20, dirname as dirname8 } from "path";
9070
+
9071
+ // packages/runtime/src/sesame-api.ts
9072
+ var SesameAPI = class {
9073
+ baseUrl;
9074
+ apiKey;
9075
+ rateLimitRemaining = 120;
9076
+ rateLimitResetAt = 0;
9077
+ constructor(config) {
9078
+ this.baseUrl = config.api_url.endsWith("/api/v1") ? config.api_url : `${config.api_url}/api/v1`;
9079
+ this.apiKey = config.api_key;
9080
+ }
9081
+ // ── Internal helpers ──
9082
+ async request(method, path, body) {
9083
+ if (this.rateLimitRemaining <= 5 && Date.now() < this.rateLimitResetAt) {
9084
+ const waitMs = this.rateLimitResetAt - Date.now();
9085
+ console.warn(`[sesame-api] Rate limit low (${this.rateLimitRemaining}), waiting ${waitMs}ms`);
9086
+ await new Promise((r) => setTimeout(r, Math.min(waitMs, 5e3)));
9087
+ }
9088
+ const url = `${this.baseUrl}${path}`;
9089
+ const headers = {
9090
+ Authorization: `Bearer ${this.apiKey}`,
9091
+ "Content-Type": "application/json"
9092
+ };
9093
+ const options = { method, headers };
9094
+ if (body && method !== "GET") {
9095
+ options.body = JSON.stringify(body);
9096
+ }
9097
+ try {
9098
+ const response = await fetch(url, options);
9099
+ const remaining = response.headers.get("x-ratelimit-remaining");
9100
+ const reset = response.headers.get("x-ratelimit-reset");
9101
+ if (remaining) this.rateLimitRemaining = parseInt(remaining, 10);
9102
+ if (reset) this.rateLimitResetAt = parseInt(reset, 10) * 1e3;
9103
+ if (!response.ok) {
9104
+ const errorBody = await response.text();
9105
+ let parsed;
9106
+ try {
9107
+ parsed = JSON.parse(errorBody);
9108
+ } catch {
9109
+ parsed = { error: errorBody };
9110
+ }
9111
+ const err = new Error(`Sesame API ${method} ${path}: ${response.status} ${parsed.error || errorBody}`);
9112
+ err.status = response.status;
9113
+ err.details = parsed;
9114
+ throw err;
9115
+ }
9116
+ const data = await response.json();
9117
+ return data.data ?? data;
9118
+ } catch (err) {
9119
+ if (err.status) throw err;
9120
+ console.error(`[sesame-api] Network error on ${method} ${path}:`, err.message);
9121
+ throw err;
9122
+ }
9123
+ }
9124
+ // ── Wake ──
9125
+ async wake(agentId) {
9126
+ return this.request("GET", `/agents/${agentId}/wake`);
9127
+ }
9128
+ // ── Agent State ──
9129
+ async getState(agentId, namespace = "default") {
9130
+ try {
9131
+ return await this.request("GET", `/agents/${agentId}/state?namespace=${namespace}`);
9132
+ } catch (err) {
9133
+ if (err.status === 404) return null;
9134
+ throw err;
9135
+ }
9136
+ }
9137
+ async setState(agentId, state, namespace = "default", ttlSeconds = 86400) {
9138
+ return this.request("PUT", `/agents/${agentId}/state`, {
9139
+ namespace,
9140
+ state,
9141
+ ttlSeconds
9142
+ });
9143
+ }
9144
+ // ── Agent Memory ──
9145
+ async getMemory(agentId, category, limit = 50) {
9146
+ const params = new URLSearchParams({ limit: String(limit) });
9147
+ if (category) params.set("category", category);
9148
+ return this.request("GET", `/agents/${agentId}/memory?${params}`);
9149
+ }
9150
+ async setMemory(agentId, category, key, content, metadata) {
9151
+ return this.request("PUT", `/agents/${agentId}/memory`, {
9152
+ category,
9153
+ key,
9154
+ content,
9155
+ metadata
9156
+ });
9157
+ }
9158
+ async deleteMemory(agentId, memoryId) {
9159
+ await this.request("DELETE", `/agents/${agentId}/memory/${memoryId}`);
9160
+ }
9161
+ // ── Agent Focus ──
9162
+ async setFocus(agentId, taskId) {
9163
+ await this.request("PUT", `/agents/${agentId}/focus`, { taskId });
9164
+ }
9165
+ async clearFocus(agentId) {
9166
+ await this.request("DELETE", `/agents/${agentId}/focus`);
9167
+ }
9168
+ // ── Tasks ──
9169
+ async createTask(task) {
9170
+ return this.request("POST", "/tasks", task);
9171
+ }
9172
+ async getTask(taskId) {
9173
+ return this.request("GET", `/tasks/${taskId}`);
9174
+ }
9175
+ async updateTask(taskId, updates) {
9176
+ return this.request("PATCH", `/tasks/${taskId}`, updates);
9177
+ }
9178
+ async getMyTasks(status) {
9179
+ const params = status ? `?status=${status}` : "";
9180
+ return this.request("GET", `/tasks/mine${params}`);
9181
+ }
9182
+ async getNextTask() {
9183
+ try {
9184
+ return await this.request("GET", "/tasks/next");
9185
+ } catch (err) {
9186
+ if (err.status === 404) return null;
9187
+ throw err;
9188
+ }
9189
+ }
9190
+ async logActivity(taskId, type, message, metadata) {
9191
+ return this.request("POST", `/tasks/${taskId}/activity`, {
9192
+ type,
9193
+ message,
9194
+ metadata
9195
+ });
9196
+ }
9197
+ async getTaskContext(taskId) {
9198
+ try {
9199
+ return await this.request("GET", `/tasks/${taskId}/context`);
9200
+ } catch (err) {
9201
+ if (err.status === 404) return null;
9202
+ throw err;
9203
+ }
9204
+ }
9205
+ async updateTaskContext(taskId, context) {
9206
+ return this.request("PATCH", `/tasks/${taskId}/context`, context);
9207
+ }
9208
+ async appendTaskContext(taskId, field, values) {
9209
+ const current = await this.getTaskContext(taskId);
9210
+ const existing = current?.[field] ?? [];
9211
+ const merged = [...existing, ...values.filter((v) => !existing.includes(v))];
9212
+ return this.request("PATCH", `/tasks/${taskId}/context`, {
9213
+ [field]: merged
9214
+ });
9215
+ }
9216
+ async searchTasks(query, scope = "all") {
9217
+ return this.request("GET", `/tasks/search?q=${encodeURIComponent(query)}&scope=${scope}`);
9218
+ }
9219
+ async handoffTask(taskId, toHandle, summary, instructions, reason, state) {
9220
+ return this.request("POST", `/tasks/${taskId}/handoff`, {
9221
+ toHandle,
9222
+ reason: reason || "Handoff",
9223
+ summary,
9224
+ instructions,
9225
+ state
9226
+ });
9227
+ }
9228
+ // ── Projects ──
9229
+ async createProject(project) {
9230
+ return this.request("POST", "/projects", project);
9231
+ }
9232
+ async getProject(projectId) {
9233
+ return this.request("GET", `/projects/${projectId}`);
9234
+ }
9235
+ async getProjectContext(projectId) {
9236
+ try {
9237
+ return await this.request("GET", `/projects/${projectId}/context`);
9238
+ } catch (err) {
9239
+ if (err.status === 404) return null;
9240
+ throw err;
9241
+ }
9242
+ }
9243
+ async updateProjectContext(projectId, context) {
9244
+ return this.request("PUT", `/projects/${projectId}/context`, context);
9245
+ }
9246
+ // ── Schedule ──
9247
+ async syncSchedule(events) {
9248
+ return this.request("PUT", "/schedule/sync", { events });
9249
+ }
9250
+ async recordOccurrence(eventId, scheduledAt, status, result) {
9251
+ return this.request("POST", `/schedule/${eventId}/occurrences`, {
9252
+ scheduledAt,
9253
+ status,
9254
+ result
9255
+ });
9256
+ }
9257
+ // ── Utility ──
9258
+ getRateLimitRemaining() {
9259
+ return this.rateLimitRemaining;
9260
+ }
9261
+ getBaseUrl() {
9262
+ return this.baseUrl;
9263
+ }
9264
+ getApiKey() {
9265
+ return this.apiKey;
9266
+ }
9267
+ };
9268
+
9269
+ // packages/runtime/src/sesame-sync.ts
9270
+ function defaultSyncState() {
9271
+ return {
9272
+ lastStatePush: null,
9273
+ lastL3Sync: null,
9274
+ syncedL3Keys: [],
9275
+ lastMemoryMdHash: null,
9276
+ lastWake: null
9277
+ };
9278
+ }
9279
+ function simpleHash(str) {
9280
+ let hash = 0;
9281
+ for (let i = 0; i < str.length; i++) {
9282
+ const char = str.charCodeAt(i);
9283
+ hash = (hash << 5) - hash + char;
9284
+ hash = hash & hash;
9285
+ }
9286
+ return hash.toString(36);
9287
+ }
9288
+ var SesameSync = class {
9289
+ api;
9290
+ agentId;
9291
+ workspaceDir;
9292
+ dataDir;
9293
+ syncState;
9294
+ syncStatePath;
9295
+ syncInterval = null;
9296
+ constructor(config, agentId, workspaceDir, dataDir) {
9297
+ this.api = new SesameAPI(config);
9298
+ this.agentId = agentId;
9299
+ this.workspaceDir = workspaceDir;
9300
+ this.dataDir = dataDir;
9301
+ this.syncStatePath = resolve20(dataDir, "sesame-sync-state.json");
9302
+ this.syncState = this.loadSyncState();
9303
+ }
9304
+ // ── State Persistence ──
9305
+ loadSyncState() {
9306
+ try {
9307
+ if (existsSync21(this.syncStatePath)) {
9308
+ return JSON.parse(readFileSync16(this.syncStatePath, "utf-8"));
9309
+ }
9310
+ } catch (err) {
9311
+ console.warn("[sesame-sync] Failed to load sync state:", err.message);
9312
+ }
9313
+ return defaultSyncState();
9314
+ }
9315
+ saveSyncState() {
9316
+ try {
9317
+ const dir = dirname8(this.syncStatePath);
9318
+ if (!existsSync21(dir)) mkdirSync16(dir, { recursive: true });
9319
+ writeFileSync9(this.syncStatePath, JSON.stringify(this.syncState, null, 2));
9320
+ } catch (err) {
9321
+ console.warn("[sesame-sync] Failed to save sync state:", err.message);
9322
+ }
9323
+ }
9324
+ // ── Push: MEMORY.md -> Agent State ──
9325
+ /**
9326
+ * Read MEMORY.md from workspace and push to Sesame agent state.
9327
+ * Only pushes if content has changed since last push.
9328
+ */
9329
+ async pushState() {
9330
+ const memoryMdPath = resolve20(this.workspaceDir, "MEMORY.md");
9331
+ if (!existsSync21(memoryMdPath)) {
9332
+ console.log("[sesame-sync] No MEMORY.md found, skipping state push");
9333
+ return false;
9334
+ }
9335
+ const content = readFileSync16(memoryMdPath, "utf-8");
9336
+ const hash = simpleHash(content);
9337
+ if (hash === this.syncState.lastMemoryMdHash) {
9338
+ return false;
9339
+ }
9340
+ try {
9341
+ await this.api.setState(this.agentId, {
9342
+ memoryMd: content,
9343
+ memoryMdHash: hash,
9344
+ lastSync: (/* @__PURE__ */ new Date()).toISOString(),
9345
+ source: "hivemind-sync"
9346
+ }, "memory", 172800);
9347
+ this.syncState.lastMemoryMdHash = hash;
9348
+ this.syncState.lastStatePush = (/* @__PURE__ */ new Date()).toISOString();
9349
+ this.saveSyncState();
9350
+ console.log("[sesame-sync] Pushed MEMORY.md to agent state");
9351
+ return true;
9352
+ } catch (err) {
9353
+ console.error("[sesame-sync] Failed to push state:", err.message);
9354
+ return false;
9355
+ }
9356
+ }
9357
+ // ── Push: Working Context -> Agent State ──
9358
+ /**
9359
+ * Push current working context (focus, active work, etc.) to agent state.
9360
+ * This is the "default" namespace for quick session recovery.
9361
+ */
9362
+ async pushWorkingContext(context) {
9363
+ try {
9364
+ await this.api.setState(this.agentId, {
9365
+ ...context,
9366
+ lastSync: (/* @__PURE__ */ new Date()).toISOString(),
9367
+ source: "hivemind-sync"
9368
+ }, "default", 86400);
9369
+ console.log("[sesame-sync] Pushed working context to agent state");
9370
+ return true;
9371
+ } catch (err) {
9372
+ console.error("[sesame-sync] Failed to push working context:", err.message);
9373
+ return false;
9374
+ }
9375
+ }
9376
+ // ── L3 Classification ──
9377
+ /**
9378
+ * Classify an L3 entry into a Sesame memory category based on content keywords.
9379
+ * Categories: people, preferences, projects, context-recovery, lessons (default)
9380
+ */
9381
+ classifyL3Entry(content) {
9382
+ const lower = content.toLowerCase();
9383
+ const peoplePatterns = [
9384
+ /\b(ryan|bailey|caitlin|human|user|agent)\b/,
9385
+ /\bwork(ing|ed|s)?\s+(with|together|alongside)\b/,
9386
+ /\b(collaborat|communicat|partner|teammate)/,
9387
+ /\b(prefers?|expects?|wants?)\s+(me|us|the agent)\b/
9388
+ ];
9389
+ if (peoplePatterns.some((p) => p.test(lower))) return "people";
9390
+ const prefPatterns = [
9391
+ /\b(i prefer|always use|never use|best practice|my workflow)\b/,
9392
+ /\b(default to|opt for|choose|convention)\b/,
9393
+ /\b(style|format|approach|pattern)\s+(is|should be|works best)\b/
9394
+ ];
9395
+ if (prefPatterns.some((p) => p.test(lower))) return "preferences";
9396
+ const projectPatterns = [
9397
+ /\b(hivemind|sesame|openclaw)\b/,
9398
+ /\b(repo(sitory)?|codebase|project|package)\b/,
9399
+ /\bgithub\.com\b/,
9400
+ /\b(src\/|packages\/|\.ts|\.js|\.py)\b/
9401
+ ];
9402
+ if (projectPatterns.some((p) => p.test(lower))) return "projects";
9403
+ const recoveryPatterns = [
9404
+ /\b(recover|restart|compaction|cold start|wake)\b/,
9405
+ /\b(rebuild|restore|flush|checkpoint)\b/,
9406
+ /\b(memory\.md|agent state|sync state)\b/
9407
+ ];
9408
+ if (recoveryPatterns.some((p) => p.test(lower))) return "context-recovery";
9409
+ return "lessons";
9410
+ }
9411
+ // ── Push: L3 Knowledge -> Agent Memory ──
9412
+ /**
9413
+ * Sync L3 promoted knowledge to Sesame agent memory.
9414
+ * Classifies entries into categories: people, preferences, projects, context-recovery, lessons.
9415
+ * Only pushes entries that haven't been synced yet.
9416
+ *
9417
+ * @param memoryDaemonUrl - URL of the local memory daemon
9418
+ */
9419
+ async syncL3ToMemory(memoryDaemonUrl) {
9420
+ let l3Entries;
9421
+ try {
9422
+ const response = await fetch(`${memoryDaemonUrl}/promotion/l3?context=global`);
9423
+ if (!response.ok) {
9424
+ console.warn("[sesame-sync] Failed to fetch L3 knowledge:", response.status);
9425
+ return 0;
9426
+ }
9427
+ const data = await response.json();
9428
+ l3Entries = data.entries || data || [];
9429
+ } catch (err) {
9430
+ console.error("[sesame-sync] Failed to fetch L3 knowledge:", err.message);
9431
+ return 0;
9432
+ }
9433
+ if (!Array.isArray(l3Entries) || l3Entries.length === 0) return 0;
9434
+ let synced = 0;
9435
+ const syncedKeys = new Set(this.syncState.syncedL3Keys);
9436
+ for (const entry of l3Entries) {
9437
+ const key = entry.key || `l3-${simpleHash(entry.content)}`;
9438
+ if (syncedKeys.has(key)) continue;
9439
+ try {
9440
+ const category = this.classifyL3Entry(entry.content);
9441
+ await this.api.setMemory(
9442
+ this.agentId,
9443
+ category,
9444
+ key,
9445
+ entry.content,
9446
+ {
9447
+ source: "hivemind-l3-promotion",
9448
+ l3Score: entry.score,
9449
+ l3Context: entry.context || "global",
9450
+ l3Category: category,
9451
+ syncedAt: (/* @__PURE__ */ new Date()).toISOString()
9452
+ }
9453
+ );
9454
+ syncedKeys.add(key);
9455
+ synced++;
9456
+ } catch (err) {
9457
+ console.warn(`[sesame-sync] Failed to sync L3 entry "${key}":`, err.message);
9458
+ }
9459
+ }
9460
+ if (synced > 0) {
9461
+ this.syncState.syncedL3Keys = Array.from(syncedKeys);
9462
+ this.syncState.lastL3Sync = (/* @__PURE__ */ new Date()).toISOString();
9463
+ this.saveSyncState();
9464
+ console.log(`[sesame-sync] Synced ${synced} L3 entries to Sesame agent memory`);
9465
+ }
9466
+ return synced;
9467
+ }
9468
+ // ── Pull: Wake -> Rebuild Context ──
9469
+ /**
9470
+ * Call the wake endpoint and return structured data for context rebuilding.
9471
+ * This is the primary recovery mechanism after restart/compaction.
9472
+ */
9473
+ async pullOnWake() {
9474
+ try {
9475
+ const wake = await this.api.wake(this.agentId);
9476
+ this.syncState.lastWake = (/* @__PURE__ */ new Date()).toISOString();
9477
+ this.saveSyncState();
9478
+ console.log("[sesame-sync] Wake data retrieved successfully");
9479
+ return wake;
9480
+ } catch (err) {
9481
+ console.error("[sesame-sync] Wake failed:", err.message);
9482
+ return null;
9483
+ }
9484
+ }
9485
+ // ── Pull: Recent Channel Messages ──
9486
+ /**
9487
+ * Pull recent messages from unread channels after wake.
9488
+ * Wake gives tasks/state but not conversational context — this fills that gap.
9489
+ *
9490
+ * @param wakeResponse - The response from pullOnWake()
9491
+ * @param limit - Messages per channel (default: 30)
9492
+ * @returns Map of channelId -> messages
9493
+ */
9494
+ async pullRecentMessages(wakeResponse, limit = 30) {
9495
+ const result = /* @__PURE__ */ new Map();
9496
+ const unreadChannels = wakeResponse.unreads || [];
9497
+ if (unreadChannels.length === 0) {
9498
+ console.log("[sesame-sync] No unread channels to pull messages from");
9499
+ return result;
9500
+ }
9501
+ for (const channel of unreadChannels) {
9502
+ const channelId = channel.channelId || channel.id;
9503
+ if (!channelId) continue;
9504
+ try {
9505
+ const response = await fetch(
9506
+ `${this.api.getBaseUrl()}/channels/${channelId}/messages?limit=${limit}&direction=before`,
9507
+ {
9508
+ headers: {
9509
+ Authorization: `Bearer ${this.api.getApiKey()}`,
9510
+ "Content-Type": "application/json"
9511
+ }
9512
+ }
9513
+ );
9514
+ if (!response.ok) {
9515
+ console.warn(`[sesame-sync] Failed to fetch messages for channel ${channelId}: ${response.status}`);
9516
+ continue;
9517
+ }
9518
+ const data = await response.json();
9519
+ const messages = (data.messages || data.data || []).map((msg) => ({
9520
+ content: msg.content || msg.plaintext || "",
9521
+ sender: msg.senderHandle || msg.sender || "unknown",
9522
+ timestamp: msg.createdAt || msg.timestamp || ""
9523
+ }));
9524
+ if (messages.length > 0) {
9525
+ result.set(channelId, messages);
9526
+ }
9527
+ } catch (err) {
9528
+ console.warn(`[sesame-sync] Failed to pull messages for ${channelId}:`, err.message);
9529
+ }
9530
+ }
9531
+ console.log(`[sesame-sync] Pulled messages from ${result.size} channels`);
9532
+ return result;
9533
+ }
9534
+ // ── Pull: Agent State -> MEMORY.md Recovery ──
9535
+ /**
9536
+ * Pull agent state and restore MEMORY.md if local copy is missing or empty.
9537
+ */
9538
+ async pullStateToMemoryMd() {
9539
+ const memoryMdPath = resolve20(this.workspaceDir, "MEMORY.md");
9540
+ if (existsSync21(memoryMdPath)) {
9541
+ const content = readFileSync16(memoryMdPath, "utf-8").trim();
9542
+ if (content.length > 0) {
9543
+ return false;
9544
+ }
9545
+ }
9546
+ try {
9547
+ const state = await this.api.getState(this.agentId, "memory");
9548
+ if (!state || !state.state.memoryMd) {
9549
+ console.log("[sesame-sync] No MEMORY.md found in agent state");
9550
+ return false;
9551
+ }
9552
+ writeFileSync9(memoryMdPath, state.state.memoryMd);
9553
+ console.log("[sesame-sync] Restored MEMORY.md from agent state");
9554
+ return true;
9555
+ } catch (err) {
9556
+ console.error("[sesame-sync] Failed to pull state:", err.message);
9557
+ return false;
9558
+ }
9559
+ }
9560
+ // ── Pre-Compaction Flush ──
9561
+ /**
9562
+ * Safety flush before compaction risk.
9563
+ * Pushes MEMORY.md to agent state and updates focused task context.
9564
+ */
9565
+ async flushBeforeCompaction(focusedTaskId, contextSummary) {
9566
+ console.log("[sesame-sync] Pre-compaction flush starting...");
9567
+ await this.pushState();
9568
+ if (contextSummary) {
9569
+ await this.pushWorkingContext({
9570
+ preCompactionFlush: true,
9571
+ contextSummary,
9572
+ focusedTaskId,
9573
+ flushedAt: (/* @__PURE__ */ new Date()).toISOString()
9574
+ });
9575
+ }
9576
+ if (focusedTaskId && contextSummary) {
9577
+ try {
9578
+ await this.api.updateTaskContext(focusedTaskId, {
9579
+ notes: `[Pre-compaction flush ${(/* @__PURE__ */ new Date()).toISOString()}] ${contextSummary}`
9580
+ });
9581
+ console.log("[sesame-sync] Updated focused task context");
9582
+ } catch (err) {
9583
+ console.warn("[sesame-sync] Failed to update task context:", err.message);
9584
+ }
9585
+ }
9586
+ console.log("[sesame-sync] Pre-compaction flush complete");
9587
+ }
9588
+ // ── Task Helpers ──
9589
+ /**
9590
+ * Log progress on a Sesame task.
9591
+ */
9592
+ async logTaskProgress(taskId, message) {
9593
+ try {
9594
+ await this.api.logActivity(taskId, "progress", message);
9595
+ } catch (err) {
9596
+ console.warn("[sesame-sync] Failed to log task progress:", err.message);
9597
+ }
9598
+ }
9599
+ /**
9600
+ * Log a decision on a Sesame task.
9601
+ */
9602
+ async logTaskDecision(taskId, message) {
9603
+ try {
9604
+ await this.api.logActivity(taskId, "decision", message);
9605
+ } catch (err) {
9606
+ console.warn("[sesame-sync] Failed to log task decision:", err.message);
9607
+ }
9608
+ }
9609
+ /**
9610
+ * Update a task's context block.
9611
+ */
9612
+ async updateTaskContext(taskId, context) {
9613
+ try {
9614
+ await this.api.updateTaskContext(taskId, context);
9615
+ } catch (err) {
9616
+ console.warn("[sesame-sync] Failed to update task context:", err.message);
9617
+ }
9618
+ }
9619
+ // ── Periodic Sync ──
9620
+ /**
9621
+ * Start periodic background sync.
9622
+ * Pushes state every intervalMs (default: 5 minutes).
9623
+ * Syncs L3 every l3IntervalMs (default: 30 minutes).
9624
+ */
9625
+ startPeriodicSync(memoryDaemonUrl, intervalMs = 5 * 60 * 1e3, l3IntervalMs = 30 * 60 * 1e3) {
9626
+ if (this.syncInterval) return;
9627
+ let l3Counter = 0;
9628
+ const l3Every = Math.max(1, Math.floor(l3IntervalMs / intervalMs));
9629
+ this.syncInterval = setInterval(async () => {
9630
+ try {
9631
+ await this.pushState();
9632
+ l3Counter++;
9633
+ if (l3Counter >= l3Every) {
9634
+ l3Counter = 0;
9635
+ await this.syncL3ToMemory(memoryDaemonUrl);
9636
+ }
9637
+ } catch (err) {
9638
+ console.error("[sesame-sync] Periodic sync error:", err.message);
9639
+ }
9640
+ }, intervalMs);
9641
+ console.log(`[sesame-sync] Periodic sync started (state: ${intervalMs / 1e3}s, L3: ${l3IntervalMs / 1e3}s)`);
9642
+ }
9643
+ /**
9644
+ * Stop periodic sync.
9645
+ */
9646
+ stopPeriodicSync() {
9647
+ if (this.syncInterval) {
9648
+ clearInterval(this.syncInterval);
9649
+ this.syncInterval = null;
9650
+ console.log("[sesame-sync] Periodic sync stopped");
9651
+ }
9652
+ }
9653
+ // ── Accessors ──
9654
+ getApi() {
9655
+ return this.api;
9656
+ }
9657
+ getSyncState() {
9658
+ return { ...this.syncState };
9659
+ }
9660
+ getAgentId() {
9661
+ return this.agentId;
9662
+ }
9663
+ };
9664
+
8961
9665
  // packages/runtime/src/pipeline.ts
8962
9666
  var PACKAGE_VERSION = "unknown";
8963
9667
  try {
8964
- const __dirname2 = dirname8(fileURLToPath3(import.meta.url));
8965
- const pkg = JSON.parse(readFileSync16(resolve20(__dirname2, "../package.json"), "utf-8"));
9668
+ const __dirname2 = dirname9(fileURLToPath3(import.meta.url));
9669
+ const pkg = JSON.parse(readFileSync17(resolve21(__dirname2, "../package.json"), "utf-8"));
8966
9670
  PACKAGE_VERSION = pkg.version ?? "unknown";
8967
9671
  } catch {
8968
9672
  }
@@ -9004,12 +9708,12 @@ function startHealthServer(port) {
9004
9708
  return server;
9005
9709
  }
9006
9710
  function writePidFile(path) {
9007
- writeFileSync9(path, String(process.pid));
9711
+ writeFileSync10(path, String(process.pid));
9008
9712
  console.log(`[hivemind] PID file written: ${path}`);
9009
9713
  }
9010
9714
  function cleanupPidFile(path) {
9011
9715
  try {
9012
- unlinkSync3(path);
9716
+ unlinkSync4(path);
9013
9717
  } catch {
9014
9718
  }
9015
9719
  }
@@ -9045,12 +9749,12 @@ async function startPipeline(configPath) {
9045
9749
  console.log("[hivemind] Global context already exists in memory daemon");
9046
9750
  }
9047
9751
  }
9048
- const requestLogger = new RequestLogger(resolve20(dirname8(configPath), "data", "dashboard.db"));
9752
+ const requestLogger = new RequestLogger(resolve21(dirname9(configPath), "data", "dashboard.db"));
9049
9753
  const agent = new Agent(config);
9050
9754
  startDashboardServer(requestLogger, config.memory, () => agent.getConversationHistories());
9051
9755
  agent.setRequestLogger(requestLogger);
9052
- const hivemindHome = process.env.HIVEMIND_HOME || resolve20(process.env.HOME || "/root", "hivemind");
9053
- const workspaceDir = resolve20(hivemindHome, config.agent.workspace || "workspace");
9756
+ const hivemindHome = process.env.HIVEMIND_HOME || resolve21(process.env.HOME || "/root", "hivemind");
9757
+ const workspaceDir = resolve21(hivemindHome, config.agent.workspace || "workspace");
9054
9758
  let contextBridge;
9055
9759
  if (memoryConnected) {
9056
9760
  try {
@@ -9084,7 +9788,7 @@ async function startPipeline(configPath) {
9084
9788
  agent.setToolRegistry(toolRegistry);
9085
9789
  console.log(`[hivemind] Context manager initialized (active: ${agent.getActiveContext()})`);
9086
9790
  if (config.auto_debug?.enabled) {
9087
- const dataDir2 = resolve20(hivemindHome, "data");
9791
+ const dataDir2 = resolve21(hivemindHome, "data");
9088
9792
  const autoDebugConfig = config.auto_debug;
9089
9793
  const logWatcher = new LogWatcher(
9090
9794
  {
@@ -9126,7 +9830,7 @@ async function startPipeline(configPath) {
9126
9830
  process.on("exit", () => processManager.stop());
9127
9831
  console.log("[hivemind] Auto-debug processors started");
9128
9832
  }
9129
- const dataDir = resolve20(hivemindHome, "data");
9833
+ const dataDir = resolve21(hivemindHome, "data");
9130
9834
  if (config.sesame.api_key) {
9131
9835
  await startSesameLoop(config, agent, toolRegistry, dataDir);
9132
9836
  } else {
@@ -9137,6 +9841,7 @@ async function startPipeline(configPath) {
9137
9841
  async function startSesameLoop(config, agent, toolRegistry, dataDir) {
9138
9842
  const sesame = new SesameClient2(config.sesame);
9139
9843
  registerMessagingTools(toolRegistry, sesame);
9844
+ let sesameSync = null;
9140
9845
  let eventsWatcher = null;
9141
9846
  if (dataDir) {
9142
9847
  eventsWatcher = new EventsWatcher(dataDir, async (channelId, text, filename, eventType) => {
@@ -9159,11 +9864,20 @@ async function startSesameLoop(config, agent, toolRegistry, dataDir) {
9159
9864
  eventsWatcher.start();
9160
9865
  }
9161
9866
  let shuttingDown = false;
9162
- const shutdown = (signal) => {
9867
+ const shutdown = async (signal) => {
9163
9868
  if (shuttingDown) return;
9164
9869
  shuttingDown = true;
9165
9870
  console.log(`
9166
9871
  [hivemind] Received ${signal}, shutting down...`);
9872
+ if (sesameSync) {
9873
+ try {
9874
+ await sesameSync.flushBeforeCompaction(void 0, `Shutdown via ${signal}`);
9875
+ sesameSync.stopPeriodicSync();
9876
+ console.log("[hivemind] Sesame state flushed before shutdown");
9877
+ } catch (err) {
9878
+ console.warn("[hivemind] Sesame flush failed:", err.message);
9879
+ }
9880
+ }
9167
9881
  try {
9168
9882
  sesame.updatePresence("offline", { emoji: "\u2B58" });
9169
9883
  sesame.disconnect();
@@ -9253,6 +9967,21 @@ async function startSesameLoop(config, agent, toolRegistry, dataDir) {
9253
9967
  await sesame.connect();
9254
9968
  sesameConnected = true;
9255
9969
  console.log("[hivemind] Listening for Sesame messages");
9970
+ const agentId = sesame.getAgentId();
9971
+ if (agentId && dataDir) {
9972
+ const hivemindHome = process.env.HIVEMIND_HOME || resolve21(process.env.HOME || "/root", "hivemind");
9973
+ const workspaceDir = resolve21(hivemindHome, config.agent.workspace || "workspace");
9974
+ sesameSync = new SesameSync(config.sesame, agentId, workspaceDir, dataDir);
9975
+ try {
9976
+ await sesameSync.pushState();
9977
+ console.log("[hivemind] Initial Sesame state sync complete");
9978
+ } catch (err) {
9979
+ console.warn("[hivemind] Initial Sesame state sync failed:", err.message);
9980
+ }
9981
+ sesameSync.startPeriodicSync(config.memory.daemon_url, 5 * 60 * 1e3, 30 * 60 * 1e3);
9982
+ process.on("exit", () => sesameSync?.stopPeriodicSync());
9983
+ console.log("[hivemind] Sesame sync module initialized");
9984
+ }
9256
9985
  await new Promise(() => {
9257
9986
  });
9258
9987
  }
@@ -9300,8 +10029,8 @@ ${response.content}
9300
10029
  console.error("Error:", err.message);
9301
10030
  }
9302
10031
  });
9303
- return new Promise((resolve21) => {
9304
- rl.on("close", resolve21);
10032
+ return new Promise((resolve22) => {
10033
+ rl.on("close", resolve22);
9305
10034
  });
9306
10035
  }
9307
10036
  async function runSpawnTask(config, configPath) {
@@ -9312,7 +10041,7 @@ async function runSpawnTask(config, configPath) {
9312
10041
  const spawnDir = process.env.SPAWN_DIR;
9313
10042
  console.log(`[spawn] Sub-agent starting (id: ${spawnId}, context: ${context})`);
9314
10043
  const agent = new Agent(config, context);
9315
- const hivemindHome = process.env.HIVEMIND_HOME || resolve20(process.env.HOME || "/root", "hivemind");
10044
+ const hivemindHome = process.env.HIVEMIND_HOME || resolve21(process.env.HOME || "/root", "hivemind");
9316
10045
  const toolRegistry = registerAllTools(hivemindHome, {
9317
10046
  enabled: true,
9318
10047
  workspace: config.agent.workspace || "workspace",
@@ -9325,7 +10054,7 @@ async function runSpawnTask(config, configPath) {
9325
10054
  const result = response.content;
9326
10055
  console.log(`[spawn] Task completed (context: ${response.context})`);
9327
10056
  if (spawnDir) {
9328
- writeFileSync9(resolve20(spawnDir, "result.txt"), result);
10057
+ writeFileSync10(resolve21(spawnDir, "result.txt"), result);
9329
10058
  }
9330
10059
  if (channelId && config.sesame.api_key) {
9331
10060
  try {
@@ -9342,7 +10071,7 @@ async function runSpawnTask(config, configPath) {
9342
10071
  const errorMsg = `[SPAWN ERROR] ${err.message}`;
9343
10072
  console.error(`[spawn] ${errorMsg}`);
9344
10073
  if (spawnDir) {
9345
- writeFileSync9(resolve20(spawnDir, "result.txt"), errorMsg);
10074
+ writeFileSync10(resolve21(spawnDir, "result.txt"), errorMsg);
9346
10075
  }
9347
10076
  process.exitCode = 1;
9348
10077
  }
@@ -9373,20 +10102,20 @@ var WorkerServer = class {
9373
10102
  }
9374
10103
  /** Start listening. */
9375
10104
  async start() {
9376
- return new Promise((resolve21, reject) => {
10105
+ return new Promise((resolve22, reject) => {
9377
10106
  this.server = createServer4((req, res) => this.handleRequest(req, res));
9378
10107
  this.server.on("error", reject);
9379
- this.server.listen(this.port, () => resolve21());
10108
+ this.server.listen(this.port, () => resolve22());
9380
10109
  });
9381
10110
  }
9382
10111
  /** Stop the server. */
9383
10112
  async stop() {
9384
- return new Promise((resolve21) => {
10113
+ return new Promise((resolve22) => {
9385
10114
  if (!this.server) {
9386
- resolve21();
10115
+ resolve22();
9387
10116
  return;
9388
10117
  }
9389
- this.server.close(() => resolve21());
10118
+ this.server.close(() => resolve22());
9390
10119
  });
9391
10120
  }
9392
10121
  getPort() {
@@ -9509,10 +10238,10 @@ var WorkerServer = class {
9509
10238
  }
9510
10239
  };
9511
10240
  function readBody2(req) {
9512
- return new Promise((resolve21, reject) => {
10241
+ return new Promise((resolve22, reject) => {
9513
10242
  const chunks = [];
9514
10243
  req.on("data", (chunk) => chunks.push(chunk));
9515
- req.on("end", () => resolve21(Buffer.concat(chunks).toString("utf-8")));
10244
+ req.on("end", () => resolve22(Buffer.concat(chunks).toString("utf-8")));
9516
10245
  req.on("error", reject);
9517
10246
  });
9518
10247
  }
@@ -9854,4 +10583,4 @@ smol-toml/dist/index.js:
9854
10583
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9855
10584
  *)
9856
10585
  */
9857
- //# sourceMappingURL=chunk-PGLO6WA5.js.map
10586
+ //# sourceMappingURL=chunk-CEJEBZTB.js.map