@askexenow/exe-os 0.8.32 → 0.8.36

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 (87) hide show
  1. package/dist/bin/backfill-conversations.js +332 -348
  2. package/dist/bin/backfill-responses.js +72 -12
  3. package/dist/bin/backfill-vectors.js +72 -12
  4. package/dist/bin/cleanup-stale-review-tasks.js +63 -3
  5. package/dist/bin/cli.js +1518 -1122
  6. package/dist/bin/exe-agent.js +4 -4
  7. package/dist/bin/exe-assign.js +80 -18
  8. package/dist/bin/exe-boot.js +408 -89
  9. package/dist/bin/exe-call.js +83 -24
  10. package/dist/bin/exe-dispatch.js +18 -10
  11. package/dist/bin/exe-doctor.js +63 -3
  12. package/dist/bin/exe-export-behaviors.js +64 -3
  13. package/dist/bin/exe-forget.js +69 -4
  14. package/dist/bin/exe-gateway.js +121 -36
  15. package/dist/bin/exe-heartbeat.js +77 -13
  16. package/dist/bin/exe-kill.js +64 -3
  17. package/dist/bin/exe-launch-agent.js +162 -35
  18. package/dist/bin/exe-link.js +946 -0
  19. package/dist/bin/exe-new-employee.js +121 -36
  20. package/dist/bin/exe-pending-messages.js +72 -7
  21. package/dist/bin/exe-pending-notifications.js +63 -3
  22. package/dist/bin/exe-pending-reviews.js +75 -10
  23. package/dist/bin/exe-rename.js +1287 -0
  24. package/dist/bin/exe-review.js +64 -4
  25. package/dist/bin/exe-search.js +79 -13
  26. package/dist/bin/exe-session-cleanup.js +91 -26
  27. package/dist/bin/exe-status.js +64 -4
  28. package/dist/bin/exe-team.js +64 -4
  29. package/dist/bin/git-sweep.js +71 -4
  30. package/dist/bin/graph-backfill.js +64 -3
  31. package/dist/bin/graph-export.js +64 -3
  32. package/dist/bin/install.js +3 -3
  33. package/dist/bin/scan-tasks.js +71 -4
  34. package/dist/bin/setup.js +156 -38
  35. package/dist/bin/shard-migrate.js +64 -3
  36. package/dist/bin/wiki-sync.js +64 -3
  37. package/dist/gateway/index.js +122 -37
  38. package/dist/hooks/bug-report-worker.js +209 -23
  39. package/dist/hooks/commit-complete.js +71 -4
  40. package/dist/hooks/error-recall.js +79 -13
  41. package/dist/hooks/ingest-worker.js +129 -43
  42. package/dist/hooks/instructions-loaded.js +71 -4
  43. package/dist/hooks/notification.js +71 -4
  44. package/dist/hooks/post-compact.js +71 -4
  45. package/dist/hooks/pre-compact.js +71 -4
  46. package/dist/hooks/pre-tool-use.js +413 -194
  47. package/dist/hooks/prompt-ingest-worker.js +82 -22
  48. package/dist/hooks/prompt-submit.js +103 -37
  49. package/dist/hooks/response-ingest-worker.js +87 -22
  50. package/dist/hooks/session-end.js +71 -4
  51. package/dist/hooks/session-start.js +79 -13
  52. package/dist/hooks/stop.js +71 -4
  53. package/dist/hooks/subagent-stop.js +71 -4
  54. package/dist/hooks/summary-worker.js +303 -50
  55. package/dist/index.js +134 -46
  56. package/dist/lib/cloud-sync.js +209 -15
  57. package/dist/lib/consolidation.js +4 -4
  58. package/dist/lib/database.js +64 -2
  59. package/dist/lib/device-registry.js +70 -3
  60. package/dist/lib/employee-templates.js +48 -22
  61. package/dist/lib/employees.js +34 -1
  62. package/dist/lib/exe-daemon.js +136 -53
  63. package/dist/lib/hybrid-search.js +79 -13
  64. package/dist/lib/identity-templates.js +57 -6
  65. package/dist/lib/identity.js +3 -3
  66. package/dist/lib/messaging.js +22 -14
  67. package/dist/lib/reminders.js +3 -3
  68. package/dist/lib/schedules.js +63 -3
  69. package/dist/lib/skill-learning.js +3 -3
  70. package/dist/lib/status-brief.js +63 -5
  71. package/dist/lib/store.js +64 -3
  72. package/dist/lib/task-router.js +4 -2
  73. package/dist/lib/tasks.js +48 -21
  74. package/dist/lib/tmux-routing.js +47 -20
  75. package/dist/mcp/server.js +727 -58
  76. package/dist/mcp/tools/complete-reminder.js +3 -3
  77. package/dist/mcp/tools/create-reminder.js +3 -3
  78. package/dist/mcp/tools/create-task.js +151 -24
  79. package/dist/mcp/tools/deactivate-behavior.js +3 -3
  80. package/dist/mcp/tools/list-reminders.js +3 -3
  81. package/dist/mcp/tools/list-tasks.js +17 -8
  82. package/dist/mcp/tools/send-message.js +24 -16
  83. package/dist/mcp/tools/update-task.js +25 -16
  84. package/dist/runtime/index.js +112 -24
  85. package/dist/tui/App.js +139 -36
  86. package/package.json +6 -2
  87. package/src/commands/exe/rename.md +12 -0
