@askexenow/exe-os 0.8.61 → 0.8.63

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 (62) hide show
  1. package/dist/bin/backfill-conversations.js +2 -3
  2. package/dist/bin/backfill-responses.js +3 -4
  3. package/dist/bin/backfill-vectors.js +0 -1
  4. package/dist/bin/cleanup-stale-review-tasks.js +0 -1
  5. package/dist/bin/cli.js +1654 -397
  6. package/dist/bin/exe-assign.js +0 -1
  7. package/dist/bin/exe-boot.js +61 -84
  8. package/dist/bin/exe-cloud.js +28 -60
  9. package/dist/bin/exe-dispatch.js +0 -1
  10. package/dist/bin/exe-doctor.js +0 -1
  11. package/dist/bin/exe-export-behaviors.js +1 -2
  12. package/dist/bin/exe-forget.js +0 -1
  13. package/dist/bin/exe-gateway.js +16 -17
  14. package/dist/bin/exe-heartbeat.js +1 -2
  15. package/dist/bin/exe-kill.js +2 -3
  16. package/dist/bin/exe-launch-agent.js +1 -2
  17. package/dist/bin/exe-link.js +49 -78
  18. package/dist/bin/exe-pending-messages.js +1 -2
  19. package/dist/bin/exe-pending-notifications.js +0 -1
  20. package/dist/bin/exe-pending-reviews.js +1 -2
  21. package/dist/bin/exe-review.js +0 -1
  22. package/dist/bin/exe-search.js +2 -3
  23. package/dist/bin/exe-session-cleanup.js +4 -5
  24. package/dist/bin/exe-status.js +0 -1
  25. package/dist/bin/exe-team.js +0 -1
  26. package/dist/bin/git-sweep.js +0 -1
  27. package/dist/bin/graph-backfill.js +5 -6
  28. package/dist/bin/graph-export.js +0 -1
  29. package/dist/bin/scan-tasks.js +0 -1
  30. package/dist/bin/setup.js +1460 -115
  31. package/dist/bin/shard-migrate.js +0 -1
  32. package/dist/bin/wiki-sync.js +0 -1
  33. package/dist/gateway/index.js +16 -17
  34. package/dist/hooks/bug-report-worker.js +11 -12
  35. package/dist/hooks/commit-complete.js +0 -1
  36. package/dist/hooks/error-recall.js +2 -3
  37. package/dist/hooks/ingest-worker.js +14 -15
  38. package/dist/hooks/instructions-loaded.js +0 -1
  39. package/dist/hooks/notification.js +0 -1
  40. package/dist/hooks/post-compact.js +0 -1
  41. package/dist/hooks/pre-compact.js +2 -3
  42. package/dist/hooks/pre-tool-use.js +0 -1
  43. package/dist/hooks/prompt-ingest-worker.js +2 -3
  44. package/dist/hooks/prompt-submit.js +6 -7
  45. package/dist/hooks/response-ingest-worker.js +2 -3
  46. package/dist/hooks/session-end.js +3 -4
  47. package/dist/hooks/session-start.js +2 -3
  48. package/dist/hooks/stop.js +2 -3
  49. package/dist/hooks/subagent-stop.js +0 -1
  50. package/dist/hooks/summary-worker.js +51 -74
  51. package/dist/index.js +7 -8
  52. package/dist/lib/cloud-sync.js +21 -12
  53. package/dist/lib/consolidation.js +0 -1
  54. package/dist/lib/exe-daemon.js +33 -65
  55. package/dist/lib/hybrid-search.js +2 -3
  56. package/dist/lib/keychain.js +19 -58
  57. package/dist/lib/schedules.js +2 -3
  58. package/dist/lib/store.js +0 -1
  59. package/dist/mcp/server.js +29 -30
  60. package/dist/runtime/index.js +2 -3
  61. package/dist/tui/App.js +24 -56
  62. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -1986,7 +1986,6 @@ import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4
1986
1986
  import { existsSync as existsSync5 } from "fs";
1987
1987
  import path5 from "path";
1988
1988
  import os4 from "os";
1989
- import crypto from "crypto";
1990
1989
  function getKeyDir() {
1991
1990
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os4.homedir(), ".exe-os");
1992
1991
  }
@@ -2051,65 +2050,34 @@ async function deleteMasterKey() {
2051
2050
  await unlink(keyPath);
2052
2051
  }
2053
2052
  }
