@askexenow/exe-os 0.9.21 → 0.9.23

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 (60) hide show
  1. package/dist/bin/backfill-conversations.js +17 -4
  2. package/dist/bin/backfill-responses.js +17 -4
  3. package/dist/bin/backfill-vectors.js +2 -2
  4. package/dist/bin/cleanup-stale-review-tasks.js +17 -4
  5. package/dist/bin/cli.js +378 -171
  6. package/dist/bin/exe-assign.js +17 -4
  7. package/dist/bin/exe-boot.js +2 -2
  8. package/dist/bin/exe-dispatch.js +17 -4
  9. package/dist/bin/exe-doctor.js +2 -2
  10. package/dist/bin/exe-export-behaviors.js +17 -4
  11. package/dist/bin/exe-forget.js +17 -4
  12. package/dist/bin/exe-gateway.js +17 -4
  13. package/dist/bin/exe-heartbeat.js +17 -4
  14. package/dist/bin/exe-kill.js +17 -4
  15. package/dist/bin/exe-launch-agent.js +17 -4
  16. package/dist/bin/exe-pending-messages.js +17 -4
  17. package/dist/bin/exe-pending-notifications.js +17 -4
  18. package/dist/bin/exe-pending-reviews.js +17 -4
  19. package/dist/bin/exe-review.js +17 -4
  20. package/dist/bin/exe-search.js +23 -8
  21. package/dist/bin/exe-session-cleanup.js +17 -4
  22. package/dist/bin/exe-start-codex.js +209 -32
  23. package/dist/bin/exe-start-opencode.js +17 -4
  24. package/dist/bin/exe-status.js +17 -4
  25. package/dist/bin/exe-team.js +17 -4
  26. package/dist/bin/git-sweep.js +17 -4
  27. package/dist/bin/graph-backfill.js +17 -4
  28. package/dist/bin/graph-export.js +17 -4
  29. package/dist/bin/install.js +42 -0
  30. package/dist/bin/intercom-check.js +17 -4
  31. package/dist/bin/scan-tasks.js +17 -4
  32. package/dist/bin/shard-migrate.js +17 -4
  33. package/dist/bin/update.js +187 -42
  34. package/dist/gateway/index.js +17 -4
  35. package/dist/hooks/bug-report-worker.js +793 -150
  36. package/dist/hooks/codex-stop-task-finalizer.js +3020 -2375
  37. package/dist/hooks/commit-complete.js +156 -6
  38. package/dist/hooks/error-recall.js +23 -8
  39. package/dist/hooks/ingest.js +17 -4
  40. package/dist/hooks/instructions-loaded.js +17 -4
  41. package/dist/hooks/notification.js +17 -4
  42. package/dist/hooks/post-compact.js +17 -4
  43. package/dist/hooks/post-tool-combined.js +23 -8
  44. package/dist/hooks/pre-compact.js +156 -8
  45. package/dist/hooks/pre-tool-use.js +21 -12
  46. package/dist/hooks/prompt-submit.js +23 -8
  47. package/dist/hooks/session-end.js +156 -8
  48. package/dist/hooks/session-start.js +23 -8
  49. package/dist/hooks/stop.js +306 -9
  50. package/dist/hooks/subagent-stop.js +306 -9
  51. package/dist/hooks/summary-worker.js +2 -2
  52. package/dist/index.js +17 -4
  53. package/dist/lib/exe-daemon.js +37 -14
  54. package/dist/lib/hybrid-search.js +23 -8
  55. package/dist/lib/schedules.js +2 -2
  56. package/dist/lib/store.js +17 -4
  57. package/dist/mcp/server.js +36 -10
  58. package/dist/runtime/index.js +17 -4
  59. package/dist/tui/App.js +17 -4
  60. package/package.json +1 -1
@@ -1266,6 +1266,17 @@ var init_daemon_auth = __esm({
1266
1266
  });
1267
1267
 
1268
1268
  // src/lib/exe-daemon-client.ts
1269
+ var exe_daemon_client_exports = {};
1270
+ __export(exe_daemon_client_exports, {
1271
+ connectEmbedDaemon: () => connectEmbedDaemon,
1272
+ disconnectClient: () => disconnectClient,
1273
+ embedBatchViaClient: () => embedBatchViaClient,
1274
+ embedViaClient: () => embedViaClient,
1275
+ isClientConnected: () => isClientConnected,
1276
+ pingDaemon: () => pingDaemon,
1277
+ sendDaemonRequest: () => sendDaemonRequest,
1278
+ sendIngestRequest: () => sendIngestRequest
1279
+ });
1269
1280
  import net from "net";
