@askexenow/exe-os 0.8.38 → 0.8.39

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 (91) hide show
  1. package/README.md +17 -8
  2. package/dist/bin/backfill-conversations.js +46 -10
  3. package/dist/bin/backfill-responses.js +46 -10
  4. package/dist/bin/backfill-vectors.js +42 -8
  5. package/dist/bin/cleanup-stale-review-tasks.js +37 -8
  6. package/dist/bin/cli.js +281 -154
  7. package/dist/bin/exe-agent.js +19 -4
  8. package/dist/bin/exe-assign.js +39 -5
  9. package/dist/bin/exe-boot.js +237 -111
  10. package/dist/bin/exe-call.js +11 -6
  11. package/dist/bin/exe-cloud.js +99 -28
  12. package/dist/bin/exe-dispatch.js +1 -1
  13. package/dist/bin/exe-doctor.js +37 -8
  14. package/dist/bin/exe-export-behaviors.js +39 -10
  15. package/dist/bin/exe-forget.js +38 -9
  16. package/dist/bin/exe-gateway.js +109 -42
  17. package/dist/bin/exe-heartbeat.js +49 -20
  18. package/dist/bin/exe-kill.js +39 -10
  19. package/dist/bin/exe-launch-agent.js +58 -22
  20. package/dist/bin/exe-link.js +184 -85
  21. package/dist/bin/exe-new-employee.js +21 -7
  22. package/dist/bin/exe-pending-messages.js +46 -17
  23. package/dist/bin/exe-pending-notifications.js +37 -8
  24. package/dist/bin/exe-pending-reviews.js +47 -18
  25. package/dist/bin/exe-rename.js +21 -7
  26. package/dist/bin/exe-review.js +34 -5
  27. package/dist/bin/exe-search.js +47 -10
  28. package/dist/bin/exe-session-cleanup.js +56 -19
  29. package/dist/bin/exe-settings.js +63 -2
  30. package/dist/bin/exe-status.js +34 -5
  31. package/dist/bin/exe-team.js +34 -5
  32. package/dist/bin/git-sweep.js +38 -9
  33. package/dist/bin/graph-backfill.js +37 -8
  34. package/dist/bin/graph-export.js +37 -8
  35. package/dist/bin/install.js +1 -1
  36. package/dist/bin/scan-tasks.js +40 -11
  37. package/dist/bin/setup.js +58 -24
  38. package/dist/bin/shard-migrate.js +37 -8
  39. package/dist/bin/wiki-sync.js +39 -9
  40. package/dist/gateway/index.js +102 -37
  41. package/dist/hooks/bug-report-worker.js +62 -28
  42. package/dist/hooks/commit-complete.js +38 -9
  43. package/dist/hooks/error-recall.js +49 -8
  44. package/dist/hooks/exe-heartbeat-hook.js +3 -2
  45. package/dist/hooks/ingest-worker.js +151 -37
  46. package/dist/hooks/ingest.js +74 -28
  47. package/dist/hooks/instructions-loaded.js +39 -9
  48. package/dist/hooks/notification.js +37 -7
  49. package/dist/hooks/post-compact.js +37 -7
  50. package/dist/hooks/pre-compact.js +35 -6
  51. package/dist/hooks/pre-tool-use.js +52 -14
  52. package/dist/hooks/prompt-ingest-worker.js +56 -10
  53. package/dist/hooks/prompt-submit.js +61 -23
  54. package/dist/hooks/response-ingest-worker.js +57 -11
  55. package/dist/hooks/session-end.js +43 -10
  56. package/dist/hooks/session-start.js +46 -8
  57. package/dist/hooks/stop.js +37 -7
  58. package/dist/hooks/subagent-stop.js +37 -7
  59. package/dist/hooks/summary-worker.js +317 -99
  60. package/dist/index.js +87 -22
  61. package/dist/lib/cloud-sync.js +172 -78
  62. package/dist/lib/config.js +4 -1
  63. package/dist/lib/consolidation.js +5 -4
  64. package/dist/lib/database.js +1 -0
  65. package/dist/lib/device-registry.js +2 -1
  66. package/dist/lib/embedder.js +9 -1
  67. package/dist/lib/employees.js +11 -6
  68. package/dist/lib/exe-daemon-client.js +6 -1
  69. package/dist/lib/exe-daemon.js +71 -28
  70. package/dist/lib/hybrid-search.js +47 -10
  71. package/dist/lib/identity.js +1 -1
  72. package/dist/lib/keychain.js +2 -1
  73. package/dist/lib/license.js +13 -4
  74. package/dist/lib/messaging.js +1 -1
  75. package/dist/lib/reminders.js +2 -2
  76. package/dist/lib/schedules.js +37 -8
  77. package/dist/lib/skill-learning.js +1 -1
  78. package/dist/lib/store.js +37 -8
  79. package/dist/lib/tasks.js +1 -1
  80. package/dist/lib/tmux-routing.js +1 -1
  81. package/dist/mcp/server.js +97 -43
  82. package/dist/mcp/tools/complete-reminder.js +1 -1
  83. package/dist/mcp/tools/create-task.js +14 -6
  84. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  85. package/dist/mcp/tools/list-reminders.js +1 -1
  86. package/dist/mcp/tools/list-tasks.js +1 -1
  87. package/dist/mcp/tools/send-message.js +1 -1
  88. package/dist/mcp/tools/update-task.js +1 -1
  89. package/dist/runtime/index.js +35 -6
  90. package/dist/tui/App.js +177 -95
  91. package/package.json +3 -3
package/dist/bin/cli.js CHANGED
@@ -42,7 +42,7 @@ __export(config_exports, {
42
42
  migrateConfig: () => migrateConfig,
43
43
  saveConfig: () => saveConfig
44
44
  });
45
- import { readFile, writeFile, mkdir } from "fs/promises";
45
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
46
46
  import { readFileSync, existsSync, renameSync } from "fs";
47
47
  import path from "path";
48
48
  import os from "os";
@@ -168,6 +168,9 @@ async function saveConfig(config) {
168
168
  await mkdir(dir, { recursive: true });
169
169
  const configPath = path.join(dir, "config.json");
170
170
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
171
+ if (config.cloud?.apiKey) {
172
+ await chmod(configPath, 384);
173
+ }
171
174
  }
172
175
  async function loadConfigFrom(configPath) {
173
176
  const raw = await readFile(configPath, "utf-8");
@@ -356,15 +359,20 @@ function addEmployee(employees, employee) {
356
359
  }
357
360
  return [...employees, normalized];
358
361
  }
