@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 +1585 -296
- package/dist/bin/exe-boot.js +21 -12
- package/dist/bin/exe-link.js +21 -12
- package/dist/bin/setup.js +1492 -115
- package/dist/hooks/summary-worker.js +21 -12
- package/dist/lib/cloud-sync.js +21 -12
- package/package.json +1 -1
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:
|
|
4774
|
-
const
|
|
4775
|
-
const modelPath =
|
|
4776
|
-
if (!
|
|
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
|
|
5201
|
-
import { readdirSync as
|
|
5202
|
-
import
|
|
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 (!
|
|
5206
|
-
|
|
6270
|
+
if (!existsSync12(IDENTITY_DIR)) {
|
|
6271
|
+
mkdirSync6(IDENTITY_DIR, { recursive: true });
|
|
5207
6272
|
}
|
|
5208
6273
|
}
|
|
5209
6274
|
function identityPath(agentId) {
|
|
5210
|
-
return
|
|
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 (!
|
|
5252
|
-
const raw =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
5863
|
-
import { existsSync as
|
|
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
|
|
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(
|
|
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
|
-
|
|
5876
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
7282
|
+
const claudeJsonPath = path15.join(os5.homedir(), ".claude.json");
|
|
6032
7283
|
let claudeJson = {};
|
|
6033
7284
|
try {
|
|
6034
|
-
claudeJson = JSON.parse(
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
6290
|
-
import
|
|
7578
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
7579
|
+
import path16 from "path";
|
|
6291
7580
|
function getLocalVersion(packageRoot) {
|
|
6292
|
-
const pkgPath =
|
|
6293
|
-
const pkg = JSON.parse(
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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 = (
|
|
10817
|
-
return
|
|
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
|
|
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
|
|
14137
|
+
import path17 from "path";
|
|
12849
14138
|
import os6 from "os";
|
|
12850
14139
|
function registerSession(entry) {
|
|
12851
|
-
const dir =
|
|
12852
|
-
if (!
|
|
12853
|
-
|
|
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
|
-
|
|
14151
|
+
writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
12863
14152
|
}
|
|
12864
14153
|
function listSessions() {
|
|
12865
14154
|
try {
|
|
12866
|
-
const raw =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
13101
|
-
import
|
|
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 =
|
|
13105
|
-
if (!
|
|
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 (!
|
|
13110
|
-
return JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
14431
|
+
QUEUE_PATH = path18.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
13143
14432
|
TTL_MS = 60 * 60 * 1e3;
|
|
13144
|
-
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
|
|
13150
|
-
import
|
|
14438
|
+
import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
|
|
14439
|
+
import path19 from "path";
|
|
13151
14440
|
function getLicenseSync() {
|
|
13152
14441
|
try {
|
|
13153
|
-
if (!
|
|
13154
|
-
const raw = JSON.parse(
|
|
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 (
|
|
13193
|
-
const raw =
|
|
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 =
|
|
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
|
|
13228
|
-
import
|
|
14516
|
+
import crypto6 from "crypto";
|
|
14517
|
+
import path20 from "path";
|
|
13229
14518
|
import os8 from "os";
|
|
13230
14519
|
import {
|
|
13231
|
-
readFileSync as
|
|
13232
|
-
readdirSync as
|
|
13233
|
-
unlinkSync as
|
|
13234
|
-
existsSync as
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
13329
|
-
import
|
|
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
|
|
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 =
|
|
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(
|
|
13465
|
-
await mkdir6(
|
|
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 =
|
|
14974
|
+
const archPath = path21.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
13686
14975
|
try {
|
|
13687
|
-
if (
|
|
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 =
|
|
15009
|
+
const gitignorePath = path21.join(baseDir, ".gitignore");
|
|
13721
15010
|
try {
|
|
13722
|
-
if (
|
|
13723
|
-
const content =
|
|
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
|
|
13745
|
-
import { existsSync as
|
|
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 =
|
|
13927
|
-
if (
|
|
13928
|
-
for (const f of
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
15348
|
+
_cached2 = path24.basename(repoRoot);
|
|
14060
15349
|
_cachedCwd = dir;
|
|
14061
15350
|
return _cached2;
|
|
14062
15351
|
} catch {
|
|
14063
|
-
_cached2 =
|
|
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
|
|
15494
|
+
import crypto9 from "crypto";
|
|
14206
15495
|
async function storeBehavior(opts) {
|
|
14207
15496
|
const client = getClient();
|
|
14208
|
-
const id =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
14536
|
-
import { writeFileSync as
|
|
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 =
|
|
14556
|
-
const cachePath =
|
|
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
|
-
|
|
14559
|
-
|
|
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
|
-
|
|
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
|
|
15005
|
-
import
|
|
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
|
|
16297
|
+
import { unlinkSync as unlinkSync10 } from "fs";
|
|
15009
16298
|
function spawnLockPath(sessionName) {
|
|
15010
|
-
return
|
|
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 (!
|
|
15022
|
-
|
|
16310
|
+
if (!existsSync22(SPAWN_LOCK_DIR)) {
|
|
16311
|
+
mkdirSync12(SPAWN_LOCK_DIR, { recursive: true });
|
|
15023
16312
|
}
|
|
15024
16313
|
const lockFile = spawnLockPath(sessionName);
|
|
15025
|
-
if (
|
|
16314
|
+
if (existsSync22(lockFile)) {
|
|
15026
16315
|
try {
|
|
15027
|
-
const lock = JSON.parse(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
15048
|
-
|
|
16336
|
+
const scriptPath = path26.join(
|
|
16337
|
+
path26.dirname(thisFile),
|
|
15049
16338
|
"..",
|
|
15050
16339
|
"bin",
|
|
15051
16340
|
"exe-export-behaviors.js"
|
|
15052
16341
|
);
|
|
15053
|
-
return
|
|
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 (!
|
|
15118
|
-
|
|
16406
|
+
if (!existsSync22(SESSION_CACHE)) {
|
|
16407
|
+
mkdirSync12(SESSION_CACHE, { recursive: true });
|
|
15119
16408
|
}
|
|
15120
16409
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
15121
|
-
const filePath =
|
|
15122
|
-
|
|
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(
|
|
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(
|
|
15139
|
-
|
|
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 (!
|
|
15201
|
-
return JSON.parse(
|
|
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 (!
|
|
15209
|
-
|
|
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
|
-
|
|
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 =
|
|
15399
|
-
const logFile =
|
|
15400
|
-
if (!
|
|
15401
|
-
|
|
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 =
|
|
15408
|
-
if (
|
|
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 =
|
|
16703
|
+
const claudeJsonPath = path26.join(os9.homedir(), ".claude.json");
|
|
15415
16704
|
let claudeJson = {};
|
|
15416
16705
|
try {
|
|
15417
|
-
claudeJson = JSON.parse(
|
|
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
|
-
|
|
16714
|
+
writeFileSync11(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
15426
16715
|
} catch {
|
|
15427
16716
|
}
|
|
15428
16717
|
try {
|
|
15429
|
-
const settingsDir =
|
|
16718
|
+
const settingsDir = path26.join(os9.homedir(), ".claude", "projects");
|
|
15430
16719
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
15431
|
-
const projSettingsDir =
|
|
15432
|
-
const settingsPath =
|
|
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(
|
|
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
|
-
|
|
15464
|
-
|
|
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 =
|
|
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 (
|
|
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
|
-
|
|
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 =
|
|
15508
|
-
|
|
15509
|
-
const ctxFile =
|
|
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
|
-
|
|
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 =
|
|
15555
|
-
|
|
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 =
|
|
15619
|
-
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 =
|
|
15625
|
-
DEBOUNCE_FILE =
|
|
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:
|
|
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(
|
|
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
|
|
19370
|
+
import path27 from "path";
|
|
18082
19371
|
import os10 from "os";
|
|
18083
19372
|
function checkPathSafety(filePath) {
|
|
18084
|
-
const resolved =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 ?
|
|
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(
|
|
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
|
|
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 =
|
|
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 ?
|
|
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
|
|
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 =
|
|
18478
|
-
const dir =
|
|
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
|
|
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 =
|
|
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
|
|
18780
|
-
import { homedir as
|
|
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:
|
|
20103
|
+
const { readFileSync: readFileSync20, existsSync: existsSync24 } = await import("fs");
|
|
18815
20104
|
const { join } = await import("path");
|
|
18816
|
-
const { homedir:
|
|
18817
|
-
const configPath = join(
|
|
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 (
|
|
20109
|
+
if (existsSync24(configPath)) {
|
|
18821
20110
|
try {
|
|
18822
|
-
const raw = JSON.parse(
|
|
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(
|
|
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(
|
|
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:
|
|
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:
|
|
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 ?
|
|
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:
|
|
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
|
|
20014
|
-
import { homedir as
|
|
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:
|
|
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
|
|
22096
|
+
import crypto11 from "crypto";
|
|
20808
22097
|
function deriveWsAuthToken(masterKey) {
|
|
20809
|
-
return Buffer.from(
|
|
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(
|
|
20813
|
-
return
|
|
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
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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 (
|
|
21181
|
-
const raw = JSON.parse(
|
|
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:
|
|
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 (
|
|
21809
|
-
const raw = JSON.parse(
|
|
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,
|
|
21991
|
-
const url = `${config.baseUrl}/api/v1${
|
|
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} ${
|
|
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:
|
|
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 =
|
|
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 =
|
|
23941
|
+
daemon = existsSync24(pidPath) ? "running" : "stopped";
|
|
22653
23942
|
} catch {
|
|
22654
23943
|
}
|
|
22655
23944
|
let version = "unknown";
|
|
22656
23945
|
try {
|
|
22657
|
-
const { readFileSync:
|
|
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(
|
|
23950
|
+
const pkg = JSON.parse(readFileSync20(pkgPath, "utf8"));
|
|
22662
23951
|
version = pkg.version;
|
|
22663
23952
|
} catch {
|
|
22664
23953
|
try {
|
|
22665
|
-
const { readFileSync:
|
|
23954
|
+
const { readFileSync: readFileSync20 } = await import("fs");
|
|
22666
23955
|
const { join: joinPath } = await import("path");
|
|
22667
|
-
const pkg = JSON.parse(
|
|
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
|
|
23275
|
-
import
|
|
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 =
|
|
23340
|
-
const settingsPath =
|
|
23341
|
-
const hasClaudeCode =
|
|
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 =
|
|
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 =
|
|
23383
|
-
const settingsPath =
|
|
23384
|
-
const claudeJsonPath =
|
|
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 (
|
|
24675
|
+
if (existsSync23(settingsPath)) {
|
|
23387
24676
|
let settings;
|
|
23388
24677
|
try {
|
|
23389
|
-
settings = JSON.parse(
|
|
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 (
|
|
24704
|
+
if (existsSync23(claudeJsonPath)) {
|
|
23416
24705
|
let claudeJson;
|
|
23417
24706
|
try {
|
|
23418
|
-
claudeJson = JSON.parse(
|
|
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 =
|
|
23438
|
-
if (
|
|
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 =
|
|
23456
|
-
const settingsPath =
|
|
23457
|
-
const claudeJsonPath =
|
|
23458
|
-
const exeOsDir =
|
|
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 (
|
|
24751
|
+
if (existsSync23(settingsPath)) {
|
|
23463
24752
|
try {
|
|
23464
|
-
settings = JSON.parse(
|
|
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
|
-
|
|
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 (
|
|
23510
|
-
const raw =
|
|
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
|
-
|
|
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 =
|
|
23540
|
-
if (
|
|
24828
|
+
const skillsDir = path35.join(claudeDir, "skills");
|
|
24829
|
+
if (existsSync23(skillsDir)) {
|
|
23541
24830
|
let skillCount = 0;
|
|
23542
24831
|
try {
|
|
23543
|
-
const entries =
|
|
24832
|
+
const entries = readdirSync7(skillsDir);
|
|
23544
24833
|
for (const entry of entries) {
|
|
23545
24834
|
if (entry.startsWith("exe")) {
|
|
23546
|
-
const fullPath =
|
|
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 =
|
|
23559
|
-
if (
|
|
23560
|
-
const content =
|
|
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)
|
|
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 =
|
|
23573
|
-
if (
|
|
24861
|
+
const agentsDir = path35.join(claudeDir, "agents");
|
|
24862
|
+
if (existsSync23(agentsDir)) {
|
|
23574
24863
|
let agentCount = 0;
|
|
23575
24864
|
try {
|
|
23576
|
-
const entries =
|
|
24865
|
+
const entries = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
|
|
23577
24866
|
let knownNames = /* @__PURE__ */ new Set();
|
|
23578
|
-
const rosterPath =
|
|
23579
|
-
if (
|
|
24867
|
+
const rosterPath = path35.join(exeOsDir, "exe-employees.json");
|
|
24868
|
+
if (existsSync23(rosterPath)) {
|
|
23580
24869
|
try {
|
|
23581
|
-
const roster = JSON.parse(
|
|
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(
|
|
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 =
|
|
23601
|
-
if (
|
|
24889
|
+
const projectsDir = path35.join(claudeDir, "projects");
|
|
24890
|
+
if (existsSync23(projectsDir)) {
|
|
23602
24891
|
let projectCount = 0;
|
|
23603
24892
|
try {
|
|
23604
|
-
const projects =
|
|
24893
|
+
const projects = readdirSync7(projectsDir);
|
|
23605
24894
|
for (const proj of projects) {
|
|
23606
|
-
const projSettings =
|
|
23607
|
-
if (!
|
|
24895
|
+
const projSettings = path35.join(projectsDir, proj, "settings.json");
|
|
24896
|
+
if (!existsSync23(projSettings)) continue;
|
|
23608
24897
|
try {
|
|
23609
|
-
const pSettings = JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
24932
|
+
const binDir = path35.dirname(exeBinPath);
|
|
23644
24933
|
let symlinkCount = 0;
|
|
23645
|
-
const rosterPath =
|
|
23646
|
-
if (
|
|
23647
|
-
const roster = JSON.parse(
|
|
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 =
|
|
23652
|
-
if (
|
|
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 &&
|
|
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 =
|
|
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 =
|
|
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
|
}
|