2054
- function exportMnemonic(key) {
2055
- if (key.length !== 32) {
2056
- throw new Error(`Key must be 32 bytes, got ${key.length}`);
2057
- }
2058
- const hash = crypto.createHash("sha256").update(key).digest();
2059
- const checksumByte = hash[0];
2060
- let bits = "";
2061
- for (const byte of key) {
2062
- bits += byte.toString(2).padStart(8, "0");
2063
- }
2064
- bits += checksumByte.toString(2).padStart(8, "0");
2065
- const words = [];
2066
- let wordlist;
2053
+ async function loadBip39() {
2067
2054
  try {
2068
- const bip39 = __require("bip39");
2069
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
2070
- if (!wordlist) throw new Error("no wordlist");
2055
+ return await import("bip39");
2071
2056
  } catch {
2072
- throw new Error("bip39 package required. Install with: npm install bip39");
2057
+ throw new Error(
2058
+ "bip39 package not found. Run: npm install -g bip39\nOr reinstall exe-os: npm install -g @askexenow/exe-os"
2059
+ );
2073
2060
  }
2074
- for (let i = 0; i < 264; i += 11) {
2075
- const index = parseInt(bits.slice(i, i + 11), 2);
2076
- words.push(wordlist[index]);
2061
+ }
2062
+ async function exportMnemonic(key) {
2063
+ if (key.length !== 32) {
2064
+ throw new Error(`Key must be 32 bytes, got ${key.length}`);
2077
2065
  }
2078
- return words.join(" ");
2066
+ const { entropyToMnemonic } = await loadBip39();
2067
+ return entropyToMnemonic(key.toString("hex"));
2079
2068
  }
2080
- function importMnemonic(mnemonic) {
2081
- const words = mnemonic.trim().split(/\s+/);
2069
+ async function importMnemonic(mnemonic) {
2070
+ const trimmed = mnemonic.trim();
2071
+ const words = trimmed.split(/\s+/);
2082
2072
  if (words.length !== 24) {
2083
2073
  throw new Error(`Expected 24 words, got ${words.length}`);
2084
2074
  }
2085
- let wordlist;
2086
- try {
2087
- const bip39 = __require("bip39");
2088
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
2089
- if (!wordlist) throw new Error("no wordlist");
2090
- } catch {
2091
- throw new Error("bip39 package required. Install with: npm install bip39");
2075
+ const { validateMnemonic, mnemonicToEntropy } = await loadBip39();
2076
+ if (!validateMnemonic(trimmed)) {
2077
+ throw new Error("Invalid mnemonic \u2014 check for typos or missing words");
2092
2078
  }
2093
- let bits = "";
2094
- for (const word of words) {
2095
- const index = wordlist.indexOf(word.toLowerCase());
2096
- if (index === -1) {
2097
- throw new Error(`Invalid BIP39 word: "${word}"`);
2098
- }
2099
- bits += index.toString(2).padStart(11, "0");
2100
- }
2101
- const entropyBits = bits.slice(0, 256);
2102
- const checksumBits = bits.slice(256, 264);
2103
- const key = Buffer.alloc(32);
2104
- for (let i = 0; i < 32; i++) {
2105
- key[i] = parseInt(entropyBits.slice(i * 8, (i + 1) * 8), 2);
2106
- }
2107
- const hash = crypto.createHash("sha256").update(key).digest();
2108
- const expectedChecksum = hash[0].toString(2).padStart(8, "0");
2109
- if (checksumBits !== expectedChecksum) {
2110
- throw new Error("Invalid mnemonic checksum");
2111
- }
2112
- return key;
2079
+ const entropy = mnemonicToEntropy(trimmed);
2080
+ return Buffer.from(entropy, "hex");
2113
2081
  }
2114
2082
  var SERVICE, ACCOUNT;
2115
2083
  var init_keychain = __esm({
@@ -3450,7 +3418,7 @@ var backfill_conversations_exports = {};
3450
3418
  __export(backfill_conversations_exports, {
3451
3419
  backfillConversations: () => backfillConversations
3452
3420
  });
3453
- import crypto2 from "crypto";
3421
+ import crypto from "crypto";
3454
3422
  import { createReadStream } from "fs";
3455
3423
  import { readdir as readdir2, stat } from "fs/promises";
3456
3424
  import path8 from "path";
@@ -3755,7 +3723,7 @@ async function backfillConversations(options) {
3755
3723
  }
3756
3724
  }
3757
3725
  await writeMemory({
3758
- id: crypto2.randomUUID(),
3726
+ id: crypto.randomUUID(),
3759
3727
  agent_id: conv.agentId,
3760
3728
  agent_role: conv.agentId === "exe" ? "COO" : "specialist",
3761
3729
  session_id: conv.sessionId,
@@ -4770,10 +4738,10 @@ async function disposeEmbedder() {
4770
4738
  async function embedDirect(text) {
4771
4739
  const llamaCpp = await import("node-llama-cpp");
4772
4740
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4773
- const { existsSync: existsSync22 } = await import("fs");
4774
- const path34 = await import("path");
4775
- const modelPath = path34.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4776
- if (!existsSync22(modelPath)) {
4741
+ const { existsSync: existsSync24 } = await import("fs");
4742
+ const path36 = await import("path");
4743
+ const modelPath = path36.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4744
+ if (!existsSync24(modelPath)) {
4777
4745
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
4778
4746
  }
4779
4747
  const llama = await llamaCpp.getLlama();
@@ -5131,60 +5099,1125 @@ async function assertVpsLicense(opts) {
5131
5099
  `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
5132
5100
  );
5133
5101
  }
5134
- function startLicenseRevalidation(intervalMs = 36e5) {
5135
- if (_revalTimer) return;
5136
- _revalTimer = setInterval(async () => {
5137
- try {
5138
- const license = await checkLicense();
5139
- if (!license.valid) {
5140
- process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
5141
- }
5142
- } catch {
5143
- }
5144
- }, intervalMs);
5145
- if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
5146
- _revalTimer.unref();
5102
+ function startLicenseRevalidation(intervalMs = 36e5) {
5103
+ if (_revalTimer) return;
5104
+ _revalTimer = setInterval(async () => {
5105
+ try {
5106
+ const license = await checkLicense();
5107
+ if (!license.valid) {
5108
+ process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
5109
+ }
5110
+ } catch {
5111
+ }
5112
+ }, intervalMs);
5113
+ if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
5114
+ _revalTimer.unref();
5115
+ }
5116
+ }
5117
+ function stopLicenseRevalidation() {
5118
+ if (_revalTimer) {
5119
+ clearInterval(_revalTimer);
5120
+ _revalTimer = null;
5121
+ }
5122
+ }
5123
+ 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;
5124
+ var init_license = __esm({
5125
+ "src/lib/license.ts"() {
5126
+ "use strict";
5127
+ init_config();
5128
+ LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
5129
+ CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
5130
+ DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
5131
+ API_BASE = "https://askexe.com/cloud";
5132
+ RETRY_DELAY_MS = 500;
5133
+ LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
5134
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
5135
+ 4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
5136
+ -----END PUBLIC KEY-----`;
5137
+ LICENSE_JWT_ALG = "ES256";
5138
+ PLAN_LIMITS = {
5139
+ free: { devices: 1, employees: 1, memories: 5e4 },
5140
+ pro: { devices: 2, employees: 5, memories: 25e4 },
5141
+ team: { devices: 10, employees: 20, memories: 1e6 },
5142
+ agency: { devices: 50, employees: 100, memories: 1e7 },
5143
+ enterprise: { devices: -1, employees: -1, memories: -1 }
5144
+ };
5145
+ FREE_LICENSE = {
5146
+ valid: true,
5147
+ plan: "free",
5148
+ email: "",
5149
+ expiresAt: null,
5150
+ deviceLimit: 1,
5151
+ employeeLimit: 1,
5152
+ memoryLimit: 5e4
5153
+ };
5154
+ CACHE_MAX_AGE_MS = 36e5;
5155
+ _revalTimer = null;
5156
+ }
5157
+ });
5158
+
5159
+ // src/lib/crypto.ts
5160
+ var crypto_exports = {};
5161
+ __export(crypto_exports, {
5162
+ decryptSyncBlob: () => decryptSyncBlob,
5163
+ encryptSyncBlob: () => encryptSyncBlob,
5164
+ initSyncCrypto: () => initSyncCrypto,
5165
+ isSyncCryptoInitialized: () => isSyncCryptoInitialized
5166
+ });
5167
+ import crypto2 from "crypto";
5168
+ function initSyncCrypto(masterKey) {
5169
+ if (masterKey.length !== 32) {
5170
+ throw new Error(`Master key must be 32 bytes, got ${masterKey.length}`);
5171
+ }
5172
+ _syncKey = Buffer.from(
5173
+ crypto2.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
5174
+ );
5175
+ }
5176
+ function isSyncCryptoInitialized() {
5177
+ return _syncKey !== null;
5178
+ }
5179
+ function requireSyncKey() {
5180
+ if (!_syncKey) {
5181
+ throw new Error("Sync crypto not initialized. Call initSyncCrypto(masterKey) first.");
5182
+ }
5183
+ return _syncKey;
5184
+ }
5185
+ function encryptSyncBlob(data) {
5186
+ const key = requireSyncKey();
5187
+ const iv = crypto2.randomBytes(IV_LENGTH);
5188
+ const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
5189
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
5190
+ const tag = cipher.getAuthTag();
5191
+ return Buffer.concat([iv, encrypted, tag]).toString("base64");
5192
+ }
5193
+ function decryptSyncBlob(ciphertext) {
5194
+ const key = requireSyncKey();
5195
+ const combined = Buffer.from(ciphertext, "base64");
5196
+ if (combined.length < IV_LENGTH + TAG_LENGTH) {
5197
+ throw new Error("Sync blob too short to contain IV + tag");
5198
+ }
5199
+ const iv = combined.subarray(0, IV_LENGTH);
5200
+ const tag = combined.subarray(combined.length - TAG_LENGTH);
5201
+ const encrypted = combined.subarray(IV_LENGTH, combined.length - TAG_LENGTH);
5202
+ const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
5203
+ decipher.setAuthTag(tag);
5204
+ return Buffer.concat([decipher.update(encrypted), decipher.final()]);
5205
+ }
5206
+ var ALGORITHM, IV_LENGTH, TAG_LENGTH, SYNC_HKDF_INFO, _syncKey;
5207
+ var init_crypto = __esm({
5208
+ "src/lib/crypto.ts"() {
5209
+ "use strict";
5210
+ ALGORITHM = "aes-256-gcm";
5211
+ IV_LENGTH = 12;
5212
+ TAG_LENGTH = 16;
5213
+ SYNC_HKDF_INFO = "exe-mem-sync-v2";
5214
+ _syncKey = null;
5215
+ }
5216
+ });
5217
+
5218
+ // src/lib/compress.ts
5219
+ import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
5220
+ function compress(input) {
5221
+ if (input.length === 0) return Buffer.alloc(0);
5222
+ return brotliCompressSync(input, {
5223
+ params: {
5224
+ [constants.BROTLI_PARAM_QUALITY]: 4
5225
+ }
5226
+ });
5227
+ }
5228
+ function decompress(input) {
5229
+ if (input.length === 0) return Buffer.alloc(0);
5230
+ return brotliDecompressSync(input);
5231
+ }
5232
+ var init_compress = __esm({
5233
+ "src/lib/compress.ts"() {
5234
+ "use strict";
5235
+ }
5236
+ });
5237
+
5238
+ // src/lib/cloud-sync.ts
5239
+ var cloud_sync_exports = {};
5240
+ __export(cloud_sync_exports, {
5241
+ assertSecureEndpoint: () => assertSecureEndpoint,
5242
+ buildRosterBlob: () => buildRosterBlob,
5243
+ cloudPull: () => cloudPull,
5244
+ cloudPullBehaviors: () => cloudPullBehaviors,
5245
+ cloudPullBlob: () => cloudPullBlob,
5246
+ cloudPullConversations: () => cloudPullConversations,
5247
+ cloudPullDocuments: () => cloudPullDocuments,
5248
+ cloudPullGlobalProcedures: () => cloudPullGlobalProcedures,
5249
+ cloudPullGraphRAG: () => cloudPullGraphRAG,
5250
+ cloudPullRoster: () => cloudPullRoster,
5251
+ cloudPullTasks: () => cloudPullTasks,
5252
+ cloudPush: () => cloudPush,
5253
+ cloudPushBehaviors: () => cloudPushBehaviors,
5254
+ cloudPushBlob: () => cloudPushBlob,
5255
+ cloudPushConversations: () => cloudPushConversations,
5256
+ cloudPushDocuments: () => cloudPushDocuments,
5257
+ cloudPushGlobalProcedures: () => cloudPushGlobalProcedures,
5258
+ cloudPushGraphRAG: () => cloudPushGraphRAG,
5259
+ cloudPushRoster: () => cloudPushRoster,
5260
+ cloudPushTasks: () => cloudPushTasks,
5261
+ cloudSync: () => cloudSync,
5262
+ mergeConfig: () => mergeConfig,
5263
+ mergeRosterFromRemote: () => mergeRosterFromRemote,
5264
+ recordRosterDeletion: () => recordRosterDeletion
5265
+ });
5266
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync11, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
5267
+ import crypto3 from "crypto";
5268
+ import path12 from "path";
5269
+ import { homedir as homedir3 } from "os";
5270
+ function sqlSafe(v) {
5271
+ return v === void 0 ? null : v;
5272
+ }
5273
+ function logError(msg) {
5274
+ try {
5275
+ const logPath = path12.join(homedir3(), ".exe-os", "workers.log");
5276
+ appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
5277
+ `);
5278
+ } catch {
5279
+ }
5280
+ }
5281
+ async function withRosterLock(fn) {
5282
+ try {
5283
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5284
+ closeSync2(fd);
5285
+ writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5286
+ } catch (err) {
5287
+ if (err.code === "EEXIST") {
5288
+ try {
5289
+ const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
5290
+ if (Date.now() - ts < LOCK_STALE_MS) {
5291
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
5292
+ }
5293
+ unlinkSync4(ROSTER_LOCK_PATH);
5294
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5295
+ closeSync2(fd);
5296
+ writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5297
+ } catch (retryErr) {
5298
+ if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
5299
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
5300
+ }
5301
+ } else {
5302
+ throw err;
5303
+ }
5304
+ }
5305
+ try {
5306
+ return await fn();
5307
+ } finally {
5308
+ try {
5309
+ unlinkSync4(ROSTER_LOCK_PATH);
5310
+ } catch {
5311
+ }
5312
+ }
5313
+ }
5314
+ async function fetchWithRetry(url, init) {
5315
+ const MAX_RETRIES2 = 3;
5316
+ const BASE_DELAY_MS2 = 200;
5317
+ let lastError;
5318
+ for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
5319
+ try {
5320
+ const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
5321
+ const resp = await fetch(url, { ...init, signal });
5322
+ if (resp && resp.status >= 500 && attempt < MAX_RETRIES2) {
5323
+ await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
5324
+ continue;
5325
+ }
5326
+ return resp;
5327
+ } catch (err) {
5328
+ lastError = err;
5329
+ if (attempt === MAX_RETRIES2) throw err;
5330
+ await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
5331
+ }
5332
+ }
5333
+ throw lastError;
5334
+ }
5335
+ function assertSecureEndpoint(endpoint) {
5336
+ if (endpoint.startsWith("https://")) return;
5337
+ if (endpoint.startsWith("http://")) {
5338
+ try {
5339
+ const parsed = new URL(endpoint);
5340
+ if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
5341
+ } catch {
5342
+ return;
5343
+ }
5344
+ throw new Error(
5345
+ `Insecure cloud endpoint rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost.`
5346
+ );
5347
+ }
5348
+ }
5349
+ async function cloudPush(records, maxVersion, config) {
5350
+ if (records.length === 0) return true;
5351
+ assertSecureEndpoint(config.endpoint);
5352
+ try {
5353
+ const json = JSON.stringify(records);
5354
+ const compressed = compress(Buffer.from(json, "utf8"));
5355
+ const blob = encryptSyncBlob(compressed);
5356
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/push`, {
5357
+ method: "POST",
5358
+ headers: {
5359
+ Authorization: `Bearer ${config.apiKey}`,
5360
+ "Content-Type": "application/json",
5361
+ "X-Device-Id": loadDeviceId(),
5362
+ "X-Expected-Version": String(maxVersion)
5363
+ },
5364
+ body: JSON.stringify({ version: maxVersion, blob })
5365
+ });
5366
+ if (resp == null) {
5367
+ logError("[cloud-sync] PUSH FAILED: no response from server");
5368
+ return false;
5369
+ }
5370
+ if (resp.status === 409) {
5371
+ logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
5372
+ return false;
5373
+ }
5374
+ return resp.ok;
5375
+ } catch (err) {
5376
+ logError(`[cloud-sync] PUSH FAILED: ${err instanceof Error ? err.message : String(err)}`);
5377
+ return false;
5378
+ }
5379
+ }
5380
+ async function cloudPull(sinceVersion, config) {
5381
+ assertSecureEndpoint(config.endpoint);
5382
+ try {
5383
+ const response = await fetchWithRetry(`${config.endpoint}/sync/pull`, {
5384
+ method: "POST",
5385
+ headers: {
5386
+ Authorization: `Bearer ${config.apiKey}`,
5387
+ "Content-Type": "application/json",
5388
+ "X-Device-Id": loadDeviceId()
5389
+ },
5390
+ body: JSON.stringify({ since_version: sinceVersion })
5391
+ });
5392
+ if (response == null) {
5393
+ logError("[cloud-sync] PULL FAILED: no response from server");
5394
+ return { records: [], maxVersion: sinceVersion };
5395
+ }
5396
+ if (!response.ok) return { records: [], maxVersion: sinceVersion };
5397
+ const data = await response.json();
5398
+ const allRecords = [];
5399
+ for (const { blob } of data.blobs ?? []) {
5400
+ try {
5401
+ const compressed = decryptSyncBlob(blob);
5402
+ const json = decompress(compressed).toString("utf8");
5403
+ const records = JSON.parse(json);
5404
+ allRecords.push(...records);
5405
+ } catch {
5406
+ continue;
5407
+ }
5408
+ }
5409
+ return { records: allRecords, maxVersion: data.max_version ?? sinceVersion };
5410
+ } catch (err) {
5411
+ logError(`[cloud-sync] PULL FAILED: ${err instanceof Error ? err.message : String(err)}`);
5412
+ return { records: [], maxVersion: sinceVersion };
5413
+ }
5414
+ }
5415
+ async function cloudSync(config) {
5416
+ let client;
5417
+ try {
5418
+ client = getClient();
5419
+ } catch {
5420
+ throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
5421
+ }
5422
+ try {
5423
+ await client.execute(
5424
+ "CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)"
5425
+ );
5426
+ } catch (e) {
5427
+ logError(`[cloud-sync] sync_meta CREATE failed: ${e instanceof Error ? e.message : String(e)}`);
5428
+ }
5429
+ const pullMeta = await client.execute(
5430
+ "SELECT value FROM sync_meta WHERE key = 'last_cloud_pull_version'"
5431
+ );
5432
+ const lastPullVersion = pullMeta.rows.length > 0 ? Number(pullMeta.rows[0].value) : 0;
5433
+ const pullResult = await cloudPull(lastPullVersion, config);
5434
+ let pulled = 0;
5435
+ if (pullResult.records.length > 0) {
5436
+ const stmts = pullResult.records.map((rec) => ({
5437
+ sql: `INSERT OR REPLACE INTO memories
5438
+ (id, agent_id, agent_role, session_id, timestamp,
5439
+ tool_name, project_name, has_error, raw_text, version,
5440
+ author_device_id, scope)
5441
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5442
+ args: [
5443
+ sqlSafe(rec.id),
5444
+ sqlSafe(rec.agent_id),
5445
+ sqlSafe(rec.agent_role),
5446
+ sqlSafe(rec.session_id),
5447
+ sqlSafe(rec.timestamp),
5448
+ sqlSafe(rec.tool_name),
5449
+ sqlSafe(rec.project_name),
5450
+ sqlSafe(rec.has_error ?? 0),
5451
+ sqlSafe(rec.raw_text ?? ""),
5452
+ sqlSafe(rec.version ?? 0),
5453
+ sqlSafe(rec.author_device_id),
5454
+ sqlSafe(rec.scope ?? "business")
5455
+ ]
5456
+ }));
5457
+ await client.batch(stmts, "write");
5458
+ pulled = pullResult.records.length;
5459
+ }
5460
+ if (pullResult.maxVersion > lastPullVersion) {
5461
+ await client.execute({
5462
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_pull_version', ?)",
5463
+ args: [String(pullResult.maxVersion)]
5464
+ });
5465
+ }
5466
+ const pushMeta = await client.execute(
5467
+ "SELECT value FROM sync_meta WHERE key = 'last_cloud_push_version'"
5468
+ );
5469
+ const lastPushVersion = pushMeta.rows.length > 0 ? Number(pushMeta.rows[0].value) : 0;
5470
+ let pushed = 0;
5471
+ let batchCursor = lastPushVersion;
5472
+ while (true) {
5473
+ const recordsResult = await client.execute({
5474
+ sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
5475
+ tool_name, project_name, has_error, raw_text, version,
5476
+ author_device_id, scope
5477
+ FROM memories
5478
+ WHERE version > ?
5479
+ AND (scope IS NULL OR scope != 'personal')
5480
+ ORDER BY version ASC
5481
+ LIMIT ?`,
5482
+ args: [batchCursor, PUSH_BATCH_SIZE]
5483
+ });
5484
+ if (recordsResult.rows.length === 0) break;
5485
+ const records = recordsResult.rows.map((row) => ({
5486
+ id: row.id,
5487
+ agent_id: row.agent_id,
5488
+ agent_role: row.agent_role,
5489
+ session_id: row.session_id,
5490
+ timestamp: row.timestamp,
5491
+ tool_name: row.tool_name,
5492
+ project_name: row.project_name,
5493
+ has_error: row.has_error,
5494
+ raw_text: row.raw_text,
5495
+ version: row.version,
5496
+ author_device_id: row.author_device_id,
5497
+ scope: row.scope
5498
+ }));
5499
+ const maxVersion = Number(records[records.length - 1].version);
5500
+ const pushOk = await cloudPush(records, maxVersion, config);
5501
+ if (!pushOk) break;
5502
+ await client.execute({
5503
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
5504
+ args: [String(maxVersion)]
5505
+ });
5506
+ pushed += records.length;
5507
+ batchCursor = maxVersion;
5508
+ if (recordsResult.rows.length < PUSH_BATCH_SIZE) break;
5509
+ }
5510
+ try {
5511
+ await cloudPushRoster(config);
5512
+ } catch (err) {
5513
+ logError(`[cloud-sync] Roster push: ${err instanceof Error ? err.message : String(err)}`);
5514
+ }
5515
+ try {
5516
+ await cloudPullRoster(config);
5517
+ } catch (err) {
5518
+ logError(`[cloud-sync] Roster pull: ${err instanceof Error ? err.message : String(err)}`);
5519
+ }
5520
+ try {
5521
+ await cloudPushGlobalProcedures(config);
5522
+ } catch (err) {
5523
+ logError(`[cloud-sync] Global procedures push: ${err instanceof Error ? err.message : String(err)}`);
5524
+ }
5525
+ try {
5526
+ await cloudPullGlobalProcedures(config);
5527
+ } catch (err) {
5528
+ logError(`[cloud-sync] Global procedures pull: ${err instanceof Error ? err.message : String(err)}`);
5529
+ }
5530
+ let behaviorsResult = { pushed: false, pulled: 0 };
5531
+ try {
5532
+ behaviorsResult.pushed = await cloudPushBehaviors(config);
5533
+ } catch (err) {
5534
+ logError(`[cloud-sync] Behaviors push: ${err instanceof Error ? err.message : String(err)}`);
5535
+ }
5536
+ try {
5537
+ const pullResult2 = await cloudPullBehaviors(config);
5538
+ behaviorsResult.pulled = pullResult2.pulled;
5539
+ } catch (err) {
5540
+ logError(`[cloud-sync] Behaviors pull: ${err instanceof Error ? err.message : String(err)}`);
5541
+ }
5542
+ let graphragResult = { pushed: false, pulled: 0 };
5543
+ try {
5544
+ graphragResult.pushed = await cloudPushGraphRAG(config);
5545
+ } catch (err) {
5546
+ logError(`[cloud-sync] GraphRAG push: ${err instanceof Error ? err.message : String(err)}`);
5547
+ }
5548
+ try {
5549
+ const pullResult2 = await cloudPullGraphRAG(config);
5550
+ graphragResult.pulled = pullResult2.pulled;
5551
+ } catch (err) {
5552
+ logError(`[cloud-sync] GraphRAG pull: ${err instanceof Error ? err.message : String(err)}`);
5553
+ }
5554
+ let tasksResult = { pushed: false, pulled: 0 };
5555
+ try {
5556
+ tasksResult.pushed = await cloudPushTasks(config);
5557
+ } catch (err) {
5558
+ logError(`[cloud-sync] Tasks push: ${err instanceof Error ? err.message : String(err)}`);
5559
+ }
5560
+ try {
5561
+ const pullResult2 = await cloudPullTasks(config);
5562
+ tasksResult.pulled = pullResult2.pulled;
5563
+ } catch (err) {
5564
+ logError(`[cloud-sync] Tasks pull: ${err instanceof Error ? err.message : String(err)}`);
5565
+ }
5566
+ let conversationsResult = { pushed: false, pulled: 0 };
5567
+ try {
5568
+ conversationsResult.pushed = await cloudPushConversations(config);
5569
+ } catch (err) {
5570
+ logError(`[cloud-sync] Conversations push: ${err instanceof Error ? err.message : String(err)}`);
5571
+ }
5572
+ try {
5573
+ const pullResult2 = await cloudPullConversations(config);
5574
+ conversationsResult.pulled = pullResult2.pulled;
5575
+ } catch (err) {
5576
+ logError(`[cloud-sync] Conversations pull: ${err instanceof Error ? err.message : String(err)}`);
5577
+ }
5578
+ let documentsResult = { pushed: false, pulled: 0 };
5579
+ try {
5580
+ documentsResult.pushed = await cloudPushDocuments(config);
5581
+ } catch (err) {
5582
+ logError(`[cloud-sync] Documents push: ${err instanceof Error ? err.message : String(err)}`);
5583
+ }
5584
+ try {
5585
+ const pullResult2 = await cloudPullDocuments(config);
5586
+ documentsResult.pulled = pullResult2.pulled;
5587
+ } catch (err) {
5588
+ logError(`[cloud-sync] Documents pull: ${err instanceof Error ? err.message : String(err)}`);
5589
+ }
5590
+ return {
5591
+ pushed,
5592
+ pulled,
5593
+ behaviors: behaviorsResult,
5594
+ graphrag: graphragResult,
5595
+ tasks: tasksResult,
5596
+ conversations: conversationsResult,
5597
+ documents: documentsResult
5598
+ };
5599
+ }
5600
+ function recordRosterDeletion(name) {
5601
+ let deletions = [];
5602
+ try {
5603
+ if (existsSync11(ROSTER_DELETIONS_PATH)) {
5604
+ deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
5605
+ }
5606
+ } catch {
5607
+ }
5608
+ if (!deletions.includes(name)) deletions.push(name);
5609
+ writeFileSync4(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5610
+ }
5611
+ function consumeRosterDeletions() {
5612
+ try {
5613
+ if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
5614
+ const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
5615
+ writeFileSync4(ROSTER_DELETIONS_PATH, "[]");
5616
+ return deletions;
5617
+ } catch {
5618
+ return [];
5619
+ }
5620
+ }
5621
+ function buildRosterBlob(paths) {
5622
+ const rosterPath = paths?.rosterPath ?? path12.join(EXE_AI_DIR, "exe-employees.json");
5623
+ const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5624
+ const configPath = paths?.configPath ?? path12.join(EXE_AI_DIR, "config.json");
5625
+ let roster = [];
5626
+ if (existsSync11(rosterPath)) {
5627
+ try {
5628
+ roster = JSON.parse(readFileSync7(rosterPath, "utf-8"));
5629
+ } catch {
5630
+ }
5631
+ }
5632
+ const identities = {};
5633
+ if (existsSync11(identityDir)) {
5634
+ for (const file of readdirSync2(identityDir).filter((f) => f.endsWith(".md"))) {
5635
+ try {
5636
+ identities[file] = readFileSync7(path12.join(identityDir, file), "utf-8");
5637
+ } catch {
5638
+ }
5639
+ }
5640
+ }
5641
+ let config;
5642
+ if (existsSync11(configPath)) {
5643
+ try {
5644
+ config = JSON.parse(readFileSync7(configPath, "utf-8"));
5645
+ } catch {
5646
+ }
5647
+ }
5648
+ const deletedNames = consumeRosterDeletions();
5649
+ const content = JSON.stringify({ roster, identities, config, deletedNames });
5650
+ const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
5651
+ return { roster, identities, config, deletedNames, version: hash };
5652
+ }
5653
+ async function cloudPushRoster(config) {
5654
+ assertSecureEndpoint(config.endpoint);
5655
+ const blob = buildRosterBlob();
5656
+ if (blob.roster.length === 0) return true;
5657
+ try {
5658
+ const client = getClient();
5659
+ const meta = await client.execute(
5660
+ "SELECT value FROM sync_meta WHERE key = 'last_roster_push_version'"
5661
+ );
5662
+ const lastVersion = meta.rows.length > 0 ? Number(meta.rows[0].value) : 0;
5663
+ if (blob.version === lastVersion) return true;
5664
+ } catch {
5665
+ }
5666
+ try {
5667
+ const json = JSON.stringify(blob);
5668
+ const compressed = compress(Buffer.from(json, "utf8"));
5669
+ const encrypted = encryptSyncBlob(compressed);
5670
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/push-roster`, {
5671
+ method: "POST",
5672
+ headers: {
5673
+ Authorization: `Bearer ${config.apiKey}`,
5674
+ "Content-Type": "application/json",
5675
+ "X-Device-Id": loadDeviceId()
5676
+ },
5677
+ body: JSON.stringify({ blob: encrypted })
5678
+ });
5679
+ if (resp.ok) {
5680
+ try {
5681
+ const client = getClient();
5682
+ await client.execute({
5683
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_roster_push_version', ?)",
5684
+ args: [String(blob.version)]
5685
+ });
5686
+ } catch {
5687
+ }
5688
+ }
5689
+ return resp.ok;
5690
+ } catch (err) {
5691
+ process.stderr.write(`[cloud-sync] ROSTER PUSH FAILED: ${err instanceof Error ? err.message : String(err)}
5692
+ `);
5693
+ return false;
5694
+ }
5695
+ }
5696
+ async function cloudPullRoster(config) {
5697
+ assertSecureEndpoint(config.endpoint);
5698
+ try {
5699
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/pull-roster`, {
5700
+ method: "GET",
5701
+ headers: {
5702
+ Authorization: `Bearer ${config.apiKey}`,
5703
+ "X-Device-Id": loadDeviceId()
5704
+ }
5705
+ });
5706
+ if (!resp.ok) return { added: 0 };
5707
+ const data = await resp.json();
5708
+ if (!data.blob) return { added: 0 };
5709
+ const compressed = decryptSyncBlob(data.blob);
5710
+ const json = decompress(compressed).toString("utf8");
5711
+ const remote = JSON.parse(json);
5712
+ return mergeRosterFromRemote(remote);
5713
+ } catch (err) {
5714
+ process.stderr.write(`[cloud-sync] ROSTER PULL FAILED: ${err instanceof Error ? err.message : String(err)}
5715
+ `);
5716
+ return { added: 0 };
5717
+ }
5718
+ }
5719
+ function mergeConfig(remoteConfig, configPath) {
5720
+ const cfgPath = configPath ?? path12.join(EXE_AI_DIR, "config.json");
5721
+ let local = {};
5722
+ if (existsSync11(cfgPath)) {
5723
+ try {
5724
+ local = JSON.parse(readFileSync7(cfgPath, "utf-8"));
5725
+ } catch {
5726
+ }
5727
+ }
5728
+ const merged = { ...remoteConfig, ...local };
5729
+ const dir = path12.dirname(cfgPath);
5730
+ if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
5731
+ writeFileSync4(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5732
+ }
5733
+ async function mergeRosterFromRemote(remote, paths) {
5734
+ return withRosterLock(async () => {
5735
+ const rosterPath = paths?.rosterPath ?? void 0;
5736
+ const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5737
+ const localEmployees = await loadEmployees(rosterPath);
5738
+ const localNames = new Set(localEmployees.map((e) => e.name));
5739
+ let added = 0;
5740
+ let identitiesUpdated = 0;
5741
+ for (const remoteEmp of remote.roster) {
5742
+ if (!localNames.has(remoteEmp.name)) {
5743
+ localEmployees.push(remoteEmp);
5744
+ localNames.add(remoteEmp.name);
5745
+ added++;
5746
+ try {
5747
+ registerBinSymlinks(remoteEmp.name);
5748
+ } catch {
5749
+ }
5750
+ }
5751
+ const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
5752
+ if (remoteIdentity) {
5753
+ if (!existsSync11(identityDir)) mkdirSync5(identityDir, { recursive: true });
5754
+ const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
5755
+ let localIdentity = null;
5756
+ try {
5757
+ localIdentity = existsSync11(idPath) ? readFileSync7(idPath, "utf-8") : null;
5758
+ } catch {
5759
+ }
5760
+ if (localIdentity !== remoteIdentity) {
5761
+ writeFileSync4(idPath, remoteIdentity, "utf-8");
5762
+ identitiesUpdated++;
5763
+ }
5764
+ }
5765
+ }
5766
+ let removed = 0;
5767
+ if (remote.deletedNames && remote.deletedNames.length > 0) {
5768
+ const toRemove = new Set(remote.deletedNames);
5769
+ const filtered = localEmployees.filter((e) => !toRemove.has(e.name));
5770
+ removed = localEmployees.length - filtered.length;
5771
+ if (removed > 0) {
5772
+ localEmployees.length = 0;
5773
+ localEmployees.push(...filtered);
5774
+ }
5775
+ }
5776
+ if (added > 0 || removed > 0) {
5777
+ await saveEmployees(localEmployees, rosterPath);
5778
+ }
5779
+ if (remote.config && Object.keys(remote.config).length > 0) {
5780
+ try {
5781
+ mergeConfig(remote.config, paths?.configPath);
5782
+ } catch {
5783
+ }
5784
+ }
5785
+ return { added, identitiesUpdated };
5786
+ });
5787
+ }
5788
+ async function cloudPushBlob(route, data, metaKey, config) {
5789
+ if (data.length === 0) return { ok: true };
5790
+ assertSecureEndpoint(config.endpoint);
5791
+ const json = JSON.stringify(data);
5792
+ const version = Buffer.from(json).length;
5793
+ try {
5794
+ const client = getClient();
5795
+ const meta = await client.execute({
5796
+ sql: "SELECT value FROM sync_meta WHERE key = ?",
5797
+ args: [metaKey]
5798
+ });
5799
+ const lastVersion = meta.rows.length > 0 ? Number(meta.rows[0].value) : 0;
5800
+ if (version === lastVersion) return { ok: true };
5801
+ } catch {
5802
+ }
5803
+ try {
5804
+ const compressed = compress(Buffer.from(json, "utf8"));
5805
+ const encrypted = encryptSyncBlob(compressed);
5806
+ const resp = await fetchWithRetry(`${config.endpoint}${route}`, {
5807
+ method: "POST",
5808
+ headers: {
5809
+ Authorization: `Bearer ${config.apiKey}`,
5810
+ "Content-Type": "application/json",
5811
+ "X-Device-Id": loadDeviceId()
5812
+ },
5813
+ body: JSON.stringify({ blob: encrypted })
5814
+ });
5815
+ if (resp.ok) {
5816
+ try {
5817
+ const client = getClient();
5818
+ await client.execute({
5819
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES (?, ?)",
5820
+ args: [metaKey, String(version)]
5821
+ });
5822
+ } catch {
5823
+ }
5824
+ }
5825
+ return { ok: resp.ok };
5826
+ } catch (err) {
5827
+ logError(`[cloud-sync] PUSH ${route}: ${err instanceof Error ? err.message : String(err)}`);
5828
+ return { ok: false };
5829
+ }
5830
+ }
5831
+ async function cloudPullBlob(route, config) {
5832
+ assertSecureEndpoint(config.endpoint);
5833
+ try {
5834
+ const resp = await fetchWithRetry(`${config.endpoint}${route}`, {
5835
+ method: "GET",
5836
+ headers: {
5837
+ Authorization: `Bearer ${config.apiKey}`,
5838
+ "X-Device-Id": loadDeviceId()
5839
+ }
5840
+ });
5841
+ if (!resp.ok) return null;
5842
+ const data = await resp.json();
5843
+ if (!data.blob) return null;
5844
+ const compressed = decryptSyncBlob(data.blob);
5845
+ const json = decompress(compressed).toString("utf8");
5846
+ return JSON.parse(json);
5847
+ } catch (err) {
5848
+ logError(`[cloud-sync] PULL ${route}: ${err instanceof Error ? err.message : String(err)}`);
5849
+ return null;
5850
+ }
5851
+ }
5852
+ async function cloudPushGlobalProcedures(config) {
5853
+ const client = getClient();
5854
+ const result = await client.execute("SELECT * FROM global_procedures LIMIT 1000");
5855
+ const rows = result.rows;
5856
+ const { ok } = await cloudPushBlob(
5857
+ "/sync/push-global-procedures",
5858
+ rows,
5859
+ "last_global_procedures_push_version",
5860
+ config
5861
+ );
5862
+ return ok;
5863
+ }
5864
+ async function cloudPullGlobalProcedures(config) {
5865
+ const remoteProcs = await cloudPullBlob(
5866
+ "/sync/pull-global-procedures",
5867
+ config
5868
+ );
5869
+ if (!remoteProcs || remoteProcs.length === 0) return { pulled: 0 };
5870
+ const client = getClient();
5871
+ const stmts = remoteProcs.map((p) => ({
5872
+ sql: `INSERT INTO global_procedures
5873
+ (id, title, content, priority, domain, active, created_at, updated_at)
5874
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
5875
+ ON CONFLICT(id) DO UPDATE SET
5876
+ title = excluded.title,
5877
+ content = excluded.content,
5878
+ priority = excluded.priority,
5879
+ domain = excluded.domain,
5880
+ active = excluded.active,
5881
+ updated_at = excluded.updated_at
5882
+ WHERE excluded.updated_at > global_procedures.updated_at`,
5883
+ args: [
5884
+ sqlSafe(p.id),
5885
+ sqlSafe(p.title),
5886
+ sqlSafe(p.content),
5887
+ sqlSafe(p.priority ?? "p0"),
5888
+ sqlSafe(p.domain),
5889
+ sqlSafe(p.active ?? 1),
5890
+ sqlSafe(p.created_at),
5891
+ sqlSafe(p.updated_at)
5892
+ ]
5893
+ }));
5894
+ await client.batch(stmts, "write");
5895
+ return { pulled: remoteProcs.length };
5896
+ }
5897
+ async function cloudPushBehaviors(config) {
5898
+ const client = getClient();
5899
+ const result = await client.execute("SELECT * FROM behaviors LIMIT 10000");
5900
+ const rows = result.rows;
5901
+ const { ok } = await cloudPushBlob(
5902
+ "/sync/push-behaviors",
5903
+ rows,
5904
+ "last_behaviors_push_version",
5905
+ config
5906
+ );
5907
+ return ok;
5908
+ }
5909
+ async function cloudPullBehaviors(config) {
5910
+ const remoteBehaviors = await cloudPullBlob(
5911
+ "/sync/pull-behaviors",
5912
+ config
5913
+ );
5914
+ if (!remoteBehaviors || remoteBehaviors.length === 0) return { pulled: 0 };
5915
+ const client = getClient();
5916
+ let pulled = 0;
5917
+ for (const behavior of remoteBehaviors) {
5918
+ const existing = await client.execute({
5919
+ sql: `SELECT COUNT(*) as cnt FROM behaviors
5920
+ WHERE agent_id = ? AND content = ?`,
5921
+ args: [sqlSafe(behavior.agent_id), sqlSafe(behavior.content)]
5922
+ });
5923
+ if (Number(existing.rows[0]?.cnt) > 0) continue;
5924
+ await client.execute({
5925
+ sql: `INSERT OR IGNORE INTO behaviors
5926
+ (id, agent_id, project_name, domain, content, active, priority, created_at, updated_at)
5927
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5928
+ args: [
5929
+ sqlSafe(behavior.id),
5930
+ sqlSafe(behavior.agent_id),
5931
+ sqlSafe(behavior.project_name),
5932
+ sqlSafe(behavior.domain),
5933
+ sqlSafe(behavior.content),
5934
+ sqlSafe(behavior.active ?? 1),
5935
+ sqlSafe(behavior.priority ?? "p1"),
5936
+ sqlSafe(behavior.created_at),
5937
+ sqlSafe(behavior.updated_at)
5938
+ ]
5939
+ });
5940
+ pulled++;
5941
+ }
5942
+ return { pulled };
5943
+ }
5944
+ async function cloudPushGraphRAG(config) {
5945
+ const client = getClient();
5946
+ const [entities, relationships, aliases, entityMems, relMems, hyperedges, hyperedgeNodes] = await Promise.all([
5947
+ client.execute("SELECT * FROM entities LIMIT 50000"),
5948
+ client.execute("SELECT * FROM relationships LIMIT 50000"),
5949
+ client.execute("SELECT * FROM entity_aliases LIMIT 50000"),
5950
+ client.execute("SELECT * FROM entity_memories LIMIT 50000"),
5951
+ client.execute("SELECT * FROM relationship_memories LIMIT 50000"),
5952
+ client.execute("SELECT * FROM hyperedges LIMIT 50000"),
5953
+ client.execute("SELECT * FROM hyperedge_nodes LIMIT 50000")
5954
+ ]);
5955
+ const blob = {
5956
+ entities: entities.rows,
5957
+ relationships: relationships.rows,
5958
+ entity_aliases: aliases.rows,
5959
+ entity_memories: entityMems.rows,
5960
+ relationship_memories: relMems.rows,
5961
+ hyperedges: hyperedges.rows,
5962
+ hyperedge_nodes: hyperedgeNodes.rows
5963
+ };
5964
+ const { ok } = await cloudPushBlob(
5965
+ "/sync/push-graphrag",
5966
+ [blob],
5967
+ "last_graphrag_push_version",
5968
+ config
5969
+ );
5970
+ return ok;
5971
+ }
5972
+ async function cloudPullGraphRAG(config) {
5973
+ const data = await cloudPullBlob(
5974
+ "/sync/pull-graphrag",
5975
+ config
5976
+ );
5977
+ if (!data || data.length === 0) return { pulled: 0 };
5978
+ const blob = data[0];
5979
+ const client = getClient();
5980
+ let pulled = 0;
5981
+ if (blob.entities.length > 0) {
5982
+ const stmts = blob.entities.map((e) => ({
5983
+ sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen, properties)
5984
+ VALUES (?, ?, ?, ?, ?, ?)`,
5985
+ args: [sqlSafe(e.id), sqlSafe(e.name), sqlSafe(e.type), sqlSafe(e.first_seen), sqlSafe(e.last_seen), sqlSafe(e.properties ?? "{}")]
5986
+ }));
5987
+ await client.batch(stmts, "write");
5988
+ pulled += stmts.length;
5989
+ }
5990
+ if (blob.relationships.length > 0) {
5991
+ const stmts = blob.relationships.map((r) => ({
5992
+ sql: `INSERT OR IGNORE INTO relationships
5993
+ (id, source_entity_id, target_entity_id, type, weight, timestamp, properties, confidence, confidence_label)
5994
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5995
+ args: [
5996
+ sqlSafe(r.id),
5997
+ sqlSafe(r.source_entity_id),
5998
+ sqlSafe(r.target_entity_id),
5999
+ sqlSafe(r.type),
6000
+ sqlSafe(r.weight ?? 1),
6001
+ sqlSafe(r.timestamp),
6002
+ sqlSafe(r.properties ?? "{}"),
6003
+ sqlSafe(r.confidence ?? 1),
6004
+ sqlSafe(r.confidence_label ?? "extracted")
6005
+ ]
6006
+ }));
6007
+ await client.batch(stmts, "write");
6008
+ pulled += stmts.length;
6009
+ }
6010
+ if (blob.entity_aliases.length > 0) {
6011
+ const stmts = blob.entity_aliases.map((a) => ({
6012
+ sql: `INSERT OR IGNORE INTO entity_aliases (alias, canonical_entity_id) VALUES (?, ?)`,
6013
+ args: [sqlSafe(a.alias), sqlSafe(a.canonical_entity_id)]
6014
+ }));
6015
+ await client.batch(stmts, "write");
6016
+ pulled += stmts.length;
5147
6017
  }
6018
+ if (blob.entity_memories.length > 0) {
6019
+ const stmts = blob.entity_memories.map((em) => ({
6020
+ sql: `INSERT OR IGNORE INTO entity_memories (entity_id, memory_id) VALUES (?, ?)`,
6021
+ args: [sqlSafe(em.entity_id), sqlSafe(em.memory_id)]
6022
+ }));
6023
+ await client.batch(stmts, "write");
6024
+ pulled += stmts.length;
6025
+ }
6026
+ if (blob.relationship_memories.length > 0) {
6027
+ const stmts = blob.relationship_memories.map((rm) => ({
6028
+ sql: `INSERT OR IGNORE INTO relationship_memories (relationship_id, memory_id) VALUES (?, ?)`,
6029
+ args: [sqlSafe(rm.relationship_id), sqlSafe(rm.memory_id)]
6030
+ }));
6031
+ await client.batch(stmts, "write");
6032
+ pulled += stmts.length;
6033
+ }
6034
+ if (blob.hyperedges.length > 0) {
6035
+ const stmts = blob.hyperedges.map((h) => ({
6036
+ sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
6037
+ VALUES (?, ?, ?, ?, ?)`,
6038
+ args: [sqlSafe(h.id), sqlSafe(h.label), sqlSafe(h.relation), sqlSafe(h.confidence ?? 1), sqlSafe(h.timestamp)]
6039
+ }));
6040
+ await client.batch(stmts, "write");
6041
+ pulled += stmts.length;
6042
+ }
6043
+ if (blob.hyperedge_nodes.length > 0) {
6044
+ const stmts = blob.hyperedge_nodes.map((hn) => ({
6045
+ sql: `INSERT OR IGNORE INTO hyperedge_nodes (hyperedge_id, entity_id) VALUES (?, ?)`,
6046
+ args: [sqlSafe(hn.hyperedge_id), sqlSafe(hn.entity_id)]
6047
+ }));
6048
+ await client.batch(stmts, "write");
6049
+ pulled += stmts.length;
6050
+ }
6051
+ return { pulled };
5148
6052
  }
5149
- function stopLicenseRevalidation() {
5150
- if (_revalTimer) {
5151
- clearInterval(_revalTimer);
5152
- _revalTimer = null;
6053
+ async function cloudPushTasks(config) {
6054
+ const client = getClient();
6055
+ const result = await client.execute("SELECT * FROM tasks LIMIT 10000");
6056
+ const rows = result.rows;
6057
+ const { ok } = await cloudPushBlob(
6058
+ "/sync/push-tasks",
6059
+ rows,
6060
+ "last_tasks_push_version",
6061
+ config
6062
+ );
6063
+ return ok;
6064
+ }
6065
+ async function cloudPullTasks(config) {
6066
+ const remoteTasks = await cloudPullBlob(
6067
+ "/sync/pull-tasks",
6068
+ config
6069
+ );
6070
+ if (!remoteTasks || remoteTasks.length === 0) return { pulled: 0 };
6071
+ const client = getClient();
6072
+ const stmts = remoteTasks.map((t) => ({
6073
+ sql: `INSERT OR IGNORE INTO tasks
6074
+ (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, created_at, updated_at,
6075
+ blocked_by, parent_task_id, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at)
6076
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6077
+ args: [
6078
+ sqlSafe(t.id),
6079
+ sqlSafe(t.title),
6080
+ sqlSafe(t.assigned_to),
6081
+ sqlSafe(t.assigned_by),
6082
+ sqlSafe(t.project_name),
6083
+ sqlSafe(t.priority ?? "p1"),
6084
+ sqlSafe(t.status ?? "open"),
6085
+ sqlSafe(t.task_file),
6086
+ sqlSafe(t.created_at),
6087
+ sqlSafe(t.updated_at),
6088
+ sqlSafe(t.blocked_by),
6089
+ sqlSafe(t.parent_task_id),
6090
+ sqlSafe(t.budget_tokens),
6091
+ sqlSafe(t.budget_fallback_model),
6092
+ sqlSafe(t.tokens_used ?? 0),
6093
+ sqlSafe(t.tokens_warned_at)
6094
+ ]
6095
+ }));
6096
+ await client.batch(stmts, "write");
6097
+ return { pulled: remoteTasks.length };
6098
+ }
6099
+ async function cloudPushConversations(config) {
6100
+ const client = getClient();
6101
+ const result = await client.execute("SELECT * FROM conversations LIMIT 50000");
6102
+ const rows = result.rows;
6103
+ const { ok } = await cloudPushBlob(
6104
+ "/sync/push-conversations",
6105
+ rows,
6106
+ "last_conversations_push_version",
6107
+ config
6108
+ );
6109
+ return ok;
6110
+ }
6111
+ async function cloudPullConversations(config) {
6112
+ const remoteConvos = await cloudPullBlob(
6113
+ "/sync/pull-conversations",
6114
+ config
6115
+ );
6116
+ if (!remoteConvos || remoteConvos.length === 0) return { pulled: 0 };
6117
+ const client = getClient();
6118
+ const stmts = remoteConvos.map((c) => ({
6119
+ sql: `INSERT OR IGNORE INTO conversations
6120
+ (id, platform, external_id, sender_id, sender_name, sender_phone, sender_email,
6121
+ recipient_id, channel_id, thread_id, reply_to_id, content_text, content_media,
6122
+ content_metadata, agent_response, agent_name, timestamp, ingested_at)
6123
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6124
+ args: [
6125
+ sqlSafe(c.id),
6126
+ sqlSafe(c.platform),
6127
+ sqlSafe(c.external_id),
6128
+ sqlSafe(c.sender_id),
6129
+ sqlSafe(c.sender_name),
6130
+ sqlSafe(c.sender_phone),
6131
+ sqlSafe(c.sender_email),
6132
+ sqlSafe(c.recipient_id),
6133
+ sqlSafe(c.channel_id),
6134
+ sqlSafe(c.thread_id),
6135
+ sqlSafe(c.reply_to_id),
6136
+ sqlSafe(c.content_text),
6137
+ sqlSafe(c.content_media),
6138
+ sqlSafe(c.content_metadata),
6139
+ sqlSafe(c.agent_response),
6140
+ sqlSafe(c.agent_name),
6141
+ sqlSafe(c.timestamp),
6142
+ sqlSafe(c.ingested_at)
6143
+ ]
6144
+ }));
6145
+ await client.batch(stmts, "write");
6146
+ return { pulled: remoteConvos.length };
6147
+ }
6148
+ async function cloudPushDocuments(config) {
6149
+ const client = getClient();
6150
+ const [workspaces, documents] = await Promise.all([
6151
+ client.execute("SELECT * FROM workspaces LIMIT 1000"),
6152
+ client.execute("SELECT * FROM documents LIMIT 10000")
6153
+ ]);
6154
+ const blob = {
6155
+ workspaces: workspaces.rows,
6156
+ documents: documents.rows
6157
+ };
6158
+ const { ok } = await cloudPushBlob(
6159
+ "/sync/push-documents",
6160
+ [blob],
6161
+ "last_documents_push_version",
6162
+ config
6163
+ );
6164
+ return ok;
6165
+ }
6166
+ async function cloudPullDocuments(config) {
6167
+ const data = await cloudPullBlob(
6168
+ "/sync/pull-documents",
6169
+ config
6170
+ );
6171
+ if (!data || data.length === 0) return { pulled: 0 };
6172
+ const blob = data[0];
6173
+ const client = getClient();
6174
+ let pulled = 0;
6175
+ if (blob.workspaces.length > 0) {
6176
+ const stmts = blob.workspaces.map((w) => ({
6177
+ sql: `INSERT OR IGNORE INTO workspaces (id, slug, name, owner_agent_id, created_at, metadata)
6178
+ VALUES (?, ?, ?, ?, ?, ?)`,
6179
+ args: [sqlSafe(w.id), sqlSafe(w.slug), sqlSafe(w.name), sqlSafe(w.owner_agent_id), sqlSafe(w.created_at), sqlSafe(w.metadata)]
6180
+ }));
6181
+ await client.batch(stmts, "write");
6182
+ pulled += stmts.length;
6183
+ }
6184
+ if (blob.documents.length > 0) {
6185
+ const stmts = blob.documents.map((d) => ({
6186
+ sql: `INSERT OR IGNORE INTO documents
6187
+ (id, workspace_id, filename, mime, source_type, user_id, uploaded_at, metadata)
6188
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
6189
+ args: [
6190
+ sqlSafe(d.id),
6191
+ sqlSafe(d.workspace_id),
6192
+ sqlSafe(d.filename),
6193
+ sqlSafe(d.mime),
6194
+ sqlSafe(d.source_type),
6195
+ sqlSafe(d.user_id),
6196
+ sqlSafe(d.uploaded_at),
6197
+ sqlSafe(d.metadata)
6198
+ ]
6199
+ }));
6200
+ await client.batch(stmts, "write");
6201
+ pulled += stmts.length;
5153
6202
  }
6203
+ return { pulled };
5154
6204
  }
5155
- 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;
5156
- var init_license = __esm({
5157
- "src/lib/license.ts"() {
6205
+ var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
6206
+ var init_cloud_sync = __esm({
6207
+ "src/lib/cloud-sync.ts"() {
5158
6208
  "use strict";
6209
+ init_database();
6210
+ init_crypto();
6211
+ init_compress();
6212
+ init_license();
5159
6213
  init_config();
5160
- LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
5161
- CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
5162
- DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
5163
- API_BASE = "https://askexe.com/cloud";
5164
- RETRY_DELAY_MS = 500;
5165
- LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
5166
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
5167
- 4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
5168
- -----END PUBLIC KEY-----`;
5169
- LICENSE_JWT_ALG = "ES256";
5170
- PLAN_LIMITS = {
5171
- free: { devices: 1, employees: 1, memories: 5e4 },
5172
- pro: { devices: 2, employees: 5, memories: 25e4 },
5173
- team: { devices: 10, employees: 20, memories: 1e6 },
5174
- agency: { devices: 50, employees: 100, memories: 1e7 },
5175
- enterprise: { devices: -1, employees: -1, memories: -1 }
5176
- };
5177
- FREE_LICENSE = {
5178
- valid: true,
5179
- plan: "free",
5180
- email: "",
5181
- expiresAt: null,
5182
- deviceLimit: 1,
5183
- employeeLimit: 1,
5184
- memoryLimit: 5e4
5185
- };
5186
- CACHE_MAX_AGE_MS = 36e5;
5187
- _revalTimer = null;
6214
+ init_employees();
6215
+ LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
6216
+ FETCH_TIMEOUT_MS = 3e4;
6217
+ PUSH_BATCH_SIZE = 5e3;
6218
+ ROSTER_LOCK_PATH = path12.join(EXE_AI_DIR, "roster-merge.lock");
6219
+ LOCK_STALE_MS = 3e4;
6220
+ ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
5188
6221
  }
5189
6222
  });
5190
6223
 
@@ -5197,17 +6230,17 @@ __export(identity_exports, {
5197
6230
  listIdentities: () => listIdentities,
5198
6231
  updateIdentity: () => updateIdentity
5199
6232
  });
5200
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
5201
- import { readdirSync as readdirSync2 } from "fs";
5202
- import path12 from "path";
6233
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
6234
+ import { readdirSync as readdirSync3 } from "fs";
6235
+ import path13 from "path";
5203
6236
  import { createHash as createHash2 } from "crypto";
5204
6237
  function ensureDir() {
5205
- if (!existsSync11(IDENTITY_DIR)) {
5206
- mkdirSync5(IDENTITY_DIR, { recursive: true });
6238
+ if (!existsSync12(IDENTITY_DIR)) {
6239
+ mkdirSync6(IDENTITY_DIR, { recursive: true });
5207
6240
  }
5208
6241
  }
5209
6242
  function identityPath(agentId) {
5210
- return path12.join(IDENTITY_DIR, `${agentId}.md`);
6243
+ return path13.join(IDENTITY_DIR, `${agentId}.md`);
5211
6244
  }
5212
6245
  function parseFrontmatter(raw) {
5213
6246
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -5248,8 +6281,8 @@ function contentHash(content) {
5248
6281
  }
5249
6282
  function getIdentity(agentId) {
5250
6283
  const filePath = identityPath(agentId);
5251
- if (!existsSync11(filePath)) return null;
5252
- const raw = readFileSync7(filePath, "utf-8");
6284
+ if (!existsSync12(filePath)) return null;
6285
+ const raw = readFileSync8(filePath, "utf-8");
5253
6286
  const { frontmatter, body } = parseFrontmatter(raw);
5254
6287
  return {
5255
6288
  agentId,
@@ -5263,7 +6296,7 @@ async function updateIdentity(agentId, content, updatedBy) {
5263
6296
  ensureDir();
5264
6297
  const filePath = identityPath(agentId);
5265
6298
  const hash = contentHash(content);
5266
- writeFileSync4(filePath, content, "utf-8");
6299
+ writeFileSync5(filePath, content, "utf-8");
5267
6300
  try {
5268
6301
  const client = getClient();
5269
6302
  await client.execute({
@@ -5280,7 +6313,7 @@ async function updateIdentity(agentId, content, updatedBy) {
5280
6313
  }
5281
6314
  function listIdentities() {
5282
6315
  ensureDir();
5283
- const files = readdirSync2(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
6316
+ const files = readdirSync3(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
5284
6317
  const results = [];
5285
6318
  for (const file of files) {
5286
6319
  const agentId = file.replace(".md", "");
@@ -5319,7 +6352,7 @@ var init_identity = __esm({
5319
6352
  "use strict";
5320
6353
  init_config();
5321
6354
  init_database();
5322
- IDENTITY_DIR = path12.join(EXE_AI_DIR, "identity");
6355
+ IDENTITY_DIR = path13.join(EXE_AI_DIR, "identity");
5323
6356
  }
5324
6357
  });
5325
6358
 
@@ -5853,31 +6886,162 @@ ${PLAN_MODE_COMPAT}
5853
6886
  }
5854
6887
  });
5855
6888
 
6889
+ // src/lib/session-wrappers.ts
6890
+ var session_wrappers_exports = {};
6891
+ __export(session_wrappers_exports, {
6892
+ generateSessionWrappers: () => generateSessionWrappers
6893
+ });
6894
+ import {
6895
+ existsSync as existsSync13,
6896
+ readFileSync as readFileSync9,
6897
+ writeFileSync as writeFileSync6,
6898
+ mkdirSync as mkdirSync7,
6899
+ chmodSync,
6900
+ readdirSync as readdirSync4,
6901
+ unlinkSync as unlinkSync5
6902
+ } from "fs";
6903
+ import path14 from "path";
6904
+ import { homedir as homedir4 } from "os";
6905
+ function generateSessionWrappers(packageRoot, homeDir) {
6906
+ const home = homeDir ?? homedir4();
6907
+ const binDir = path14.join(home, ".exe-os", "bin");
6908
+ const rosterPath = path14.join(home, ".exe-os", "exe-employees.json");
6909
+ mkdirSync7(binDir, { recursive: true });
6910
+ const exeStartDst = path14.join(binDir, "exe-start");
6911
+ const candidates = [
6912
+ path14.join(packageRoot, "dist", "bin", "exe-start.sh"),
6913
+ path14.join(packageRoot, "src", "bin", "exe-start.sh")
6914
+ ];
6915
+ for (const src of candidates) {
6916
+ if (existsSync13(src)) {
6917
+ writeFileSync6(exeStartDst, readFileSync9(src));
6918
+ chmodSync(exeStartDst, 493);
6919
+ break;
6920
+ }
6921
+ }
6922
+ let employees = [];
6923
+ try {
6924
+ employees = JSON.parse(readFileSync9(rosterPath, "utf8"));
6925
+ } catch {
6926
+ return { created: 0, pathConfigured: false };
6927
+ }
6928
+ if (employees.length === 0) {
6929
+ return { created: 0, pathConfigured: false };
6930
+ }
6931
+ try {
6932
+ for (const f of readdirSync4(binDir)) {
6933
+ if (f === "exe-start") continue;
6934
+ const fPath = path14.join(binDir, f);
6935
+ try {
6936
+ const content = readFileSync9(fPath, "utf8");
6937
+ if (content.includes("exe-start")) {
6938
+ unlinkSync5(fPath);
6939
+ }
6940
+ } catch {
6941
+ }
6942
+ }
6943
+ } catch {
6944
+ }
6945
+ let created = 0;
6946
+ const wrapperContent = `#!/bin/bash
6947
+ exec "${exeStartDst}" "$0" "$@"
6948
+ `;
6949
+ for (const emp of employees) {
6950
+ for (let n = 1; n <= MAX_N; n++) {
6951
+ const wrapperPath = path14.join(binDir, `${emp.name}${n}`);
6952
+ writeFileSync6(wrapperPath, wrapperContent);
6953
+ chmodSync(wrapperPath, 493);
6954
+ created++;
6955
+ }
6956
+ }
6957
+ const pathConfigured = ensurePath(home, binDir);
6958
+ return { created, pathConfigured };
6959
+ }
6960
+ function ensurePath(home, binDir) {
6961
+ if (process.env.PATH?.split(":").includes(binDir)) {
6962
+ return false;
6963
+ }
6964
+ const exportLine = `
6965
+ # exe-os session commands
6966
+ export PATH="${binDir}:$PATH"
6967
+ `;
6968
+ const shell = process.env.SHELL ?? "/bin/bash";
6969
+ const profilePaths = [];
6970
+ if (shell.includes("zsh")) {
6971
+ profilePaths.push(path14.join(home, ".zshrc"));
6972
+ } else if (shell.includes("bash")) {
6973
+ profilePaths.push(path14.join(home, ".bashrc"));
6974
+ profilePaths.push(path14.join(home, ".bash_profile"));
6975
+ } else {
6976
+ profilePaths.push(path14.join(home, ".profile"));
6977
+ }
6978
+ for (const profilePath of profilePaths) {
6979
+ try {
6980
+ let content = "";
6981
+ try {
6982
+ content = readFileSync9(profilePath, "utf8");
6983
+ } catch {
6984
+ }
6985
+ if (content.includes(".exe-os/bin")) {
6986
+ return false;
6987
+ }
6988
+ writeFileSync6(profilePath, content + exportLine);
6989
+ return true;
6990
+ } catch {
6991
+ continue;
6992
+ }
6993
+ }
6994
+ return false;
6995
+ }
6996
+ var MAX_N;
6997
+ var init_session_wrappers = __esm({
6998
+ "src/lib/session-wrappers.ts"() {
6999
+ "use strict";
7000
+ MAX_N = 9;
7001
+ }
7002
+ });
7003
+
5856
7004
  // src/lib/setup-wizard.ts
5857
7005
  var setup_wizard_exports = {};
5858
7006
  __export(setup_wizard_exports, {
5859
7007
  runSetupWizard: () => runSetupWizard,
5860
7008
  validateModel: () => validateModel
5861
7009
  });
5862
- import crypto3 from "crypto";
5863
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4 } from "fs";
7010
+ import crypto4 from "crypto";
7011
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync7, unlinkSync as unlinkSync6 } from "fs";
5864
7012
  import os5 from "os";
5865
- import path13 from "path";
7013
+ import path15 from "path";
5866
7014
  import { createInterface as createInterface2 } from "readline";
7015
+ function findPackageRoot2() {
7016
+ let dir = path15.dirname(new URL(import.meta.url).pathname);
7017
+ const root = path15.parse(dir).root;
7018
+ while (dir !== root) {
7019
+ const pkgPath = path15.join(dir, "package.json");
7020
+ if (existsSync14(pkgPath)) {
7021
+ try {
7022
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
7023
+ if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
7024
+ } catch {
7025
+ }
7026
+ }
7027
+ dir = path15.dirname(dir);
7028
+ }
7029
+ return null;
7030
+ }
5867
7031
  function loadSetupState() {
5868
7032
  try {
5869
- return JSON.parse(readFileSync8(SETUP_STATE_PATH, "utf8"));
7033
+ return JSON.parse(readFileSync10(SETUP_STATE_PATH, "utf8"));
5870
7034
  } catch {
5871
7035
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
5872
7036
  }
5873
7037
  }
5874
7038
  function saveSetupState(state) {
5875
- mkdirSync6(path13.dirname(SETUP_STATE_PATH), { recursive: true });
5876
- writeFileSync5(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7039
+ mkdirSync8(path15.dirname(SETUP_STATE_PATH), { recursive: true });
7040
+ writeFileSync7(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
5877
7041
  }
5878
7042
  function clearSetupState() {
5879
7043
  try {
5880
- unlinkSync4(SETUP_STATE_PATH);
7044
+ unlinkSync6(SETUP_STATE_PATH);
5881
7045
  } catch {
5882
7046
  }
5883
7047
  }
@@ -5911,20 +7075,67 @@ async function runSetupWizard(opts = {}) {
5911
7075
  log("");
5912
7076
  log("=== exe-os Setup ===");
5913
7077
  log("");
5914
- log("Already set up on another device?");
5915
- log(" Run `exe-link` to sync your encryption key and skip setup.");
7078
+ log("Is this a new installation or pairing with an existing device?");
5916
7079
  log("");
5917
- const skipSetup = await ask(rl, "Fresh install? (Y/n): ");
5918
- if (skipSetup.toLowerCase() === "n") {
5919
- log("Run `exe-link` to import your encryption key from another device.");
5920
- rl.close();
5921
- return;
7080
+ log(" [1] New installation (first device)");
7081
+ log(" [2] Pair with existing device (I have a 24-word phrase)");
7082
+ log("");
7083
+ const installType = await ask(rl, "Choice (1/2): ");
7084
+ let isPairing = false;
7085
+ let pairingRosterPulled = false;
7086
+ if (installType === "2") {
7087
+ isPairing = true;
7088
+ log("");
7089
+ const { importMnemonic: importMnemonic2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
7090
+ const mnemonic = await ask(rl, "Paste your 24-word recovery phrase: ");
7091
+ try {
7092
+ const key = await importMnemonic2(mnemonic);
7093
+ await setMasterKey(key);
7094
+ log("Master key imported and stored securely.");
7095
+ log("");
7096
+ log("Enter the API key from your existing device.");
7097
+ log("(Find it in ~/.exe-os/config.json under cloud.apiKey, or ask your team lead.)");
7098
+ log("");
7099
+ const apiKey = await ask(rl, "API key (exe_sk_...): ");
7100
+ if (apiKey && apiKey.startsWith("exe_sk_")) {
7101
+ const cloudEndpoint = "https://askexe.com/cloud";
7102
+ const cloudCfg = { apiKey, endpoint: cloudEndpoint };
7103
+ const earlyConfig = await loadConfig();
7104
+ earlyConfig.cloud = cloudCfg;
7105
+ await saveConfig(earlyConfig);
7106
+ const { saveLicense: saveLic, mirrorLicenseKey: mirrorLic } = await Promise.resolve().then(() => (init_license(), license_exports));
7107
+ saveLic(apiKey);
7108
+ mirrorLic(apiKey);
7109
+ log("Cloud sync configured.");
7110
+ try {
7111
+ const { initSyncCrypto: initSyncCrypto2 } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
7112
+ const { cloudPullRoster: cloudPullRoster2 } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
7113
+ initSyncCrypto2(key);
7114
+ const result = await cloudPullRoster2({ apiKey, endpoint: cloudEndpoint });
7115
+ if (result.added > 0) {
7116
+ log(`Pulled ${result.added} employee(s) from Exe Cloud.`);
7117
+ pairingRosterPulled = true;
7118
+ }
7119
+ } catch {
7120
+ log("Could not pull roster from cloud \u2014 you can set up employees manually.");
7121
+ }
7122
+ } else {
7123
+ log("No API key provided \u2014 cloud sync will need to be configured later.");
7124
+ log("Run /exe-cloud after setup to connect.");
7125
+ }
7126
+ log("");
7127
+ } catch (err) {
7128
+ log(`Key import failed: ${err instanceof Error ? err.message : String(err)}`);
7129
+ log("Check your phrase and try again, or choose option 1 for a fresh install.");
7130
+ rl.close();
7131
+ return;
7132
+ }
5922
7133
  }
5923
7134
  const state = loadSetupState();
5924
7135
  if (state.completedSteps.length > 0) {
5925
7136
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
5926
7137
  }
5927
- if (existsSync12(LEGACY_LANCE_PATH)) {
7138
+ if (existsSync14(LEGACY_LANCE_PATH)) {
5928
7139
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
5929
7140
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
5930
7141
  log(" The old directory will not be modified or deleted.");
@@ -5936,7 +7147,7 @@ async function runSetupWizard(opts = {}) {
5936
7147
  log("Encryption key already exists \u2014 skipping generation.");
5937
7148
  } else {
5938
7149
  log("Generating 256-bit encryption key...");
5939
- const key = crypto3.randomBytes(32);
7150
+ const key = crypto4.randomBytes(32);
5940
7151
  await setMasterKey(key);
5941
7152
  log("Encryption key generated and stored securely.");
5942
7153
  }
@@ -5947,7 +7158,15 @@ async function runSetupWizard(opts = {}) {
5947
7158
  }
5948
7159
  log("");
5949
7160
  let cloudConfig;
5950
- if (!state.completedSteps.includes(2)) {
7161
+ if (isPairing) {
7162
+ const pairingConfig = await loadConfig();
7163
+ if (pairingConfig.cloud?.apiKey) {
7164
+ cloudConfig = pairingConfig.cloud;
7165
+ log("Cloud sync: using shared API key from pairing.");
7166
+ }
7167
+ state.completedSteps.push(2);
7168
+ saveSetupState(state);
7169
+ } else if (!state.completedSteps.includes(2)) {
5951
7170
  log("Exe Cloud: your memories are end-to-end encrypted, compressed, and");
5952
7171
  log("backed up on Exe Cloud. Free for all plans. We can't read your data \u2014");
5953
7172
  log("only your encryption key can decrypt it.");
@@ -6028,10 +7247,10 @@ async function runSetupWizard(opts = {}) {
6028
7247
  await saveConfig(config);
6029
7248
  log("");
6030
7249
  try {
6031
- const claudeJsonPath = path13.join(os5.homedir(), ".claude.json");
7250
+ const claudeJsonPath = path15.join(os5.homedir(), ".claude.json");
6032
7251
  let claudeJson = {};
6033
7252
  try {
6034
- claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
7253
+ claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
6035
7254
  } catch {
6036
7255
  }
6037
7256
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -6040,7 +7259,7 @@ async function runSetupWizard(opts = {}) {
6040
7259
  if (!projects[dir]) projects[dir] = {};
6041
7260
  projects[dir].hasTrustDialogAccepted = true;
6042
7261
  }
6043
- writeFileSync5(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7262
+ writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6044
7263
  } catch {
6045
7264
  }
6046
7265
  state.completedSteps.push(5);
@@ -6066,7 +7285,34 @@ async function runSetupWizard(opts = {}) {
6066
7285
  } = await Promise.resolve().then(() => (init_license(), license_exports));
6067
7286
  const createdEmployees = [];
6068
7287
  let cooName = "exe";
6069
- if (!state.completedSteps.includes(6)) {
7288
+ if (pairingRosterPulled) {
7289
+ const roster = await loadEmployees2(EMPLOYEES_PATH2).catch(() => []);
7290
+ const existingCoo = roster.find((e) => e.role === "COO");
7291
+ if (existingCoo) {
7292
+ cooName = existingCoo.name;
7293
+ log(`Team synced from cloud. COO: ${cooName}`);
7294
+ const teamList = roster.map((e) => `${e.name} (${e.role})`).join(", ");
7295
+ log(`Team: ${teamList}`);
7296
+ createdEmployees.push(...roster.map((e) => ({ name: e.name, role: e.role })));
7297
+ }
7298
+ for (const emp of roster) {
7299
+ registerBinSymlinks2(emp.name);
7300
+ }
7301
+ try {
7302
+ const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
7303
+ const pkgRoot = findPackageRoot2();
7304
+ if (pkgRoot) {
7305
+ const wrapResult = generateSessionWrappers2(pkgRoot);
7306
+ if (wrapResult.created > 0) {
7307
+ log(`Session shortcuts generated: ${roster.map((e) => `${e.name}1`).join(", ")}, ...`);
7308
+ }
7309
+ }
7310
+ } catch {
7311
+ }
7312
+ state.completedSteps.push(6, 7, 8);
7313
+ saveSetupState(state);
7314
+ log("");
7315
+ } else if (!state.completedSteps.includes(6)) {
6070
7316
  log("=== Your Team ===");
6071
7317
  log("");
6072
7318
  log("Every install starts with a COO \u2014 your right-hand operator.");
@@ -6092,9 +7338,9 @@ async function runSetupWizard(opts = {}) {
6092
7338
  const cooIdentityContent = getIdentityTemplate("coo");
6093
7339
  if (cooIdentityContent) {
6094
7340
  const cooIdPath = identityPath2(cooName);
6095
- mkdirSync6(path13.dirname(cooIdPath), { recursive: true });
7341
+ mkdirSync8(path15.dirname(cooIdPath), { recursive: true });
6096
7342
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
6097
- writeFileSync5(cooIdPath, replaced, "utf-8");
7343
+ writeFileSync7(cooIdPath, replaced, "utf-8");
6098
7344
  }
6099
7345
  registerBinSymlinks2(cooName);
6100
7346
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -6193,9 +7439,9 @@ async function runSetupWizard(opts = {}) {
6193
7439
  const ctoIdentityContent = getIdentityTemplate("cto");
6194
7440
  if (ctoIdentityContent) {
6195
7441
  const ctoIdPath = identityPath2(ctoName);
6196
- mkdirSync6(path13.dirname(ctoIdPath), { recursive: true });
7442
+ mkdirSync8(path15.dirname(ctoIdPath), { recursive: true });
6197
7443
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
6198
- writeFileSync5(ctoIdPath, replaced, "utf-8");
7444
+ writeFileSync7(ctoIdPath, replaced, "utf-8");
6199
7445
  }
6200
7446
  registerBinSymlinks2(ctoName);
6201
7447
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -6221,9 +7467,9 @@ async function runSetupWizard(opts = {}) {
6221
7467
  const cmoIdentityContent = getIdentityTemplate("cmo");
6222
7468
  if (cmoIdentityContent) {
6223
7469
  const cmoIdPath = identityPath2(cmoName);
6224
- mkdirSync6(path13.dirname(cmoIdPath), { recursive: true });
7470
+ mkdirSync8(path15.dirname(cmoIdPath), { recursive: true });
6225
7471
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
6226
- writeFileSync5(cmoIdPath, replaced, "utf-8");
7472
+ writeFileSync7(cmoIdPath, replaced, "utf-8");
6227
7473
  }
6228
7474
  registerBinSymlinks2(cmoName);
6229
7475
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -6236,11 +7482,24 @@ async function runSetupWizard(opts = {}) {
6236
7482
  } else {
6237
7483
  log("Step 8 already complete \u2014 skipping.");
6238
7484
  }
7485
+ if (!pairingRosterPulled) {
7486
+ try {
7487
+ const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
7488
+ const pkgRoot = findPackageRoot2();
7489
+ if (pkgRoot) {
7490
+ const wrapResult = generateSessionWrappers2(pkgRoot);
7491
+ if (wrapResult.created > 0) {
7492
+ log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
7493
+ }
7494
+ }
7495
+ } catch {
7496
+ }
7497
+ }
6239
7498
  clearSetupState();
6240
7499
  log("=== Two Ways to Work ===");
6241
7500
  log("");
6242
7501
  log(" 1. Claude Code mode");
6243
- log(` Type \`${cooName}\` in your terminal. Works with your Claude Code subscription.`);
7502
+ log(` Type \`${cooName}1\` in your project folder. Works with your Claude Code subscription.`);
6244
7503
  log(" Best for developers who live in the terminal.");
6245
7504
  log("");
6246
7505
  log(" 2. Dashboard mode");
@@ -6250,8 +7509,6 @@ async function runSetupWizard(opts = {}) {
6250
7509
  log(" Both modes share the same memory, employees, and data.");
6251
7510
  log(" You can switch anytime.");
6252
7511
  log("");
6253
- log(" For Claude Code mode, run: exe-os claude");
6254
- log("");
6255
7512
  log("=== Setup Complete ===");
6256
7513
  log("Database: " + config.dbPath);
6257
7514
  if (cloudConfig) {
@@ -6267,7 +7524,7 @@ async function runSetupWizard(opts = {}) {
6267
7524
  log("Team: " + createdEmployees.map((e) => `${e.name} (${e.role})`).join(", "));
6268
7525
  }
6269
7526
  log("");
6270
- log(`Type \`${cooName}\` to start (Claude Code) or \`exe-os\` for dashboard.`);
7527
+ log(`Type \`${cooName}1\` to start (Claude Code) or \`exe-os\` for dashboard.`);
6271
7528
  log("");
6272
7529
  } finally {
6273
7530
  rl.close();
@@ -6280,17 +7537,17 @@ var init_setup_wizard = __esm({
6280
7537
  init_config();
6281
7538
  init_keychain();
6282
7539
  init_model_downloader();
6283
- SETUP_STATE_PATH = path13.join(os5.homedir(), ".exe-os", "setup-state.json");
7540
+ SETUP_STATE_PATH = path15.join(os5.homedir(), ".exe-os", "setup-state.json");
6284
7541
  }
6285
7542
  });
6286
7543
 
6287
7544
  // src/lib/update-check.ts
6288
7545
  import { execSync as execSync4 } from "child_process";
6289
- import { readFileSync as readFileSync9 } from "fs";
6290
- import path14 from "path";
7546
+ import { readFileSync as readFileSync11 } from "fs";
7547
+ import path16 from "path";
6291
7548
  function getLocalVersion(packageRoot) {
6292
- const pkgPath = path14.join(packageRoot, "package.json");
6293
- const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
7549
+ const pkgPath = path16.join(packageRoot, "package.json");
7550
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
6294
7551
  return pkg.version;
6295
7552
  }
6296
7553
  function getRemoteVersion() {
@@ -7925,7 +9182,7 @@ var init_yoga_wasm_base64_esm = __esm({
7925
9182
  });
7926
9183
 
7927
9184
  // node_modules/yoga-layout/dist/src/generated/YGEnums.js
7928
- var Align, BoxSizing, Dimension, Direction, Display, Edge, Errata, ExperimentalFeature, FlexDirection, Gutter, Justify, LogLevel, MeasureMode, NodeType, Overflow, PositionType, Unit, Wrap, constants, YGEnums_default;
9185
+ var Align, BoxSizing, Dimension, Direction, Display, Edge, Errata, ExperimentalFeature, FlexDirection, Gutter, Justify, LogLevel, MeasureMode, NodeType, Overflow, PositionType, Unit, Wrap, constants2, YGEnums_default;
7929
9186
  var init_YGEnums = __esm({
7930
9187
  "node_modules/yoga-layout/dist/src/generated/YGEnums.js"() {
7931
9188
  "use strict";
@@ -8055,7 +9312,7 @@ var init_YGEnums = __esm({
8055
9312
  Wrap2[Wrap2["WrapReverse"] = 2] = "WrapReverse";
8056
9313
  return Wrap2;
8057
9314
  })({});
8058
- constants = {
9315
+ constants2 = {
8059
9316
  ALIGN_AUTO: Align.Auto,
8060
9317
  ALIGN_FLEX_START: Align.FlexStart,
8061
9318
  ALIGN_CENTER: Align.Center,
@@ -8129,7 +9386,7 @@ var init_YGEnums = __esm({
8129
9386
  WRAP_WRAP: Wrap.Wrap,
8130
9387
  WRAP_WRAP_REVERSE: Wrap.WrapReverse
8131
9388
  };
8132
- YGEnums_default = constants;
9389
+ YGEnums_default = constants2;
8133
9390
  }
8134
9391
  });
8135
9392
 
@@ -10813,8 +12070,8 @@ var init_ErrorOverview = __esm({
10813
12070
  "use strict";
10814
12071
  init_Box();
10815
12072
  init_Text();
10816
- cleanupPath = (path34) => {
10817
- return path34?.replace(`file://${cwd()}/`, "");
12073
+ cleanupPath = (path36) => {
12074
+ return path36?.replace(`file://${cwd()}/`, "");
10818
12075
  };
10819
12076
  stackUtils = new StackUtils({
10820
12077
  cwd: cwd(),
@@ -12843,14 +14100,14 @@ __export(session_registry_exports, {
12843
14100
  pruneStaleSessions: () => pruneStaleSessions,
12844
14101
  registerSession: () => registerSession
12845
14102
  });
12846
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, existsSync as existsSync14 } from "fs";
14103
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, existsSync as existsSync16 } from "fs";
12847
14104
  import { execSync as execSync6 } from "child_process";
12848
- import path15 from "path";
14105
+ import path17 from "path";
12849
14106
  import os6 from "os";
12850
14107
  function registerSession(entry) {
12851
- const dir = path15.dirname(REGISTRY_PATH);
12852
- if (!existsSync14(dir)) {
12853
- mkdirSync7(dir, { recursive: true });
14108
+ const dir = path17.dirname(REGISTRY_PATH);
14109
+ if (!existsSync16(dir)) {
14110
+ mkdirSync9(dir, { recursive: true });
12854
14111
  }
12855
14112
  const sessions = listSessions();
12856
14113
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -12859,11 +14116,11 @@ function registerSession(entry) {
12859
14116
  } else {
12860
14117
  sessions.push(entry);
12861
14118
  }
12862
- writeFileSync6(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
14119
+ writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
12863
14120
  }
12864
14121
  function listSessions() {
12865
14122
  try {
12866
- const raw = readFileSync11(REGISTRY_PATH, "utf8");
14123
+ const raw = readFileSync13(REGISTRY_PATH, "utf8");
12867
14124
  return JSON.parse(raw);
12868
14125
  } catch {
12869
14126
  return [];
@@ -12884,7 +14141,7 @@ function pruneStaleSessions() {
12884
14141
  const alive = sessions.filter((s) => liveSet.has(s.windowName));
12885
14142
  const pruned = sessions.length - alive.length;
12886
14143
  if (pruned > 0) {
12887
- writeFileSync6(REGISTRY_PATH, JSON.stringify(alive, null, 2));
14144
+ writeFileSync8(REGISTRY_PATH, JSON.stringify(alive, null, 2));
12888
14145
  }
12889
14146
  return pruned;
12890
14147
  }
@@ -12892,7 +14149,7 @@ var REGISTRY_PATH;
12892
14149
  var init_session_registry = __esm({
12893
14150
  "src/lib/session-registry.ts"() {
12894
14151
  "use strict";
12895
- REGISTRY_PATH = path15.join(os6.homedir(), ".exe-os", "session-registry.json");
14152
+ REGISTRY_PATH = path17.join(os6.homedir(), ".exe-os", "session-registry.json");
12896
14153
  }
12897
14154
  });
12898
14155
 
@@ -13097,17 +14354,17 @@ var init_provider_table = __esm({
13097
14354
  });
13098
14355
 
13099
14356
  // src/lib/intercom-queue.ts
13100
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, renameSync as renameSync4, existsSync as existsSync15, mkdirSync as mkdirSync8 } from "fs";
13101
- import path16 from "path";
14357
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, renameSync as renameSync4, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
14358
+ import path18 from "path";
13102
14359
  import os7 from "os";
13103
14360
  function ensureDir2() {
13104
- const dir = path16.dirname(QUEUE_PATH);
13105
- if (!existsSync15(dir)) mkdirSync8(dir, { recursive: true });
14361
+ const dir = path18.dirname(QUEUE_PATH);
14362
+ if (!existsSync17(dir)) mkdirSync10(dir, { recursive: true });
13106
14363
  }
13107
14364
  function readQueue() {
13108
14365
  try {
13109
- if (!existsSync15(QUEUE_PATH)) return [];
13110
- return JSON.parse(readFileSync12(QUEUE_PATH, "utf8"));
14366
+ if (!existsSync17(QUEUE_PATH)) return [];
14367
+ return JSON.parse(readFileSync14(QUEUE_PATH, "utf8"));
13111
14368
  } catch {
13112
14369
  return [];
13113
14370
  }
@@ -13115,7 +14372,7 @@ function readQueue() {
13115
14372
  function writeQueue(queue) {
13116
14373
  ensureDir2();
13117
14374
  const tmp = `${QUEUE_PATH}.tmp`;
13118
- writeFileSync7(tmp, JSON.stringify(queue, null, 2));
14375
+ writeFileSync9(tmp, JSON.stringify(queue, null, 2));
13119
14376
  renameSync4(tmp, QUEUE_PATH);
13120
14377
  }
13121
14378
  function queueIntercom(targetSession, reason) {
@@ -13139,19 +14396,19 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
13139
14396
  var init_intercom_queue = __esm({
13140
14397
  "src/lib/intercom-queue.ts"() {
13141
14398
  "use strict";
13142
- QUEUE_PATH = path16.join(os7.homedir(), ".exe-os", "intercom-queue.json");
14399
+ QUEUE_PATH = path18.join(os7.homedir(), ".exe-os", "intercom-queue.json");
13143
14400
  TTL_MS = 60 * 60 * 1e3;
13144
- INTERCOM_LOG = path16.join(os7.homedir(), ".exe-os", "intercom.log");
14401
+ INTERCOM_LOG = path18.join(os7.homedir(), ".exe-os", "intercom.log");
13145
14402
  }
13146
14403
  });
13147
14404
 
13148
14405
  // src/lib/plan-limits.ts
13149
- import { readFileSync as readFileSync13, existsSync as existsSync16 } from "fs";
13150
- import path17 from "path";
14406
+ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
14407
+ import path19 from "path";
13151
14408
  function getLicenseSync() {
13152
14409
  try {
13153
- if (!existsSync16(CACHE_PATH2)) return freeLicense();
13154
- const raw = JSON.parse(readFileSync13(CACHE_PATH2, "utf8"));
14410
+ if (!existsSync18(CACHE_PATH2)) return freeLicense();
14411
+ const raw = JSON.parse(readFileSync15(CACHE_PATH2, "utf8"));
13155
14412
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
13156
14413
  const parts = raw.token.split(".");
13157
14414
  if (parts.length !== 3) return freeLicense();
@@ -13189,8 +14446,8 @@ function assertEmployeeLimitSync(rosterPath) {
13189
14446
  const filePath = rosterPath ?? EMPLOYEES_PATH;
13190
14447
  let count = 0;
13191
14448
  try {
13192
- if (existsSync16(filePath)) {
13193
- const raw = readFileSync13(filePath, "utf8");
14449
+ if (existsSync18(filePath)) {
14450
+ const raw = readFileSync15(filePath, "utf8");
13194
14451
  const employees = JSON.parse(raw);
13195
14452
  count = Array.isArray(employees) ? employees.length : 0;
13196
14453
  }
@@ -13219,25 +14476,25 @@ var init_plan_limits = __esm({
13219
14476
  this.name = "PlanLimitError";
13220
14477
  }
13221
14478
  };
13222
- CACHE_PATH2 = path17.join(EXE_AI_DIR, "license-cache.json");
14479
+ CACHE_PATH2 = path19.join(EXE_AI_DIR, "license-cache.json");
13223
14480
  }
13224
14481
  });
13225
14482
 
13226
14483
  // src/lib/notifications.ts
13227
- import crypto4 from "crypto";
13228
- import path18 from "path";
14484
+ import crypto5 from "crypto";
14485
+ import path20 from "path";
13229
14486
  import os8 from "os";
13230
14487
  import {
13231
- readFileSync as readFileSync14,
13232
- readdirSync as readdirSync3,
13233
- unlinkSync as unlinkSync5,
13234
- existsSync as existsSync17,
14488
+ readFileSync as readFileSync16,
14489
+ readdirSync as readdirSync5,
14490
+ unlinkSync as unlinkSync7,
14491
+ existsSync as existsSync19,
13235
14492
  rmdirSync
13236
14493
  } from "fs";
13237
14494
  async function writeNotification(notification) {
13238
14495
  try {
13239
14496
  const client = getClient();
13240
- const id = crypto4.randomUUID();
14497
+ const id = crypto5.randomUUID();
13241
14498
  const now = (/* @__PURE__ */ new Date()).toISOString();
13242
14499
  await client.execute({
13243
14500
  sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
@@ -13276,7 +14533,7 @@ var init_notifications = __esm({
13276
14533
  });
13277
14534
 
13278
14535
  // src/lib/session-kill-telemetry.ts
13279
- import crypto5 from "crypto";
14536
+ import crypto6 from "crypto";
13280
14537
  async function recordSessionKill(input) {
13281
14538
  try {
13282
14539
  const client = getClient();
@@ -13286,7 +14543,7 @@ async function recordSessionKill(input) {
13286
14543
  ticks_idle, estimated_tokens_saved)
13287
14544
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
13288
14545
  args: [
13289
- crypto5.randomUUID(),
14546
+ crypto6.randomUUID(),
13290
14547
  input.sessionName,
13291
14548
  input.agentId,
13292
14549
  (/* @__PURE__ */ new Date()).toISOString(),
@@ -13325,11 +14582,11 @@ __export(tasks_crud_exports, {
13325
14582
  updateTaskStatus: () => updateTaskStatus,
13326
14583
  writeCheckpoint: () => writeCheckpoint
13327
14584
  });
13328
- import crypto6 from "crypto";
13329
- import path19 from "path";
14585
+ import crypto7 from "crypto";
14586
+ import path21 from "path";
13330
14587
  import { execSync as execSync9 } from "child_process";
13331
14588
  import { mkdir as mkdir6, writeFile as writeFile5, appendFile } from "fs/promises";
13332
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
14589
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
13333
14590
  async function writeCheckpoint(input) {
13334
14591
  const client = getClient();
13335
14592
  const row = await resolveTask(client, input.taskId);
@@ -13416,7 +14673,7 @@ async function resolveTask(client, identifier, scopeSession) {
13416
14673
  }
13417
14674
  async function createTaskCore(input) {
13418
14675
  const client = getClient();
13419
- const id = crypto6.randomUUID();
14676
+ const id = crypto7.randomUUID();
13420
14677
  const now = (/* @__PURE__ */ new Date()).toISOString();
13421
14678
  const slug = slugify(input.title);
13422
14679
  const taskFile = input.taskFile ?? `exe/${input.assignedTo}/${slug}.md`;
@@ -13461,8 +14718,8 @@ async function createTaskCore(input) {
13461
14718
  }
13462
14719
  if (input.baseDir) {
13463
14720
  try {
13464
- await mkdir6(path19.join(input.baseDir, "exe", "output"), { recursive: true });
13465
- await mkdir6(path19.join(input.baseDir, "exe", "research"), { recursive: true });
14721
+ await mkdir6(path21.join(input.baseDir, "exe", "output"), { recursive: true });
14722
+ await mkdir6(path21.join(input.baseDir, "exe", "research"), { recursive: true });
13466
14723
  await ensureArchitectureDoc(input.baseDir, input.projectName);
13467
14724
  await ensureGitignoreExe(input.baseDir);
13468
14725
  } catch {
@@ -13682,9 +14939,9 @@ async function deleteTaskCore(taskId, _baseDir) {
13682
14939
  return { taskFile, assignedTo, assignedBy, taskSlug };
13683
14940
  }
13684
14941
  async function ensureArchitectureDoc(baseDir, projectName) {
13685
- const archPath = path19.join(baseDir, "exe", "ARCHITECTURE.md");
14942
+ const archPath = path21.join(baseDir, "exe", "ARCHITECTURE.md");
13686
14943
  try {
13687
- if (existsSync18(archPath)) return;
14944
+ if (existsSync20(archPath)) return;
13688
14945
  const template = [
13689
14946
  `# ${projectName} \u2014 System Architecture`,
13690
14947
  "",
@@ -13717,10 +14974,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
13717
14974
  }
13718
14975
  }
13719
14976
  async function ensureGitignoreExe(baseDir) {
13720
- const gitignorePath = path19.join(baseDir, ".gitignore");
14977
+ const gitignorePath = path21.join(baseDir, ".gitignore");
13721
14978
  try {
13722
- if (existsSync18(gitignorePath)) {
13723
- const content = readFileSync15(gitignorePath, "utf-8");
14979
+ if (existsSync20(gitignorePath)) {
14980
+ const content = readFileSync17(gitignorePath, "utf-8");
13724
14981
  if (/^\/?exe\/?$/m.test(content)) return;
13725
14982
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
13726
14983
  } else {
@@ -13741,8 +14998,8 @@ var init_tasks_crud = __esm({
13741
14998
  });
13742
14999
 
13743
15000
  // src/lib/tasks-review.ts
13744
- import path20 from "path";
13745
- import { existsSync as existsSync19, readdirSync as readdirSync4, unlinkSync as unlinkSync6 } from "fs";
15001
+ import path22 from "path";
15002
+ import { existsSync as existsSync21, readdirSync as readdirSync6, unlinkSync as unlinkSync8 } from "fs";
13746
15003
  async function countPendingReviews(sessionScope) {
13747
15004
  const client = getClient();
13748
15005
  if (sessionScope) {
@@ -13923,11 +15180,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
13923
15180
  );
13924
15181
  }
13925
15182
  try {
13926
- const cacheDir = path20.join(EXE_AI_DIR, "session-cache");
13927
- if (existsSync19(cacheDir)) {
13928
- for (const f of readdirSync4(cacheDir)) {
15183
+ const cacheDir = path22.join(EXE_AI_DIR, "session-cache");
15184
+ if (existsSync21(cacheDir)) {
15185
+ for (const f of readdirSync6(cacheDir)) {
13929
15186
  if (f.startsWith("review-notified-")) {
13930
- unlinkSync6(path20.join(cacheDir, f));
15187
+ unlinkSync8(path22.join(cacheDir, f));
13931
15188
  }
13932
15189
  }
13933
15190
  }
@@ -13948,7 +15205,7 @@ var init_tasks_review = __esm({
13948
15205
  });
13949
15206
 
13950
15207
  // src/lib/tasks-chain.ts
13951
- import path21 from "path";
15208
+ import path23 from "path";
13952
15209
  import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
13953
15210
  async function cascadeUnblock(taskId, baseDir, now) {
13954
15211
  const client = getClient();
@@ -13965,7 +15222,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
13965
15222
  });
13966
15223
  for (const ur of unblockedRows.rows) {
13967
15224
  try {
13968
- const ubFile = path21.join(baseDir, String(ur.task_file));
15225
+ const ubFile = path23.join(baseDir, String(ur.task_file));
13969
15226
  let ubContent = await readFile5(ubFile, "utf-8");
13970
15227
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
13971
15228
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -14034,7 +15291,7 @@ var init_tasks_chain = __esm({
14034
15291
 
14035
15292
  // src/lib/project-name.ts
14036
15293
  import { execSync as execSync10 } from "child_process";
14037
- import path22 from "path";
15294
+ import path24 from "path";
14038
15295
  function getProjectName(cwd2) {
14039
15296
  const dir = cwd2 ?? process.cwd();
14040
15297
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -14047,7 +15304,7 @@ function getProjectName(cwd2) {
14047
15304
  timeout: 2e3,
14048
15305
  stdio: ["pipe", "pipe", "pipe"]
14049
15306
  }).trim();
14050
- repoRoot = path22.dirname(gitCommonDir);
15307
+ repoRoot = path24.dirname(gitCommonDir);
14051
15308
  } catch {
14052
15309
  repoRoot = execSync10("git rev-parse --show-toplevel", {
14053
15310
  cwd: dir,
@@ -14056,11 +15313,11 @@ function getProjectName(cwd2) {
14056
15313
  stdio: ["pipe", "pipe", "pipe"]
14057
15314
  }).trim();
14058
15315
  }
14059
- _cached2 = path22.basename(repoRoot);
15316
+ _cached2 = path24.basename(repoRoot);
14060
15317
  _cachedCwd = dir;
14061
15318
  return _cached2;
14062
15319
  } catch {
14063
- _cached2 = path22.basename(dir);
15320
+ _cached2 = path24.basename(dir);
14064
15321
  _cachedCwd = dir;
14065
15322
  return _cached2;
14066
15323
  }
@@ -14202,10 +15459,10 @@ var init_tasks_notify = __esm({
14202
15459
  });
14203
15460
 
14204
15461
  // src/lib/behaviors.ts
14205
- import crypto7 from "crypto";
15462
+ import crypto8 from "crypto";
14206
15463
  async function storeBehavior(opts) {
14207
15464
  const client = getClient();
14208
- const id = crypto7.randomUUID();
15465
+ const id = crypto8.randomUUID();
14209
15466
  const now = (/* @__PURE__ */ new Date()).toISOString();
14210
15467
  await client.execute({
14211
15468
  sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
@@ -14234,7 +15491,7 @@ __export(skill_learning_exports, {
14234
15491
  storeTrajectory: () => storeTrajectory,
14235
15492
  sweepTrajectories: () => sweepTrajectories
14236
15493
  });
14237
- import crypto8 from "crypto";
15494
+ import crypto9 from "crypto";
14238
15495
  async function extractTrajectory(taskId, agentId) {
14239
15496
  const client = getClient();
14240
15497
  const result = await client.execute({
@@ -14263,11 +15520,11 @@ async function extractTrajectory(taskId, agentId) {
14263
15520
  return signature;
14264
15521
  }
14265
15522
  function hashSignature(signature) {
14266
- return crypto8.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
15523
+ return crypto9.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
14267
15524
  }
14268
15525
  async function storeTrajectory(opts) {
14269
15526
  const client = getClient();
14270
- const id = crypto8.randomUUID();
15527
+ const id = crypto9.randomUUID();
14271
15528
  const now = (/* @__PURE__ */ new Date()).toISOString();
14272
15529
  const signatureHash = hashSignature(opts.signature);
14273
15530
  await client.execute({
@@ -14532,8 +15789,8 @@ __export(tasks_exports, {
14532
15789
  updateTaskStatus: () => updateTaskStatus,
14533
15790
  writeCheckpoint: () => writeCheckpoint
14534
15791
  });
14535
- import path23 from "path";
14536
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7 } from "fs";
15792
+ import path25 from "path";
15793
+ import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, unlinkSync as unlinkSync9 } from "fs";
14537
15794
  async function createTask(input) {
14538
15795
  const result = await createTaskCore(input);
14539
15796
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -14552,14 +15809,14 @@ async function updateTask(input) {
14552
15809
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
14553
15810
  try {
14554
15811
  const agent = String(row.assigned_to);
14555
- const cacheDir = path23.join(EXE_AI_DIR, "session-cache");
14556
- const cachePath = path23.join(cacheDir, `current-task-${agent}.json`);
15812
+ const cacheDir = path25.join(EXE_AI_DIR, "session-cache");
15813
+ const cachePath = path25.join(cacheDir, `current-task-${agent}.json`);
14557
15814
  if (input.status === "in_progress") {
14558
- mkdirSync9(cacheDir, { recursive: true });
14559
- writeFileSync8(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
15815
+ mkdirSync11(cacheDir, { recursive: true });
15816
+ writeFileSync10(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
14560
15817
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
14561
15818
  try {
14562
- unlinkSync7(cachePath);
15819
+ unlinkSync9(cachePath);
14563
15820
  } catch {
14564
15821
  }
14565
15822
  }
@@ -15001,13 +16258,13 @@ __export(tmux_routing_exports, {
15001
16258
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
15002
16259
  });
15003
16260
  import { execFileSync as execFileSync3, execSync as execSync11 } from "child_process";
15004
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, existsSync as existsSync20, appendFileSync } from "fs";
15005
- import path24 from "path";
16261
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, existsSync as existsSync22, appendFileSync as appendFileSync2 } from "fs";
16262
+ import path26 from "path";
15006
16263
  import os9 from "os";
15007
16264
  import { fileURLToPath as fileURLToPath4 } from "url";
15008
- import { unlinkSync as unlinkSync8 } from "fs";
16265
+ import { unlinkSync as unlinkSync10 } from "fs";
15009
16266
  function spawnLockPath(sessionName) {
15010
- return path24.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
16267
+ return path26.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
15011
16268
  }
15012
16269
  function isProcessAlive(pid) {
15013
16270
  try {
@@ -15018,13 +16275,13 @@ function isProcessAlive(pid) {
15018
16275
  }
15019
16276
  }
15020
16277
  function acquireSpawnLock2(sessionName) {
15021
- if (!existsSync20(SPAWN_LOCK_DIR)) {
15022
- mkdirSync10(SPAWN_LOCK_DIR, { recursive: true });
16278
+ if (!existsSync22(SPAWN_LOCK_DIR)) {
16279
+ mkdirSync12(SPAWN_LOCK_DIR, { recursive: true });
15023
16280
  }
15024
16281
  const lockFile = spawnLockPath(sessionName);
15025
- if (existsSync20(lockFile)) {
16282
+ if (existsSync22(lockFile)) {
15026
16283
  try {
15027
- const lock = JSON.parse(readFileSync16(lockFile, "utf8"));
16284
+ const lock = JSON.parse(readFileSync18(lockFile, "utf8"));
15028
16285
  const age = Date.now() - lock.timestamp;
15029
16286
  if (isProcessAlive(lock.pid) && age < 6e4) {
15030
16287
  return false;
@@ -15032,25 +16289,25 @@ function acquireSpawnLock2(sessionName) {
15032
16289
  } catch {
15033
16290
  }
15034
16291
  }
15035
- writeFileSync9(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
16292
+ writeFileSync11(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
15036
16293
  return true;
15037
16294
  }
15038
16295
  function releaseSpawnLock2(sessionName) {
15039
16296
  try {
15040
- unlinkSync8(spawnLockPath(sessionName));
16297
+ unlinkSync10(spawnLockPath(sessionName));
15041
16298
  } catch {
15042
16299
  }
15043
16300
  }
15044
16301
  function resolveBehaviorsExporterScript() {
15045
16302
  try {
15046
16303
  const thisFile = fileURLToPath4(import.meta.url);
15047
- const scriptPath = path24.join(
15048
- path24.dirname(thisFile),
16304
+ const scriptPath = path26.join(
16305
+ path26.dirname(thisFile),
15049
16306
  "..",
15050
16307
  "bin",
15051
16308
  "exe-export-behaviors.js"
15052
16309
  );
15053
- return existsSync20(scriptPath) ? scriptPath : null;
16310
+ return existsSync22(scriptPath) ? scriptPath : null;
15054
16311
  } catch {
15055
16312
  return null;
15056
16313
  }
@@ -15114,12 +16371,12 @@ function extractRootExe(name) {
15114
16371
  return match?.[1] ?? null;
15115
16372
  }
15116
16373
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
15117
- if (!existsSync20(SESSION_CACHE)) {
15118
- mkdirSync10(SESSION_CACHE, { recursive: true });
16374
+ if (!existsSync22(SESSION_CACHE)) {
16375
+ mkdirSync12(SESSION_CACHE, { recursive: true });
15119
16376
  }
15120
16377
  const rootExe = extractRootExe(parentExe) ?? parentExe;
15121
- const filePath = path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
15122
- writeFileSync9(filePath, JSON.stringify({
16378
+ const filePath = path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
16379
+ writeFileSync11(filePath, JSON.stringify({
15123
16380
  parentExe: rootExe,
15124
16381
  dispatchedBy: dispatchedBy || rootExe,
15125
16382
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -15127,7 +16384,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
15127
16384
  }
15128
16385
  function getParentExe(sessionKey) {
15129
16386
  try {
15130
- const data = JSON.parse(readFileSync16(path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
16387
+ const data = JSON.parse(readFileSync18(path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
15131
16388
  return data.parentExe || null;
15132
16389
  } catch {
15133
16390
  return null;
@@ -15135,8 +16392,8 @@ function getParentExe(sessionKey) {
15135
16392
  }
15136
16393
  function getDispatchedBy(sessionKey) {
15137
16394
  try {
15138
- const data = JSON.parse(readFileSync16(
15139
- path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
16395
+ const data = JSON.parse(readFileSync18(
16396
+ path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
15140
16397
  "utf8"
15141
16398
  ));
15142
16399
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -15197,16 +16454,16 @@ async function verifyPaneAtCapacity(sessionName) {
15197
16454
  }
15198
16455
  function readDebounceState() {
15199
16456
  try {
15200
- if (!existsSync20(DEBOUNCE_FILE)) return {};
15201
- return JSON.parse(readFileSync16(DEBOUNCE_FILE, "utf8"));
16457
+ if (!existsSync22(DEBOUNCE_FILE)) return {};
16458
+ return JSON.parse(readFileSync18(DEBOUNCE_FILE, "utf8"));
15202
16459
  } catch {
15203
16460
  return {};
15204
16461
  }
15205
16462
  }
15206
16463
  function writeDebounceState(state) {
15207
16464
  try {
15208
- if (!existsSync20(SESSION_CACHE)) mkdirSync10(SESSION_CACHE, { recursive: true });
15209
- writeFileSync9(DEBOUNCE_FILE, JSON.stringify(state));
16465
+ if (!existsSync22(SESSION_CACHE)) mkdirSync12(SESSION_CACHE, { recursive: true });
16466
+ writeFileSync11(DEBOUNCE_FILE, JSON.stringify(state));
15210
16467
  } catch {
15211
16468
  }
15212
16469
  }
@@ -15230,7 +16487,7 @@ function logIntercom(msg) {
15230
16487
  process.stderr.write(`[intercom] ${msg}
15231
16488
  `);
15232
16489
  try {
15233
- appendFileSync(INTERCOM_LOG2, line);
16490
+ appendFileSync2(INTERCOM_LOG2, line);
15234
16491
  } catch {
15235
16492
  }
15236
16493
  }
@@ -15395,26 +16652,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15395
16652
  const transport = getTransport();
15396
16653
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
15397
16654
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
15398
- const logDir = path24.join(os9.homedir(), ".exe-os", "session-logs");
15399
- const logFile = path24.join(logDir, `${instanceLabel}-${Date.now()}.log`);
15400
- if (!existsSync20(logDir)) {
15401
- mkdirSync10(logDir, { recursive: true });
16655
+ const logDir = path26.join(os9.homedir(), ".exe-os", "session-logs");
16656
+ const logFile = path26.join(logDir, `${instanceLabel}-${Date.now()}.log`);
16657
+ if (!existsSync22(logDir)) {
16658
+ mkdirSync12(logDir, { recursive: true });
15402
16659
  }
15403
16660
  transport.kill(sessionName);
15404
16661
  let cleanupSuffix = "";
15405
16662
  try {
15406
16663
  const thisFile = fileURLToPath4(import.meta.url);
15407
- const cleanupScript = path24.join(path24.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
15408
- if (existsSync20(cleanupScript)) {
16664
+ const cleanupScript = path26.join(path26.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
16665
+ if (existsSync22(cleanupScript)) {
15409
16666
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
15410
16667
  }
15411
16668
  } catch {
15412
16669
  }
15413
16670
  try {
15414
- const claudeJsonPath = path24.join(os9.homedir(), ".claude.json");
16671
+ const claudeJsonPath = path26.join(os9.homedir(), ".claude.json");
15415
16672
  let claudeJson = {};
15416
16673
  try {
15417
- claudeJson = JSON.parse(readFileSync16(claudeJsonPath, "utf8"));
16674
+ claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
15418
16675
  } catch {
15419
16676
  }
15420
16677
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -15422,17 +16679,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15422
16679
  const trustDir = opts?.cwd ?? projectDir;
15423
16680
  if (!projects[trustDir]) projects[trustDir] = {};
15424
16681
  projects[trustDir].hasTrustDialogAccepted = true;
15425
- writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
16682
+ writeFileSync11(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
15426
16683
  } catch {
15427
16684
  }
15428
16685
  try {
15429
- const settingsDir = path24.join(os9.homedir(), ".claude", "projects");
16686
+ const settingsDir = path26.join(os9.homedir(), ".claude", "projects");
15430
16687
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
15431
- const projSettingsDir = path24.join(settingsDir, normalizedKey);
15432
- const settingsPath = path24.join(projSettingsDir, "settings.json");
16688
+ const projSettingsDir = path26.join(settingsDir, normalizedKey);
16689
+ const settingsPath = path26.join(projSettingsDir, "settings.json");
15433
16690
  let settings = {};
15434
16691
  try {
15435
- settings = JSON.parse(readFileSync16(settingsPath, "utf8"));
16692
+ settings = JSON.parse(readFileSync18(settingsPath, "utf8"));
15436
16693
  } catch {
15437
16694
  }
15438
16695
  const perms = settings.permissions ?? {};
@@ -15460,8 +16717,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15460
16717
  if (changed) {
15461
16718
  perms.allow = allow;
15462
16719
  settings.permissions = perms;
15463
- mkdirSync10(projSettingsDir, { recursive: true });
15464
- writeFileSync9(settingsPath, JSON.stringify(settings, null, 2) + "\n");
16720
+ mkdirSync12(projSettingsDir, { recursive: true });
16721
+ writeFileSync11(settingsPath, JSON.stringify(settings, null, 2) + "\n");
15465
16722
  }
15466
16723
  } catch {
15467
16724
  }
@@ -15473,7 +16730,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15473
16730
  let behaviorsFlag = "";
15474
16731
  let legacyFallbackWarned = false;
15475
16732
  if (!useExeAgent && !useBinSymlink) {
15476
- const identityPath2 = path24.join(
16733
+ const identityPath2 = path26.join(
15477
16734
  os9.homedir(),
15478
16735
  ".exe-os",
15479
16736
  "identity",
@@ -15483,13 +16740,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15483
16740
  const hasAgentFlag = claudeSupportsAgentFlag();
15484
16741
  if (hasAgentFlag) {
15485
16742
  identityFlag = ` --agent ${employeeName}`;
15486
- } else if (existsSync20(identityPath2)) {
16743
+ } else if (existsSync22(identityPath2)) {
15487
16744
  identityFlag = ` --append-system-prompt-file ${identityPath2}`;
15488
16745
  legacyFallbackWarned = true;
15489
16746
  }
15490
16747
  const behaviorsFile = exportBehaviorsSync(
15491
16748
  employeeName,
15492
- path24.basename(spawnCwd),
16749
+ path26.basename(spawnCwd),
15493
16750
  sessionName
15494
16751
  );
15495
16752
  if (behaviorsFile) {
@@ -15504,16 +16761,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15504
16761
  }
15505
16762
  let sessionContextFlag = "";
15506
16763
  try {
15507
- const ctxDir = path24.join(os9.homedir(), ".exe-os", "session-cache");
15508
- mkdirSync10(ctxDir, { recursive: true });
15509
- const ctxFile = path24.join(ctxDir, `session-context-${sessionName}.md`);
16764
+ const ctxDir = path26.join(os9.homedir(), ".exe-os", "session-cache");
16765
+ mkdirSync12(ctxDir, { recursive: true });
16766
+ const ctxFile = path26.join(ctxDir, `session-context-${sessionName}.md`);
15510
16767
  const ctxContent = [
15511
16768
  `## Session Context`,
15512
16769
  `You are running in tmux session: ${sessionName}.`,
15513
16770
  `Your parent exe session is ${exeSession}.`,
15514
16771
  `Your employees (if any) use the -${exeSession} suffix (e.g., tom-${exeSession}).`
15515
16772
  ].join("\n");
15516
- writeFileSync9(ctxFile, ctxContent);
16773
+ writeFileSync11(ctxFile, ctxContent);
15517
16774
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
15518
16775
  } catch {
15519
16776
  }
@@ -15551,8 +16808,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15551
16808
  transport.pipeLog(sessionName, logFile);
15552
16809
  try {
15553
16810
  const mySession = getMySession();
15554
- const dispatchInfo = path24.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
15555
- writeFileSync9(dispatchInfo, JSON.stringify({
16811
+ const dispatchInfo = path26.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
16812
+ writeFileSync11(dispatchInfo, JSON.stringify({
15556
16813
  dispatchedBy: mySession,
15557
16814
  rootExe: exeSession,
15558
16815
  provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
@@ -15615,14 +16872,14 @@ var init_tmux_routing = __esm({
15615
16872
  init_provider_table();
15616
16873
  init_intercom_queue();
15617
16874
  init_plan_limits();
15618
- SPAWN_LOCK_DIR = path24.join(os9.homedir(), ".exe-os", "spawn-locks");
15619
- SESSION_CACHE = path24.join(os9.homedir(), ".exe-os", "session-cache");
16875
+ SPAWN_LOCK_DIR = path26.join(os9.homedir(), ".exe-os", "spawn-locks");
16876
+ SESSION_CACHE = path26.join(os9.homedir(), ".exe-os", "session-cache");
15620
16877
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
15621
16878
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
15622
16879
  VERIFY_PANE_LINES = 200;
15623
16880
  INTERCOM_DEBOUNCE_MS = 3e4;
15624
- INTERCOM_LOG2 = path24.join(os9.homedir(), ".exe-os", "intercom.log");
15625
- DEBOUNCE_FILE = path24.join(SESSION_CACHE, "intercom-debounce.json");
16881
+ INTERCOM_LOG2 = path26.join(os9.homedir(), ".exe-os", "intercom.log");
16882
+ DEBOUNCE_FILE = path26.join(SESSION_CACHE, "intercom-debounce.json");
15626
16883
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
15627
16884
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
15628
16885
  }
@@ -16043,11 +17300,11 @@ function Footer() {
16043
17300
  } catch {
16044
17301
  }
16045
17302
  try {
16046
- const { existsSync: existsSync22 } = await import("fs");
17303
+ const { existsSync: existsSync24 } = await import("fs");
16047
17304
  const { join } = await import("path");
16048
17305
  const home = process.env.HOME ?? "";
16049
17306
  const pidPath = join(home, ".exe-os", "exed.pid");
16050
- setDaemon(existsSync22(pidPath) ? "running" : "stopped");
17307
+ setDaemon(existsSync24(pidPath) ? "running" : "stopped");
16051
17308
  } catch {
16052
17309
  setDaemon("unknown");
16053
17310
  }
@@ -18078,10 +19335,10 @@ var init_hooks = __esm({
18078
19335
  });
18079
19336
 
18080
19337
  // src/runtime/safety-checks.ts
18081
- import path25 from "path";
19338
+ import path27 from "path";
18082
19339
  import os10 from "os";
18083
19340
  function checkPathSafety(filePath) {
18084
- const resolved = path25.resolve(filePath);
19341
+ const resolved = path27.resolve(filePath);
18085
19342
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
18086
19343
  const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
18087
19344
  if (matches) {
@@ -18091,7 +19348,7 @@ function checkPathSafety(filePath) {
18091
19348
  return { safe: true, bypassImmune: true };
18092
19349
  }
18093
19350
  function checkReadPathSafety(filePath) {
18094
- const resolved = path25.resolve(filePath);
19351
+ const resolved = path27.resolve(filePath);
18095
19352
  const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
18096
19353
  (p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
18097
19354
  );
@@ -18117,11 +19374,11 @@ var init_safety_checks = __esm({
18117
19374
  reason: "Git config can set hooks and command execution"
18118
19375
  },
18119
19376
  {
18120
- pattern: (p) => p.startsWith(path25.join(HOME, ".claude")),
19377
+ pattern: (p) => p.startsWith(path27.join(HOME, ".claude")),
18121
19378
  reason: "Claude configuration files are protected"
18122
19379
  },
18123
19380
  {
18124
- pattern: (p) => p.startsWith(path25.join(HOME, ".exe-os")),
19381
+ pattern: (p) => p.startsWith(path27.join(HOME, ".exe-os")),
18125
19382
  reason: "exe-os configuration files are protected"
18126
19383
  },
18127
19384
  {
@@ -18138,7 +19395,7 @@ var init_safety_checks = __esm({
18138
19395
  },
18139
19396
  {
18140
19397
  pattern: (p) => {
18141
- const name = path25.basename(p);
19398
+ const name = path27.basename(p);
18142
19399
  return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
18143
19400
  },
18144
19401
  reason: "Shell configuration files can execute arbitrary code on login"
@@ -18165,7 +19422,7 @@ __export(file_read_exports, {
18165
19422
  FileReadTool: () => FileReadTool
18166
19423
  });
18167
19424
  import fs3 from "fs/promises";
18168
- import path26 from "path";
19425
+ import path28 from "path";
18169
19426
  import { z } from "zod";
18170
19427
  function isBinary(buf) {
18171
19428
  for (let i = 0; i < buf.length; i++) {
@@ -18201,7 +19458,7 @@ var init_file_read = __esm({
18201
19458
  return { behavior: "allow" };
18202
19459
  },
18203
19460
  async call(input, context) {
18204
- const filePath = path26.isAbsolute(input.file_path) ? input.file_path : path26.resolve(context.cwd, input.file_path);
19461
+ const filePath = path28.isAbsolute(input.file_path) ? input.file_path : path28.resolve(context.cwd, input.file_path);
18205
19462
  let stat2;
18206
19463
  try {
18207
19464
  stat2 = await fs3.stat(filePath);
@@ -18241,7 +19498,7 @@ __export(glob_exports, {
18241
19498
  GlobTool: () => GlobTool
18242
19499
  });
18243
19500
  import fs4 from "fs/promises";
18244
- import path27 from "path";
19501
+ import path29 from "path";
18245
19502
  import { z as z2 } from "zod";
18246
19503
  async function walkDir(dir, maxDepth = 10) {
18247
19504
  const results = [];
@@ -18257,7 +19514,7 @@ async function walkDir(dir, maxDepth = 10) {
18257
19514
  if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
18258
19515
  continue;
18259
19516
  }
18260
- const fullPath = path27.join(current, entry.name);
19517
+ const fullPath = path29.join(current, entry.name);
18261
19518
  if (entry.isDirectory()) {
18262
19519
  await walk(fullPath, depth + 1);
18263
19520
  } else {
@@ -18291,11 +19548,11 @@ var init_glob = __esm({
18291
19548
  inputSchema: inputSchema2,
18292
19549
  isReadOnly: true,
18293
19550
  async call(input, context) {
18294
- const baseDir = input.path ? path27.isAbsolute(input.path) ? input.path : path27.resolve(context.cwd, input.path) : context.cwd;
19551
+ const baseDir = input.path ? path29.isAbsolute(input.path) ? input.path : path29.resolve(context.cwd, input.path) : context.cwd;
18295
19552
  try {
18296
19553
  const entries = await walkDir(baseDir);
18297
19554
  const matched = entries.filter(
18298
- (e) => simpleGlobMatch(path27.relative(baseDir, e.path), input.pattern)
19555
+ (e) => simpleGlobMatch(path29.relative(baseDir, e.path), input.pattern)
18299
19556
  );
18300
19557
  matched.sort((a, b) => b.mtime - a.mtime);
18301
19558
  if (matched.length === 0) {
@@ -18321,7 +19578,7 @@ __export(grep_exports, {
18321
19578
  });
18322
19579
  import { spawn as spawn2 } from "child_process";
18323
19580
  import fs5 from "fs/promises";
18324
- import path28 from "path";
19581
+ import path30 from "path";
18325
19582
  import { z as z3 } from "zod";
18326
19583
  function runRipgrep(input, searchPath, context) {
18327
19584
  return new Promise((resolve, reject) => {
@@ -18375,7 +19632,7 @@ async function nodeGrep(input, searchPath) {
18375
19632
  }
18376
19633
  for (const entry of entries) {
18377
19634
  if (entry.name === "node_modules" || entry.name === ".git") continue;
18378
- const fullPath = path28.join(dir, entry.name);
19635
+ const fullPath = path30.join(dir, entry.name);
18379
19636
  if (entry.isDirectory()) {
18380
19637
  await walk(fullPath);
18381
19638
  } else {
@@ -18421,7 +19678,7 @@ var init_grep = __esm({
18421
19678
  inputSchema: inputSchema3,
18422
19679
  isReadOnly: true,
18423
19680
  async call(input, context) {
18424
- const searchPath = input.path ? path28.isAbsolute(input.path) ? input.path : path28.resolve(context.cwd, input.path) : context.cwd;
19681
+ const searchPath = input.path ? path30.isAbsolute(input.path) ? input.path : path30.resolve(context.cwd, input.path) : context.cwd;
18425
19682
  try {
18426
19683
  const result = await runRipgrep(input, searchPath, context);
18427
19684
  return result;
@@ -18446,7 +19703,7 @@ __export(file_write_exports, {
18446
19703
  FileWriteTool: () => FileWriteTool
18447
19704
  });
18448
19705
  import fs6 from "fs/promises";
18449
- import path29 from "path";
19706
+ import path31 from "path";
18450
19707
  import { z as z4 } from "zod";
18451
19708
  var inputSchema4, FileWriteTool;
18452
19709
  var init_file_write = __esm({
@@ -18474,8 +19731,8 @@ var init_file_write = __esm({
18474
19731
  return { behavior: "allow" };
18475
19732
  },
18476
19733
  async call(input, context) {
18477
- const filePath = path29.isAbsolute(input.file_path) ? input.file_path : path29.resolve(context.cwd, input.file_path);
18478
- const dir = path29.dirname(filePath);
19734
+ const filePath = path31.isAbsolute(input.file_path) ? input.file_path : path31.resolve(context.cwd, input.file_path);
19735
+ const dir = path31.dirname(filePath);
18479
19736
  await fs6.mkdir(dir, { recursive: true });
18480
19737
  await fs6.writeFile(filePath, input.content, "utf-8");
18481
19738
  return {
@@ -18493,7 +19750,7 @@ __export(file_edit_exports, {
18493
19750
  FileEditTool: () => FileEditTool
18494
19751
  });
18495
19752
  import fs7 from "fs/promises";
18496
- import path30 from "path";
19753
+ import path32 from "path";
18497
19754
  import { z as z5 } from "zod";
18498
19755
  function countOccurrences(haystack, needle) {
18499
19756
  let count = 0;
@@ -18534,7 +19791,7 @@ var init_file_edit = __esm({
18534
19791
  return { behavior: "allow" };
18535
19792
  },
18536
19793
  async call(input, context) {
18537
- const filePath = path30.isAbsolute(input.file_path) ? input.file_path : path30.resolve(context.cwd, input.file_path);
19794
+ const filePath = path32.isAbsolute(input.file_path) ? input.file_path : path32.resolve(context.cwd, input.file_path);
18538
19795
  let content;
18539
19796
  try {
18540
19797
  content = await fs7.readFile(filePath, "utf-8");
@@ -18776,8 +20033,8 @@ var init_bash = __esm({
18776
20033
  // src/tui/views/CommandCenter.tsx
18777
20034
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
18778
20035
  import TextInput from "ink-text-input";
18779
- import path31 from "path";
18780
- import { homedir as homedir3 } from "os";
20036
+ import path33 from "path";
20037
+ import { homedir as homedir5 } from "os";
18781
20038
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
18782
20039
  function CommandCenterView({
18783
20040
  onSelectProject,
@@ -18811,15 +20068,15 @@ function CommandCenterView({
18811
20068
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
18812
20069
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
18813
20070
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
18814
- const { readFileSync: readFileSync18, existsSync: existsSync22 } = await import("fs");
20071
+ const { readFileSync: readFileSync20, existsSync: existsSync24 } = await import("fs");
18815
20072
  const { join } = await import("path");
18816
- const { homedir: homedir5 } = await import("os");
18817
- const configPath = join(homedir5(), ".exe-os", "config.json");
20073
+ const { homedir: homedir7 } = await import("os");
20074
+ const configPath = join(homedir7(), ".exe-os", "config.json");
18818
20075
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
18819
20076
  let providerConfigs = {};
18820
- if (existsSync22(configPath)) {
20077
+ if (existsSync24(configPath)) {
18821
20078
  try {
18822
- const raw = JSON.parse(readFileSync18(configPath, "utf8"));
20079
+ const raw = JSON.parse(readFileSync20(configPath, "utf8"));
18823
20080
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
18824
20081
  if (raw.providers && typeof raw.providers === "object") {
18825
20082
  providerConfigs = raw.providers;
@@ -18877,10 +20134,10 @@ function CommandCenterView({
18877
20134
  registry.register(BashTool2);
18878
20135
  let agentRole = "CTO";
18879
20136
  try {
18880
- const markerDir = join(homedir5(), ".exe-os", "session-cache");
20137
+ const markerDir = join(homedir7(), ".exe-os", "session-cache");
18881
20138
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
18882
20139
  for (const f of agentFiles) {
18883
- const data = JSON.parse(readFileSync18(join(markerDir, f), "utf8"));
20140
+ const data = JSON.parse(readFileSync20(join(markerDir, f), "utf8"));
18884
20141
  if (data.agentRole) {
18885
20142
  agentRole = data.agentRole;
18886
20143
  break;
@@ -19017,7 +20274,7 @@ function CommandCenterView({
19017
20274
  const demoEntries = DEMO_PROJECTS.map((p) => ({
19018
20275
  projectName: p.projectName,
19019
20276
  exeSession: p.exeSession,
19020
- projectDir: path31.join(homedir3(), p.projectName),
20277
+ projectDir: path33.join(homedir5(), p.projectName),
19021
20278
  employeeCount: p.employees.length,
19022
20279
  activeCount: p.employees.filter((e) => e.status === "active").length,
19023
20280
  memoryCount: p.employees.length * 4e3,
@@ -19055,7 +20312,7 @@ function CommandCenterView({
19055
20312
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
19056
20313
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
19057
20314
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
19058
- const { existsSync: existsSync22 } = await import("fs");
20315
+ const { existsSync: existsSync24 } = await import("fs");
19059
20316
  const { join } = await import("path");
19060
20317
  const client = getClient2();
19061
20318
  if (!client) {
@@ -19124,7 +20381,7 @@ function CommandCenterView({
19124
20381
  }
19125
20382
  const memoryCount = memoryCounts.get(name) ?? 0;
19126
20383
  const openTaskCount = openTaskCounts.get(name) ?? 0;
19127
- const hasGit = projectDir ? existsSync22(join(projectDir, ".git")) : false;
20384
+ const hasGit = projectDir ? existsSync24(join(projectDir, ".git")) : false;
19128
20385
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
19129
20386
  projectList.push({
19130
20387
  projectName: name,
@@ -19149,7 +20406,7 @@ function CommandCenterView({
19149
20406
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
19150
20407
  try {
19151
20408
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
19152
- setHealth((h) => ({ ...h, daemon: existsSync22(pidPath) ? "running" : "stopped" }));
20409
+ setHealth((h) => ({ ...h, daemon: existsSync24(pidPath) ? "running" : "stopped" }));
19153
20410
  } catch {
19154
20411
  }
19155
20412
  const activityResult = await client.execute(
@@ -20010,8 +21267,8 @@ var init_useOrchestrator = __esm({
20010
21267
 
20011
21268
  // src/tui/views/Sessions.tsx
20012
21269
  import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
20013
- import path32 from "path";
20014
- import { homedir as homedir4 } from "os";
21270
+ import path34 from "path";
21271
+ import { homedir as homedir6 } from "os";
20015
21272
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
20016
21273
  function SessionsView({
20017
21274
  initialProject,
@@ -20045,7 +21302,7 @@ function SessionsView({
20045
21302
  if (demo) {
20046
21303
  setProjects(DEMO_PROJECTS.map((p) => ({
20047
21304
  ...p,
20048
- projectDir: path32.join(homedir4(), p.projectName),
21305
+ projectDir: path34.join(homedir6(), p.projectName),
20049
21306
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
20050
21307
  })));
20051
21308
  return;
@@ -20804,16 +22061,16 @@ __export(ws_auth_exports, {
20804
22061
  deriveWsAuthToken: () => deriveWsAuthToken,
20805
22062
  hashAuthToken: () => hashAuthToken
20806
22063
  });
20807
- import crypto9 from "crypto";
22064
+ import crypto10 from "crypto";
20808
22065
  function deriveWsAuthToken(masterKey) {
20809
- return Buffer.from(crypto9.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
22066
+ return Buffer.from(crypto10.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
20810
22067
  }
20811
22068
  function deriveOrgId(masterKey) {
20812
- const raw = Buffer.from(crypto9.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
20813
- return crypto9.createHash("sha256").update(raw).digest("hex").slice(0, 32);
22069
+ const raw = Buffer.from(crypto10.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
22070
+ return crypto10.createHash("sha256").update(raw).digest("hex").slice(0, 32);
20814
22071
  }
20815
22072
  function hashAuthToken(token) {
20816
- return crypto9.createHash("sha256").update(token).digest("hex");
22073
+ return crypto10.createHash("sha256").update(token).digest("hex");
20817
22074
  }
20818
22075
  var WS_AUTH_HKDF_INFO, ORG_ID_HKDF_INFO;
20819
22076
  var init_ws_auth = __esm({
@@ -21017,7 +22274,7 @@ function assertSecureWsUrl(url) {
21017
22274
  `Malformed WebSocket URL rejected: "${url}".`
21018
22275
  );
21019
22276
  }
21020
- if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
22277
+ if (LOCALHOST_PATTERNS2.test(parsed.hostname)) return;
21021
22278
  throw new Error(
21022
22279
  `Insecure WebSocket URL rejected: "${url}". Use wss:// for remote hosts. Plain ws:// is only allowed for localhost.`
21023
22280
  );
@@ -21026,7 +22283,7 @@ function assertSecureWsUrl(url) {
21026
22283
  function isGatewayEvent(msg) {
21027
22284
  return typeof msg.type === "string" && GATEWAY_EVENT_TYPES.has(msg.type);
21028
22285
  }
21029
- var MIN_RECONNECT_MS, MAX_RECONNECT_MS, AUTH_RESPONSE_TIMEOUT_MS, DEFAULT_CHANNELS, GATEWAY_EVENT_TYPES, LOCALHOST_PATTERNS;
22286
+ var MIN_RECONNECT_MS, MAX_RECONNECT_MS, AUTH_RESPONSE_TIMEOUT_MS, DEFAULT_CHANNELS, GATEWAY_EVENT_TYPES, LOCALHOST_PATTERNS2;
21030
22287
  var init_gateway_client = __esm({
21031
22288
  "src/lib/gateway-client.ts"() {
21032
22289
  "use strict";
@@ -21042,7 +22299,7 @@ var init_gateway_client = __esm({
21042
22299
  "health",
21043
22300
  "escalation"
21044
22301
  ]);
21045
- LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
22302
+ LOCALHOST_PATTERNS2 = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
21046
22303
  }
21047
22304
  });
21048
22305
 
@@ -21173,12 +22430,12 @@ async function loadGatewayConfig() {
21173
22430
  state.running = false;
21174
22431
  }
21175
22432
  try {
21176
- const { existsSync: existsSync22, readFileSync: readFileSync18 } = await import("fs");
22433
+ const { existsSync: existsSync24, readFileSync: readFileSync20 } = await import("fs");
21177
22434
  const { join } = await import("path");
21178
22435
  const home = process.env.HOME ?? "";
21179
22436
  const configPath = join(home, ".exe-os", "gateway.json");
21180
- if (existsSync22(configPath)) {
21181
- const raw = JSON.parse(readFileSync18(configPath, "utf8"));
22437
+ if (existsSync24(configPath)) {
22438
+ const raw = JSON.parse(readFileSync20(configPath, "utf8"));
21182
22439
  state.port = raw.port ?? 3100;
21183
22440
  state.gatewayUrl = raw.gatewayUrl ?? "";
21184
22441
  if (raw.adapters) {
@@ -21801,12 +23058,12 @@ function TeamView({ onBack, onViewSessions }) {
21801
23058
  setMembers(teamData);
21802
23059
  setDbError(null);
21803
23060
  try {
21804
- const { existsSync: existsSync22, readFileSync: readFileSync18 } = await import("fs");
23061
+ const { existsSync: existsSync24, readFileSync: readFileSync20 } = await import("fs");
21805
23062
  const { join } = await import("path");
21806
23063
  const home = process.env.HOME ?? "";
21807
23064
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
21808
- if (existsSync22(gatewayConfig)) {
21809
- const raw = JSON.parse(readFileSync18(gatewayConfig, "utf8"));
23065
+ if (existsSync24(gatewayConfig)) {
23066
+ const raw = JSON.parse(readFileSync20(gatewayConfig, "utf8"));
21810
23067
  if (raw.agents && raw.agents.length > 0) {
21811
23068
  setExternals(raw.agents.map((a) => ({
21812
23069
  name: a.name,
@@ -21987,8 +23244,8 @@ __export(wiki_client_exports, {
21987
23244
  listDocuments: () => listDocuments,
21988
23245
  listWorkspaces: () => listWorkspaces
21989
23246
  });
21990
- async function wikiFetch(config, path34, method = "GET", body) {
21991
- const url = `${config.baseUrl}/api/v1${path34}`;
23247
+ async function wikiFetch(config, path36, method = "GET", body) {
23248
+ const url = `${config.baseUrl}/api/v1${path36}`;
21992
23249
  const headers = {
21993
23250
  Authorization: `Bearer ${config.apiKey}`,
21994
23251
  "Content-Type": "application/json"
@@ -22021,7 +23278,7 @@ async function wikiFetch(config, path34, method = "GET", body) {
22021
23278
  }
22022
23279
  }
22023
23280
  if (!response.ok) {
22024
- throw new Error(`Wiki API ${method} ${path34}: ${response.status} ${response.statusText}`);
23281
+ throw new Error(`Wiki API ${method} ${path36}: ${response.status} ${response.statusText}`);
22025
23282
  }
22026
23283
  return response.json();
22027
23284
  } finally {
@@ -22631,12 +23888,12 @@ function SettingsView({ onBack }) {
22631
23888
  }
22632
23889
  setProviders(providerList);
22633
23890
  try {
22634
- const { existsSync: existsSync22 } = await import("fs");
23891
+ const { existsSync: existsSync24 } = await import("fs");
22635
23892
  const { join } = await import("path");
22636
23893
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
22637
23894
  const cfg = await loadConfig2();
22638
23895
  const home = process.env.HOME ?? "";
22639
- const hasKey = existsSync22(join(home, ".exe-os", "master.key"));
23896
+ const hasKey = existsSync24(join(home, ".exe-os", "master.key"));
22640
23897
  if (cfg.cloud) {
22641
23898
  setCloud({
22642
23899
  configured: true,
@@ -22649,22 +23906,22 @@ function SettingsView({ onBack }) {
22649
23906
  const pidPath = join(home, ".exe-os", "exed.pid");
22650
23907
  let daemon = "unknown";
22651
23908
  try {
22652
- daemon = existsSync22(pidPath) ? "running" : "stopped";
23909
+ daemon = existsSync24(pidPath) ? "running" : "stopped";
22653
23910
  } catch {
22654
23911
  }
22655
23912
  let version = "unknown";
22656
23913
  try {
22657
- const { readFileSync: readFileSync18 } = await import("fs");
23914
+ const { readFileSync: readFileSync20 } = await import("fs");
22658
23915
  const { createRequire } = await import("module");
22659
23916
  const require2 = createRequire(import.meta.url);
22660
23917
  const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
22661
- const pkg = JSON.parse(readFileSync18(pkgPath, "utf8"));
23918
+ const pkg = JSON.parse(readFileSync20(pkgPath, "utf8"));
22662
23919
  version = pkg.version;
22663
23920
  } catch {
22664
23921
  try {
22665
- const { readFileSync: readFileSync18 } = await import("fs");
23922
+ const { readFileSync: readFileSync20 } = await import("fs");
22666
23923
  const { join: joinPath } = await import("path");
22667
- const pkg = JSON.parse(readFileSync18(joinPath(process.cwd(), "package.json"), "utf8"));
23924
+ const pkg = JSON.parse(readFileSync20(joinPath(process.cwd(), "package.json"), "utf8"));
22668
23925
  version = pkg.version;
22669
23926
  } catch {
22670
23927
  }
@@ -23271,8 +24528,8 @@ Unhandled rejection: ${reason}
23271
24528
  });
23272
24529
 
23273
24530
  // src/bin/cli.ts
23274
- import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync10, readdirSync as readdirSync5, rmSync } from "fs";
23275
- import path33 from "path";
24531
+ import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync12, readdirSync as readdirSync7, rmSync } from "fs";
24532
+ import path35 from "path";
23276
24533
  import os11 from "os";
23277
24534
  var args = process.argv.slice(2);
23278
24535
  if (args.includes("--global")) {
@@ -23336,11 +24593,11 @@ if (args.includes("--global")) {
23336
24593
  });
23337
24594
  await init_App2().then(() => App_exports);
23338
24595
  } else {
23339
- const claudeDir = path33.join(os11.homedir(), ".claude");
23340
- const settingsPath = path33.join(claudeDir, "settings.json");
23341
- const hasClaudeCode = existsSync21(settingsPath) && (() => {
24596
+ const claudeDir = path35.join(os11.homedir(), ".claude");
24597
+ const settingsPath = path35.join(claudeDir, "settings.json");
24598
+ const hasClaudeCode = existsSync23(settingsPath) && (() => {
23342
24599
  try {
23343
- const raw = readFileSync17(settingsPath, "utf8");
24600
+ const raw = readFileSync19(settingsPath, "utf8");
23344
24601
  return raw.includes("exe-os") || raw.includes("exe-mem");
23345
24602
  } catch {
23346
24603
  return false;
@@ -23379,14 +24636,14 @@ async function runClaudeInstall() {
23379
24636
  }
23380
24637
  }
23381
24638
  async function runClaudeCheck() {
23382
- const claudeDir = path33.join(os11.homedir(), ".claude");
23383
- const settingsPath = path33.join(claudeDir, "settings.json");
23384
- const claudeJsonPath = path33.join(os11.homedir(), ".claude.json");
24639
+ const claudeDir = path35.join(os11.homedir(), ".claude");
24640
+ const settingsPath = path35.join(claudeDir, "settings.json");
24641
+ const claudeJsonPath = path35.join(os11.homedir(), ".claude.json");
23385
24642
  let ok = true;
23386
- if (existsSync21(settingsPath)) {
24643
+ if (existsSync23(settingsPath)) {
23387
24644
  let settings;
23388
24645
  try {
23389
- settings = JSON.parse(readFileSync17(settingsPath, "utf8"));
24646
+ settings = JSON.parse(readFileSync19(settingsPath, "utf8"));
23390
24647
  } catch {
23391
24648
  console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
23392
24649
  ok = false;
@@ -23412,10 +24669,10 @@ async function runClaudeCheck() {
23412
24669
  console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
23413
24670
  ok = false;
23414
24671
  }
23415
- if (existsSync21(claudeJsonPath)) {
24672
+ if (existsSync23(claudeJsonPath)) {
23416
24673
  let claudeJson;
23417
24674
  try {
23418
- claudeJson = JSON.parse(readFileSync17(claudeJsonPath, "utf8"));
24675
+ claudeJson = JSON.parse(readFileSync19(claudeJsonPath, "utf8"));
23419
24676
  } catch {
23420
24677
  console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
23421
24678
  ok = false;
@@ -23434,8 +24691,8 @@ async function runClaudeCheck() {
23434
24691
  console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
23435
24692
  ok = false;
23436
24693
  }
23437
- const skillsDir = path33.join(claudeDir, "skills");
23438
- if (existsSync21(skillsDir)) {
24694
+ const skillsDir = path35.join(claudeDir, "skills");
24695
+ if (existsSync23(skillsDir)) {
23439
24696
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
23440
24697
  } else {
23441
24698
  console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
@@ -23452,16 +24709,16 @@ async function runClaudeUninstall(flags = []) {
23452
24709
  const dryRun = flags.includes("--dry-run");
23453
24710
  const purge = flags.includes("--purge");
23454
24711
  const homeDir = os11.homedir();
23455
- const claudeDir = path33.join(homeDir, ".claude");
23456
- const settingsPath = path33.join(claudeDir, "settings.json");
23457
- const claudeJsonPath = path33.join(homeDir, ".claude.json");
23458
- const exeOsDir = path33.join(homeDir, ".exe-os");
24712
+ const claudeDir = path35.join(homeDir, ".claude");
24713
+ const settingsPath = path35.join(claudeDir, "settings.json");
24714
+ const claudeJsonPath = path35.join(homeDir, ".claude.json");
24715
+ const exeOsDir = path35.join(homeDir, ".exe-os");
23459
24716
  let removed = 0;
23460
24717
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
23461
24718
  let settings = {};
23462
- if (existsSync21(settingsPath)) {
24719
+ if (existsSync23(settingsPath)) {
23463
24720
  try {
23464
- settings = JSON.parse(readFileSync17(settingsPath, "utf8"));
24721
+ settings = JSON.parse(readFileSync19(settingsPath, "utf8"));
23465
24722
  } catch {
23466
24723
  console.error("Your ~/.claude/settings.json appears malformed.");
23467
24724
  if (purge) {
@@ -23499,15 +24756,15 @@ async function runClaudeUninstall(flags = []) {
23499
24756
  permCount = before - settings.permissions.allow.length;
23500
24757
  }
23501
24758
  if (!dryRun) {
23502
- writeFileSync10(settingsPath, JSON.stringify(settings, null, 2) + "\n");
24759
+ writeFileSync12(settingsPath, JSON.stringify(settings, null, 2) + "\n");
23503
24760
  }
23504
24761
  log("\u2713 Removed exe-os hooks from settings.json");
23505
24762
  if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
23506
24763
  removed++;
23507
24764
  }
23508
24765
  }
23509
- if (existsSync21(claudeJsonPath)) {
23510
- const raw = readFileSync17(claudeJsonPath, "utf8");
24766
+ if (existsSync23(claudeJsonPath)) {
24767
+ const raw = readFileSync19(claudeJsonPath, "utf8");
23511
24768
  if (raw.length > 1e6) {
23512
24769
  console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
23513
24770
  } else {
@@ -23528,7 +24785,7 @@ async function runClaudeUninstall(flags = []) {
23528
24785
  }
23529
24786
  if (removedMcp) {
23530
24787
  if (!dryRun) {
23531
- writeFileSync10(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
24788
+ writeFileSync12(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
23532
24789
  }
23533
24790
  log("\u2713 Removed exe-os MCP server from claude.json");
23534
24791
  removed++;
@@ -23536,14 +24793,14 @@ async function runClaudeUninstall(flags = []) {
23536
24793
  }
23537
24794
  }
23538
24795
  }
23539
- const skillsDir = path33.join(claudeDir, "skills");
23540
- if (existsSync21(skillsDir)) {
24796
+ const skillsDir = path35.join(claudeDir, "skills");
24797
+ if (existsSync23(skillsDir)) {
23541
24798
  let skillCount = 0;
23542
24799
  try {
23543
- const entries = readdirSync5(skillsDir);
24800
+ const entries = readdirSync7(skillsDir);
23544
24801
  for (const entry of entries) {
23545
24802
  if (entry.startsWith("exe")) {
23546
- const fullPath = path33.join(skillsDir, entry);
24803
+ const fullPath = path35.join(skillsDir, entry);
23547
24804
  if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
23548
24805
  skillCount++;
23549
24806
  }
@@ -23555,30 +24812,30 @@ async function runClaudeUninstall(flags = []) {
23555
24812
  removed++;
23556
24813
  }
23557
24814
  }
23558
- const claudeMdPath = path33.join(claudeDir, "CLAUDE.md");
23559
- if (existsSync21(claudeMdPath)) {
23560
- const content = readFileSync17(claudeMdPath, "utf8");
24815
+ const claudeMdPath = path35.join(claudeDir, "CLAUDE.md");
24816
+ if (existsSync23(claudeMdPath)) {
24817
+ const content = readFileSync19(claudeMdPath, "utf8");
23561
24818
  const startMarker = "<!-- exe-os:orchestration-start -->";
23562
24819
  const endMarker = "<!-- exe-os:orchestration-end -->";
23563
24820
  const startIdx = content.indexOf(startMarker);
23564
24821
  const endIdx = content.indexOf(endMarker);
23565
24822
  if (startIdx !== -1 && endIdx !== -1) {
23566
24823
  const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
23567
- if (!dryRun) writeFileSync10(claudeMdPath, cleaned);
24824
+ if (!dryRun) writeFileSync12(claudeMdPath, cleaned);
23568
24825
  log("\u2713 Removed orchestration block from CLAUDE.md");
23569
24826
  removed++;
23570
24827
  }
23571
24828
  }
23572
- const agentsDir = path33.join(claudeDir, "agents");
23573
- if (existsSync21(agentsDir)) {
24829
+ const agentsDir = path35.join(claudeDir, "agents");
24830
+ if (existsSync23(agentsDir)) {
23574
24831
  let agentCount = 0;
23575
24832
  try {
23576
- const entries = readdirSync5(agentsDir).filter((f) => f.endsWith(".md"));
24833
+ const entries = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
23577
24834
  let knownNames = /* @__PURE__ */ new Set();
23578
- const rosterPath = path33.join(exeOsDir, "exe-employees.json");
23579
- if (existsSync21(rosterPath)) {
24835
+ const rosterPath = path35.join(exeOsDir, "exe-employees.json");
24836
+ if (existsSync23(rosterPath)) {
23580
24837
  try {
23581
- const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
24838
+ const roster = JSON.parse(readFileSync19(rosterPath, "utf8"));
23582
24839
  knownNames = new Set(roster.map((e) => e.name));
23583
24840
  } catch {
23584
24841
  }
@@ -23586,7 +24843,7 @@ async function runClaudeUninstall(flags = []) {
23586
24843
  for (const entry of entries) {
23587
24844
  const name = entry.replace(/\.md$/, "");
23588
24845
  if (knownNames.has(name)) {
23589
- if (!dryRun) rmSync(path33.join(agentsDir, entry), { force: true });
24846
+ if (!dryRun) rmSync(path35.join(agentsDir, entry), { force: true });
23590
24847
  agentCount++;
23591
24848
  }
23592
24849
  }
@@ -23597,16 +24854,16 @@ async function runClaudeUninstall(flags = []) {
23597
24854
  removed++;
23598
24855
  }
23599
24856
  }
23600
- const projectsDir = path33.join(claudeDir, "projects");
23601
- if (existsSync21(projectsDir)) {
24857
+ const projectsDir = path35.join(claudeDir, "projects");
24858
+ if (existsSync23(projectsDir)) {
23602
24859
  let projectCount = 0;
23603
24860
  try {
23604
- const projects = readdirSync5(projectsDir);
24861
+ const projects = readdirSync7(projectsDir);
23605
24862
  for (const proj of projects) {
23606
- const projSettings = path33.join(projectsDir, proj, "settings.json");
23607
- if (!existsSync21(projSettings)) continue;
24863
+ const projSettings = path35.join(projectsDir, proj, "settings.json");
24864
+ if (!existsSync23(projSettings)) continue;
23608
24865
  try {
23609
- const pSettings = JSON.parse(readFileSync17(projSettings, "utf8"));
24866
+ const pSettings = JSON.parse(readFileSync19(projSettings, "utf8"));
23610
24867
  let changed = false;
23611
24868
  if (Array.isArray(pSettings.permissions?.allow)) {
23612
24869
  const before = pSettings.permissions.allow.length;
@@ -23616,7 +24873,7 @@ async function runClaudeUninstall(flags = []) {
23616
24873
  if (pSettings.permissions.allow.length < before) changed = true;
23617
24874
  }
23618
24875
  if (changed && !dryRun) {
23619
- writeFileSync10(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
24876
+ writeFileSync12(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
23620
24877
  }
23621
24878
  if (changed) projectCount++;
23622
24879
  } catch {
@@ -23640,16 +24897,16 @@ async function runClaudeUninstall(flags = []) {
23640
24897
  };
23641
24898
  const exeBinPath = findExeBin3();
23642
24899
  if (!exeBinPath) throw new Error("exe-os not found in PATH");
23643
- const binDir = path33.dirname(exeBinPath);
24900
+ const binDir = path35.dirname(exeBinPath);
23644
24901
  let symlinkCount = 0;
23645
- const rosterPath = path33.join(exeOsDir, "exe-employees.json");
23646
- if (existsSync21(rosterPath)) {
23647
- const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
24902
+ const rosterPath = path35.join(exeOsDir, "exe-employees.json");
24903
+ if (existsSync23(rosterPath)) {
24904
+ const roster = JSON.parse(readFileSync19(rosterPath, "utf8"));
23648
24905
  for (const emp of roster) {
23649
24906
  if (emp.name === "exe") continue;
23650
24907
  for (const suffix of ["", "-opencode"]) {
23651
- const linkPath = path33.join(binDir, `${emp.name}${suffix}`);
23652
- if (existsSync21(linkPath)) {
24908
+ const linkPath = path35.join(binDir, `${emp.name}${suffix}`);
24909
+ if (existsSync23(linkPath)) {
23653
24910
  if (!dryRun) rmSync(linkPath, { force: true });
23654
24911
  symlinkCount++;
23655
24912
  }
@@ -23662,7 +24919,7 @@ async function runClaudeUninstall(flags = []) {
23662
24919
  }
23663
24920
  } catch {
23664
24921
  }
23665
- if (purge && existsSync21(exeOsDir)) {
24922
+ if (purge && existsSync23(exeOsDir)) {
23666
24923
  if (!dryRun) {
23667
24924
  process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
23668
24925
  process.stdout.write(" Removing ~/.exe-os...\n");
@@ -23687,7 +24944,7 @@ async function checkForUpdateOnBoot() {
23687
24944
  const config = await loadConfig2();
23688
24945
  if (!config.autoUpdate.checkOnBoot) return;
23689
24946
  const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
23690
- const packageRoot = path33.resolve(
24947
+ const packageRoot = path35.resolve(
23691
24948
  new URL("../..", import.meta.url).pathname
23692
24949
  );
23693
24950
  const result = checkForUpdate2(packageRoot);
@@ -23746,7 +25003,7 @@ async function runActivate(key) {
23746
25003
  const idTemplate = getIdentityTemplate(identityKey);
23747
25004
  if (idTemplate) {
23748
25005
  const idPath = identityPath2(name);
23749
- const dir = path33.dirname(idPath);
25006
+ const dir = path35.dirname(idPath);
23750
25007
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
23751
25008
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
23752
25009
  }