@askexenow/exe-os 0.9.13 → 0.9.15

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.
Files changed (70) hide show
  1. package/dist/bin/backfill-conversations.js +31 -4
  2. package/dist/bin/backfill-responses.js +31 -4
  3. package/dist/bin/backfill-vectors.js +25 -4
  4. package/dist/bin/cleanup-stale-review-tasks.js +1 -1
  5. package/dist/bin/cli.js +55 -8
  6. package/dist/bin/exe-assign.js +31 -4
  7. package/dist/bin/exe-boot.js +25 -4
  8. package/dist/bin/exe-dispatch.js +1 -1
  9. package/dist/bin/exe-doctor.js +1 -1
  10. package/dist/bin/exe-export-behaviors.js +1 -1
  11. package/dist/bin/exe-forget.js +1 -1
  12. package/dist/bin/exe-gateway.js +447 -21
  13. package/dist/bin/exe-heartbeat.js +1 -1
  14. package/dist/bin/exe-kill.js +1 -1
  15. package/dist/bin/exe-launch-agent.js +1 -1
  16. package/dist/bin/exe-link.js +31 -4
  17. package/dist/bin/exe-pending-messages.js +1 -1
  18. package/dist/bin/exe-pending-notifications.js +1 -1
  19. package/dist/bin/exe-pending-reviews.js +1 -1
  20. package/dist/bin/exe-rename.js +31 -4
  21. package/dist/bin/exe-review.js +1 -1
  22. package/dist/bin/exe-search.js +31 -4
  23. package/dist/bin/exe-session-cleanup.js +25 -4
  24. package/dist/bin/exe-start-codex.js +1 -1
  25. package/dist/bin/exe-start-opencode.js +1 -1
  26. package/dist/bin/exe-status.js +1 -1
  27. package/dist/bin/exe-team.js +1 -1
  28. package/dist/bin/git-sweep.js +25 -4
  29. package/dist/bin/graph-backfill.js +1 -1
  30. package/dist/bin/graph-export.js +1 -1
  31. package/dist/bin/scan-tasks.js +25 -4
  32. package/dist/bin/setup.js +46 -8
  33. package/dist/bin/shard-migrate.js +1 -1
  34. package/dist/bin/wiki-sync.js +1 -1
  35. package/dist/gateway/index.js +128 -125
  36. package/dist/hooks/bug-report-worker.js +1 -1
  37. package/dist/hooks/codex-stop-task-finalizer.js +1 -1
  38. package/dist/hooks/commit-complete.js +25 -4
  39. package/dist/hooks/error-recall.js +31 -4
  40. package/dist/hooks/ingest-worker.js +25 -4
  41. package/dist/hooks/ingest.js +1 -1
  42. package/dist/hooks/instructions-loaded.js +31 -4
  43. package/dist/hooks/notification.js +31 -4
  44. package/dist/hooks/post-compact.js +31 -4
  45. package/dist/hooks/pre-compact.js +25 -4
  46. package/dist/hooks/pre-tool-use.js +31 -4
  47. package/dist/hooks/prompt-ingest-worker.js +25 -4
  48. package/dist/hooks/prompt-submit.js +25 -4
  49. package/dist/hooks/response-ingest-worker.js +25 -4
  50. package/dist/hooks/session-end.js +25 -4
  51. package/dist/hooks/session-start.js +31 -4
  52. package/dist/hooks/stop.js +25 -4
  53. package/dist/hooks/subagent-stop.js +31 -4
  54. package/dist/hooks/summary-worker.js +25 -4
  55. package/dist/index.js +128 -125
  56. package/dist/lib/cloud-sync.js +31 -4
  57. package/dist/lib/database.js +31 -4
  58. package/dist/lib/db-daemon-client.js +31 -3
  59. package/dist/lib/db.js +31 -4
  60. package/dist/lib/device-registry.js +31 -4
  61. package/dist/lib/embedder.js +30 -3
  62. package/dist/lib/exe-daemon-client.js +31 -3
  63. package/dist/lib/exe-daemon.js +1969 -156
  64. package/dist/lib/hybrid-search.js +31 -4
  65. package/dist/lib/schedules.js +1 -1
  66. package/dist/lib/store.js +1 -1
  67. package/dist/mcp/server.js +25 -4
  68. package/dist/runtime/index.js +25 -4
  69. package/dist/tui/App.js +34 -4
  70. package/package.json +1 -1
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -951,7 +957,7 @@ async function ensureCompatibilityViews(prisma) {
951
957
  for (const mapping of VIEW_MAPPINGS) {
952
958
  const relation = mapping.source.replace(/"/g, "");
953
959
  const rows = await prisma.$queryRawUnsafe(
954
- "SELECT to_regclass($1) AS regclass",
960
+ "SELECT to_regclass($1)::text AS regclass",
955
961
  relation
956
962
  );
957
963
  if (!rows[0]?.regclass) {
@@ -1305,8 +1311,29 @@ function findPackageRoot() {
1305
1311
  }
1306
1312
  return null;
1307
1313
  }
1314
+ function getAvailableMemoryGB() {
1315
+ if (process.platform === "darwin") {
1316
+ try {
1317
+ const { execSync: execSync5 } = __require("child_process");
1318
+ const vmstat = execSync5("vm_stat", { encoding: "utf8" });
1319
+ const pageSize = 16384;
1320
+ const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1321
+ const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
1322
+ const free = vmstat.match(/Pages free:\s+(\d+)/);
1323
+ const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
1324
+ const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
1325
+ const freePages = free ? parseInt(free[1], 10) : 0;
1326
+ const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
1327
+ const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
1328
+ return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
1329
+ } catch {
1330
+ return os6.freemem() / (1024 * 1024 * 1024);
1331
+ }
1332
+ }
1333
+ return os6.freemem() / (1024 * 1024 * 1024);
1334
+ }
1308
1335
  function spawnDaemon() {
1309
- const freeGB = os6.freemem() / (1024 * 1024 * 1024);
1336
+ const freeGB = getAvailableMemoryGB();
1310
1337
  const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
1311
1338
  if (totalGB <= 8) {
1312
1339
  process.stderr.write(
@@ -1315,9 +1342,9 @@ function spawnDaemon() {
1315
1342
  );
1316
1343
  return;
1317
1344
  }
1318
- if (totalGB <= 16 && freeGB < 4) {
1345
+ if (totalGB <= 16 && freeGB < 2) {
1319
1346
  process.stderr.write(
1320
- `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1347
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1321
1348
  `
1322
1349
  );
1323
1350
  return;
@@ -799,7 +799,7 @@ async function ensureCompatibilityViews(prisma) {
799
799
  for (const mapping of VIEW_MAPPINGS) {
800
800
  const relation = mapping.source.replace(/"/g, "");
801
801
  const rows = await prisma.$queryRawUnsafe(
802
- "SELECT to_regclass($1) AS regclass",
802
+ "SELECT to_regclass($1)::text AS regclass",
803
803
  relation
804
804
  );
805
805
  if (!rows[0]?.regclass) {
@@ -1153,8 +1153,29 @@ function findPackageRoot() {
1153
1153
  }
1154
1154
  return null;
1155
1155
  }
1156
+ function getAvailableMemoryGB() {
1157
+ if (process.platform === "darwin") {
1158
+ try {
1159
+ const { execSync: execSync5 } = __require("child_process");
1160
+ const vmstat = execSync5("vm_stat", { encoding: "utf8" });
1161
+ const pageSize = 16384;
1162
+ const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1163
+ const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
1164
+ const free = vmstat.match(/Pages free:\s+(\d+)/);
1165
+ const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
1166
+ const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
1167
+ const freePages = free ? parseInt(free[1], 10) : 0;
1168
+ const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
1169
+ const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
1170
+ return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
1171
+ } catch {
1172
+ return os4.freemem() / (1024 * 1024 * 1024);
1173
+ }
1174
+ }
1175
+ return os4.freemem() / (1024 * 1024 * 1024);
1176
+ }
1156
1177
  function spawnDaemon() {
1157
- const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1178
+ const freeGB = getAvailableMemoryGB();
1158
1179
  const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1159
1180
  if (totalGB <= 8) {
1160
1181
  process.stderr.write(
@@ -1163,9 +1184,9 @@ function spawnDaemon() {
1163
1184
  );
1164
1185
  return;
1165
1186
  }
1166
- if (totalGB <= 16 && freeGB < 4) {
1187
+ if (totalGB <= 16 && freeGB < 2) {
1167
1188
  process.stderr.write(
1168
- `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1189
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1169
1190
  `
1170
1191
  );
1171
1192
  return;
package/dist/index.js CHANGED
@@ -1504,7 +1504,7 @@ async function ensureCompatibilityViews(prisma) {
1504
1504
  for (const mapping of VIEW_MAPPINGS) {
1505
1505
  const relation = mapping.source.replace(/"/g, "");
1506
1506
  const rows = await prisma.$queryRawUnsafe(
1507
- "SELECT to_regclass($1) AS regclass",
1507
+ "SELECT to_regclass($1)::text AS regclass",
1508
1508
  relation
1509
1509
  );
1510
1510
  if (!rows[0]?.regclass) {
@@ -1858,8 +1858,29 @@ function findPackageRoot() {
1858
1858
  }
1859
1859
  return null;
1860
1860
  }
1861
+ function getAvailableMemoryGB() {
1862
+ if (process.platform === "darwin") {
1863
+ try {
1864
+ const { execSync: execSync8 } = __require("child_process");
1865
+ const vmstat = execSync8("vm_stat", { encoding: "utf8" });
1866
+ const pageSize = 16384;
1867
+ const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1868
+ const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
1869
+ const free = vmstat.match(/Pages free:\s+(\d+)/);
1870
+ const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
1871
+ const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
1872
+ const freePages = free ? parseInt(free[1], 10) : 0;
1873
+ const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
1874
+ const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
1875
+ return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
1876
+ } catch {
1877
+ return os7.freemem() / (1024 * 1024 * 1024);
1878
+ }
1879
+ }
1880
+ return os7.freemem() / (1024 * 1024 * 1024);
1881
+ }
1861
1882
  function spawnDaemon() {
1862
- const freeGB = os7.freemem() / (1024 * 1024 * 1024);
1883
+ const freeGB = getAvailableMemoryGB();
1863
1884
  const totalGB = os7.totalmem() / (1024 * 1024 * 1024);
1864
1885
  if (totalGB <= 8) {
1865
1886
  process.stderr.write(
@@ -1868,9 +1889,9 @@ function spawnDaemon() {
1868
1889
  );
1869
1890
  return;
1870
1891
  }
1871
- if (totalGB <= 16 && freeGB < 4) {
1892
+ if (totalGB <= 16 && freeGB < 2) {
1872
1893
  process.stderr.write(
1873
- `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1894
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1874
1895
  `
1875
1896
  );
1876
1897
  return;
@@ -14128,6 +14149,7 @@ var WhatsAppAdapter = class {
14128
14149
  // src/gateway/adapters/signal.ts
14129
14150
  import { randomUUID as randomUUID10 } from "crypto";
14130
14151
  var DEFAULT_TIMEOUT_MS = 1e4;
14152
+ var POLL_INTERVAL_MS = 2e3;
14131
14153
  var SignalAdapter = class {
14132
14154
  platform = "signal";
14133
14155
  baseUrl = "";
@@ -14135,12 +14157,13 @@ var SignalAdapter = class {
14135
14157
  abortController = null;
14136
14158
  messageHandler = null;
14137
14159
  _connected = false;
14160
+ pollTimer = null;
14138
14161
  normalizeBaseUrl(url) {
14139
14162
  const trimmed = url.trim();
14140
14163
  if (/^https?:\/\//i.test(trimmed)) {
14141
14164
  return trimmed.replace(/\/+$/, "");
14142
14165
  }
14143
- return `https://${trimmed}`.replace(/\/+$/, "");
14166
+ return `http://${trimmed}`.replace(/\/+$/, "");
14144
14167
  }
14145
14168
  async connect(config2) {
14146
14169
  this.baseUrl = this.normalizeBaseUrl(
@@ -14150,12 +14173,12 @@ var SignalAdapter = class {
14150
14173
  const check = await this.healthCheck();
14151
14174
  if (!check.connected) {
14152
14175
  throw new Error(
14153
- `signal-cli daemon not reachable at ${this.baseUrl}. Start it with: signal-cli -a ${this.account} daemon --http`
14176
+ `signal-cli REST API not reachable at ${this.baseUrl}. Ensure bbernhard/signal-cli-rest-api container is running.`
14154
14177
  );
14155
14178
  }
14156
14179
  this._connected = true;
14157
14180
  this.abortController = new AbortController();
14158
- void this.startEventStream();
14181
+ void this.startPolling();
14159
14182
  void this.syncContacts().catch((err) => {
14160
14183
  console.error("[signal] Contact sync failed:", err);
14161
14184
  });
@@ -14166,6 +14189,10 @@ var SignalAdapter = class {
14166
14189
  async disconnect() {
14167
14190
  this.abortController?.abort();
14168
14191
  this.abortController = null;
14192
+ if (this.pollTimer) {
14193
+ clearTimeout(this.pollTimer);
14194
+ this.pollTimer = null;
14195
+ }
14169
14196
  this._connected = false;
14170
14197
  }
14171
14198
  onMessage(handler) {
@@ -14173,21 +14200,34 @@ var SignalAdapter = class {
14173
14200
  }
14174
14201
  async sendText(channelId, text, _options) {
14175
14202
  const isGroup = channelId.startsWith("group:");
14176
- const params = {
14203
+ const body = {
14177
14204
  message: text,
14178
- ...isGroup ? { groupId: channelId.slice("group:".length) } : { recipient: [channelId] }
14205
+ number: this.account,
14206
+ ...isGroup ? { recipients: [], group_id: channelId.slice("group:".length) } : { recipients: [channelId] }
14179
14207
  };
14180
- if (this.account) {
14181
- params.account = this.account;
14208
+ const res = await fetch(`${this.baseUrl}/v2/send`, {
14209
+ method: "POST",
14210
+ headers: { "Content-Type": "application/json" },
14211
+ body: JSON.stringify(body),
14212
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
14213
+ });
14214
+ if (!res.ok) {
14215
+ const errText = await res.text().catch(() => "");
14216
+ throw new Error(`Signal send failed (${res.status}): ${errText}`);
14182
14217
  }
14183
- await this.rpcRequest("send", params);
14184
14218
  }
14185
14219
  async sendTyping(channelId) {
14186
14220
  try {
14187
14221
  const isGroup = channelId.startsWith("group:");
14188
- await this.rpcRequest("sendTyping", {
14189
- ...isGroup ? { groupId: channelId.slice("group:".length) } : { recipient: [channelId] },
14190
- ...this.account ? { account: this.account } : {}
14222
+ const endpoint = isGroup ? `${this.baseUrl}/v1/typing-indicator/${this.account}` : `${this.baseUrl}/v1/typing-indicator/${this.account}`;
14223
+ await fetch(endpoint, {
14224
+ method: "PUT",
14225
+ headers: { "Content-Type": "application/json" },
14226
+ body: JSON.stringify({
14227
+ recipient: isGroup ? void 0 : channelId,
14228
+ group_id: isGroup ? channelId.slice("group:".length) : void 0
14229
+ }),
14230
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
14191
14231
  });
14192
14232
  } catch {
14193
14233
  }
@@ -14196,7 +14236,7 @@ var SignalAdapter = class {
14196
14236
  if (!this.baseUrl) return { connected: this._connected };
14197
14237
  const start = Date.now();
14198
14238
  try {
14199
- const res = await fetch(`${this.baseUrl}/api/v1/check`, {
14239
+ const res = await fetch(`${this.baseUrl}/v1/about`, {
14200
14240
  method: "GET",
14201
14241
  signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
14202
14242
  });
@@ -14210,96 +14250,48 @@ var SignalAdapter = class {
14210
14250
  return { connected: false };
14211
14251
  }
14212
14252
  }
14213
- async rpcRequest(method, params) {
14214
- const id = randomUUID10();
14215
- const res = await fetch(`${this.baseUrl}/api/v1/rpc`, {
14216
- method: "POST",
14217
- headers: { "Content-Type": "application/json" },
14218
- body: JSON.stringify({ jsonrpc: "2.0", method, params, id }),
14219
- signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
14220
- });
14221
- if (res.status === 201) return void 0;
14222
- const text = await res.text();
14223
- if (!text) throw new Error(`Signal RPC empty response (${res.status})`);
14224
- const parsed = JSON.parse(text);
14225
- if (parsed.error) {
14226
- throw new Error(
14227
- `Signal RPC ${parsed.error.code ?? "unknown"}: ${parsed.error.message ?? "error"}`
14228
- );
14229
- }
14230
- return parsed.result;
14231
- }
14232
- async startEventStream() {
14233
- const url = new URL(`${this.baseUrl}/api/v1/events`);
14234
- if (this.account) {
14235
- url.searchParams.set("account", this.account);
14236
- }
14253
+ async startPolling() {
14237
14254
  while (this.abortController && !this.abortController.signal.aborted) {
14238
14255
  try {
14239
- const res = await fetch(url, {
14240
- method: "GET",
14241
- headers: { Accept: "text/event-stream" },
14242
- signal: this.abortController.signal
14243
- });
14244
- if (!res.ok || !res.body) {
14245
- throw new Error(`Signal SSE failed (${res.status})`);
14246
- }
14247
- const reader = res.body.getReader();
14248
- const decoder = new TextDecoder();
14249
- let buffer = "";
14250
- let currentEvent = {};
14251
- const flushEvent = () => {
14252
- if (currentEvent.data) {
14253
- void this.handleSseEvent(currentEvent);
14254
- }
14255
- currentEvent = {};
14256
- };
14257
- while (true) {
14258
- const { value, done } = await reader.read();
14259
- if (done) break;
14260
- buffer += decoder.decode(value, { stream: true });
14261
- let lineEnd = buffer.indexOf("\n");
14262
- while (lineEnd !== -1) {
14263
- let line = buffer.slice(0, lineEnd);
14264
- buffer = buffer.slice(lineEnd + 1);
14265
- if (line.endsWith("\r")) line = line.slice(0, -1);
14266
- if (line === "") {
14267
- flushEvent();
14268
- } else if (!line.startsWith(":")) {
14269
- const colonIdx = line.indexOf(":");
14270
- if (colonIdx !== -1) {
14271
- const field = line.slice(0, colonIdx).trim();
14272
- const val = line.slice(colonIdx + 1).replace(/^ /, "");
14273
- if (field === "event") currentEvent.event = val;
14274
- else if (field === "data") {
14275
- currentEvent.data = currentEvent.data ? `${currentEvent.data}
14276
- ${val}` : val;
14277
- }
14278
- }
14279
- }
14280
- lineEnd = buffer.indexOf("\n");
14281
- }
14282
- }
14256
+ await this.pollMessages();
14283
14257
  } catch (err) {
14284
14258
  if (this.abortController?.signal.aborted) return;
14285
- console.error("[signal] SSE stream error, reconnecting in 5s:", err);
14286
- await new Promise((r) => setTimeout(r, 5e3));
14259
+ console.error("[signal] Poll error:", err);
14287
14260
  }
14261
+ await new Promise((resolve) => {
14262
+ this.pollTimer = setTimeout(resolve, POLL_INTERVAL_MS);
14263
+ });
14288
14264
  }
14289
14265
  }
14290
- async handleSseEvent(event) {
14291
- if (!event.data || !this.messageHandler) return;
14292
- let payload;
14293
- try {
14294
- payload = JSON.parse(event.data);
14295
- } catch {
14296
- return;
14266
+ async pollMessages() {
14267
+ if (!this.account || !this.messageHandler) return;
14268
+ const res = await fetch(
14269
+ `${this.baseUrl}/v1/receive/${encodeURIComponent(this.account)}`,
14270
+ {
14271
+ method: "GET",
14272
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
14273
+ }
14274
+ );
14275
+ if (!res.ok) {
14276
+ if (res.status === 400) {
14277
+ return;
14278
+ }
14279
+ throw new Error(`Signal receive failed (${res.status})`);
14280
+ }
14281
+ const entries = await res.json();
14282
+ if (!Array.isArray(entries) || entries.length === 0) return;
14283
+ for (const entry of entries) {
14284
+ await this.handleEntry(entry);
14297
14285
  }
14298
- const envelope = payload.envelope;
14286
+ }
14287
+ async handleEntry(entry) {
14288
+ if (!this.messageHandler) return;
14289
+ const envelope = entry.envelope;
14299
14290
  if (!envelope) return;
14300
- const senderId = envelope.sourceNumber ?? envelope.sourceUuid ?? "";
14301
- if (envelope.reactionMessage) {
14302
- const rm = envelope.reactionMessage;
14291
+ const senderId = envelope.sourceNumber ?? envelope.source ?? envelope.sourceUuid ?? "";
14292
+ if (envelope.dataMessage?.reaction) {
14293
+ const rm = envelope.dataMessage.reaction;
14294
+ if (rm.isRemove) return;
14303
14295
  const normalized2 = {
14304
14296
  messageId: randomUUID10(),
14305
14297
  platform: "signal",
@@ -14311,11 +14303,11 @@ ${val}` : val;
14311
14303
  timestamp: new Date(
14312
14304
  envelope.timestamp ?? Date.now()
14313
14305
  ).toISOString(),
14314
- raw: payload,
14306
+ raw: entry,
14315
14307
  dataCategory: "reaction",
14316
14308
  reaction: {
14317
- emoji: rm.emoji,
14318
- targetMessageId: String(rm.targetTimestamp),
14309
+ emoji: rm.emoji ?? "",
14310
+ targetMessageId: String(rm.targetSentTimestamp ?? ""),
14319
14311
  reactedBy: senderId,
14320
14312
  timestamp: new Date(
14321
14313
  envelope.timestamp ?? Date.now()
@@ -14327,7 +14319,7 @@ ${val}` : val;
14327
14319
  }
14328
14320
  if (envelope.receiptMessage) {
14329
14321
  const rcpt = envelope.receiptMessage;
14330
- for (const ts2 of rcpt.timestamps) {
14322
+ for (const ts2 of rcpt.timestamps ?? []) {
14331
14323
  const normalized2 = {
14332
14324
  messageId: randomUUID10(),
14333
14325
  platform: "signal",
@@ -14339,11 +14331,11 @@ ${val}` : val;
14339
14331
  timestamp: new Date(
14340
14332
  envelope.timestamp ?? Date.now()
14341
14333
  ).toISOString(),
14342
- raw: payload,
14334
+ raw: entry,
14343
14335
  dataCategory: "read_receipt",
14344
14336
  readReceipt: {
14345
14337
  messageId: String(ts2),
14346
- status: rcpt.type === "read" ? "read" : "delivered",
14338
+ status: rcpt.type === "READ" ? "read" : "delivered",
14347
14339
  timestamp: new Date(
14348
14340
  envelope.timestamp ?? Date.now()
14349
14341
  ).toISOString(),
@@ -14357,6 +14349,7 @@ ${val}` : val;
14357
14349
  if (envelope.editMessage) {
14358
14350
  const em = envelope.editMessage;
14359
14351
  const dm2 = em.dataMessage;
14352
+ if (!dm2) return;
14360
14353
  const isGroup2 = !!dm2.groupInfo?.groupId;
14361
14354
  const normalized2 = {
14362
14355
  messageId: String(dm2.timestamp ?? randomUUID10()),
@@ -14369,11 +14362,11 @@ ${val}` : val;
14369
14362
  timestamp: new Date(
14370
14363
  envelope.timestamp ?? Date.now()
14371
14364
  ).toISOString(),
14372
- media: this.extractMedia(dm2),
14373
- raw: payload,
14365
+ media: this.extractMedia(dm2.attachments),
14366
+ raw: entry,
14374
14367
  dataCategory: "edit",
14375
14368
  replyTo: {
14376
- messageId: String(em.targetTimestamp),
14369
+ messageId: String(em.targetSentTimestamp ?? ""),
14377
14370
  text: "",
14378
14371
  senderId
14379
14372
  }
@@ -14395,13 +14388,13 @@ ${val}` : val;
14395
14388
  timestamp: new Date(
14396
14389
  envelope.timestamp ?? Date.now()
14397
14390
  ).toISOString(),
14398
- media: this.extractMedia(dm),
14391
+ media: this.extractMedia(dm.attachments),
14399
14392
  replyTo: dm.quote ? {
14400
14393
  messageId: String(dm.quote.id ?? ""),
14401
14394
  text: dm.quote.text ?? "",
14402
- senderId: dm.quote.authorNumber ?? ""
14395
+ senderId: dm.quote.author ?? ""
14403
14396
  } : void 0,
14404
- raw: payload,
14397
+ raw: entry,
14405
14398
  dataCategory: "message"
14406
14399
  };
14407
14400
  await this.emitMessage(normalized);
@@ -14414,12 +14407,15 @@ ${val}` : val;
14414
14407
  console.error("[signal] Message handler error:", err);
14415
14408
  }
14416
14409
  }
14417
- /** Import all Signal contacts via listContacts RPC */
14410
+ /** Import all Signal contacts */
14418
14411
  async syncContacts() {
14419
- if (!this.messageHandler) return;
14420
- const contacts = await this.rpcRequest("listContacts", {
14421
- ...this.account ? { account: this.account } : {}
14422
- });
14412
+ if (!this.messageHandler || !this.account) return;
14413
+ const res = await fetch(
14414
+ `${this.baseUrl}/v1/contacts/${encodeURIComponent(this.account)}`,
14415
+ { signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS) }
14416
+ );
14417
+ if (!res.ok) return;
14418
+ const contacts = await res.json();
14423
14419
  if (!Array.isArray(contacts)) return;
14424
14420
  for (const contact of contacts) {
14425
14421
  const phone = contact.number ?? "";
@@ -14446,12 +14442,15 @@ ${val}` : val;
14446
14442
  }
14447
14443
  console.log(`[signal] Synced ${contacts.length} contacts`);
14448
14444
  }
14449
- /** Import all Signal groups via listGroups RPC */
14445
+ /** Import all Signal groups */
14450
14446
  async syncGroups() {
14451
- if (!this.messageHandler) return;
14452
- const groups = await this.rpcRequest("listGroups", {
14453
- ...this.account ? { account: this.account } : {}
14454
- });
14447
+ if (!this.messageHandler || !this.account) return;
14448
+ const res = await fetch(
14449
+ `${this.baseUrl}/v1/groups/${encodeURIComponent(this.account)}`,
14450
+ { signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS) }
14451
+ );
14452
+ if (!res.ok) return;
14453
+ const groups = await res.json();
14455
14454
  if (!Array.isArray(groups)) return;
14456
14455
  for (const group of groups) {
14457
14456
  const normalized = {
@@ -14476,15 +14475,19 @@ ${val}` : val;
14476
14475
  }
14477
14476
  console.log(`[signal] Synced ${groups.length} groups`);
14478
14477
  }
14479
- extractMedia(dm) {
14480
- if (!dm.attachments?.length) return void 0;
14481
- return dm.attachments.map((att) => {
14478
+ extractMedia(attachments) {
14479
+ if (!attachments?.length) return void 0;
14480
+ return attachments.map((att) => {
14482
14481
  const ct = att.contentType ?? "";
14483
14482
  let type = "document";
14484
14483
  if (ct.startsWith("image/")) type = "image";
14485
14484
  else if (ct.startsWith("video/")) type = "video";
14486
14485
  else if (ct.startsWith("audio/")) type = "audio";
14487
- return { type, fileName: att.filename ?? void 0 };
14486
+ return {
14487
+ type,
14488
+ fileName: att.filename ?? void 0,
14489
+ url: att.id ? `${this.baseUrl}/v1/attachments/${att.id}` : void 0
14490
+ };
14488
14491
  });
14489
14492
  }
14490
14493
  };
@@ -15053,7 +15056,7 @@ import { promisify } from "util";
15053
15056
  import os13 from "os";
15054
15057
  import path21 from "path";
15055
15058
  var execFileAsync = promisify(execFile);
15056
- var POLL_INTERVAL_MS = 5e3;
15059
+ var POLL_INTERVAL_MS2 = 5e3;
15057
15060
  var MESSAGES_DB_PATH = path21.join(
15058
15061
  process.env.HOME ?? os13.homedir(),
15059
15062
  "Library/Messages/chat.db"
@@ -15090,7 +15093,7 @@ var IMessageAdapter = class {
15090
15093
  console.log("[imessage] Connected via AppleScript bridge");
15091
15094
  this.pollTimer = setInterval(() => {
15092
15095
  void this.pollMessages();
15093
- }, POLL_INTERVAL_MS);
15096
+ }, POLL_INTERVAL_MS2);
15094
15097
  }
15095
15098
  async disconnect() {
15096
15099
  if (this.pollTimer) {
@@ -1,5 +1,11 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
3
9
  var __esm = (fn, res) => function __init() {
4
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
11
  };
@@ -605,7 +611,7 @@ async function ensureCompatibilityViews(prisma) {
605
611
  for (const mapping of VIEW_MAPPINGS) {
606
612
  const relation = mapping.source.replace(/"/g, "");
607
613
  const rows = await prisma.$queryRawUnsafe(
608
- "SELECT to_regclass($1) AS regclass",
614
+ "SELECT to_regclass($1)::text AS regclass",
609
615
  relation
610
616
  );
611
617
  if (!rows[0]?.regclass) {
@@ -959,8 +965,29 @@ function findPackageRoot() {
959
965
  }
960
966
  return null;
961
967
  }
968
+ function getAvailableMemoryGB() {
969
+ if (process.platform === "darwin") {
970
+ try {
971
+ const { execSync: execSync2 } = __require("child_process");
972
+ const vmstat = execSync2("vm_stat", { encoding: "utf8" });
973
+ const pageSize = 16384;
974
+ const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
975
+ const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
976
+ const free = vmstat.match(/Pages free:\s+(\d+)/);
977
+ const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
978
+ const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
979
+ const freePages = free ? parseInt(free[1], 10) : 0;
980
+ const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
981
+ const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
982
+ return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
983
+ } catch {
984
+ return os4.freemem() / (1024 * 1024 * 1024);
985
+ }
986
+ }
987
+ return os4.freemem() / (1024 * 1024 * 1024);
988
+ }
962
989
  function spawnDaemon() {
963
- const freeGB = os4.freemem() / (1024 * 1024 * 1024);
990
+ const freeGB = getAvailableMemoryGB();
964
991
  const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
965
992
  if (totalGB <= 8) {
966
993
  process.stderr.write(
@@ -969,9 +996,9 @@ function spawnDaemon() {
969
996
  );
970
997
  return;
971
998
  }
972
- if (totalGB <= 16 && freeGB < 4) {
999
+ if (totalGB <= 16 && freeGB < 2) {
973
1000
  process.stderr.write(
974
- `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
1001
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
975
1002
  `
976
1003
  );
977
1004
  return;