package/dist/tui/App.js CHANGED
@@ -39,6 +39,61 @@ var init_devtools = __esm({
39
39
  }
40
40
  });
41
41
 
42
+ // src/lib/db-retry.ts
43
+ function isBusyError(err) {
44
+ if (err instanceof Error) {
45
+ const msg = err.message.toLowerCase();
46
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
47
+ }
48
+ return false;
49
+ }
50
+ function delay(ms) {
51
+ return new Promise((resolve) => setTimeout(resolve, ms));
52
+ }
53
+ async function retryOnBusy(fn, label) {
54
+ let lastError;
55
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
56
+ try {
57
+ return await fn();
58
+ } catch (err) {
59
+ lastError = err;
60
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
61
+ throw err;
62
+ }
63
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
64
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
65
+ process.stderr.write(
66
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
67
+ `
68
+ );
69
+ await delay(backoff + jitter);
70
+ }
71
+ }
72
+ throw lastError;
73
+ }
74
+ function wrapWithRetry(client) {
75
+ return new Proxy(client, {
76
+ get(target, prop, receiver) {
77
+ if (prop === "execute") {
78
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
79
+ }
80
+ if (prop === "batch") {
81
+ return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
82
+ }
83
+ return Reflect.get(target, prop, receiver);
84
+ }
85
+ });
86
+ }
87
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
88
+ var init_db_retry = __esm({
89
+ "src/lib/db-retry.ts"() {
90
+ "use strict";
91
+ MAX_RETRIES = 3;
92
+ BASE_DELAY_MS = 200;
93
+ MAX_JITTER_MS = 300;
94
+ }
95
+ });
96
+
42
97
  // src/lib/database.ts
43
98
  var database_exports = {};
44
99
  __export(database_exports, {
@@ -46,6 +101,7 @@ __export(database_exports, {
46
101
  disposeTurso: () => disposeTurso,
47
102
  ensureSchema: () => ensureSchema,
48
103
  getClient: () => getClient,
104
+ getRawClient: () => getRawClient,
49
105
  initDatabase: () => initDatabase,
50
106
  initTurso: () => initTurso,
51
107
  isInitialized: () => isInitialized
@@ -55,6 +111,7 @@ async function initDatabase(config) {
55
111
  if (_client) {
56
112
  _client.close();
57
113
  _client = null;
114
+ _resilientClient = null;
58
115
  }
59
116
  const opts = {
60
117
  url: `file:${config.dbPath}`
@@ -63,20 +120,27 @@ async function initDatabase(config) {
63
120
  opts.encryptionKey = config.encryptionKey;
64
121
  }
65
122
  _client = createClient(opts);
123
+ _resilientClient = wrapWithRetry(_client);
66
124
  }
67
125
  function isInitialized() {
68
126
  return _client !== null;
69
127
  }
70
128
  function getClient() {
129
+ if (!_resilientClient) {
130
+ throw new Error("Database client not initialized. Call initDatabase() first.");
131
+ }
132
+ return _resilientClient;
133
+ }
134
+ function getRawClient() {
71
135
  if (!_client) {
72
136
  throw new Error("Database client not initialized. Call initDatabase() first.");
73
137
  }
74
138
  return _client;
75
139
  }
76
140
  async function ensureSchema() {
77
- const client = getClient();
141
+ const client = getRawClient();
78
142
  await client.execute("PRAGMA journal_mode = WAL");
79
- await client.execute("PRAGMA busy_timeout = 5000");
143
+ await client.execute("PRAGMA busy_timeout = 30000");
80
144
  try {
81
145
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
82
146
  } catch {
@@ -869,13 +933,16 @@ async function disposeDatabase() {
869
933
  if (_client) {
870
934
  _client.close();
871
935
  _client = null;
936
+ _resilientClient = null;
872
937
  }
873
938
  }
874
- var _client, initTurso, disposeTurso;
939
+ var _client, _resilientClient, initTurso, disposeTurso;
875
940
  var init_database = __esm({
876
941
  "src/lib/database.ts"() {
877
942
  "use strict";
943
+ init_db_retry();
878
944
  _client = null;
945
+ _resilientClient = null;
879
946
  initTurso = initDatabase;
880
947
  disposeTurso = disposeDatabase;
881
948
  }
@@ -3755,13 +3822,18 @@ __export(employees_exports, {
3755
3822
  EMPLOYEES_PATH: () => EMPLOYEES_PATH,
3756
3823
  addEmployee: () => addEmployee,
3757
3824
  getEmployee: () => getEmployee,
3825
+ getEmployeeByRole: () => getEmployeeByRole,
3826
+ getEmployeeNamesByRole: () => getEmployeeNamesByRole,
3827
+ hasRole: () => hasRole,
3828
+ isMultiInstance: () => isMultiInstance,
3758
3829
  loadEmployees: () => loadEmployees,
3830
+ loadEmployeesSync: () => loadEmployeesSync,
3759
3831
  registerBinSymlinks: () => registerBinSymlinks,
3760
3832
  saveEmployees: () => saveEmployees,
3761
3833
  validateEmployeeName: () => validateEmployeeName
3762
3834
  });
3763
3835
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
3764
- import { existsSync as existsSync5, symlinkSync, readlinkSync } from "fs";
3836
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync5 } from "fs";
3765
3837
  import { execSync as execSync3 } from "child_process";
3766
3838
  import path10 from "path";
3767
3839
  function validateEmployeeName(name) {
@@ -3794,9 +3866,36 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
3794
3866
  await mkdir2(path10.dirname(employeesPath), { recursive: true });
3795
3867
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
3796
3868
  }
3869
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
3870
+ if (!existsSync5(employeesPath)) return [];
3871
+ try {
3872
+ return JSON.parse(readFileSync5(employeesPath, "utf-8"));
3873
+ } catch {
3874
+ return [];
3875
+ }
3876
+ }
3797
3877
  function getEmployee(employees, name) {
3798
3878
  return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
3799
3879
  }
3880
+ function getEmployeeByRole(employees, role) {
3881
+ const lower = role.toLowerCase();
3882
+ return employees.find((e) => e.role.toLowerCase() === lower);
3883
+ }
3884
+ function getEmployeeNamesByRole(employees, role) {
3885
+ const lower = role.toLowerCase();
3886
+ return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
3887
+ }
3888
+ function hasRole(agentName, role) {
3889
+ const employees = loadEmployeesSync();
3890
+ const emp = getEmployee(employees, agentName);
3891
+ return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
3892
+ }
3893
+ function isMultiInstance(agentName, employees) {
3894
+ const roster = employees ?? loadEmployeesSync();
3895
+ const emp = getEmployee(roster, agentName);
3896
+ if (!emp) return false;
3897
+ return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
3898
+ }
3800
3899
  function addEmployee(employees, employee) {
3801
3900
  const normalized = { ...employee, name: employee.name.toLowerCase() };
3802
3901
  if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
@@ -3839,12 +3938,13 @@ function registerBinSymlinks(name) {
3839
3938
  }
3840
3939
  return { created, skipped, errors };
3841
3940
  }
3842
- var EMPLOYEES_PATH;
3941
+ var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
3843
3942
  var init_employees = __esm({
3844
3943
  "src/lib/employees.ts"() {
3845
3944
  "use strict";
3846
3945
  init_config();
3847
3946
  EMPLOYEES_PATH = path10.join(EXE_AI_DIR, "exe-employees.json");
3947
+ MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
3848
3948
  }
3849
3949
  });
3850
3950
 
@@ -3918,12 +4018,14 @@ var init_task_router = __esm({
3918
4018
  },
3919
4019
  tierRules: {
3920
4020
  junior: {
3921
- eligible: ["tom"],
4021
+ eligible: [],
4022
+ // resolved dynamically from roster (Principal Engineer role)
3922
4023
  reviewRequired: false,
3923
4024
  manualOnly: false
3924
4025
  },
3925
4026
  standard: {
3926
- eligible: ["tom"],
4027
+ eligible: [],
4028
+ // resolved dynamically from roster (Principal Engineer role)
3927
4029
  reviewRequired: false,
3928
4030
  manualOnly: false
3929
4031
  },
@@ -4167,7 +4269,7 @@ var init_provider_table = __esm({
4167
4269
  });
4168
4270
 
4169
4271
  // src/lib/intercom-queue.ts
4170
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
4272
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
4171
4273
  import path11 from "path";
4172
4274
  import os4 from "os";
4173
4275
  function ensureDir() {
@@ -4177,7 +4279,7 @@ function ensureDir() {
4177
4279
  function readQueue() {
4178
4280
  try {
4179
4281
  if (!existsSync6(QUEUE_PATH)) return [];
4180
- return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
4282
+ return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
4181
4283
  } catch {
4182
4284
  return [];
4183
4285
  }
@@ -4216,12 +4318,12 @@ var init_intercom_queue = __esm({
4216
4318
  });
4217
4319
 
4218
4320
  // src/lib/plan-limits.ts
4219
- import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
4321
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
4220
4322
  import path12 from "path";
4221
4323
  function getLicenseSync() {
4222
4324
  try {
4223
4325
  if (!existsSync7(CACHE_PATH2)) return freeLicense();
4224
- const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
4326
+ const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
4225
4327
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
4226
4328
  const parts = raw.token.split(".");
4227
4329
  if (parts.length !== 3) return freeLicense();
@@ -4260,7 +4362,7 @@ function assertEmployeeLimitSync(rosterPath) {
4260
4362
  let count = 0;
4261
4363
  try {
4262
4364
  if (existsSync7(filePath)) {
4263
- const raw = readFileSync6(filePath, "utf8");
4365
+ const raw = readFileSync7(filePath, "utf8");
4264
4366
  const employees = JSON.parse(raw);
4265
4367
  count = Array.isArray(employees) ? employees.length : 0;
4266
4368
  }
@@ -4298,7 +4400,7 @@ import crypto from "crypto";
4298
4400
  import path13 from "path";
4299
4401
  import os5 from "os";
4300
4402
  import {
4301
- readFileSync as readFileSync7,
4403
+ readFileSync as readFileSync8,
4302
4404
  readdirSync,
4303
4405
  unlinkSync,
4304
4406
  existsSync as existsSync8,
@@ -4384,7 +4486,7 @@ import crypto3 from "crypto";
4384
4486
  import path14 from "path";
4385
4487
  import { execSync as execSync6 } from "child_process";
4386
4488
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
4387
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
4489
+ import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
4388
4490
  async function writeCheckpoint(input) {
4389
4491
  const client = getClient();
4390
4492
  const row = await resolveTask(client, input.taskId);
@@ -4761,7 +4863,7 @@ async function ensureGitignoreExe(baseDir) {
4761
4863
  const gitignorePath = path14.join(baseDir, ".gitignore");
4762
4864
  try {
4763
4865
  if (existsSync9(gitignorePath)) {
4764
- const content = readFileSync8(gitignorePath, "utf-8");
4866
+ const content = readFileSync9(gitignorePath, "utf-8");
4765
4867
  if (/^\/?exe\/?$/m.test(content)) return;
4766
4868
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
4767
4869
  } else {
@@ -5137,7 +5239,7 @@ async function dispatchTaskToEmployee(input) {
5137
5239
  } else {
5138
5240
  const projectDir = input.projectDir ?? process.cwd();
5139
5241
  const result = ensureEmployee(input.assignedTo, exeSession, projectDir, {
5140
- autoInstance: input.assignedTo === "tom" || input.assignedTo === "sasha"
5242
+ autoInstance: isMultiInstance(input.assignedTo)
5141
5243
  });
5142
5244
  if (result.status === "failed") {
5143
5245
  process.stderr.write(
@@ -5172,6 +5274,7 @@ var init_tasks_notify = __esm({
5172
5274
  init_session_key();
5173
5275
  init_notifications();
5174
5276
  init_transport();
5277
+ init_employees();
5175
5278
  }
5176
5279
  });
5177
5280
 
@@ -5945,7 +6048,7 @@ __export(tmux_routing_exports, {
5945
6048
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
5946
6049
  });
5947
6050
  import { execFileSync as execFileSync3, execSync as execSync8 } from "child_process";
5948
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
6051
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
5949
6052
  import path19 from "path";
5950
6053
  import os6 from "os";
5951
6054
  import { fileURLToPath } from "url";
@@ -6012,7 +6115,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6012
6115
  }
6013
6116
  function getParentExe(sessionKey) {
6014
6117
  try {
6015
- const data = JSON.parse(readFileSync9(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6118
+ const data = JSON.parse(readFileSync10(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6016
6119
  return data.parentExe || null;
6017
6120
  } catch {
6018
6121
  return null;
@@ -6020,7 +6123,7 @@ function getParentExe(sessionKey) {
6020
6123
  }
6021
6124
  function getDispatchedBy(sessionKey) {
6022
6125
  try {
6023
- const data = JSON.parse(readFileSync9(
6126
+ const data = JSON.parse(readFileSync10(
6024
6127
  path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6025
6128
  "utf8"
6026
6129
  ));
@@ -6083,7 +6186,7 @@ async function verifyPaneAtCapacity(sessionName) {
6083
6186
  function readDebounceState() {
6084
6187
  try {
6085
6188
  if (!existsSync11(DEBOUNCE_FILE)) return {};
6086
- return JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
6189
+ return JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
6087
6190
  } catch {
6088
6191
  return {};
6089
6192
  }
@@ -6283,7 +6386,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6283
6386
  const claudeJsonPath = path19.join(os6.homedir(), ".claude.json");
6284
6387
  let claudeJson = {};
6285
6388
  try {
6286
- claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
6389
+ claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
6287
6390
  } catch {
6288
6391
  }
6289
6392
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -6301,7 +6404,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6301
6404
  const settingsPath = path19.join(projSettingsDir, "settings.json");
6302
6405
  let settings = {};
6303
6406
  try {
6304
- settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
6407
+ settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
6305
6408
  } catch {
6306
6409
  }
6307
6410
  const perms = settings.permissions ?? {};
@@ -7370,7 +7473,7 @@ function listShards() {
7370
7473
  }
7371
7474
  async function ensureShardSchema(client) {
7372
7475
  await client.execute("PRAGMA journal_mode = WAL");
7373
- await client.execute("PRAGMA busy_timeout = 5000");
7476
+ await client.execute("PRAGMA busy_timeout = 30000");
7374
7477
  try {
7375
7478
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
7376
7479
  } catch {
@@ -14635,7 +14738,7 @@ function CommandCenterView({
14635
14738
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
14636
14739
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
14637
14740
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
14638
- const { readFileSync: readFileSync10, existsSync: existsSync14 } = await import("fs");
14741
+ const { readFileSync: readFileSync11, existsSync: existsSync14 } = await import("fs");
14639
14742
  const { join } = await import("path");
14640
14743
  const { homedir } = await import("os");
14641
14744
  const configPath = join(homedir(), ".exe-os", "config.json");
@@ -14643,7 +14746,7 @@ function CommandCenterView({
14643
14746
  let providerConfigs = {};
14644
14747
  if (existsSync14(configPath)) {
14645
14748
  try {
14646
- const raw = JSON.parse(readFileSync10(configPath, "utf8"));
14749
+ const raw = JSON.parse(readFileSync11(configPath, "utf8"));
14647
14750
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
14648
14751
  if (raw.providers && typeof raw.providers === "object") {
14649
14752
  providerConfigs = raw.providers;
@@ -14704,7 +14807,7 @@ function CommandCenterView({
14704
14807
  const markerDir = join(homedir(), ".exe-os", "session-cache");
14705
14808
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
14706
14809
  for (const f of agentFiles) {
14707
- const data = JSON.parse(readFileSync10(join(markerDir, f), "utf8"));
14810
+ const data = JSON.parse(readFileSync11(join(markerDir, f), "utf8"));
14708
14811
  if (data.agentRole) {
14709
14812
  agentRole = data.agentRole;
14710
14813
  break;
@@ -16397,12 +16500,12 @@ async function loadGatewayConfig() {
16397
16500
  state.running = false;
16398
16501
  }
16399
16502
  try {
16400
- const { existsSync: existsSync14, readFileSync: readFileSync10 } = await import("fs");
16503
+ const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
16401
16504
  const { join } = await import("path");
16402
16505
  const home = process.env.HOME ?? "";
16403
16506
  const configPath = join(home, ".exe-os", "gateway.json");
16404
16507
  if (existsSync14(configPath)) {
16405
- const raw = JSON.parse(readFileSync10(configPath, "utf8"));
16508
+ const raw = JSON.parse(readFileSync11(configPath, "utf8"));
16406
16509
  state.port = raw.port ?? 3100;
16407
16510
  state.gatewayUrl = raw.gatewayUrl ?? "";
16408
16511
  if (raw.adapters) {
@@ -16872,12 +16975,12 @@ function TeamView({ onBack }) {
16872
16975
  setMembers(teamData);
16873
16976
  setDbError(false);
16874
16977
  try {
16875
- const { existsSync: existsSync14, readFileSync: readFileSync10 } = await import("fs");
16978
+ const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
16876
16979
  const { join } = await import("path");
16877
16980
  const home = process.env.HOME ?? "";
16878
16981
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
16879
16982
  if (existsSync14(gatewayConfig)) {
16880
- const raw = JSON.parse(readFileSync10(gatewayConfig, "utf8"));
16983
+ const raw = JSON.parse(readFileSync11(gatewayConfig, "utf8"));
16881
16984
  if (raw.agents && raw.agents.length > 0) {
16882
16985
  setExternals(raw.agents.map((a) => ({
16883
16986
  name: a.name,
@@ -17413,14 +17516,14 @@ function SettingsView({ onBack }) {
17413
17516
  try {
17414
17517
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
17415
17518
  const roster = await loadEmployees2();
17416
- const { existsSync: existsSync14, readFileSync: readFileSync10 } = await import("fs");
17519
+ const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
17417
17520
  const { join } = await import("path");
17418
17521
  const home = process.env.HOME ?? "";
17419
17522
  const configPath = join(home, ".exe-os", "config.json");
17420
17523
  let empConfig = {};
17421
17524
  if (existsSync14(configPath)) {
17422
17525
  try {
17423
- const raw = JSON.parse(readFileSync10(configPath, "utf8"));
17526
+ const raw = JSON.parse(readFileSync11(configPath, "utf8"));
17424
17527
  if (raw.employees && typeof raw.employees === "object") {
17425
17528
  empConfig = raw.employees;
17426
17529
  }
@@ -17435,7 +17538,7 @@ function SettingsView({ onBack }) {
17435
17538
  } catch {
17436
17539
  }
17437
17540
  try {
17438
- const { existsSync: existsSync14, readFileSync: readFileSync10 } = await import("fs");
17541
+ const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
17439
17542
  const { join } = await import("path");
17440
17543
  const home = process.env.HOME ?? "";
17441
17544
  const ccSettingsPath = join(home, ".claude", "settings.json");
@@ -17443,7 +17546,7 @@ function SettingsView({ onBack }) {
17443
17546
  let hooksWired = false;
17444
17547
  if (installed) {
17445
17548
  try {
17446
- const settings = JSON.parse(readFileSync10(ccSettingsPath, "utf8"));
17549
+ const settings = JSON.parse(readFileSync11(ccSettingsPath, "utf8"));
17447
17550
  const hooks = settings.hooks;
17448
17551
  if (hooks) {
17449
17552
  hooksWired = Object.values(hooks).flat().some((h) => h.command?.includes("exe-os") || h.command?.includes("exe-mem"));
@@ -17455,13 +17558,13 @@ function SettingsView({ onBack }) {
17455
17558
  } catch {
17456
17559
  }
17457
17560
  try {
17458
- const { existsSync: existsSync14, readFileSync: readFileSync10 } = await import("fs");
17561
+ const { existsSync: existsSync14, readFileSync: readFileSync11 } = await import("fs");
17459
17562
  const { join } = await import("path");
17460
17563
  const home = process.env.HOME ?? "";
17461
17564
  const licensePath = join(home, ".exe-os", "license.json");
17462
17565
  if (existsSync14(licensePath)) {
17463
17566
  try {
17464
- const lic = JSON.parse(readFileSync10(licensePath, "utf8"));
17567
+ const lic = JSON.parse(readFileSync11(licensePath, "utf8"));
17465
17568
  setLicense({ valid: lic.valid !== false, detail: lic.plan ?? "licensed" });
17466
17569
  } catch {
17467
17570
  setLicense({ valid: false, detail: "invalid license file" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.8.32",
3
+ "version": "0.8.36",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "CC-BY-NC-4.0",
6
6
  "type": "module",
@@ -27,6 +27,7 @@
27
27
  "exe-os-install": "./dist/bin/install.js",
28
28
  "exe-agent": "./dist/bin/exe-agent.js",
29
29
  "exe-os-backfill-responses": "./dist/bin/backfill-responses.js",
30
+ "exe-os-backfill-conversations": "./dist/bin/backfill-conversations.js",
30
31
  "exe-os-repo-drift": "./dist/bin/exe-repo-drift.js",
31
32
  "exe-kill": "./dist/bin/exe-kill.js",
32
33
  "exe-os-list-providers": "./dist/bin/list-providers.js",
@@ -65,7 +66,7 @@
65
66
  "test:watch": "vitest",
66
67
  "typecheck": "tsc --noEmit",
67
68
  "build": "tsup",
68
- "deploy": "tsup && npm install -g . && node dist/bin/install.js --global",
69
+ "deploy": "node dist/bin/pre-build-guard.js 2>/dev/null; tsup && npm install -g . && node dist/bin/install.js --global && echo '[exe-os] Deploy complete. MCP servers will auto-reconnect on next tool call.'",
69
70
  "postinstall": "node dist/bin/install.js --global 2>/dev/null || true",
70
71
  "prepublishOnly": "npm run typecheck && npm run build && npx vitest run --exclude 'tests/tui/**' --exclude 'tests/lib/tmux-routing.test.ts' --exclude 'tests/lib/intercom-routing.test.ts' --exclude 'tests/gateway/**' --exclude 'tests/installer/setup-wizard.test.ts' --exclude 'tests/mcp/ingest-document.test.ts' --exclude 'tests/lib/hybrid-search.test.ts'"
71
72
  },
@@ -74,6 +75,9 @@
74
75
  "@discordjs/voice": "^0.19.2",
75
76
  "@libsql/client": "^0.14.0",
76
77
  "@modelcontextprotocol/sdk": "^1.27.1",
78
+ "@opentelemetry/api": "^1.9.1",
79
+ "@opentelemetry/sdk-node": "^0.215.0",
80
+ "@opentelemetry/sdk-trace-base": "^2.7.0",
77
81
  "@slack/bolt": "^4.7.0",
78
82
  "@slack/web-api": "^7.15.1",
79
83
  "@types/react": "^19.2.14",
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Rename an employee across all systems (roster, identity, agent file, symlinks, DB)
3
+ allowed-tools: Bash
4
+ argument-hint: <oldName> <newName>
5
+ ---
6
+
7
+ Atomically rename an employee. Updates roster, identity file, agent file, bin symlinks, and all database references.
8
+
9
+ Run this command:
10
+ ```bash
11
+ node "$(npm root -g)/@askexenow/exe-os/dist/bin/exe-rename.js" $ARGUMENTS
12
+ ```