@askexenow/exe-os 0.8.40 → 0.8.42

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 (78) hide show
  1. package/dist/bin/backfill-conversations.js +805 -642
  2. package/dist/bin/backfill-responses.js +804 -641
  3. package/dist/bin/backfill-vectors.js +791 -634
  4. package/dist/bin/cleanup-stale-review-tasks.js +788 -631
  5. package/dist/bin/cli.js +1376 -659
  6. package/dist/bin/exe-agent.js +20 -1
  7. package/dist/bin/exe-assign.js +1503 -1343
  8. package/dist/bin/exe-boot.js +2549 -1784
  9. package/dist/bin/exe-call.js +39 -1
  10. package/dist/bin/exe-cloud.js +12 -2
  11. package/dist/bin/exe-dispatch.js +39 -2
  12. package/dist/bin/exe-doctor.js +791 -634
  13. package/dist/bin/exe-export-behaviors.js +792 -637
  14. package/dist/bin/exe-forget.js +145 -0
  15. package/dist/bin/exe-gateway.js +2501 -1846
  16. package/dist/bin/exe-heartbeat.js +147 -1
  17. package/dist/bin/exe-kill.js +795 -640
  18. package/dist/bin/exe-launch-agent.js +2168 -2008
  19. package/dist/bin/exe-link.js +44 -12
  20. package/dist/bin/exe-new-employee.js +6 -2
  21. package/dist/bin/exe-pending-messages.js +146 -1
  22. package/dist/bin/exe-pending-notifications.js +788 -631
  23. package/dist/bin/exe-pending-reviews.js +176 -1
  24. package/dist/bin/exe-rename.js +23 -0
  25. package/dist/bin/exe-review.js +490 -327
  26. package/dist/bin/exe-search.js +157 -4
  27. package/dist/bin/exe-session-cleanup.js +2487 -403
  28. package/dist/bin/exe-settings.js +2 -1
  29. package/dist/bin/exe-status.js +474 -317
  30. package/dist/bin/exe-team.js +474 -317
  31. package/dist/bin/git-sweep.js +2691 -151
  32. package/dist/bin/graph-backfill.js +794 -637
  33. package/dist/bin/graph-export.js +798 -641
  34. package/dist/bin/scan-tasks.js +2951 -44
  35. package/dist/bin/setup.js +50 -26
  36. package/dist/bin/shard-migrate.js +792 -637
  37. package/dist/bin/wiki-sync.js +794 -637
  38. package/dist/gateway/index.js +2542 -1887
  39. package/dist/hooks/bug-report-worker.js +2118 -576
  40. package/dist/hooks/commit-complete.js +2690 -150
  41. package/dist/hooks/error-recall.js +157 -4
  42. package/dist/hooks/ingest-worker.js +1455 -803
  43. package/dist/hooks/instructions-loaded.js +151 -0
  44. package/dist/hooks/notification.js +153 -2
  45. package/dist/hooks/post-compact.js +164 -0
  46. package/dist/hooks/pre-compact.js +3073 -101
  47. package/dist/hooks/pre-tool-use.js +151 -0
  48. package/dist/hooks/prompt-ingest-worker.js +1670 -1509
  49. package/dist/hooks/prompt-submit.js +2650 -1074
  50. package/dist/hooks/response-ingest-worker.js +154 -6
  51. package/dist/hooks/session-end.js +153 -2
  52. package/dist/hooks/session-start.js +157 -4
  53. package/dist/hooks/stop.js +151 -0
  54. package/dist/hooks/subagent-stop.js +155 -2
  55. package/dist/hooks/summary-worker.js +190 -21
  56. package/dist/index.js +326 -102
  57. package/dist/lib/cloud-sync.js +31 -10
  58. package/dist/lib/config.js +2 -0
  59. package/dist/lib/consolidation.js +69 -2
  60. package/dist/lib/database.js +19 -0
  61. package/dist/lib/device-registry.js +19 -0
  62. package/dist/lib/embedder.js +3 -1
  63. package/dist/lib/employee-templates.js +20 -1
  64. package/dist/lib/exe-daemon.js +285 -18
  65. package/dist/lib/hybrid-search.js +157 -4
  66. package/dist/lib/messaging.js +39 -2
  67. package/dist/lib/schedules.js +792 -637
  68. package/dist/lib/store.js +796 -636
  69. package/dist/lib/tasks.js +1485 -918
  70. package/dist/lib/tmux-routing.js +194 -10
  71. package/dist/mcp/server.js +1643 -924
  72. package/dist/mcp/tools/create-task.js +2283 -829
  73. package/dist/mcp/tools/list-tasks.js +2788 -159
  74. package/dist/mcp/tools/send-message.js +39 -2
  75. package/dist/mcp/tools/update-task.js +79 -0
  76. package/dist/runtime/index.js +280 -68
  77. package/dist/tui/App.js +1485 -645
  78. package/package.json +3 -2
