@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
@@ -6,7 +6,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  });
7
7
 
8
8
  // src/lib/cloud-sync.ts
9
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
9
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync, openSync, closeSync } from "fs";
10
+ import crypto2 from "crypto";
10
11
  import path5 from "path";
11
12
  import { homedir } from "os";
12
13
 
@@ -436,17 +437,29 @@ var PUSH_BATCH_SIZE = 5e3;
436
437
  var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
437
438
  var LOCK_STALE_MS = 3e4;
438
439
  async function withRosterLock(fn) {
439
- if (existsSync5(ROSTER_LOCK_PATH)) {
440
- try {
441
- const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
442
- if (Date.now() - ts < LOCK_STALE_MS) {
440
+ try {
441
+ const fd = openSync(ROSTER_LOCK_PATH, "wx");
442
+ closeSync(fd);
443
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
444
+ } catch (err) {
445
+ if (err.code === "EEXIST") {
446
+ try {
447
+ const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
448
+ if (Date.now() - ts < LOCK_STALE_MS) {
449
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
450
+ }
451
+ unlinkSync(ROSTER_LOCK_PATH);
452
+ const fd = openSync(ROSTER_LOCK_PATH, "wx");
453
+ closeSync(fd);
454
+ writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
455
+ } catch (retryErr) {
456
+ if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
443
457
  throw new Error("Roster merge already in progress \u2014 another sync is running");
444
458
  }
445
- } catch (err) {
446
- if (err instanceof Error && err.message.includes("already in progress")) throw err;
459
+ } else {
460
+ throw err;
447
461
  }
448
462
  }
449
- writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
450
463
  try {
451
464
  return await fn();
452
465
  } finally {
@@ -464,7 +477,7 @@ async function fetchWithRetry(url, init) {
464
477
  try {
465
478
  const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
466
479
  const resp = await fetch(url, { ...init, signal });
467
- if (resp.status >= 500 && attempt < MAX_RETRIES) {
480
+ if (resp && resp.status >= 500 && attempt < MAX_RETRIES) {
468
481
  await new Promise((r) => setTimeout(r, BASE_DELAY_MS * Math.pow(2, attempt)));
469
482
  continue;
470
483
  }
@@ -508,6 +521,10 @@ async function cloudPush(records, maxVersion, config) {
508
521
  },
509
522
  body: JSON.stringify({ version: maxVersion, blob })
510
523
  });
524
+ if (resp == null) {
525
+ logError("[cloud-sync] PUSH FAILED: no response from server");
526
+ return false;
527
+ }
511
528
  if (resp.status === 409) {
512
529
  logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
513
530
  return false;
@@ -530,6 +547,10 @@ async function cloudPull(sinceVersion, config) {
530
547
  },
531
548
  body: JSON.stringify({ since_version: sinceVersion })
532
549
  });
550
+ if (response == null) {
551
+ logError("[cloud-sync] PULL FAILED: no response from server");
552
+ return { records: [], maxVersion: sinceVersion };
553
+ }
533
554
  if (!response.ok) return { records: [], maxVersion: sinceVersion };
534
555
  const data = await response.json();
535
556
  const allRecords = [];
@@ -769,7 +790,7 @@ function buildRosterBlob(paths) {
769
790
  }
770
791
  const deletedNames = consumeRosterDeletions();
771
792
  const content = JSON.stringify({ roster, identities, config, deletedNames });
772
- const hash = Buffer.from(content).length;
793
+ const hash = crypto2.createHash("sha256").update(content).digest("hex").slice(0, 16);
773
794
  return { roster, identities, config, deletedNames, version: hash };
774
795
  }
775
796
  async function cloudPushRoster(config) {
@@ -23,6 +23,7 @@ var EXE_AI_DIR = resolveDataDir();
23
23
  var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
24
24
  var MODELS_DIR = path.join(EXE_AI_DIR, "models");
25
25
  var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
26
+ var COO_AGENT_NAME = "exe";
26
27
  var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
27
28
  var CURRENT_CONFIG_VERSION = 1;
28
29
  var DEFAULT_CONFIG = {
@@ -225,6 +226,7 @@ async function loadConfigFrom(configPath) {
225
226
  export {
226
227
  CONFIG_MIGRATIONS,
227
228
  CONFIG_PATH,
229
+ COO_AGENT_NAME,
228
230
  CURRENT_CONFIG_VERSION,
229
231
  DB_PATH,
230
232
  EXE_AI_DIR,
@@ -3,6 +3,22 @@ var __esm = (fn, res) => function __init() {
3
3
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
4
  };
5
5
 
6
+ // src/lib/db-retry.ts
7
+ var init_db_retry = __esm({
8
+ "src/lib/db-retry.ts"() {
9
+ "use strict";
10
+ }
11
+ });
12
+
13
+ // src/lib/database.ts
14
+ import { createClient } from "@libsql/client";
15
+ var init_database = __esm({
16
+ "src/lib/database.ts"() {
17
+ "use strict";
18
+ init_db_retry();
19
+ }
20
+ });
21
+
6
22
  // src/lib/config.ts
7
23
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
8
24
  import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
@@ -103,8 +119,8 @@ var init_config = __esm({
103
119
  // src/lib/consolidation.ts
104
120
  import { randomUUID } from "crypto";
105
121
 
106
- // src/lib/database.ts
107
- import { createClient } from "@libsql/client";
122
+ // src/lib/store.ts
123
+ init_database();
108
124
 
109
125
  // src/lib/keychain.ts
110
126
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
@@ -115,6 +131,57 @@ import crypto from "crypto";
115
131
 
116
132
  // src/lib/store.ts
117
133
  init_config();
134
+
135
+ // src/lib/state-bus.ts
136
+ var StateBus = class {
137
+ handlers = /* @__PURE__ */ new Map();
138
+ globalHandlers = /* @__PURE__ */ new Set();
139
+ /** Emit an event to all subscribers */
140
+ emit(event) {
141
+ const typeHandlers = this.handlers.get(event.type);
142
+ if (typeHandlers) {
143
+ for (const handler of typeHandlers) {
144
+ try {
145
+ handler(event);
146
+ } catch {
147
+ }
148
+ }
149
+ }
150
+ for (const handler of this.globalHandlers) {
151
+ try {
152
+ handler(event);
153
+ } catch {
154
+ }
155
+ }
156
+ }
157
+ /** Subscribe to a specific event type */
158
+ on(type, handler) {
159
+ if (!this.handlers.has(type)) {
160
+ this.handlers.set(type, /* @__PURE__ */ new Set());
161
+ }
162
+ this.handlers.get(type).add(handler);
163
+ }
164
+ /** Subscribe to ALL events */
165
+ onAny(handler) {
166
+ this.globalHandlers.add(handler);
167
+ }
168
+ /** Unsubscribe from a specific event type */
169
+ off(type, handler) {
170
+ this.handlers.get(type)?.delete(handler);
171
+ }
172
+ /** Unsubscribe from ALL events */
173
+ offAny(handler) {
174
+ this.globalHandlers.delete(handler);
175
+ }
176
+ /** Remove all listeners */
177
+ clear() {
178
+ this.handlers.clear();
179
+ this.globalHandlers.clear();
180
+ }
181
+ };
182
+ var orgBus = new StateBus();
183
+
184
+ // src/lib/store.ts
118
185
  function vectorToBlob(vector) {
119
186
  const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
120
187
  return JSON.stringify(Array.from(f32));
@@ -293,6 +293,13 @@ async function ensureSchema() {
293
293
  });
294
294
  } catch {
295
295
  }
296
+ try {
297
+ await client.execute({
298
+ sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
299
+ args: []
300
+ });
301
+ } catch {
302
+ }
296
303
  try {
297
304
  await client.execute({
298
305
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
@@ -739,6 +746,18 @@ async function ensureSchema() {
739
746
  CREATE INDEX IF NOT EXISTS idx_session_kills_agent
740
747
  ON session_kills(agent_id);
741
748
  `);
749
+ await client.execute(`
750
+ CREATE TABLE IF NOT EXISTS global_procedures (
751
+ id TEXT PRIMARY KEY,
752
+ title TEXT NOT NULL,
753
+ content TEXT NOT NULL,
754
+ priority TEXT NOT NULL DEFAULT 'p0',
755
+ domain TEXT,
756
+ active INTEGER NOT NULL DEFAULT 1,
757
+ created_at TEXT NOT NULL,
758
+ updated_at TEXT NOT NULL
759
+ )
760
+ `);
742
761
  await client.executeMultiple(`
743
762
  CREATE TABLE IF NOT EXISTS conversations (
744
763
  id TEXT PRIMARY KEY,
@@ -315,6 +315,13 @@ async function ensureSchema() {
315
315
  });
316
316
  } catch {
317
317
  }
318
+ try {
319
+ await client.execute({
320
+ sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
321
+ args: []
322
+ });
323
+ } catch {
324
+ }
318
325
  try {
319
326
  await client.execute({
320
327
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
@@ -761,6 +768,18 @@ async function ensureSchema() {
761
768
  CREATE INDEX IF NOT EXISTS idx_session_kills_agent
762
769
  ON session_kills(agent_id);
763
770
  `);
771
+ await client.execute(`
772
+ CREATE TABLE IF NOT EXISTS global_procedures (
773
+ id TEXT PRIMARY KEY,
774
+ title TEXT NOT NULL,
775
+ content TEXT NOT NULL,
776
+ priority TEXT NOT NULL DEFAULT 'p0',
777
+ domain TEXT,
778
+ active INTEGER NOT NULL DEFAULT 1,
779
+ created_at TEXT NOT NULL,
780
+ updated_at TEXT NOT NULL
781
+ )
782
+ `);
764
783
  await client.executeMultiple(`
765
784
  CREATE TABLE IF NOT EXISTS conversations (
766
785
  id TEXT PRIMARY KEY,
@@ -13,6 +13,7 @@ var config_exports = {};
13
13
  __export(config_exports, {
14
14
  CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
15
15
  CONFIG_PATH: () => CONFIG_PATH,
16
+ COO_AGENT_NAME: () => COO_AGENT_NAME,
16
17
  CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
17
18
  DB_PATH: () => DB_PATH,
18
19
  EXE_AI_DIR: () => EXE_AI_DIR,
@@ -168,7 +169,7 @@ async function loadConfigFrom(configPath) {
168
169
  return { ...DEFAULT_CONFIG };
169
170
  }
170
171
  }
171
- var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
172
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, COO_AGENT_NAME, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
172
173
  var init_config = __esm({
173
174
  "src/lib/config.ts"() {
174
175
  "use strict";
@@ -176,6 +177,7 @@ var init_config = __esm({
176
177
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
177
178
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
178
179
  CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
180
+ COO_AGENT_NAME = "exe";
179
181
  LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
180
182
  CURRENT_CONFIG_VERSION = 1;
181
183
  DEFAULT_CONFIG = {
@@ -1,3 +1,21 @@
1
+ // src/lib/global-procedures.ts
2
+ import { randomUUID } from "crypto";
3
+
4
+ // src/lib/database.ts
5
+ import { createClient } from "@libsql/client";
6
+
7
+ // src/lib/global-procedures.ts
8
+ var _cache = "";
9
+ var _cacheLoaded = false;
10
+ function getGlobalProceduresBlock() {
11
+ if (!_cacheLoaded) return "";
12
+ if (!_cache) return "";
13
+ return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
14
+
15
+ ${_cache}
16
+ `;
17
+ }
18
+
1
19
  // src/lib/employee-templates.ts
2
20
  var BASE_OPERATING_PROCEDURES = `
3
21
  EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES (above all work):
@@ -148,7 +166,8 @@ var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
148
166
  function getSessionPrompt(storedPrompt) {
149
167
  const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
150
168
  const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
151
- return `${rolePrompt}
169
+ const globalBlock = getGlobalProceduresBlock();
170
+ return `${globalBlock}${rolePrompt}
152
171
  ${BASE_OPERATING_PROCEDURES}`;
153
172
  }
154
173
  var TEMPLATES = {