@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
@@ -666,6 +666,13 @@ async function ensureSchema() {
666
666
  });
667
667
  } catch {
668
668
  }
669
+ try {
670
+ await client.execute({
671
+ sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
672
+ args: []
673
+ });
674
+ } catch {
675
+ }
669
676
  try {
670
677
  await client.execute({
671
678
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
@@ -1112,6 +1119,18 @@ async function ensureSchema() {
1112
1119
  CREATE INDEX IF NOT EXISTS idx_session_kills_agent
1113
1120
  ON session_kills(agent_id);
1114
1121
  `);
1122
+ await client.execute(`
1123
+ CREATE TABLE IF NOT EXISTS global_procedures (
1124
+ id TEXT PRIMARY KEY,
1125
+ title TEXT NOT NULL,
1126
+ content TEXT NOT NULL,
1127
+ priority TEXT NOT NULL DEFAULT 'p0',
1128
+ domain TEXT,
1129
+ active INTEGER NOT NULL DEFAULT 1,
1130
+ created_at TEXT NOT NULL,
1131
+ updated_at TEXT NOT NULL
1132
+ )
1133
+ `);
1115
1134
  await client.executeMultiple(`
1116
1135
  CREATE TABLE IF NOT EXISTS conversations (
1117
1136
  id TEXT PRIMARY KEY,
@@ -1677,6 +1696,61 @@ var init_session_kill_telemetry = __esm({
1677
1696
  }
1678
1697
  });
1679
1698
 
1699
+ // src/lib/state-bus.ts
1700
+ var StateBus, orgBus;
1701
+ var init_state_bus = __esm({
1702
+ "src/lib/state-bus.ts"() {
1703
+ "use strict";
1704
+ StateBus = class {
1705
+ handlers = /* @__PURE__ */ new Map();
1706
+ globalHandlers = /* @__PURE__ */ new Set();
1707
+ /** Emit an event to all subscribers */
1708
+ emit(event) {
1709
+ const typeHandlers = this.handlers.get(event.type);
1710
+ if (typeHandlers) {
1711
+ for (const handler of typeHandlers) {
1712
+ try {
1713
+ handler(event);
1714
+ } catch {
1715
+ }
1716
+ }
1717
+ }
1718
+ for (const handler of this.globalHandlers) {
1719
+ try {
1720
+ handler(event);
1721
+ } catch {
1722
+ }
1723
+ }
1724
+ }
1725
+ /** Subscribe to a specific event type */
1726
+ on(type, handler) {
1727
+ if (!this.handlers.has(type)) {
1728
+ this.handlers.set(type, /* @__PURE__ */ new Set());
1729
+ }
1730
+ this.handlers.get(type).add(handler);
1731
+ }
1732
+ /** Subscribe to ALL events */
1733
+ onAny(handler) {
1734
+ this.globalHandlers.add(handler);
1735
+ }
1736
+ /** Unsubscribe from a specific event type */
1737
+ off(type, handler) {
1738
+ this.handlers.get(type)?.delete(handler);
1739
+ }
1740
+ /** Unsubscribe from ALL events */
1741
+ offAny(handler) {
1742
+ this.globalHandlers.delete(handler);
1743
+ }
1744
+ /** Remove all listeners */
1745
+ clear() {
1746
+ this.handlers.clear();
1747
+ this.globalHandlers.clear();
1748
+ }
1749
+ };
1750
+ orgBus = new StateBus();
1751
+ }
1752
+ });
1753
+
1680
1754
  // src/lib/tasks-crud.ts
1681
1755
  import crypto3 from "crypto";
1682
1756
  import path9 from "path";
@@ -1820,9 +1894,15 @@ async function createTaskCore(input) {
1820
1894
  }
1821
1895
  }
1822
1896
  const complexity = input.complexity ?? "standard";
1897
+ let sessionScope = null;
1898
+ try {
1899
+ const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
1900
+ sessionScope = resolveExeSession2();
1901
+ } catch {
1902
+ }
1823
1903
  await client.execute({
1824
- sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, created_at, updated_at)
1825
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1904
+ sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
1905
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1826
1906
  args: [
1827
1907
  id,
1828
1908
  input.title,
@@ -1841,6 +1921,7 @@ async function createTaskCore(input) {
1841
1921
  input.budgetFallbackModel ?? null,
1842
1922
  0,
1843
1923
  null,
1924
+ sessionScope,
1844
1925
  now,
1845
1926
  now
1846
1927
  ]
@@ -1885,9 +1966,18 @@ async function listTasks(input) {
1885
1966
  conditions.push("priority = ?");
1886
1967
  args.push(input.priority);
1887
1968
  }
1969
+ try {
1970
+ const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
1971
+ const session = resolveExeSession2();
1972
+ if (session) {
1973
+ conditions.push("(session_scope IS NULL OR session_scope = ?)");
1974
+ args.push(session);
1975
+ }
1976
+ } catch {
1977
+ }
1888
1978
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1889
1979
  const result = await client.execute({
1890
- sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC`,
1980
+ sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
1891
1981
  args
1892
1982
  });
1893
1983
  return result.rows.map((r) => ({
@@ -2108,6 +2198,34 @@ async function listPendingReviews(limit) {
2108
2198
  });
2109
2199
  return result.rows;
2110
2200
  }
2201
+ async function cleanupOrphanedReviews() {
2202
+ const client = getClient();
2203
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2204
+ const r1 = await client.execute({
2205
+ sql: `UPDATE tasks SET status = 'done', updated_at = ?
2206
+ WHERE status = 'needs_review'
2207
+ AND assigned_by = 'system'
2208
+ AND title LIKE 'Review:%'
2209
+ AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
2210
+ args: [now]
2211
+ });
2212
+ const staleThreshold = new Date(Date.now() - 60 * 60 * 1e3).toISOString();
2213
+ const r2 = await client.execute({
2214
+ sql: `UPDATE tasks SET status = 'done', updated_at = ?
2215
+ WHERE status = 'needs_review'
2216
+ AND result IS NOT NULL
2217
+ AND updated_at < ?`,
2218
+ args: [now, staleThreshold]
2219
+ });
2220
+ const total = r1.rowsAffected + r2.rowsAffected;
2221
+ if (total > 0) {
2222
+ process.stderr.write(
2223
+ `[cleanup] Closed ${total} orphaned review(s): ${r1.rowsAffected} cascade + ${r2.rowsAffected} stale
2224
+ `
2225
+ );
2226
+ }
2227
+ return total;
2228
+ }
2111
2229
  function getReviewChecklist(role, agent, taskSlug) {
2112
2230
  const roleLower = role.toLowerCase();
2113
2231
  if (roleLower.includes("engineer") || roleLower === "principal engineer") {
@@ -2221,6 +2339,7 @@ var init_tasks_review = __esm({
2221
2339
  init_tasks_crud();
2222
2340
  init_tmux_routing();
2223
2341
  init_session_key();
2342
+ init_state_bus();
2224
2343
  }
2225
2344
  });
2226
2345
 
@@ -2385,13 +2504,12 @@ function assertSessionScope(actionType, targetProject) {
2385
2504
  };
2386
2505
  }
2387
2506
  process.stderr.write(
2388
- `[session-scope] Cross-project ${actionType}: session project="${currentProject}" \u2260 target project="${targetProject}"
2507
+ `[session-scope] BLOCKED cross-project ${actionType}: session project="${currentProject}" \u2260 target project="${targetProject}"
2389
2508
  `
2390
2509
  );
2391
2510
  return {
2392
- allowed: true,
2393
- // v1: warn-only, don't block
2394
- reason: "cross_session_granted",
2511
+ allowed: false,
2512
+ reason: "cross_session_denied",
2395
2513
  currentProject,
2396
2514
  targetProject,
2397
2515
  targetSession: findSessionForProject(targetProject)?.windowName
@@ -2417,8 +2535,9 @@ async function dispatchTaskToEmployee(input) {
2417
2535
  try {
2418
2536
  const { assertSessionScope: assertSessionScope2 } = (init_session_scope(), __toCommonJS(session_scope_exports));
2419
2537
  const check = assertSessionScope2("dispatch_task", input.projectName);
2420
- if (check.reason === "cross_session_granted") {
2538
+ if (check.reason === "cross_session_denied") {
2421
2539
  crossProject = true;
2540
+ return { dispatched: "skipped", crossProject: true };
2422
2541
  }
2423
2542
  } catch {
2424
2543
  }
@@ -2849,6 +2968,7 @@ var init_skill_learning = __esm({
2849
2968
  // src/lib/tasks.ts
2850
2969
  var tasks_exports = {};
2851
2970
  __export(tasks_exports, {
2971
+ cleanupOrphanedReviews: () => cleanupOrphanedReviews,
2852
2972
  countNewPendingReviewsSince: () => countNewPendingReviewsSince,
2853
2973
  countPendingReviews: () => countPendingReviews,
2854
2974
  createTask: () => createTask,
@@ -2914,6 +3034,21 @@ async function updateTask(input) {
2914
3034
  });
2915
3035
  } catch {
2916
3036
  }
3037
+ try {
3038
+ const client = getClient();
3039
+ const cascaded = await client.execute({
3040
+ sql: `UPDATE tasks SET status = 'done', updated_at = ?
3041
+ WHERE parent_task_id = ? AND status = 'needs_review'`,
3042
+ args: [now, taskId]
3043
+ });
3044
+ if (cascaded.rowsAffected > 0) {
3045
+ process.stderr.write(
3046
+ `[cascade] Closed ${cascaded.rowsAffected} orphaned review task(s) for parent ${taskId}
3047
+ `
3048
+ );
3049
+ }
3050
+ } catch {
3051
+ }
2917
3052
  }
2918
3053
  const isTerminal = input.status === "done" || input.status === "needs_review";
2919
3054
  if (isTerminal) {
@@ -2927,6 +3062,13 @@ async function updateTask(input) {
2927
3062
  await cascadeUnblock(taskId, input.baseDir, now);
2928
3063
  } catch {
2929
3064
  }
3065
+ orgBus.emit({
3066
+ type: "task_completed",
3067
+ taskId,
3068
+ employee: String(row.assigned_to),
3069
+ result: input.result ?? "",
3070
+ timestamp: now
3071
+ });
2930
3072
  if (row.parent_task_id) {
2931
3073
  try {
2932
3074
  await checkSubtaskCompletion(String(row.parent_task_id), String(row.project_name));
@@ -2994,6 +3136,7 @@ var init_tasks = __esm({
2994
3136
  init_database();
2995
3137
  init_config();
2996
3138
  init_notifications();
3139
+ init_state_bus();
2997
3140
  init_tasks_crud();
2998
3141
  init_tasks_review();
2999
3142
  init_tasks_crud();
@@ -3384,8 +3527,28 @@ function getMySession() {
3384
3527
  return getTransport().getMySession();
3385
3528
  }
3386
3529
  function employeeSessionName(employee, exeSession, instance) {
3530
+ if (!/^exe\d+$/.test(exeSession)) {
3531
+ const root = extractRootExe(exeSession);
3532
+ if (root) {
3533
+ process.stderr.write(
3534
+ `[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
3535
+ `
3536
+ );
3537
+ exeSession = root;
3538
+ } else {
3539
+ throw new Error(
3540
+ `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
3541
+ );
3542
+ }
3543
+ }
3387
3544
  const suffix = instance != null && instance > 0 ? String(instance) : "";
3388
- return `${employee}${suffix}-${exeSession}`;
3545
+ const name = `${employee}${suffix}-${exeSession}`;
3546
+ if (!VALID_SESSION_NAME.test(name)) {
3547
+ throw new Error(
3548
+ `Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
3549
+ );
3550
+ }
3551
+ return name;
3389
3552
  }
3390
3553
  function parseParentExe(sessionName, agentId) {
3391
3554
  const escaped = agentId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -3625,6 +3788,22 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
3625
3788
  error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
3626
3789
  };
3627
3790
  }
3791
+ if (!/^exe\d+$/.test(exeSession)) {
3792
+ const root = extractRootExe(exeSession);
3793
+ if (root) {
3794
+ process.stderr.write(
3795
+ `[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
3796
+ `
3797
+ );
3798
+ exeSession = root;
3799
+ } else {
3800
+ return {
3801
+ status: "failed",
3802
+ sessionName: "",
3803
+ error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
3804
+ };
3805
+ }
3806
+ }
3628
3807
  let effectiveInstance = opts?.instance;
3629
3808
  if (effectiveInstance === void 0 && opts?.autoInstance) {
3630
3809
  const free = findFreeInstance(
@@ -3871,7 +4050,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
3871
4050
  releaseSpawnLock(sessionName);
3872
4051
  return { sessionName };
3873
4052
  }
3874
- var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
4053
+ var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
3875
4054
  var init_tmux_routing = __esm({
3876
4055
  "src/lib/tmux-routing.ts"() {
3877
4056
  "use strict";
@@ -3886,6 +4065,7 @@ var init_tmux_routing = __esm({
3886
4065
  SPAWN_LOCK_DIR = path14.join(os6.homedir(), ".exe-os", "spawn-locks");
3887
4066
  SESSION_CACHE = path14.join(os6.homedir(), ".exe-os", "session-cache");
3888
4067
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
4068
+ VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
3889
4069
  VERIFY_PANE_LINES = 200;
3890
4070
  INTERCOM_DEBOUNCE_MS = 3e4;
3891
4071
  INTERCOM_LOG2 = path14.join(os6.homedir(), ".exe-os", "intercom.log");
@@ -4195,6 +4375,71 @@ var init_shard_manager = __esm({
4195
4375
  }
4196
4376
  });
4197
4377
 
4378
+ // src/lib/global-procedures.ts
4379
+ var global_procedures_exports = {};
4380
+ __export(global_procedures_exports, {
4381
+ deactivateGlobalProcedure: () => deactivateGlobalProcedure,
4382
+ getGlobalProceduresBlock: () => getGlobalProceduresBlock,
4383
+ loadGlobalProcedures: () => loadGlobalProcedures,
4384
+ storeGlobalProcedure: () => storeGlobalProcedure
4385
+ });
4386
+ import { randomUUID as randomUUID3 } from "crypto";
4387
+ async function loadGlobalProcedures() {
4388
+ const client = getClient();
4389
+ const result = await client.execute({
4390
+ sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
4391
+ args: []
4392
+ });
4393
+ const procedures = result.rows;
4394
+ if (procedures.length > 0) {
4395
+ _cache = procedures.map((p) => `### ${p.title}
4396
+ ${p.content}`).join("\n\n");
4397
+ } else {
4398
+ _cache = "";
4399
+ }
4400
+ _cacheLoaded = true;
4401
+ return procedures;
4402
+ }
4403
+ function getGlobalProceduresBlock() {
4404
+ if (!_cacheLoaded) return "";
4405
+ if (!_cache) return "";
4406
+ return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
4407
+
4408
+ ${_cache}
4409
+ `;
4410
+ }
4411
+ async function storeGlobalProcedure(input) {
4412
+ const id = randomUUID3();
4413
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4414
+ const client = getClient();
4415
+ await client.execute({
4416
+ sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
4417
+ VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
4418
+ args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
4419
+ });
4420
+ await loadGlobalProcedures();
4421
+ return id;
4422
+ }
4423
+ async function deactivateGlobalProcedure(id) {
4424
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4425
+ const client = getClient();
4426
+ const result = await client.execute({
4427
+ sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
4428
+ args: [now, id]
4429
+ });
4430
+ await loadGlobalProcedures();
4431
+ return result.rowsAffected > 0;
4432
+ }
4433
+ var _cache, _cacheLoaded;
4434
+ var init_global_procedures = __esm({
4435
+ "src/lib/global-procedures.ts"() {
4436
+ "use strict";
4437
+ init_database();
4438
+ _cache = "";
4439
+ _cacheLoaded = false;
4440
+ }
4441
+ });
4442
+
4198
4443
  // src/lib/store.ts
4199
4444
  var store_exports = {};
4200
4445
  __export(store_exports, {
@@ -4274,6 +4519,11 @@ async function initStore(options) {
4274
4519
  "version-query"
4275
4520
  );
4276
4521
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
4522
+ try {
4523
+ const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
4524
+ await loadGlobalProcedures2();
4525
+ } catch {
4526
+ }
4277
4527
  }
4278
4528
  function classifyTier(record) {
4279
4529
  if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
@@ -4315,6 +4565,12 @@ async function writeMemory(record) {
4315
4565
  supersedes_id: record.supersedes_id ?? null
4316
4566
  };
4317
4567
  _pendingRecords.push(dbRow);
4568
+ orgBus.emit({
4569
+ type: "memory_stored",
4570
+ agentId: record.agent_id,
4571
+ project: record.project_name,
4572
+ timestamp: record.timestamp
4573
+ });
4318
4574
  const MAX_PENDING = 1e3;
4319
4575
  if (_pendingRecords.length > MAX_PENDING) {
4320
4576
  const dropped = _pendingRecords.length - MAX_PENDING;
@@ -4660,6 +4916,7 @@ var init_store = __esm({
4660
4916
  init_database();
4661
4917
  init_keychain();
4662
4918
  init_config();
4919
+ init_state_bus();
4663
4920
  INIT_MAX_RETRIES = 3;
4664
4921
  INIT_RETRY_DELAY_MS = 1e3;
4665
4922
  _pendingRecords = [];
@@ -6625,60 +6882,15 @@ function createQuietRenderer() {
6625
6882
  };
6626
6883
  }
6627
6884
 
6628
- // src/runtime/state-bus.ts
6629
- var StateBus = class {
6630
- handlers = /* @__PURE__ */ new Map();
6631
- globalHandlers = /* @__PURE__ */ new Set();
6632
- /** Emit an event to all subscribers */
6633
- emit(event) {
6634
- const typeHandlers = this.handlers.get(event.type);
6635
- if (typeHandlers) {
6636
- for (const handler of typeHandlers) {
6637
- try {
6638
- handler(event);
6639
- } catch {
6640
- }
6641
- }
6642
- }
6643
- for (const handler of this.globalHandlers) {
6644
- try {
6645
- handler(event);
6646
- } catch {
6647
- }
6648
- }
6649
- }
6650
- /** Subscribe to a specific event type */
6651
- on(type, handler) {
6652
- if (!this.handlers.has(type)) {
6653
- this.handlers.set(type, /* @__PURE__ */ new Set());
6654
- }
6655
- this.handlers.get(type).add(handler);
6656
- }
6657
- /** Subscribe to ALL events */
6658
- onAny(handler) {
6659
- this.globalHandlers.add(handler);
6660
- }
6661
- /** Unsubscribe from a specific event type */
6662
- off(type, handler) {
6663
- this.handlers.get(type)?.delete(handler);
6664
- }
6665
- /** Unsubscribe from ALL events */
6666
- offAny(handler) {
6667
- this.globalHandlers.delete(handler);
6668
- }
6669
- /** Remove all listeners */
6670
- clear() {
6671
- this.handlers.clear();
6672
- this.globalHandlers.clear();
6673
- }
6674
- };
6675
- var orgBus = new StateBus();
6885
+ // src/runtime/index.ts
6886
+ init_state_bus();
6676
6887
 
6677
6888
  // src/runtime/session-manager.ts
6678
- import { randomUUID as randomUUID4 } from "crypto";
6889
+ import { randomUUID as randomUUID5 } from "crypto";
6890
+ init_state_bus();
6679
6891
 
6680
6892
  // src/runtime/exe-hooks.ts
6681
- import { randomUUID as randomUUID3 } from "crypto";
6893
+ import { randomUUID as randomUUID4 } from "crypto";
6682
6894
  function createExeOSHooks(config) {
6683
6895
  let sessionRegistered = false;
6684
6896
  return {
@@ -6737,7 +6949,7 @@ function createExeOSHooks(config) {
6737
6949
  const toolResponse = result.isError ? { error: result.content } : { output: result.content };
6738
6950
  const rawText = extractSemanticText2(toolName, toolInput, toolResponse);
6739
6951
  await writeMemory2({
6740
- id: randomUUID3(),
6952
+ id: randomUUID4(),
6741
6953
  agent_id: config.agentId,
6742
6954
  agent_role: "employee",
6743
6955
  session_id: `api-${config.agentId}`,
@@ -6760,7 +6972,7 @@ function createExeOSHooks(config) {
6760
6972
  const { writeMemory: writeMemory2 } = await Promise.resolve().then(() => (init_store(), store_exports));
6761
6973
  if (summary) {
6762
6974
  await writeMemory2({
6763
- id: randomUUID3(),
6975
+ id: randomUUID4(),
6764
6976
  agent_id: config.agentId,
6765
6977
  agent_role: "employee",
6766
6978
  session_id: `api-${config.agentId}`,
@@ -6831,7 +7043,7 @@ function createExeOSHooks(config) {
6831
7043
  await client.execute({
6832
7044
  sql: `INSERT OR IGNORE INTO notifications (id, type, source_agent, message, task_file, created_at, read)
6833
7045
  VALUES (?, 'system', ?, ?, NULL, ?, 0)`,
6834
- args: [randomUUID3(), config.agentId, message.slice(0, 500), (/* @__PURE__ */ new Date()).toISOString()]
7046
+ args: [randomUUID4(), config.agentId, message.slice(0, 500), (/* @__PURE__ */ new Date()).toISOString()]
6835
7047
  });
6836
7048
  } catch {
6837
7049
  }
@@ -6847,7 +7059,7 @@ function createExeOSHooks(config) {
6847
7059
  try {
6848
7060
  const { writeMemory: writeMemory2 } = await Promise.resolve().then(() => (init_store(), store_exports));
6849
7061
  await writeMemory2({
6850
- id: randomUUID3(),
7062
+ id: randomUUID4(),
6851
7063
  agent_id: config.agentId,
6852
7064
  agent_role: "employee",
6853
7065
  session_id: `api-${config.agentId}`,
@@ -6869,7 +7081,7 @@ function createExeOSHooks(config) {
6869
7081
  try {
6870
7082
  const { writeMemory: writeMemory2 } = await Promise.resolve().then(() => (init_store(), store_exports));
6871
7083
  await writeMemory2({
6872
- id: randomUUID3(),
7084
+ id: randomUUID4(),
6873
7085
  agent_id: config.agentId,
6874
7086
  agent_role: "employee",
6875
7087
  session_id: `api-${config.agentId}`,
@@ -6906,7 +7118,7 @@ function createExeOSHooks(config) {
6906
7118
  if (tasks.rows.length > 0) {
6907
7119
  const taskList = tasks.rows.map((r) => `- [${String(r.status)}] ${String(r.title)} (${String(r.task_file)})`).join("\n");
6908
7120
  await writeMemory2({
6909
- id: randomUUID3(),
7121
+ id: randomUUID4(),
6910
7122
  agent_id: config.agentId,
6911
7123
  agent_role: "employee",
6912
7124
  session_id: `api-${config.agentId}`,
@@ -6932,7 +7144,7 @@ ${taskList}`,
6932
7144
  try {
6933
7145
  const { writeMemory: writeMemory2 } = await Promise.resolve().then(() => (init_store(), store_exports));
6934
7146
  await writeMemory2({
6935
- id: randomUUID3(),
7147
+ id: randomUUID4(),
6936
7148
  agent_id: config.agentId,
6937
7149
  agent_role: "employee",
6938
7150
  session_id: `api-${config.agentId}`,
@@ -6959,7 +7171,7 @@ var SessionManager = class {
6959
7171
  eventHandlers = /* @__PURE__ */ new Set();
6960
7172
  /** Start a new agent session for an employee */
6961
7173
  startSession(employeeId, config) {
6962
- const sessionId = randomUUID4();
7174
+ const sessionId = randomUUID5();
6963
7175
  const abortController = new AbortController();
6964
7176
  const session = {
6965
7177
  info: {