1270
1281
  import os6 from "os";
1271
1282
  import { spawn } from "child_process";
@@ -1502,6 +1513,9 @@ async function connectEmbedDaemon() {
1502
1513
  }
1503
1514
  return false;
1504
1515
  }
1516
+ function sendRequest(texts, priority) {
1517
+ return sendDaemonRequest({ texts, priority });
1518
+ }
1505
1519
  function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
1506
1520
  return new Promise((resolve) => {
1507
1521
  if (!_socket || !_connected) {
@@ -1524,10 +1538,170 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
1524
1538
  }
1525
1539
  });
1526
1540
  }
1541
+ async function pingDaemon() {
1542
+ if (!_socket || !_connected) return null;
1543
+ const response = await sendDaemonRequest({ type: "health" }, 5e3);
1544
+ if (response.health) {
1545
+ return response.health;
1546
+ }
1547
+ return null;
1548
+ }
1549
+ function killAndRespawnDaemon() {
1550
+ if (!acquireSpawnLock()) {
1551
+ process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
1552
+ if (_socket) {
1553
+ _socket.destroy();
1554
+ _socket = null;
1555
+ }
1556
+ _connected = false;
1557
+ _buffer = "";
1558
+ return;
1559
+ }
1560
+ try {
1561
+ process.stderr.write("[exed-client] Killing daemon for restart...\n");
1562
+ if (existsSync7(PID_PATH)) {
1563
+ try {
1564
+ const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
1565
+ if (pid > 0) {
1566
+ try {
1567
+ process.kill(pid, "SIGKILL");
1568
+ } catch {
1569
+ }
1570
+ }
1571
+ } catch {
1572
+ }
1573
+ }
1574
+ if (_socket) {
1575
+ _socket.destroy();
1576
+ _socket = null;
1577
+ }
1578
+ _connected = false;
1579
+ _buffer = "";
1580
+ try {
1581
+ unlinkSync3(PID_PATH);
1582
+ } catch {
1583
+ }
1584
+ try {
1585
+ unlinkSync3(SOCKET_PATH);
1586
+ } catch {
1587
+ }
1588
+ spawnDaemon();
1589
+ } finally {
1590
+ releaseSpawnLock();
1591
+ }
1592
+ }
1593
+ function isDaemonTooYoung() {
1594
+ try {
1595
+ const stat = statSync(PID_PATH);
1596
+ return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
1597
+ } catch {
1598
+ return false;
1599
+ }
1600
+ }
1601
+ async function retryThenRestart(doRequest, label) {
1602
+ const result = await doRequest();
1603
+ if (!result.error) {
1604
+ _consecutiveFailures = 0;
1605
+ return result;
1606
+ }
1607
+ _consecutiveFailures++;
1608
+ for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
1609
+ const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
1610
+ process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
1611
+ `);
1612
+ await new Promise((r) => setTimeout(r, delayMs));
1613
+ if (!_connected) {
1614
+ if (!await connectToSocket()) continue;
1615
+ }
1616
+ const retry = await doRequest();
1617
+ if (!retry.error) {
1618
+ _consecutiveFailures = 0;
1619
+ return retry;
1620
+ }
1621
+ _consecutiveFailures++;
1622
+ }
1623
+ if (isDaemonTooYoung()) {
1624
+ process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
1625
+ `);
1626
+ return { error: result.error };
1627
+ }
1628
+ process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
1629
+ `);
1630
+ killAndRespawnDaemon();
1631
+ const start = Date.now();
1632
+ let delay2 = 200;
1633
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1634
+ await new Promise((r) => setTimeout(r, delay2));
1635
+ if (await connectToSocket()) break;
1636
+ delay2 = Math.min(delay2 * 2, 3e3);
1637
+ }
1638
+ if (!_connected) return { error: "Daemon restart failed" };
1639
+ const final = await doRequest();
1640
+ if (!final.error) _consecutiveFailures = 0;
1641
+ return final;
1642
+ }
1643
+ async function embedViaClient(text, priority = "high") {
1644
+ if (!_connected && !await connectEmbedDaemon()) return null;
1645
+ _requestCount++;
1646
+ if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
1647
+ const health = await pingDaemon();
1648
+ if (!health && !isDaemonTooYoung()) {
1649
+ process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
1650
+ `);
1651
+ killAndRespawnDaemon();
1652
+ const start = Date.now();
1653
+ let d = 200;
1654
+ while (Date.now() - start < CONNECT_TIMEOUT_MS) {
1655
+ await new Promise((r) => setTimeout(r, d));
1656
+ if (await connectToSocket()) break;
1657
+ d = Math.min(d * 2, 3e3);
1658
+ }
1659
+ if (!_connected) return null;
1660
+ }
1661
+ }
1662
+ const result = await retryThenRestart(
1663
+ () => sendRequest([text], priority),
1664
+ "Embed"
1665
+ );
1666
+ return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
1667
+ }
1668
+ async function embedBatchViaClient(texts, priority = "high") {
1669
+ if (!_connected && !await connectEmbedDaemon()) return null;
1670
+ _requestCount++;
1671
+ const result = await retryThenRestart(
1672
+ () => sendRequest(texts, priority),
1673
+ "Batch embed"
1674
+ );
1675
+ return !result.error && result.vectors ? result.vectors : null;
1676
+ }
1677
+ function disconnectClient() {
1678
+ if (_socket) {
1679
+ _socket.destroy();
1680
+ _socket = null;
1681
+ }
1682
+ _connected = false;
1683
+ _buffer = "";
1684
+ for (const [id, entry] of _pending) {
1685
+ clearTimeout(entry.timer);
1686
+ _pending.delete(id);
1687
+ entry.resolve({ error: "Client disconnected" });
1688
+ }
1689
+ }
1527
1690
  function isClientConnected() {
1528
1691
  return _connected;
1529
1692
  }
