@askexenow/exe-os 0.8.61 → 0.8.62

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.
package/dist/bin/cli.js CHANGED
@@ -4770,10 +4770,10 @@ async function disposeEmbedder() {
4770
4770
  async function embedDirect(text) {
4771
4771
  const llamaCpp = await import("node-llama-cpp");
4772
4772
  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)) {
4773
+ const { existsSync: existsSync24 } = await import("fs");
4774
+ const path36 = await import("path");
4775
+ const modelPath = path36.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
4776
+ if (!existsSync24(modelPath)) {
4777
4777
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
4778
4778
  }
4779
4779
  const llama = await llamaCpp.getLlama();
@@ -5188,6 +5188,1071 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
5188
5188
  }
5189
5189
  });
5190
5190
 
5191
+ // src/lib/crypto.ts
5192
+ var crypto_exports = {};
5193
+ __export(crypto_exports, {
5194
+ decryptSyncBlob: () => decryptSyncBlob,
5195
+ encryptSyncBlob: () => encryptSyncBlob,
5196
+ initSyncCrypto: () => initSyncCrypto,
5197
+ isSyncCryptoInitialized: () => isSyncCryptoInitialized
5198
+ });
5199
+ import crypto3 from "crypto";
5200
+ function initSyncCrypto(masterKey) {
5201
+ if (masterKey.length !== 32) {
5202
+ throw new Error(`Master key must be 32 bytes, got ${masterKey.length}`);
5203
+ }
5204
+ _syncKey = Buffer.from(
5205
+ crypto3.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
5206
+ );
5207
+ }
5208
+ function isSyncCryptoInitialized() {
5209
+ return _syncKey !== null;
5210
+ }
5211
+ function requireSyncKey() {
5212
+ if (!_syncKey) {
5213
+ throw new Error("Sync crypto not initialized. Call initSyncCrypto(masterKey) first.");
5214
+ }
5215
+ return _syncKey;
5216
+ }
5217
+ function encryptSyncBlob(data) {
5218
+ const key = requireSyncKey();
5219
+ const iv = crypto3.randomBytes(IV_LENGTH);
5220
+ const cipher = crypto3.createCipheriv(ALGORITHM, key, iv);
5221
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
5222
+ const tag = cipher.getAuthTag();
5223
+ return Buffer.concat([iv, encrypted, tag]).toString("base64");
5224
+ }
5225
+ function decryptSyncBlob(ciphertext) {
5226
+ const key = requireSyncKey();
5227
+ const combined = Buffer.from(ciphertext, "base64");
5228
+ if (combined.length < IV_LENGTH + TAG_LENGTH) {
5229
+ throw new Error("Sync blob too short to contain IV + tag");
5230
+ }
5231
+ const iv = combined.subarray(0, IV_LENGTH);
5232
+ const tag = combined.subarray(combined.length - TAG_LENGTH);
5233
+ const encrypted = combined.subarray(IV_LENGTH, combined.length - TAG_LENGTH);
5234
+ const decipher = crypto3.createDecipheriv(ALGORITHM, key, iv);
5235
+ decipher.setAuthTag(tag);
5236
+ return Buffer.concat([decipher.update(encrypted), decipher.final()]);
5237
+ }
5238
+ var ALGORITHM, IV_LENGTH, TAG_LENGTH, SYNC_HKDF_INFO, _syncKey;
5239
+ var init_crypto = __esm({
5240
+ "src/lib/crypto.ts"() {
5241
+ "use strict";
5242
+ ALGORITHM = "aes-256-gcm";
5243
+ IV_LENGTH = 12;
5244
+ TAG_LENGTH = 16;
5245
+ SYNC_HKDF_INFO = "exe-mem-sync-v2";
5246
+ _syncKey = null;
5247
+ }
5248
+ });
5249
+
5250
+ // src/lib/compress.ts
5251
+ import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
5252
+ function compress(input) {
5253
+ if (input.length === 0) return Buffer.alloc(0);
5254
+ return brotliCompressSync(input, {
5255
+ params: {
5256
+ [constants.BROTLI_PARAM_QUALITY]: 4
5257
+ }
5258
+ });
5259
+ }
5260
+ function decompress(input) {
5261
+ if (input.length === 0) return Buffer.alloc(0);
5262
+ return brotliDecompressSync(input);
5263
+ }
5264
+ var init_compress = __esm({
5265
+ "src/lib/compress.ts"() {
5266
+ "use strict";
5267
+ }
5268
+ });
5269
+
5270
+ // src/lib/cloud-sync.ts
5271
+ var cloud_sync_exports = {};
5272
+ __export(cloud_sync_exports, {
5273
+ assertSecureEndpoint: () => assertSecureEndpoint,
5274
+ buildRosterBlob: () => buildRosterBlob,
5275
+ cloudPull: () => cloudPull,
5276
+ cloudPullBehaviors: () => cloudPullBehaviors,
5277
+ cloudPullBlob: () => cloudPullBlob,
5278
+ cloudPullConversations: () => cloudPullConversations,
5279
+ cloudPullDocuments: () => cloudPullDocuments,
5280
+ cloudPullGlobalProcedures: () => cloudPullGlobalProcedures,
5281
+ cloudPullGraphRAG: () => cloudPullGraphRAG,
5282
+ cloudPullRoster: () => cloudPullRoster,
5283
+ cloudPullTasks: () => cloudPullTasks,
5284
+ cloudPush: () => cloudPush,
5285
+ cloudPushBehaviors: () => cloudPushBehaviors,
5286
+ cloudPushBlob: () => cloudPushBlob,
5287
+ cloudPushConversations: () => cloudPushConversations,
5288
+ cloudPushDocuments: () => cloudPushDocuments,
5289
+ cloudPushGlobalProcedures: () => cloudPushGlobalProcedures,
5290
+ cloudPushGraphRAG: () => cloudPushGraphRAG,
5291
+ cloudPushRoster: () => cloudPushRoster,
5292
+ cloudPushTasks: () => cloudPushTasks,
5293
+ cloudSync: () => cloudSync,
5294
+ mergeConfig: () => mergeConfig,
5295
+ mergeRosterFromRemote: () => mergeRosterFromRemote,
5296
+ recordRosterDeletion: () => recordRosterDeletion
5297
+ });
5298
+ 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";
5299
+ import crypto4 from "crypto";
5300
+ import path12 from "path";
5301
+ import { homedir as homedir3 } from "os";
5302
+ function sqlSafe(v) {
5303
+ return v === void 0 ? null : v;
5304
+ }
5305
+ function logError(msg) {
5306
+ try {
5307
+ const logPath = path12.join(homedir3(), ".exe-os", "workers.log");
5308
+ appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
5309
+ `);
5310
+ } catch {
5311
+ }
5312
+ }
5313
+ async function withRosterLock(fn) {
5314
+ try {
5315
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5316
+ closeSync2(fd);
5317
+ writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5318
+ } catch (err) {
5319
+ if (err.code === "EEXIST") {
5320
+ try {
5321
+ const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
5322
+ if (Date.now() - ts < LOCK_STALE_MS) {
5323
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
5324
+ }
5325
+ unlinkSync4(ROSTER_LOCK_PATH);
5326
+ const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5327
+ closeSync2(fd);
5328
+ writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5329
+ } catch (retryErr) {
5330
+ if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
5331
+ throw new Error("Roster merge already in progress \u2014 another sync is running");
5332
+ }
5333
+ } else {
5334
+ throw err;
5335
+ }
5336
+ }
5337
+ try {
5338
+ return await fn();
5339
+ } finally {
5340
+ try {
5341
+ unlinkSync4(ROSTER_LOCK_PATH);
5342
+ } catch {
5343
+ }
5344
+ }
5345
+ }
5346
+ async function fetchWithRetry(url, init) {
5347
+ const MAX_RETRIES2 = 3;
5348
+ const BASE_DELAY_MS2 = 200;
5349
+ let lastError;
5350
+ for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
5351
+ try {
5352
+ const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
5353
+ const resp = await fetch(url, { ...init, signal });
5354
+ if (resp && resp.status >= 500 && attempt < MAX_RETRIES2) {
5355
+ await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
5356
+ continue;
5357
+ }
5358
+ return resp;
5359
+ } catch (err) {
5360
+ lastError = err;
5361
+ if (attempt === MAX_RETRIES2) throw err;
5362
+ await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
5363
+ }
5364
+ }
5365
+ throw lastError;
5366
+ }
5367
+ function assertSecureEndpoint(endpoint) {
5368
+ if (endpoint.startsWith("https://")) return;
5369
+ if (endpoint.startsWith("http://")) {
5370
+ try {
5371
+ const parsed = new URL(endpoint);
5372
+ if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
5373
+ } catch {
5374
+ return;
5375
+ }
5376
+ throw new Error(
5377
+ `Insecure cloud endpoint rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost.`
5378
+ );
5379
+ }
5380
+ }
5381
+ async function cloudPush(records, maxVersion, config) {
5382
+ if (records.length === 0) return true;
5383
+ assertSecureEndpoint(config.endpoint);
5384
+ try {
5385
+ const json = JSON.stringify(records);
5386
+ const compressed = compress(Buffer.from(json, "utf8"));
5387
+ const blob = encryptSyncBlob(compressed);
5388
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/push`, {
5389
+ method: "POST",
5390
+ headers: {
5391
+ Authorization: `Bearer ${config.apiKey}`,
5392
+ "Content-Type": "application/json",
5393
+ "X-Device-Id": loadDeviceId(),
5394
+ "X-Expected-Version": String(maxVersion)
5395
+ },
5396
+ body: JSON.stringify({ version: maxVersion, blob })
5397
+ });
5398
+ if (resp == null) {
5399
+ logError("[cloud-sync] PUSH FAILED: no response from server");
5400
+ return false;
5401
+ }
5402
+ if (resp.status === 409) {
5403
+ logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
5404
+ return false;
5405
+ }
5406
+ return resp.ok;
5407
+ } catch (err) {
5408
+ logError(`[cloud-sync] PUSH FAILED: ${err instanceof Error ? err.message : String(err)}`);
5409
+ return false;
5410
+ }
5411
+ }
5412
+ async function cloudPull(sinceVersion, config) {
5413
+ assertSecureEndpoint(config.endpoint);
5414
+ try {
5415
+ const response = await fetchWithRetry(`${config.endpoint}/sync/pull`, {
5416
+ method: "POST",
5417
+ headers: {
5418
+ Authorization: `Bearer ${config.apiKey}`,
5419
+ "Content-Type": "application/json",
5420
+ "X-Device-Id": loadDeviceId()
5421
+ },
5422
+ body: JSON.stringify({ since_version: sinceVersion })
5423
+ });
5424
+ if (response == null) {
5425
+ logError("[cloud-sync] PULL FAILED: no response from server");
5426
+ return { records: [], maxVersion: sinceVersion };
5427
+ }
5428
+ if (!response.ok) return { records: [], maxVersion: sinceVersion };
5429
+ const data = await response.json();
5430
+ const allRecords = [];
5431
+ for (const { blob } of data.blobs ?? []) {
5432
+ try {
5433
+ const compressed = decryptSyncBlob(blob);
5434
+ const json = decompress(compressed).toString("utf8");
5435
+ const records = JSON.parse(json);
5436
+ allRecords.push(...records);
5437
+ } catch {
5438
+ continue;
5439
+ }
5440
+ }
5441
+ return { records: allRecords, maxVersion: data.max_version ?? sinceVersion };
5442
+ } catch (err) {
5443
+ logError(`[cloud-sync] PULL FAILED: ${err instanceof Error ? err.message : String(err)}`);
5444
+ return { records: [], maxVersion: sinceVersion };
5445
+ }
5446
+ }
5447
+ async function cloudSync(config) {
5448
+ let client;
5449
+ try {
5450
+ client = getClient();
5451
+ } catch {
5452
+ throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
5453
+ }
5454
+ try {
5455
+ await client.execute(
5456
+ "CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)"
5457
+ );
5458
+ } catch (e) {
5459
+ logError(`[cloud-sync] sync_meta CREATE failed: ${e instanceof Error ? e.message : String(e)}`);
5460
+ }
5461
+ const pullMeta = await client.execute(
5462
+ "SELECT value FROM sync_meta WHERE key = 'last_cloud_pull_version'"
5463
+ );
5464
+ const lastPullVersion = pullMeta.rows.length > 0 ? Number(pullMeta.rows[0].value) : 0;
5465
+ const pullResult = await cloudPull(lastPullVersion, config);
5466
+ let pulled = 0;
5467
+ if (pullResult.records.length > 0) {
5468
+ const stmts = pullResult.records.map((rec) => ({
5469
+ sql: `INSERT OR REPLACE INTO memories
5470
+ (id, agent_id, agent_role, session_id, timestamp,
5471
+ tool_name, project_name, has_error, raw_text, version,
5472
+ author_device_id, scope)
5473
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5474
+ args: [
5475
+ sqlSafe(rec.id),
5476
+ sqlSafe(rec.agent_id),
5477
+ sqlSafe(rec.agent_role),
5478
+ sqlSafe(rec.session_id),
5479
+ sqlSafe(rec.timestamp),
5480
+ sqlSafe(rec.tool_name),
5481
+ sqlSafe(rec.project_name),
5482
+ sqlSafe(rec.has_error ?? 0),
5483
+ sqlSafe(rec.raw_text ?? ""),
5484
+ sqlSafe(rec.version ?? 0),
5485
+ sqlSafe(rec.author_device_id),
5486
+ sqlSafe(rec.scope ?? "business")
5487
+ ]
5488
+ }));
5489
+ await client.batch(stmts, "write");
5490
+ pulled = pullResult.records.length;
5491
+ }
5492
+ if (pullResult.maxVersion > lastPullVersion) {
5493
+ await client.execute({
5494
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_pull_version', ?)",
5495
+ args: [String(pullResult.maxVersion)]
5496
+ });
5497
+ }
5498
+ const pushMeta = await client.execute(
5499
+ "SELECT value FROM sync_meta WHERE key = 'last_cloud_push_version'"
5500
+ );
5501
+ const lastPushVersion = pushMeta.rows.length > 0 ? Number(pushMeta.rows[0].value) : 0;
5502
+ let pushed = 0;
5503
+ let batchCursor = lastPushVersion;
5504
+ while (true) {
5505
+ const recordsResult = await client.execute({
5506
+ sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
5507
+ tool_name, project_name, has_error, raw_text, version,
5508
+ author_device_id, scope
5509
+ FROM memories
5510
+ WHERE version > ?
5511
+ AND (scope IS NULL OR scope != 'personal')
5512
+ ORDER BY version ASC
5513
+ LIMIT ?`,
5514
+ args: [batchCursor, PUSH_BATCH_SIZE]
5515
+ });
5516
+ if (recordsResult.rows.length === 0) break;
5517
+ const records = recordsResult.rows.map((row) => ({
5518
+ id: row.id,
5519
+ agent_id: row.agent_id,
5520
+ agent_role: row.agent_role,
5521
+ session_id: row.session_id,
5522
+ timestamp: row.timestamp,
5523
+ tool_name: row.tool_name,
5524
+ project_name: row.project_name,
5525
+ has_error: row.has_error,
5526
+ raw_text: row.raw_text,
5527
+ version: row.version,
5528
+ author_device_id: row.author_device_id,
5529
+ scope: row.scope
5530
+ }));
5531
+ const maxVersion = Number(records[records.length - 1].version);
5532
+ const pushOk = await cloudPush(records, maxVersion, config);
5533
+ if (!pushOk) break;
5534
+ await client.execute({
5535
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
5536
+ args: [String(maxVersion)]
5537
+ });
5538
+ pushed += records.length;
5539
+ batchCursor = maxVersion;
5540
+ if (recordsResult.rows.length < PUSH_BATCH_SIZE) break;
5541
+ }
5542
+ try {
5543
+ await cloudPushRoster(config);
5544
+ } catch (err) {
5545
+ logError(`[cloud-sync] Roster push: ${err instanceof Error ? err.message : String(err)}`);
5546
+ }
5547
+ try {
5548
+ await cloudPullRoster(config);
5549
+ } catch (err) {
5550
+ logError(`[cloud-sync] Roster pull: ${err instanceof Error ? err.message : String(err)}`);
5551
+ }
5552
+ try {
5553
+ await cloudPushGlobalProcedures(config);
5554
+ } catch (err) {
5555
+ logError(`[cloud-sync] Global procedures push: ${err instanceof Error ? err.message : String(err)}`);
5556
+ }
5557
+ try {
5558
+ await cloudPullGlobalProcedures(config);
5559
+ } catch (err) {
5560
+ logError(`[cloud-sync] Global procedures pull: ${err instanceof Error ? err.message : String(err)}`);
5561
+ }
5562
+ let behaviorsResult = { pushed: false, pulled: 0 };
5563
+ try {
5564
+ behaviorsResult.pushed = await cloudPushBehaviors(config);
5565
+ } catch (err) {
5566
+ logError(`[cloud-sync] Behaviors push: ${err instanceof Error ? err.message : String(err)}`);
5567
+ }
5568
+ try {
5569
+ const pullResult2 = await cloudPullBehaviors(config);
5570
+ behaviorsResult.pulled = pullResult2.pulled;
5571
+ } catch (err) {
5572
+ logError(`[cloud-sync] Behaviors pull: ${err instanceof Error ? err.message : String(err)}`);
5573
+ }
5574
+ let graphragResult = { pushed: false, pulled: 0 };
5575
+ try {
5576
+ graphragResult.pushed = await cloudPushGraphRAG(config);
5577
+ } catch (err) {
5578
+ logError(`[cloud-sync] GraphRAG push: ${err instanceof Error ? err.message : String(err)}`);
5579
+ }
5580
+ try {
5581
+ const pullResult2 = await cloudPullGraphRAG(config);
5582
+ graphragResult.pulled = pullResult2.pulled;
5583
+ } catch (err) {
5584
+ logError(`[cloud-sync] GraphRAG pull: ${err instanceof Error ? err.message : String(err)}`);
5585
+ }
5586
+ let tasksResult = { pushed: false, pulled: 0 };
5587
+ try {
5588
+ tasksResult.pushed = await cloudPushTasks(config);
5589
+ } catch (err) {
5590
+ logError(`[cloud-sync] Tasks push: ${err instanceof Error ? err.message : String(err)}`);
5591
+ }
5592
+ try {
5593
+ const pullResult2 = await cloudPullTasks(config);
5594
+ tasksResult.pulled = pullResult2.pulled;
5595
+ } catch (err) {
5596
+ logError(`[cloud-sync] Tasks pull: ${err instanceof Error ? err.message : String(err)}`);
5597
+ }
5598
+ let conversationsResult = { pushed: false, pulled: 0 };
5599
+ try {
5600
+ conversationsResult.pushed = await cloudPushConversations(config);
5601
+ } catch (err) {
5602
+ logError(`[cloud-sync] Conversations push: ${err instanceof Error ? err.message : String(err)}`);
5603
+ }
5604
+ try {
5605
+ const pullResult2 = await cloudPullConversations(config);
5606
+ conversationsResult.pulled = pullResult2.pulled;
5607
+ } catch (err) {
5608
+ logError(`[cloud-sync] Conversations pull: ${err instanceof Error ? err.message : String(err)}`);
5609
+ }
5610
+ let documentsResult = { pushed: false, pulled: 0 };
5611
+ try {
5612
+ documentsResult.pushed = await cloudPushDocuments(config);
5613
+ } catch (err) {
5614
+ logError(`[cloud-sync] Documents push: ${err instanceof Error ? err.message : String(err)}`);
5615
+ }
5616
+ try {
5617
+ const pullResult2 = await cloudPullDocuments(config);
5618
+ documentsResult.pulled = pullResult2.pulled;
5619
+ } catch (err) {
5620
+ logError(`[cloud-sync] Documents pull: ${err instanceof Error ? err.message : String(err)}`);
5621
+ }
5622
+ return {
5623
+ pushed,
5624
+ pulled,
5625
+ behaviors: behaviorsResult,
5626
+ graphrag: graphragResult,
5627
+ tasks: tasksResult,
5628
+ conversations: conversationsResult,
5629
+ documents: documentsResult
5630
+ };
5631
+ }
5632
+ function recordRosterDeletion(name) {
5633
+ let deletions = [];
5634
+ try {
5635
+ if (existsSync11(ROSTER_DELETIONS_PATH)) {
5636
+ deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
5637
+ }
5638
+ } catch {
5639
+ }
5640
+ if (!deletions.includes(name)) deletions.push(name);
5641
+ writeFileSync4(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5642
+ }
5643
+ function consumeRosterDeletions() {
5644
+ try {
5645
+ if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
5646
+ const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
5647
+ writeFileSync4(ROSTER_DELETIONS_PATH, "[]");
5648
+ return deletions;
5649
+ } catch {
5650
+ return [];
5651
+ }
5652
+ }
5653
+ function buildRosterBlob(paths) {
5654
+ const rosterPath = paths?.rosterPath ?? path12.join(EXE_AI_DIR, "exe-employees.json");
5655
+ const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5656
+ const configPath = paths?.configPath ?? path12.join(EXE_AI_DIR, "config.json");
5657
+ let roster = [];
5658
+ if (existsSync11(rosterPath)) {
5659
+ try {
5660
+ roster = JSON.parse(readFileSync7(rosterPath, "utf-8"));
5661
+ } catch {
5662
+ }
5663
+ }
5664
+ const identities = {};
5665
+ if (existsSync11(identityDir)) {
5666
+ for (const file of readdirSync2(identityDir).filter((f) => f.endsWith(".md"))) {
5667
+ try {
5668
+ identities[file] = readFileSync7(path12.join(identityDir, file), "utf-8");
5669
+ } catch {
5670
+ }
5671
+ }
5672
+ }
5673
+ let config;
5674
+ if (existsSync11(configPath)) {
5675
+ try {
5676
+ config = JSON.parse(readFileSync7(configPath, "utf-8"));
5677
+ } catch {
5678
+ }
5679
+ }
5680
+ const deletedNames = consumeRosterDeletions();
5681
+ const content = JSON.stringify({ roster, identities, config, deletedNames });
5682
+ const hash = crypto4.createHash("sha256").update(content).digest("hex").slice(0, 16);
5683
+ return { roster, identities, config, deletedNames, version: hash };
5684
+ }
5685
+ async function cloudPushRoster(config) {
5686
+ assertSecureEndpoint(config.endpoint);
5687
+ const blob = buildRosterBlob();
5688
+ if (blob.roster.length === 0) return true;
5689
+ try {
5690
+ const client = getClient();
5691
+ const meta = await client.execute(
5692
+ "SELECT value FROM sync_meta WHERE key = 'last_roster_push_version'"
5693
+ );
5694
+ const lastVersion = meta.rows.length > 0 ? Number(meta.rows[0].value) : 0;
5695
+ if (blob.version === lastVersion) return true;
5696
+ } catch {
5697
+ }
5698
+ try {
5699
+ const json = JSON.stringify(blob);
5700
+ const compressed = compress(Buffer.from(json, "utf8"));
5701
+ const encrypted = encryptSyncBlob(compressed);
5702
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/push-roster`, {
5703
+ method: "POST",
5704
+ headers: {
5705
+ Authorization: `Bearer ${config.apiKey}`,
5706
+ "Content-Type": "application/json",
5707
+ "X-Device-Id": loadDeviceId()
5708
+ },
5709
+ body: JSON.stringify({ blob: encrypted })
5710
+ });
5711
+ if (resp.ok) {
5712
+ try {
5713
+ const client = getClient();
5714
+ await client.execute({
5715
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_roster_push_version', ?)",
5716
+ args: [String(blob.version)]
5717
+ });
5718
+ } catch {
5719
+ }
5720
+ }
5721
+ return resp.ok;
5722
+ } catch (err) {
5723
+ process.stderr.write(`[cloud-sync] ROSTER PUSH FAILED: ${err instanceof Error ? err.message : String(err)}
5724
+ `);
5725
+ return false;
5726
+ }
5727
+ }
5728
+ async function cloudPullRoster(config) {
5729
+ assertSecureEndpoint(config.endpoint);
5730
+ try {
5731
+ const resp = await fetchWithRetry(`${config.endpoint}/sync/pull-roster`, {
5732
+ method: "GET",
5733
+ headers: {
5734
+ Authorization: `Bearer ${config.apiKey}`,
5735
+ "X-Device-Id": loadDeviceId()
5736
+ }
5737
+ });
5738
+ if (!resp.ok) return { added: 0 };
5739
+ const data = await resp.json();
5740
+ if (!data.blob) return { added: 0 };
5741
+ const compressed = decryptSyncBlob(data.blob);
5742
+ const json = decompress(compressed).toString("utf8");
5743
+ const remote = JSON.parse(json);
5744
+ return mergeRosterFromRemote(remote);
5745
+ } catch (err) {
5746
+ process.stderr.write(`[cloud-sync] ROSTER PULL FAILED: ${err instanceof Error ? err.message : String(err)}
5747
+ `);
5748
+ return { added: 0 };
5749
+ }
5750
+ }
5751
+ function mergeConfig(remoteConfig, configPath) {
5752
+ const cfgPath = configPath ?? path12.join(EXE_AI_DIR, "config.json");
5753
+ let local = {};
5754
+ if (existsSync11(cfgPath)) {
5755
+ try {
5756
+ local = JSON.parse(readFileSync7(cfgPath, "utf-8"));
5757
+ } catch {
5758
+ }
5759
+ }
5760
+ const merged = { ...remoteConfig, ...local };
5761
+ const dir = path12.dirname(cfgPath);
5762
+ if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
5763
+ writeFileSync4(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5764
+ }
5765
+ async function mergeRosterFromRemote(remote, paths) {
5766
+ return withRosterLock(async () => {
5767
+ const rosterPath = paths?.rosterPath ?? void 0;
5768
+ const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5769
+ const localEmployees = await loadEmployees(rosterPath);
5770
+ const localNames = new Set(localEmployees.map((e) => e.name));
5771
+ let added = 0;
5772
+ let identitiesUpdated = 0;
5773
+ for (const remoteEmp of remote.roster) {
5774
+ if (!localNames.has(remoteEmp.name)) {
5775
+ localEmployees.push(remoteEmp);
5776
+ localNames.add(remoteEmp.name);
5777
+ added++;
5778
+ try {
5779
+ registerBinSymlinks(remoteEmp.name);
5780
+ } catch {
5781
+ }
5782
+ }
5783
+ const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
5784
+ if (remoteIdentity) {
5785
+ if (!existsSync11(identityDir)) mkdirSync5(identityDir, { recursive: true });
5786
+ const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
5787
+ let localIdentity = null;
5788
+ try {
5789
+ localIdentity = existsSync11(idPath) ? readFileSync7(idPath, "utf-8") : null;
5790
+ } catch {
5791
+ }
5792
+ if (localIdentity !== remoteIdentity) {
5793
+ writeFileSync4(idPath, remoteIdentity, "utf-8");
5794
+ identitiesUpdated++;
5795
+ }
5796
+ }
5797
+ }
5798
+ let removed = 0;
5799
+ if (remote.deletedNames && remote.deletedNames.length > 0) {
5800
+ const toRemove = new Set(remote.deletedNames);
5801
+ const filtered = localEmployees.filter((e) => !toRemove.has(e.name));
5802
+ removed = localEmployees.length - filtered.length;
5803
+ if (removed > 0) {
5804
+ localEmployees.length = 0;
5805
+ localEmployees.push(...filtered);
5806
+ }
5807
+ }
5808
+ if (added > 0 || removed > 0) {
5809
+ await saveEmployees(localEmployees, rosterPath);
5810
+ }
5811
+ if (remote.config && Object.keys(remote.config).length > 0) {
5812
+ try {
5813
+ mergeConfig(remote.config, paths?.configPath);
5814
+ } catch {
5815
+ }
5816
+ }
5817
+ return { added, identitiesUpdated };
5818
+ });
5819
+ }
5820
+ async function cloudPushBlob(route, data, metaKey, config) {
5821
+ if (data.length === 0) return { ok: true };
5822
+ assertSecureEndpoint(config.endpoint);
5823
+ const json = JSON.stringify(data);
5824
+ const version = Buffer.from(json).length;
5825
+ try {
5826
+ const client = getClient();
5827
+ const meta = await client.execute({
5828
+ sql: "SELECT value FROM sync_meta WHERE key = ?",
5829
+ args: [metaKey]
5830
+ });
5831
+ const lastVersion = meta.rows.length > 0 ? Number(meta.rows[0].value) : 0;
5832
+ if (version === lastVersion) return { ok: true };
5833
+ } catch {
5834
+ }
5835
+ try {
5836
+ const compressed = compress(Buffer.from(json, "utf8"));
5837
+ const encrypted = encryptSyncBlob(compressed);
5838
+ const resp = await fetchWithRetry(`${config.endpoint}${route}`, {
5839
+ method: "POST",
5840
+ headers: {
5841
+ Authorization: `Bearer ${config.apiKey}`,
5842
+ "Content-Type": "application/json",
5843
+ "X-Device-Id": loadDeviceId()
5844
+ },
5845
+ body: JSON.stringify({ blob: encrypted })
5846
+ });
5847
+ if (resp.ok) {
5848
+ try {
5849
+ const client = getClient();
5850
+ await client.execute({
5851
+ sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES (?, ?)",
5852
+ args: [metaKey, String(version)]
5853
+ });
5854
+ } catch {
5855
+ }
5856
+ }
5857
+ return { ok: resp.ok };
5858
+ } catch (err) {
5859
+ logError(`[cloud-sync] PUSH ${route}: ${err instanceof Error ? err.message : String(err)}`);
5860
+ return { ok: false };
5861
+ }
5862
+ }
5863
+ async function cloudPullBlob(route, config) {
5864
+ assertSecureEndpoint(config.endpoint);
5865
+ try {
5866
+ const resp = await fetchWithRetry(`${config.endpoint}${route}`, {
5867
+ method: "GET",
5868
+ headers: {
5869
+ Authorization: `Bearer ${config.apiKey}`,
5870
+ "X-Device-Id": loadDeviceId()
5871
+ }
5872
+ });
5873
+ if (!resp.ok) return null;
5874
+ const data = await resp.json();
5875
+ if (!data.blob) return null;
5876
+ const compressed = decryptSyncBlob(data.blob);
5877
+ const json = decompress(compressed).toString("utf8");
5878
+ return JSON.parse(json);
5879
+ } catch (err) {
5880
+ logError(`[cloud-sync] PULL ${route}: ${err instanceof Error ? err.message : String(err)}`);
5881
+ return null;
5882
+ }
5883
+ }
5884
+ async function cloudPushGlobalProcedures(config) {
5885
+ const client = getClient();
5886
+ const result = await client.execute("SELECT * FROM global_procedures LIMIT 1000");
5887
+ const rows = result.rows;
5888
+ const { ok } = await cloudPushBlob(
5889
+ "/sync/push-global-procedures",
5890
+ rows,
5891
+ "last_global_procedures_push_version",
5892
+ config
5893
+ );
5894
+ return ok;
5895
+ }
5896
+ async function cloudPullGlobalProcedures(config) {
5897
+ const remoteProcs = await cloudPullBlob(
5898
+ "/sync/pull-global-procedures",
5899
+ config
5900
+ );
5901
+ if (!remoteProcs || remoteProcs.length === 0) return { pulled: 0 };
5902
+ const client = getClient();
5903
+ const stmts = remoteProcs.map((p) => ({
5904
+ sql: `INSERT INTO global_procedures
5905
+ (id, title, content, priority, domain, active, created_at, updated_at)
5906
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
5907
+ ON CONFLICT(id) DO UPDATE SET
5908
+ title = excluded.title,
5909
+ content = excluded.content,
5910
+ priority = excluded.priority,
5911
+ domain = excluded.domain,
5912
+ active = excluded.active,
5913
+ updated_at = excluded.updated_at
5914
+ WHERE excluded.updated_at > global_procedures.updated_at`,
5915
+ args: [
5916
+ sqlSafe(p.id),
5917
+ sqlSafe(p.title),
5918
+ sqlSafe(p.content),
5919
+ sqlSafe(p.priority ?? "p0"),
5920
+ sqlSafe(p.domain),
5921
+ sqlSafe(p.active ?? 1),
5922
+ sqlSafe(p.created_at),
5923
+ sqlSafe(p.updated_at)
5924
+ ]
5925
+ }));
5926
+ await client.batch(stmts, "write");
5927
+ return { pulled: remoteProcs.length };
5928
+ }
5929
+ async function cloudPushBehaviors(config) {
5930
+ const client = getClient();
5931
+ const result = await client.execute("SELECT * FROM behaviors LIMIT 10000");
5932
+ const rows = result.rows;
5933
+ const { ok } = await cloudPushBlob(
5934
+ "/sync/push-behaviors",
5935
+ rows,
5936
+ "last_behaviors_push_version",
5937
+ config
5938
+ );
5939
+ return ok;
5940
+ }
5941
+ async function cloudPullBehaviors(config) {
5942
+ const remoteBehaviors = await cloudPullBlob(
5943
+ "/sync/pull-behaviors",
5944
+ config
5945
+ );
5946
+ if (!remoteBehaviors || remoteBehaviors.length === 0) return { pulled: 0 };
5947
+ const client = getClient();
5948
+ let pulled = 0;
5949
+ for (const behavior of remoteBehaviors) {
5950
+ const existing = await client.execute({
5951
+ sql: `SELECT COUNT(*) as cnt FROM behaviors
5952
+ WHERE agent_id = ? AND content = ?`,
5953
+ args: [sqlSafe(behavior.agent_id), sqlSafe(behavior.content)]
5954
+ });
5955
+ if (Number(existing.rows[0]?.cnt) > 0) continue;
5956
+ await client.execute({
5957
+ sql: `INSERT OR IGNORE INTO behaviors
5958
+ (id, agent_id, project_name, domain, content, active, priority, created_at, updated_at)
5959
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5960
+ args: [
5961
+ sqlSafe(behavior.id),
5962
+ sqlSafe(behavior.agent_id),
5963
+ sqlSafe(behavior.project_name),
5964
+ sqlSafe(behavior.domain),
5965
+ sqlSafe(behavior.content),
5966
+ sqlSafe(behavior.active ?? 1),
5967
+ sqlSafe(behavior.priority ?? "p1"),
5968
+ sqlSafe(behavior.created_at),
5969
+ sqlSafe(behavior.updated_at)
5970
+ ]
5971
+ });
5972
+ pulled++;
5973
+ }
5974
+ return { pulled };
5975
+ }
5976
+ async function cloudPushGraphRAG(config) {
5977
+ const client = getClient();
5978
+ const [entities, relationships, aliases, entityMems, relMems, hyperedges, hyperedgeNodes] = await Promise.all([
5979
+ client.execute("SELECT * FROM entities LIMIT 50000"),
5980
+ client.execute("SELECT * FROM relationships LIMIT 50000"),
5981
+ client.execute("SELECT * FROM entity_aliases LIMIT 50000"),
5982
+ client.execute("SELECT * FROM entity_memories LIMIT 50000"),
5983
+ client.execute("SELECT * FROM relationship_memories LIMIT 50000"),
5984
+ client.execute("SELECT * FROM hyperedges LIMIT 50000"),
5985
+ client.execute("SELECT * FROM hyperedge_nodes LIMIT 50000")
5986
+ ]);
5987
+ const blob = {
5988
+ entities: entities.rows,
5989
+ relationships: relationships.rows,
5990
+ entity_aliases: aliases.rows,
5991
+ entity_memories: entityMems.rows,
5992
+ relationship_memories: relMems.rows,
5993
+ hyperedges: hyperedges.rows,
5994
+ hyperedge_nodes: hyperedgeNodes.rows
5995
+ };
5996
+ const { ok } = await cloudPushBlob(
5997
+ "/sync/push-graphrag",
5998
+ [blob],
5999
+ "last_graphrag_push_version",
6000
+ config
6001
+ );
6002
+ return ok;
6003
+ }
6004
+ async function cloudPullGraphRAG(config) {
6005
+ const data = await cloudPullBlob(
6006
+ "/sync/pull-graphrag",
6007
+ config
6008
+ );
6009
+ if (!data || data.length === 0) return { pulled: 0 };
6010
+ const blob = data[0];
6011
+ const client = getClient();
6012
+ let pulled = 0;
6013
+ if (blob.entities.length > 0) {
6014
+ const stmts = blob.entities.map((e) => ({
6015
+ sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen, properties)
6016
+ VALUES (?, ?, ?, ?, ?, ?)`,
6017
+ args: [sqlSafe(e.id), sqlSafe(e.name), sqlSafe(e.type), sqlSafe(e.first_seen), sqlSafe(e.last_seen), sqlSafe(e.properties ?? "{}")]
6018
+ }));
6019
+ await client.batch(stmts, "write");
6020
+ pulled += stmts.length;
6021
+ }
6022
+ if (blob.relationships.length > 0) {
6023
+ const stmts = blob.relationships.map((r) => ({
6024
+ sql: `INSERT OR IGNORE INTO relationships
6025
+ (id, source_entity_id, target_entity_id, type, weight, timestamp, properties, confidence, confidence_label)
6026
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6027
+ args: [
6028
+ sqlSafe(r.id),
6029
+ sqlSafe(r.source_entity_id),
6030
+ sqlSafe(r.target_entity_id),
6031
+ sqlSafe(r.type),
6032
+ sqlSafe(r.weight ?? 1),
6033
+ sqlSafe(r.timestamp),
6034
+ sqlSafe(r.properties ?? "{}"),
6035
+ sqlSafe(r.confidence ?? 1),
6036
+ sqlSafe(r.confidence_label ?? "extracted")
6037
+ ]
6038
+ }));
6039
+ await client.batch(stmts, "write");
6040
+ pulled += stmts.length;
6041
+ }
6042
+ if (blob.entity_aliases.length > 0) {
6043
+ const stmts = blob.entity_aliases.map((a) => ({
6044
+ sql: `INSERT OR IGNORE INTO entity_aliases (alias, canonical_entity_id) VALUES (?, ?)`,
6045
+ args: [sqlSafe(a.alias), sqlSafe(a.canonical_entity_id)]
6046
+ }));
6047
+ await client.batch(stmts, "write");
6048
+ pulled += stmts.length;
6049
+ }
6050
+ if (blob.entity_memories.length > 0) {
6051
+ const stmts = blob.entity_memories.map((em) => ({
6052
+ sql: `INSERT OR IGNORE INTO entity_memories (entity_id, memory_id) VALUES (?, ?)`,
6053
+ args: [sqlSafe(em.entity_id), sqlSafe(em.memory_id)]
6054
+ }));
6055
+ await client.batch(stmts, "write");
6056
+ pulled += stmts.length;
6057
+ }
6058
+ if (blob.relationship_memories.length > 0) {
6059
+ const stmts = blob.relationship_memories.map((rm) => ({
6060
+ sql: `INSERT OR IGNORE INTO relationship_memories (relationship_id, memory_id) VALUES (?, ?)`,
6061
+ args: [sqlSafe(rm.relationship_id), sqlSafe(rm.memory_id)]
6062
+ }));
6063
+ await client.batch(stmts, "write");
6064
+ pulled += stmts.length;
6065
+ }
6066
+ if (blob.hyperedges.length > 0) {
6067
+ const stmts = blob.hyperedges.map((h) => ({
6068
+ sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
6069
+ VALUES (?, ?, ?, ?, ?)`,
6070
+ args: [sqlSafe(h.id), sqlSafe(h.label), sqlSafe(h.relation), sqlSafe(h.confidence ?? 1), sqlSafe(h.timestamp)]
6071
+ }));
6072
+ await client.batch(stmts, "write");
6073
+ pulled += stmts.length;
6074
+ }
6075
+ if (blob.hyperedge_nodes.length > 0) {
6076
+ const stmts = blob.hyperedge_nodes.map((hn) => ({
6077
+ sql: `INSERT OR IGNORE INTO hyperedge_nodes (hyperedge_id, entity_id) VALUES (?, ?)`,
6078
+ args: [sqlSafe(hn.hyperedge_id), sqlSafe(hn.entity_id)]
6079
+ }));
6080
+ await client.batch(stmts, "write");
6081
+ pulled += stmts.length;
6082
+ }
6083
+ return { pulled };
6084
+ }
6085
+ async function cloudPushTasks(config) {
6086
+ const client = getClient();
6087
+ const result = await client.execute("SELECT * FROM tasks LIMIT 10000");
6088
+ const rows = result.rows;
6089
+ const { ok } = await cloudPushBlob(
6090
+ "/sync/push-tasks",
6091
+ rows,
6092
+ "last_tasks_push_version",
6093
+ config
6094
+ );
6095
+ return ok;
6096
+ }
6097
+ async function cloudPullTasks(config) {
6098
+ const remoteTasks = await cloudPullBlob(
6099
+ "/sync/pull-tasks",
6100
+ config
6101
+ );
6102
+ if (!remoteTasks || remoteTasks.length === 0) return { pulled: 0 };
6103
+ const client = getClient();
6104
+ const stmts = remoteTasks.map((t) => ({
6105
+ sql: `INSERT OR IGNORE INTO tasks
6106
+ (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, created_at, updated_at,
6107
+ blocked_by, parent_task_id, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at)
6108
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6109
+ args: [
6110
+ sqlSafe(t.id),
6111
+ sqlSafe(t.title),
6112
+ sqlSafe(t.assigned_to),
6113
+ sqlSafe(t.assigned_by),
6114
+ sqlSafe(t.project_name),
6115
+ sqlSafe(t.priority ?? "p1"),
6116
+ sqlSafe(t.status ?? "open"),
6117
+ sqlSafe(t.task_file),
6118
+ sqlSafe(t.created_at),
6119
+ sqlSafe(t.updated_at),
6120
+ sqlSafe(t.blocked_by),
6121
+ sqlSafe(t.parent_task_id),
6122
+ sqlSafe(t.budget_tokens),
6123
+ sqlSafe(t.budget_fallback_model),
6124
+ sqlSafe(t.tokens_used ?? 0),
6125
+ sqlSafe(t.tokens_warned_at)
6126
+ ]
6127
+ }));
6128
+ await client.batch(stmts, "write");
6129
+ return { pulled: remoteTasks.length };
6130
+ }
6131
+ async function cloudPushConversations(config) {
6132
+ const client = getClient();
6133
+ const result = await client.execute("SELECT * FROM conversations LIMIT 50000");
6134
+ const rows = result.rows;
6135
+ const { ok } = await cloudPushBlob(
6136
+ "/sync/push-conversations",
6137
+ rows,
6138
+ "last_conversations_push_version",
6139
+ config
6140
+ );
6141
+ return ok;
6142
+ }
6143
+ async function cloudPullConversations(config) {
6144
+ const remoteConvos = await cloudPullBlob(
6145
+ "/sync/pull-conversations",
6146
+ config
6147
+ );
6148
+ if (!remoteConvos || remoteConvos.length === 0) return { pulled: 0 };
6149
+ const client = getClient();
6150
+ const stmts = remoteConvos.map((c) => ({
6151
+ sql: `INSERT OR IGNORE INTO conversations
6152
+ (id, platform, external_id, sender_id, sender_name, sender_phone, sender_email,
6153
+ recipient_id, channel_id, thread_id, reply_to_id, content_text, content_media,
6154
+ content_metadata, agent_response, agent_name, timestamp, ingested_at)
6155
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6156
+ args: [
6157
+ sqlSafe(c.id),
6158
+ sqlSafe(c.platform),
6159
+ sqlSafe(c.external_id),
6160
+ sqlSafe(c.sender_id),
6161
+ sqlSafe(c.sender_name),
6162
+ sqlSafe(c.sender_phone),
6163
+ sqlSafe(c.sender_email),
6164
+ sqlSafe(c.recipient_id),
6165
+ sqlSafe(c.channel_id),
6166
+ sqlSafe(c.thread_id),
6167
+ sqlSafe(c.reply_to_id),
6168
+ sqlSafe(c.content_text),
6169
+ sqlSafe(c.content_media),
6170
+ sqlSafe(c.content_metadata),
6171
+ sqlSafe(c.agent_response),
6172
+ sqlSafe(c.agent_name),
6173
+ sqlSafe(c.timestamp),
6174
+ sqlSafe(c.ingested_at)
6175
+ ]
6176
+ }));
6177
+ await client.batch(stmts, "write");
6178
+ return { pulled: remoteConvos.length };
6179
+ }
6180
+ async function cloudPushDocuments(config) {
6181
+ const client = getClient();
6182
+ const [workspaces, documents] = await Promise.all([
6183
+ client.execute("SELECT * FROM workspaces LIMIT 1000"),
6184
+ client.execute("SELECT * FROM documents LIMIT 10000")
6185
+ ]);
6186
+ const blob = {
6187
+ workspaces: workspaces.rows,
6188
+ documents: documents.rows
6189
+ };
6190
+ const { ok } = await cloudPushBlob(
6191
+ "/sync/push-documents",
6192
+ [blob],
6193
+ "last_documents_push_version",
6194
+ config
6195
+ );
6196
+ return ok;
6197
+ }
6198
+ async function cloudPullDocuments(config) {
6199
+ const data = await cloudPullBlob(
6200
+ "/sync/pull-documents",
6201
+ config
6202
+ );
6203
+ if (!data || data.length === 0) return { pulled: 0 };
6204
+ const blob = data[0];
6205
+ const client = getClient();
6206
+ let pulled = 0;
6207
+ if (blob.workspaces.length > 0) {
6208
+ const stmts = blob.workspaces.map((w) => ({
6209
+ sql: `INSERT OR IGNORE INTO workspaces (id, slug, name, owner_agent_id, created_at, metadata)
6210
+ VALUES (?, ?, ?, ?, ?, ?)`,
6211
+ args: [sqlSafe(w.id), sqlSafe(w.slug), sqlSafe(w.name), sqlSafe(w.owner_agent_id), sqlSafe(w.created_at), sqlSafe(w.metadata)]
6212
+ }));
6213
+ await client.batch(stmts, "write");
6214
+ pulled += stmts.length;
6215
+ }
6216
+ if (blob.documents.length > 0) {
6217
+ const stmts = blob.documents.map((d) => ({
6218
+ sql: `INSERT OR IGNORE INTO documents
6219
+ (id, workspace_id, filename, mime, source_type, user_id, uploaded_at, metadata)
6220
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
6221
+ args: [
6222
+ sqlSafe(d.id),
6223
+ sqlSafe(d.workspace_id),
6224
+ sqlSafe(d.filename),
6225
+ sqlSafe(d.mime),
6226
+ sqlSafe(d.source_type),
6227
+ sqlSafe(d.user_id),
6228
+ sqlSafe(d.uploaded_at),
6229
+ sqlSafe(d.metadata)
6230
+ ]
6231
+ }));
6232
+ await client.batch(stmts, "write");
6233
+ pulled += stmts.length;
6234
+ }
6235
+ return { pulled };
6236
+ }
6237
+ var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
6238
+ var init_cloud_sync = __esm({
6239
+ "src/lib/cloud-sync.ts"() {
6240
+ "use strict";
6241
+ init_database();
6242
+ init_crypto();
6243
+ init_compress();
6244
+ init_license();
6245
+ init_config();
6246
+ init_employees();
6247
+ LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
6248
+ FETCH_TIMEOUT_MS = 3e4;
6249
+ PUSH_BATCH_SIZE = 5e3;
6250
+ ROSTER_LOCK_PATH = path12.join(EXE_AI_DIR, "roster-merge.lock");
6251
+ LOCK_STALE_MS = 3e4;
6252
+ ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
6253
+ }
6254
+ });
6255
+
5191
6256
  // src/lib/identity.ts