362
+ function findExeBin() {
363
+ try {
364
+ return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
365
+ } catch {
366
+ return null;
367
+ }
368
+ }
359
369
  function registerBinSymlinks(name) {
360
370
  const created = [];
361
371
  const skipped = [];
362
372
  const errors = [];
363
- let exeBinPath;
364
- try {
365
- exeBinPath = execSync("which exe", { encoding: "utf-8" }).trim();
366
- } catch {
367
- errors.push("Could not find 'exe' in PATH");
373
+ const exeBinPath = findExeBin();
374
+ if (!exeBinPath) {
375
+ errors.push("Could not find 'exe-os' in PATH");
368
376
  return { created, skipped, errors };
369
377
  }
370
378
  const binDir = path2.dirname(exeBinPath);
@@ -1096,6 +1104,7 @@ async function ensureSchema() {
1096
1104
  const client = getRawClient();
1097
1105
  await client.execute("PRAGMA journal_mode = WAL");
1098
1106
  await client.execute("PRAGMA busy_timeout = 30000");
1107
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
1099
1108
  try {
1100
1109
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
1101
1110
  } catch {
@@ -1912,12 +1921,13 @@ __export(keychain_exports, {
1912
1921
  importMnemonic: () => importMnemonic,
1913
1922
  setMasterKey: () => setMasterKey
1914
1923
  });
1915
- import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod } from "fs/promises";
1924
+ import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
1916
1925
  import { existsSync as existsSync5 } from "fs";
1917
1926
  import path5 from "path";
1927
+ import os4 from "os";
1918
1928
  import crypto from "crypto";
1919
1929
  function getKeyDir() {
1920
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(process.env.HOME ?? "/tmp", ".exe-os");
1930
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os4.homedir(), ".exe-os");
1921
1931
  }
1922
1932
  function getKeyPath() {
1923
1933
  return path5.join(getKeyDir(), "master.key");
@@ -1965,7 +1975,7 @@ async function setMasterKey(key) {
1965
1975
  await mkdir4(dir, { recursive: true });
1966
1976
  const keyPath = getKeyPath();
1967
1977
  await writeFile4(keyPath, b64 + "\n", "utf-8");
1968
- await chmod(keyPath, 384);
1978
+ await chmod2(keyPath, 384);
1969
1979
  }
1970
1980
  async function deleteMasterKey() {
1971
1981
  const keytar = await tryKeytar();
@@ -2307,6 +2317,28 @@ __export(store_exports, {
2307
2317
  vectorToBlob: () => vectorToBlob,
2308
2318
  writeMemory: () => writeMemory
2309
2319
  });
2320
+ function isBusyError2(err) {
2321
+ if (err instanceof Error) {
2322
+ const msg = err.message.toLowerCase();
2323
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
2324
+ }
2325
+ return false;
2326
+ }
2327
+ async function retryOnBusy2(fn, label) {
2328
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
2329
+ try {
2330
+ return await fn();
2331
+ } catch (err) {
2332
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
2333
+ process.stderr.write(
2334
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
2335
+ `
2336
+ );
2337
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
2338
+ }
2339
+ }
2340
+ throw new Error("unreachable");
2341
+ }
2310
2342
  async function initStore(options) {
2311
2343
  if (_flushTimer !== null) {
2312
2344
  clearInterval(_flushTimer);
@@ -2335,14 +2367,17 @@ async function initStore(options) {
2335
2367
  dbPath,
2336
2368
  encryptionKey: hexKey
2337
2369
  });
2338
- await ensureSchema();
2370
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
2339
2371
  try {
2340
2372
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
2341
2373
  initShardManager2(hexKey);
2342
2374
  } catch {
2343
2375
  }
2344
2376
  const client = getClient();
2345
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
2377
+ const vResult = await retryOnBusy2(
2378
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
2379
+ "version-query"
2380
+ );
2346
2381
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
2347
2382
  }
2348
2383
  function classifyTier(record) {
@@ -2722,7 +2757,7 @@ async function getMemoryCardinality(agentId) {
2722
2757
  return 0;
2723
2758
  }
2724
2759
  }
2725
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2760
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2726
2761
  var init_store = __esm({
2727
2762
  "src/lib/store.ts"() {
2728
2763
  "use strict";
@@ -2730,6 +2765,8 @@ var init_store = __esm({
2730
2765
  init_database();
2731
2766
  init_keychain();
2732
2767
  init_config();
2768
+ INIT_MAX_RETRIES = 3;
2769
+ INIT_RETRY_DELAY_MS = 1e3;
2733
2770
  _pendingRecords = [];
2734
2771
  _batchSize = 20;
2735
2772
  _flushIntervalMs = 1e4;
@@ -2748,6 +2785,10 @@ import path7 from "path";
2748
2785
  import { fileURLToPath as fileURLToPath2 } from "url";
2749
2786
  function handleData(chunk) {
2750
2787
  _buffer += chunk.toString();
2788
+ if (_buffer.length > MAX_BUFFER) {
2789
+ _buffer = "";
2790
+ return;
2791
+ }
2751
2792
  let newlineIdx;
2752
2793
  while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
2753
2794
  const line = _buffer.slice(0, newlineIdx).trim();
@@ -3055,7 +3096,7 @@ function disconnectClient() {
3055
3096
  entry.resolve({ error: "Client disconnected" });
3056
3097
  }
3057
3098
  }
3058
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending;
3099
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
3059
3100
  var init_exe_daemon_client = __esm({
3060
3101
  "src/lib/exe-daemon-client.ts"() {
3061
3102
  "use strict";
@@ -3072,6 +3113,7 @@ var init_exe_daemon_client = __esm({
3072
3113
  _requestCount = 0;
3073
3114
  HEALTH_CHECK_INTERVAL = 100;
3074
3115
  _pending = /* @__PURE__ */ new Map();
3116
+ MAX_BUFFER = 1e7;
3075
3117
  }
3076
3118
  });
3077
3119
 
@@ -3109,7 +3151,8 @@ import { parseArgs } from "util";
3109
3151
  async function findJsonlFiles(sinceDate, projectFilter) {
3110
3152
  const projectsDir = path8.join(homedir(), ".claude", "projects");
3111
3153
  const files = [];
3112
- async function walk(dir) {
3154
+ async function walk(dir, depth = 0) {
3155
+ if (depth > MAX_WALK_DEPTH) return;
3113
3156
  let entries;
3114
3157
  try {
3115
3158
  entries = await readdir2(dir, { withFileTypes: true });
@@ -3120,7 +3163,7 @@ async function findJsonlFiles(sinceDate, projectFilter) {
3120
3163
  const full = path8.join(dir, entry.name);
3121
3164
  if (entry.isDirectory()) {
3122
3165
  if (entry.name === "subagents" || entry.name === "tool-results") continue;
3123
- await walk(full);
3166
+ await walk(full, depth + 1);
3124
3167
  } else if (entry.name.endsWith(".jsonl")) {
3125
3168
  try {
3126
3169
  const s = await stat(full);
@@ -3438,7 +3481,7 @@ async function backfillConversations(options) {
3438
3481
  );
3439
3482
  return stats;
3440
3483
  }
3441
- var TOOL_NAME, MIN_MESSAGES, MAX_SUMMARY_LENGTH;
3484
+ var TOOL_NAME, MIN_MESSAGES, MAX_SUMMARY_LENGTH, MAX_WALK_DEPTH;
3442
3485
  var init_backfill_conversations = __esm({
3443
3486
  "src/bin/backfill-conversations.ts"() {
3444
3487
  "use strict";
@@ -3449,6 +3492,7 @@ var init_backfill_conversations = __esm({
3449
3492
  TOOL_NAME = "backfill-conversation";
3450
3493
  MIN_MESSAGES = 3;
3451
3494
  MAX_SUMMARY_LENGTH = 4e3;
3495
+ MAX_WALK_DEPTH = 10;
3452
3496
  if (isMainModule(import.meta.url)) {
3453
3497
  const { values } = parseArgs({
3454
3498
  options: {
@@ -4227,9 +4271,17 @@ async function renameEmployee(oldName, newName, opts = {}) {
4227
4271
  return { success: false, error: err instanceof Error ? err.message : String(err) };
4228
4272
  }
4229
4273
  }
4274
+ function findExeBin2() {
4275
+ try {
4276
+ return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
4277
+ } catch {
4278
+ return null;
4279
+ }
4280
+ }
4230
4281
  function removeOldSymlinks(name) {
4231
4282
  try {
4232
- const exeBinPath = execSync2("which exe", { encoding: "utf-8" }).trim();
4283
+ const exeBinPath = findExeBin2();
4284
+ if (!exeBinPath) return;
4233
4285
  const binDir = path9.dirname(exeBinPath);
4234
4286
  for (const suffix of ["", "-opencode"]) {
4235
4287
  const linkPath = path9.join(binDir, `${name}${suffix}`);
@@ -4408,8 +4460,8 @@ async function embedDirect(text) {
4408
4460
  const llamaCpp = await import("node-llama-cpp");
4409
4461
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4410
4462
  const { existsSync: existsSync22 } = await import("fs");
4411
- const path32 = await import("path");
4412
- const modelPath = path32.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4463
+ const path34 = await import("path");
4464
+ const modelPath = path34.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4413
4465
  if (!existsSync22(modelPath)) {
4414
4466
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
4415
4467
  }
@@ -4459,6 +4511,14 @@ import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, existsS
4459
4511
  import { randomUUID as randomUUID2 } from "crypto";
4460
4512
  import path11 from "path";
4461
4513
  import { jwtVerify, importSPKI } from "jose";
4514
+ async function fetchRetry(url, init) {
4515
+ try {
4516
+ return await fetch(url, init);
4517
+ } catch {
4518
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
4519
+ return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
4520
+ }
4521
+ }
4462
4522
  function loadDeviceId() {
4463
4523
  const deviceJsonPath = path11.join(EXE_AI_DIR, "device.json");
4464
4524
  try {
@@ -4490,7 +4550,7 @@ function loadLicense() {
4490
4550
  }
4491
4551
  function saveLicense(apiKey) {
4492
4552
  mkdirSync3(EXE_AI_DIR, { recursive: true });
4493
- writeFileSync2(LICENSE_PATH, apiKey.trim(), "utf8");
4553
+ writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4494
4554
  }
4495
4555
  async function verifyLicenseJwt(token) {
4496
4556
  try {
@@ -4542,7 +4602,7 @@ function cacheResponse(token) {
4542
4602
  async function validateLicense(apiKey, deviceId) {
4543
4603
  const did = deviceId ?? loadDeviceId();
4544
4604
  try {
4545
- const res = await fetch(`${API_BASE}/auth/activate`, {
4605
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
4546
4606
  method: "POST",
4547
4607
  headers: { "Content-Type": "application/json" },
4548
4608
  body: JSON.stringify({ apiKey, deviceId: did }),
@@ -4633,7 +4693,7 @@ async function assertVpsLicense(opts) {
4633
4693
  let explicitRejection = false;
4634
4694
  let transientFailure = false;
4635
4695
  try {
4636
- const res = await fetch(`${API_BASE}/auth/activate`, {
4696
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
4637
4697
  method: "POST",
4638
4698
  headers: { "Content-Type": "application/json" },
4639
4699
  body: JSON.stringify({ apiKey, deviceId }),
@@ -4735,7 +4795,7 @@ function stopLicenseRevalidation() {
4735
4795
  _revalTimer = null;
4736
4796
  }
4737
4797
  }
4738
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
4798
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
4739
4799
  var init_license = __esm({
4740
4800
  "src/lib/license.ts"() {
4741
4801
  "use strict";
@@ -4744,6 +4804,7 @@ var init_license = __esm({
4744
4804
  CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
4745
4805
  DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
4746
4806
  API_BASE = "https://askexe.com/cloud";
4807
+ RETRY_DELAY_MS = 500;
4747
4808
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
4748
4809
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
4749
4810
  4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
@@ -5443,7 +5504,7 @@ __export(setup_wizard_exports, {
5443
5504
  });
5444
5505
  import crypto3 from "crypto";
5445
5506
  import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4 } from "fs";
5446
- import os4 from "os";
5507
+ import os5 from "os";
5447
5508
  import path13 from "path";
5448
5509
  import { createInterface as createInterface2 } from "readline";
5449
5510
  function loadSetupState() {
@@ -5536,12 +5597,23 @@ async function runSetupWizard(opts = {}) {
5536
5597
  try {
5537
5598
  const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
5538
5599
  const deviceId = loadDeviceId2();
5539
- const res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
5540
- method: "POST",
5541
- headers: { "Content-Type": "application/json" },
5542
- body: JSON.stringify({ deviceId }),
5543
- signal: AbortSignal.timeout(1e4)
5544
- });
5600
+ let res;
5601
+ try {
5602
+ res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
5603
+ method: "POST",
5604
+ headers: { "Content-Type": "application/json" },
5605
+ body: JSON.stringify({ deviceId }),
5606
+ signal: AbortSignal.timeout(1e4)
5607
+ });
5608
+ } catch {
5609
+ await new Promise((r) => setTimeout(r, 500));
5610
+ res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
5611
+ method: "POST",
5612
+ headers: { "Content-Type": "application/json" },
5613
+ body: JSON.stringify({ deviceId }),
5614
+ signal: AbortSignal.timeout(1e4)
5615
+ });
5616
+ }
5545
5617
  if (res.ok) {
5546
5618
  const data = await res.json();
5547
5619
  if (data.apiKey) {
@@ -5599,7 +5671,7 @@ async function runSetupWizard(opts = {}) {
5599
5671
  await saveConfig(config);
5600
5672
  log("");
5601
5673
  try {
5602
- const claudeJsonPath = path13.join(os4.homedir(), ".claude.json");
5674
+ const claudeJsonPath = path13.join(os5.homedir(), ".claude.json");
5603
5675
  let claudeJson = {};
5604
5676
  try {
5605
5677
  claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
@@ -5607,7 +5679,7 @@ async function runSetupWizard(opts = {}) {
5607
5679
  }
5608
5680
  if (!claudeJson.projects) claudeJson.projects = {};
5609
5681
  const projects = claudeJson.projects;
5610
- for (const dir of [process.cwd(), os4.homedir()]) {
5682
+ for (const dir of [process.cwd(), os5.homedir()]) {
5611
5683
  if (!projects[dir]) projects[dir] = {};
5612
5684
  projects[dir].hasTrustDialogAccepted = true;
5613
5685
  }
@@ -5851,7 +5923,7 @@ var init_setup_wizard = __esm({
5851
5923
  init_config();
5852
5924
  init_keychain();
5853
5925
  init_model_downloader();
5854
- SETUP_STATE_PATH = path13.join(os4.homedir(), ".exe-os", "setup-state.json");
5926
+ SETUP_STATE_PATH = path13.join(os5.homedir(), ".exe-os", "setup-state.json");
5855
5927
  }
5856
5928
  });
5857
5929
 
@@ -10213,8 +10285,8 @@ var init_ErrorOverview = __esm({
10213
10285
  "use strict";
10214
10286
  init_Box();
10215
10287
  init_Text();
10216
- cleanupPath = (path32) => {
10217
- return path32?.replace(`file://${cwd()}/`, "");
10288
+ cleanupPath = (path34) => {
10289
+ return path34?.replace(`file://${cwd()}/`, "");
10218
10290
  };
10219
10291
  stackUtils = new StackUtils({
10220
10292
  cwd: cwd(),
@@ -12668,7 +12740,7 @@ var init_demo_data = __esm({
12668
12740
  "src/tui/demo-data.ts"() {
12669
12741
  "use strict";
12670
12742
  DEMO_EMPLOYEES = [
12671
- { name: "exe", role: "COO", status: "active", activity: "Reviewing yoshi's task-aware behavior injection PR", memoryCount: 16409, projects: [
12743
+ { name: "exe", role: "COO", status: "active", activity: "Reviewing yoshi's task-aware behavior injection PR", memoryCount: 15e3, projects: [
12672
12744
  { name: "exe-os", status: "active" },
12673
12745
  { name: "exe-create", status: "has_tasks" },
12674
12746
  { name: "openclaw", status: "idle" }
@@ -12677,7 +12749,7 @@ var init_demo_data = __esm({
12677
12749
  "Dispatched behavior injection task",
12678
12750
  "Approved gateway Phase 4"
12679
12751
  ] },
12680
- { name: "yoshi", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", memoryCount: 8164, projects: [
12752
+ { name: "yoshi", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", memoryCount: 8e3, projects: [
12681
12753
  { name: "exe-os", status: "active" },
12682
12754
  { name: "exe-create", status: "idle" }
12683
12755
  ], recentTasks: [
@@ -12685,7 +12757,7 @@ var init_demo_data = __esm({
12685
12757
  "Fixed TUI mouse listener leak",
12686
12758
  "Built task-aware behavior injection"
12687
12759
  ] },
12688
- { name: "mari", role: "CMO", status: "idle", activity: "", memoryCount: 2158, projects: [
12760
+ { name: "mari", role: "CMO", status: "idle", activity: "", memoryCount: 2e3, projects: [
12689
12761
  { name: "exe-build-skills", status: "has_tasks" },
12690
12762
  { name: "exe-os", status: "idle" }
12691
12763
  ], recentTasks: [
@@ -12693,13 +12765,13 @@ var init_demo_data = __esm({
12693
12765
  "Designed exe-os UI system",
12694
12766
  "Fixed logo layouts"
12695
12767
  ] },
12696
- { name: "tom", role: "Principal Engineer", status: "idle", activity: "", memoryCount: 689, projects: [
12768
+ { name: "tom", role: "Principal Engineer", status: "idle", activity: "", memoryCount: 700, projects: [
12697
12769
  { name: "exe-os", status: "idle" }
12698
12770
  ], recentTasks: [
12699
12771
  "Implemented BashTool sandboxed execution",
12700
12772
  "Ported session scoping to exe-agent-memory"
12701
12773
  ] },
12702
- { name: "sasha", role: "Content Production", status: "offline", activity: "", memoryCount: 60, projects: [
12774
+ { name: "sasha", role: "Content Production", status: "offline", activity: "", memoryCount: 50, projects: [
12703
12775
  { name: "exe-build-skills", status: "idle" }
12704
12776
  ], recentTasks: [
12705
12777
  "Rendered carousel export prototype"
@@ -12712,7 +12784,7 @@ var init_demo_data = __esm({
12712
12784
  { time: "11:15", agent: "mari", action: "Completed exe-os UI design system" },
12713
12785
  { time: "10:50", agent: "exe", action: "Approved gateway Phase 4" }
12714
12786
  ];
12715
- DEMO_HEALTH = { memories: 27453, daemon: "running", cloud: "disabled" };
12787
+ DEMO_HEALTH = { memories: 25750, daemon: "running", cloud: "disabled" };
12716
12788
  DEMO_PROJECTS = [
12717
12789
  {
12718
12790
  projectName: "exe-os",
@@ -14580,7 +14652,7 @@ var init_hooks = __esm({
14580
14652
 
14581
14653
  // src/runtime/safety-checks.ts
14582
14654
  import path14 from "path";
14583
- import os5 from "os";
14655
+ import os6 from "os";
14584
14656
  function checkPathSafety(filePath) {
14585
14657
  const resolved = path14.resolve(filePath);
14586
14658
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
@@ -14607,7 +14679,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
14607
14679
  var init_safety_checks = __esm({
14608
14680
  "src/runtime/safety-checks.ts"() {
14609
14681
  "use strict";
14610
- HOME = os5.homedir();
14682
+ HOME = os6.homedir();
14611
14683
  BYPASS_IMMUNE_PATTERNS = [
14612
14684
  {
14613
14685
  pattern: /\/\.git\/hooks\//,
@@ -14839,8 +14911,13 @@ function runRipgrep(input, searchPath, context) {
14839
14911
  timeout: 3e4,
14840
14912
  stdio: ["ignore", "pipe", "pipe"]
14841
14913
  });
14914
+ const MAX_OUTPUT = 1e7;
14842
14915
  const chunks = [];
14843
- child.stdout.on("data", (chunk) => chunks.push(chunk));
14916
+ let totalSize = 0;
14917
+ child.stdout.on("data", (chunk) => {
14918
+ totalSize += chunk.length;
14919
+ if (totalSize <= MAX_OUTPUT) chunks.push(chunk);
14920
+ });
14844
14921
  const onAbort = () => child.kill("SIGTERM");
14845
14922
  context.abortSignal.addEventListener("abort", onAbort, { once: true });
14846
14923
  child.on("close", (code) => {
@@ -15224,10 +15301,19 @@ var init_bash = __esm({
15224
15301
  stdio: ["ignore", "pipe", "pipe"],
15225
15302
  env: { ...process.env }
15226
15303
  });
15304
+ const MAX_OUTPUT_SIZE = 5242880;
15227
15305
  const stdoutChunks = [];
15228
15306
  const stderrChunks = [];
15229
- child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
15230
- child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
15307
+ let stdoutSize = 0;
15308
+ let stderrSize = 0;
15309
+ child.stdout.on("data", (chunk) => {
15310
+ if (stdoutSize < MAX_OUTPUT_SIZE) stdoutChunks.push(chunk);
15311
+ stdoutSize += chunk.length;
15312
+ });
15313
+ child.stderr.on("data", (chunk) => {
15314
+ if (stderrSize < MAX_OUTPUT_SIZE) stderrChunks.push(chunk);
15315
+ stderrSize += chunk.length;
15316
+ });
15231
15317
  const onAbort = () => {
15232
15318
  child.kill("SIGTERM");
15233
15319
  setTimeout(() => {
@@ -15270,7 +15356,7 @@ __export(session_registry_exports, {
15270
15356
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync14 } from "fs";
15271
15357
  import { execSync as execSync4 } from "child_process";
15272
15358
  import path20 from "path";
15273
- import os6 from "os";
15359
+ import os7 from "os";
15274
15360
  function registerSession(entry) {
15275
15361
  const dir = path20.dirname(REGISTRY_PATH);
15276
15362
  if (!existsSync14(dir)) {
@@ -15316,13 +15402,15 @@ var REGISTRY_PATH;
15316
15402
  var init_session_registry = __esm({
15317
15403
  "src/lib/session-registry.ts"() {
15318
15404
  "use strict";
15319
- REGISTRY_PATH = path20.join(os6.homedir(), ".exe-os", "session-registry.json");
15405
+ REGISTRY_PATH = path20.join(os7.homedir(), ".exe-os", "session-registry.json");
15320
15406
  }
15321
15407
  });
15322
15408
 
15323
15409
  // src/tui/views/CommandCenter.tsx
15324
15410
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
15325
15411
  import TextInput from "ink-text-input";
15412
+ import path21 from "path";
15413
+ import { homedir as homedir3 } from "os";
15326
15414
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
15327
15415
  function CommandCenterView({
15328
15416
  onSelectProject,
@@ -15358,8 +15446,8 @@ function CommandCenterView({
15358
15446
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
15359
15447
  const { readFileSync: readFileSync18, existsSync: existsSync22 } = await import("fs");
15360
15448
  const { join } = await import("path");
15361
- const { homedir: homedir3 } = await import("os");
15362
- const configPath = join(homedir3(), ".exe-os", "config.json");
15449
+ const { homedir: homedir5 } = await import("os");
15450
+ const configPath = join(homedir5(), ".exe-os", "config.json");
15363
15451
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
15364
15452
  let providerConfigs = {};
15365
15453
  if (existsSync22(configPath)) {
@@ -15422,7 +15510,7 @@ function CommandCenterView({
15422
15510
  registry.register(BashTool2);
15423
15511
  let agentRole = "CTO";
15424
15512
  try {
15425
- const markerDir = join(homedir3(), ".exe-os", "session-cache");
15513
+ const markerDir = join(homedir5(), ".exe-os", "session-cache");
15426
15514
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
15427
15515
  for (const f of agentFiles) {
15428
15516
  const data = JSON.parse(readFileSync18(join(markerDir, f), "utf8"));
@@ -15562,10 +15650,10 @@ function CommandCenterView({
15562
15650
  const demoEntries = DEMO_PROJECTS.map((p) => ({
15563
15651
  projectName: p.projectName,
15564
15652
  exeSession: p.exeSession,
15565
- projectDir: `/Users/demo/${p.projectName}`,
15653
+ projectDir: path21.join(homedir3(), p.projectName),
15566
15654
  employeeCount: p.employees.length,
15567
15655
  activeCount: p.employees.filter((e) => e.status === "active").length,
15568
- memoryCount: p.projectName === "exe-os" ? 18331 : p.projectName === "exe-create" || p.projectName === "exe-build-skills" ? 2100 : 890,
15656
+ memoryCount: p.employees.length * 4e3,
15569
15657
  status: p.employees.some((e) => e.status === "active") ? "active" : "idle",
15570
15658
  type: p.projectName.startsWith("exe-") ? "code" : "automation",
15571
15659
  recentTasks: DEMO_RECENT_TASKS[p.projectName] ?? []
@@ -16390,10 +16478,10 @@ var init_provider_table = __esm({
16390
16478
 
16391
16479
  // src/lib/intercom-queue.ts
16392
16480
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, renameSync as renameSync4, existsSync as existsSync15, mkdirSync as mkdirSync7 } from "fs";
16393
- import path21 from "path";
16394
- import os7 from "os";
16481
+ import path22 from "path";
16482
+ import os8 from "os";
16395
16483
  function ensureDir2() {
16396
- const dir = path21.dirname(QUEUE_PATH);
16484
+ const dir = path22.dirname(QUEUE_PATH);
16397
16485
  if (!existsSync15(dir)) mkdirSync7(dir, { recursive: true });
16398
16486
  }
16399
16487
  function readQueue() {
@@ -16431,15 +16519,15 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
16431
16519
  var init_intercom_queue = __esm({
16432
16520
  "src/lib/intercom-queue.ts"() {
16433
16521
  "use strict";
16434
- QUEUE_PATH = path21.join(os7.homedir(), ".exe-os", "intercom-queue.json");
16522
+ QUEUE_PATH = path22.join(os8.homedir(), ".exe-os", "intercom-queue.json");
16435
16523
  TTL_MS = 60 * 60 * 1e3;
16436
- INTERCOM_LOG = path21.join(os7.homedir(), ".exe-os", "intercom.log");
16524
+ INTERCOM_LOG = path22.join(os8.homedir(), ".exe-os", "intercom.log");
16437
16525
  }
16438
16526
  });
16439
16527
 
16440
16528
  // src/lib/plan-limits.ts
16441
16529
  import { readFileSync as readFileSync12, existsSync as existsSync16 } from "fs";
16442
- import path22 from "path";
16530
+ import path23 from "path";
16443
16531
  function getLicenseSync() {
16444
16532
  try {
16445
16533
  if (!existsSync16(CACHE_PATH2)) return freeLicense();
@@ -16511,14 +16599,14 @@ var init_plan_limits = __esm({
16511
16599
  this.name = "PlanLimitError";
16512
16600
  }
16513
16601
  };
16514
- CACHE_PATH2 = path22.join(EXE_AI_DIR, "license-cache.json");
16602
+ CACHE_PATH2 = path23.join(EXE_AI_DIR, "license-cache.json");
16515
16603
  }
16516
16604
  });
16517
16605
 
16518
16606
  // src/lib/notifications.ts
16519
16607
  import crypto4 from "crypto";
16520
- import path23 from "path";
16521
- import os8 from "os";
16608
+ import path24 from "path";
16609
+ import os9 from "os";
16522
16610
  import {
16523
16611
  readFileSync as readFileSync13,
16524
16612
  readdirSync as readdirSync3,
@@ -16603,7 +16691,7 @@ var init_session_kill_telemetry = __esm({
16603
16691
 
16604
16692
  // src/lib/tasks-crud.ts
16605
16693
  import crypto6 from "crypto";
16606
- import path24 from "path";
16694
+ import path25 from "path";
16607
16695
  import { execSync as execSync7 } from "child_process";
16608
16696
  import { mkdir as mkdir6, writeFile as writeFile5, appendFile } from "fs/promises";
16609
16697
  import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
@@ -16736,8 +16824,8 @@ async function createTaskCore(input) {
16736
16824
  }
16737
16825
  if (input.baseDir) {
16738
16826
  try {
16739
- await mkdir6(path24.join(input.baseDir, "exe", "output"), { recursive: true });
16740
- await mkdir6(path24.join(input.baseDir, "exe", "research"), { recursive: true });
16827
+ await mkdir6(path25.join(input.baseDir, "exe", "output"), { recursive: true });
16828
+ await mkdir6(path25.join(input.baseDir, "exe", "research"), { recursive: true });
16741
16829
  await ensureArchitectureDoc(input.baseDir, input.projectName);
16742
16830
  await ensureGitignoreExe(input.baseDir);
16743
16831
  } catch {
@@ -16945,7 +17033,7 @@ async function deleteTaskCore(taskId, _baseDir) {
16945
17033
  return { taskFile, assignedTo, assignedBy, taskSlug };
16946
17034
  }
16947
17035
  async function ensureArchitectureDoc(baseDir, projectName) {
16948
- const archPath = path24.join(baseDir, "exe", "ARCHITECTURE.md");
17036
+ const archPath = path25.join(baseDir, "exe", "ARCHITECTURE.md");
16949
17037
  try {
16950
17038
  if (existsSync18(archPath)) return;
16951
17039
  const template = [
@@ -16980,7 +17068,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
16980
17068
  }
16981
17069
  }
16982
17070
  async function ensureGitignoreExe(baseDir) {
16983
- const gitignorePath = path24.join(baseDir, ".gitignore");
17071
+ const gitignorePath = path25.join(baseDir, ".gitignore");
16984
17072
  try {
16985
17073
  if (existsSync18(gitignorePath)) {
16986
17074
  const content = readFileSync14(gitignorePath, "utf-8");
@@ -17003,7 +17091,7 @@ var init_tasks_crud = __esm({
17003
17091
  });
17004
17092
 
17005
17093
  // src/lib/tasks-review.ts
17006
- import path25 from "path";
17094
+ import path26 from "path";
17007
17095
  import { existsSync as existsSync19, readdirSync as readdirSync4, unlinkSync as unlinkSync6 } from "fs";
17008
17096
  async function countPendingReviews() {
17009
17097
  const client = getClient();
@@ -17124,11 +17212,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
17124
17212
  );
17125
17213
  }
17126
17214
  try {
17127
- const cacheDir = path25.join(EXE_AI_DIR, "session-cache");
17215
+ const cacheDir = path26.join(EXE_AI_DIR, "session-cache");
17128
17216
  if (existsSync19(cacheDir)) {
17129
17217
  for (const f of readdirSync4(cacheDir)) {
17130
17218
  if (f.startsWith("review-notified-")) {
17131
- unlinkSync6(path25.join(cacheDir, f));
17219
+ unlinkSync6(path26.join(cacheDir, f));
17132
17220
  }
17133
17221
  }
17134
17222
  }
@@ -17149,7 +17237,7 @@ var init_tasks_review = __esm({
17149
17237
  });
17150
17238
 
17151
17239
  // src/lib/tasks-chain.ts
17152
- import path26 from "path";
17240
+ import path27 from "path";
17153
17241
  import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
17154
17242
  async function cascadeUnblock(taskId, baseDir, now) {
17155
17243
  const client = getClient();
@@ -17165,7 +17253,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
17165
17253
  });
17166
17254
  for (const ur of unblockedRows.rows) {
17167
17255
  try {
17168
- const ubFile = path26.join(baseDir, String(ur.task_file));
17256
+ const ubFile = path27.join(baseDir, String(ur.task_file));
17169
17257
  let ubContent = await readFile5(ubFile, "utf-8");
17170
17258
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
17171
17259
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -17231,7 +17319,7 @@ var init_tasks_chain = __esm({
17231
17319
 
17232
17320
  // src/lib/project-name.ts
17233
17321
  import { execSync as execSync8 } from "child_process";
17234
- import path27 from "path";
17322
+ import path28 from "path";
17235
17323
  function getProjectName(cwd2) {
17236
17324
  const dir = cwd2 ?? process.cwd();
17237
17325
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -17244,7 +17332,7 @@ function getProjectName(cwd2) {
17244
17332
  timeout: 2e3,
17245
17333
  stdio: ["pipe", "pipe", "pipe"]
17246
17334
  }).trim();
17247
- repoRoot = path27.dirname(gitCommonDir);
17335
+ repoRoot = path28.dirname(gitCommonDir);
17248
17336
  } catch {
17249
17337
  repoRoot = execSync8("git rev-parse --show-toplevel", {
17250
17338
  cwd: dir,
@@ -17253,11 +17341,11 @@ function getProjectName(cwd2) {
17253
17341
  stdio: ["pipe", "pipe", "pipe"]
17254
17342
  }).trim();
17255
17343
  }
17256
- _cached2 = path27.basename(repoRoot);
17344
+ _cached2 = path28.basename(repoRoot);
17257
17345
  _cachedCwd = dir;
17258
17346
  return _cached2;
17259
17347
  } catch {
17260
- _cached2 = path27.basename(dir);
17348
+ _cached2 = path28.basename(dir);
17261
17349
  _cachedCwd = dir;
17262
17350
  return _cached2;
17263
17351
  }
@@ -17728,7 +17816,7 @@ __export(tasks_exports, {
17728
17816
  updateTaskStatus: () => updateTaskStatus,
17729
17817
  writeCheckpoint: () => writeCheckpoint
17730
17818
  });
17731
- import path28 from "path";
17819
+ import path29 from "path";
17732
17820
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, unlinkSync as unlinkSync7 } from "fs";
17733
17821
  async function createTask(input) {
17734
17822
  const result = await createTaskCore(input);
@@ -17748,8 +17836,8 @@ async function updateTask(input) {
17748
17836
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
17749
17837
  try {
17750
17838
  const agent = String(row.assigned_to);
17751
- const cacheDir = path28.join(EXE_AI_DIR, "session-cache");
17752
- const cachePath = path28.join(cacheDir, `current-task-${agent}.json`);
17839
+ const cacheDir = path29.join(EXE_AI_DIR, "session-cache");
17840
+ const cachePath = path29.join(cacheDir, `current-task-${agent}.json`);
17753
17841
  if (input.status === "in_progress") {
17754
17842
  mkdirSync8(cacheDir, { recursive: true });
17755
17843
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -18171,12 +18259,12 @@ __export(tmux_routing_exports, {
18171
18259
  });
18172
18260
  import { execFileSync as execFileSync3, execSync as execSync9 } from "child_process";
18173
18261
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, existsSync as existsSync20, appendFileSync } from "fs";
18174
- import path29 from "path";
18175
- import os9 from "os";
18262
+ import path30 from "path";
18263
+ import os10 from "os";
18176
18264
  import { fileURLToPath as fileURLToPath4 } from "url";
18177
18265
  import { unlinkSync as unlinkSync8 } from "fs";
18178
18266
  function spawnLockPath(sessionName) {
18179
- return path29.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
18267
+ return path30.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
18180
18268
  }
18181
18269
  function isProcessAlive(pid) {
18182
18270
  try {
@@ -18213,8 +18301,8 @@ function releaseSpawnLock2(sessionName) {
18213
18301
  function resolveBehaviorsExporterScript() {
18214
18302
  try {
18215
18303
  const thisFile = fileURLToPath4(import.meta.url);
18216
- const scriptPath = path29.join(
18217
- path29.dirname(thisFile),
18304
+ const scriptPath = path30.join(
18305
+ path30.dirname(thisFile),
18218
18306
  "..",
18219
18307
  "bin",
18220
18308
  "exe-export-behaviors.js"
@@ -18264,7 +18352,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
18264
18352
  mkdirSync9(SESSION_CACHE, { recursive: true });
18265
18353
  }
18266
18354
  const rootExe = extractRootExe(parentExe) ?? parentExe;
18267
- const filePath = path29.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
18355
+ const filePath = path30.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
18268
18356
  writeFileSync8(filePath, JSON.stringify({
18269
18357
  parentExe: rootExe,
18270
18358
  dispatchedBy: dispatchedBy || rootExe,
@@ -18273,7 +18361,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
18273
18361
  }
18274
18362
  function getParentExe(sessionKey) {
18275
18363
  try {
18276
- const data = JSON.parse(readFileSync15(path29.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
18364
+ const data = JSON.parse(readFileSync15(path30.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
18277
18365
  return data.parentExe || null;
18278
18366
  } catch {
18279
18367
  return null;
@@ -18282,7 +18370,7 @@ function getParentExe(sessionKey) {
18282
18370
  function getDispatchedBy(sessionKey) {
18283
18371
  try {
18284
18372
  const data = JSON.parse(readFileSync15(
18285
- path29.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
18373
+ path30.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
18286
18374
  "utf8"
18287
18375
  ));
18288
18376
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -18525,8 +18613,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18525
18613
  const transport = getTransport();
18526
18614
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
18527
18615
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
18528
- const logDir = path29.join(os9.homedir(), ".exe-os", "session-logs");
18529
- const logFile = path29.join(logDir, `${instanceLabel}-${Date.now()}.log`);
18616
+ const logDir = path30.join(os10.homedir(), ".exe-os", "session-logs");
18617
+ const logFile = path30.join(logDir, `${instanceLabel}-${Date.now()}.log`);
18530
18618
  if (!existsSync20(logDir)) {
18531
18619
  mkdirSync9(logDir, { recursive: true });
18532
18620
  }
@@ -18534,14 +18622,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18534
18622
  let cleanupSuffix = "";
18535
18623
  try {
18536
18624
  const thisFile = fileURLToPath4(import.meta.url);
18537
- const cleanupScript = path29.join(path29.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
18625
+ const cleanupScript = path30.join(path30.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
18538
18626
  if (existsSync20(cleanupScript)) {
18539
18627
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
18540
18628
  }
18541
18629
  } catch {
18542
18630
  }
18543
18631
  try {
18544
- const claudeJsonPath = path29.join(os9.homedir(), ".claude.json");
18632
+ const claudeJsonPath = path30.join(os10.homedir(), ".claude.json");
18545
18633
  let claudeJson = {};
18546
18634
  try {
18547
18635
  claudeJson = JSON.parse(readFileSync15(claudeJsonPath, "utf8"));
@@ -18556,10 +18644,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18556
18644
  } catch {
18557
18645
  }
18558
18646
  try {
18559
- const settingsDir = path29.join(os9.homedir(), ".claude", "projects");
18647
+ const settingsDir = path30.join(os10.homedir(), ".claude", "projects");
18560
18648
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
18561
- const projSettingsDir = path29.join(settingsDir, normalizedKey);
18562
- const settingsPath = path29.join(projSettingsDir, "settings.json");
18649
+ const projSettingsDir = path30.join(settingsDir, normalizedKey);
18650
+ const settingsPath = path30.join(projSettingsDir, "settings.json");
18563
18651
  let settings = {};
18564
18652
  try {
18565
18653
  settings = JSON.parse(readFileSync15(settingsPath, "utf8"));
@@ -18603,8 +18691,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18603
18691
  let behaviorsFlag = "";
18604
18692
  let legacyFallbackWarned = false;
18605
18693
  if (!useExeAgent && !useBinSymlink) {
18606
- const identityPath2 = path29.join(
18607
- os9.homedir(),
18694
+ const identityPath2 = path30.join(
18695
+ os10.homedir(),
18608
18696
  ".exe-os",
18609
18697
  "identity",
18610
18698
  `${employeeName}.md`
@@ -18619,7 +18707,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18619
18707
  }
18620
18708
  const behaviorsFile = exportBehaviorsSync(
18621
18709
  employeeName,
18622
- path29.basename(spawnCwd),
18710
+ path30.basename(spawnCwd),
18623
18711
  sessionName
18624
18712
  );
18625
18713
  if (behaviorsFile) {
@@ -18634,9 +18722,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18634
18722
  }
18635
18723
  let sessionContextFlag = "";
18636
18724
  try {
18637
- const ctxDir = path29.join(os9.homedir(), ".exe-os", "session-cache");
18725
+ const ctxDir = path30.join(os10.homedir(), ".exe-os", "session-cache");
18638
18726
  mkdirSync9(ctxDir, { recursive: true });
18639
- const ctxFile = path29.join(ctxDir, `session-context-${sessionName}.md`);
18727
+ const ctxFile = path30.join(ctxDir, `session-context-${sessionName}.md`);
18640
18728
  const ctxContent = [
18641
18729
  `## Session Context`,
18642
18730
  `You are running in tmux session: ${sessionName}.`,
@@ -18681,7 +18769,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
18681
18769
  transport.pipeLog(sessionName, logFile);
18682
18770
  try {
18683
18771
  const mySession = getMySession();
18684
- const dispatchInfo = path29.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
18772
+ const dispatchInfo = path30.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
18685
18773
  writeFileSync8(dispatchInfo, JSON.stringify({
18686
18774
  dispatchedBy: mySession,
18687
18775
  rootExe: exeSession,
@@ -18745,13 +18833,13 @@ var init_tmux_routing = __esm({
18745
18833
  init_provider_table();
18746
18834
  init_intercom_queue();
18747
18835
  init_plan_limits();
18748
- SPAWN_LOCK_DIR = path29.join(os9.homedir(), ".exe-os", "spawn-locks");
18749
- SESSION_CACHE = path29.join(os9.homedir(), ".exe-os", "session-cache");
18836
+ SPAWN_LOCK_DIR = path30.join(os10.homedir(), ".exe-os", "spawn-locks");
18837
+ SESSION_CACHE = path30.join(os10.homedir(), ".exe-os", "session-cache");
18750
18838
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
18751
18839
  VERIFY_PANE_LINES = 200;
18752
18840
  INTERCOM_DEBOUNCE_MS = 3e4;
18753
- INTERCOM_LOG2 = path29.join(os9.homedir(), ".exe-os", "intercom.log");
18754
- DEBOUNCE_FILE = path29.join(SESSION_CACHE, "intercom-debounce.json");
18841
+ INTERCOM_LOG2 = path30.join(os10.homedir(), ".exe-os", "intercom.log");
18842
+ DEBOUNCE_FILE = path30.join(SESSION_CACHE, "intercom-debounce.json");
18755
18843
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
18756
18844
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
18757
18845
  }
@@ -19139,6 +19227,8 @@ var init_useOrchestrator = __esm({
19139
19227
 
19140
19228
  // src/tui/views/Sessions.tsx
19141
19229
  import { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
19230
+ import path31 from "path";
19231
+ import { homedir as homedir4 } from "os";
19142
19232
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
19143
19233
  function SessionsView({
19144
19234
  initialProject,
@@ -19171,7 +19261,7 @@ function SessionsView({
19171
19261
  if (demo) {
19172
19262
  setProjects(DEMO_PROJECTS.map((p) => ({
19173
19263
  ...p,
19174
- projectDir: `/Users/demo/${p.projectName}`,
19264
+ projectDir: path31.join(homedir4(), p.projectName),
19175
19265
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
19176
19266
  })));
19177
19267
  return;
@@ -21034,8 +21124,8 @@ __export(wiki_client_exports, {
21034
21124
  listDocuments: () => listDocuments,
21035
21125
  listWorkspaces: () => listWorkspaces
21036
21126
  });
21037
- async function wikiFetch(config, path32, method = "GET", body) {
21038
- const url = `${config.baseUrl}/api/v1${path32}`;
21127
+ async function wikiFetch(config, path34, method = "GET", body) {
21128
+ const url = `${config.baseUrl}/api/v1${path34}`;
21039
21129
  const headers = {
21040
21130
  Authorization: `Bearer ${config.apiKey}`,
21041
21131
  "Content-Type": "application/json"
@@ -21043,14 +21133,32 @@ async function wikiFetch(config, path32, method = "GET", body) {
21043
21133
  const controller = new AbortController();
21044
21134
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
21045
21135
  try {
21046
- const response = await fetch(url, {
21047
- method,
21048
- headers,
21049
- body: body ? JSON.stringify(body) : void 0,
21050
- signal: controller.signal
21051
- });
21136
+ let response;
21137
+ try {
21138
+ response = await fetch(url, {
21139
+ method,
21140
+ headers,
21141
+ body: body ? JSON.stringify(body) : void 0,
21142
+ signal: controller.signal
21143
+ });
21144
+ } catch {
21145
+ clearTimeout(timeout);
21146
+ const retryController = new AbortController();
21147
+ const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
21148
+ try {
21149
+ await new Promise((r) => setTimeout(r, 500));
21150
+ response = await fetch(url, {
21151
+ method,
21152
+ headers,
21153
+ body: body ? JSON.stringify(body) : void 0,
21154
+ signal: retryController.signal
21155
+ });
21156
+ } finally {
21157
+ clearTimeout(retryTimeout);
21158
+ }
21159
+ }
21052
21160
  if (!response.ok) {
21053
- throw new Error(`Wiki API ${method} ${path32}: ${response.status} ${response.statusText}`);
21161
+ throw new Error(`Wiki API ${method} ${path34}: ${response.status} ${response.statusText}`);
21054
21162
  }
21055
21163
  return response.json();
21056
21164
  } finally {
@@ -21901,9 +22009,9 @@ var init_App2 = __esm({
21901
22009
  // src/lib/update-check.ts
21902
22010
  import { execSync as execSync11 } from "child_process";
21903
22011
  import { readFileSync as readFileSync16 } from "fs";
21904
- import path30 from "path";
22012
+ import path32 from "path";
21905
22013
  function getLocalVersion(packageRoot) {
21906
- const pkgPath = path30.join(packageRoot, "package.json");
22014
+ const pkgPath = path32.join(packageRoot, "package.json");
21907
22015
  const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
21908
22016
  return pkg.version;
21909
22017
  }
@@ -21995,8 +22103,8 @@ var init_update = __esm({
21995
22103
 
21996
22104
  // src/bin/cli.ts
21997
22105
  import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync9, readdirSync as readdirSync5, rmSync } from "fs";
21998
- import path31 from "path";
21999
- import os10 from "os";
22106
+ import path33 from "path";
22107
+ import os11 from "os";
22000
22108
  var args = process.argv.slice(2);
22001
22109
  if (args.includes("--global")) {
22002
22110
  process.stderr.write(
@@ -22069,9 +22177,9 @@ async function runClaudeInstall() {
22069
22177
  }
22070
22178
  }
22071
22179
  async function runClaudeCheck() {
22072
- const claudeDir = path31.join(os10.homedir(), ".claude");
22073
- const settingsPath = path31.join(claudeDir, "settings.json");
22074
- const claudeJsonPath = path31.join(os10.homedir(), ".claude.json");
22180
+ const claudeDir = path33.join(os11.homedir(), ".claude");
22181
+ const settingsPath = path33.join(claudeDir, "settings.json");
22182
+ const claudeJsonPath = path33.join(os11.homedir(), ".claude.json");
22075
22183
  let ok = true;
22076
22184
  if (existsSync21(settingsPath)) {
22077
22185
  let settings;
@@ -22124,7 +22232,7 @@ async function runClaudeCheck() {
22124
22232
  console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
22125
22233
  ok = false;
22126
22234
  }
22127
- const skillsDir = path31.join(claudeDir, "skills");
22235
+ const skillsDir = path33.join(claudeDir, "skills");
22128
22236
  if (existsSync21(skillsDir)) {
22129
22237
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
22130
22238
  } else {
@@ -22141,11 +22249,11 @@ async function runClaudeCheck() {
22141
22249
  async function runClaudeUninstall(flags = []) {
22142
22250
  const dryRun = flags.includes("--dry-run");
22143
22251
  const purge = flags.includes("--purge");
22144
- const homeDir = os10.homedir();
22145
- const claudeDir = path31.join(homeDir, ".claude");
22146
- const settingsPath = path31.join(claudeDir, "settings.json");
22147
- const claudeJsonPath = path31.join(homeDir, ".claude.json");
22148
- const exeOsDir = path31.join(homeDir, ".exe-os");
22252
+ const homeDir = os11.homedir();
22253
+ const claudeDir = path33.join(homeDir, ".claude");
22254
+ const settingsPath = path33.join(claudeDir, "settings.json");
22255
+ const claudeJsonPath = path33.join(homeDir, ".claude.json");
22256
+ const exeOsDir = path33.join(homeDir, ".exe-os");
22149
22257
  let removed = 0;
22150
22258
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
22151
22259
  let settings = {};
@@ -22197,32 +22305,43 @@ async function runClaudeUninstall(flags = []) {
22197
22305
  }
22198
22306
  }
22199
22307
  if (existsSync21(claudeJsonPath)) {
22200
- const claudeJson = JSON.parse(readFileSync17(claudeJsonPath, "utf8"));
22201
- if (claudeJson.mcpServers) {
22202
- let removedMcp = false;
22203
- for (const key of ["exe-mem", "exe-os"]) {
22204
- if (claudeJson.mcpServers[key]) {
22205
- if (!dryRun) delete claudeJson.mcpServers[key];
22206
- removedMcp = true;
22308
+ const raw = readFileSync17(claudeJsonPath, "utf8");
22309
+ if (raw.length > 1e6) {
22310
+ console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
22311
+ } else {
22312
+ let claudeJson;
22313
+ try {
22314
+ claudeJson = JSON.parse(raw);
22315
+ } catch {
22316
+ console.error("claude.json is malformed JSON \u2014 skipping.");
22317
+ claudeJson = {};
22318
+ }
22319
+ if (claudeJson.mcpServers) {
22320
+ let removedMcp = false;
22321
+ for (const key of ["exe-mem", "exe-os"]) {
22322
+ if (claudeJson.mcpServers[key]) {
22323
+ if (!dryRun) delete claudeJson.mcpServers[key];
22324
+ removedMcp = true;
22325
+ }
22207
22326
  }
22208
- }
22209
- if (removedMcp) {
22210
- if (!dryRun) {
22211
- writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
22327
+ if (removedMcp) {
22328
+ if (!dryRun) {
22329
+ writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
22330
+ }
22331
+ log("\u2713 Removed exe-os MCP server from claude.json");
22332
+ removed++;
22212
22333
  }
22213
- log("\u2713 Removed exe-os MCP server from claude.json");
22214
- removed++;
22215
22334
  }
22216
22335
  }
22217
22336
  }
22218
- const skillsDir = path31.join(claudeDir, "skills");
22337
+ const skillsDir = path33.join(claudeDir, "skills");
22219
22338
  if (existsSync21(skillsDir)) {
22220
22339
  let skillCount = 0;
22221
22340
  try {
22222
22341
  const entries = readdirSync5(skillsDir);
22223
22342
  for (const entry of entries) {
22224
22343
  if (entry.startsWith("exe")) {
22225
- const fullPath = path31.join(skillsDir, entry);
22344
+ const fullPath = path33.join(skillsDir, entry);
22226
22345
  if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
22227
22346
  skillCount++;
22228
22347
  }
@@ -22234,7 +22353,7 @@ async function runClaudeUninstall(flags = []) {
22234
22353
  removed++;
22235
22354
  }
22236
22355
  }
22237
- const claudeMdPath = path31.join(claudeDir, "CLAUDE.md");
22356
+ const claudeMdPath = path33.join(claudeDir, "CLAUDE.md");
22238
22357
  if (existsSync21(claudeMdPath)) {
22239
22358
  const content = readFileSync17(claudeMdPath, "utf8");
22240
22359
  const startMarker = "<!-- exe-os:orchestration-start -->";
@@ -22248,13 +22367,13 @@ async function runClaudeUninstall(flags = []) {
22248
22367
  removed++;
22249
22368
  }
22250
22369
  }
22251
- const agentsDir = path31.join(claudeDir, "agents");
22370
+ const agentsDir = path33.join(claudeDir, "agents");
22252
22371
  if (existsSync21(agentsDir)) {
22253
22372
  let agentCount = 0;
22254
22373
  try {
22255
22374
  const entries = readdirSync5(agentsDir).filter((f) => f.endsWith(".md"));
22256
22375
  let knownNames = /* @__PURE__ */ new Set();
22257
- const rosterPath = path31.join(exeOsDir, "exe-employees.json");
22376
+ const rosterPath = path33.join(exeOsDir, "exe-employees.json");
22258
22377
  if (existsSync21(rosterPath)) {
22259
22378
  try {
22260
22379
  const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
@@ -22265,7 +22384,7 @@ async function runClaudeUninstall(flags = []) {
22265
22384
  for (const entry of entries) {
22266
22385
  const name = entry.replace(/\.md$/, "");
22267
22386
  if (knownNames.has(name)) {
22268
- if (!dryRun) rmSync(path31.join(agentsDir, entry), { force: true });
22387
+ if (!dryRun) rmSync(path33.join(agentsDir, entry), { force: true });
22269
22388
  agentCount++;
22270
22389
  }
22271
22390
  }
@@ -22276,13 +22395,13 @@ async function runClaudeUninstall(flags = []) {
22276
22395
  removed++;
22277
22396
  }
22278
22397
  }
22279
- const projectsDir = path31.join(claudeDir, "projects");
22398
+ const projectsDir = path33.join(claudeDir, "projects");
22280
22399
  if (existsSync21(projectsDir)) {
22281
22400
  let projectCount = 0;
22282
22401
  try {
22283
22402
  const projects = readdirSync5(projectsDir);
22284
22403
  for (const proj of projects) {
22285
- const projSettings = path31.join(projectsDir, proj, "settings.json");
22404
+ const projSettings = path33.join(projectsDir, proj, "settings.json");
22286
22405
  if (!existsSync21(projSettings)) continue;
22287
22406
  try {
22288
22407
  const pSettings = JSON.parse(readFileSync17(projSettings, "utf8"));
@@ -22310,16 +22429,24 @@ async function runClaudeUninstall(flags = []) {
22310
22429
  }
22311
22430
  try {
22312
22431
  const { execSync: execSync13 } = await import("child_process");
22313
- const exeBinPath = execSync13("which exe", { encoding: "utf-8" }).trim();
22314
- const binDir = path31.dirname(exeBinPath);
22432
+ const findExeBin3 = () => {
22433
+ try {
22434
+ return execSync13(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
22435
+ } catch {
22436
+ return null;
22437
+ }
22438
+ };
22439
+ const exeBinPath = findExeBin3();
22440
+ if (!exeBinPath) throw new Error("exe-os not found in PATH");
22441
+ const binDir = path33.dirname(exeBinPath);
22315
22442
  let symlinkCount = 0;
22316
- const rosterPath = path31.join(exeOsDir, "exe-employees.json");
22443
+ const rosterPath = path33.join(exeOsDir, "exe-employees.json");
22317
22444
  if (existsSync21(rosterPath)) {
22318
22445
  const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
22319
22446
  for (const emp of roster) {
22320
22447
  if (emp.name === "exe") continue;
22321
22448
  for (const suffix of ["", "-opencode"]) {
22322
- const linkPath = path31.join(binDir, `${emp.name}${suffix}`);
22449
+ const linkPath = path33.join(binDir, `${emp.name}${suffix}`);
22323
22450
  if (existsSync21(linkPath)) {
22324
22451
  if (!dryRun) rmSync(linkPath, { force: true });
22325
22452
  symlinkCount++;
@@ -22358,7 +22485,7 @@ async function checkForUpdateOnBoot() {
22358
22485
  const config = await loadConfig2();
22359
22486
  if (!config.autoUpdate.checkOnBoot) return;
22360
22487
  const { checkForUpdate: checkForUpdate2 } = await init_update().then(() => update_exports);
22361
- const packageRoot = path31.resolve(
22488
+ const packageRoot = path33.resolve(
22362
22489
  new URL("../..", import.meta.url).pathname
22363
22490
  );
22364
22491
  const result = checkForUpdate2(packageRoot);
@@ -22417,7 +22544,7 @@ async function runActivate(key) {
22417
22544
  const idTemplate = getIdentityTemplate(identityKey);
22418
22545
  if (idTemplate) {
22419
22546
  const idPath = identityPath2(name);
22420
- const dir = path31.dirname(idPath);
22547
+ const dir = path33.dirname(idPath);
22421
22548
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
22422
22549
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
22423
22550
  }