1530
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _pending, MAX_BUFFER;
1693
+ function sendIngestRequest(payload) {
1694
+ if (!_socket || !_connected) return false;
1695
+ try {
1696
+ const id = randomUUID();
1697
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
1698
+ _socket.write(JSON.stringify({ id, token, type: "ingest", ...payload }) + "\n");
1699
+ return true;
1700
+ } catch {
1701
+ return false;
1702
+ }
1703
+ }
1704
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
1531
1705
  var init_exe_daemon_client = __esm({
1532
1706
  "src/lib/exe-daemon-client.ts"() {
1533
1707
  "use strict";
@@ -1543,12 +1717,27 @@ var init_exe_daemon_client = __esm({
1543
1717
  _socket = null;
1544
1718
  _connected = false;
1545
1719
  _buffer = "";
1720
+ _requestCount = 0;
1721
+ _consecutiveFailures = 0;
1722
+ HEALTH_CHECK_INTERVAL = 100;
1723
+ MAX_RETRIES_BEFORE_RESTART = 3;
1724
+ RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
1725
+ MIN_DAEMON_AGE_MS = 3e4;
1546
1726
  _pending = /* @__PURE__ */ new Map();
1547
1727
  MAX_BUFFER = 1e7;
1548
1728
  }
1549
1729
  });
1550
1730
 
1551
1731
  // src/lib/daemon-protocol.ts
1732
+ var daemon_protocol_exports = {};
1733
+ __export(daemon_protocol_exports, {
1734
+ deserializeArgs: () => deserializeArgs,
1735
+ deserializeResultSet: () => deserializeResultSet,
1736
+ deserializeValue: () => deserializeValue,
1737
+ serializeArgs: () => serializeArgs,
1738
+ serializeResultSet: () => serializeResultSet,
1739
+ serializeValue: () => serializeValue
1740
+ });
1552
1741
  function serializeValue(v) {
1553
1742
  if (v === null || v === void 0) return null;
1554
1743
  if (typeof v === "bigint") return Number(v);
@@ -1573,6 +1762,32 @@ function deserializeValue(v) {
1573
1762
  }
1574
1763
  return v;
1575
1764
  }
1765
+ function serializeArgs(args) {
1766
+ return args.map(serializeValue);
1767
+ }
1768
+ function deserializeArgs(args) {
1769
+ return args.map(deserializeValue);
1770
+ }
1771
+ function serializeResultSet(rs) {
1772
+ const rows = [];
1773
+ for (const row of rs.rows) {
1774
+ const obj = {};
1775
+ for (let i = 0; i < rs.columns.length; i++) {
1776
+ const col = rs.columns[i];
1777
+ if (col !== void 0) {
1778
+ obj[col] = serializeValue(row[i]);
1779
+ }
1780
+ }
1781
+ rows.push(obj);
1782
+ }
1783
+ return {
1784
+ columns: [...rs.columns],
1785
+ columnTypes: [...rs.columnTypes ?? []],
1786
+ rows,
1787
+ rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
1788
+ lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
1789
+ };
1790
+ }
1576
1791
  function deserializeResultSet(srs) {
1577
1792
  const rows = srs.rows.map((obj) => {
1578
1793
  const values = srs.columns.map(
@@ -3137,8 +3352,8 @@ function getShardClient(projectName) {
3137
3352
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
3138
3353
  }
3139
3354
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3140
- if (!safeName) {
3141
- throw new Error(`Invalid project name for shard: "${projectName}"`);
3355
+ if (!safeName || safeName === "unknown") {
3356
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
3142
3357
  }
3143
3358
  const cached = _shards.get(safeName);
3144
3359
  if (cached) {
@@ -4007,19 +4222,32 @@ async function flushBatch() {
4007
4222
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4008
4223
  if (isShardingEnabled2()) {
4009
4224
  const byProject = /* @__PURE__ */ new Map();
4225
+ let skippedUnknown = 0;
4010
4226
  for (const row of batch) {
4011
- const proj = row.project_name || "unknown";
4227
+ const proj = row.project_name?.trim();
4228
+ if (!proj) {
4229
+ skippedUnknown++;
4230
+ continue;
4231
+ }
4012
4232
  if (!byProject.has(proj)) byProject.set(proj, []);
4013
4233
  byProject.get(proj).push(row);
4014
4234
  }
4235
+ if (skippedUnknown > 0) {
4236
+ process.stderr.write(
4237
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
4238
+ `
4239
+ );
4240
+ }
4015
4241
  for (const [project, rows] of byProject) {
4016
4242
  try {
4017
4243
  const shardClient = await getReadyShardClient2(project);
4018
4244
  const shardStmts = rows.map(buildStmt);
4019
4245
  await shardClient.batch(shardStmts, "write");
4020
4246
  } catch (err) {
4247
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
4248
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
4021
4249
  process.stderr.write(
4022
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
4250
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
4023
4251
  `
4024
4252
  );
4025
4253
  }
@@ -4258,6 +4486,77 @@ var init_store = __esm({
4258
4486
  }
4259
4487
  });
4260
4488
 
4489
+ // src/bin/fast-db-init.ts
4490
+ var fast_db_init_exports = {};
4491
+ __export(fast_db_init_exports, {
4492
+ fastDbInit: () => fastDbInit
4493
+ });
4494
+ async function fastDbInit() {
4495
+ const { isInitialized: isInitialized2, getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4496
+ if (isInitialized2()) {
4497
+ return getClient2();
4498
+ }
4499
+ try {
4500
+ const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
4501
+ const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
4502
+ await connectEmbedDaemon2();
4503
+ if (isClientConnected2()) {
4504
+ const daemonClient = {
4505
+ async execute(stmt) {
4506
+ const sql = typeof stmt === "string" ? stmt : stmt.sql;
4507
+ const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
4508
+ const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
4509
+ if (resp.error) throw new Error(String(resp.error));
4510
+ if (resp.db) return deserializeResultSet2(resp.db);
4511
+ throw new Error("Unexpected daemon response");
4512
+ },
4513
+ async batch(stmts, mode) {
4514
+ const statements = stmts.map((s) => {
4515
+ const sql = typeof s === "string" ? s : s.sql;
4516
+ const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
4517
+ return { sql, args };
4518
+ });
4519
+ const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
4520
+ if (resp.error) throw new Error(String(resp.error));
4521
+ const batchResults = resp["db-batch"];
4522
+ if (batchResults) return batchResults.map(deserializeResultSet2);
4523
+ throw new Error("Unexpected daemon batch response");
4524
+ },
4525
+ async transaction(_mode) {
4526
+ throw new Error("Transactions not supported via daemon socket");
4527
+ },
4528
+ async executeMultiple(_sql) {
4529
+ throw new Error("executeMultiple not supported via daemon socket");
4530
+ },
4531
+ async migrate(_stmts) {
4532
+ throw new Error("migrate not supported via daemon socket");
4533
+ },
4534
+ sync() {
4535
+ return Promise.resolve(void 0);
4536
+ },
4537
+ close() {
4538
+ },
4539
+ get closed() {
4540
+ return false;
4541
+ },
4542
+ get protocol() {
4543
+ return "file";
4544
+ }
4545
+ };
4546
+ return daemonClient;
4547
+ }
4548
+ } catch {
4549
+ }
4550
+ const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
4551
+ await initStore2({ lightweight: true });
4552
+ return getClient2();
4553
+ }
4554
+ var init_fast_db_init = __esm({
4555
+ "src/bin/fast-db-init.ts"() {
4556
+ "use strict";
4557
+ }
4558
+ });
4559
+
4261
4560
  // src/lib/active-agent.ts
4262
4561
  init_config();
4263
4562
  init_session_key();
@@ -4379,10 +4678,8 @@ process.stdin.on("end", async () => {
4379
4678
  if (canCoordinate(agent.agentId, agent.agentRole)) {
4380
4679
  process.exit(0);
4381
4680
  }
4382
- const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
4383
- await initStore2();
4384
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4385
- const client = getClient2();
4681
+ const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
4682
+ const client = await fastDbInit2();
4386
4683
  const saScope = sessionScopeFilter();
4387
4684
  const pendingResult = await client.execute({
4388
4685
  sql: `SELECT title, status FROM tasks WHERE assigned_to = ? AND status IN ('open', 'in_progress')${saScope.sql} ORDER BY status DESC, priority ASC`,
@@ -3050,8 +3050,8 @@ function getShardClient(projectName) {
3050
3050
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
3051
3051
  }
3052
3052
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3053
- if (!safeName) {
3054
- throw new Error(`Invalid project name for shard: "${projectName}"`);
3053
+ if (!safeName || safeName === "unknown") {
3054
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
3055
3055
  }
3056
3056
  const cached = _shards.get(safeName);
3057
3057
  if (cached) {
package/dist/index.js CHANGED
@@ -6892,8 +6892,8 @@ function getShardClient(projectName) {
6892
6892
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
6893
6893
  }
6894
6894
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
6895
- if (!safeName) {
6896
- throw new Error(`Invalid project name for shard: "${projectName}"`);
6895
+ if (!safeName || safeName === "unknown") {
6896
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
6897
6897
  }
6898
6898
  const cached = _shards.get(safeName);
6899
6899
  if (cached) {
@@ -7762,19 +7762,32 @@ async function flushBatch() {
7762
7762
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
7763
7763
  if (isShardingEnabled2()) {
7764
7764
  const byProject = /* @__PURE__ */ new Map();
7765
+ let skippedUnknown = 0;
7765
7766
  for (const row of batch) {
7766
- const proj = row.project_name || "unknown";
7767
+ const proj = row.project_name?.trim();
7768
+ if (!proj) {
7769
+ skippedUnknown++;
7770
+ continue;
7771
+ }
7767
7772
  if (!byProject.has(proj)) byProject.set(proj, []);
7768
7773
  byProject.get(proj).push(row);
7769
7774
  }
7775
+ if (skippedUnknown > 0) {
7776
+ process.stderr.write(
7777
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
7778
+ `
7779
+ );
7780
+ }
7770
7781
  for (const [project, rows] of byProject) {
7771
7782
  try {
7772
7783
  const shardClient = await getReadyShardClient2(project);
7773
7784
  const shardStmts = rows.map(buildStmt);
7774
7785
  await shardClient.batch(shardStmts, "write");
7775
7786
  } catch (err) {
7787
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
7788
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
7776
7789
  process.stderr.write(
7777
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
7790
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
7778
7791
  `
7779
7792
  );
7780
7793
  }
@@ -723,8 +723,8 @@ function getShardClient(projectName) {
723
723
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
724
724
  }
725
725
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
726
- if (!safeName) {
727
- throw new Error(`Invalid project name for shard: "${projectName}"`);
726
+ if (!safeName || safeName === "unknown") {
727
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
728
728
  }
729
729
  const cached = _shards.get(safeName);
730
730
  if (cached) {
@@ -4464,19 +4464,32 @@ async function flushBatch() {
4464
4464
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
4465
4465
  if (isShardingEnabled2()) {
4466
4466
  const byProject = /* @__PURE__ */ new Map();
4467
+ let skippedUnknown = 0;
4467
4468
  for (const row of batch) {
4468
- const proj = row.project_name || "unknown";
4469
+ const proj = row.project_name?.trim();
4470
+ if (!proj) {
4471
+ skippedUnknown++;
4472
+ continue;
4473
+ }
4469
4474
  if (!byProject.has(proj)) byProject.set(proj, []);
4470
4475
  byProject.get(proj).push(row);
4471
4476
  }
4477
+ if (skippedUnknown > 0) {
4478
+ process.stderr.write(
4479
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
4480
+ `
4481
+ );
4482
+ }
4472
4483
  for (const [project, rows] of byProject) {
4473
4484
  try {
4474
4485
  const shardClient = await getReadyShardClient2(project);
4475
4486
  const shardStmts = rows.map(buildStmt);
4476
4487
  await shardClient.batch(shardStmts, "write");
4477
4488
  } catch (err) {
4489
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
4490
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
4478
4491
  process.stderr.write(
4479
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
4492
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
4480
4493
  `
4481
4494
  );
4482
4495
  }
@@ -9330,8 +9343,8 @@ function createReviewNudgeRealDeps(getClient2) {
9330
9343
  return Number(result.rows[0]?.cnt ?? 0);
9331
9344
  },
9332
9345
  sendNudge: (sessionName) => {
9333
- const { getTransport: getTransport2 } = (init_transport(), __toCommonJS(transport_exports));
9334
- getTransport2().sendKeys(sessionName, "check reviews");
9346
+ const { queueIntercom: qi } = (init_intercom_queue(), __toCommonJS(intercom_queue_exports));
9347
+ qi(sessionName, "review nudge: pending reviews");
9335
9348
  },
9336
9349
  persistState: saveNudgeState
9337
9350
  };
@@ -12453,7 +12466,7 @@ function _resetNudgeState() {
12453
12466
  _lastNudge.clear();
12454
12467
  }
12455
12468
  async function runTaskEnforcementTick(deps) {
12456
- const { transport, agentConfig, employees, client, scopeFilter } = deps;
12469
+ const { transport, employees, client, scopeFilter } = deps;
12457
12470
  const now = deps.now ?? Date.now();
12458
12471
  const sessions = transport.listSessions();
12459
12472
  for (const session of sessions) {
@@ -12466,6 +12479,17 @@ async function runTaskEnforcementTick(deps) {
12466
12479
  }
12467
12480
  const employee = employees.find((e) => e.name === agentName);
12468
12481
  if (!employee) continue;
12482
+ let effectiveScope = scopeFilter;
12483
+ const dashIndex = session.indexOf("-");
12484
+ if (dashIndex > 0) {
12485
+ const coordinatorSession = session.slice(dashIndex + 1);
12486
+ if (coordinatorSession) {
12487
+ effectiveScope = {
12488
+ sql: " AND (session_scope IS NULL OR session_scope = ?)",
12489
+ args: [coordinatorSession]
12490
+ };
12491
+ }
12492
+ }
12469
12493
  const isManager = MANAGER_ROLES.includes(employee.role);
12470
12494
  try {
12471
12495
  let action = "skip";
@@ -12475,8 +12499,8 @@ async function runTaskEnforcementTick(deps) {
12475
12499
  let paneIdle;
12476
12500
  if (isManager) {
12477
12501
  const openResult = await client.execute({
12478
- sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status = 'open'${scopeFilter.sql}`,
12479
- args: [agentName, ...scopeFilter.args]
12502
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status = 'open'${effectiveScope.sql}`,
12503
+ args: [agentName, ...effectiveScope.args]
12480
12504
  });
12481
12505
  openTasks = Number(openResult.rows[0]?.cnt ?? 0);
12482
12506
  if (openTasks > 0) {
@@ -12528,8 +12552,8 @@ async function runTaskEnforcementTick(deps) {
12528
12552
  );
12529
12553
  } else {
12530
12554
  const taskResult = await client.execute({
12531
- sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status IN ('open', 'in_progress')${scopeFilter.sql}`,
12532
- args: [agentName, ...scopeFilter.args]
12555
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status IN ('open', 'in_progress')${effectiveScope.sql}`,
12556
+ args: [agentName, ...effectiveScope.args]
12533
12557
  });
12534
12558
  const taskCount = Number(taskResult.rows[0]?.cnt ?? 0);
12535
12559
  openTasks = taskCount;
@@ -12557,9 +12581,7 @@ async function runTaskEnforcementTick(deps) {
12557
12581
  );
12558
12582
  }
12559
12583
  if (action === "skip" || action === "idle" || action === "grace_period" || action === "active") continue;
12560
- const config = agentConfig[agentName];
12561
- const runtime = config?.runtime ?? "claude";
12562
- sendNudge(transport, session, runtime, action);
12584
+ queueIntercom(session, `enforcement: ${reason}`);
12563
12585
  _lastNudge.set(session, now);
12564
12586
  } catch {
12565
12587
  }
@@ -12569,6 +12591,7 @@ var TASK_ENFORCEMENT_INTERVAL_MS, TASK_ENFORCEMENT_DEBOUNCE_MS, MANAGER_GRACE_PE
12569
12591
  var init_task_enforcement = __esm({
12570
12592
  "src/lib/task-enforcement.ts"() {
12571
12593
  "use strict";
12594
+ init_intercom_queue();
12572
12595
  TASK_ENFORCEMENT_INTERVAL_MS = 6e4;
12573
12596
  TASK_ENFORCEMENT_DEBOUNCE_MS = 18e4;
12574
12597
  MANAGER_GRACE_PERIOD_MS = 6e5;
@@ -2911,8 +2911,8 @@ function getShardClient(projectName) {
2911
2911
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2912
2912
  }
2913
2913
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2914
- if (!safeName) {
2915
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2914
+ if (!safeName || safeName === "unknown") {
2915
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2916
2916
  }
2917
2917
  const cached = _shards.get(safeName);
2918
2918
  if (cached) {
@@ -3781,19 +3781,32 @@ async function flushBatch() {
3781
3781
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
3782
3782
  if (isShardingEnabled2()) {
3783
3783
  const byProject = /* @__PURE__ */ new Map();
3784
+ let skippedUnknown = 0;
3784
3785
  for (const row of batch) {
3785
- const proj = row.project_name || "unknown";
3786
+ const proj = row.project_name?.trim();
3787
+ if (!proj) {
3788
+ skippedUnknown++;
3789
+ continue;
3790
+ }
3786
3791
  if (!byProject.has(proj)) byProject.set(proj, []);
3787
3792
  byProject.get(proj).push(row);
3788
3793
  }
3794
+ if (skippedUnknown > 0) {
3795
+ process.stderr.write(
3796
+ `[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
3797
+ `
3798
+ );
3799
+ }
3789
3800
  for (const [project, rows] of byProject) {
3790
3801
  try {
3791
3802
  const shardClient = await getReadyShardClient2(project);
3792
3803
  const shardStmts = rows.map(buildStmt);
3793
3804
  await shardClient.batch(shardStmts, "write");
3794
3805
  } catch (err) {
3806
+ const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
3807
+ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
3795
3808
  process.stderr.write(
3796
- `[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
3809
+ `[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
3797
3810
  `
3798
3811
  );
3799
3812
  }
@@ -5209,10 +5222,12 @@ async function hybridSearch(queryText, agentId, options) {
5209
5222
  );
5210
5223
  }
5211
5224
  let rerankerAvailable = false;
5212
- try {
5213
- const { isRerankerAvailable: isRerankerAvailable2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
5214
- rerankerAvailable = isRerankerAvailable2();
5215
- } catch {
5225
+ if (process.env.EXE_IS_DAEMON === "1") {
5226
+ try {
5227
+ const { isRerankerAvailable: isRerankerAvailable2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
5228
+ rerankerAvailable = isRerankerAvailable2();
5229
+ } catch {
5230
+ }
5216
5231
  }
5217
5232
  const broadFetchTopK = config.scalingRoadmap?.rerankerAutoTrigger?.fetchTopK ?? 150;
5218
5233
  const fetchLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : rerankerAvailable ? Math.max(limit * 4, 60) : Math.max(limit * 3, 30);
@@ -2595,8 +2595,8 @@ function getShardClient(projectName) {
2595
2595
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2596
2596
  }
2597
2597
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2598
- if (!safeName) {
2599
- throw new Error(`Invalid project name for shard: "${projectName}"`);
2598
+ if (!safeName || safeName === "unknown") {
2599
+ throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2600
2600
  }
2601
2601
  const cached = _shards.get(safeName);
2602
2602
  if (cached) {