@askexenow/exe-os 0.8.33 → 0.8.37
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/backfill-conversations.js +341 -349
- package/dist/bin/backfill-responses.js +81 -13
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1737 -1117
- package/dist/bin/exe-assign.js +89 -19
- package/dist/bin/exe-boot.js +951 -101
- package/dist/bin/exe-call.js +61 -2
- package/dist/bin/exe-dispatch.js +61 -13
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +71 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +178 -45
- package/dist/bin/exe-heartbeat.js +79 -14
- package/dist/bin/exe-kill.js +71 -3
- package/dist/bin/exe-launch-agent.js +148 -14
- package/dist/bin/exe-link.js +1437 -0
- package/dist/bin/exe-new-employee.js +98 -13
- package/dist/bin/exe-pending-messages.js +74 -8
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +77 -11
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +73 -5
- package/dist/bin/exe-search.js +88 -14
- package/dist/bin/exe-session-cleanup.js +102 -28
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +80 -5
- package/dist/bin/graph-backfill.js +71 -3
- package/dist/bin/graph-export.js +71 -3
- package/dist/bin/install.js +38 -8
- package/dist/bin/scan-tasks.js +80 -5
- package/dist/bin/setup.js +128 -10
- package/dist/bin/shard-migrate.js +71 -3
- package/dist/bin/wiki-sync.js +71 -3
- package/dist/gateway/index.js +179 -46
- package/dist/hooks/bug-report-worker.js +254 -28
- package/dist/hooks/commit-complete.js +80 -5
- package/dist/hooks/error-recall.js +89 -15
- package/dist/hooks/exe-heartbeat-hook.js +1 -1
- package/dist/hooks/ingest-worker.js +185 -51
- package/dist/hooks/ingest.js +1 -1
- package/dist/hooks/instructions-loaded.js +81 -6
- package/dist/hooks/notification.js +81 -6
- package/dist/hooks/post-compact.js +81 -6
- package/dist/hooks/pre-compact.js +81 -6
- package/dist/hooks/pre-tool-use.js +423 -196
- package/dist/hooks/prompt-ingest-worker.js +91 -23
- package/dist/hooks/prompt-submit.js +159 -45
- package/dist/hooks/response-ingest-worker.js +96 -23
- package/dist/hooks/session-end.js +81 -6
- package/dist/hooks/session-start.js +89 -15
- package/dist/hooks/stop.js +81 -6
- package/dist/hooks/subagent-stop.js +81 -6
- package/dist/hooks/summary-worker.js +807 -55
- package/dist/index.js +198 -60
- package/dist/lib/cloud-sync.js +703 -18
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +64 -2
- package/dist/lib/device-registry.js +70 -3
- package/dist/lib/employee-templates.js +26 -0
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +207 -74
- package/dist/lib/hybrid-search.js +88 -14
- package/dist/lib/identity-templates.js +51 -0
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +65 -17
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +63 -3
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/status-brief.js +63 -5
- package/dist/lib/store.js +73 -4
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +95 -28
- package/dist/lib/tmux-routing.js +92 -23
- package/dist/mcp/server.js +800 -74
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +198 -31
- package/dist/mcp/tools/deactivate-behavior.js +4 -4
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +19 -9
- package/dist/mcp/tools/send-message.js +69 -21
- package/dist/mcp/tools/update-task.js +28 -18
- package/dist/runtime/index.js +166 -28
- package/dist/tui/App.js +193 -40
- package/package.json +7 -3
- package/src/commands/exe/afk.md +116 -0
- package/src/commands/exe/rename.md +12 -0
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -277,6 +277,61 @@ var init_memory = __esm({
|
|
|
277
277
|
}
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
+
// src/lib/db-retry.ts
|
|
281
|
+
function isBusyError(err) {
|
|
282
|
+
if (err instanceof Error) {
|
|
283
|
+
const msg = err.message.toLowerCase();
|
|
284
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function delay(ms) {
|
|
289
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
290
|
+
}
|
|
291
|
+
async function retryOnBusy(fn, label) {
|
|
292
|
+
let lastError;
|
|
293
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
294
|
+
try {
|
|
295
|
+
return await fn();
|
|
296
|
+
} catch (err) {
|
|
297
|
+
lastError = err;
|
|
298
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
302
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
303
|
+
process.stderr.write(
|
|
304
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
305
|
+
`
|
|
306
|
+
);
|
|
307
|
+
await delay(backoff + jitter);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
throw lastError;
|
|
311
|
+
}
|
|
312
|
+
function wrapWithRetry(client) {
|
|
313
|
+
return new Proxy(client, {
|
|
314
|
+
get(target, prop, receiver) {
|
|
315
|
+
if (prop === "execute") {
|
|
316
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
317
|
+
}
|
|
318
|
+
if (prop === "batch") {
|
|
319
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
320
|
+
}
|
|
321
|
+
return Reflect.get(target, prop, receiver);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
326
|
+
var init_db_retry = __esm({
|
|
327
|
+
"src/lib/db-retry.ts"() {
|
|
328
|
+
"use strict";
|
|
329
|
+
MAX_RETRIES = 3;
|
|
330
|
+
BASE_DELAY_MS = 200;
|
|
331
|
+
MAX_JITTER_MS = 300;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
280
335
|
// src/lib/database.ts
|
|
281
336
|
var database_exports = {};
|
|
282
337
|
__export(database_exports, {
|
|
@@ -284,6 +339,7 @@ __export(database_exports, {
|
|
|
284
339
|
disposeTurso: () => disposeTurso,
|
|
285
340
|
ensureSchema: () => ensureSchema,
|
|
286
341
|
getClient: () => getClient,
|
|
342
|
+
getRawClient: () => getRawClient,
|
|
287
343
|
initDatabase: () => initDatabase,
|
|
288
344
|
initTurso: () => initTurso,
|
|
289
345
|
isInitialized: () => isInitialized
|
|
@@ -293,6 +349,7 @@ async function initDatabase(config) {
|
|
|
293
349
|
if (_client) {
|
|
294
350
|
_client.close();
|
|
295
351
|
_client = null;
|
|
352
|
+
_resilientClient = null;
|
|
296
353
|
}
|
|
297
354
|
const opts = {
|
|
298
355
|
url: `file:${config.dbPath}`
|
|
@@ -301,20 +358,27 @@ async function initDatabase(config) {
|
|
|
301
358
|
opts.encryptionKey = config.encryptionKey;
|
|
302
359
|
}
|
|
303
360
|
_client = createClient(opts);
|
|
361
|
+
_resilientClient = wrapWithRetry(_client);
|
|
304
362
|
}
|
|
305
363
|
function isInitialized() {
|
|
306
364
|
return _client !== null;
|
|
307
365
|
}
|
|
308
366
|
function getClient() {
|
|
367
|
+
if (!_resilientClient) {
|
|
368
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
369
|
+
}
|
|
370
|
+
return _resilientClient;
|
|
371
|
+
}
|
|
372
|
+
function getRawClient() {
|
|
309
373
|
if (!_client) {
|
|
310
374
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
311
375
|
}
|
|
312
376
|
return _client;
|
|
313
377
|
}
|
|
314
378
|
async function ensureSchema() {
|
|
315
|
-
const client =
|
|
379
|
+
const client = getRawClient();
|
|
316
380
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
317
|
-
await client.execute("PRAGMA busy_timeout =
|
|
381
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
318
382
|
try {
|
|
319
383
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
320
384
|
} catch {
|
|
@@ -1107,13 +1171,16 @@ async function disposeDatabase() {
|
|
|
1107
1171
|
if (_client) {
|
|
1108
1172
|
_client.close();
|
|
1109
1173
|
_client = null;
|
|
1174
|
+
_resilientClient = null;
|
|
1110
1175
|
}
|
|
1111
1176
|
}
|
|
1112
|
-
var _client, initTurso, disposeTurso;
|
|
1177
|
+
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1113
1178
|
var init_database = __esm({
|
|
1114
1179
|
"src/lib/database.ts"() {
|
|
1115
1180
|
"use strict";
|
|
1181
|
+
init_db_retry();
|
|
1116
1182
|
_client = null;
|
|
1183
|
+
_resilientClient = null;
|
|
1117
1184
|
initTurso = initDatabase;
|
|
1118
1185
|
disposeTurso = disposeDatabase;
|
|
1119
1186
|
}
|
|
@@ -1323,7 +1390,7 @@ function listShards() {
|
|
|
1323
1390
|
}
|
|
1324
1391
|
async function ensureShardSchema(client) {
|
|
1325
1392
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1326
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1393
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1327
1394
|
try {
|
|
1328
1395
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1329
1396
|
} catch {
|
|
@@ -1584,7 +1651,8 @@ async function writeMemory(record) {
|
|
|
1584
1651
|
has_error: record.has_error ? 1 : 0,
|
|
1585
1652
|
raw_text: record.raw_text,
|
|
1586
1653
|
vector: record.vector,
|
|
1587
|
-
version:
|
|
1654
|
+
version: 0,
|
|
1655
|
+
// Placeholder — assigned atomically at flush time
|
|
1588
1656
|
task_id: record.task_id ?? null,
|
|
1589
1657
|
importance: record.importance ?? 5,
|
|
1590
1658
|
status: record.status ?? "active",
|
|
@@ -1618,6 +1686,13 @@ async function flushBatch() {
|
|
|
1618
1686
|
_flushing = true;
|
|
1619
1687
|
try {
|
|
1620
1688
|
const batch = _pendingRecords.slice(0);
|
|
1689
|
+
const client = getClient();
|
|
1690
|
+
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1691
|
+
let baseVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1692
|
+
for (const row of batch) {
|
|
1693
|
+
row.version = baseVersion++;
|
|
1694
|
+
}
|
|
1695
|
+
_nextVersion = baseVersion;
|
|
1621
1696
|
const buildStmt = (row) => {
|
|
1622
1697
|
const hasVector = row.vector !== null;
|
|
1623
1698
|
const taskId = row.task_id ?? null;
|
|
@@ -2296,8 +2371,8 @@ function drainQueue(isSessionBusy2, sendKeys) {
|
|
|
2296
2371
|
} catch {
|
|
2297
2372
|
}
|
|
2298
2373
|
item.attempts++;
|
|
2299
|
-
if (item.attempts >=
|
|
2300
|
-
logQueue(`FAILED \u2192 ${item.targetSession} (${
|
|
2374
|
+
if (item.attempts >= MAX_RETRIES2) {
|
|
2375
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
|
|
2301
2376
|
failed++;
|
|
2302
2377
|
continue;
|
|
2303
2378
|
}
|
|
@@ -2330,12 +2405,12 @@ function logQueue(msg) {
|
|
|
2330
2405
|
} catch {
|
|
2331
2406
|
}
|
|
2332
2407
|
}
|
|
2333
|
-
var QUEUE_PATH,
|
|
2408
|
+
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
2334
2409
|
var init_intercom_queue = __esm({
|
|
2335
2410
|
"src/lib/intercom-queue.ts"() {
|
|
2336
2411
|
"use strict";
|
|
2337
2412
|
QUEUE_PATH = path5.join(os3.homedir(), ".exe-os", "intercom-queue.json");
|
|
2338
|
-
|
|
2413
|
+
MAX_RETRIES2 = 5;
|
|
2339
2414
|
TTL_MS = 60 * 60 * 1e3;
|
|
2340
2415
|
INTERCOM_LOG = path5.join(os3.homedir(), ".exe-os", "intercom.log");
|
|
2341
2416
|
}
|
|
@@ -2343,7 +2418,7 @@ var init_intercom_queue = __esm({
|
|
|
2343
2418
|
|
|
2344
2419
|
// src/lib/employees.ts
|
|
2345
2420
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
2346
|
-
import { existsSync as existsSync6, symlinkSync, readlinkSync } from "fs";
|
|
2421
|
+
import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
|
|
2347
2422
|
import { execSync as execSync4 } from "child_process";
|
|
2348
2423
|
import path6 from "path";
|
|
2349
2424
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
@@ -2357,20 +2432,35 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
2357
2432
|
return [];
|
|
2358
2433
|
}
|
|
2359
2434
|
}
|
|
2435
|
+
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
2436
|
+
if (!existsSync6(employeesPath)) return [];
|
|
2437
|
+
try {
|
|
2438
|
+
return JSON.parse(readFileSync4(employeesPath, "utf-8"));
|
|
2439
|
+
} catch {
|
|
2440
|
+
return [];
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2360
2443
|
function getEmployee(employees, name) {
|
|
2361
2444
|
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
2362
2445
|
}
|
|
2363
|
-
|
|
2446
|
+
function isMultiInstance(agentName, employees) {
|
|
2447
|
+
const roster = employees ?? loadEmployeesSync();
|
|
2448
|
+
const emp = getEmployee(roster, agentName);
|
|
2449
|
+
if (!emp) return false;
|
|
2450
|
+
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
2451
|
+
}
|
|
2452
|
+
var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
|
|
2364
2453
|
var init_employees = __esm({
|
|
2365
2454
|
"src/lib/employees.ts"() {
|
|
2366
2455
|
"use strict";
|
|
2367
2456
|
init_config();
|
|
2368
2457
|
EMPLOYEES_PATH = path6.join(EXE_AI_DIR, "exe-employees.json");
|
|
2458
|
+
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
2369
2459
|
}
|
|
2370
2460
|
});
|
|
2371
2461
|
|
|
2372
2462
|
// src/lib/license.ts
|
|
2373
|
-
import { readFileSync as
|
|
2463
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
2374
2464
|
import { randomUUID } from "crypto";
|
|
2375
2465
|
import path7 from "path";
|
|
2376
2466
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -2393,12 +2483,12 @@ var init_license = __esm({
|
|
|
2393
2483
|
});
|
|
2394
2484
|
|
|
2395
2485
|
// src/lib/plan-limits.ts
|
|
2396
|
-
import { readFileSync as
|
|
2486
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
|
|
2397
2487
|
import path8 from "path";
|
|
2398
2488
|
function getLicenseSync() {
|
|
2399
2489
|
try {
|
|
2400
2490
|
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
2401
|
-
const raw = JSON.parse(
|
|
2491
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
|
|
2402
2492
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2403
2493
|
const parts = raw.token.split(".");
|
|
2404
2494
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2437,7 +2527,7 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2437
2527
|
let count = 0;
|
|
2438
2528
|
try {
|
|
2439
2529
|
if (existsSync8(filePath)) {
|
|
2440
|
-
const raw =
|
|
2530
|
+
const raw = readFileSync6(filePath, "utf8");
|
|
2441
2531
|
const employees = JSON.parse(raw);
|
|
2442
2532
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2443
2533
|
}
|
|
@@ -2475,7 +2565,7 @@ import crypto2 from "crypto";
|
|
|
2475
2565
|
import path9 from "path";
|
|
2476
2566
|
import os4 from "os";
|
|
2477
2567
|
import {
|
|
2478
|
-
readFileSync as
|
|
2568
|
+
readFileSync as readFileSync7,
|
|
2479
2569
|
readdirSync,
|
|
2480
2570
|
unlinkSync,
|
|
2481
2571
|
existsSync as existsSync9,
|
|
@@ -2631,7 +2721,7 @@ import crypto4 from "crypto";
|
|
|
2631
2721
|
import path10 from "path";
|
|
2632
2722
|
import { execSync as execSync5 } from "child_process";
|
|
2633
2723
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
2634
|
-
import { existsSync as existsSync10, readFileSync as
|
|
2724
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
2635
2725
|
async function writeCheckpoint(input) {
|
|
2636
2726
|
const client = getClient();
|
|
2637
2727
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -3008,7 +3098,7 @@ async function ensureGitignoreExe(baseDir) {
|
|
|
3008
3098
|
const gitignorePath = path10.join(baseDir, ".gitignore");
|
|
3009
3099
|
try {
|
|
3010
3100
|
if (existsSync10(gitignorePath)) {
|
|
3011
|
-
const content =
|
|
3101
|
+
const content = readFileSync8(gitignorePath, "utf-8");
|
|
3012
3102
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
3013
3103
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
3014
3104
|
} else {
|
|
@@ -3483,7 +3573,7 @@ async function dispatchTaskToEmployee(input) {
|
|
|
3483
3573
|
} else {
|
|
3484
3574
|
const projectDir = input.projectDir ?? process.cwd();
|
|
3485
3575
|
const result = ensureEmployee(input.assignedTo, exeSession, projectDir, {
|
|
3486
|
-
autoInstance: input.assignedTo
|
|
3576
|
+
autoInstance: isMultiInstance(input.assignedTo)
|
|
3487
3577
|
});
|
|
3488
3578
|
if (result.status === "failed") {
|
|
3489
3579
|
process.stderr.write(
|
|
@@ -3518,6 +3608,7 @@ var init_tasks_notify = __esm({
|
|
|
3518
3608
|
init_session_key();
|
|
3519
3609
|
init_notifications();
|
|
3520
3610
|
init_transport();
|
|
3611
|
+
init_employees();
|
|
3521
3612
|
}
|
|
3522
3613
|
});
|
|
3523
3614
|
|
|
@@ -4271,6 +4362,7 @@ var init_capacity_monitor = __esm({
|
|
|
4271
4362
|
// src/lib/tmux-routing.ts
|
|
4272
4363
|
var tmux_routing_exports = {};
|
|
4273
4364
|
__export(tmux_routing_exports, {
|
|
4365
|
+
acquireSpawnLock: () => acquireSpawnLock,
|
|
4274
4366
|
employeeSessionName: () => employeeSessionName,
|
|
4275
4367
|
ensureEmployee: () => ensureEmployee,
|
|
4276
4368
|
extractRootExe: () => extractRootExe,
|
|
@@ -4285,16 +4377,53 @@ __export(tmux_routing_exports, {
|
|
|
4285
4377
|
notifyParentExe: () => notifyParentExe,
|
|
4286
4378
|
parseParentExe: () => parseParentExe,
|
|
4287
4379
|
registerParentExe: () => registerParentExe,
|
|
4380
|
+
releaseSpawnLock: () => releaseSpawnLock,
|
|
4288
4381
|
resolveExeSession: () => resolveExeSession,
|
|
4289
4382
|
sendIntercom: () => sendIntercom,
|
|
4290
4383
|
spawnEmployee: () => spawnEmployee,
|
|
4291
4384
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
4292
4385
|
});
|
|
4293
4386
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
4294
|
-
import { readFileSync as
|
|
4387
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
4295
4388
|
import path15 from "path";
|
|
4296
4389
|
import os5 from "os";
|
|
4297
4390
|
import { fileURLToPath } from "url";
|
|
4391
|
+
import { unlinkSync as unlinkSync4 } from "fs";
|
|
4392
|
+
function spawnLockPath(sessionName) {
|
|
4393
|
+
return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
4394
|
+
}
|
|
4395
|
+
function isProcessAlive(pid) {
|
|
4396
|
+
try {
|
|
4397
|
+
process.kill(pid, 0);
|
|
4398
|
+
return true;
|
|
4399
|
+
} catch {
|
|
4400
|
+
return false;
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
function acquireSpawnLock(sessionName) {
|
|
4404
|
+
if (!existsSync12(SPAWN_LOCK_DIR)) {
|
|
4405
|
+
mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
|
|
4406
|
+
}
|
|
4407
|
+
const lockFile = spawnLockPath(sessionName);
|
|
4408
|
+
if (existsSync12(lockFile)) {
|
|
4409
|
+
try {
|
|
4410
|
+
const lock = JSON.parse(readFileSync9(lockFile, "utf8"));
|
|
4411
|
+
const age = Date.now() - lock.timestamp;
|
|
4412
|
+
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
4413
|
+
return false;
|
|
4414
|
+
}
|
|
4415
|
+
} catch {
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
writeFileSync5(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
4419
|
+
return true;
|
|
4420
|
+
}
|
|
4421
|
+
function releaseSpawnLock(sessionName) {
|
|
4422
|
+
try {
|
|
4423
|
+
unlinkSync4(spawnLockPath(sessionName));
|
|
4424
|
+
} catch {
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4298
4427
|
function resolveBehaviorsExporterScript() {
|
|
4299
4428
|
try {
|
|
4300
4429
|
const thisFile = fileURLToPath(import.meta.url);
|
|
@@ -4358,7 +4487,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4358
4487
|
}
|
|
4359
4488
|
function getParentExe(sessionKey) {
|
|
4360
4489
|
try {
|
|
4361
|
-
const data = JSON.parse(
|
|
4490
|
+
const data = JSON.parse(readFileSync9(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
4362
4491
|
return data.parentExe || null;
|
|
4363
4492
|
} catch {
|
|
4364
4493
|
return null;
|
|
@@ -4366,7 +4495,7 @@ function getParentExe(sessionKey) {
|
|
|
4366
4495
|
}
|
|
4367
4496
|
function getDispatchedBy(sessionKey) {
|
|
4368
4497
|
try {
|
|
4369
|
-
const data = JSON.parse(
|
|
4498
|
+
const data = JSON.parse(readFileSync9(
|
|
4370
4499
|
path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
4371
4500
|
"utf8"
|
|
4372
4501
|
));
|
|
@@ -4393,10 +4522,10 @@ function isEmployeeAlive(sessionName) {
|
|
|
4393
4522
|
}
|
|
4394
4523
|
function findFreeInstance(employeeName, exeSession, maxInstances = 10, isAlive = isEmployeeAlive) {
|
|
4395
4524
|
const base = employeeSessionName(employeeName, exeSession);
|
|
4396
|
-
if (!isAlive(base)) return 0;
|
|
4525
|
+
if (!isAlive(base) && acquireSpawnLock(base)) return 0;
|
|
4397
4526
|
for (let i = 2; i <= maxInstances; i++) {
|
|
4398
4527
|
const candidate = employeeSessionName(employeeName, exeSession, i);
|
|
4399
|
-
if (!isAlive(candidate)) return i;
|
|
4528
|
+
if (!isAlive(candidate) && acquireSpawnLock(candidate)) return i;
|
|
4400
4529
|
}
|
|
4401
4530
|
return null;
|
|
4402
4531
|
}
|
|
@@ -4429,7 +4558,7 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
4429
4558
|
function readDebounceState() {
|
|
4430
4559
|
try {
|
|
4431
4560
|
if (!existsSync12(DEBOUNCE_FILE)) return {};
|
|
4432
|
-
return JSON.parse(
|
|
4561
|
+
return JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
|
|
4433
4562
|
} catch {
|
|
4434
4563
|
return {};
|
|
4435
4564
|
}
|
|
@@ -4629,7 +4758,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4629
4758
|
const claudeJsonPath = path15.join(os5.homedir(), ".claude.json");
|
|
4630
4759
|
let claudeJson = {};
|
|
4631
4760
|
try {
|
|
4632
|
-
claudeJson = JSON.parse(
|
|
4761
|
+
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
4633
4762
|
} catch {
|
|
4634
4763
|
}
|
|
4635
4764
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -4647,7 +4776,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4647
4776
|
const settingsPath = path15.join(projSettingsDir, "settings.json");
|
|
4648
4777
|
let settings = {};
|
|
4649
4778
|
try {
|
|
4650
|
-
settings = JSON.parse(
|
|
4779
|
+
settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
|
|
4651
4780
|
} catch {
|
|
4652
4781
|
}
|
|
4653
4782
|
const perms = settings.permissions ?? {};
|
|
@@ -4760,6 +4889,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4760
4889
|
command: spawnCommand
|
|
4761
4890
|
});
|
|
4762
4891
|
if (spawnResult.error) {
|
|
4892
|
+
releaseSpawnLock(sessionName);
|
|
4763
4893
|
return { sessionName, error: `tmux new-session failed: ${spawnResult.error}` };
|
|
4764
4894
|
}
|
|
4765
4895
|
transport.pipeLog(sessionName, logFile);
|
|
@@ -4797,6 +4927,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4797
4927
|
}
|
|
4798
4928
|
}
|
|
4799
4929
|
if (!booted) {
|
|
4930
|
+
releaseSpawnLock(sessionName);
|
|
4800
4931
|
return { sessionName, error: `${useExeAgent ? "exe-agent" : "claude"} did not boot within 15s` };
|
|
4801
4932
|
}
|
|
4802
4933
|
if (!useExeAgent) {
|
|
@@ -4813,9 +4944,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4813
4944
|
pid: 0,
|
|
4814
4945
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4815
4946
|
});
|
|
4947
|
+
releaseSpawnLock(sessionName);
|
|
4816
4948
|
return { sessionName };
|
|
4817
4949
|
}
|
|
4818
|
-
var SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
4950
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
4819
4951
|
var init_tmux_routing = __esm({
|
|
4820
4952
|
"src/lib/tmux-routing.ts"() {
|
|
4821
4953
|
"use strict";
|
|
@@ -4827,6 +4959,7 @@ var init_tmux_routing = __esm({
|
|
|
4827
4959
|
init_provider_table();
|
|
4828
4960
|
init_intercom_queue();
|
|
4829
4961
|
init_plan_limits();
|
|
4962
|
+
SPAWN_LOCK_DIR = path15.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
4830
4963
|
SESSION_CACHE = path15.join(os5.homedir(), ".exe-os", "session-cache");
|
|
4831
4964
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4832
4965
|
VERIFY_PANE_LINES = 200;
|
|
@@ -5319,7 +5452,7 @@ __export(agent_signals_exports, {
|
|
|
5319
5452
|
hasOpenTasks: () => hasOpenTasks,
|
|
5320
5453
|
hasUnreadInbox: () => hasUnreadInbox
|
|
5321
5454
|
});
|
|
5322
|
-
import { readFileSync as
|
|
5455
|
+
import { readFileSync as readFileSync10, existsSync as existsSync13 } from "fs";
|
|
5323
5456
|
import os6 from "os";
|
|
5324
5457
|
import path16 from "path";
|
|
5325
5458
|
async function hasOpenTasks(client, agentId) {
|
|
@@ -5364,7 +5497,7 @@ async function hasUnreadInbox(client, agentId) {
|
|
|
5364
5497
|
function hadRecentIntercomAck(sessionName, windowMs, nowMs = Date.now(), intercomLog = path16.join(os6.homedir(), ".exe-os", "intercom.log")) {
|
|
5365
5498
|
if (!existsSync13(intercomLog)) return false;
|
|
5366
5499
|
try {
|
|
5367
|
-
const raw =
|
|
5500
|
+
const raw = readFileSync10(intercomLog, "utf8");
|
|
5368
5501
|
const lines = raw.split("\n");
|
|
5369
5502
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
5370
5503
|
const line = lines[i];
|
|
@@ -5796,11 +5929,11 @@ ${synthesisText}`;
|
|
|
5796
5929
|
}
|
|
5797
5930
|
const insertSql = vector ? `INSERT INTO memories
|
|
5798
5931
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
5799
|
-
tool_name, project_name, has_error, raw_text, vector, version, consolidated)
|
|
5800
|
-
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, vector32(?), 0, 1)` : `INSERT INTO memories
|
|
5932
|
+
tool_name, project_name, has_error, raw_text, vector, version, consolidated, importance)
|
|
5933
|
+
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, vector32(?), 0, 1, 9)` : `INSERT INTO memories
|
|
5801
5934
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
5802
|
-
tool_name, project_name, has_error, raw_text, vector, version, consolidated)
|
|
5803
|
-
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, NULL, 0, 1)`;
|
|
5935
|
+
tool_name, project_name, has_error, raw_text, vector, version, consolidated, importance)
|
|
5936
|
+
VALUES (?, ?, 'consolidation', 'daemon-consolidation', ?, 'consolidation', ?, 0, ?, NULL, 0, 1, 9)`;
|
|
5804
5937
|
const insertArgs = vector ? [consolidatedId, cluster.agentId, now, cluster.projectName, rawText, vectorToBlob(vector)] : [consolidatedId, cluster.agentId, now, cluster.projectName, rawText];
|
|
5805
5938
|
await client.execute({ sql: insertSql, args: insertArgs });
|
|
5806
5939
|
const sourceIds = cluster.memories.map((m) => m.id);
|
|
@@ -6047,7 +6180,7 @@ var init_consolidation = __esm({
|
|
|
6047
6180
|
import net from "net";
|
|
6048
6181
|
import { spawn } from "child_process";
|
|
6049
6182
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6050
|
-
import { existsSync as existsSync14, unlinkSync as
|
|
6183
|
+
import { existsSync as existsSync14, unlinkSync as unlinkSync5, readFileSync as readFileSync11, openSync, closeSync, statSync } from "fs";
|
|
6051
6184
|
import path17 from "path";
|
|
6052
6185
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6053
6186
|
function handleData(chunk) {
|
|
@@ -6072,7 +6205,7 @@ function handleData(chunk) {
|
|
|
6072
6205
|
function cleanupStaleFiles() {
|
|
6073
6206
|
if (existsSync14(PID_PATH)) {
|
|
6074
6207
|
try {
|
|
6075
|
-
const pid = parseInt(
|
|
6208
|
+
const pid = parseInt(readFileSync11(PID_PATH, "utf8").trim(), 10);
|
|
6076
6209
|
if (pid > 0) {
|
|
6077
6210
|
try {
|
|
6078
6211
|
process.kill(pid, 0);
|
|
@@ -6083,11 +6216,11 @@ function cleanupStaleFiles() {
|
|
|
6083
6216
|
} catch {
|
|
6084
6217
|
}
|
|
6085
6218
|
try {
|
|
6086
|
-
|
|
6219
|
+
unlinkSync5(PID_PATH);
|
|
6087
6220
|
} catch {
|
|
6088
6221
|
}
|
|
6089
6222
|
try {
|
|
6090
|
-
|
|
6223
|
+
unlinkSync5(SOCKET_PATH);
|
|
6091
6224
|
} catch {
|
|
6092
6225
|
}
|
|
6093
6226
|
}
|
|
@@ -6139,7 +6272,7 @@ function spawnDaemon() {
|
|
|
6139
6272
|
}
|
|
6140
6273
|
}
|
|
6141
6274
|
}
|
|
6142
|
-
function
|
|
6275
|
+
function acquireSpawnLock2() {
|
|
6143
6276
|
try {
|
|
6144
6277
|
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
6145
6278
|
closeSync(fd);
|
|
@@ -6149,7 +6282,7 @@ function acquireSpawnLock() {
|
|
|
6149
6282
|
const stat = statSync(SPAWN_LOCK_PATH);
|
|
6150
6283
|
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
6151
6284
|
try {
|
|
6152
|
-
|
|
6285
|
+
unlinkSync5(SPAWN_LOCK_PATH);
|
|
6153
6286
|
} catch {
|
|
6154
6287
|
}
|
|
6155
6288
|
try {
|
|
@@ -6164,9 +6297,9 @@ function acquireSpawnLock() {
|
|
|
6164
6297
|
return false;
|
|
6165
6298
|
}
|
|
6166
6299
|
}
|
|
6167
|
-
function
|
|
6300
|
+
function releaseSpawnLock2() {
|
|
6168
6301
|
try {
|
|
6169
|
-
|
|
6302
|
+
unlinkSync5(SPAWN_LOCK_PATH);
|
|
6170
6303
|
} catch {
|
|
6171
6304
|
}
|
|
6172
6305
|
}
|
|
@@ -6211,20 +6344,20 @@ function connectToSocket() {
|
|
|
6211
6344
|
async function connectEmbedDaemon() {
|
|
6212
6345
|
if (_socket && _connected) return true;
|
|
6213
6346
|
if (await connectToSocket()) return true;
|
|
6214
|
-
if (
|
|
6347
|
+
if (acquireSpawnLock2()) {
|
|
6215
6348
|
try {
|
|
6216
6349
|
cleanupStaleFiles();
|
|
6217
6350
|
spawnDaemon();
|
|
6218
6351
|
} finally {
|
|
6219
|
-
|
|
6352
|
+
releaseSpawnLock2();
|
|
6220
6353
|
}
|
|
6221
6354
|
}
|
|
6222
6355
|
const start = Date.now();
|
|
6223
|
-
let
|
|
6356
|
+
let delay2 = 100;
|
|
6224
6357
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
6225
|
-
await new Promise((r) => setTimeout(r,
|
|
6358
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
6226
6359
|
if (await connectToSocket()) return true;
|
|
6227
|
-
|
|
6360
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
6228
6361
|
}
|
|
6229
6362
|
return false;
|
|
6230
6363
|
}
|
|
@@ -6280,7 +6413,7 @@ function killAndRespawnDaemon() {
|
|
|
6280
6413
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
6281
6414
|
if (existsSync14(PID_PATH)) {
|
|
6282
6415
|
try {
|
|
6283
|
-
const pid = parseInt(
|
|
6416
|
+
const pid = parseInt(readFileSync11(PID_PATH, "utf8").trim(), 10);
|
|
6284
6417
|
if (pid > 0) {
|
|
6285
6418
|
try {
|
|
6286
6419
|
process.kill(pid, "SIGKILL");
|
|
@@ -6297,11 +6430,11 @@ function killAndRespawnDaemon() {
|
|
|
6297
6430
|
_connected = false;
|
|
6298
6431
|
_buffer = "";
|
|
6299
6432
|
try {
|
|
6300
|
-
|
|
6433
|
+
unlinkSync5(PID_PATH);
|
|
6301
6434
|
} catch {
|
|
6302
6435
|
}
|
|
6303
6436
|
try {
|
|
6304
|
-
|
|
6437
|
+
unlinkSync5(SOCKET_PATH);
|
|
6305
6438
|
} catch {
|
|
6306
6439
|
}
|
|
6307
6440
|
spawnDaemon();
|
|
@@ -6316,11 +6449,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
6316
6449
|
`);
|
|
6317
6450
|
killAndRespawnDaemon();
|
|
6318
6451
|
const start = Date.now();
|
|
6319
|
-
let
|
|
6452
|
+
let delay2 = 200;
|
|
6320
6453
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
6321
|
-
await new Promise((r) => setTimeout(r,
|
|
6454
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
6322
6455
|
if (await connectToSocket()) break;
|
|
6323
|
-
|
|
6456
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
6324
6457
|
}
|
|
6325
6458
|
if (!_connected) return null;
|
|
6326
6459
|
}
|
|
@@ -6332,11 +6465,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
6332
6465
|
`);
|
|
6333
6466
|
killAndRespawnDaemon();
|
|
6334
6467
|
const start = Date.now();
|
|
6335
|
-
let
|
|
6468
|
+
let delay2 = 200;
|
|
6336
6469
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
6337
|
-
await new Promise((r) => setTimeout(r,
|
|
6470
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
6338
6471
|
if (await connectToSocket()) break;
|
|
6339
|
-
|
|
6472
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
6340
6473
|
}
|
|
6341
6474
|
if (!_connected) return null;
|
|
6342
6475
|
const retry = await sendRequest([text], priority);
|
|
@@ -7232,11 +7365,11 @@ __export(update_check_exports, {
|
|
|
7232
7365
|
getRemoteVersion: () => getRemoteVersion
|
|
7233
7366
|
});
|
|
7234
7367
|
import { execSync as execSync11 } from "child_process";
|
|
7235
|
-
import { readFileSync as
|
|
7368
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
7236
7369
|
import path18 from "path";
|
|
7237
7370
|
function getLocalVersion(packageRoot) {
|
|
7238
7371
|
const pkgPath = path18.join(packageRoot, "package.json");
|
|
7239
|
-
const pkg = JSON.parse(
|
|
7372
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
7240
7373
|
return pkg.version;
|
|
7241
7374
|
}
|
|
7242
7375
|
function getRemoteVersion() {
|
|
@@ -7308,12 +7441,12 @@ __export(device_registry_exports, {
|
|
|
7308
7441
|
});
|
|
7309
7442
|
import crypto9 from "crypto";
|
|
7310
7443
|
import os7 from "os";
|
|
7311
|
-
import { readFileSync as
|
|
7444
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, existsSync as existsSync15 } from "fs";
|
|
7312
7445
|
import path19 from "path";
|
|
7313
7446
|
function getDeviceInfo() {
|
|
7314
7447
|
if (existsSync15(DEVICE_JSON_PATH)) {
|
|
7315
7448
|
try {
|
|
7316
|
-
const raw =
|
|
7449
|
+
const raw = readFileSync13(DEVICE_JSON_PATH, "utf8");
|
|
7317
7450
|
const data = JSON.parse(raw);
|
|
7318
7451
|
if (data.deviceId && data.friendlyName && data.hostname) {
|
|
7319
7452
|
return data;
|
|
@@ -7691,7 +7824,7 @@ async function deliverLocalMessage(messageId) {
|
|
|
7691
7824
|
return true;
|
|
7692
7825
|
} catch {
|
|
7693
7826
|
const newRetryCount = msg.retryCount + 1;
|
|
7694
|
-
if (newRetryCount >=
|
|
7827
|
+
if (newRetryCount >= MAX_RETRIES3) {
|
|
7695
7828
|
await markFailed(messageId, "session unavailable after 10 retries");
|
|
7696
7829
|
} else {
|
|
7697
7830
|
await client.execute({
|
|
@@ -7780,7 +7913,7 @@ async function retryPendingMessages() {
|
|
|
7780
7913
|
sql: `SELECT * FROM messages
|
|
7781
7914
|
WHERE status = 'pending' AND retry_count < ?
|
|
7782
7915
|
ORDER BY id`,
|
|
7783
|
-
args: [
|
|
7916
|
+
args: [MAX_RETRIES3]
|
|
7784
7917
|
});
|
|
7785
7918
|
let delivered = 0;
|
|
7786
7919
|
for (const row of result.rows) {
|
|
@@ -7793,13 +7926,13 @@ async function retryPendingMessages() {
|
|
|
7793
7926
|
}
|
|
7794
7927
|
return delivered;
|
|
7795
7928
|
}
|
|
7796
|
-
var
|
|
7929
|
+
var MAX_RETRIES3, _wsClientSend;
|
|
7797
7930
|
var init_messaging = __esm({
|
|
7798
7931
|
"src/lib/messaging.ts"() {
|
|
7799
7932
|
"use strict";
|
|
7800
7933
|
init_database();
|
|
7801
7934
|
init_tmux_routing();
|
|
7802
|
-
|
|
7935
|
+
MAX_RETRIES3 = 10;
|
|
7803
7936
|
_wsClientSend = null;
|
|
7804
7937
|
}
|
|
7805
7938
|
});
|
|
@@ -7808,7 +7941,7 @@ var init_messaging = __esm({
|
|
|
7808
7941
|
init_config();
|
|
7809
7942
|
init_memory();
|
|
7810
7943
|
import net2 from "net";
|
|
7811
|
-
import { writeFileSync as writeFileSync7, unlinkSync as
|
|
7944
|
+
import { writeFileSync as writeFileSync7, unlinkSync as unlinkSync6, mkdirSync as mkdirSync8, existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
7812
7945
|
import path20 from "path";
|
|
7813
7946
|
import { getLlama } from "node-llama-cpp";
|
|
7814
7947
|
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path20.join(EXE_AI_DIR, "exed.sock");
|
|
@@ -7913,11 +8046,11 @@ async function shutdown() {
|
|
|
7913
8046
|
}
|
|
7914
8047
|
_llama = null;
|
|
7915
8048
|
try {
|
|
7916
|
-
|
|
8049
|
+
unlinkSync6(SOCKET_PATH2);
|
|
7917
8050
|
} catch {
|
|
7918
8051
|
}
|
|
7919
8052
|
try {
|
|
7920
|
-
|
|
8053
|
+
unlinkSync6(PID_PATH2);
|
|
7921
8054
|
} catch {
|
|
7922
8055
|
}
|
|
7923
8056
|
process.stderr.write("[exed] Shutdown complete.\n");
|
|
@@ -7955,18 +8088,18 @@ function startServer() {
|
|
|
7955
8088
|
const oldPath = path20.join(path20.dirname(SOCKET_PATH2), oldFile);
|
|
7956
8089
|
try {
|
|
7957
8090
|
if (oldFile.endsWith(".pid")) {
|
|
7958
|
-
const pid = parseInt(
|
|
8091
|
+
const pid = parseInt(readFileSync14(oldPath, "utf8").trim(), 10);
|
|
7959
8092
|
if (pid > 0) try {
|
|
7960
8093
|
process.kill(pid, "SIGKILL");
|
|
7961
8094
|
} catch {
|
|
7962
8095
|
}
|
|
7963
8096
|
}
|
|
7964
|
-
|
|
8097
|
+
unlinkSync6(oldPath);
|
|
7965
8098
|
} catch {
|
|
7966
8099
|
}
|
|
7967
8100
|
}
|
|
7968
8101
|
try {
|
|
7969
|
-
|
|
8102
|
+
unlinkSync6(SOCKET_PATH2);
|
|
7970
8103
|
} catch {
|
|
7971
8104
|
}
|
|
7972
8105
|
const server = net2.createServer((socket) => {
|
|
@@ -8379,7 +8512,7 @@ process.on("SIGTERM", () => void shutdown());
|
|
|
8379
8512
|
function checkExistingDaemon() {
|
|
8380
8513
|
try {
|
|
8381
8514
|
if (!existsSync16(PID_PATH2)) return false;
|
|
8382
|
-
const pid = parseInt(
|
|
8515
|
+
const pid = parseInt(readFileSync14(PID_PATH2, "utf8").trim(), 10);
|
|
8383
8516
|
if (!pid || isNaN(pid)) return false;
|
|
8384
8517
|
process.kill(pid, 0);
|
|
8385
8518
|
process.stderr.write(`[exed] Another daemon is already running (PID ${pid}). Exiting.
|
|
@@ -8392,7 +8525,7 @@ function checkExistingDaemon() {
|
|
|
8392
8525
|
return true;
|
|
8393
8526
|
}
|
|
8394
8527
|
try {
|
|
8395
|
-
|
|
8528
|
+
unlinkSync6(PID_PATH2);
|
|
8396
8529
|
} catch {
|
|
8397
8530
|
}
|
|
8398
8531
|
return false;
|
|
@@ -8555,11 +8688,11 @@ try {
|
|
|
8555
8688
|
process.stderr.write(`[exed] FATAL: ${err instanceof Error ? err.message : String(err)}
|
|
8556
8689
|
`);
|
|
8557
8690
|
try {
|
|
8558
|
-
|
|
8691
|
+
unlinkSync6(SOCKET_PATH2);
|
|
8559
8692
|
} catch {
|
|
8560
8693
|
}
|
|
8561
8694
|
try {
|
|
8562
|
-
|
|
8695
|
+
unlinkSync6(PID_PATH2);
|
|
8563
8696
|
} catch {
|
|
8564
8697
|
}
|
|
8565
8698
|
process.exit(1);
|