5192
6257
  var identity_exports = {};
5193
6258
  __export(identity_exports, {
@@ -5197,17 +6262,17 @@ __export(identity_exports, {
5197
6262
  listIdentities: () => listIdentities,
5198
6263
  updateIdentity: () => updateIdentity
5199
6264
  });
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";
6265
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
6266
+ import { readdirSync as readdirSync3 } from "fs";
6267
+ import path13 from "path";
5203
6268
  import { createHash as createHash2 } from "crypto";
5204
6269
  function ensureDir() {
5205
- if (!existsSync11(IDENTITY_DIR)) {
5206
- mkdirSync5(IDENTITY_DIR, { recursive: true });
6270
+ if (!existsSync12(IDENTITY_DIR)) {
6271
+ mkdirSync6(IDENTITY_DIR, { recursive: true });
5207
6272
  }
5208
6273
  }
5209
6274
  function identityPath(agentId) {
5210
- return path12.join(IDENTITY_DIR, `${agentId}.md`);
6275
+ return path13.join(IDENTITY_DIR, `${agentId}.md`);
5211
6276
  }
5212
6277
  function parseFrontmatter(raw) {
5213
6278
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -5248,8 +6313,8 @@ function contentHash(content) {
5248
6313
  }
5249
6314
  function getIdentity(agentId) {
5250
6315
  const filePath = identityPath(agentId);
5251
- if (!existsSync11(filePath)) return null;
5252
- const raw = readFileSync7(filePath, "utf-8");
6316
+ if (!existsSync12(filePath)) return null;
6317
+ const raw = readFileSync8(filePath, "utf-8");
5253
6318
  const { frontmatter, body } = parseFrontmatter(raw);
5254
6319
  return {
5255
6320
  agentId,
@@ -5263,7 +6328,7 @@ async function updateIdentity(agentId, content, updatedBy) {
5263
6328
  ensureDir();
5264
6329
  const filePath = identityPath(agentId);
5265
6330
  const hash = contentHash(content);
5266
- writeFileSync4(filePath, content, "utf-8");
6331
+ writeFileSync5(filePath, content, "utf-8");
5267
6332
  try {
5268
6333
  const client = getClient();
5269
6334
  await client.execute({
@@ -5280,7 +6345,7 @@ async function updateIdentity(agentId, content, updatedBy) {
5280
6345
  }
5281
6346
  function listIdentities() {
5282
6347
  ensureDir();
5283
- const files = readdirSync2(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
6348
+ const files = readdirSync3(IDENTITY_DIR).filter((f) => f.endsWith(".md"));
5284
6349
  const results = [];
5285
6350
  for (const file of files) {
5286
6351
  const agentId = file.replace(".md", "");
@@ -5319,7 +6384,7 @@ var init_identity = __esm({
5319
6384
  "use strict";
5320
6385
  init_config();
5321
6386
  init_database();
5322
- IDENTITY_DIR = path12.join(EXE_AI_DIR, "identity");
6387
+ IDENTITY_DIR = path13.join(EXE_AI_DIR, "identity");
5323
6388
  }
5324
6389
  });
5325
6390
 
@@ -5853,31 +6918,162 @@ ${PLAN_MODE_COMPAT}
5853
6918
  }
5854
6919
  });
5855
6920
 
6921
+ // src/lib/session-wrappers.ts
6922
+ var session_wrappers_exports = {};
6923
+ __export(session_wrappers_exports, {
6924
+ generateSessionWrappers: () => generateSessionWrappers
6925
+ });
6926
+ import {
6927
+ existsSync as existsSync13,
6928
+ readFileSync as readFileSync9,
6929
+ writeFileSync as writeFileSync6,
6930
+ mkdirSync as mkdirSync7,
6931
+ chmodSync,
6932
+ readdirSync as readdirSync4,
6933
+ unlinkSync as unlinkSync5
6934
+ } from "fs";
6935
+ import path14 from "path";
6936
+ import { homedir as homedir4 } from "os";
6937
+ function generateSessionWrappers(packageRoot, homeDir) {
6938
+ const home = homeDir ?? homedir4();
6939
+ const binDir = path14.join(home, ".exe-os", "bin");
6940
+ const rosterPath = path14.join(home, ".exe-os", "exe-employees.json");
6941
+ mkdirSync7(binDir, { recursive: true });
6942
+ const exeStartDst = path14.join(binDir, "exe-start");
6943
+ const candidates = [
6944
+ path14.join(packageRoot, "dist", "bin", "exe-start.sh"),
6945
+ path14.join(packageRoot, "src", "bin", "exe-start.sh")
6946
+ ];
6947
+ for (const src of candidates) {
6948
+ if (existsSync13(src)) {
6949
+ writeFileSync6(exeStartDst, readFileSync9(src));
6950
+ chmodSync(exeStartDst, 493);
6951
+ break;
6952
+ }
6953
+ }
6954
+ let employees = [];
6955
+ try {
6956
+ employees = JSON.parse(readFileSync9(rosterPath, "utf8"));
6957
+ } catch {
6958
+ return { created: 0, pathConfigured: false };
6959
+ }
6960
+ if (employees.length === 0) {
6961
+ return { created: 0, pathConfigured: false };
6962
+ }
6963
+ try {
6964
+ for (const f of readdirSync4(binDir)) {
6965
+ if (f === "exe-start") continue;
6966
+ const fPath = path14.join(binDir, f);
6967
+ try {
6968
+ const content = readFileSync9(fPath, "utf8");
6969
+ if (content.includes("exe-start")) {
6970
+ unlinkSync5(fPath);
6971
+ }
6972
+ } catch {
6973
+ }
6974
+ }
6975
+ } catch {
6976
+ }
6977
+ let created = 0;
6978
+ const wrapperContent = `#!/bin/bash
6979
+ exec "${exeStartDst}" "$0" "$@"
6980
+ `;
6981
+ for (const emp of employees) {
6982
+ for (let n = 1; n <= MAX_N; n++) {
6983
+ const wrapperPath = path14.join(binDir, `${emp.name}${n}`);
6984
+ writeFileSync6(wrapperPath, wrapperContent);
6985
+ chmodSync(wrapperPath, 493);
6986
+ created++;
6987
+ }
6988
+ }
6989
+ const pathConfigured = ensurePath(home, binDir);
6990
+ return { created, pathConfigured };
6991
+ }
6992
+ function ensurePath(home, binDir) {
6993
+ if (process.env.PATH?.split(":").includes(binDir)) {
6994
+ return false;
6995
+ }
6996
+ const exportLine = `
6997
+ # exe-os session commands
6998
+ export PATH="${binDir}:$PATH"
6999
+ `;
7000
+ const shell = process.env.SHELL ?? "/bin/bash";
7001
+ const profilePaths = [];
7002
+ if (shell.includes("zsh")) {
7003
+ profilePaths.push(path14.join(home, ".zshrc"));
7004
+ } else if (shell.includes("bash")) {
7005
+ profilePaths.push(path14.join(home, ".bashrc"));
7006
+ profilePaths.push(path14.join(home, ".bash_profile"));
7007
+ } else {
7008
+ profilePaths.push(path14.join(home, ".profile"));
7009
+ }
7010
+ for (const profilePath of profilePaths) {
7011
+ try {
7012
+ let content = "";
7013
+ try {
7014
+ content = readFileSync9(profilePath, "utf8");
7015
+ } catch {
7016
+ }
7017
+ if (content.includes(".exe-os/bin")) {
7018
+ return false;
7019
+ }
7020
+ writeFileSync6(profilePath, content + exportLine);
7021
+ return true;
7022
+ } catch {
7023
+ continue;
7024
+ }
7025
+ }
7026
+ return false;
7027
+ }
7028
+ var MAX_N;
7029
+ var init_session_wrappers = __esm({
7030
+ "src/lib/session-wrappers.ts"() {
7031
+ "use strict";
7032
+ MAX_N = 9;
7033
+ }
7034
+ });
7035
+
5856
7036
  // src/lib/setup-wizard.ts
5857
7037
  var setup_wizard_exports = {};
5858
7038
  __export(setup_wizard_exports, {
5859
7039
  runSetupWizard: () => runSetupWizard,
5860
7040
  validateModel: () => validateModel
5861
7041
  });
5862
- import crypto3 from "crypto";
5863
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4 } from "fs";
7042
+ import crypto5 from "crypto";
7043
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync7, unlinkSync as unlinkSync6 } from "fs";
5864
7044
  import os5 from "os";
5865
- import path13 from "path";
7045
+ import path15 from "path";
5866
7046
  import { createInterface as createInterface2 } from "readline";
7047
+ function findPackageRoot2() {
7048
+ let dir = path15.dirname(new URL(import.meta.url).pathname);
7049
+ const root = path15.parse(dir).root;
7050
+ while (dir !== root) {
7051
+ const pkgPath = path15.join(dir, "package.json");
7052
+ if (existsSync14(pkgPath)) {
7053
+ try {
7054
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
7055
+ if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
7056
+ } catch {
7057
+ }
7058
+ }
7059
+ dir = path15.dirname(dir);
7060
+ }
7061
+ return null;
7062
+ }
5867
7063
  function loadSetupState() {
5868
7064
  try {
5869
- return JSON.parse(readFileSync8(SETUP_STATE_PATH, "utf8"));
7065
+ return JSON.parse(readFileSync10(SETUP_STATE_PATH, "utf8"));
5870
7066
  } catch {
5871
7067
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
5872
7068
  }
5873
7069
  }
5874
7070
  function saveSetupState(state) {
5875
- mkdirSync6(path13.dirname(SETUP_STATE_PATH), { recursive: true });
5876
- writeFileSync5(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7071
+ mkdirSync8(path15.dirname(SETUP_STATE_PATH), { recursive: true });
7072
+ writeFileSync7(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
5877
7073
  }
5878
7074
  function clearSetupState() {
5879
7075
  try {
5880
- unlinkSync4(SETUP_STATE_PATH);
7076
+ unlinkSync6(SETUP_STATE_PATH);
5881
7077
  } catch {
5882
7078
  }
5883
7079
  }
@@ -5911,20 +7107,67 @@ async function runSetupWizard(opts = {}) {
5911
7107
  log("");
5912
7108
  log("=== exe-os Setup ===");
5913
7109
  log("");
5914
- log("Already set up on another device?");
5915
- log(" Run `exe-link` to sync your encryption key and skip setup.");
7110
+ log("Is this a new installation or pairing with an existing device?");
5916
7111
  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;
7112
+ log(" [1] New installation (first device)");
7113
+ log(" [2] Pair with existing device (I have a 24-word phrase)");
7114
+ log("");
7115
+ const installType = await ask(rl, "Choice (1/2): ");
7116
+ let isPairing = false;
7117
+ let pairingRosterPulled = false;
7118
+ if (installType === "2") {
7119
+ isPairing = true;
7120
+ log("");
7121
+ const { importMnemonic: importMnemonic2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
7122
+ const mnemonic = await ask(rl, "Paste your 24-word recovery phrase: ");
7123
+ try {
7124
+ const key = importMnemonic2(mnemonic);
7125
+ await setMasterKey(key);
7126
+ log("Master key imported and stored securely.");
7127
+ log("");
7128
+ log("Enter the API key from your existing device.");
7129
+ log("(Find it in ~/.exe-os/config.json under cloud.apiKey, or ask your team lead.)");
7130
+ log("");
7131
+ const apiKey = await ask(rl, "API key (exe_sk_...): ");
7132
+ if (apiKey && apiKey.startsWith("exe_sk_")) {
7133
+ const cloudEndpoint = "https://askexe.com/cloud";
7134
+ const cloudCfg = { apiKey, endpoint: cloudEndpoint };
7135
+ const earlyConfig = await loadConfig();
7136
+ earlyConfig.cloud = cloudCfg;
7137
+ await saveConfig(earlyConfig);
7138
+ const { saveLicense: saveLic, mirrorLicenseKey: mirrorLic } = await Promise.resolve().then(() => (init_license(), license_exports));
7139
+ saveLic(apiKey);
7140
+ mirrorLic(apiKey);
7141
+ log("Cloud sync configured.");
7142
+ try {
7143
+ const { initSyncCrypto: initSyncCrypto2 } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
7144
+ const { cloudPullRoster: cloudPullRoster2 } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
7145
+ initSyncCrypto2(key);
7146
+ const result = await cloudPullRoster2({ apiKey, endpoint: cloudEndpoint });
7147
+ if (result.added > 0) {
7148
+ log(`Pulled ${result.added} employee(s) from Exe Cloud.`);
7149
+ pairingRosterPulled = true;
7150
+ }
7151
+ } catch {
7152
+ log("Could not pull roster from cloud \u2014 you can set up employees manually.");
7153
+ }
7154
+ } else {
7155
+ log("No API key provided \u2014 cloud sync will need to be configured later.");
7156
+ log("Run /exe-cloud after setup to connect.");
7157
+ }
7158
+ log("");
7159
+ } catch (err) {
7160
+ log(`Key import failed: ${err instanceof Error ? err.message : String(err)}`);
7161
+ log("Check your phrase and try again, or choose option 1 for a fresh install.");
7162
+ rl.close();
7163
+ return;
7164
+ }
5922
7165
  }
5923
7166
  const state = loadSetupState();
5924
7167
  if (state.completedSteps.length > 0) {
5925
7168
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
5926
7169
  }
5927
- if (existsSync12(LEGACY_LANCE_PATH)) {
7170
+ if (existsSync14(LEGACY_LANCE_PATH)) {
5928
7171
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
5929
7172
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
5930
7173
  log(" The old directory will not be modified or deleted.");
@@ -5936,7 +7179,7 @@ async function runSetupWizard(opts = {}) {
5936
7179
  log("Encryption key already exists \u2014 skipping generation.");
5937
7180
  } else {
5938
7181
  log("Generating 256-bit encryption key...");
5939
- const key = crypto3.randomBytes(32);
7182
+ const key = crypto5.randomBytes(32);
5940
7183
  await setMasterKey(key);
5941
7184
  log("Encryption key generated and stored securely.");
5942
7185
  }
@@ -5947,7 +7190,15 @@ async function runSetupWizard(opts = {}) {
5947
7190
  }
5948
7191
  log("");
5949
7192
  let cloudConfig;
5950
- if (!state.completedSteps.includes(2)) {
7193
+ if (isPairing) {
7194
+ const pairingConfig = await loadConfig();
7195
+ if (pairingConfig.cloud?.apiKey) {
7196
+ cloudConfig = pairingConfig.cloud;
7197
+ log("Cloud sync: using shared API key from pairing.");
7198
+ }
7199
+ state.completedSteps.push(2);
7200
+ saveSetupState(state);
7201
+ } else if (!state.completedSteps.includes(2)) {
5951
7202
  log("Exe Cloud: your memories are end-to-end encrypted, compressed, and");
5952
7203
  log("backed up on Exe Cloud. Free for all plans. We can't read your data \u2014");
5953
7204
  log("only your encryption key can decrypt it.");
@@ -6028,10 +7279,10 @@ async function runSetupWizard(opts = {}) {
6028
7279
  await saveConfig(config);
6029
7280
  log("");
6030
7281
  try {
6031
- const claudeJsonPath = path13.join(os5.homedir(), ".claude.json");
7282
+ const claudeJsonPath = path15.join(os5.homedir(), ".claude.json");
6032
7283
  let claudeJson = {};
6033
7284
  try {
6034
- claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
7285
+ claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
6035
7286
  } catch {
6036
7287
  }
6037
7288
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -6040,7 +7291,7 @@ async function runSetupWizard(opts = {}) {
6040
7291
  if (!projects[dir]) projects[dir] = {};
6041
7292
  projects[dir].hasTrustDialogAccepted = true;
6042
7293
  }
6043
- writeFileSync5(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7294
+ writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6044
7295
  } catch {
6045
7296
  }
6046
7297
  state.completedSteps.push(5);
@@ -6066,7 +7317,34 @@ async function runSetupWizard(opts = {}) {
6066
7317
  } = await Promise.resolve().then(() => (init_license(), license_exports));
6067
7318
  const createdEmployees = [];
6068
7319
  let cooName = "exe";
6069
- if (!state.completedSteps.includes(6)) {
7320
+ if (pairingRosterPulled) {
7321
+ const roster = await loadEmployees2(EMPLOYEES_PATH2).catch(() => []);
7322
+ const existingCoo = roster.find((e) => e.role === "COO");
7323
+ if (existingCoo) {
7324
+ cooName = existingCoo.name;
7325
+ log(`Team synced from cloud. COO: ${cooName}`);
7326
+ const teamList = roster.map((e) => `${e.name} (${e.role})`).join(", ");
7327
+ log(`Team: ${teamList}`);
7328
+ createdEmployees.push(...roster.map((e) => ({ name: e.name, role: e.role })));
7329
+ }
7330
+ for (const emp of roster) {
7331
+ registerBinSymlinks2(emp.name);
7332
+ }
7333
+ try {
7334
+ const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
7335
+ const pkgRoot = findPackageRoot2();
7336
+ if (pkgRoot) {
7337
+ const wrapResult = generateSessionWrappers2(pkgRoot);
7338
+ if (wrapResult.created > 0) {
7339
+ log(`Session shortcuts generated: ${roster.map((e) => `${e.name}1`).join(", ")}, ...`);
7340
+ }
7341
+ }
7342
+ } catch {
7343
+ }
7344
+ state.completedSteps.push(6, 7, 8);
7345
+ saveSetupState(state);
7346
+ log("");
7347
+ } else if (!state.completedSteps.includes(6)) {
6070
7348
  log("=== Your Team ===");
6071
7349
  log("");
6072
7350
  log("Every install starts with a COO \u2014 your right-hand operator.");
@@ -6092,9 +7370,9 @@ async function runSetupWizard(opts = {}) {
6092
7370
  const cooIdentityContent = getIdentityTemplate("coo");
6093
7371
  if (cooIdentityContent) {
6094
7372
  const cooIdPath = identityPath2(cooName);
6095
- mkdirSync6(path13.dirname(cooIdPath), { recursive: true });
7373
+ mkdirSync8(path15.dirname(cooIdPath), { recursive: true });
6096
7374
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
6097
- writeFileSync5(cooIdPath, replaced, "utf-8");
7375
+ writeFileSync7(cooIdPath, replaced, "utf-8");
6098
7376
  }
6099
7377
  registerBinSymlinks2(cooName);
6100
7378
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -6193,9 +7471,9 @@ async function runSetupWizard(opts = {}) {
6193
7471
  const ctoIdentityContent = getIdentityTemplate("cto");
6194
7472
  if (ctoIdentityContent) {
6195
7473
  const ctoIdPath = identityPath2(ctoName);
6196
- mkdirSync6(path13.dirname(ctoIdPath), { recursive: true });
7474
+ mkdirSync8(path15.dirname(ctoIdPath), { recursive: true });
6197
7475
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
6198
- writeFileSync5(ctoIdPath, replaced, "utf-8");
7476
+ writeFileSync7(ctoIdPath, replaced, "utf-8");
6199
7477
  }
6200
7478
  registerBinSymlinks2(ctoName);
6201
7479
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -6221,9 +7499,9 @@ async function runSetupWizard(opts = {}) {
6221
7499
  const cmoIdentityContent = getIdentityTemplate("cmo");
6222
7500
  if (cmoIdentityContent) {
6223
7501
  const cmoIdPath = identityPath2(cmoName);
6224
- mkdirSync6(path13.dirname(cmoIdPath), { recursive: true });
7502
+ mkdirSync8(path15.dirname(cmoIdPath), { recursive: true });
6225
7503
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
6226
- writeFileSync5(cmoIdPath, replaced, "utf-8");
7504
+ writeFileSync7(cmoIdPath, replaced, "utf-8");
6227
7505
  }
6228
7506
  registerBinSymlinks2(cmoName);
6229
7507
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -6236,11 +7514,24 @@ async function runSetupWizard(opts = {}) {
6236
7514
  } else {
6237
7515
  log("Step 8 already complete \u2014 skipping.");
6238
7516
  }
7517
+ if (!pairingRosterPulled) {
7518
+ try {
7519
+ const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
7520
+ const pkgRoot = findPackageRoot2();
7521
+ if (pkgRoot) {
7522
+ const wrapResult = generateSessionWrappers2(pkgRoot);
7523
+ if (wrapResult.created > 0) {
7524
+ log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
7525
+ }
7526
+ }
7527
+ } catch {
7528
+ }
7529
+ }
6239
7530
  clearSetupState();
6240
7531
  log("=== Two Ways to Work ===");
6241
7532
  log("");
6242
7533
  log(" 1. Claude Code mode");
6243
- log(` Type \`${cooName}\` in your terminal. Works with your Claude Code subscription.`);
7534
+ log(` Type \`${cooName}1\` in your project folder. Works with your Claude Code subscription.`);
6244
7535
  log(" Best for developers who live in the terminal.");
6245
7536
  log("");
6246
7537
  log(" 2. Dashboard mode");
@@ -6250,8 +7541,6 @@ async function runSetupWizard(opts = {}) {
6250
7541
  log(" Both modes share the same memory, employees, and data.");
6251
7542
  log(" You can switch anytime.");
6252
7543
  log("");
6253
- log(" For Claude Code mode, run: exe-os claude");
6254
- log("");
6255
7544
  log("=== Setup Complete ===");
6256
7545
  log("Database: " + config.dbPath);
6257
7546
  if (cloudConfig) {
@@ -6267,7 +7556,7 @@ async function runSetupWizard(opts = {}) {
6267
7556
  log("Team: " + createdEmployees.map((e) => `${e.name} (${e.role})`).join(", "));
6268
7557
  }
6269
7558
  log("");
6270
- log(`Type \`${cooName}\` to start (Claude Code) or \`exe-os\` for dashboard.`);
7559
+ log(`Type \`${cooName}1\` to start (Claude Code) or \`exe-os\` for dashboard.`);
6271
7560
  log("");
6272
7561
  } finally {
6273
7562
  rl.close();
@@ -6280,17 +7569,17 @@ var init_setup_wizard = __esm({
6280
7569
  init_config();
6281
7570
  init_keychain();
6282
7571
  init_model_downloader();
6283
- SETUP_STATE_PATH = path13.join(os5.homedir(), ".exe-os", "setup-state.json");
7572
+ SETUP_STATE_PATH = path15.join(os5.homedir(), ".exe-os", "setup-state.json");
6284
7573
  }
6285
7574
  });
6286
7575
 
6287
7576
  // src/lib/update-check.ts
6288
7577
  import { execSync as execSync4 } from "child_process";
6289
- import { readFileSync as readFileSync9 } from "fs";
6290
- import path14 from "path";
7578
+ import { readFileSync as readFileSync11 } from "fs";
7579
+ import path16 from "path";
6291
7580
  function getLocalVersion(packageRoot) {
6292
- const pkgPath = path14.join(packageRoot, "package.json");
6293
- const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
7581
+ const pkgPath = path16.join(packageRoot, "package.json");
7582
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
6294
7583
  return pkg.version;
6295
7584
  }
6296
7585
  function getRemoteVersion() {
@@ -7925,7 +9214,7 @@ var init_yoga_wasm_base64_esm = __esm({
7925
9214
  });
7926
9215
 
7927
9216
  // 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;
9217
+ var Align, BoxSizing, Dimension, Direction, Display, Edge, Errata, ExperimentalFeature, FlexDirection, Gutter, Justify, LogLevel, MeasureMode, NodeType, Overflow, PositionType, Unit, Wrap, constants2, YGEnums_default;
7929
9218
  var init_YGEnums = __esm({
7930
9219
  "node_modules/yoga-layout/dist/src/generated/YGEnums.js"() {
7931
9220
  "use strict";
@@ -8055,7 +9344,7 @@ var init_YGEnums = __esm({
8055
9344
  Wrap2[Wrap2["WrapReverse"] = 2] = "WrapReverse";
8056
9345
  return Wrap2;
8057
9346
  })({});
8058
- constants = {
9347
+ constants2 = {
8059
9348
  ALIGN_AUTO: Align.Auto,
8060
9349
  ALIGN_FLEX_START: Align.FlexStart,
8061
9350
  ALIGN_CENTER: Align.Center,
@@ -8129,7 +9418,7 @@ var init_YGEnums = __esm({
8129
9418
  WRAP_WRAP: Wrap.Wrap,
8130
9419
  WRAP_WRAP_REVERSE: Wrap.WrapReverse
8131
9420
  };
8132
- YGEnums_default = constants;
9421
+ YGEnums_default = constants2;
8133
9422
  }
8134
9423
  });
8135
9424
 
@@ -10813,8 +12102,8 @@ var init_ErrorOverview = __esm({
10813
12102
  "use strict";
10814
12103
  init_Box();
10815
12104
  init_Text();
10816
- cleanupPath = (path34) => {
10817
- return path34?.replace(`file://${cwd()}/`, "");
12105
+ cleanupPath = (path36) => {
12106
+ return path36?.replace(`file://${cwd()}/`, "");
10818
12107
  };
10819
12108
  stackUtils = new StackUtils({
10820
12109
  cwd: cwd(),
@@ -12843,14 +14132,14 @@ __export(session_registry_exports, {
12843
14132
  pruneStaleSessions: () => pruneStaleSessions,
12844
14133
  registerSession: () => registerSession
12845
14134
  });
12846
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, existsSync as existsSync14 } from "fs";
14135
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, existsSync as existsSync16 } from "fs";
12847
14136
  import { execSync as execSync6 } from "child_process";
12848
- import path15 from "path";
14137
+ import path17 from "path";
12849
14138
  import os6 from "os";
12850
14139
  function registerSession(entry) {
12851
- const dir = path15.dirname(REGISTRY_PATH);
12852
- if (!existsSync14(dir)) {
12853
- mkdirSync7(dir, { recursive: true });
14140
+ const dir = path17.dirname(REGISTRY_PATH);
14141
+ if (!existsSync16(dir)) {
14142
+ mkdirSync9(dir, { recursive: true });
12854
14143
  }
12855
14144
  const sessions = listSessions();
12856
14145
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -12859,11 +14148,11 @@ function registerSession(entry) {
12859
14148
  } else {
12860
14149
  sessions.push(entry);
12861
14150
  }
12862
- writeFileSync6(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
14151
+ writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
12863
14152
  }
12864
14153
  function listSessions() {
12865
14154
  try {
12866
- const raw = readFileSync11(REGISTRY_PATH, "utf8");
14155
+ const raw = readFileSync13(REGISTRY_PATH, "utf8");
12867
14156
  return JSON.parse(raw);
12868
14157
  } catch {
12869
14158
  return [];
@@ -12884,7 +14173,7 @@ function pruneStaleSessions() {
12884
14173
  const alive = sessions.filter((s) => liveSet.has(s.windowName));
12885
14174
  const pruned = sessions.length - alive.length;
12886
14175
  if (pruned > 0) {
12887
- writeFileSync6(REGISTRY_PATH, JSON.stringify(alive, null, 2));
14176
+ writeFileSync8(REGISTRY_PATH, JSON.stringify(alive, null, 2));
12888
14177
  }
12889
14178
  return pruned;
12890
14179
  }
@@ -12892,7 +14181,7 @@ var REGISTRY_PATH;
12892
14181
  var init_session_registry = __esm({
12893
14182
  "src/lib/session-registry.ts"() {
12894
14183
  "use strict";
12895
- REGISTRY_PATH = path15.join(os6.homedir(), ".exe-os", "session-registry.json");
14184
+ REGISTRY_PATH = path17.join(os6.homedir(), ".exe-os", "session-registry.json");
12896
14185
  }
12897
14186
  });
12898
14187
 
@@ -13097,17 +14386,17 @@ var init_provider_table = __esm({
13097
14386
  });
13098
14387
 
13099
14388
  // 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";
14389
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, renameSync as renameSync4, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
14390
+ import path18 from "path";
13102
14391
  import os7 from "os";
13103
14392
  function ensureDir2() {
13104
- const dir = path16.dirname(QUEUE_PATH);
13105
- if (!existsSync15(dir)) mkdirSync8(dir, { recursive: true });
14393
+ const dir = path18.dirname(QUEUE_PATH);
14394
+ if (!existsSync17(dir)) mkdirSync10(dir, { recursive: true });
13106
14395
  }
13107
14396
  function readQueue() {
13108
14397
  try {
13109
- if (!existsSync15(QUEUE_PATH)) return [];
13110
- return JSON.parse(readFileSync12(QUEUE_PATH, "utf8"));
14398
+ if (!existsSync17(QUEUE_PATH)) return [];
14399
+ return JSON.parse(readFileSync14(QUEUE_PATH, "utf8"));
13111
14400
  } catch {
13112
14401
  return [];
13113
14402
  }
@@ -13115,7 +14404,7 @@ function readQueue() {
13115
14404
  function writeQueue(queue) {
13116
14405
  ensureDir2();
13117
14406
  const tmp = `${QUEUE_PATH}.tmp`;
13118
- writeFileSync7(tmp, JSON.stringify(queue, null, 2));
14407
+ writeFileSync9(tmp, JSON.stringify(queue, null, 2));
13119
14408
  renameSync4(tmp, QUEUE_PATH);
13120
14409
  }
13121
14410
  function queueIntercom(targetSession, reason) {
@@ -13139,19 +14428,19 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
13139
14428
  var init_intercom_queue = __esm({
13140
14429
  "src/lib/intercom-queue.ts"() {
13141
14430
  "use strict";
13142
- QUEUE_PATH = path16.join(os7.homedir(), ".exe-os", "intercom-queue.json");
14431
+ QUEUE_PATH = path18.join(os7.homedir(), ".exe-os", "intercom-queue.json");
13143
14432
  TTL_MS = 60 * 60 * 1e3;
13144
- INTERCOM_LOG = path16.join(os7.homedir(), ".exe-os", "intercom.log");
14433
+ INTERCOM_LOG = path18.join(os7.homedir(), ".exe-os", "intercom.log");
13145
14434
  }
13146
14435
  });
13147
14436
 
13148
14437
  // src/lib/plan-limits.ts
13149
- import { readFileSync as readFileSync13, existsSync as existsSync16 } from "fs";
13150
- import path17 from "path";
14438
+ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
14439
+ import path19 from "path";
13151
14440
  function getLicenseSync() {
13152
14441
  try {
13153
- if (!existsSync16(CACHE_PATH2)) return freeLicense();
13154
- const raw = JSON.parse(readFileSync13(CACHE_PATH2, "utf8"));
14442
+ if (!existsSync18(CACHE_PATH2)) return freeLicense();
14443
+ const raw = JSON.parse(readFileSync15(CACHE_PATH2, "utf8"));
13155
14444
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
13156
14445
  const parts = raw.token.split(".");
13157
14446
  if (parts.length !== 3) return freeLicense();
@@ -13189,8 +14478,8 @@ function assertEmployeeLimitSync(rosterPath) {
13189
14478
  const filePath = rosterPath ?? EMPLOYEES_PATH;
13190
14479
  let count = 0;
13191
14480
  try {
13192
- if (existsSync16(filePath)) {
13193
- const raw = readFileSync13(filePath, "utf8");
14481
+ if (existsSync18(filePath)) {
14482
+ const raw = readFileSync15(filePath, "utf8");
13194
14483
  const employees = JSON.parse(raw);
13195
14484
  count = Array.isArray(employees) ? employees.length : 0;
13196
14485
  }
@@ -13219,25 +14508,25 @@ var init_plan_limits = __esm({
13219
14508
  this.name = "PlanLimitError";
13220
14509
  }
13221
14510
  };
13222
- CACHE_PATH2 = path17.join(EXE_AI_DIR, "license-cache.json");
14511
+ CACHE_PATH2 = path19.join(EXE_AI_DIR, "license-cache.json");
13223
14512
  }
13224
14513
  });
13225
14514
 
13226
14515
  // src/lib/notifications.ts
13227
- import crypto4 from "crypto";
13228
- import path18 from "path";
14516
+ import crypto6 from "crypto";
14517
+ import path20 from "path";
13229
14518
  import os8 from "os";
13230
14519
  import {
13231
- readFileSync as readFileSync14,
13232
- readdirSync as readdirSync3,
13233
- unlinkSync as unlinkSync5,
13234
- existsSync as existsSync17,
14520
+ readFileSync as readFileSync16,
14521
+ readdirSync as readdirSync5,
14522
+ unlinkSync as unlinkSync7,
14523
+ existsSync as existsSync19,
13235
14524
  rmdirSync
13236
14525
  } from "fs";
13237
14526
  async function writeNotification(notification) {
13238
14527
  try {
13239
14528
  const client = getClient();
13240
- const id = crypto4.randomUUID();
14529
+ const id = crypto6.randomUUID();
13241
14530
  const now = (/* @__PURE__ */ new Date()).toISOString();
13242
14531
  await client.execute({
13243
14532
  sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
@@ -13276,7 +14565,7 @@ var init_notifications = __esm({
13276
14565
  });
13277
14566
 
13278
14567
  // src/lib/session-kill-telemetry.ts
13279
- import crypto5 from "crypto";
14568
+ import crypto7 from "crypto";
13280
14569
  async function recordSessionKill(input) {
13281
14570
  try {
13282
14571
  const client = getClient();
@@ -13286,7 +14575,7 @@ async function recordSessionKill(input) {
13286
14575
  ticks_idle, estimated_tokens_saved)
13287
14576
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
13288
14577
  args: [
13289
- crypto5.randomUUID(),
14578
+ crypto7.randomUUID(),
13290
14579
  input.sessionName,
13291
14580
  input.agentId,
13292
14581
  (/* @__PURE__ */ new Date()).toISOString(),
@@ -13325,11 +14614,11 @@ __export(tasks_crud_exports, {
13325
14614
  updateTaskStatus: () => updateTaskStatus,
13326
14615
  writeCheckpoint: () => writeCheckpoint
13327
14616
  });
13328
- import crypto6 from "crypto";
13329
- import path19 from "path";
14617
+ import crypto8 from "crypto";
14618
+ import path21 from "path";
13330
14619
  import { execSync as execSync9 } from "child_process";
13331
14620
  import { mkdir as mkdir6, writeFile as writeFile5, appendFile } from "fs/promises";
13332
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
14621
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
13333
14622
  async function writeCheckpoint(input) {
13334
14623
  const client = getClient();
13335
14624
  const row = await resolveTask(client, input.taskId);
@@ -13416,7 +14705,7 @@ async function resolveTask(client, identifier, scopeSession) {
13416
14705
  }
13417
14706
  async function createTaskCore(input) {
13418
14707
  const client = getClient();
13419
- const id = crypto6.randomUUID();
14708
+ const id = crypto8.randomUUID();
13420
14709
  const now = (/* @__PURE__ */ new Date()).toISOString();
13421
14710
  const slug = slugify(input.title);
13422
14711
  const taskFile = input.taskFile ?? `exe/${input.assignedTo}/${slug}.md`;
@@ -13461,8 +14750,8 @@ async function createTaskCore(input) {
13461
14750
  }
13462
14751
  if (input.baseDir) {
13463
14752
  try {
13464
- await mkdir6(path19.join(input.baseDir, "exe", "output"), { recursive: true });
13465
- await mkdir6(path19.join(input.baseDir, "exe", "research"), { recursive: true });
14753
+ await mkdir6(path21.join(input.baseDir, "exe", "output"), { recursive: true });
14754
+ await mkdir6(path21.join(input.baseDir, "exe", "research"), { recursive: true });
13466
14755
  await ensureArchitectureDoc(input.baseDir, input.projectName);
13467
14756
  await ensureGitignoreExe(input.baseDir);
13468
14757
  } catch {
@@ -13682,9 +14971,9 @@ async function deleteTaskCore(taskId, _baseDir) {
13682
14971
  return { taskFile, assignedTo, assignedBy, taskSlug };
13683
14972
  }
13684
14973
  async function ensureArchitectureDoc(baseDir, projectName) {
13685
- const archPath = path19.join(baseDir, "exe", "ARCHITECTURE.md");
14974
+ const archPath = path21.join(baseDir, "exe", "ARCHITECTURE.md");
13686
14975
  try {
13687
- if (existsSync18(archPath)) return;
14976
+ if (existsSync20(archPath)) return;
13688
14977
  const template = [
13689
14978
  `# ${projectName} \u2014 System Architecture`,
13690
14979
  "",
@@ -13717,10 +15006,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
13717
15006
  }
13718
15007
  }
13719
15008
  async function ensureGitignoreExe(baseDir) {
13720
- const gitignorePath = path19.join(baseDir, ".gitignore");
15009
+ const gitignorePath = path21.join(baseDir, ".gitignore");
13721
15010
  try {
13722
- if (existsSync18(gitignorePath)) {
13723
- const content = readFileSync15(gitignorePath, "utf-8");
15011
+ if (existsSync20(gitignorePath)) {
15012
+ const content = readFileSync17(gitignorePath, "utf-8");
13724
15013
  if (/^\/?exe\/?$/m.test(content)) return;
13725
15014
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
13726
15015
  } else {
@@ -13741,8 +15030,8 @@ var init_tasks_crud = __esm({
13741
15030
  });
13742
15031
 
13743
15032
  // src/lib/tasks-review.ts
13744
- import path20 from "path";
13745
- import { existsSync as existsSync19, readdirSync as readdirSync4, unlinkSync as unlinkSync6 } from "fs";
15033
+ import path22 from "path";
15034
+ import { existsSync as existsSync21, readdirSync as readdirSync6, unlinkSync as unlinkSync8 } from "fs";
13746
15035
  async function countPendingReviews(sessionScope) {
13747
15036
  const client = getClient();
13748
15037
  if (sessionScope) {
@@ -13923,11 +15212,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
13923
15212
  );
13924
15213
  }
13925
15214
  try {
13926
- const cacheDir = path20.join(EXE_AI_DIR, "session-cache");
13927
- if (existsSync19(cacheDir)) {
13928
- for (const f of readdirSync4(cacheDir)) {
15215
+ const cacheDir = path22.join(EXE_AI_DIR, "session-cache");
15216
+ if (existsSync21(cacheDir)) {
15217
+ for (const f of readdirSync6(cacheDir)) {
13929
15218
  if (f.startsWith("review-notified-")) {
13930
- unlinkSync6(path20.join(cacheDir, f));
15219
+ unlinkSync8(path22.join(cacheDir, f));
13931
15220
  }
13932
15221
  }
13933
15222
  }
@@ -13948,7 +15237,7 @@ var init_tasks_review = __esm({
13948
15237
  });
13949
15238
 
13950
15239
  // src/lib/tasks-chain.ts
13951
- import path21 from "path";
15240
+ import path23 from "path";
13952
15241
  import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
13953
15242
  async function cascadeUnblock(taskId, baseDir, now) {
13954
15243
  const client = getClient();
@@ -13965,7 +15254,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
13965
15254
  });
13966
15255
  for (const ur of unblockedRows.rows) {
13967
15256
  try {
13968
- const ubFile = path21.join(baseDir, String(ur.task_file));
15257
+ const ubFile = path23.join(baseDir, String(ur.task_file));
13969
15258
  let ubContent = await readFile5(ubFile, "utf-8");
13970
15259
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
13971
15260
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -14034,7 +15323,7 @@ var init_tasks_chain = __esm({
14034
15323
 
14035
15324
  // src/lib/project-name.ts
14036
15325
  import { execSync as execSync10 } from "child_process";
14037
- import path22 from "path";
15326
+ import path24 from "path";
14038
15327
  function getProjectName(cwd2) {
14039
15328
  const dir = cwd2 ?? process.cwd();
14040
15329
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -14047,7 +15336,7 @@ function getProjectName(cwd2) {
14047
15336
  timeout: 2e3,
14048
15337
  stdio: ["pipe", "pipe", "pipe"]
14049
15338
  }).trim();
14050
- repoRoot = path22.dirname(gitCommonDir);
15339
+ repoRoot = path24.dirname(gitCommonDir);
14051
15340
  } catch {
14052
15341
  repoRoot = execSync10("git rev-parse --show-toplevel", {
14053
15342
  cwd: dir,
@@ -14056,11 +15345,11 @@ function getProjectName(cwd2) {
14056
15345
  stdio: ["pipe", "pipe", "pipe"]
14057
15346
  }).trim();
14058
15347
  }
14059
- _cached2 = path22.basename(repoRoot);
15348
+ _cached2 = path24.basename(repoRoot);
14060
15349
  _cachedCwd = dir;
14061
15350
  return _cached2;
14062
15351
  } catch {
14063
- _cached2 = path22.basename(dir);
15352
+ _cached2 = path24.basename(dir);
14064
15353
  _cachedCwd = dir;
14065
15354
  return _cached2;
14066
15355
  }
@@ -14202,10 +15491,10 @@ var init_tasks_notify = __esm({
14202
15491
  });
14203
15492
 
14204
15493
  // src/lib/behaviors.ts
14205
- import crypto7 from "crypto";
15494
+ import crypto9 from "crypto";
14206
15495
  async function storeBehavior(opts) {
14207
15496
  const client = getClient();
14208
- const id = crypto7.randomUUID();
15497
+ const id = crypto9.randomUUID();
14209
15498
  const now = (/* @__PURE__ */ new Date()).toISOString();
14210
15499
  await client.execute({
14211
15500
  sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
@@ -14234,7 +15523,7 @@ __export(skill_learning_exports, {
14234
15523
  storeTrajectory: () => storeTrajectory,
14235
15524
  sweepTrajectories: () => sweepTrajectories
14236
15525
  });
14237
- import crypto8 from "crypto";
15526
+ import crypto10 from "crypto";
14238
15527
  async function extractTrajectory(taskId, agentId) {
14239
15528
  const client = getClient();
14240
15529
  const result = await client.execute({
@@ -14263,11 +15552,11 @@ async function extractTrajectory(taskId, agentId) {
14263
15552
  return signature;
14264
15553
  }
14265
15554
  function hashSignature(signature) {
14266
- return crypto8.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
15555
+ return crypto10.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
14267
15556
  }
14268
15557
  async function storeTrajectory(opts) {
14269
15558
  const client = getClient();
14270
- const id = crypto8.randomUUID();
15559
+ const id = crypto10.randomUUID();
14271
15560
  const now = (/* @__PURE__ */ new Date()).toISOString();
14272
15561
  const signatureHash = hashSignature(opts.signature);
14273
15562
  await client.execute({
@@ -14532,8 +15821,8 @@ __export(tasks_exports, {
14532
15821
  updateTaskStatus: () => updateTaskStatus,
14533
15822
  writeCheckpoint: () => writeCheckpoint
14534
15823
  });
14535
- import path23 from "path";
14536
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7 } from "fs";
15824
+ import path25 from "path";
15825
+ import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, unlinkSync as unlinkSync9 } from "fs";
14537
15826
  async function createTask(input) {
14538
15827
  const result = await createTaskCore(input);
14539
15828
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -14552,14 +15841,14 @@ async function updateTask(input) {
14552
15841
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
14553
15842
  try {
14554
15843
  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`);
15844
+ const cacheDir = path25.join(EXE_AI_DIR, "session-cache");
15845
+ const cachePath = path25.join(cacheDir, `current-task-${agent}.json`);
14557
15846
  if (input.status === "in_progress") {
14558
- mkdirSync9(cacheDir, { recursive: true });
14559
- writeFileSync8(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
15847
+ mkdirSync11(cacheDir, { recursive: true });
15848
+ writeFileSync10(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
14560
15849
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
14561
15850
  try {
14562
- unlinkSync7(cachePath);
15851
+ unlinkSync9(cachePath);
14563
15852
  } catch {
14564
15853
  }
14565
15854
  }
@@ -15001,13 +16290,13 @@ __export(tmux_routing_exports, {
15001
16290
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
15002
16291
  });
15003
16292
  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";
16293
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, existsSync as existsSync22, appendFileSync as appendFileSync2 } from "fs";
16294
+ import path26 from "path";
15006
16295
  import os9 from "os";
15007
16296
  import { fileURLToPath as fileURLToPath4 } from "url";
15008
- import { unlinkSync as unlinkSync8 } from "fs";
16297
+ import { unlinkSync as unlinkSync10 } from "fs";
15009
16298
  function spawnLockPath(sessionName) {
15010
- return path24.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
16299
+ return path26.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
15011
16300
  }
15012
16301
  function isProcessAlive(pid) {
15013
16302
  try {
@@ -15018,13 +16307,13 @@ function isProcessAlive(pid) {
15018
16307
  }
15019
16308
  }
15020
16309
  function acquireSpawnLock2(sessionName) {
15021
- if (!existsSync20(SPAWN_LOCK_DIR)) {
15022
- mkdirSync10(SPAWN_LOCK_DIR, { recursive: true });
16310
+ if (!existsSync22(SPAWN_LOCK_DIR)) {
16311
+ mkdirSync12(SPAWN_LOCK_DIR, { recursive: true });
15023
16312
  }
15024
16313
  const lockFile = spawnLockPath(sessionName);
15025
- if (existsSync20(lockFile)) {
16314
+ if (existsSync22(lockFile)) {
15026
16315
  try {
15027
- const lock = JSON.parse(readFileSync16(lockFile, "utf8"));
16316
+ const lock = JSON.parse(readFileSync18(lockFile, "utf8"));
15028
16317
  const age = Date.now() - lock.timestamp;
15029
16318
  if (isProcessAlive(lock.pid) && age < 6e4) {
15030
16319
  return false;
@@ -15032,25 +16321,25 @@ function acquireSpawnLock2(sessionName) {
15032
16321
  } catch {
15033
16322
  }
15034
16323
  }
15035
- writeFileSync9(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
16324
+ writeFileSync11(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
15036
16325
  return true;
15037
16326
  }
15038
16327
  function releaseSpawnLock2(sessionName) {
15039
16328
  try {
15040
- unlinkSync8(spawnLockPath(sessionName));
16329
+ unlinkSync10(spawnLockPath(sessionName));
15041
16330
  } catch {
15042
16331
  }
15043
16332
  }
15044
16333
  function resolveBehaviorsExporterScript() {
15045
16334
  try {
15046
16335
  const thisFile = fileURLToPath4(import.meta.url);
15047
- const scriptPath = path24.join(
15048
- path24.dirname(thisFile),
16336
+ const scriptPath = path26.join(
16337
+ path26.dirname(thisFile),
15049
16338
  "..",
15050
16339
  "bin",
15051
16340
  "exe-export-behaviors.js"
15052
16341
  );
15053
- return existsSync20(scriptPath) ? scriptPath : null;
16342
+ return existsSync22(scriptPath) ? scriptPath : null;
15054
16343
  } catch {
15055
16344
  return null;
15056
16345
  }
@@ -15114,12 +16403,12 @@ function extractRootExe(name) {
15114
16403
  return match?.[1] ?? null;
15115
16404
  }
15116
16405
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
15117
- if (!existsSync20(SESSION_CACHE)) {
15118
- mkdirSync10(SESSION_CACHE, { recursive: true });
16406
+ if (!existsSync22(SESSION_CACHE)) {
16407
+ mkdirSync12(SESSION_CACHE, { recursive: true });
15119
16408
  }
15120
16409
  const rootExe = extractRootExe(parentExe) ?? parentExe;
15121
- const filePath = path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
15122
- writeFileSync9(filePath, JSON.stringify({
16410
+ const filePath = path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
16411
+ writeFileSync11(filePath, JSON.stringify({
15123
16412
  parentExe: rootExe,
15124
16413
  dispatchedBy: dispatchedBy || rootExe,
15125
16414
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -15127,7 +16416,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
15127
16416
  }
15128
16417
  function getParentExe(sessionKey) {
15129
16418
  try {
15130
- const data = JSON.parse(readFileSync16(path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
16419
+ const data = JSON.parse(readFileSync18(path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
15131
16420
  return data.parentExe || null;
15132
16421
  } catch {
15133
16422
  return null;
@@ -15135,8 +16424,8 @@ function getParentExe(sessionKey) {
15135
16424
  }
15136
16425
  function getDispatchedBy(sessionKey) {
15137
16426
  try {
15138
- const data = JSON.parse(readFileSync16(
15139
- path24.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
16427
+ const data = JSON.parse(readFileSync18(
16428
+ path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
15140
16429
  "utf8"
15141
16430
  ));
15142
16431
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -15197,16 +16486,16 @@ async function verifyPaneAtCapacity(sessionName) {
15197
16486
  }
15198
16487
  function readDebounceState() {
15199
16488
  try {
15200
- if (!existsSync20(DEBOUNCE_FILE)) return {};
15201
- return JSON.parse(readFileSync16(DEBOUNCE_FILE, "utf8"));
16489
+ if (!existsSync22(DEBOUNCE_FILE)) return {};
16490
+ return JSON.parse(readFileSync18(DEBOUNCE_FILE, "utf8"));
15202
16491
  } catch {
15203
16492
  return {};
15204
16493
  }
15205
16494
  }
15206
16495
  function writeDebounceState(state) {
15207
16496
  try {
15208
- if (!existsSync20(SESSION_CACHE)) mkdirSync10(SESSION_CACHE, { recursive: true });
15209
- writeFileSync9(DEBOUNCE_FILE, JSON.stringify(state));
16497
+ if (!existsSync22(SESSION_CACHE)) mkdirSync12(SESSION_CACHE, { recursive: true });
16498
+ writeFileSync11(DEBOUNCE_FILE, JSON.stringify(state));
15210
16499
  } catch {
15211
16500
  }
15212
16501
  }
@@ -15230,7 +16519,7 @@ function logIntercom(msg) {
15230
16519
  process.stderr.write(`[intercom] ${msg}
15231
16520
  `);
15232
16521
  try {
15233
- appendFileSync(INTERCOM_LOG2, line);
16522
+ appendFileSync2(INTERCOM_LOG2, line);
15234
16523
  } catch {
15235
16524
  }
15236
16525
  }
@@ -15395,26 +16684,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15395
16684
  const transport = getTransport();
15396
16685
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
15397
16686
  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 });
16687
+ const logDir = path26.join(os9.homedir(), ".exe-os", "session-logs");
16688
+ const logFile = path26.join(logDir, `${instanceLabel}-${Date.now()}.log`);
16689
+ if (!existsSync22(logDir)) {
16690
+ mkdirSync12(logDir, { recursive: true });
15402
16691
  }
15403
16692
  transport.kill(sessionName);
15404
16693
  let cleanupSuffix = "";
15405
16694
  try {
15406
16695
  const thisFile = fileURLToPath4(import.meta.url);
15407
- const cleanupScript = path24.join(path24.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
15408
- if (existsSync20(cleanupScript)) {
16696
+ const cleanupScript = path26.join(path26.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
16697
+ if (existsSync22(cleanupScript)) {
15409
16698
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
15410
16699
  }
15411
16700
  } catch {
15412
16701
  }
15413
16702
  try {
15414
- const claudeJsonPath = path24.join(os9.homedir(), ".claude.json");
16703
+ const claudeJsonPath = path26.join(os9.homedir(), ".claude.json");
15415
16704
  let claudeJson = {};
15416
16705
  try {
15417
- claudeJson = JSON.parse(readFileSync16(claudeJsonPath, "utf8"));
16706
+ claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
15418
16707
  } catch {
15419
16708
  }
15420
16709
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -15422,17 +16711,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15422
16711
  const trustDir = opts?.cwd ?? projectDir;
15423
16712
  if (!projects[trustDir]) projects[trustDir] = {};
15424
16713
  projects[trustDir].hasTrustDialogAccepted = true;
15425
- writeFileSync9(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
16714
+ writeFileSync11(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
15426
16715
  } catch {
15427
16716
  }
15428
16717
  try {
15429
- const settingsDir = path24.join(os9.homedir(), ".claude", "projects");
16718
+ const settingsDir = path26.join(os9.homedir(), ".claude", "projects");
15430
16719
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
15431
- const projSettingsDir = path24.join(settingsDir, normalizedKey);
15432
- const settingsPath = path24.join(projSettingsDir, "settings.json");
16720
+ const projSettingsDir = path26.join(settingsDir, normalizedKey);
16721
+ const settingsPath = path26.join(projSettingsDir, "settings.json");
15433
16722
  let settings = {};
15434
16723
  try {
15435
- settings = JSON.parse(readFileSync16(settingsPath, "utf8"));
16724
+ settings = JSON.parse(readFileSync18(settingsPath, "utf8"));
15436
16725
  } catch {
15437
16726
  }
15438
16727
  const perms = settings.permissions ?? {};
@@ -15460,8 +16749,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15460
16749
  if (changed) {
15461
16750
  perms.allow = allow;
15462
16751
  settings.permissions = perms;
15463
- mkdirSync10(projSettingsDir, { recursive: true });
15464
- writeFileSync9(settingsPath, JSON.stringify(settings, null, 2) + "\n");
16752
+ mkdirSync12(projSettingsDir, { recursive: true });
16753
+ writeFileSync11(settingsPath, JSON.stringify(settings, null, 2) + "\n");
15465
16754
  }
15466
16755
  } catch {
15467
16756
  }
@@ -15473,7 +16762,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15473
16762
  let behaviorsFlag = "";
15474
16763
  let legacyFallbackWarned = false;
15475
16764
  if (!useExeAgent && !useBinSymlink) {
15476
- const identityPath2 = path24.join(
16765
+ const identityPath2 = path26.join(
15477
16766
  os9.homedir(),
15478
16767
  ".exe-os",
15479
16768
  "identity",
@@ -15483,13 +16772,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15483
16772
  const hasAgentFlag = claudeSupportsAgentFlag();
15484
16773
  if (hasAgentFlag) {
15485
16774
  identityFlag = ` --agent ${employeeName}`;
15486
- } else if (existsSync20(identityPath2)) {
16775
+ } else if (existsSync22(identityPath2)) {
15487
16776
  identityFlag = ` --append-system-prompt-file ${identityPath2}`;
15488
16777
  legacyFallbackWarned = true;
15489
16778
  }
15490
16779
  const behaviorsFile = exportBehaviorsSync(
15491
16780
  employeeName,
15492
- path24.basename(spawnCwd),
16781
+ path26.basename(spawnCwd),
15493
16782
  sessionName
15494
16783
  );
15495
16784
  if (behaviorsFile) {
@@ -15504,16 +16793,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15504
16793
  }
15505
16794
  let sessionContextFlag = "";
15506
16795
  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`);
16796
+ const ctxDir = path26.join(os9.homedir(), ".exe-os", "session-cache");
16797
+ mkdirSync12(ctxDir, { recursive: true });
16798
+ const ctxFile = path26.join(ctxDir, `session-context-${sessionName}.md`);
15510
16799
  const ctxContent = [
15511
16800
  `## Session Context`,
15512
16801
  `You are running in tmux session: ${sessionName}.`,
15513
16802
  `Your parent exe session is ${exeSession}.`,
15514
16803
  `Your employees (if any) use the -${exeSession} suffix (e.g., tom-${exeSession}).`
15515
16804
  ].join("\n");
15516
- writeFileSync9(ctxFile, ctxContent);
16805
+ writeFileSync11(ctxFile, ctxContent);
15517
16806
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
15518
16807
  } catch {
15519
16808
  }
@@ -15551,8 +16840,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
15551
16840
  transport.pipeLog(sessionName, logFile);
15552
16841
  try {
15553
16842
  const mySession = getMySession();
15554
- const dispatchInfo = path24.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
15555
- writeFileSync9(dispatchInfo, JSON.stringify({
16843
+ const dispatchInfo = path26.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
16844
+ writeFileSync11(dispatchInfo, JSON.stringify({
15556
16845
  dispatchedBy: mySession,
15557
16846
  rootExe: exeSession,
15558
16847
  provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
@@ -15615,14 +16904,14 @@ var init_tmux_routing = __esm({
15615
16904
  init_provider_table();
15616
16905
  init_intercom_queue();
15617
16906
  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");
16907
+ SPAWN_LOCK_DIR = path26.join(os9.homedir(), ".exe-os", "spawn-locks");
16908
+ SESSION_CACHE = path26.join(os9.homedir(), ".exe-os", "session-cache");
15620
16909
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
15621
16910
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
15622
16911
  VERIFY_PANE_LINES = 200;
15623
16912
  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");
16913
+ INTERCOM_LOG2 = path26.join(os9.homedir(), ".exe-os", "intercom.log");
16914
+ DEBOUNCE_FILE = path26.join(SESSION_CACHE, "intercom-debounce.json");
15626
16915
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
15627
16916
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
15628
16917
  }
@@ -16043,11 +17332,11 @@ function Footer() {
16043
17332
  } catch {
16044
17333
  }
16045
17334
  try {
16046
- const { existsSync: existsSync22 } = await import("fs");
17335
+ const { existsSync: existsSync24 } = await import("fs");
16047
17336
  const { join } = await import("path");
16048
17337
  const home = process.env.HOME ?? "";
16049
17338
  const pidPath = join(home, ".exe-os", "exed.pid");
16050
- setDaemon(existsSync22(pidPath) ? "running" : "stopped");
17339
+ setDaemon(existsSync24(pidPath) ? "running" : "stopped");
16051
17340
  } catch {
16052
17341
  setDaemon("unknown");
16053
17342
  }
@@ -18078,10 +19367,10 @@ var init_hooks = __esm({
18078
19367
  });
18079
19368
 
18080
19369
  // src/runtime/safety-checks.ts
18081
- import path25 from "path";
19370
+ import path27 from "path";
18082
19371
  import os10 from "os";
18083
19372
  function checkPathSafety(filePath) {
18084
- const resolved = path25.resolve(filePath);
19373
+ const resolved = path27.resolve(filePath);
18085
19374
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
18086
19375
  const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
18087
19376
  if (matches) {
@@ -18091,7 +19380,7 @@ function checkPathSafety(filePath) {
18091
19380
  return { safe: true, bypassImmune: true };
18092
19381
  }
18093
19382
  function checkReadPathSafety(filePath) {
18094
- const resolved = path25.resolve(filePath);
19383
+ const resolved = path27.resolve(filePath);
18095
19384
  const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
18096
19385
  (p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
18097
19386
  );
@@ -18117,11 +19406,11 @@ var init_safety_checks = __esm({
18117
19406
  reason: "Git config can set hooks and command execution"
18118
19407
  },
18119
19408
  {
18120
- pattern: (p) => p.startsWith(path25.join(HOME, ".claude")),
19409
+ pattern: (p) => p.startsWith(path27.join(HOME, ".claude")),
18121
19410
  reason: "Claude configuration files are protected"
18122
19411
  },
18123
19412
  {
18124
- pattern: (p) => p.startsWith(path25.join(HOME, ".exe-os")),
19413
+ pattern: (p) => p.startsWith(path27.join(HOME, ".exe-os")),
18125
19414
  reason: "exe-os configuration files are protected"
18126
19415
  },
18127
19416
  {
@@ -18138,7 +19427,7 @@ var init_safety_checks = __esm({
18138
19427
  },
18139
19428
  {
18140
19429
  pattern: (p) => {
18141
- const name = path25.basename(p);
19430
+ const name = path27.basename(p);
18142
19431
  return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
18143
19432
  },
18144
19433
  reason: "Shell configuration files can execute arbitrary code on login"
@@ -18165,7 +19454,7 @@ __export(file_read_exports, {
18165
19454
  FileReadTool: () => FileReadTool
18166
19455
  });
18167
19456
  import fs3 from "fs/promises";
18168
- import path26 from "path";
19457
+ import path28 from "path";
18169
19458
  import { z } from "zod";
18170
19459
  function isBinary(buf) {
18171
19460
  for (let i = 0; i < buf.length; i++) {
@@ -18201,7 +19490,7 @@ var init_file_read = __esm({
18201
19490
  return { behavior: "allow" };
18202
19491
  },
18203
19492
  async call(input, context) {
18204
- const filePath = path26.isAbsolute(input.file_path) ? input.file_path : path26.resolve(context.cwd, input.file_path);
19493
+ const filePath = path28.isAbsolute(input.file_path) ? input.file_path : path28.resolve(context.cwd, input.file_path);
18205
19494
  let stat2;
18206
19495
  try {
18207
19496
  stat2 = await fs3.stat(filePath);
@@ -18241,7 +19530,7 @@ __export(glob_exports, {
18241
19530
  GlobTool: () => GlobTool
18242
19531
  });
18243
19532
  import fs4 from "fs/promises";
18244
- import path27 from "path";
19533
+ import path29 from "path";
18245
19534
  import { z as z2 } from "zod";
18246
19535
  async function walkDir(dir, maxDepth = 10) {
18247
19536
  const results = [];
@@ -18257,7 +19546,7 @@ async function walkDir(dir, maxDepth = 10) {
18257
19546
  if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
18258
19547
  continue;
18259
19548
  }
18260
- const fullPath = path27.join(current, entry.name);
19549
+ const fullPath = path29.join(current, entry.name);
18261
19550
  if (entry.isDirectory()) {
18262
19551
  await walk(fullPath, depth + 1);
18263
19552
  } else {
@@ -18291,11 +19580,11 @@ var init_glob = __esm({
18291
19580
  inputSchema: inputSchema2,
18292
19581
  isReadOnly: true,
18293
19582
  async call(input, context) {
18294
- const baseDir = input.path ? path27.isAbsolute(input.path) ? input.path : path27.resolve(context.cwd, input.path) : context.cwd;
19583
+ const baseDir = input.path ? path29.isAbsolute(input.path) ? input.path : path29.resolve(context.cwd, input.path) : context.cwd;
18295
19584
  try {
18296
19585
  const entries = await walkDir(baseDir);
18297
19586
  const matched = entries.filter(
18298
- (e) => simpleGlobMatch(path27.relative(baseDir, e.path), input.pattern)
19587
+ (e) => simpleGlobMatch(path29.relative(baseDir, e.path), input.pattern)
18299
19588
  );
18300
19589
  matched.sort((a, b) => b.mtime - a.mtime);
18301
19590
  if (matched.length === 0) {
@@ -18321,7 +19610,7 @@ __export(grep_exports, {
18321
19610
  });
18322
19611
  import { spawn as spawn2 } from "child_process";
18323
19612
  import fs5 from "fs/promises";
18324
- import path28 from "path";
19613
+ import path30 from "path";
18325
19614
  import { z as z3 } from "zod";
18326
19615
  function runRipgrep(input, searchPath, context) {
18327
19616
  return new Promise((resolve, reject) => {
@@ -18375,7 +19664,7 @@ async function nodeGrep(input, searchPath) {
18375
19664
  }
18376
19665
  for (const entry of entries) {
18377
19666
  if (entry.name === "node_modules" || entry.name === ".git") continue;
18378
- const fullPath = path28.join(dir, entry.name);
19667
+ const fullPath = path30.join(dir, entry.name);
18379
19668
  if (entry.isDirectory()) {
18380
19669
  await walk(fullPath);
18381
19670
  } else {
@@ -18421,7 +19710,7 @@ var init_grep = __esm({
18421
19710
  inputSchema: inputSchema3,
18422
19711
  isReadOnly: true,
18423
19712
  async call(input, context) {
18424
- const searchPath = input.path ? path28.isAbsolute(input.path) ? input.path : path28.resolve(context.cwd, input.path) : context.cwd;
19713
+ const searchPath = input.path ? path30.isAbsolute(input.path) ? input.path : path30.resolve(context.cwd, input.path) : context.cwd;
18425
19714
  try {
18426
19715
  const result = await runRipgrep(input, searchPath, context);
18427
19716
  return result;
@@ -18446,7 +19735,7 @@ __export(file_write_exports, {
18446
19735
  FileWriteTool: () => FileWriteTool
18447
19736
  });
18448
19737
  import fs6 from "fs/promises";
18449
- import path29 from "path";
19738
+ import path31 from "path";
18450
19739
  import { z as z4 } from "zod";
18451
19740
  var inputSchema4, FileWriteTool;
18452
19741
  var init_file_write = __esm({
@@ -18474,8 +19763,8 @@ var init_file_write = __esm({
18474
19763
  return { behavior: "allow" };
18475
19764
  },
18476
19765
  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);
19766
+ const filePath = path31.isAbsolute(input.file_path) ? input.file_path : path31.resolve(context.cwd, input.file_path);
19767
+ const dir = path31.dirname(filePath);
18479
19768
  await fs6.mkdir(dir, { recursive: true });
18480
19769
  await fs6.writeFile(filePath, input.content, "utf-8");
18481
19770
  return {
@@ -18493,7 +19782,7 @@ __export(file_edit_exports, {
18493
19782
  FileEditTool: () => FileEditTool
18494
19783
  });
18495
19784
  import fs7 from "fs/promises";
18496
- import path30 from "path";
19785
+ import path32 from "path";
18497
19786
  import { z as z5 } from "zod";
18498
19787
  function countOccurrences(haystack, needle) {
18499
19788
  let count = 0;
@@ -18534,7 +19823,7 @@ var init_file_edit = __esm({
18534
19823
  return { behavior: "allow" };
18535
19824
  },
18536
19825
  async call(input, context) {
18537
- const filePath = path30.isAbsolute(input.file_path) ? input.file_path : path30.resolve(context.cwd, input.file_path);
19826
+ const filePath = path32.isAbsolute(input.file_path) ? input.file_path : path32.resolve(context.cwd, input.file_path);
18538
19827
  let content;
18539
19828
  try {
18540
19829
  content = await fs7.readFile(filePath, "utf-8");
@@ -18776,8 +20065,8 @@ var init_bash = __esm({
18776
20065
  // src/tui/views/CommandCenter.tsx
18777
20066
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
18778
20067
  import TextInput from "ink-text-input";
18779
- import path31 from "path";
18780
- import { homedir as homedir3 } from "os";
20068
+ import path33 from "path";
20069
+ import { homedir as homedir5 } from "os";
18781
20070
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
18782
20071
  function CommandCenterView({
18783
20072
  onSelectProject,
@@ -18811,15 +20100,15 @@ function CommandCenterView({
18811
20100
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
18812
20101
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
18813
20102
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
18814
- const { readFileSync: readFileSync18, existsSync: existsSync22 } = await import("fs");
20103
+ const { readFileSync: readFileSync20, existsSync: existsSync24 } = await import("fs");
18815
20104
  const { join } = await import("path");
18816
- const { homedir: homedir5 } = await import("os");
18817
- const configPath = join(homedir5(), ".exe-os", "config.json");
20105
+ const { homedir: homedir7 } = await import("os");
20106
+ const configPath = join(homedir7(), ".exe-os", "config.json");
18818
20107
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
18819
20108
  let providerConfigs = {};
18820
- if (existsSync22(configPath)) {
20109
+ if (existsSync24(configPath)) {
18821
20110
  try {
18822
- const raw = JSON.parse(readFileSync18(configPath, "utf8"));
20111
+ const raw = JSON.parse(readFileSync20(configPath, "utf8"));
18823
20112
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
18824
20113
  if (raw.providers && typeof raw.providers === "object") {
18825
20114
  providerConfigs = raw.providers;
@@ -18877,10 +20166,10 @@ function CommandCenterView({
18877
20166
  registry.register(BashTool2);
18878
20167
  let agentRole = "CTO";
18879
20168
  try {
18880
- const markerDir = join(homedir5(), ".exe-os", "session-cache");
20169
+ const markerDir = join(homedir7(), ".exe-os", "session-cache");
18881
20170
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
18882
20171
  for (const f of agentFiles) {
18883
- const data = JSON.parse(readFileSync18(join(markerDir, f), "utf8"));
20172
+ const data = JSON.parse(readFileSync20(join(markerDir, f), "utf8"));
18884
20173
  if (data.agentRole) {
18885
20174
  agentRole = data.agentRole;
18886
20175
  break;
@@ -19017,7 +20306,7 @@ function CommandCenterView({
19017
20306
  const demoEntries = DEMO_PROJECTS.map((p) => ({
19018
20307
  projectName: p.projectName,
19019
20308
  exeSession: p.exeSession,
19020
- projectDir: path31.join(homedir3(), p.projectName),
20309
+ projectDir: path33.join(homedir5(), p.projectName),
19021
20310
  employeeCount: p.employees.length,
19022
20311
  activeCount: p.employees.filter((e) => e.status === "active").length,
19023
20312
  memoryCount: p.employees.length * 4e3,
@@ -19055,7 +20344,7 @@ function CommandCenterView({
19055
20344
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
19056
20345
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
19057
20346
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
19058
- const { existsSync: existsSync22 } = await import("fs");
20347
+ const { existsSync: existsSync24 } = await import("fs");
19059
20348
  const { join } = await import("path");
19060
20349
  const client = getClient2();
19061
20350
  if (!client) {
@@ -19124,7 +20413,7 @@ function CommandCenterView({
19124
20413
  }
19125
20414
  const memoryCount = memoryCounts.get(name) ?? 0;
19126
20415
  const openTaskCount = openTaskCounts.get(name) ?? 0;
19127
- const hasGit = projectDir ? existsSync22(join(projectDir, ".git")) : false;
20416
+ const hasGit = projectDir ? existsSync24(join(projectDir, ".git")) : false;
19128
20417
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
19129
20418
  projectList.push({
19130
20419
  projectName: name,
@@ -19149,7 +20438,7 @@ function CommandCenterView({
19149
20438
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
19150
20439
  try {
19151
20440
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
19152
- setHealth((h) => ({ ...h, daemon: existsSync22(pidPath) ? "running" : "stopped" }));
20441
+ setHealth((h) => ({ ...h, daemon: existsSync24(pidPath) ? "running" : "stopped" }));
19153
20442
  } catch {
19154
20443
  }
19155
20444
  const activityResult = await client.execute(
@@ -20010,8 +21299,8 @@ var init_useOrchestrator = __esm({
20010
21299
 
20011
21300
  // src/tui/views/Sessions.tsx
20012
21301
  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";
21302
+ import path34 from "path";
21303
+ import { homedir as homedir6 } from "os";
20015
21304
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
20016
21305
  function SessionsView({
20017
21306
  initialProject,
@@ -20045,7 +21334,7 @@ function SessionsView({
20045
21334
  if (demo) {
20046
21335
  setProjects(DEMO_PROJECTS.map((p) => ({
20047
21336
  ...p,
20048
- projectDir: path32.join(homedir4(), p.projectName),
21337
+ projectDir: path34.join(homedir6(), p.projectName),
20049
21338
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
20050
21339
  })));
20051
21340
  return;
@@ -20804,16 +22093,16 @@ __export(ws_auth_exports, {
20804
22093
  deriveWsAuthToken: () => deriveWsAuthToken,
20805
22094
  hashAuthToken: () => hashAuthToken
20806
22095
  });
20807
- import crypto9 from "crypto";
22096
+ import crypto11 from "crypto";
20808
22097
  function deriveWsAuthToken(masterKey) {
20809
- return Buffer.from(crypto9.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
22098
+ return Buffer.from(crypto11.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
20810
22099
  }
20811
22100
  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);
22101
+ const raw = Buffer.from(crypto11.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
22102
+ return crypto11.createHash("sha256").update(raw).digest("hex").slice(0, 32);
20814
22103
  }
20815
22104
  function hashAuthToken(token) {
20816
- return crypto9.createHash("sha256").update(token).digest("hex");
22105
+ return crypto11.createHash("sha256").update(token).digest("hex");
20817
22106
  }
20818
22107
  var WS_AUTH_HKDF_INFO, ORG_ID_HKDF_INFO;
20819
22108
  var init_ws_auth = __esm({
@@ -21017,7 +22306,7 @@ function assertSecureWsUrl(url) {
21017
22306
  `Malformed WebSocket URL rejected: "${url}".`
21018
22307
  );
21019
22308
  }
21020
- if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
22309
+ if (LOCALHOST_PATTERNS2.test(parsed.hostname)) return;
21021
22310
  throw new Error(
21022
22311
  `Insecure WebSocket URL rejected: "${url}". Use wss:// for remote hosts. Plain ws:// is only allowed for localhost.`
21023
22312
  );
@@ -21026,7 +22315,7 @@ function assertSecureWsUrl(url) {
21026
22315
  function isGatewayEvent(msg) {
21027
22316
  return typeof msg.type === "string" && GATEWAY_EVENT_TYPES.has(msg.type);
21028
22317
  }
21029
- var MIN_RECONNECT_MS, MAX_RECONNECT_MS, AUTH_RESPONSE_TIMEOUT_MS, DEFAULT_CHANNELS, GATEWAY_EVENT_TYPES, LOCALHOST_PATTERNS;
22318
+ var MIN_RECONNECT_MS, MAX_RECONNECT_MS, AUTH_RESPONSE_TIMEOUT_MS, DEFAULT_CHANNELS, GATEWAY_EVENT_TYPES, LOCALHOST_PATTERNS2;
21030
22319
  var init_gateway_client = __esm({
21031
22320
  "src/lib/gateway-client.ts"() {
21032
22321
  "use strict";
@@ -21042,7 +22331,7 @@ var init_gateway_client = __esm({
21042
22331
  "health",
21043
22332
  "escalation"
21044
22333
  ]);
21045
- LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
22334
+ LOCALHOST_PATTERNS2 = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
21046
22335
  }
21047
22336
  });
21048
22337
 
@@ -21173,12 +22462,12 @@ async function loadGatewayConfig() {
21173
22462
  state.running = false;
21174
22463
  }
21175
22464
  try {
21176
- const { existsSync: existsSync22, readFileSync: readFileSync18 } = await import("fs");
22465
+ const { existsSync: existsSync24, readFileSync: readFileSync20 } = await import("fs");
21177
22466
  const { join } = await import("path");
21178
22467
  const home = process.env.HOME ?? "";
21179
22468
  const configPath = join(home, ".exe-os", "gateway.json");
21180
- if (existsSync22(configPath)) {
21181
- const raw = JSON.parse(readFileSync18(configPath, "utf8"));
22469
+ if (existsSync24(configPath)) {
22470
+ const raw = JSON.parse(readFileSync20(configPath, "utf8"));
21182
22471
  state.port = raw.port ?? 3100;
21183
22472
  state.gatewayUrl = raw.gatewayUrl ?? "";
21184
22473
  if (raw.adapters) {
@@ -21801,12 +23090,12 @@ function TeamView({ onBack, onViewSessions }) {
21801
23090
  setMembers(teamData);
21802
23091
  setDbError(null);
21803
23092
  try {
21804
- const { existsSync: existsSync22, readFileSync: readFileSync18 } = await import("fs");
23093
+ const { existsSync: existsSync24, readFileSync: readFileSync20 } = await import("fs");
21805
23094
  const { join } = await import("path");
21806
23095
  const home = process.env.HOME ?? "";
21807
23096
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
21808
- if (existsSync22(gatewayConfig)) {
21809
- const raw = JSON.parse(readFileSync18(gatewayConfig, "utf8"));
23097
+ if (existsSync24(gatewayConfig)) {
23098
+ const raw = JSON.parse(readFileSync20(gatewayConfig, "utf8"));
21810
23099
  if (raw.agents && raw.agents.length > 0) {
21811
23100
  setExternals(raw.agents.map((a) => ({
21812
23101
  name: a.name,
@@ -21987,8 +23276,8 @@ __export(wiki_client_exports, {
21987
23276
  listDocuments: () => listDocuments,
21988
23277
  listWorkspaces: () => listWorkspaces
21989
23278
  });
21990
- async function wikiFetch(config, path34, method = "GET", body) {
21991
- const url = `${config.baseUrl}/api/v1${path34}`;
23279
+ async function wikiFetch(config, path36, method = "GET", body) {
23280
+ const url = `${config.baseUrl}/api/v1${path36}`;
21992
23281
  const headers = {
21993
23282
  Authorization: `Bearer ${config.apiKey}`,
21994
23283
  "Content-Type": "application/json"
@@ -22021,7 +23310,7 @@ async function wikiFetch(config, path34, method = "GET", body) {
22021
23310
  }
22022
23311
  }
22023
23312
  if (!response.ok) {
22024
- throw new Error(`Wiki API ${method} ${path34}: ${response.status} ${response.statusText}`);
23313
+ throw new Error(`Wiki API ${method} ${path36}: ${response.status} ${response.statusText}`);
22025
23314
  }
22026
23315
  return response.json();
22027
23316
  } finally {
@@ -22631,12 +23920,12 @@ function SettingsView({ onBack }) {
22631
23920
  }
22632
23921
  setProviders(providerList);
22633
23922
  try {
22634
- const { existsSync: existsSync22 } = await import("fs");
23923
+ const { existsSync: existsSync24 } = await import("fs");
22635
23924
  const { join } = await import("path");
22636
23925
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
22637
23926
  const cfg = await loadConfig2();
22638
23927
  const home = process.env.HOME ?? "";
22639
- const hasKey = existsSync22(join(home, ".exe-os", "master.key"));
23928
+ const hasKey = existsSync24(join(home, ".exe-os", "master.key"));
22640
23929
  if (cfg.cloud) {
22641
23930
  setCloud({
22642
23931
  configured: true,
@@ -22649,22 +23938,22 @@ function SettingsView({ onBack }) {
22649
23938
  const pidPath = join(home, ".exe-os", "exed.pid");
22650
23939
  let daemon = "unknown";
22651
23940
  try {
22652
- daemon = existsSync22(pidPath) ? "running" : "stopped";
23941
+ daemon = existsSync24(pidPath) ? "running" : "stopped";
22653
23942
  } catch {
22654
23943
  }
22655
23944
  let version = "unknown";
22656
23945
  try {
22657
- const { readFileSync: readFileSync18 } = await import("fs");
23946
+ const { readFileSync: readFileSync20 } = await import("fs");
22658
23947
  const { createRequire } = await import("module");
22659
23948
  const require2 = createRequire(import.meta.url);
22660
23949
  const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
22661
- const pkg = JSON.parse(readFileSync18(pkgPath, "utf8"));
23950
+ const pkg = JSON.parse(readFileSync20(pkgPath, "utf8"));
22662
23951
  version = pkg.version;
22663
23952
  } catch {
22664
23953
  try {
22665
- const { readFileSync: readFileSync18 } = await import("fs");
23954
+ const { readFileSync: readFileSync20 } = await import("fs");
22666
23955
  const { join: joinPath } = await import("path");
22667
- const pkg = JSON.parse(readFileSync18(joinPath(process.cwd(), "package.json"), "utf8"));
23956
+ const pkg = JSON.parse(readFileSync20(joinPath(process.cwd(), "package.json"), "utf8"));
22668
23957
  version = pkg.version;
22669
23958
  } catch {
22670
23959
  }
@@ -23271,8 +24560,8 @@ Unhandled rejection: ${reason}
23271
24560
  });
23272
24561
 
23273
24562
  // 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";
24563
+ import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync12, readdirSync as readdirSync7, rmSync } from "fs";
24564
+ import path35 from "path";
23276
24565
  import os11 from "os";
23277
24566
  var args = process.argv.slice(2);
23278
24567
  if (args.includes("--global")) {
@@ -23336,11 +24625,11 @@ if (args.includes("--global")) {
23336
24625
  });
23337
24626
  await init_App2().then(() => App_exports);
23338
24627
  } else {
23339
- const claudeDir = path33.join(os11.homedir(), ".claude");
23340
- const settingsPath = path33.join(claudeDir, "settings.json");
23341
- const hasClaudeCode = existsSync21(settingsPath) && (() => {
24628
+ const claudeDir = path35.join(os11.homedir(), ".claude");
24629
+ const settingsPath = path35.join(claudeDir, "settings.json");
24630
+ const hasClaudeCode = existsSync23(settingsPath) && (() => {
23342
24631
  try {
23343
- const raw = readFileSync17(settingsPath, "utf8");
24632
+ const raw = readFileSync19(settingsPath, "utf8");
23344
24633
  return raw.includes("exe-os") || raw.includes("exe-mem");
23345
24634
  } catch {
23346
24635
  return false;
@@ -23379,14 +24668,14 @@ async function runClaudeInstall() {
23379
24668
  }
23380
24669
  }
23381
24670
  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");
24671
+ const claudeDir = path35.join(os11.homedir(), ".claude");
24672
+ const settingsPath = path35.join(claudeDir, "settings.json");
24673
+ const claudeJsonPath = path35.join(os11.homedir(), ".claude.json");
23385
24674
  let ok = true;
23386
- if (existsSync21(settingsPath)) {
24675
+ if (existsSync23(settingsPath)) {
23387
24676
  let settings;
23388
24677
  try {
23389
- settings = JSON.parse(readFileSync17(settingsPath, "utf8"));
24678
+ settings = JSON.parse(readFileSync19(settingsPath, "utf8"));
23390
24679
  } catch {
23391
24680
  console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
23392
24681
  ok = false;
@@ -23412,10 +24701,10 @@ async function runClaudeCheck() {
23412
24701
  console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
23413
24702
  ok = false;
23414
24703
  }
23415
- if (existsSync21(claudeJsonPath)) {
24704
+ if (existsSync23(claudeJsonPath)) {
23416
24705
  let claudeJson;
23417
24706
  try {
23418
- claudeJson = JSON.parse(readFileSync17(claudeJsonPath, "utf8"));
24707
+ claudeJson = JSON.parse(readFileSync19(claudeJsonPath, "utf8"));
23419
24708
  } catch {
23420
24709
  console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
23421
24710
  ok = false;
@@ -23434,8 +24723,8 @@ async function runClaudeCheck() {
23434
24723
  console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
23435
24724
  ok = false;
23436
24725
  }
23437
- const skillsDir = path33.join(claudeDir, "skills");
23438
- if (existsSync21(skillsDir)) {
24726
+ const skillsDir = path35.join(claudeDir, "skills");
24727
+ if (existsSync23(skillsDir)) {
23439
24728
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
23440
24729
  } else {
23441
24730
  console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
@@ -23452,16 +24741,16 @@ async function runClaudeUninstall(flags = []) {
23452
24741
  const dryRun = flags.includes("--dry-run");
23453
24742
  const purge = flags.includes("--purge");
23454
24743
  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");
24744
+ const claudeDir = path35.join(homeDir, ".claude");
24745
+ const settingsPath = path35.join(claudeDir, "settings.json");
24746
+ const claudeJsonPath = path35.join(homeDir, ".claude.json");
24747
+ const exeOsDir = path35.join(homeDir, ".exe-os");
23459
24748
  let removed = 0;
23460
24749
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
23461
24750
  let settings = {};
23462
- if (existsSync21(settingsPath)) {
24751
+ if (existsSync23(settingsPath)) {
23463
24752
  try {
23464
- settings = JSON.parse(readFileSync17(settingsPath, "utf8"));
24753
+ settings = JSON.parse(readFileSync19(settingsPath, "utf8"));
23465
24754
  } catch {
23466
24755
  console.error("Your ~/.claude/settings.json appears malformed.");
23467
24756
  if (purge) {
@@ -23499,15 +24788,15 @@ async function runClaudeUninstall(flags = []) {
23499
24788
  permCount = before - settings.permissions.allow.length;
23500
24789
  }
23501
24790
  if (!dryRun) {
23502
- writeFileSync10(settingsPath, JSON.stringify(settings, null, 2) + "\n");
24791
+ writeFileSync12(settingsPath, JSON.stringify(settings, null, 2) + "\n");
23503
24792
  }
23504
24793
  log("\u2713 Removed exe-os hooks from settings.json");
23505
24794
  if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
23506
24795
  removed++;
23507
24796
  }
23508
24797
  }
23509
- if (existsSync21(claudeJsonPath)) {
23510
- const raw = readFileSync17(claudeJsonPath, "utf8");
24798
+ if (existsSync23(claudeJsonPath)) {
24799
+ const raw = readFileSync19(claudeJsonPath, "utf8");
23511
24800
  if (raw.length > 1e6) {
23512
24801
  console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
23513
24802
  } else {
@@ -23528,7 +24817,7 @@ async function runClaudeUninstall(flags = []) {
23528
24817
  }
23529
24818
  if (removedMcp) {
23530
24819
  if (!dryRun) {
23531
- writeFileSync10(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
24820
+ writeFileSync12(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
23532
24821
  }
23533
24822
  log("\u2713 Removed exe-os MCP server from claude.json");
23534
24823
  removed++;
@@ -23536,14 +24825,14 @@ async function runClaudeUninstall(flags = []) {
23536
24825
  }
23537
24826
  }
23538
24827
  }
23539
- const skillsDir = path33.join(claudeDir, "skills");
23540
- if (existsSync21(skillsDir)) {
24828
+ const skillsDir = path35.join(claudeDir, "skills");
24829
+ if (existsSync23(skillsDir)) {
23541
24830
  let skillCount = 0;
23542
24831
  try {
23543
- const entries = readdirSync5(skillsDir);
24832
+ const entries = readdirSync7(skillsDir);
23544
24833
  for (const entry of entries) {
23545
24834
  if (entry.startsWith("exe")) {
23546
- const fullPath = path33.join(skillsDir, entry);
24835
+ const fullPath = path35.join(skillsDir, entry);
23547
24836
  if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
23548
24837
  skillCount++;
23549
24838
  }
@@ -23555,30 +24844,30 @@ async function runClaudeUninstall(flags = []) {
23555
24844
  removed++;
23556
24845
  }
23557
24846
  }
23558
- const claudeMdPath = path33.join(claudeDir, "CLAUDE.md");
23559
- if (existsSync21(claudeMdPath)) {
23560
- const content = readFileSync17(claudeMdPath, "utf8");
24847
+ const claudeMdPath = path35.join(claudeDir, "CLAUDE.md");
24848
+ if (existsSync23(claudeMdPath)) {
24849
+ const content = readFileSync19(claudeMdPath, "utf8");
23561
24850
  const startMarker = "<!-- exe-os:orchestration-start -->";
23562
24851
  const endMarker = "<!-- exe-os:orchestration-end -->";
23563
24852
  const startIdx = content.indexOf(startMarker);
23564
24853
  const endIdx = content.indexOf(endMarker);
23565
24854
  if (startIdx !== -1 && endIdx !== -1) {
23566
24855
  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);
24856
+ if (!dryRun) writeFileSync12(claudeMdPath, cleaned);
23568
24857
  log("\u2713 Removed orchestration block from CLAUDE.md");
23569
24858
  removed++;
23570
24859
  }
23571
24860
  }
23572
- const agentsDir = path33.join(claudeDir, "agents");
23573
- if (existsSync21(agentsDir)) {
24861
+ const agentsDir = path35.join(claudeDir, "agents");
24862
+ if (existsSync23(agentsDir)) {
23574
24863
  let agentCount = 0;
23575
24864
  try {
23576
- const entries = readdirSync5(agentsDir).filter((f) => f.endsWith(".md"));
24865
+ const entries = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
23577
24866
  let knownNames = /* @__PURE__ */ new Set();
23578
- const rosterPath = path33.join(exeOsDir, "exe-employees.json");
23579
- if (existsSync21(rosterPath)) {
24867
+ const rosterPath = path35.join(exeOsDir, "exe-employees.json");
24868
+ if (existsSync23(rosterPath)) {
23580
24869
  try {
23581
- const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
24870
+ const roster = JSON.parse(readFileSync19(rosterPath, "utf8"));
23582
24871
  knownNames = new Set(roster.map((e) => e.name));
23583
24872
  } catch {
23584
24873
  }
@@ -23586,7 +24875,7 @@ async function runClaudeUninstall(flags = []) {
23586
24875
  for (const entry of entries) {
23587
24876
  const name = entry.replace(/\.md$/, "");
23588
24877
  if (knownNames.has(name)) {
23589
- if (!dryRun) rmSync(path33.join(agentsDir, entry), { force: true });
24878
+ if (!dryRun) rmSync(path35.join(agentsDir, entry), { force: true });
23590
24879
  agentCount++;
23591
24880
  }
23592
24881
  }
@@ -23597,16 +24886,16 @@ async function runClaudeUninstall(flags = []) {
23597
24886
  removed++;
23598
24887
  }
23599
24888
  }
23600
- const projectsDir = path33.join(claudeDir, "projects");
23601
- if (existsSync21(projectsDir)) {
24889
+ const projectsDir = path35.join(claudeDir, "projects");
24890
+ if (existsSync23(projectsDir)) {
23602
24891
  let projectCount = 0;
23603
24892
  try {
23604
- const projects = readdirSync5(projectsDir);
24893
+ const projects = readdirSync7(projectsDir);
23605
24894
  for (const proj of projects) {
23606
- const projSettings = path33.join(projectsDir, proj, "settings.json");
23607
- if (!existsSync21(projSettings)) continue;
24895
+ const projSettings = path35.join(projectsDir, proj, "settings.json");
24896
+ if (!existsSync23(projSettings)) continue;
23608
24897
  try {
23609
- const pSettings = JSON.parse(readFileSync17(projSettings, "utf8"));
24898
+ const pSettings = JSON.parse(readFileSync19(projSettings, "utf8"));
23610
24899
  let changed = false;
23611
24900
  if (Array.isArray(pSettings.permissions?.allow)) {
23612
24901
  const before = pSettings.permissions.allow.length;
@@ -23616,7 +24905,7 @@ async function runClaudeUninstall(flags = []) {
23616
24905
  if (pSettings.permissions.allow.length < before) changed = true;
23617
24906
  }
23618
24907
  if (changed && !dryRun) {
23619
- writeFileSync10(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
24908
+ writeFileSync12(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
23620
24909
  }
23621
24910
  if (changed) projectCount++;
23622
24911
  } catch {
@@ -23640,16 +24929,16 @@ async function runClaudeUninstall(flags = []) {
23640
24929
  };
23641
24930
  const exeBinPath = findExeBin3();
23642
24931
  if (!exeBinPath) throw new Error("exe-os not found in PATH");
23643
- const binDir = path33.dirname(exeBinPath);
24932
+ const binDir = path35.dirname(exeBinPath);
23644
24933
  let symlinkCount = 0;
23645
- const rosterPath = path33.join(exeOsDir, "exe-employees.json");
23646
- if (existsSync21(rosterPath)) {
23647
- const roster = JSON.parse(readFileSync17(rosterPath, "utf8"));
24934
+ const rosterPath = path35.join(exeOsDir, "exe-employees.json");
24935
+ if (existsSync23(rosterPath)) {
24936
+ const roster = JSON.parse(readFileSync19(rosterPath, "utf8"));
23648
24937
  for (const emp of roster) {
23649
24938
  if (emp.name === "exe") continue;
23650
24939
  for (const suffix of ["", "-opencode"]) {
23651
- const linkPath = path33.join(binDir, `${emp.name}${suffix}`);
23652
- if (existsSync21(linkPath)) {
24940
+ const linkPath = path35.join(binDir, `${emp.name}${suffix}`);
24941
+ if (existsSync23(linkPath)) {
23653
24942
  if (!dryRun) rmSync(linkPath, { force: true });
23654
24943
  symlinkCount++;
23655
24944
  }
@@ -23662,7 +24951,7 @@ async function runClaudeUninstall(flags = []) {
23662
24951
  }
23663
24952
  } catch {
23664
24953
  }
23665
- if (purge && existsSync21(exeOsDir)) {
24954
+ if (purge && existsSync23(exeOsDir)) {
23666
24955
  if (!dryRun) {
23667
24956
  process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
23668
24957
  process.stdout.write(" Removing ~/.exe-os...\n");
@@ -23687,7 +24976,7 @@ async function checkForUpdateOnBoot() {
23687
24976
  const config = await loadConfig2();
23688
24977
  if (!config.autoUpdate.checkOnBoot) return;
23689
24978
  const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
23690
- const packageRoot = path33.resolve(
24979
+ const packageRoot = path35.resolve(
23691
24980
  new URL("../..", import.meta.url).pathname
23692
24981
  );
23693
24982
  const result = checkForUpdate2(packageRoot);
@@ -23746,7 +25035,7 @@ async function runActivate(key) {
23746
25035
  const idTemplate = getIdentityTemplate(identityKey);
23747
25036
  if (idTemplate) {
23748
25037
  const idPath = identityPath2(name);
23749
- const dir = path33.dirname(idPath);
25038
+ const dir = path35.dirname(idPath);
23750
25039
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
23751
25040
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
23752
25041
  }