@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
@@ -20,6 +20,7 @@ var config_exports = {};
20
20
  __export(config_exports, {
21
21
  CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
22
22
  CONFIG_PATH: () => CONFIG_PATH,
23
+ COO_AGENT_NAME: () => COO_AGENT_NAME,
23
24
  CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
24
25
  DB_PATH: () => DB_PATH,
25
26
  EXE_AI_DIR: () => EXE_AI_DIR,
@@ -175,7 +176,7 @@ async function loadConfigFrom(configPath) {
175
176
  return { ...DEFAULT_CONFIG };
176
177
  }
177
178
  }
178
- var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
179
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
179
180
  var init_config = __esm({
180
181
  "src/lib/config.ts"() {
181
182
  "use strict";
@@ -183,6 +184,7 @@ var init_config = __esm({
183
184
  DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
184
185
  MODELS_DIR = path2.join(EXE_AI_DIR, "models");
185
186
  CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
187
+ COO_AGENT_NAME = "exe";
186
188
  LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
187
189
  CURRENT_CONFIG_VERSION = 1;
188
190
  DEFAULT_CONFIG = {
@@ -671,7 +673,8 @@ __export(cloud_sync_exports, {
671
673
  mergeRosterFromRemote: () => mergeRosterFromRemote,
672
674
  recordRosterDeletion: () => recordRosterDeletion
673
675
  });
674
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
676
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync, openSync, closeSync } from "fs";
677
+ import crypto3 from "crypto";
675
678
  import path6 from "path";
676
679
  import { homedir } from "os";
677
680
  function logError(msg) {
@@ -683,17 +686,29 @@ function logError(msg) {
683
686
  }
684
687
  }
685
688
  async function withRosterLock(fn) {
686
- if (existsSync6(ROSTER_LOCK_PATH)) {
687
- try {
688
- const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
689
- if (Date.now() - ts < LOCK_STALE_MS) {
689
+ try {
690
+ const fd = openSync(ROSTER_LOCK_PATH, "wx");
691
+ closeSync(fd);
692
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
693
+ } catch (err) {
694
+ if (err.code === "EEXIST") {
695
+ try {
696
+ const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
697
+ if (Date.now() - ts < LOCK_STALE_MS) {
698
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
699
+ }
700
+ unlinkSync(ROSTER_LOCK_PATH);
701
+ const fd = openSync(ROSTER_LOCK_PATH, "wx");
702
+ closeSync(fd);
703
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
704
+ } catch (retryErr) {
705
+ if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
690
706
  throw new Error("Roster merge already in progress \u2014 another sync is running");
691
707
  }
692
- } catch (err) {
693
- if (err instanceof Error && err.message.includes("already in progress")) throw err;
708
+ } else {
709
+ throw err;
694
710
  }
695
711
  }
696
- writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
697
712
  try {
698
713
  return await fn();
699
714
  } finally {
@@ -711,7 +726,7 @@ async function fetchWithRetry(url, init) {
711
726
  try {
712
727
  const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
713
728
  const resp = await fetch(url, { ...init, signal });
714
- if (resp.status >= 500 && attempt < MAX_RETRIES) {
729
+ if (resp && resp.status >= 500 && attempt < MAX_RETRIES) {
715
730
  await new Promise((r) => setTimeout(r, BASE_DELAY_MS * Math.pow(2, attempt)));
716
731
  continue;
717
732
  }
@@ -755,6 +770,10 @@ async function cloudPush(records, maxVersion, config) {
755
770
  },
756
771
  body: JSON.stringify({ version: maxVersion, blob })
757
772
  });
773
+ if (resp == null) {
774
+ logError("[cloud-sync] PUSH FAILED: no response from server");
775
+ return false;
776
+ }
758
777
  if (resp.status === 409) {
759
778
  logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
760
779
  return false;
@@ -777,6 +796,10 @@ async function cloudPull(sinceVersion, config) {
777
796
  },
778
797
  body: JSON.stringify({ since_version: sinceVersion })
779
798
  });
799
+ if (response == null) {
800
+ logError("[cloud-sync] PULL FAILED: no response from server");
801
+ return { records: [], maxVersion: sinceVersion };
802
+ }
780
803
  if (!response.ok) return { records: [], maxVersion: sinceVersion };
781
804
  const data = await response.json();
782
805
  const allRecords = [];
@@ -1015,7 +1038,7 @@ function buildRosterBlob(paths) {
1015
1038
  }
1016
1039
  const deletedNames = consumeRosterDeletions();
1017
1040
  const content = JSON.stringify({ roster, identities, config, deletedNames });
1018
- const hash = Buffer.from(content).length;
1041
+ const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
1019
1042
  return { roster, identities, config, deletedNames, version: hash };
1020
1043
  }
1021
1044
  async function cloudPushRoster(config) {
@@ -1684,8 +1707,17 @@ async function main() {
1684
1707
  }
1685
1708
  const mnemonic = exportMnemonic(key);
1686
1709
  console.log("Your 24-word recovery phrase:\n");
1687
- console.log(` ${mnemonic}
1710
+ const showFull = process.argv.includes("--show-full");
1711
+ if (showFull) {
1712
+ console.log(` ${mnemonic}
1688
1713
  `);
1714
+ } else {
1715
+ const words = mnemonic.split(" ");
1716
+ const masked = words.length > 4 ? [...words.slice(0, 2), ...words.slice(2, -2).map(() => "****"), ...words.slice(-2)].join(" ") : mnemonic;
1717
+ console.log(` ${masked}
1718
+ `);
1719
+ console.log("To reveal full phrase: run with --show-full\n");
1720
+ }
1689
1721
  console.log("Write this down and enter it on your new device with /exe-link import.");
1690
1722
  console.log("Anyone with this phrase can decrypt your memories.");
1691
1723
  console.log("\u26A0 Clear your terminal history after copying.");
@@ -890,6 +890,10 @@ function registerBinSymlinks(name) {
890
890
  return { created, skipped, errors };
891
891
  }
892
892
 
893
+ // src/lib/global-procedures.ts
894
+ init_database();
895
+ import { randomUUID } from "crypto";
896
+
893
897
  // src/lib/employee-templates.ts
894
898
  var TEMPLATE_VERSION = 1;
895
899
  var TEMPLATES = {
@@ -1236,7 +1240,7 @@ import path4 from "path";
1236
1240
  // src/lib/license.ts
1237
1241
  init_config();
1238
1242
  import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
1239
- import { randomUUID } from "crypto";
1243
+ import { randomUUID as randomUUID2 } from "crypto";
1240
1244
  import path3 from "path";
1241
1245
  import { jwtVerify, importSPKI } from "jose";
1242
1246
  var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
@@ -1289,7 +1293,7 @@ function loadDeviceId() {
1289
1293
  }
1290
1294
  } catch {
1291
1295
  }
1292
- const id = randomUUID();
1296
+ const id = randomUUID2();
1293
1297
  mkdirSync(EXE_AI_DIR, { recursive: true });
1294
1298
  writeFileSync(DEVICE_ID_PATH, id, "utf8");
1295
1299
  return id;
@@ -301,6 +301,13 @@ async function ensureSchema() {
301
301
  });
302
302
  } catch {
303
303
  }
304
+ try {
305
+ await client.execute({
306
+ sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
307
+ args: []
308
+ });
309
+ } catch {
310
+ }
304
311
  try {
305
312
  await client.execute({
306
313
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
@@ -747,6 +754,18 @@ async function ensureSchema() {
747
754
  CREATE INDEX IF NOT EXISTS idx_session_kills_agent
748
755
  ON session_kills(agent_id);
749
756
  `);
757
+ await client.execute(`
758
+ CREATE TABLE IF NOT EXISTS global_procedures (
759
+ id TEXT PRIMARY KEY,
760
+ title TEXT NOT NULL,
761
+ content TEXT NOT NULL,
762
+ priority TEXT NOT NULL DEFAULT 'p0',
763
+ domain TEXT,
764
+ active INTEGER NOT NULL DEFAULT 1,
765
+ created_at TEXT NOT NULL,
766
+ updated_at TEXT NOT NULL
767
+ )
768
+ `);
750
769
  await client.executeMultiple(`
751
770
  CREATE TABLE IF NOT EXISTS conversations (
752
771
  id TEXT PRIMARY KEY,
@@ -1085,6 +1104,61 @@ var init_config = __esm({
1085
1104
  }
1086
1105
  });
1087
1106
 
1107
+ // src/lib/state-bus.ts
1108
+ var StateBus, orgBus;
1109
+ var init_state_bus = __esm({
1110
+ "src/lib/state-bus.ts"() {
1111
+ "use strict";
1112
+ StateBus = class {
1113
+ handlers = /* @__PURE__ */ new Map();
1114
+ globalHandlers = /* @__PURE__ */ new Set();
1115
+ /** Emit an event to all subscribers */
1116
+ emit(event) {
1117
+ const typeHandlers = this.handlers.get(event.type);
1118
+ if (typeHandlers) {
1119
+ for (const handler of typeHandlers) {
1120
+ try {
1121
+ handler(event);
1122
+ } catch {
1123
+ }
1124
+ }
1125
+ }
1126
+ for (const handler of this.globalHandlers) {
1127
+ try {
1128
+ handler(event);
1129
+ } catch {
1130
+ }
1131
+ }
1132
+ }
1133
+ /** Subscribe to a specific event type */
1134
+ on(type, handler) {
1135
+ if (!this.handlers.has(type)) {
1136
+ this.handlers.set(type, /* @__PURE__ */ new Set());
1137
+ }
1138
+ this.handlers.get(type).add(handler);
1139
+ }
1140
+ /** Subscribe to ALL events */
1141
+ onAny(handler) {
1142
+ this.globalHandlers.add(handler);
1143
+ }
1144
+ /** Unsubscribe from a specific event type */
1145
+ off(type, handler) {
1146
+ this.handlers.get(type)?.delete(handler);
1147
+ }
1148
+ /** Unsubscribe from ALL events */
1149
+ offAny(handler) {
1150
+ this.globalHandlers.delete(handler);
1151
+ }
1152
+ /** Remove all listeners */
1153
+ clear() {
1154
+ this.handlers.clear();
1155
+ this.globalHandlers.clear();
1156
+ }
1157
+ };
1158
+ orgBus = new StateBus();
1159
+ }
1160
+ });
1161
+
1088
1162
  // src/lib/shard-manager.ts
1089
1163
  var shard_manager_exports = {};
1090
1164
  __export(shard_manager_exports, {
@@ -1326,6 +1400,71 @@ var init_shard_manager = __esm({
1326
1400
  }
1327
1401
  });
1328
1402
 
1403
+ // src/lib/global-procedures.ts
1404
+ var global_procedures_exports = {};
1405
+ __export(global_procedures_exports, {
1406
+ deactivateGlobalProcedure: () => deactivateGlobalProcedure,
1407
+ getGlobalProceduresBlock: () => getGlobalProceduresBlock,
1408
+ loadGlobalProcedures: () => loadGlobalProcedures,
1409
+ storeGlobalProcedure: () => storeGlobalProcedure
1410
+ });
1411
+ import { randomUUID } from "crypto";
1412
+ async function loadGlobalProcedures() {
1413
+ const client = getClient();
1414
+ const result = await client.execute({
1415
+ sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
1416
+ args: []
1417
+ });
1418
+ const procedures = result.rows;
1419
+ if (procedures.length > 0) {
1420
+ _cache = procedures.map((p) => `### ${p.title}
1421
+ ${p.content}`).join("\n\n");
1422
+ } else {
1423
+ _cache = "";
1424
+ }
1425
+ _cacheLoaded = true;
1426
+ return procedures;
1427
+ }
1428
+ function getGlobalProceduresBlock() {
1429
+ if (!_cacheLoaded) return "";
1430
+ if (!_cache) return "";
1431
+ return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
1432
+
1433
+ ${_cache}
1434
+ `;
1435
+ }
1436
+ async function storeGlobalProcedure(input) {
1437
+ const id = randomUUID();
1438
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1439
+ const client = getClient();
1440
+ await client.execute({
1441
+ sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
1442
+ VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
1443
+ args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
1444
+ });
1445
+ await loadGlobalProcedures();
1446
+ return id;
1447
+ }
1448
+ async function deactivateGlobalProcedure(id) {
1449
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1450
+ const client = getClient();
1451
+ const result = await client.execute({
1452
+ sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
1453
+ args: [now, id]
1454
+ });
1455
+ await loadGlobalProcedures();
1456
+ return result.rowsAffected > 0;
1457
+ }
1458
+ var _cache, _cacheLoaded;
1459
+ var init_global_procedures = __esm({
1460
+ "src/lib/global-procedures.ts"() {
1461
+ "use strict";
1462
+ init_database();
1463
+ _cache = "";
1464
+ _cacheLoaded = false;
1465
+ }
1466
+ });
1467
+
1329
1468
  // src/lib/session-registry.ts
1330
1469
  import path4 from "path";
1331
1470
  import os3 from "os";
@@ -1411,7 +1550,7 @@ var init_employees = __esm({
1411
1550
 
1412
1551
  // src/lib/license.ts
1413
1552
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1414
- import { randomUUID } from "crypto";
1553
+ import { randomUUID as randomUUID2 } from "crypto";
1415
1554
  import path7 from "path";
1416
1555
  import { jwtVerify, importSPKI } from "jose";
1417
1556
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
@@ -1513,6 +1652,7 @@ async function getMasterKey() {
1513
1652
 
1514
1653
  // src/lib/store.ts
1515
1654
  init_config();
1655
+ init_state_bus();
1516
1656
  var INIT_MAX_RETRIES = 3;
1517
1657
  var INIT_RETRY_DELAY_MS = 1e3;
1518
1658
  function isBusyError2(err) {
@@ -1583,6 +1723,11 @@ async function initStore(options) {
1583
1723
  "version-query"
1584
1724
  );
1585
1725
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1726
+ try {
1727
+ const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
1728
+ await loadGlobalProcedures2();
1729
+ } catch {
1730
+ }
1586
1731
  }
1587
1732
 
1588
1733
  // src/lib/messaging.ts