@@ -330,6 +330,13 @@ async function ensureSchema() {
330
330
  });
331
331
  } catch {
332
332
  }
333
+ try {
334
+ await client.execute({
335
+ sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
336
+ args: []
337
+ });
338
+ } catch {
339
+ }
333
340
  try {
334
341
  await client.execute({
335
342
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
@@ -776,6 +783,18 @@ async function ensureSchema() {
776
783
  CREATE INDEX IF NOT EXISTS idx_session_kills_agent
777
784
  ON session_kills(agent_id);
778
785
  `);
786
+ await client.execute(`
787
+ CREATE TABLE IF NOT EXISTS global_procedures (
788
+ id TEXT PRIMARY KEY,
789
+ title TEXT NOT NULL,
790
+ content TEXT NOT NULL,
791
+ priority TEXT NOT NULL DEFAULT 'p0',
792
+ domain TEXT,
793
+ active INTEGER NOT NULL DEFAULT 1,
794
+ created_at TEXT NOT NULL,
795
+ updated_at TEXT NOT NULL
796
+ )
797
+ `);
779
798
  await client.executeMultiple(`
780
799
  CREATE TABLE IF NOT EXISTS conversations (
781
800
  id TEXT PRIMARY KEY,
@@ -1085,6 +1104,7 @@ var config_exports = {};
1085
1104
  __export(config_exports, {
1086
1105
  CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
1087
1106
  CONFIG_PATH: () => CONFIG_PATH,
1107
+ COO_AGENT_NAME: () => COO_AGENT_NAME,
1088
1108
  CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
1089
1109
  DB_PATH: () => DB_PATH,
1090
1110
  EXE_AI_DIR: () => EXE_AI_DIR,
@@ -1240,7 +1260,7 @@ async function loadConfigFrom(configPath) {
1240
1260
  return { ...DEFAULT_CONFIG };
1241
1261
  }
1242
1262
  }
1243
- var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
1263
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
1244
1264
  var init_config = __esm({
1245
1265
  "src/lib/config.ts"() {
1246
1266
  "use strict";
@@ -1248,6 +1268,7 @@ var init_config = __esm({
1248
1268
  DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
1249
1269
  MODELS_DIR = path2.join(EXE_AI_DIR, "models");
1250
1270
  CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
1271
+ COO_AGENT_NAME = "exe";
1251
1272
  LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
1252
1273
  CURRENT_CONFIG_VERSION = 1;
1253
1274
  DEFAULT_CONFIG = {
@@ -1567,6 +1588,71 @@ var init_shard_manager = __esm({
1567
1588
  }
1568
1589
  });
1569
1590
 
1591
+ // src/lib/global-procedures.ts
1592
+ var global_procedures_exports = {};
1593
+ __export(global_procedures_exports, {
1594
+ deactivateGlobalProcedure: () => deactivateGlobalProcedure,
1595
+ getGlobalProceduresBlock: () => getGlobalProceduresBlock,
1596
+ loadGlobalProcedures: () => loadGlobalProcedures,
1597
+ storeGlobalProcedure: () => storeGlobalProcedure
1598
+ });
1599
+ import { randomUUID } from "crypto";
1600
+ async function loadGlobalProcedures() {
1601
+ const client = getClient();
1602
+ const result = await client.execute({
1603
+ sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
1604
+ args: []
1605
+ });
1606
+ const procedures = result.rows;
1607
+ if (procedures.length > 0) {
1608
+ _cache = procedures.map((p) => `### ${p.title}
1609
+ ${p.content}`).join("\n\n");
1610
+ } else {
1611
+ _cache = "";
1612
+ }
1613
+ _cacheLoaded = true;
1614
+ return procedures;
1615
+ }
1616
+ function getGlobalProceduresBlock() {
1617
+ if (!_cacheLoaded) return "";
1618
+ if (!_cache) return "";
1619
+ return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
1620
+
1621
+ ${_cache}
1622
+ `;
1623
+ }
1624
+ async function storeGlobalProcedure(input) {
1625
+ const id = randomUUID();
1626
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1627
+ const client = getClient();
1628
+ await client.execute({
1629
+ sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
1630
+ VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
1631
+ args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
1632
+ });
1633
+ await loadGlobalProcedures();
1634
+ return id;
1635
+ }
1636
+ async function deactivateGlobalProcedure(id) {
1637
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1638
+ const client = getClient();
1639
+ const result = await client.execute({
1640
+ sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
1641
+ args: [now, id]
1642
+ });
1643
+ await loadGlobalProcedures();
1644
+ return result.rowsAffected > 0;
1645
+ }
1646
+ var _cache, _cacheLoaded;
1647
+ var init_global_procedures = __esm({
1648
+ "src/lib/global-procedures.ts"() {
1649
+ "use strict";
1650
+ init_database();
1651
+ _cache = "";
1652
+ _cacheLoaded = false;
1653
+ }
1654
+ });
1655
+
1570
1656
  // src/lib/employees.ts
1571
1657
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1572
1658
  import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
@@ -1638,7 +1724,7 @@ var init_employees = __esm({
1638
1724
 
1639
1725
  // src/lib/license.ts
1640
1726
  import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1641
- import { randomUUID } from "crypto";
1727
+ import { randomUUID as randomUUID2 } from "crypto";
1642
1728
  import path6 from "path";
1643
1729
  import { jwtVerify, importSPKI } from "jose";
1644
1730
  async function fetchRetry(url, init) {
@@ -1665,7 +1751,7 @@ function loadDeviceId() {
1665
1751
  }
1666
1752
  } catch {
1667
1753
  }
1668
- const id = randomUUID();
1754
+ const id = randomUUID2();
1669
1755
  mkdirSync2(EXE_AI_DIR, { recursive: true });
1670
1756
  writeFileSync(DEVICE_ID_PATH, id, "utf8");
1671
1757
  return id;
@@ -1947,7 +2033,7 @@ var init_plan_limits = __esm({
1947
2033
  // src/lib/exe-daemon-client.ts
1948
2034
  import net from "net";
1949
2035
  import { spawn } from "child_process";
1950
- import { randomUUID as randomUUID2 } from "crypto";
2036
+ import { randomUUID as randomUUID3 } from "crypto";
1951
2037
  import { existsSync as existsSync8, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
1952
2038
  import path8 from "path";
1953
2039
  import { fileURLToPath } from "url";
@@ -2139,7 +2225,7 @@ function sendRequest(texts, priority) {
2139
2225
  resolve({ error: "Not connected" });
2140
2226
  return;
2141
2227
  }
2142
- const id = randomUUID2();
2228
+ const id = randomUUID3();
2143
2229
  const timer = setTimeout(() => {
2144
2230
  _pending.delete(id);
2145
2231
  resolve({ error: "Request timeout" });
@@ -2157,7 +2243,7 @@ function sendRequest(texts, priority) {
2157
2243
  async function pingDaemon() {
2158
2244
  if (!_socket || !_connected) return null;
2159
2245
  return new Promise((resolve) => {
2160
- const id = randomUUID2();
2246
+ const id = randomUUID3();
2161
2247
  const timer = setTimeout(() => {
2162
2248
  _pending.delete(id);
2163
2249
  resolve(null);
@@ -2458,7 +2544,8 @@ __export(cloud_sync_exports, {
2458
2544
  mergeRosterFromRemote: () => mergeRosterFromRemote,
2459
2545
  recordRosterDeletion: () => recordRosterDeletion
2460
2546
  });
2461
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, existsSync as existsSync9, readdirSync as readdirSync3, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3 } from "fs";
2547
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, existsSync as existsSync9, readdirSync as readdirSync3, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2 } from "fs";
2548
+ import crypto4 from "crypto";
2462
2549
  import path9 from "path";
2463
2550
  import { homedir } from "os";
2464
2551
  function logError(msg) {
@@ -2470,17 +2557,29 @@ function logError(msg) {
2470
2557
  }
2471
2558
  }
2472
2559
  async function withRosterLock(fn) {
2473
- if (existsSync9(ROSTER_LOCK_PATH)) {
2474
- try {
2475
- const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
2476
- if (Date.now() - ts < LOCK_STALE_MS) {
2560
+ try {
2561
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
2562
+ closeSync2(fd);
2563
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
2564
+ } catch (err) {
2565
+ if (err.code === "EEXIST") {
2566
+ try {
2567
+ const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
2568
+ if (Date.now() - ts < LOCK_STALE_MS) {
2569
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
2570
+ }
2571
+ unlinkSync3(ROSTER_LOCK_PATH);
2572
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
2573
+ closeSync2(fd);
2574
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
2575
+ } catch (retryErr) {
2576
+ if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
2477
2577
  throw new Error("Roster merge already in progress \u2014 another sync is running");
2478
2578
  }
2479
- } catch (err) {
2480
- if (err instanceof Error && err.message.includes("already in progress")) throw err;
2579
+ } else {
2580
+ throw err;
2481
2581
  }
2482
2582
  }
2483
- writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
2484
2583
  try {
2485
2584
  return await fn();
2486
2585
  } finally {
@@ -2498,7 +2597,7 @@ async function fetchWithRetry(url, init) {
2498
2597
  try {
2499
2598
  const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
2500
2599
  const resp = await fetch(url, { ...init, signal });
2501
- if (resp.status >= 500 && attempt < MAX_RETRIES2) {
2600
+ if (resp && resp.status >= 500 && attempt < MAX_RETRIES2) {
2502
2601
  await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
2503
2602
  continue;
2504
2603
  }
@@ -2542,6 +2641,10 @@ async function cloudPush(records, maxVersion, config) {
2542
2641
  },
2543
2642
  body: JSON.stringify({ version: maxVersion, blob })
2544
2643
  });
2644
+ if (resp == null) {
2645
+ logError("[cloud-sync] PUSH FAILED: no response from server");
2646
+ return false;
2647
+ }
2545
2648
  if (resp.status === 409) {
2546
2649
  logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
2547
2650
  return false;
@@ -2564,6 +2667,10 @@ async function cloudPull(sinceVersion, config) {
2564
2667
  },
2565
2668
  body: JSON.stringify({ since_version: sinceVersion })
2566
2669
  });
2670
+ if (response == null) {
2671
+ logError("[cloud-sync] PULL FAILED: no response from server");
2672
+ return { records: [], maxVersion: sinceVersion };
2673
+ }
2567
2674
  if (!response.ok) return { records: [], maxVersion: sinceVersion };
2568
2675
  const data = await response.json();
2569
2676
  const allRecords = [];
@@ -2802,7 +2909,7 @@ function buildRosterBlob(paths) {
2802
2909
  }
2803
2910
  const deletedNames = consumeRosterDeletions();
2804
2911
  const content = JSON.stringify({ roster, identities, config, deletedNames });
2805
- const hash = Buffer.from(content).length;
2912
+ const hash = crypto4.createHash("sha256").update(content).digest("hex").slice(0, 16);
2806
2913
  return { roster, identities, config, deletedNames, version: hash };
2807
2914
  }
2808
2915
  async function cloudPushRoster(config) {
@@ -3386,6 +3493,57 @@ init_memory();
3386
3493
  init_database();
3387
3494
  init_keychain();
3388
3495
  init_config();
3496
+
3497
+ // src/lib/state-bus.ts
3498
+ var StateBus = class {
3499
+ handlers = /* @__PURE__ */ new Map();
3500
+ globalHandlers = /* @__PURE__ */ new Set();
3501
+ /** Emit an event to all subscribers */
3502
+ emit(event) {
3503
+ const typeHandlers = this.handlers.get(event.type);
3504
+ if (typeHandlers) {
3505
+ for (const handler of typeHandlers) {
3506
+ try {
3507
+ handler(event);
3508
+ } catch {
3509
+ }
3510
+ }
3511
+ }
3512
+ for (const handler of this.globalHandlers) {
3513
+ try {
3514
+ handler(event);
3515
+ } catch {
3516
+ }
3517
+ }
3518
+ }
3519
+ /** Subscribe to a specific event type */
3520
+ on(type, handler) {
3521
+ if (!this.handlers.has(type)) {
3522
+ this.handlers.set(type, /* @__PURE__ */ new Set());
3523
+ }
3524
+ this.handlers.get(type).add(handler);
3525
+ }
3526
+ /** Subscribe to ALL events */
3527
+ onAny(handler) {
3528
+ this.globalHandlers.add(handler);
3529
+ }
3530
+ /** Unsubscribe from a specific event type */
3531
+ off(type, handler) {
3532
+ this.handlers.get(type)?.delete(handler);
3533
+ }
3534
+ /** Unsubscribe from ALL events */
3535
+ offAny(handler) {
3536
+ this.globalHandlers.delete(handler);
3537
+ }
3538
+ /** Remove all listeners */
3539
+ clear() {
3540
+ this.handlers.clear();
3541
+ this.globalHandlers.clear();
3542
+ }
3543
+ };
3544
+ var orgBus = new StateBus();
3545
+
3546
+ // src/lib/store.ts
3389
3547
  var INIT_MAX_RETRIES = 3;
3390
3548
  var INIT_RETRY_DELAY_MS = 1e3;
3391
3549
  function isBusyError2(err) {
@@ -3456,6 +3614,11 @@ async function initStore(options) {
3456
3614
  "version-query"
3457
3615
  );
3458
3616
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
3617
+ try {
3618
+ const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
3619
+ await loadGlobalProcedures2();
3620
+ } catch {
3621
+ }
3459
3622
  }
3460
3623
  function classifyTier(record) {
3461
3624
  if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
@@ -3497,6 +3660,12 @@ async function writeMemory(record) {
3497
3660
  supersedes_id: record.supersedes_id ?? null
3498
3661
  };
3499
3662
  _pendingRecords.push(dbRow);
3663
+ orgBus.emit({
3664
+ type: "memory_stored",
3665
+ agentId: record.agent_id,
3666
+ project: record.project_name,
3667
+ timestamp: record.timestamp
3668
+ });
3500
3669
  const MAX_PENDING = 1e3;
3501
3670
  if (_pendingRecords.length > MAX_PENDING) {
3502
3671
  const dropped = _pendingRecords.length - MAX_PENDING;
@@ -3653,7 +3822,7 @@ function vectorToBlob(vector) {
3653
3822
 
3654
3823
  // src/adapters/claude/hooks/summary-worker.ts
3655
3824
  init_database();
3656
- import crypto4 from "crypto";
3825
+ import crypto5 from "crypto";
3657
3826
 
3658
3827
  // src/lib/notifications.ts
3659
3828
  init_database();
@@ -3694,7 +3863,7 @@ async function writeNotification(notification) {
3694
3863
 
3695
3864
  // src/adapters/claude/hooks/summary-worker.ts
3696
3865
  import { execSync as execSync2 } from "child_process";
3697
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
3866
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, openSync as openSync3, closeSync as closeSync3 } from "fs";
3698
3867
  import path11 from "path";
3699
3868
  async function main() {
3700
3869
  const agentId = process.env.AGENT_ID ?? "default";
@@ -3764,7 +3933,7 @@ async function main() {
3764
3933
  process.exit(0);
3765
3934
  }
3766
3935
  await writeMemory({
3767
- id: crypto4.randomUUID(),
3936
+ id: crypto5.randomUUID(),
3768
3937
  agent_id: agentId,
3769
3938
  agent_role: agentRole,
3770
3939
  session_id: `auto-summary-${Date.now()}`,
@@ -3829,14 +3998,14 @@ async function main() {
3829
3998
  const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
3830
3999
  const bLogPath = path11.join(exeDir2, "workers.log");
3831
4000
  mkdirSync5(path11.dirname(bLogPath), { recursive: true });
3832
- const bLogFd = openSync2(bLogPath, "a");
4001
+ const bLogFd = openSync3(bLogPath, "a");
3833
4002
  const child = spawn2(process.execPath, [backfillPath], {
3834
4003
  detached: true,
3835
4004
  stdio: ["ignore", "ignore", bLogFd]
3836
4005
  });
3837
4006
  child.unref();
3838
4007
  try {
3839
- closeSync2(bLogFd);
4008
+ closeSync3(bLogFd);
3840
4009
  } catch {
3841
4010
  }
3842
4011
  process.stderr.write("[summary-worker] Spawned backfill job\n");