@askexenow/exe-os 0.9.16 → 0.9.18
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 +1242 -909
- package/dist/bin/backfill-responses.js +1245 -912
- package/dist/bin/backfill-vectors.js +1244 -906
- package/dist/bin/cleanup-stale-review-tasks.js +1870 -417
- package/dist/bin/cli.js +217 -107
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +62 -0
- package/dist/bin/exe-assign.js +346 -10
- package/dist/bin/exe-boot.js +387 -32
- package/dist/bin/exe-call.js +72 -2
- package/dist/bin/exe-cloud.js +8 -0
- package/dist/bin/exe-dispatch.js +1821 -225
- package/dist/bin/exe-doctor.js +720 -52
- package/dist/bin/exe-export-behaviors.js +1429 -148
- package/dist/bin/exe-forget.js +1408 -34
- package/dist/bin/exe-gateway.js +1629 -1295
- package/dist/bin/exe-heartbeat.js +1899 -448
- package/dist/bin/exe-kill.js +1624 -346
- package/dist/bin/exe-launch-agent.js +726 -90
- package/dist/bin/exe-link.js +27 -8
- package/dist/bin/exe-new-employee.js +75 -9
- package/dist/bin/exe-pending-messages.js +2769 -1316
- package/dist/bin/exe-pending-notifications.js +2829 -1376
- package/dist/bin/exe-pending-reviews.js +2847 -1392
- package/dist/bin/exe-rename.js +89 -8
- package/dist/bin/exe-review.js +1494 -312
- package/dist/bin/exe-search.js +1608 -1300
- package/dist/bin/exe-session-cleanup.js +194 -91
- package/dist/bin/exe-settings.js +10 -2
- package/dist/bin/exe-start-codex.js +769 -120
- package/dist/bin/exe-start-opencode.js +763 -108
- package/dist/bin/exe-status.js +1887 -434
- package/dist/bin/exe-team.js +1782 -324
- package/dist/bin/git-sweep.js +408 -33
- package/dist/bin/graph-backfill.js +681 -27
- package/dist/bin/graph-export.js +1419 -141
- package/dist/bin/install.js +4 -8
- package/dist/bin/intercom-check.js +8641 -0
- package/dist/bin/scan-tasks.js +553 -38
- package/dist/bin/setup.js +82 -10
- package/dist/bin/shard-migrate.js +682 -28
- package/dist/gateway/index.js +1629 -1295
- package/dist/hooks/bug-report-worker.js +1136 -183
- package/dist/hooks/codex-stop-task-finalizer.js +1060 -107
- package/dist/hooks/commit-complete.js +408 -33
- package/dist/hooks/error-recall.js +1608 -1300
- package/dist/hooks/ingest-worker.js +250 -7966
- package/dist/hooks/ingest.js +707 -119
- package/dist/hooks/instructions-loaded.js +383 -20
- package/dist/hooks/notification.js +383 -20
- package/dist/hooks/post-compact.js +384 -21
- package/dist/hooks/{response-ingest-worker.js → post-tool-combined.js} +4157 -1716
- package/dist/hooks/pre-compact.js +486 -45
- package/dist/hooks/pre-tool-use.js +385 -22
- package/dist/hooks/prompt-submit.js +291 -96
- package/dist/hooks/session-end.js +490 -48
- package/dist/hooks/session-start.js +236 -22
- package/dist/hooks/stop.js +192 -50
- package/dist/hooks/subagent-stop.js +95 -18
- package/dist/hooks/summary-worker.js +205 -361
- package/dist/index.js +221 -105
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +27 -8
- package/dist/lib/consolidation.js +437 -41
- package/dist/lib/database.js +20 -8
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +20 -8
- package/dist/lib/device-registry.js +27 -8
- package/dist/lib/employee-templates.js +62 -0
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon.js +6703 -6259
- package/dist/lib/hybrid-search.js +1608 -1300
- package/dist/lib/identity.js +1 -1
- package/dist/lib/messaging.js +11 -3
- package/dist/lib/reminders.js +1 -1
- package/dist/lib/schedules.js +718 -26
- package/dist/lib/session-registry.js +11 -0
- package/dist/lib/skill-learning.js +639 -9
- package/dist/lib/store.js +676 -27
- package/dist/lib/tasks.js +665 -27
- package/dist/lib/tmux-routing.js +732 -94
- package/dist/lib/token-spend.js +1 -1
- package/dist/mcp/server.js +856 -383
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +616 -46
- package/dist/mcp/tools/deactivate-behavior.js +9 -1
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +10 -2
- package/dist/mcp/tools/send-message.js +11 -3
- package/dist/mcp/tools/update-task.js +677 -39
- package/dist/runtime/index.js +425 -37
- package/dist/tui/App.js +365 -34
- package/package.json +5 -2
- package/src/commands/exe/intercom.md +6 -17
- package/dist/bin/wiki-sync.js +0 -2991
- package/dist/hooks/prompt-ingest-worker.js +0 -3979
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -328,12 +328,25 @@ async function ensurePrivateDir(dirPath) {
|
|
|
328
328
|
} catch {
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
|
+
function ensurePrivateDirSync(dirPath) {
|
|
332
|
+
mkdirSync2(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
333
|
+
try {
|
|
334
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
331
338
|
async function enforcePrivateFile(filePath) {
|
|
332
339
|
try {
|
|
333
340
|
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
334
341
|
} catch {
|
|
335
342
|
}
|
|
336
343
|
}
|
|
344
|
+
function enforcePrivateFileSync(filePath) {
|
|
345
|
+
try {
|
|
346
|
+
if (existsSync2(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
347
|
+
} catch {
|
|
348
|
+
}
|
|
349
|
+
}
|
|
337
350
|
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
338
351
|
var init_secure_files = __esm({
|
|
339
352
|
"src/lib/secure-files.ts"() {
|
|
@@ -344,6 +357,21 @@ var init_secure_files = __esm({
|
|
|
344
357
|
});
|
|
345
358
|
|
|
346
359
|
// src/lib/config.ts
|
|
360
|
+
var config_exports = {};
|
|
361
|
+
__export(config_exports, {
|
|
362
|
+
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
363
|
+
CONFIG_PATH: () => CONFIG_PATH,
|
|
364
|
+
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
365
|
+
DB_PATH: () => DB_PATH,
|
|
366
|
+
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
367
|
+
LEGACY_LANCE_PATH: () => LEGACY_LANCE_PATH,
|
|
368
|
+
MODELS_DIR: () => MODELS_DIR,
|
|
369
|
+
loadConfig: () => loadConfig,
|
|
370
|
+
loadConfigFrom: () => loadConfigFrom,
|
|
371
|
+
loadConfigSync: () => loadConfigSync,
|
|
372
|
+
migrateConfig: () => migrateConfig,
|
|
373
|
+
saveConfig: () => saveConfig
|
|
374
|
+
});
|
|
347
375
|
import { readFile, writeFile } from "fs/promises";
|
|
348
376
|
import { readFileSync as readFileSync2, existsSync as existsSync3, renameSync } from "fs";
|
|
349
377
|
import path2 from "path";
|
|
@@ -447,6 +475,46 @@ async function loadConfig() {
|
|
|
447
475
|
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
448
476
|
}
|
|
449
477
|
}
|
|
478
|
+
function loadConfigSync() {
|
|
479
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
480
|
+
const configPath = path2.join(dir, "config.json");
|
|
481
|
+
if (!existsSync3(configPath)) {
|
|
482
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
483
|
+
}
|
|
484
|
+
try {
|
|
485
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
486
|
+
let parsed = JSON.parse(raw);
|
|
487
|
+
parsed = migrateLegacyConfig(parsed);
|
|
488
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
489
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
490
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
491
|
+
normalizeAutoUpdate(migratedCfg);
|
|
492
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
493
|
+
} catch {
|
|
494
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
async function saveConfig(config) {
|
|
498
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
499
|
+
await ensurePrivateDir(dir);
|
|
500
|
+
const configPath = path2.join(dir, "config.json");
|
|
501
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
502
|
+
await enforcePrivateFile(configPath);
|
|
503
|
+
}
|
|
504
|
+
async function loadConfigFrom(configPath) {
|
|
505
|
+
const raw = await readFile(configPath, "utf-8");
|
|
506
|
+
try {
|
|
507
|
+
let parsed = JSON.parse(raw);
|
|
508
|
+
parsed = migrateLegacyConfig(parsed);
|
|
509
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
510
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
511
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
512
|
+
normalizeAutoUpdate(migratedCfg);
|
|
513
|
+
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
514
|
+
} catch {
|
|
515
|
+
return { ...DEFAULT_CONFIG };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
450
518
|
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
451
519
|
var init_config = __esm({
|
|
452
520
|
"src/lib/config.ts"() {
|
|
@@ -583,7 +651,7 @@ var init_agent_config = __esm({
|
|
|
583
651
|
init_secure_files();
|
|
584
652
|
AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
|
|
585
653
|
DEFAULT_MODELS = {
|
|
586
|
-
claude: "claude-opus-4",
|
|
654
|
+
claude: "claude-opus-4.6",
|
|
587
655
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
588
656
|
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
589
657
|
};
|
|
@@ -765,9 +833,9 @@ var MAX_RETRIES2, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
|
765
833
|
var init_db_retry = __esm({
|
|
766
834
|
"src/lib/db-retry.ts"() {
|
|
767
835
|
"use strict";
|
|
768
|
-
MAX_RETRIES2 =
|
|
769
|
-
BASE_DELAY_MS =
|
|
770
|
-
MAX_JITTER_MS =
|
|
836
|
+
MAX_RETRIES2 = 5;
|
|
837
|
+
BASE_DELAY_MS = 250;
|
|
838
|
+
MAX_JITTER_MS = 400;
|
|
771
839
|
}
|
|
772
840
|
});
|
|
773
841
|
|
|
@@ -1426,7 +1494,762 @@ var init_database_adapter = __esm({
|
|
|
1426
1494
|
}
|
|
1427
1495
|
});
|
|
1428
1496
|
|
|
1497
|
+
// src/types/memory.ts
|
|
1498
|
+
var EMBEDDING_DIM;
|
|
1499
|
+
var init_memory = __esm({
|
|
1500
|
+
"src/types/memory.ts"() {
|
|
1501
|
+
"use strict";
|
|
1502
|
+
EMBEDDING_DIM = 1024;
|
|
1503
|
+
}
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
// src/lib/daemon-auth.ts
|
|
1507
|
+
import crypto from "crypto";
|
|
1508
|
+
import path7 from "path";
|
|
1509
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1510
|
+
function normalizeToken(token) {
|
|
1511
|
+
if (!token) return null;
|
|
1512
|
+
const trimmed = token.trim();
|
|
1513
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1514
|
+
}
|
|
1515
|
+
function readDaemonToken() {
|
|
1516
|
+
try {
|
|
1517
|
+
if (!existsSync7(DAEMON_TOKEN_PATH)) return null;
|
|
1518
|
+
return normalizeToken(readFileSync6(DAEMON_TOKEN_PATH, "utf8"));
|
|
1519
|
+
} catch {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
function ensureDaemonToken(seed) {
|
|
1524
|
+
const existing = readDaemonToken();
|
|
1525
|
+
if (existing) return existing;
|
|
1526
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
1527
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1528
|
+
writeFileSync5(DAEMON_TOKEN_PATH, `${token}
|
|
1529
|
+
`, "utf8");
|
|
1530
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1531
|
+
return token;
|
|
1532
|
+
}
|
|
1533
|
+
var DAEMON_TOKEN_PATH;
|
|
1534
|
+
var init_daemon_auth = __esm({
|
|
1535
|
+
"src/lib/daemon-auth.ts"() {
|
|
1536
|
+
"use strict";
|
|
1537
|
+
init_config();
|
|
1538
|
+
init_secure_files();
|
|
1539
|
+
DAEMON_TOKEN_PATH = path7.join(EXE_AI_DIR, "exed.token");
|
|
1540
|
+
}
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1543
|
+
// src/lib/exe-daemon-client.ts
|
|
1544
|
+
var exe_daemon_client_exports = {};
|
|
1545
|
+
__export(exe_daemon_client_exports, {
|
|
1546
|
+
connectEmbedDaemon: () => connectEmbedDaemon,
|
|
1547
|
+
disconnectClient: () => disconnectClient,
|
|
1548
|
+
embedBatchViaClient: () => embedBatchViaClient,
|
|
1549
|
+
embedViaClient: () => embedViaClient,
|
|
1550
|
+
isClientConnected: () => isClientConnected,
|
|
1551
|
+
pingDaemon: () => pingDaemon,
|
|
1552
|
+
sendDaemonRequest: () => sendDaemonRequest,
|
|
1553
|
+
sendIngestRequest: () => sendIngestRequest
|
|
1554
|
+
});
|
|
1555
|
+
import net from "net";
|
|
1556
|
+
import os6 from "os";
|
|
1557
|
+
import { spawn } from "child_process";
|
|
1558
|
+
import { randomUUID } from "crypto";
|
|
1559
|
+
import { existsSync as existsSync8, unlinkSync as unlinkSync2, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
|
|
1560
|
+
import path8 from "path";
|
|
1561
|
+
import { fileURLToPath } from "url";
|
|
1562
|
+
function handleData(chunk) {
|
|
1563
|
+
_buffer += chunk.toString();
|
|
1564
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1565
|
+
_buffer = "";
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
let newlineIdx;
|
|
1569
|
+
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1570
|
+
const line = _buffer.slice(0, newlineIdx).trim();
|
|
1571
|
+
_buffer = _buffer.slice(newlineIdx + 1);
|
|
1572
|
+
if (!line) continue;
|
|
1573
|
+
try {
|
|
1574
|
+
const response = JSON.parse(line);
|
|
1575
|
+
const id = response.id;
|
|
1576
|
+
if (!id) continue;
|
|
1577
|
+
const entry = _pending.get(id);
|
|
1578
|
+
if (entry) {
|
|
1579
|
+
clearTimeout(entry.timer);
|
|
1580
|
+
_pending.delete(id);
|
|
1581
|
+
entry.resolve(response);
|
|
1582
|
+
}
|
|
1583
|
+
} catch {
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
function cleanupStaleFiles() {
|
|
1588
|
+
if (existsSync8(PID_PATH)) {
|
|
1589
|
+
try {
|
|
1590
|
+
const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
|
|
1591
|
+
if (pid > 0) {
|
|
1592
|
+
try {
|
|
1593
|
+
process.kill(pid, 0);
|
|
1594
|
+
return;
|
|
1595
|
+
} catch {
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
} catch {
|
|
1599
|
+
}
|
|
1600
|
+
try {
|
|
1601
|
+
unlinkSync2(PID_PATH);
|
|
1602
|
+
} catch {
|
|
1603
|
+
}
|
|
1604
|
+
try {
|
|
1605
|
+
unlinkSync2(SOCKET_PATH);
|
|
1606
|
+
} catch {
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
function findPackageRoot() {
|
|
1611
|
+
let dir = path8.dirname(fileURLToPath(import.meta.url));
|
|
1612
|
+
const { root } = path8.parse(dir);
|
|
1613
|
+
while (dir !== root) {
|
|
1614
|
+
if (existsSync8(path8.join(dir, "package.json"))) return dir;
|
|
1615
|
+
dir = path8.dirname(dir);
|
|
1616
|
+
}
|
|
1617
|
+
return null;
|
|
1618
|
+
}
|
|
1619
|
+
function getAvailableMemoryGB() {
|
|
1620
|
+
if (process.platform === "darwin") {
|
|
1621
|
+
try {
|
|
1622
|
+
const { execSync: execSync7 } = __require("child_process");
|
|
1623
|
+
const vmstat = execSync7("vm_stat", { encoding: "utf8" });
|
|
1624
|
+
const pageSize = 16384;
|
|
1625
|
+
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1626
|
+
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
1627
|
+
const free = vmstat.match(/Pages free:\s+(\d+)/);
|
|
1628
|
+
const inactive = vmstat.match(/Pages inactive:\s+(\d+)/);
|
|
1629
|
+
const speculative = vmstat.match(/Pages speculative:\s+(\d+)/);
|
|
1630
|
+
const freePages = free ? parseInt(free[1], 10) : 0;
|
|
1631
|
+
const inactivePages = inactive ? parseInt(inactive[1], 10) : 0;
|
|
1632
|
+
const speculativePages = speculative ? parseInt(speculative[1], 10) : 0;
|
|
1633
|
+
return (freePages + inactivePages + speculativePages) * actualPageSize / (1024 * 1024 * 1024);
|
|
1634
|
+
} catch {
|
|
1635
|
+
return os6.freemem() / (1024 * 1024 * 1024);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
return os6.freemem() / (1024 * 1024 * 1024);
|
|
1639
|
+
}
|
|
1640
|
+
function spawnDaemon() {
|
|
1641
|
+
const freeGB = getAvailableMemoryGB();
|
|
1642
|
+
const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
|
|
1643
|
+
if (totalGB <= 8) {
|
|
1644
|
+
process.stderr.write(
|
|
1645
|
+
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
1646
|
+
`
|
|
1647
|
+
);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
if (totalGB <= 16 && freeGB < 2) {
|
|
1651
|
+
process.stderr.write(
|
|
1652
|
+
`[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB available / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only.
|
|
1653
|
+
`
|
|
1654
|
+
);
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const pkgRoot = findPackageRoot();
|
|
1658
|
+
if (!pkgRoot) {
|
|
1659
|
+
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const daemonPath = path8.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1663
|
+
if (!existsSync8(daemonPath)) {
|
|
1664
|
+
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1665
|
+
`);
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
const resolvedPath = daemonPath;
|
|
1669
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
1670
|
+
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1671
|
+
`);
|
|
1672
|
+
const logPath = path8.join(path8.dirname(SOCKET_PATH), "exed.log");
|
|
1673
|
+
let stderrFd = "ignore";
|
|
1674
|
+
try {
|
|
1675
|
+
stderrFd = openSync(logPath, "a");
|
|
1676
|
+
} catch {
|
|
1677
|
+
}
|
|
1678
|
+
const heapCapMB = totalGB <= 8 ? 256 : 512;
|
|
1679
|
+
const nodeArgs = [`--max-old-space-size=${heapCapMB}`, resolvedPath];
|
|
1680
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
1681
|
+
detached: true,
|
|
1682
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
1683
|
+
env: {
|
|
1684
|
+
...process.env,
|
|
1685
|
+
TMUX: void 0,
|
|
1686
|
+
// Daemon is global — must not inherit session scope
|
|
1687
|
+
TMUX_PANE: void 0,
|
|
1688
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
1689
|
+
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
1690
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
1691
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
child.unref();
|
|
1695
|
+
if (typeof stderrFd === "number") {
|
|
1696
|
+
try {
|
|
1697
|
+
closeSync(stderrFd);
|
|
1698
|
+
} catch {
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
function acquireSpawnLock() {
|
|
1703
|
+
try {
|
|
1704
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
1705
|
+
closeSync(fd);
|
|
1706
|
+
return true;
|
|
1707
|
+
} catch {
|
|
1708
|
+
try {
|
|
1709
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
1710
|
+
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
1711
|
+
try {
|
|
1712
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
1713
|
+
} catch {
|
|
1714
|
+
}
|
|
1715
|
+
try {
|
|
1716
|
+
const fd = openSync(SPAWN_LOCK_PATH, "wx");
|
|
1717
|
+
closeSync(fd);
|
|
1718
|
+
return true;
|
|
1719
|
+
} catch {
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
} catch {
|
|
1723
|
+
}
|
|
1724
|
+
return false;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
function releaseSpawnLock() {
|
|
1728
|
+
try {
|
|
1729
|
+
unlinkSync2(SPAWN_LOCK_PATH);
|
|
1730
|
+
} catch {
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
function connectToSocket() {
|
|
1734
|
+
return new Promise((resolve) => {
|
|
1735
|
+
if (_socket && _connected) {
|
|
1736
|
+
resolve(true);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
const socket = net.createConnection({ path: SOCKET_PATH });
|
|
1740
|
+
const connectTimeout = setTimeout(() => {
|
|
1741
|
+
socket.destroy();
|
|
1742
|
+
resolve(false);
|
|
1743
|
+
}, 2e3);
|
|
1744
|
+
socket.on("connect", () => {
|
|
1745
|
+
clearTimeout(connectTimeout);
|
|
1746
|
+
_socket = socket;
|
|
1747
|
+
_connected = true;
|
|
1748
|
+
_buffer = "";
|
|
1749
|
+
socket.on("data", handleData);
|
|
1750
|
+
socket.on("close", () => {
|
|
1751
|
+
_connected = false;
|
|
1752
|
+
_socket = null;
|
|
1753
|
+
for (const [id, entry] of _pending) {
|
|
1754
|
+
clearTimeout(entry.timer);
|
|
1755
|
+
_pending.delete(id);
|
|
1756
|
+
entry.resolve({ error: "Connection closed" });
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
socket.on("error", () => {
|
|
1760
|
+
_connected = false;
|
|
1761
|
+
_socket = null;
|
|
1762
|
+
});
|
|
1763
|
+
resolve(true);
|
|
1764
|
+
});
|
|
1765
|
+
socket.on("error", () => {
|
|
1766
|
+
clearTimeout(connectTimeout);
|
|
1767
|
+
resolve(false);
|
|
1768
|
+
});
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
async function connectEmbedDaemon() {
|
|
1772
|
+
if (_socket && _connected) return true;
|
|
1773
|
+
if (await connectToSocket()) return true;
|
|
1774
|
+
if (acquireSpawnLock()) {
|
|
1775
|
+
try {
|
|
1776
|
+
cleanupStaleFiles();
|
|
1777
|
+
spawnDaemon();
|
|
1778
|
+
} finally {
|
|
1779
|
+
releaseSpawnLock();
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
const start = Date.now();
|
|
1783
|
+
let delay2 = 100;
|
|
1784
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1785
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1786
|
+
if (await connectToSocket()) return true;
|
|
1787
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1788
|
+
}
|
|
1789
|
+
return false;
|
|
1790
|
+
}
|
|
1791
|
+
function sendRequest(texts, priority) {
|
|
1792
|
+
return sendDaemonRequest({ texts, priority });
|
|
1793
|
+
}
|
|
1794
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
1795
|
+
return new Promise((resolve) => {
|
|
1796
|
+
if (!_socket || !_connected) {
|
|
1797
|
+
resolve({ error: "Not connected" });
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
const id = randomUUID();
|
|
1801
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
1802
|
+
const timer = setTimeout(() => {
|
|
1803
|
+
_pending.delete(id);
|
|
1804
|
+
resolve({ error: "Request timeout" });
|
|
1805
|
+
}, timeoutMs);
|
|
1806
|
+
_pending.set(id, { resolve, timer });
|
|
1807
|
+
try {
|
|
1808
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
1809
|
+
} catch {
|
|
1810
|
+
clearTimeout(timer);
|
|
1811
|
+
_pending.delete(id);
|
|
1812
|
+
resolve({ error: "Write failed" });
|
|
1813
|
+
}
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
async function pingDaemon() {
|
|
1817
|
+
if (!_socket || !_connected) return null;
|
|
1818
|
+
const response = await sendDaemonRequest({ type: "health" }, 5e3);
|
|
1819
|
+
if (response.health) {
|
|
1820
|
+
return response.health;
|
|
1821
|
+
}
|
|
1822
|
+
return null;
|
|
1823
|
+
}
|
|
1824
|
+
function killAndRespawnDaemon() {
|
|
1825
|
+
if (!acquireSpawnLock()) {
|
|
1826
|
+
process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
|
|
1827
|
+
if (_socket) {
|
|
1828
|
+
_socket.destroy();
|
|
1829
|
+
_socket = null;
|
|
1830
|
+
}
|
|
1831
|
+
_connected = false;
|
|
1832
|
+
_buffer = "";
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
try {
|
|
1836
|
+
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
1837
|
+
if (existsSync8(PID_PATH)) {
|
|
1838
|
+
try {
|
|
1839
|
+
const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
|
|
1840
|
+
if (pid > 0) {
|
|
1841
|
+
try {
|
|
1842
|
+
process.kill(pid, "SIGKILL");
|
|
1843
|
+
} catch {
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
} catch {
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
if (_socket) {
|
|
1850
|
+
_socket.destroy();
|
|
1851
|
+
_socket = null;
|
|
1852
|
+
}
|
|
1853
|
+
_connected = false;
|
|
1854
|
+
_buffer = "";
|
|
1855
|
+
try {
|
|
1856
|
+
unlinkSync2(PID_PATH);
|
|
1857
|
+
} catch {
|
|
1858
|
+
}
|
|
1859
|
+
try {
|
|
1860
|
+
unlinkSync2(SOCKET_PATH);
|
|
1861
|
+
} catch {
|
|
1862
|
+
}
|
|
1863
|
+
spawnDaemon();
|
|
1864
|
+
} finally {
|
|
1865
|
+
releaseSpawnLock();
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
function isDaemonTooYoung() {
|
|
1869
|
+
try {
|
|
1870
|
+
const stat = statSync(PID_PATH);
|
|
1871
|
+
return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
|
|
1872
|
+
} catch {
|
|
1873
|
+
return false;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
async function retryThenRestart(doRequest, label) {
|
|
1877
|
+
const result2 = await doRequest();
|
|
1878
|
+
if (!result2.error) {
|
|
1879
|
+
_consecutiveFailures = 0;
|
|
1880
|
+
return result2;
|
|
1881
|
+
}
|
|
1882
|
+
_consecutiveFailures++;
|
|
1883
|
+
for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
|
|
1884
|
+
const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
|
|
1885
|
+
process.stderr.write(`[exed-client] ${label} failed (${result2.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
|
|
1886
|
+
`);
|
|
1887
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
1888
|
+
if (!_connected) {
|
|
1889
|
+
if (!await connectToSocket()) continue;
|
|
1890
|
+
}
|
|
1891
|
+
const retry = await doRequest();
|
|
1892
|
+
if (!retry.error) {
|
|
1893
|
+
_consecutiveFailures = 0;
|
|
1894
|
+
return retry;
|
|
1895
|
+
}
|
|
1896
|
+
_consecutiveFailures++;
|
|
1897
|
+
}
|
|
1898
|
+
if (isDaemonTooYoung()) {
|
|
1899
|
+
process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
|
|
1900
|
+
`);
|
|
1901
|
+
return { error: result2.error };
|
|
1902
|
+
}
|
|
1903
|
+
process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
|
|
1904
|
+
`);
|
|
1905
|
+
killAndRespawnDaemon();
|
|
1906
|
+
const start = Date.now();
|
|
1907
|
+
let delay2 = 200;
|
|
1908
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1909
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1910
|
+
if (await connectToSocket()) break;
|
|
1911
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1912
|
+
}
|
|
1913
|
+
if (!_connected) return { error: "Daemon restart failed" };
|
|
1914
|
+
const final = await doRequest();
|
|
1915
|
+
if (!final.error) _consecutiveFailures = 0;
|
|
1916
|
+
return final;
|
|
1917
|
+
}
|
|
1918
|
+
async function embedViaClient(text, priority = "high") {
|
|
1919
|
+
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
1920
|
+
_requestCount++;
|
|
1921
|
+
if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
|
|
1922
|
+
const health = await pingDaemon();
|
|
1923
|
+
if (!health && !isDaemonTooYoung()) {
|
|
1924
|
+
process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
|
|
1925
|
+
`);
|
|
1926
|
+
killAndRespawnDaemon();
|
|
1927
|
+
const start = Date.now();
|
|
1928
|
+
let d = 200;
|
|
1929
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1930
|
+
await new Promise((r) => setTimeout(r, d));
|
|
1931
|
+
if (await connectToSocket()) break;
|
|
1932
|
+
d = Math.min(d * 2, 3e3);
|
|
1933
|
+
}
|
|
1934
|
+
if (!_connected) return null;
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
const result2 = await retryThenRestart(
|
|
1938
|
+
() => sendRequest([text], priority),
|
|
1939
|
+
"Embed"
|
|
1940
|
+
);
|
|
1941
|
+
return !result2.error && result2.vectors?.[0] ? result2.vectors[0] : null;
|
|
1942
|
+
}
|
|
1943
|
+
async function embedBatchViaClient(texts, priority = "high") {
|
|
1944
|
+
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
1945
|
+
_requestCount++;
|
|
1946
|
+
const result2 = await retryThenRestart(
|
|
1947
|
+
() => sendRequest(texts, priority),
|
|
1948
|
+
"Batch embed"
|
|
1949
|
+
);
|
|
1950
|
+
return !result2.error && result2.vectors ? result2.vectors : null;
|
|
1951
|
+
}
|
|
1952
|
+
function disconnectClient() {
|
|
1953
|
+
if (_socket) {
|
|
1954
|
+
_socket.destroy();
|
|
1955
|
+
_socket = null;
|
|
1956
|
+
}
|
|
1957
|
+
_connected = false;
|
|
1958
|
+
_buffer = "";
|
|
1959
|
+
for (const [id, entry] of _pending) {
|
|
1960
|
+
clearTimeout(entry.timer);
|
|
1961
|
+
_pending.delete(id);
|
|
1962
|
+
entry.resolve({ error: "Client disconnected" });
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
function isClientConnected() {
|
|
1966
|
+
return _connected;
|
|
1967
|
+
}
|
|
1968
|
+
function sendIngestRequest(payload) {
|
|
1969
|
+
if (!_socket || !_connected) return false;
|
|
1970
|
+
try {
|
|
1971
|
+
const id = randomUUID();
|
|
1972
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
1973
|
+
_socket.write(JSON.stringify({ id, token, type: "ingest", ...payload }) + "\n");
|
|
1974
|
+
return true;
|
|
1975
|
+
} catch {
|
|
1976
|
+
return false;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
|
|
1980
|
+
var init_exe_daemon_client = __esm({
|
|
1981
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
1982
|
+
"use strict";
|
|
1983
|
+
init_config();
|
|
1984
|
+
init_daemon_auth();
|
|
1985
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
|
|
1986
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path8.join(EXE_AI_DIR, "exed.pid");
|
|
1987
|
+
SPAWN_LOCK_PATH = path8.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1988
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1989
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
1990
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
1991
|
+
DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
1992
|
+
_socket = null;
|
|
1993
|
+
_connected = false;
|
|
1994
|
+
_buffer = "";
|
|
1995
|
+
_requestCount = 0;
|
|
1996
|
+
_consecutiveFailures = 0;
|
|
1997
|
+
HEALTH_CHECK_INTERVAL = 100;
|
|
1998
|
+
MAX_RETRIES_BEFORE_RESTART = 3;
|
|
1999
|
+
RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
|
|
2000
|
+
MIN_DAEMON_AGE_MS = 3e4;
|
|
2001
|
+
_pending = /* @__PURE__ */ new Map();
|
|
2002
|
+
MAX_BUFFER = 1e7;
|
|
2003
|
+
}
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
// src/lib/daemon-protocol.ts
|
|
2007
|
+
var daemon_protocol_exports = {};
|
|
2008
|
+
__export(daemon_protocol_exports, {
|
|
2009
|
+
deserializeArgs: () => deserializeArgs,
|
|
2010
|
+
deserializeResultSet: () => deserializeResultSet,
|
|
2011
|
+
deserializeValue: () => deserializeValue,
|
|
2012
|
+
serializeArgs: () => serializeArgs,
|
|
2013
|
+
serializeResultSet: () => serializeResultSet,
|
|
2014
|
+
serializeValue: () => serializeValue
|
|
2015
|
+
});
|
|
2016
|
+
function serializeValue(v) {
|
|
2017
|
+
if (v === null || v === void 0) return null;
|
|
2018
|
+
if (typeof v === "bigint") return Number(v);
|
|
2019
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
2020
|
+
if (v instanceof Uint8Array) {
|
|
2021
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
2022
|
+
}
|
|
2023
|
+
if (ArrayBuffer.isView(v)) {
|
|
2024
|
+
return { __blob: Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString("base64") };
|
|
2025
|
+
}
|
|
2026
|
+
if (v instanceof ArrayBuffer) {
|
|
2027
|
+
return { __blob: Buffer.from(v).toString("base64") };
|
|
2028
|
+
}
|
|
2029
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
2030
|
+
return String(v);
|
|
2031
|
+
}
|
|
2032
|
+
function deserializeValue(v) {
|
|
2033
|
+
if (v === null) return null;
|
|
2034
|
+
if (typeof v === "object" && v !== null && "__blob" in v) {
|
|
2035
|
+
const buf = Buffer.from(v.__blob, "base64");
|
|
2036
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
2037
|
+
}
|
|
2038
|
+
return v;
|
|
2039
|
+
}
|
|
2040
|
+
function serializeArgs(args) {
|
|
2041
|
+
return args.map(serializeValue);
|
|
2042
|
+
}
|
|
2043
|
+
function deserializeArgs(args) {
|
|
2044
|
+
return args.map(deserializeValue);
|
|
2045
|
+
}
|
|
2046
|
+
function serializeResultSet(rs) {
|
|
2047
|
+
const rows = [];
|
|
2048
|
+
for (const row of rs.rows) {
|
|
2049
|
+
const obj = {};
|
|
2050
|
+
for (let i = 0; i < rs.columns.length; i++) {
|
|
2051
|
+
const col = rs.columns[i];
|
|
2052
|
+
if (col !== void 0) {
|
|
2053
|
+
obj[col] = serializeValue(row[i]);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
rows.push(obj);
|
|
2057
|
+
}
|
|
2058
|
+
return {
|
|
2059
|
+
columns: [...rs.columns],
|
|
2060
|
+
columnTypes: [...rs.columnTypes ?? []],
|
|
2061
|
+
rows,
|
|
2062
|
+
rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
|
|
2063
|
+
lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
function deserializeResultSet(srs) {
|
|
2067
|
+
const rows = srs.rows.map((obj) => {
|
|
2068
|
+
const values = srs.columns.map(
|
|
2069
|
+
(col) => deserializeValue(obj[col] ?? null)
|
|
2070
|
+
);
|
|
2071
|
+
const row = values;
|
|
2072
|
+
for (let i = 0; i < srs.columns.length; i++) {
|
|
2073
|
+
const col = srs.columns[i];
|
|
2074
|
+
if (col !== void 0) {
|
|
2075
|
+
row[col] = values[i] ?? null;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
Object.defineProperty(row, "length", {
|
|
2079
|
+
value: values.length,
|
|
2080
|
+
enumerable: false
|
|
2081
|
+
});
|
|
2082
|
+
return row;
|
|
2083
|
+
});
|
|
2084
|
+
return {
|
|
2085
|
+
columns: srs.columns,
|
|
2086
|
+
columnTypes: srs.columnTypes ?? [],
|
|
2087
|
+
rows,
|
|
2088
|
+
rowsAffected: srs.rowsAffected,
|
|
2089
|
+
lastInsertRowid: srs.lastInsertRowid != null ? BigInt(srs.lastInsertRowid) : void 0,
|
|
2090
|
+
toJSON: () => ({
|
|
2091
|
+
columns: srs.columns,
|
|
2092
|
+
columnTypes: srs.columnTypes ?? [],
|
|
2093
|
+
rows: srs.rows,
|
|
2094
|
+
rowsAffected: srs.rowsAffected,
|
|
2095
|
+
lastInsertRowid: srs.lastInsertRowid
|
|
2096
|
+
})
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
var init_daemon_protocol = __esm({
|
|
2100
|
+
"src/lib/daemon-protocol.ts"() {
|
|
2101
|
+
"use strict";
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
// src/lib/db-daemon-client.ts
|
|
2106
|
+
var db_daemon_client_exports = {};
|
|
2107
|
+
__export(db_daemon_client_exports, {
|
|
2108
|
+
createDaemonDbClient: () => createDaemonDbClient,
|
|
2109
|
+
initDaemonDbClient: () => initDaemonDbClient
|
|
2110
|
+
});
|
|
2111
|
+
function normalizeStatement2(stmt) {
|
|
2112
|
+
if (typeof stmt === "string") {
|
|
2113
|
+
return { sql: stmt, args: [] };
|
|
2114
|
+
}
|
|
2115
|
+
const sql = stmt.sql;
|
|
2116
|
+
let args = [];
|
|
2117
|
+
if (Array.isArray(stmt.args)) {
|
|
2118
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
2119
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
2120
|
+
const named = {};
|
|
2121
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
2122
|
+
named[key] = serializeValue(val);
|
|
2123
|
+
}
|
|
2124
|
+
return { sql, args: named };
|
|
2125
|
+
}
|
|
2126
|
+
return { sql, args };
|
|
2127
|
+
}
|
|
2128
|
+
function createDaemonDbClient(fallbackClient) {
|
|
2129
|
+
let _useDaemon = false;
|
|
2130
|
+
const client = {
|
|
2131
|
+
async execute(stmt) {
|
|
2132
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
2133
|
+
return fallbackClient.execute(stmt);
|
|
2134
|
+
}
|
|
2135
|
+
const { sql, args } = normalizeStatement2(stmt);
|
|
2136
|
+
const response = await sendDaemonRequest({
|
|
2137
|
+
type: "db-execute",
|
|
2138
|
+
sql,
|
|
2139
|
+
args
|
|
2140
|
+
});
|
|
2141
|
+
if (response.error) {
|
|
2142
|
+
const errMsg = String(response.error);
|
|
2143
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
|
|
2144
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
2145
|
+
`);
|
|
2146
|
+
return fallbackClient.execute(stmt);
|
|
2147
|
+
}
|
|
2148
|
+
throw new Error(errMsg);
|
|
2149
|
+
}
|
|
2150
|
+
if (response.db) {
|
|
2151
|
+
return deserializeResultSet(response.db);
|
|
2152
|
+
}
|
|
2153
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
2154
|
+
return fallbackClient.execute(stmt);
|
|
2155
|
+
},
|
|
2156
|
+
async batch(stmts, mode) {
|
|
2157
|
+
if (!_useDaemon || !isClientConnected()) {
|
|
2158
|
+
return fallbackClient.batch(stmts, mode);
|
|
2159
|
+
}
|
|
2160
|
+
const statements = stmts.map(normalizeStatement2);
|
|
2161
|
+
const response = await sendDaemonRequest({
|
|
2162
|
+
type: "db-batch",
|
|
2163
|
+
statements,
|
|
2164
|
+
mode: mode ?? "deferred"
|
|
2165
|
+
});
|
|
2166
|
+
if (response.error) {
|
|
2167
|
+
const errMsg = String(response.error);
|
|
2168
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
|
|
2169
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
2170
|
+
`);
|
|
2171
|
+
return fallbackClient.batch(stmts, mode);
|
|
2172
|
+
}
|
|
2173
|
+
throw new Error(errMsg);
|
|
2174
|
+
}
|
|
2175
|
+
const batchResults = response["db-batch"];
|
|
2176
|
+
if (batchResults) {
|
|
2177
|
+
return batchResults.map(deserializeResultSet);
|
|
2178
|
+
}
|
|
2179
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
2180
|
+
return fallbackClient.batch(stmts, mode);
|
|
2181
|
+
},
|
|
2182
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
2183
|
+
async transaction(mode) {
|
|
2184
|
+
return fallbackClient.transaction(mode);
|
|
2185
|
+
},
|
|
2186
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
2187
|
+
async executeMultiple(sql) {
|
|
2188
|
+
return fallbackClient.executeMultiple(sql);
|
|
2189
|
+
},
|
|
2190
|
+
// migrate — delegate to fallback
|
|
2191
|
+
async migrate(stmts) {
|
|
2192
|
+
return fallbackClient.migrate(stmts);
|
|
2193
|
+
},
|
|
2194
|
+
// Sync mode — delegate to fallback
|
|
2195
|
+
sync() {
|
|
2196
|
+
return fallbackClient.sync();
|
|
2197
|
+
},
|
|
2198
|
+
close() {
|
|
2199
|
+
_useDaemon = false;
|
|
2200
|
+
},
|
|
2201
|
+
get closed() {
|
|
2202
|
+
return fallbackClient.closed;
|
|
2203
|
+
},
|
|
2204
|
+
get protocol() {
|
|
2205
|
+
return fallbackClient.protocol;
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
return {
|
|
2209
|
+
...client,
|
|
2210
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
2211
|
+
_enableDaemon() {
|
|
2212
|
+
_useDaemon = true;
|
|
2213
|
+
},
|
|
2214
|
+
/** Check if daemon routing is active */
|
|
2215
|
+
_isDaemonActive() {
|
|
2216
|
+
return _useDaemon && isClientConnected();
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
2221
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
2222
|
+
const connected = await connectEmbedDaemon();
|
|
2223
|
+
if (!connected) {
|
|
2224
|
+
process.stderr.write("[db-daemon] Daemon unavailable \u2014 using direct SQLite\n");
|
|
2225
|
+
return null;
|
|
2226
|
+
}
|
|
2227
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
2228
|
+
client._enableDaemon();
|
|
2229
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
2230
|
+
return client;
|
|
2231
|
+
}
|
|
2232
|
+
var init_db_daemon_client = __esm({
|
|
2233
|
+
"src/lib/db-daemon-client.ts"() {
|
|
2234
|
+
"use strict";
|
|
2235
|
+
init_exe_daemon_client();
|
|
2236
|
+
init_daemon_protocol();
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
|
|
1429
2240
|
// src/lib/database.ts
|
|
2241
|
+
var database_exports = {};
|
|
2242
|
+
__export(database_exports, {
|
|
2243
|
+
disposeDatabase: () => disposeDatabase,
|
|
2244
|
+
disposeTurso: () => disposeTurso,
|
|
2245
|
+
ensureSchema: () => ensureSchema,
|
|
2246
|
+
getClient: () => getClient,
|
|
2247
|
+
getRawClient: () => getRawClient,
|
|
2248
|
+
initDaemonClient: () => initDaemonClient,
|
|
2249
|
+
initDatabase: () => initDatabase,
|
|
2250
|
+
initTurso: () => initTurso,
|
|
2251
|
+
isInitialized: () => isInitialized
|
|
2252
|
+
});
|
|
1430
2253
|
import { createClient } from "@libsql/client";
|
|
1431
2254
|
async function initDatabase(config) {
|
|
1432
2255
|
if (_walCheckpointTimer) {
|
|
@@ -1465,15 +2288,18 @@ async function initDatabase(config) {
|
|
|
1465
2288
|
});
|
|
1466
2289
|
}, 3e4);
|
|
1467
2290
|
_walCheckpointTimer.unref();
|
|
1468
|
-
if (process.env.DATABASE_URL) {
|
|
2291
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
1469
2292
|
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1470
2293
|
}
|
|
1471
2294
|
}
|
|
2295
|
+
function isInitialized() {
|
|
2296
|
+
return _adapterClient !== null || _client !== null;
|
|
2297
|
+
}
|
|
1472
2298
|
function getClient() {
|
|
1473
2299
|
if (!_adapterClient) {
|
|
1474
2300
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1475
2301
|
}
|
|
1476
|
-
if (process.env.DATABASE_URL) {
|
|
2302
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
1477
2303
|
return _adapterClient;
|
|
1478
2304
|
}
|
|
1479
2305
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
@@ -1484,6 +2310,22 @@ function getClient() {
|
|
|
1484
2310
|
}
|
|
1485
2311
|
return _resilientClient;
|
|
1486
2312
|
}
|
|
2313
|
+
async function initDaemonClient() {
|
|
2314
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
|
|
2315
|
+
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
2316
|
+
if (process.env.VITEST) return;
|
|
2317
|
+
if (!_resilientClient) return;
|
|
2318
|
+
if (_daemonClient) return;
|
|
2319
|
+
try {
|
|
2320
|
+
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
2321
|
+
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
2322
|
+
} catch (err) {
|
|
2323
|
+
process.stderr.write(
|
|
2324
|
+
`[database] Daemon client init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
2325
|
+
`
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
1487
2329
|
function getRawClient() {
|
|
1488
2330
|
if (!_client) {
|
|
1489
2331
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
@@ -1622,6 +2464,13 @@ async function ensureSchema() {
|
|
|
1622
2464
|
});
|
|
1623
2465
|
} catch {
|
|
1624
2466
|
}
|
|
2467
|
+
try {
|
|
2468
|
+
await client.execute({
|
|
2469
|
+
sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
|
|
2470
|
+
args: []
|
|
2471
|
+
});
|
|
2472
|
+
} catch {
|
|
2473
|
+
}
|
|
1625
2474
|
try {
|
|
1626
2475
|
await client.execute({
|
|
1627
2476
|
sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
|
|
@@ -2466,38 +3315,59 @@ async function ensureSchema() {
|
|
|
2466
3315
|
} catch {
|
|
2467
3316
|
}
|
|
2468
3317
|
}
|
|
2469
|
-
|
|
3318
|
+
async function disposeDatabase() {
|
|
3319
|
+
if (_walCheckpointTimer) {
|
|
3320
|
+
clearInterval(_walCheckpointTimer);
|
|
3321
|
+
_walCheckpointTimer = null;
|
|
3322
|
+
}
|
|
3323
|
+
if (_daemonClient) {
|
|
3324
|
+
_daemonClient.close();
|
|
3325
|
+
_daemonClient = null;
|
|
3326
|
+
}
|
|
3327
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
3328
|
+
_adapterClient.close();
|
|
3329
|
+
}
|
|
3330
|
+
_adapterClient = null;
|
|
3331
|
+
if (_client) {
|
|
3332
|
+
_client.close();
|
|
3333
|
+
_client = null;
|
|
3334
|
+
_resilientClient = null;
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
2470
3338
|
var init_database = __esm({
|
|
2471
3339
|
"src/lib/database.ts"() {
|
|
2472
3340
|
"use strict";
|
|
2473
3341
|
init_db_retry();
|
|
2474
3342
|
init_employees();
|
|
2475
3343
|
init_database_adapter();
|
|
3344
|
+
init_memory();
|
|
2476
3345
|
_client = null;
|
|
2477
3346
|
_resilientClient = null;
|
|
2478
3347
|
_walCheckpointTimer = null;
|
|
2479
3348
|
_daemonClient = null;
|
|
2480
3349
|
_adapterClient = null;
|
|
2481
3350
|
initTurso = initDatabase;
|
|
3351
|
+
disposeTurso = disposeDatabase;
|
|
2482
3352
|
}
|
|
2483
3353
|
});
|
|
2484
3354
|
|
|
2485
3355
|
// src/lib/license.ts
|
|
2486
|
-
import { readFileSync as
|
|
2487
|
-
import { randomUUID } from "crypto";
|
|
3356
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
3357
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2488
3358
|
import { createRequire as createRequire2 } from "module";
|
|
2489
3359
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2490
|
-
import
|
|
2491
|
-
import
|
|
3360
|
+
import os7 from "os";
|
|
3361
|
+
import path9 from "path";
|
|
2492
3362
|
import { jwtVerify, importSPKI } from "jose";
|
|
2493
3363
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
2494
3364
|
var init_license = __esm({
|
|
2495
3365
|
"src/lib/license.ts"() {
|
|
2496
3366
|
"use strict";
|
|
2497
3367
|
init_config();
|
|
2498
|
-
LICENSE_PATH =
|
|
2499
|
-
CACHE_PATH =
|
|
2500
|
-
DEVICE_ID_PATH =
|
|
3368
|
+
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
3369
|
+
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
3370
|
+
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
2501
3371
|
PLAN_LIMITS = {
|
|
2502
3372
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
2503
3373
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -2509,12 +3379,12 @@ var init_license = __esm({
|
|
|
2509
3379
|
});
|
|
2510
3380
|
|
|
2511
3381
|
// src/lib/plan-limits.ts
|
|
2512
|
-
import { readFileSync as
|
|
2513
|
-
import
|
|
3382
|
+
import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
|
|
3383
|
+
import path10 from "path";
|
|
2514
3384
|
function getLicenseSync() {
|
|
2515
3385
|
try {
|
|
2516
|
-
if (!
|
|
2517
|
-
const raw = JSON.parse(
|
|
3386
|
+
if (!existsSync10(CACHE_PATH2)) return freeLicense();
|
|
3387
|
+
const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
|
|
2518
3388
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2519
3389
|
const parts = raw.token.split(".");
|
|
2520
3390
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2552,8 +3422,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2552
3422
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
2553
3423
|
let count = 0;
|
|
2554
3424
|
try {
|
|
2555
|
-
if (
|
|
2556
|
-
const raw =
|
|
3425
|
+
if (existsSync10(filePath)) {
|
|
3426
|
+
const raw = readFileSync9(filePath, "utf8");
|
|
2557
3427
|
const employees = JSON.parse(raw);
|
|
2558
3428
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2559
3429
|
}
|
|
@@ -2582,7 +3452,7 @@ var init_plan_limits = __esm({
|
|
|
2582
3452
|
this.name = "PlanLimitError";
|
|
2583
3453
|
}
|
|
2584
3454
|
};
|
|
2585
|
-
CACHE_PATH2 =
|
|
3455
|
+
CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2586
3456
|
}
|
|
2587
3457
|
});
|
|
2588
3458
|
|
|
@@ -2620,20 +3490,20 @@ var init_task_scope = __esm({
|
|
|
2620
3490
|
});
|
|
2621
3491
|
|
|
2622
3492
|
// src/lib/notifications.ts
|
|
2623
|
-
import
|
|
2624
|
-
import
|
|
2625
|
-
import
|
|
3493
|
+
import crypto2 from "crypto";
|
|
3494
|
+
import path11 from "path";
|
|
3495
|
+
import os8 from "os";
|
|
2626
3496
|
import {
|
|
2627
|
-
readFileSync as
|
|
3497
|
+
readFileSync as readFileSync10,
|
|
2628
3498
|
readdirSync,
|
|
2629
|
-
unlinkSync as
|
|
2630
|
-
existsSync as
|
|
3499
|
+
unlinkSync as unlinkSync3,
|
|
3500
|
+
existsSync as existsSync11,
|
|
2631
3501
|
rmdirSync
|
|
2632
3502
|
} from "fs";
|
|
2633
3503
|
async function writeNotification(notification) {
|
|
2634
3504
|
try {
|
|
2635
3505
|
const client = getClient();
|
|
2636
|
-
const id =
|
|
3506
|
+
const id = crypto2.randomUUID();
|
|
2637
3507
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2638
3508
|
const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
|
|
2639
3509
|
await client.execute({
|
|
@@ -2677,7 +3547,7 @@ var init_notifications = __esm({
|
|
|
2677
3547
|
});
|
|
2678
3548
|
|
|
2679
3549
|
// src/lib/session-kill-telemetry.ts
|
|
2680
|
-
import
|
|
3550
|
+
import crypto3 from "crypto";
|
|
2681
3551
|
async function recordSessionKill(input) {
|
|
2682
3552
|
try {
|
|
2683
3553
|
const client = getClient();
|
|
@@ -2687,7 +3557,7 @@ async function recordSessionKill(input) {
|
|
|
2687
3557
|
ticks_idle, estimated_tokens_saved)
|
|
2688
3558
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
2689
3559
|
args: [
|
|
2690
|
-
|
|
3560
|
+
crypto3.randomUUID(),
|
|
2691
3561
|
input.sessionName,
|
|
2692
3562
|
input.agentId,
|
|
2693
3563
|
(/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2767,7 +3637,7 @@ var init_state_bus = __esm({
|
|
|
2767
3637
|
|
|
2768
3638
|
// src/lib/project-name.ts
|
|
2769
3639
|
import { execSync as execSync4 } from "child_process";
|
|
2770
|
-
import
|
|
3640
|
+
import path12 from "path";
|
|
2771
3641
|
function getProjectName(cwd) {
|
|
2772
3642
|
const dir = cwd ?? process.cwd();
|
|
2773
3643
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -2780,7 +3650,7 @@ function getProjectName(cwd) {
|
|
|
2780
3650
|
timeout: 2e3,
|
|
2781
3651
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2782
3652
|
}).trim();
|
|
2783
|
-
repoRoot =
|
|
3653
|
+
repoRoot = path12.dirname(gitCommonDir);
|
|
2784
3654
|
} catch {
|
|
2785
3655
|
repoRoot = execSync4("git rev-parse --show-toplevel", {
|
|
2786
3656
|
cwd: dir,
|
|
@@ -2789,11 +3659,11 @@ function getProjectName(cwd) {
|
|
|
2789
3659
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2790
3660
|
}).trim();
|
|
2791
3661
|
}
|
|
2792
|
-
_cached2 =
|
|
3662
|
+
_cached2 = path12.basename(repoRoot);
|
|
2793
3663
|
_cachedCwd = dir;
|
|
2794
3664
|
return _cached2;
|
|
2795
3665
|
} catch {
|
|
2796
|
-
_cached2 =
|
|
3666
|
+
_cached2 = path12.basename(dir);
|
|
2797
3667
|
_cachedCwd = dir;
|
|
2798
3668
|
return _cached2;
|
|
2799
3669
|
}
|
|
@@ -2870,12 +3740,12 @@ var init_session_scope = __esm({
|
|
|
2870
3740
|
});
|
|
2871
3741
|
|
|
2872
3742
|
// src/lib/tasks-crud.ts
|
|
2873
|
-
import
|
|
2874
|
-
import
|
|
2875
|
-
import
|
|
3743
|
+
import crypto4 from "crypto";
|
|
3744
|
+
import path13 from "path";
|
|
3745
|
+
import os9 from "os";
|
|
2876
3746
|
import { execSync as execSync5 } from "child_process";
|
|
2877
3747
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2878
|
-
import { existsSync as
|
|
3748
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
2879
3749
|
async function writeCheckpoint(input) {
|
|
2880
3750
|
const client = getClient();
|
|
2881
3751
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -2991,7 +3861,7 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
2991
3861
|
}
|
|
2992
3862
|
async function createTaskCore(input) {
|
|
2993
3863
|
const client = getClient();
|
|
2994
|
-
const id =
|
|
3864
|
+
const id = crypto4.randomUUID();
|
|
2995
3865
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2996
3866
|
const slug = slugify(input.title);
|
|
2997
3867
|
let earlySessionScope = null;
|
|
@@ -3000,15 +3870,20 @@ async function createTaskCore(input) {
|
|
|
3000
3870
|
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
3001
3871
|
const resolved = resolveExeSession2();
|
|
3002
3872
|
if (resolved && input.projectName) {
|
|
3003
|
-
const
|
|
3004
|
-
|
|
3005
|
-
if (sessionProject && sessionProject !== input.projectName) {
|
|
3006
|
-
scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
|
|
3007
|
-
process.stderr.write(`[create_task] ${scopeMismatchWarning}
|
|
3008
|
-
`);
|
|
3009
|
-
earlySessionScope = null;
|
|
3010
|
-
} else {
|
|
3873
|
+
const isCoordinatorSession = !resolved.includes("-");
|
|
3874
|
+
if (isCoordinatorSession) {
|
|
3011
3875
|
earlySessionScope = resolved;
|
|
3876
|
+
} else {
|
|
3877
|
+
const { getSessionProject: getSessionProject2 } = await Promise.resolve().then(() => (init_session_scope(), session_scope_exports));
|
|
3878
|
+
const sessionProject = getSessionProject2(resolved);
|
|
3879
|
+
if (sessionProject && sessionProject !== input.projectName) {
|
|
3880
|
+
scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
|
|
3881
|
+
process.stderr.write(`[create_task] ${scopeMismatchWarning}
|
|
3882
|
+
`);
|
|
3883
|
+
earlySessionScope = null;
|
|
3884
|
+
} else {
|
|
3885
|
+
earlySessionScope = resolved;
|
|
3886
|
+
}
|
|
3012
3887
|
}
|
|
3013
3888
|
} else {
|
|
3014
3889
|
earlySessionScope = resolved;
|
|
@@ -3069,8 +3944,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3069
3944
|
}
|
|
3070
3945
|
if (input.baseDir) {
|
|
3071
3946
|
try {
|
|
3072
|
-
await mkdir3(
|
|
3073
|
-
await mkdir3(
|
|
3947
|
+
await mkdir3(path13.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
3948
|
+
await mkdir3(path13.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
3074
3949
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
3075
3950
|
await ensureGitignoreExe(input.baseDir);
|
|
3076
3951
|
} catch {
|
|
@@ -3106,10 +3981,10 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3106
3981
|
});
|
|
3107
3982
|
if (input.baseDir) {
|
|
3108
3983
|
try {
|
|
3109
|
-
const EXE_OS_DIR =
|
|
3110
|
-
const mdPath =
|
|
3111
|
-
const mdDir =
|
|
3112
|
-
if (!
|
|
3984
|
+
const EXE_OS_DIR = path13.join(os9.homedir(), ".exe-os");
|
|
3985
|
+
const mdPath = path13.join(EXE_OS_DIR, taskFile);
|
|
3986
|
+
const mdDir = path13.dirname(mdPath);
|
|
3987
|
+
if (!existsSync12(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
3113
3988
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
3114
3989
|
const mdContent = `# ${input.title}
|
|
3115
3990
|
|
|
@@ -3409,9 +4284,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
3409
4284
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
3410
4285
|
}
|
|
3411
4286
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
3412
|
-
const archPath =
|
|
4287
|
+
const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
3413
4288
|
try {
|
|
3414
|
-
if (
|
|
4289
|
+
if (existsSync12(archPath)) return;
|
|
3415
4290
|
const template = [
|
|
3416
4291
|
`# ${projectName} \u2014 System Architecture`,
|
|
3417
4292
|
"",
|
|
@@ -3444,10 +4319,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
3444
4319
|
}
|
|
3445
4320
|
}
|
|
3446
4321
|
async function ensureGitignoreExe(baseDir) {
|
|
3447
|
-
const gitignorePath =
|
|
4322
|
+
const gitignorePath = path13.join(baseDir, ".gitignore");
|
|
3448
4323
|
try {
|
|
3449
|
-
if (
|
|
3450
|
-
const content =
|
|
4324
|
+
if (existsSync12(gitignorePath)) {
|
|
4325
|
+
const content = readFileSync11(gitignorePath, "utf-8");
|
|
3451
4326
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
3452
4327
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
3453
4328
|
} else {
|
|
@@ -3490,8 +4365,8 @@ __export(tasks_review_exports, {
|
|
|
3490
4365
|
isStale: () => isStale,
|
|
3491
4366
|
listPendingReviews: () => listPendingReviews
|
|
3492
4367
|
});
|
|
3493
|
-
import
|
|
3494
|
-
import { existsSync as
|
|
4368
|
+
import path14 from "path";
|
|
4369
|
+
import { existsSync as existsSync13, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
3495
4370
|
function formatAge(isoTimestamp) {
|
|
3496
4371
|
if (!isoTimestamp) return "";
|
|
3497
4372
|
const ms = Date.now() - new Date(isoTimestamp).getTime();
|
|
@@ -3760,11 +4635,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3760
4635
|
);
|
|
3761
4636
|
}
|
|
3762
4637
|
try {
|
|
3763
|
-
const cacheDir =
|
|
3764
|
-
if (
|
|
4638
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
4639
|
+
if (existsSync13(cacheDir)) {
|
|
3765
4640
|
for (const f of readdirSync2(cacheDir)) {
|
|
3766
4641
|
if (f.startsWith("review-notified-")) {
|
|
3767
|
-
|
|
4642
|
+
unlinkSync4(path14.join(cacheDir, f));
|
|
3768
4643
|
}
|
|
3769
4644
|
}
|
|
3770
4645
|
}
|
|
@@ -3786,7 +4661,7 @@ var init_tasks_review = __esm({
|
|
|
3786
4661
|
});
|
|
3787
4662
|
|
|
3788
4663
|
// src/lib/tasks-chain.ts
|
|
3789
|
-
import
|
|
4664
|
+
import path15 from "path";
|
|
3790
4665
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
3791
4666
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
3792
4667
|
const client = getClient();
|
|
@@ -3803,7 +4678,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
3803
4678
|
});
|
|
3804
4679
|
for (const ur of unblockedRows.rows) {
|
|
3805
4680
|
try {
|
|
3806
|
-
const ubFile =
|
|
4681
|
+
const ubFile = path15.join(baseDir, String(ur.task_file));
|
|
3807
4682
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
3808
4683
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
3809
4684
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -3893,6 +4768,10 @@ async function dispatchTaskToEmployee(input) {
|
|
|
3893
4768
|
if (transport.isAlive(sessionName)) {
|
|
3894
4769
|
const result2 = sendIntercom(sessionName);
|
|
3895
4770
|
const dispatched = result2 === "acknowledged" || result2 === "debounced" || result2 === "queued" ? "verified" : result2 === "delivered" ? "sent_unverified" : "session_dead";
|
|
4771
|
+
process.stderr.write(
|
|
4772
|
+
`[dispatch-audit] intercom \u2192 ${sessionName} | task="${input.title}" [${input.priority}] | result=${dispatched} (sendIntercom=${result2})
|
|
4773
|
+
`
|
|
4774
|
+
);
|
|
3896
4775
|
return { dispatched, session: sessionName, crossProject };
|
|
3897
4776
|
} else {
|
|
3898
4777
|
const projectDir2 = input.projectDir ?? process.cwd();
|
|
@@ -3901,11 +4780,15 @@ async function dispatchTaskToEmployee(input) {
|
|
|
3901
4780
|
});
|
|
3902
4781
|
if (result2.status === "failed") {
|
|
3903
4782
|
process.stderr.write(
|
|
3904
|
-
`[dispatch]
|
|
4783
|
+
`[dispatch-audit] SPAWN FAILED \u2192 ${input.assignedTo} | task="${input.title}" [${input.priority}] | error=${result2.error}
|
|
3905
4784
|
`
|
|
3906
4785
|
);
|
|
3907
4786
|
return { dispatched: "session_missing" };
|
|
3908
4787
|
}
|
|
4788
|
+
process.stderr.write(
|
|
4789
|
+
`[dispatch-audit] SPAWNED \u2192 ${result2.sessionName} | task="${input.title}" [${input.priority}]
|
|
4790
|
+
`
|
|
4791
|
+
);
|
|
3909
4792
|
return { dispatched: "spawned", session: result2.sessionName, crossProject };
|
|
3910
4793
|
}
|
|
3911
4794
|
} catch {
|
|
@@ -3915,7 +4798,13 @@ async function dispatchTaskToEmployee(input) {
|
|
|
3915
4798
|
function notifyTaskDone() {
|
|
3916
4799
|
try {
|
|
3917
4800
|
const key = getSessionKey();
|
|
3918
|
-
if (key && !process.env.VITEST)
|
|
4801
|
+
if (key && !process.env.VITEST) {
|
|
4802
|
+
notifyParentExe(key);
|
|
4803
|
+
process.stderr.write(
|
|
4804
|
+
`[dispatch-audit] notifyTaskDone \u2192 parent coordinator (session=${key})
|
|
4805
|
+
`
|
|
4806
|
+
);
|
|
4807
|
+
}
|
|
3919
4808
|
} catch {
|
|
3920
4809
|
}
|
|
3921
4810
|
}
|
|
@@ -3936,16 +4825,91 @@ var init_tasks_notify = __esm({
|
|
|
3936
4825
|
}
|
|
3937
4826
|
});
|
|
3938
4827
|
|
|
4828
|
+
// src/lib/embedder.ts
|
|
4829
|
+
var embedder_exports = {};
|
|
4830
|
+
__export(embedder_exports, {
|
|
4831
|
+
disposeEmbedder: () => disposeEmbedder,
|
|
4832
|
+
embed: () => embed,
|
|
4833
|
+
embedDirect: () => embedDirect,
|
|
4834
|
+
getEmbedder: () => getEmbedder
|
|
4835
|
+
});
|
|
4836
|
+
async function getEmbedder() {
|
|
4837
|
+
const ok = await connectEmbedDaemon();
|
|
4838
|
+
if (!ok) {
|
|
4839
|
+
throw new Error(
|
|
4840
|
+
"Could not connect to embedding daemon. Ensure the model is installed (run /exe-setup)."
|
|
4841
|
+
);
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
async function embed(text) {
|
|
4845
|
+
const priority = process.env.EXE_EMBED_PRIORITY === "low" ? "low" : "high";
|
|
4846
|
+
const vector = await embedViaClient(text, priority);
|
|
4847
|
+
if (!vector) {
|
|
4848
|
+
throw new Error(
|
|
4849
|
+
"Embedding failed: daemon unavailable. Run /exe-setup to verify model installation."
|
|
4850
|
+
);
|
|
4851
|
+
}
|
|
4852
|
+
if (vector.length !== EMBEDDING_DIM) {
|
|
4853
|
+
throw new Error(
|
|
4854
|
+
`Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}. Ensure the correct Jina v5-small Q4_K_M GGUF model is installed.`
|
|
4855
|
+
);
|
|
4856
|
+
}
|
|
4857
|
+
return vector;
|
|
4858
|
+
}
|
|
4859
|
+
async function disposeEmbedder() {
|
|
4860
|
+
disconnectClient();
|
|
4861
|
+
}
|
|
4862
|
+
async function embedDirect(text) {
|
|
4863
|
+
const llamaCpp = await import("node-llama-cpp");
|
|
4864
|
+
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4865
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
4866
|
+
const path20 = await import("path");
|
|
4867
|
+
const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
4868
|
+
if (!existsSync17(modelPath)) {
|
|
4869
|
+
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
4870
|
+
}
|
|
4871
|
+
const llama = await llamaCpp.getLlama();
|
|
4872
|
+
const model = await llama.loadModel({ modelPath });
|
|
4873
|
+
const context = await model.createEmbeddingContext();
|
|
4874
|
+
try {
|
|
4875
|
+
const embedding = await context.getEmbeddingFor(text);
|
|
4876
|
+
const vector = Array.from(embedding.vector);
|
|
4877
|
+
if (vector.length !== EMBEDDING_DIM) {
|
|
4878
|
+
throw new Error(
|
|
4879
|
+
`Embedding dimension mismatch: expected ${EMBEDDING_DIM}, got ${vector.length}.`
|
|
4880
|
+
);
|
|
4881
|
+
}
|
|
4882
|
+
return vector;
|
|
4883
|
+
} finally {
|
|
4884
|
+
await context.dispose();
|
|
4885
|
+
await model.dispose();
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
var init_embedder = __esm({
|
|
4889
|
+
"src/lib/embedder.ts"() {
|
|
4890
|
+
"use strict";
|
|
4891
|
+
init_memory();
|
|
4892
|
+
init_exe_daemon_client();
|
|
4893
|
+
}
|
|
4894
|
+
});
|
|
4895
|
+
|
|
3939
4896
|
// src/lib/behaviors.ts
|
|
3940
|
-
import
|
|
4897
|
+
import crypto5 from "crypto";
|
|
3941
4898
|
async function storeBehavior(opts) {
|
|
3942
4899
|
const client = getClient();
|
|
3943
|
-
const id =
|
|
4900
|
+
const id = crypto5.randomUUID();
|
|
3944
4901
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4902
|
+
let vector = null;
|
|
4903
|
+
try {
|
|
4904
|
+
const { embed: embed2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
|
|
4905
|
+
const vec = await embed2(opts.content);
|
|
4906
|
+
vector = new Float32Array(vec);
|
|
4907
|
+
} catch {
|
|
4908
|
+
}
|
|
3945
4909
|
await client.execute({
|
|
3946
|
-
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
|
|
3947
|
-
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
3948
|
-
args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now]
|
|
4910
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector)
|
|
4911
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?)`,
|
|
4912
|
+
args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now, vector ? vector.buffer : null]
|
|
3949
4913
|
});
|
|
3950
4914
|
return id;
|
|
3951
4915
|
}
|
|
@@ -3969,7 +4933,7 @@ __export(skill_learning_exports, {
|
|
|
3969
4933
|
storeTrajectory: () => storeTrajectory,
|
|
3970
4934
|
sweepTrajectories: () => sweepTrajectories
|
|
3971
4935
|
});
|
|
3972
|
-
import
|
|
4936
|
+
import crypto6 from "crypto";
|
|
3973
4937
|
async function extractTrajectory(taskId, agentId) {
|
|
3974
4938
|
const client = getClient();
|
|
3975
4939
|
const result2 = await client.execute({
|
|
@@ -3998,11 +4962,11 @@ async function extractTrajectory(taskId, agentId) {
|
|
|
3998
4962
|
return signature;
|
|
3999
4963
|
}
|
|
4000
4964
|
function hashSignature(signature) {
|
|
4001
|
-
return
|
|
4965
|
+
return crypto6.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
|
|
4002
4966
|
}
|
|
4003
4967
|
async function storeTrajectory(opts) {
|
|
4004
4968
|
const client = getClient();
|
|
4005
|
-
const id =
|
|
4969
|
+
const id = crypto6.randomUUID();
|
|
4006
4970
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4007
4971
|
const signatureHash = hashSignature(opts.signature);
|
|
4008
4972
|
await client.execute({
|
|
@@ -4267,8 +5231,8 @@ __export(tasks_exports, {
|
|
|
4267
5231
|
updateTaskStatus: () => updateTaskStatus,
|
|
4268
5232
|
writeCheckpoint: () => writeCheckpoint
|
|
4269
5233
|
});
|
|
4270
|
-
import
|
|
4271
|
-
import { writeFileSync as
|
|
5234
|
+
import path16 from "path";
|
|
5235
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
|
|
4272
5236
|
async function createTask(input) {
|
|
4273
5237
|
const result2 = await createTaskCore(input);
|
|
4274
5238
|
if (!input.skipDispatch && result2.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -4287,14 +5251,14 @@ async function updateTask(input) {
|
|
|
4287
5251
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
4288
5252
|
try {
|
|
4289
5253
|
const agent = String(row.assigned_to);
|
|
4290
|
-
const cacheDir =
|
|
4291
|
-
const cachePath =
|
|
5254
|
+
const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
|
|
5255
|
+
const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
|
|
4292
5256
|
if (input.status === "in_progress") {
|
|
4293
5257
|
mkdirSync5(cacheDir, { recursive: true });
|
|
4294
|
-
|
|
5258
|
+
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
4295
5259
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
|
|
4296
5260
|
try {
|
|
4297
|
-
|
|
5261
|
+
unlinkSync5(cachePath);
|
|
4298
5262
|
} catch {
|
|
4299
5263
|
}
|
|
4300
5264
|
}
|
|
@@ -4736,7 +5700,7 @@ var init_capacity_monitor = __esm({
|
|
|
4736
5700
|
// src/lib/tmux-routing.ts
|
|
4737
5701
|
var tmux_routing_exports = {};
|
|
4738
5702
|
__export(tmux_routing_exports, {
|
|
4739
|
-
acquireSpawnLock: () =>
|
|
5703
|
+
acquireSpawnLock: () => acquireSpawnLock2,
|
|
4740
5704
|
employeeSessionName: () => employeeSessionName,
|
|
4741
5705
|
ensureEmployee: () => ensureEmployee,
|
|
4742
5706
|
extractRootExe: () => extractRootExe,
|
|
@@ -4752,20 +5716,20 @@ __export(tmux_routing_exports, {
|
|
|
4752
5716
|
notifyParentExe: () => notifyParentExe,
|
|
4753
5717
|
parseParentExe: () => parseParentExe,
|
|
4754
5718
|
registerParentExe: () => registerParentExe,
|
|
4755
|
-
releaseSpawnLock: () =>
|
|
5719
|
+
releaseSpawnLock: () => releaseSpawnLock2,
|
|
4756
5720
|
resolveExeSession: () => resolveExeSession,
|
|
4757
5721
|
sendIntercom: () => sendIntercom,
|
|
4758
5722
|
spawnEmployee: () => spawnEmployee,
|
|
4759
5723
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
4760
5724
|
});
|
|
4761
5725
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
4762
|
-
import { readFileSync as
|
|
4763
|
-
import
|
|
4764
|
-
import
|
|
4765
|
-
import { fileURLToPath } from "url";
|
|
4766
|
-
import { unlinkSync as
|
|
5726
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
5727
|
+
import path17 from "path";
|
|
5728
|
+
import os10 from "os";
|
|
5729
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5730
|
+
import { unlinkSync as unlinkSync6 } from "fs";
|
|
4767
5731
|
function spawnLockPath(sessionName) {
|
|
4768
|
-
return
|
|
5732
|
+
return path17.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
4769
5733
|
}
|
|
4770
5734
|
function isProcessAlive(pid) {
|
|
4771
5735
|
try {
|
|
@@ -4775,14 +5739,14 @@ function isProcessAlive(pid) {
|
|
|
4775
5739
|
return false;
|
|
4776
5740
|
}
|
|
4777
5741
|
}
|
|
4778
|
-
function
|
|
4779
|
-
if (!
|
|
5742
|
+
function acquireSpawnLock2(sessionName) {
|
|
5743
|
+
if (!existsSync14(SPAWN_LOCK_DIR)) {
|
|
4780
5744
|
mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
|
|
4781
5745
|
}
|
|
4782
5746
|
const lockFile = spawnLockPath(sessionName);
|
|
4783
|
-
if (
|
|
5747
|
+
if (existsSync14(lockFile)) {
|
|
4784
5748
|
try {
|
|
4785
|
-
const lock = JSON.parse(
|
|
5749
|
+
const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
|
|
4786
5750
|
const age = Date.now() - lock.timestamp;
|
|
4787
5751
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
4788
5752
|
return false;
|
|
@@ -4790,25 +5754,25 @@ function acquireSpawnLock(sessionName) {
|
|
|
4790
5754
|
} catch {
|
|
4791
5755
|
}
|
|
4792
5756
|
}
|
|
4793
|
-
|
|
5757
|
+
writeFileSync8(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
4794
5758
|
return true;
|
|
4795
5759
|
}
|
|
4796
|
-
function
|
|
5760
|
+
function releaseSpawnLock2(sessionName) {
|
|
4797
5761
|
try {
|
|
4798
|
-
|
|
5762
|
+
unlinkSync6(spawnLockPath(sessionName));
|
|
4799
5763
|
} catch {
|
|
4800
5764
|
}
|
|
4801
5765
|
}
|
|
4802
5766
|
function resolveBehaviorsExporterScript() {
|
|
4803
5767
|
try {
|
|
4804
|
-
const thisFile =
|
|
4805
|
-
const scriptPath =
|
|
4806
|
-
|
|
5768
|
+
const thisFile = fileURLToPath2(import.meta.url);
|
|
5769
|
+
const scriptPath = path17.join(
|
|
5770
|
+
path17.dirname(thisFile),
|
|
4807
5771
|
"..",
|
|
4808
5772
|
"bin",
|
|
4809
5773
|
"exe-export-behaviors.js"
|
|
4810
5774
|
);
|
|
4811
|
-
return
|
|
5775
|
+
return existsSync14(scriptPath) ? scriptPath : null;
|
|
4812
5776
|
} catch {
|
|
4813
5777
|
return null;
|
|
4814
5778
|
}
|
|
@@ -4874,12 +5838,12 @@ function extractRootExe(name) {
|
|
|
4874
5838
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
4875
5839
|
}
|
|
4876
5840
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
4877
|
-
if (!
|
|
5841
|
+
if (!existsSync14(SESSION_CACHE)) {
|
|
4878
5842
|
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
4879
5843
|
}
|
|
4880
5844
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
4881
|
-
const filePath =
|
|
4882
|
-
|
|
5845
|
+
const filePath = path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
5846
|
+
writeFileSync8(filePath, JSON.stringify({
|
|
4883
5847
|
parentExe: rootExe,
|
|
4884
5848
|
dispatchedBy: dispatchedBy || rootExe,
|
|
4885
5849
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -4887,7 +5851,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4887
5851
|
}
|
|
4888
5852
|
function getParentExe(sessionKey) {
|
|
4889
5853
|
try {
|
|
4890
|
-
const data = JSON.parse(
|
|
5854
|
+
const data = JSON.parse(readFileSync12(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
4891
5855
|
return data.parentExe || null;
|
|
4892
5856
|
} catch {
|
|
4893
5857
|
return null;
|
|
@@ -4895,8 +5859,8 @@ function getParentExe(sessionKey) {
|
|
|
4895
5859
|
}
|
|
4896
5860
|
function getDispatchedBy(sessionKey) {
|
|
4897
5861
|
try {
|
|
4898
|
-
const data = JSON.parse(
|
|
4899
|
-
|
|
5862
|
+
const data = JSON.parse(readFileSync12(
|
|
5863
|
+
path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
4900
5864
|
"utf8"
|
|
4901
5865
|
));
|
|
4902
5866
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -4931,10 +5895,10 @@ function isEmployeeAlive(sessionName) {
|
|
|
4931
5895
|
}
|
|
4932
5896
|
function findFreeInstance(employeeName2, exeSession2, maxInstances = 10, isAlive = isEmployeeAlive) {
|
|
4933
5897
|
const base = employeeSessionName(employeeName2, exeSession2);
|
|
4934
|
-
if (!isAlive(base) &&
|
|
5898
|
+
if (!isAlive(base) && acquireSpawnLock2(base)) return 0;
|
|
4935
5899
|
for (let i = 2; i <= maxInstances; i++) {
|
|
4936
5900
|
const candidate = employeeSessionName(employeeName2, exeSession2, i);
|
|
4937
|
-
if (!isAlive(candidate) &&
|
|
5901
|
+
if (!isAlive(candidate) && acquireSpawnLock2(candidate)) return i;
|
|
4938
5902
|
}
|
|
4939
5903
|
return null;
|
|
4940
5904
|
}
|
|
@@ -4966,8 +5930,8 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
4966
5930
|
}
|
|
4967
5931
|
function readDebounceState() {
|
|
4968
5932
|
try {
|
|
4969
|
-
if (!
|
|
4970
|
-
const raw = JSON.parse(
|
|
5933
|
+
if (!existsSync14(DEBOUNCE_FILE)) return {};
|
|
5934
|
+
const raw = JSON.parse(readFileSync12(DEBOUNCE_FILE, "utf8"));
|
|
4971
5935
|
const state = {};
|
|
4972
5936
|
for (const [key, val] of Object.entries(raw)) {
|
|
4973
5937
|
if (typeof val === "number") {
|
|
@@ -4983,8 +5947,8 @@ function readDebounceState() {
|
|
|
4983
5947
|
}
|
|
4984
5948
|
function writeDebounceState(state) {
|
|
4985
5949
|
try {
|
|
4986
|
-
if (!
|
|
4987
|
-
|
|
5950
|
+
if (!existsSync14(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
5951
|
+
writeFileSync8(DEBOUNCE_FILE, JSON.stringify(state));
|
|
4988
5952
|
} catch {
|
|
4989
5953
|
}
|
|
4990
5954
|
}
|
|
@@ -5048,7 +6012,7 @@ function isSessionBusy(sessionName) {
|
|
|
5048
6012
|
function isExeSession(sessionName) {
|
|
5049
6013
|
const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
|
|
5050
6014
|
const coordinatorName = getCoordinatorName();
|
|
5051
|
-
return matchesBaseWithInstance(coordinatorName)
|
|
6015
|
+
return matchesBaseWithInstance(coordinatorName);
|
|
5052
6016
|
}
|
|
5053
6017
|
function sendIntercom(targetSession) {
|
|
5054
6018
|
const transport = getTransport();
|
|
@@ -5083,8 +6047,8 @@ function sendIntercom(targetSession) {
|
|
|
5083
6047
|
try {
|
|
5084
6048
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5085
6049
|
const agent = baseAgentName(rawAgent);
|
|
5086
|
-
const markerPath =
|
|
5087
|
-
if (
|
|
6050
|
+
const markerPath = path17.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
6051
|
+
if (existsSync14(markerPath)) {
|
|
5088
6052
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker + not idle \u2014 will auto-chain)`);
|
|
5089
6053
|
return "debounced";
|
|
5090
6054
|
}
|
|
@@ -5094,8 +6058,8 @@ function sendIntercom(targetSession) {
|
|
|
5094
6058
|
try {
|
|
5095
6059
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5096
6060
|
const agent = baseAgentName(rawAgent);
|
|
5097
|
-
const taskDir =
|
|
5098
|
-
if (
|
|
6061
|
+
const taskDir = path17.join(process.cwd(), "exe", agent);
|
|
6062
|
+
if (existsSync14(taskDir)) {
|
|
5099
6063
|
const files = readdirSync3(taskDir).filter(
|
|
5100
6064
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
5101
6065
|
);
|
|
@@ -5262,26 +6226,26 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5262
6226
|
const transport = getTransport();
|
|
5263
6227
|
const sessionName = employeeSessionName(employeeName2, exeSession2, opts?.instance);
|
|
5264
6228
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName2}${opts.instance}` : employeeName2;
|
|
5265
|
-
const logDir =
|
|
5266
|
-
const logFile =
|
|
5267
|
-
if (!
|
|
6229
|
+
const logDir = path17.join(os10.homedir(), ".exe-os", "session-logs");
|
|
6230
|
+
const logFile = path17.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
6231
|
+
if (!existsSync14(logDir)) {
|
|
5268
6232
|
mkdirSync6(logDir, { recursive: true });
|
|
5269
6233
|
}
|
|
5270
6234
|
transport.kill(sessionName);
|
|
5271
6235
|
let cleanupSuffix = "";
|
|
5272
6236
|
try {
|
|
5273
|
-
const thisFile =
|
|
5274
|
-
const cleanupScript =
|
|
5275
|
-
if (
|
|
6237
|
+
const thisFile = fileURLToPath2(import.meta.url);
|
|
6238
|
+
const cleanupScript = path17.join(path17.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
6239
|
+
if (existsSync14(cleanupScript)) {
|
|
5276
6240
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName2}" "${exeSession2}"`;
|
|
5277
6241
|
}
|
|
5278
6242
|
} catch {
|
|
5279
6243
|
}
|
|
5280
6244
|
try {
|
|
5281
|
-
const claudeJsonPath =
|
|
6245
|
+
const claudeJsonPath = path17.join(os10.homedir(), ".claude.json");
|
|
5282
6246
|
let claudeJson = {};
|
|
5283
6247
|
try {
|
|
5284
|
-
claudeJson = JSON.parse(
|
|
6248
|
+
claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
|
|
5285
6249
|
} catch {
|
|
5286
6250
|
}
|
|
5287
6251
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -5289,17 +6253,17 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5289
6253
|
const trustDir = opts?.cwd ?? projectDir2;
|
|
5290
6254
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
5291
6255
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
5292
|
-
|
|
6256
|
+
writeFileSync8(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
5293
6257
|
} catch {
|
|
5294
6258
|
}
|
|
5295
6259
|
try {
|
|
5296
|
-
const settingsDir =
|
|
6260
|
+
const settingsDir = path17.join(os10.homedir(), ".claude", "projects");
|
|
5297
6261
|
const normalizedKey = (opts?.cwd ?? projectDir2).replace(/\//g, "-").replace(/^-/, "");
|
|
5298
|
-
const projSettingsDir =
|
|
5299
|
-
const settingsPath =
|
|
6262
|
+
const projSettingsDir = path17.join(settingsDir, normalizedKey);
|
|
6263
|
+
const settingsPath = path17.join(projSettingsDir, "settings.json");
|
|
5300
6264
|
let settings = {};
|
|
5301
6265
|
try {
|
|
5302
|
-
settings = JSON.parse(
|
|
6266
|
+
settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
|
|
5303
6267
|
} catch {
|
|
5304
6268
|
}
|
|
5305
6269
|
const perms = settings.permissions ?? {};
|
|
@@ -5328,7 +6292,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5328
6292
|
perms.allow = allow;
|
|
5329
6293
|
settings.permissions = perms;
|
|
5330
6294
|
mkdirSync6(projSettingsDir, { recursive: true });
|
|
5331
|
-
|
|
6295
|
+
writeFileSync8(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5332
6296
|
}
|
|
5333
6297
|
} catch {
|
|
5334
6298
|
}
|
|
@@ -5343,8 +6307,8 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5343
6307
|
let behaviorsFlag = "";
|
|
5344
6308
|
let legacyFallbackWarned = false;
|
|
5345
6309
|
if (!useExeAgent && !useBinSymlink) {
|
|
5346
|
-
const identityPath =
|
|
5347
|
-
|
|
6310
|
+
const identityPath = path17.join(
|
|
6311
|
+
os10.homedir(),
|
|
5348
6312
|
".exe-os",
|
|
5349
6313
|
"identity",
|
|
5350
6314
|
`${employeeName2}.md`
|
|
@@ -5353,13 +6317,13 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5353
6317
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
5354
6318
|
if (hasAgentFlag) {
|
|
5355
6319
|
identityFlag = ` --agent ${employeeName2}`;
|
|
5356
|
-
} else if (
|
|
6320
|
+
} else if (existsSync14(identityPath)) {
|
|
5357
6321
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
5358
6322
|
legacyFallbackWarned = true;
|
|
5359
6323
|
}
|
|
5360
6324
|
const behaviorsFile = exportBehaviorsSync(
|
|
5361
6325
|
employeeName2,
|
|
5362
|
-
|
|
6326
|
+
path17.basename(spawnCwd),
|
|
5363
6327
|
sessionName
|
|
5364
6328
|
);
|
|
5365
6329
|
if (behaviorsFile) {
|
|
@@ -5374,16 +6338,16 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5374
6338
|
}
|
|
5375
6339
|
let sessionContextFlag = "";
|
|
5376
6340
|
try {
|
|
5377
|
-
const ctxDir =
|
|
6341
|
+
const ctxDir = path17.join(os10.homedir(), ".exe-os", "session-cache");
|
|
5378
6342
|
mkdirSync6(ctxDir, { recursive: true });
|
|
5379
|
-
const ctxFile =
|
|
6343
|
+
const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
|
|
5380
6344
|
const ctxContent = [
|
|
5381
6345
|
`## Session Context`,
|
|
5382
6346
|
`You are running in tmux session: ${sessionName}.`,
|
|
5383
6347
|
`Your parent coordinator session is ${exeSession2}.`,
|
|
5384
6348
|
`Your employees (if any) use the -${exeSession2} suffix.`
|
|
5385
6349
|
].join("\n");
|
|
5386
|
-
|
|
6350
|
+
writeFileSync8(ctxFile, ctxContent);
|
|
5387
6351
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
5388
6352
|
} catch {
|
|
5389
6353
|
}
|
|
@@ -5457,14 +6421,14 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5457
6421
|
command: spawnCommand
|
|
5458
6422
|
});
|
|
5459
6423
|
if (spawnResult.error) {
|
|
5460
|
-
|
|
6424
|
+
releaseSpawnLock2(sessionName);
|
|
5461
6425
|
return { sessionName, error: `tmux new-session failed: ${spawnResult.error}` };
|
|
5462
6426
|
}
|
|
5463
6427
|
transport.pipeLog(sessionName, logFile);
|
|
5464
6428
|
try {
|
|
5465
6429
|
const mySession = getMySession();
|
|
5466
|
-
const dispatchInfo =
|
|
5467
|
-
|
|
6430
|
+
const dispatchInfo = path17.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
6431
|
+
writeFileSync8(dispatchInfo, JSON.stringify({
|
|
5468
6432
|
dispatchedBy: mySession,
|
|
5469
6433
|
rootExe: exeSession2,
|
|
5470
6434
|
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
@@ -5502,7 +6466,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5502
6466
|
}
|
|
5503
6467
|
}
|
|
5504
6468
|
if (!booted) {
|
|
5505
|
-
|
|
6469
|
+
releaseSpawnLock2(sessionName);
|
|
5506
6470
|
const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
|
|
5507
6471
|
return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
|
|
5508
6472
|
}
|
|
@@ -5520,7 +6484,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
5520
6484
|
pid: 0,
|
|
5521
6485
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5522
6486
|
});
|
|
5523
|
-
|
|
6487
|
+
releaseSpawnLock2(sessionName);
|
|
5524
6488
|
return { sessionName };
|
|
5525
6489
|
}
|
|
5526
6490
|
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, CODEX_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
@@ -5538,20 +6502,77 @@ var init_tmux_routing = __esm({
|
|
|
5538
6502
|
init_intercom_queue();
|
|
5539
6503
|
init_plan_limits();
|
|
5540
6504
|
init_employees();
|
|
5541
|
-
SPAWN_LOCK_DIR =
|
|
5542
|
-
SESSION_CACHE =
|
|
6505
|
+
SPAWN_LOCK_DIR = path17.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
6506
|
+
SESSION_CACHE = path17.join(os10.homedir(), ".exe-os", "session-cache");
|
|
5543
6507
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5544
6508
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
5545
6509
|
VERIFY_PANE_LINES = 200;
|
|
5546
6510
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5547
6511
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
5548
|
-
INTERCOM_LOG2 =
|
|
5549
|
-
DEBOUNCE_FILE =
|
|
6512
|
+
INTERCOM_LOG2 = path17.join(os10.homedir(), ".exe-os", "intercom.log");
|
|
6513
|
+
DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
|
|
5550
6514
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
5551
6515
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
5552
6516
|
}
|
|
5553
6517
|
});
|
|
5554
6518
|
|
|
6519
|
+
// src/lib/keychain.ts
|
|
6520
|
+
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
6521
|
+
import { existsSync as existsSync15 } from "fs";
|
|
6522
|
+
import path18 from "path";
|
|
6523
|
+
import os11 from "os";
|
|
6524
|
+
function getKeyDir() {
|
|
6525
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path18.join(os11.homedir(), ".exe-os");
|
|
6526
|
+
}
|
|
6527
|
+
function getKeyPath() {
|
|
6528
|
+
return path18.join(getKeyDir(), "master.key");
|
|
6529
|
+
}
|
|
6530
|
+
async function tryKeytar() {
|
|
6531
|
+
try {
|
|
6532
|
+
return await import("keytar");
|
|
6533
|
+
} catch {
|
|
6534
|
+
return null;
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
async function getMasterKey() {
|
|
6538
|
+
const keytar = await tryKeytar();
|
|
6539
|
+
if (keytar) {
|
|
6540
|
+
try {
|
|
6541
|
+
const stored = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
6542
|
+
if (stored) {
|
|
6543
|
+
return Buffer.from(stored, "base64");
|
|
6544
|
+
}
|
|
6545
|
+
} catch {
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
const keyPath = getKeyPath();
|
|
6549
|
+
if (!existsSync15(keyPath)) {
|
|
6550
|
+
process.stderr.write(
|
|
6551
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os11.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
6552
|
+
`
|
|
6553
|
+
);
|
|
6554
|
+
return null;
|
|
6555
|
+
}
|
|
6556
|
+
try {
|
|
6557
|
+
const content = await readFile4(keyPath, "utf-8");
|
|
6558
|
+
return Buffer.from(content.trim(), "base64");
|
|
6559
|
+
} catch (err) {
|
|
6560
|
+
process.stderr.write(
|
|
6561
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
6562
|
+
`
|
|
6563
|
+
);
|
|
6564
|
+
return null;
|
|
6565
|
+
}
|
|
6566
|
+
}
|
|
6567
|
+
var SERVICE, ACCOUNT;
|
|
6568
|
+
var init_keychain = __esm({
|
|
6569
|
+
"src/lib/keychain.ts"() {
|
|
6570
|
+
"use strict";
|
|
6571
|
+
SERVICE = "exe-mem";
|
|
6572
|
+
ACCOUNT = "master-key";
|
|
6573
|
+
}
|
|
6574
|
+
});
|
|
6575
|
+
|
|
5555
6576
|
// src/lib/shard-manager.ts
|
|
5556
6577
|
var shard_manager_exports = {};
|
|
5557
6578
|
__export(shard_manager_exports, {
|
|
@@ -5566,12 +6587,12 @@ __export(shard_manager_exports, {
|
|
|
5566
6587
|
listShards: () => listShards,
|
|
5567
6588
|
shardExists: () => shardExists
|
|
5568
6589
|
});
|
|
5569
|
-
import
|
|
5570
|
-
import { existsSync as
|
|
6590
|
+
import path19 from "path";
|
|
6591
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
|
|
5571
6592
|
import { createClient as createClient2 } from "@libsql/client";
|
|
5572
6593
|
function initShardManager(encryptionKey) {
|
|
5573
6594
|
_encryptionKey = encryptionKey;
|
|
5574
|
-
if (!
|
|
6595
|
+
if (!existsSync16(SHARDS_DIR)) {
|
|
5575
6596
|
mkdirSync7(SHARDS_DIR, { recursive: true });
|
|
5576
6597
|
}
|
|
5577
6598
|
_shardingEnabled = true;
|
|
@@ -5601,7 +6622,7 @@ function getShardClient(projectName) {
|
|
|
5601
6622
|
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
5602
6623
|
evictLRU();
|
|
5603
6624
|
}
|
|
5604
|
-
const dbPath =
|
|
6625
|
+
const dbPath = path19.join(SHARDS_DIR, `${safeName}.db`);
|
|
5605
6626
|
const client = createClient2({
|
|
5606
6627
|
url: `file:${dbPath}`,
|
|
5607
6628
|
encryptionKey: _encryptionKey
|
|
@@ -5612,10 +6633,10 @@ function getShardClient(projectName) {
|
|
|
5612
6633
|
}
|
|
5613
6634
|
function shardExists(projectName) {
|
|
5614
6635
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5615
|
-
return
|
|
6636
|
+
return existsSync16(path19.join(SHARDS_DIR, `${safeName}.db`));
|
|
5616
6637
|
}
|
|
5617
6638
|
function listShards() {
|
|
5618
|
-
if (!
|
|
6639
|
+
if (!existsSync16(SHARDS_DIR)) return [];
|
|
5619
6640
|
return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
5620
6641
|
}
|
|
5621
6642
|
async function ensureShardSchema(client) {
|
|
@@ -5862,7 +6883,7 @@ var init_shard_manager = __esm({
|
|
|
5862
6883
|
"src/lib/shard-manager.ts"() {
|
|
5863
6884
|
"use strict";
|
|
5864
6885
|
init_config();
|
|
5865
|
-
SHARDS_DIR =
|
|
6886
|
+
SHARDS_DIR = path19.join(EXE_AI_DIR, "shards");
|
|
5866
6887
|
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
5867
6888
|
MAX_OPEN_SHARDS = 10;
|
|
5868
6889
|
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
@@ -5982,6 +7003,68 @@ var init_platform_procedures = __esm({
|
|
|
5982
7003
|
domain: "architecture",
|
|
5983
7004
|
priority: "p0",
|
|
5984
7005
|
content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
|
|
7006
|
+
},
|
|
7007
|
+
// --- MCP is the ONLY data interface ---
|
|
7008
|
+
{
|
|
7009
|
+
title: "MCP disconnect \u2014 ask the user, never work around it",
|
|
7010
|
+
domain: "workflow",
|
|
7011
|
+
priority: "p0",
|
|
7012
|
+
content: "If MCP tools are unavailable, disconnected, or returning connection errors: STOP. Tell the user clearly: 'MCP server is disconnected. Please run /mcp to reconnect.' Do NOT attempt workarounds \u2014 no raw Node imports, no direct DB access, no CLI hacks, no daemon socket calls. MCP is the ONLY data interface. Working around it wastes time, hits bundling issues, and bypasses the contract boundary. Ask once, wait, proceed when reconnected."
|
|
7013
|
+
},
|
|
7014
|
+
// --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
|
|
7015
|
+
{
|
|
7016
|
+
title: "MCP tools \u2014 memory and search",
|
|
7017
|
+
domain: "tool-use",
|
|
7018
|
+
priority: "p1",
|
|
7019
|
+
content: "recall_my_memory: search your own memories (semantic + FTS). ask_team_memory: search a colleague's memories by agent name. store_memory: persist a memory (decisions, summaries, context). commit_memory: high-importance memory that survives consolidation. search_everything: unified search across memories, tasks, entities, conversations. get_session_context: temporal window of memories around a timestamp. consolidate_memories: merge duplicate/related memories into insights. get_memory_cardinality: count memories per agent (health check)."
|
|
7020
|
+
},
|
|
7021
|
+
{
|
|
7022
|
+
title: "MCP tools \u2014 task orchestration",
|
|
7023
|
+
domain: "tool-use",
|
|
7024
|
+
priority: "p1",
|
|
7025
|
+
content: "create_task: dispatch work to an employee (auto-spawns session). The ONLY dispatch path. list_tasks: query tasks by status, assignee, project. get_task: fetch full task details by ID. update_task: change status (in_progress, done, blocked, cancelled) + add result summary. close_task: finalize a reviewed task (COO only). checkpoint_task: save progress state for crash recovery. resume_employee: re-spawn an employee session for an existing task."
|
|
7026
|
+
},
|
|
7027
|
+
{
|
|
7028
|
+
title: "MCP tools \u2014 knowledge graph (GraphRAG)",
|
|
7029
|
+
domain: "tool-use",
|
|
7030
|
+
priority: "p1",
|
|
7031
|
+
content: "query_relationships: find connections between entities in the knowledge graph. get_entity_neighbors: explore an entity's direct connections. get_hot_entities: find most-referenced entities (trending topics). get_graph_stats: graph health \u2014 entity/relationship counts, density. export_graph: export graph data for visualization. merge_entities: deduplicate entities (alias resolution). find_similar_trajectories: match tool-call patterns to past task solutions."
|
|
7032
|
+
},
|
|
7033
|
+
{
|
|
7034
|
+
title: "MCP tools \u2014 identity, behavior, and decisions",
|
|
7035
|
+
domain: "tool-use",
|
|
7036
|
+
priority: "p1",
|
|
7037
|
+
content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query."
|
|
7038
|
+
},
|
|
7039
|
+
{
|
|
7040
|
+
title: "MCP tools \u2014 communication and messaging",
|
|
7041
|
+
domain: "tool-use",
|
|
7042
|
+
priority: "p1",
|
|
7043
|
+
content: "send_message: send supplementary context to another agent (NOT for actionable work \u2014 use create_task). acknowledge_messages: mark messages as read. send_whatsapp: send WhatsApp message via gateway (customer-facing alerts). query_conversations: search ingested conversations across all channels (WhatsApp, email, etc.)."
|
|
7044
|
+
},
|
|
7045
|
+
{
|
|
7046
|
+
title: "MCP tools \u2014 wiki, documents, and content",
|
|
7047
|
+
domain: "tool-use",
|
|
7048
|
+
priority: "p1",
|
|
7049
|
+
content: "create_wiki_page: create a wiki page in exe-wiki. list_wiki_pages: browse wiki pages. get_wiki_page: read a wiki page. update_wiki_page: edit a wiki page. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
|
|
7050
|
+
},
|
|
7051
|
+
{
|
|
7052
|
+
title: "MCP tools \u2014 system, operations, and admin",
|
|
7053
|
+
domain: "tool-use",
|
|
7054
|
+
priority: "p1",
|
|
7055
|
+
content: "get_agent_spend: token usage per agent/session (cost tracking). list_agent_sessions: view agent session history. get_session_kills: audit log of killed sessions. get_daemon_health: check exed daemon status. get_auto_wake_status: daemon auto-wake configuration. get_worker_gate: check worker deployment gates. run_memory_audit: health check \u2014 duplicates, null vectors, orphaned rows. run_consolidation: trigger sleep-time memory consolidation. cloud_sync: force a cloud sync cycle. backup_vps: trigger VPS backup."
|
|
7056
|
+
},
|
|
7057
|
+
{
|
|
7058
|
+
title: "MCP tools \u2014 config, licensing, and team",
|
|
7059
|
+
domain: "tool-use",
|
|
7060
|
+
priority: "p1",
|
|
7061
|
+
content: "set_agent_config: view/change per-agent runtime and model settings. list_employees: view the employee roster. add_person: add a person to the CRM contacts roster. list_people: browse CRM contacts. get_person: fetch contact details. get_license_status: check license validity. create_license: generate a new license key (admin). list_licenses: view all issued licenses. activate_license: activate a license on a device."
|
|
7062
|
+
},
|
|
7063
|
+
{
|
|
7064
|
+
title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
|
|
7065
|
+
domain: "tool-use",
|
|
7066
|
+
priority: "p1",
|
|
7067
|
+
content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage Layer 0 procedures (actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
|
|
5985
7068
|
}
|
|
5986
7069
|
];
|
|
5987
7070
|
PLATFORM_PROCEDURE_TITLES = new Set(
|
|
@@ -5998,7 +7081,7 @@ __export(global_procedures_exports, {
|
|
|
5998
7081
|
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
5999
7082
|
storeGlobalProcedure: () => storeGlobalProcedure
|
|
6000
7083
|
});
|
|
6001
|
-
import { randomUUID as
|
|
7084
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6002
7085
|
async function loadGlobalProcedures() {
|
|
6003
7086
|
const client = getClient();
|
|
6004
7087
|
const result2 = await client.execute({
|
|
@@ -6027,7 +7110,7 @@ ${sections.join("\n\n")}
|
|
|
6027
7110
|
`;
|
|
6028
7111
|
}
|
|
6029
7112
|
async function storeGlobalProcedure(input) {
|
|
6030
|
-
const id =
|
|
7113
|
+
const id = randomUUID3();
|
|
6031
7114
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6032
7115
|
const client = getClient();
|
|
6033
7116
|
await client.execute({
|
|
@@ -6061,70 +7144,25 @@ ${p.content}`).join("\n\n");
|
|
|
6061
7144
|
}
|
|
6062
7145
|
});
|
|
6063
7146
|
|
|
6064
|
-
// src/bin/exe-dispatch.ts
|
|
6065
|
-
init_tmux_routing();
|
|
6066
|
-
init_tasks_crud();
|
|
6067
|
-
|
|
6068
7147
|
// src/lib/store.ts
|
|
7148
|
+
var store_exports = {};
|
|
7149
|
+
__export(store_exports, {
|
|
7150
|
+
attachDocumentMetadata: () => attachDocumentMetadata,
|
|
7151
|
+
buildRawVisibilityFilter: () => buildRawVisibilityFilter,
|
|
7152
|
+
buildWikiScopeFilter: () => buildWikiScopeFilter,
|
|
7153
|
+
classifyTier: () => classifyTier,
|
|
7154
|
+
disposeStore: () => disposeStore,
|
|
7155
|
+
flushBatch: () => flushBatch,
|
|
7156
|
+
flushTier3: () => flushTier3,
|
|
7157
|
+
getMemoryCardinality: () => getMemoryCardinality,
|
|
7158
|
+
initStore: () => initStore,
|
|
7159
|
+
reserveVersions: () => reserveVersions,
|
|
7160
|
+
searchMemories: () => searchMemories,
|
|
7161
|
+
updateMemoryStatus: () => updateMemoryStatus,
|
|
7162
|
+
vectorToBlob: () => vectorToBlob,
|
|
7163
|
+
writeMemory: () => writeMemory
|
|
7164
|
+
});
|
|
6069
7165
|
import { createHash } from "crypto";
|
|
6070
|
-
init_database();
|
|
6071
|
-
|
|
6072
|
-
// src/lib/keychain.ts
|
|
6073
|
-
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
6074
|
-
import { existsSync as existsSync13 } from "fs";
|
|
6075
|
-
import path16 from "path";
|
|
6076
|
-
import os10 from "os";
|
|
6077
|
-
var SERVICE = "exe-mem";
|
|
6078
|
-
var ACCOUNT = "master-key";
|
|
6079
|
-
function getKeyDir() {
|
|
6080
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path16.join(os10.homedir(), ".exe-os");
|
|
6081
|
-
}
|
|
6082
|
-
function getKeyPath() {
|
|
6083
|
-
return path16.join(getKeyDir(), "master.key");
|
|
6084
|
-
}
|
|
6085
|
-
async function tryKeytar() {
|
|
6086
|
-
try {
|
|
6087
|
-
return await import("keytar");
|
|
6088
|
-
} catch {
|
|
6089
|
-
return null;
|
|
6090
|
-
}
|
|
6091
|
-
}
|
|
6092
|
-
async function getMasterKey() {
|
|
6093
|
-
const keytar = await tryKeytar();
|
|
6094
|
-
if (keytar) {
|
|
6095
|
-
try {
|
|
6096
|
-
const stored = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
6097
|
-
if (stored) {
|
|
6098
|
-
return Buffer.from(stored, "base64");
|
|
6099
|
-
}
|
|
6100
|
-
} catch {
|
|
6101
|
-
}
|
|
6102
|
-
}
|
|
6103
|
-
const keyPath = getKeyPath();
|
|
6104
|
-
if (!existsSync13(keyPath)) {
|
|
6105
|
-
process.stderr.write(
|
|
6106
|
-
`[keychain] Key not found at ${keyPath} (HOME=${os10.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
6107
|
-
`
|
|
6108
|
-
);
|
|
6109
|
-
return null;
|
|
6110
|
-
}
|
|
6111
|
-
try {
|
|
6112
|
-
const content = await readFile4(keyPath, "utf-8");
|
|
6113
|
-
return Buffer.from(content.trim(), "base64");
|
|
6114
|
-
} catch (err) {
|
|
6115
|
-
process.stderr.write(
|
|
6116
|
-
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
6117
|
-
`
|
|
6118
|
-
);
|
|
6119
|
-
return null;
|
|
6120
|
-
}
|
|
6121
|
-
}
|
|
6122
|
-
|
|
6123
|
-
// src/lib/store.ts
|
|
6124
|
-
init_config();
|
|
6125
|
-
init_state_bus();
|
|
6126
|
-
var INIT_MAX_RETRIES = 3;
|
|
6127
|
-
var INIT_RETRY_DELAY_MS = 1e3;
|
|
6128
7166
|
function isBusyError2(err) {
|
|
6129
7167
|
if (err instanceof Error) {
|
|
6130
7168
|
const msg = err.message.toLowerCase();
|
|
@@ -6147,12 +7185,6 @@ async function retryOnBusy2(fn, label) {
|
|
|
6147
7185
|
}
|
|
6148
7186
|
throw new Error("unreachable");
|
|
6149
7187
|
}
|
|
6150
|
-
var _pendingRecords = [];
|
|
6151
|
-
var _batchSize = 20;
|
|
6152
|
-
var _flushIntervalMs = 1e4;
|
|
6153
|
-
var _flushTimer = null;
|
|
6154
|
-
var _flushing = false;
|
|
6155
|
-
var _nextVersion = 1;
|
|
6156
7188
|
async function initStore(options) {
|
|
6157
7189
|
if (_flushTimer !== null) {
|
|
6158
7190
|
clearInterval(_flushTimer);
|
|
@@ -6182,6 +7214,11 @@ async function initStore(options) {
|
|
|
6182
7214
|
encryptionKey: hexKey
|
|
6183
7215
|
});
|
|
6184
7216
|
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
7217
|
+
try {
|
|
7218
|
+
const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
7219
|
+
await initDaemonClient2();
|
|
7220
|
+
} catch {
|
|
7221
|
+
}
|
|
6185
7222
|
if (!options?.lightweight) {
|
|
6186
7223
|
try {
|
|
6187
7224
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -6201,6 +7238,565 @@ async function initStore(options) {
|
|
|
6201
7238
|
}
|
|
6202
7239
|
}
|
|
6203
7240
|
}
|
|
7241
|
+
function classifyTier(record) {
|
|
7242
|
+
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
7243
|
+
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
7244
|
+
return 3;
|
|
7245
|
+
}
|
|
7246
|
+
function inferFilePaths(record) {
|
|
7247
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
7248
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
7249
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
7250
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
7251
|
+
}
|
|
7252
|
+
function inferCommitHash(record) {
|
|
7253
|
+
if (record.tool_name !== "Bash") return null;
|
|
7254
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
7255
|
+
return match ? match[1] : null;
|
|
7256
|
+
}
|
|
7257
|
+
function inferLanguageType(record) {
|
|
7258
|
+
const text = record.raw_text;
|
|
7259
|
+
if (!text || text.length < 10) return null;
|
|
7260
|
+
const trimmed = text.trimStart();
|
|
7261
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
7262
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
7263
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
7264
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
7265
|
+
return "mixed";
|
|
7266
|
+
}
|
|
7267
|
+
function inferDomain(record) {
|
|
7268
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
7269
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
7270
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
7271
|
+
return null;
|
|
7272
|
+
}
|
|
7273
|
+
async function writeMemory(record) {
|
|
7274
|
+
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
7275
|
+
throw new Error(
|
|
7276
|
+
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
7277
|
+
);
|
|
7278
|
+
}
|
|
7279
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
7280
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
7281
|
+
return;
|
|
7282
|
+
}
|
|
7283
|
+
try {
|
|
7284
|
+
const client = getClient();
|
|
7285
|
+
const existing = await client.execute({
|
|
7286
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
7287
|
+
args: [contentHash, record.agent_id]
|
|
7288
|
+
});
|
|
7289
|
+
if (existing.rows.length > 0) return;
|
|
7290
|
+
} catch {
|
|
7291
|
+
}
|
|
7292
|
+
const dbRow = {
|
|
7293
|
+
id: record.id,
|
|
7294
|
+
agent_id: record.agent_id,
|
|
7295
|
+
agent_role: record.agent_role,
|
|
7296
|
+
session_id: record.session_id,
|
|
7297
|
+
timestamp: record.timestamp,
|
|
7298
|
+
tool_name: record.tool_name,
|
|
7299
|
+
project_name: record.project_name,
|
|
7300
|
+
has_error: record.has_error ? 1 : 0,
|
|
7301
|
+
raw_text: record.raw_text,
|
|
7302
|
+
vector: record.vector,
|
|
7303
|
+
version: 0,
|
|
7304
|
+
// Placeholder — assigned atomically at flush time
|
|
7305
|
+
task_id: record.task_id ?? null,
|
|
7306
|
+
importance: record.importance ?? 5,
|
|
7307
|
+
status: record.status ?? "active",
|
|
7308
|
+
confidence: record.confidence ?? 0.7,
|
|
7309
|
+
last_accessed: record.last_accessed ?? record.timestamp,
|
|
7310
|
+
workspace_id: record.workspace_id ?? null,
|
|
7311
|
+
document_id: record.document_id ?? null,
|
|
7312
|
+
user_id: record.user_id ?? null,
|
|
7313
|
+
char_offset: record.char_offset ?? null,
|
|
7314
|
+
page_number: record.page_number ?? null,
|
|
7315
|
+
source_path: record.source_path ?? null,
|
|
7316
|
+
source_type: record.source_type ?? null,
|
|
7317
|
+
tier: record.tier ?? classifyTier(record),
|
|
7318
|
+
supersedes_id: record.supersedes_id ?? null,
|
|
7319
|
+
draft: record.draft ? 1 : 0,
|
|
7320
|
+
memory_type: record.memory_type ?? "raw",
|
|
7321
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
7322
|
+
content_hash: contentHash,
|
|
7323
|
+
intent: record.intent ?? null,
|
|
7324
|
+
outcome: record.outcome ?? null,
|
|
7325
|
+
domain: record.domain ?? inferDomain(record),
|
|
7326
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
7327
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
7328
|
+
chain_position: record.chain_position ?? null,
|
|
7329
|
+
review_status: record.review_status ?? null,
|
|
7330
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
7331
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
7332
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
7333
|
+
duration_ms: record.duration_ms ?? null,
|
|
7334
|
+
token_cost: record.token_cost ?? null,
|
|
7335
|
+
audience: record.audience ?? null,
|
|
7336
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
7337
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
7338
|
+
};
|
|
7339
|
+
_pendingRecords.push(dbRow);
|
|
7340
|
+
orgBus.emit({
|
|
7341
|
+
type: "memory_stored",
|
|
7342
|
+
agentId: record.agent_id,
|
|
7343
|
+
project: record.project_name,
|
|
7344
|
+
timestamp: record.timestamp
|
|
7345
|
+
});
|
|
7346
|
+
const MAX_PENDING = 1e3;
|
|
7347
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
7348
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
7349
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
7350
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
7351
|
+
}
|
|
7352
|
+
if (_flushTimer === null) {
|
|
7353
|
+
_flushTimer = setInterval(() => {
|
|
7354
|
+
void flushBatch();
|
|
7355
|
+
}, _flushIntervalMs);
|
|
7356
|
+
if (_flushTimer && typeof _flushTimer === "object" && "unref" in _flushTimer) {
|
|
7357
|
+
_flushTimer.unref();
|
|
7358
|
+
}
|
|
7359
|
+
}
|
|
7360
|
+
if (_pendingRecords.length >= _batchSize) {
|
|
7361
|
+
await flushBatch();
|
|
7362
|
+
}
|
|
7363
|
+
}
|
|
7364
|
+
async function flushBatch() {
|
|
7365
|
+
if (_flushing || _pendingRecords.length === 0) return 0;
|
|
7366
|
+
_flushing = true;
|
|
7367
|
+
try {
|
|
7368
|
+
const batch = _pendingRecords.slice(0);
|
|
7369
|
+
const client = getClient();
|
|
7370
|
+
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
7371
|
+
let baseVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
7372
|
+
for (const row of batch) {
|
|
7373
|
+
row.version = baseVersion++;
|
|
7374
|
+
}
|
|
7375
|
+
_nextVersion = baseVersion;
|
|
7376
|
+
const buildStmt = (row) => {
|
|
7377
|
+
const hasVector = row.vector !== null;
|
|
7378
|
+
const taskId = row.task_id ?? null;
|
|
7379
|
+
const importance = row.importance ?? 5;
|
|
7380
|
+
const status = row.status ?? "active";
|
|
7381
|
+
const confidence = row.confidence ?? 0.7;
|
|
7382
|
+
const lastAccessed = row.last_accessed ?? row.timestamp;
|
|
7383
|
+
const workspaceId = row.workspace_id ?? null;
|
|
7384
|
+
const documentId = row.document_id ?? null;
|
|
7385
|
+
const userId = row.user_id ?? null;
|
|
7386
|
+
const charOffset = row.char_offset ?? null;
|
|
7387
|
+
const pageNumber = row.page_number ?? null;
|
|
7388
|
+
const sourcePath = row.source_path ?? null;
|
|
7389
|
+
const sourceType = row.source_type ?? null;
|
|
7390
|
+
const tier = row.tier ?? 3;
|
|
7391
|
+
const supersedesId = row.supersedes_id ?? null;
|
|
7392
|
+
const draft = row.draft ? 1 : 0;
|
|
7393
|
+
const memoryType = row.memory_type ?? "raw";
|
|
7394
|
+
const trajectory = row.trajectory ?? null;
|
|
7395
|
+
const contentHash = row.content_hash ?? null;
|
|
7396
|
+
const intent = row.intent ?? null;
|
|
7397
|
+
const outcome = row.outcome ?? null;
|
|
7398
|
+
const domain = row.domain ?? null;
|
|
7399
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
7400
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
7401
|
+
const chainPosition = row.chain_position ?? null;
|
|
7402
|
+
const reviewStatus = row.review_status ?? null;
|
|
7403
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
7404
|
+
const filePaths = row.file_paths ?? null;
|
|
7405
|
+
const commitHash = row.commit_hash ?? null;
|
|
7406
|
+
const durationMs = row.duration_ms ?? null;
|
|
7407
|
+
const tokenCost = row.token_cost ?? null;
|
|
7408
|
+
const audience = row.audience ?? null;
|
|
7409
|
+
const languageType = row.language_type ?? null;
|
|
7410
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
7411
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
7412
|
+
tool_name, project_name,
|
|
7413
|
+
has_error, raw_text, vector, version, task_id, importance, status,
|
|
7414
|
+
confidence, last_accessed,
|
|
7415
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
7416
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
7417
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
7418
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
7419
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
7420
|
+
const metaArgs = [
|
|
7421
|
+
intent,
|
|
7422
|
+
outcome,
|
|
7423
|
+
domain,
|
|
7424
|
+
referencedEntities,
|
|
7425
|
+
retrievalCount,
|
|
7426
|
+
chainPosition,
|
|
7427
|
+
reviewStatus,
|
|
7428
|
+
contextWindowPct,
|
|
7429
|
+
filePaths,
|
|
7430
|
+
commitHash,
|
|
7431
|
+
durationMs,
|
|
7432
|
+
tokenCost,
|
|
7433
|
+
audience,
|
|
7434
|
+
languageType,
|
|
7435
|
+
parentMemoryId
|
|
7436
|
+
];
|
|
7437
|
+
const baseArgs = [
|
|
7438
|
+
row.id,
|
|
7439
|
+
row.agent_id,
|
|
7440
|
+
row.agent_role,
|
|
7441
|
+
row.session_id,
|
|
7442
|
+
row.timestamp,
|
|
7443
|
+
row.tool_name,
|
|
7444
|
+
row.project_name,
|
|
7445
|
+
row.has_error,
|
|
7446
|
+
row.raw_text
|
|
7447
|
+
];
|
|
7448
|
+
const sharedArgs = [
|
|
7449
|
+
row.version,
|
|
7450
|
+
taskId,
|
|
7451
|
+
importance,
|
|
7452
|
+
status,
|
|
7453
|
+
confidence,
|
|
7454
|
+
lastAccessed,
|
|
7455
|
+
workspaceId,
|
|
7456
|
+
documentId,
|
|
7457
|
+
userId,
|
|
7458
|
+
charOffset,
|
|
7459
|
+
pageNumber,
|
|
7460
|
+
sourcePath,
|
|
7461
|
+
sourceType,
|
|
7462
|
+
tier,
|
|
7463
|
+
supersedesId,
|
|
7464
|
+
draft,
|
|
7465
|
+
memoryType,
|
|
7466
|
+
trajectory,
|
|
7467
|
+
contentHash
|
|
7468
|
+
];
|
|
7469
|
+
return {
|
|
7470
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
7471
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
7472
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
7473
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
7474
|
+
};
|
|
7475
|
+
};
|
|
7476
|
+
const globalClient = getClient();
|
|
7477
|
+
const globalStmts = batch.map(buildStmt);
|
|
7478
|
+
await globalClient.batch(globalStmts, "write");
|
|
7479
|
+
_pendingRecords.splice(0, batch.length);
|
|
7480
|
+
try {
|
|
7481
|
+
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
7482
|
+
if (isShardingEnabled2()) {
|
|
7483
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
7484
|
+
for (const row of batch) {
|
|
7485
|
+
const proj = row.project_name || "unknown";
|
|
7486
|
+
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
7487
|
+
byProject.get(proj).push(row);
|
|
7488
|
+
}
|
|
7489
|
+
for (const [project, rows] of byProject) {
|
|
7490
|
+
try {
|
|
7491
|
+
const shardClient = await getReadyShardClient2(project);
|
|
7492
|
+
const shardStmts = rows.map(buildStmt);
|
|
7493
|
+
await shardClient.batch(shardStmts, "write");
|
|
7494
|
+
} catch (err) {
|
|
7495
|
+
process.stderr.write(
|
|
7496
|
+
`[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
|
|
7497
|
+
`
|
|
7498
|
+
);
|
|
7499
|
+
}
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
} catch {
|
|
7503
|
+
}
|
|
7504
|
+
return batch.length;
|
|
7505
|
+
} finally {
|
|
7506
|
+
_flushing = false;
|
|
7507
|
+
}
|
|
7508
|
+
}
|
|
7509
|
+
function buildWikiScopeFilter(options, columnPrefix) {
|
|
7510
|
+
const args = [];
|
|
7511
|
+
let clause = "";
|
|
7512
|
+
if (options?.workspaceId !== void 0) {
|
|
7513
|
+
clause += ` AND ${columnPrefix}workspace_id = ?`;
|
|
7514
|
+
args.push(options.workspaceId);
|
|
7515
|
+
}
|
|
7516
|
+
if (options?.userId === void 0) {
|
|
7517
|
+
clause += ` AND ${columnPrefix}user_id IS NULL`;
|
|
7518
|
+
} else if (options.userId === null) {
|
|
7519
|
+
clause += ` AND ${columnPrefix}user_id IS NULL`;
|
|
7520
|
+
} else {
|
|
7521
|
+
clause += ` AND (${columnPrefix}user_id = ? OR ${columnPrefix}user_id IS NULL)`;
|
|
7522
|
+
args.push(options.userId);
|
|
7523
|
+
}
|
|
7524
|
+
return { clause, args };
|
|
7525
|
+
}
|
|
7526
|
+
function buildRawVisibilityFilter(options, columnPrefix) {
|
|
7527
|
+
if (options?.includeRaw === false) {
|
|
7528
|
+
return {
|
|
7529
|
+
clause: ` AND COALESCE(${columnPrefix}memory_type, 'raw') != 'raw'`,
|
|
7530
|
+
args: []
|
|
7531
|
+
};
|
|
7532
|
+
}
|
|
7533
|
+
return { clause: "", args: [] };
|
|
7534
|
+
}
|
|
7535
|
+
async function searchMemories(queryVector, agentId, options) {
|
|
7536
|
+
let client;
|
|
7537
|
+
try {
|
|
7538
|
+
const { isShardingEnabled: isShardingEnabled2, shardExists: shardExists2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
7539
|
+
if (isShardingEnabled2() && options?.projectName && shardExists2(options.projectName)) {
|
|
7540
|
+
client = await getReadyShardClient2(options.projectName);
|
|
7541
|
+
} else {
|
|
7542
|
+
client = getClient();
|
|
7543
|
+
}
|
|
7544
|
+
} catch {
|
|
7545
|
+
client = getClient();
|
|
7546
|
+
}
|
|
7547
|
+
const limit = options?.limit ?? 10;
|
|
7548
|
+
const statusFilter = options?.includeArchived ? "" : `
|
|
7549
|
+
AND COALESCE(status, 'active') = 'active'`;
|
|
7550
|
+
const draftFilter = options?.includeDrafts ? "" : `
|
|
7551
|
+
AND (draft = 0 OR draft IS NULL)`;
|
|
7552
|
+
let sql = `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
7553
|
+
tool_name, project_name,
|
|
7554
|
+
has_error, raw_text, vector, importance, status,
|
|
7555
|
+
confidence, last_accessed,
|
|
7556
|
+
workspace_id, document_id, user_id,
|
|
7557
|
+
char_offset, page_number,
|
|
7558
|
+
source_path, source_type
|
|
7559
|
+
FROM memories
|
|
7560
|
+
WHERE agent_id = ?
|
|
7561
|
+
AND vector IS NOT NULL${statusFilter}${draftFilter}
|
|
7562
|
+
AND COALESCE(confidence, 0.7) >= 0.3`;
|
|
7563
|
+
const args = [agentId];
|
|
7564
|
+
const scope = buildWikiScopeFilter(options, "");
|
|
7565
|
+
sql += scope.clause;
|
|
7566
|
+
args.push(...scope.args);
|
|
7567
|
+
const rawVisibility = buildRawVisibilityFilter(options, "");
|
|
7568
|
+
sql += rawVisibility.clause;
|
|
7569
|
+
args.push(...rawVisibility.args);
|
|
7570
|
+
if (options?.projectName) {
|
|
7571
|
+
sql += ` AND project_name = ?`;
|
|
7572
|
+
args.push(options.projectName);
|
|
7573
|
+
}
|
|
7574
|
+
if (options?.toolName) {
|
|
7575
|
+
sql += ` AND tool_name = ?`;
|
|
7576
|
+
args.push(options.toolName);
|
|
7577
|
+
}
|
|
7578
|
+
if (options?.hasError !== void 0) {
|
|
7579
|
+
sql += ` AND has_error = ?`;
|
|
7580
|
+
args.push(options.hasError ? 1 : 0);
|
|
7581
|
+
}
|
|
7582
|
+
if (options?.since) {
|
|
7583
|
+
sql += ` AND timestamp >= ?`;
|
|
7584
|
+
args.push(options.since);
|
|
7585
|
+
}
|
|
7586
|
+
if (options?.memoryType) {
|
|
7587
|
+
sql += ` AND memory_type = ?`;
|
|
7588
|
+
args.push(options.memoryType);
|
|
7589
|
+
}
|
|
7590
|
+
sql += ` ORDER BY vector_distance_cos(vector, vector32(?))`;
|
|
7591
|
+
args.push(vectorToBlob(queryVector));
|
|
7592
|
+
sql += ` LIMIT ?`;
|
|
7593
|
+
args.push(limit);
|
|
7594
|
+
const result2 = await client.execute({ sql, args });
|
|
7595
|
+
return result2.rows.map((row) => ({
|
|
7596
|
+
id: row.id,
|
|
7597
|
+
agent_id: row.agent_id,
|
|
7598
|
+
agent_role: row.agent_role,
|
|
7599
|
+
session_id: row.session_id,
|
|
7600
|
+
timestamp: row.timestamp,
|
|
7601
|
+
tool_name: row.tool_name,
|
|
7602
|
+
project_name: row.project_name,
|
|
7603
|
+
has_error: row.has_error === 1,
|
|
7604
|
+
raw_text: row.raw_text,
|
|
7605
|
+
vector: row.vector == null ? [] : Array.isArray(row.vector) ? row.vector : Array.from(row.vector),
|
|
7606
|
+
importance: row.importance ?? 5,
|
|
7607
|
+
status: row.status ?? "active",
|
|
7608
|
+
confidence: row.confidence ?? 0.7,
|
|
7609
|
+
last_accessed: row.last_accessed ?? row.timestamp,
|
|
7610
|
+
workspace_id: row.workspace_id ?? null,
|
|
7611
|
+
document_id: row.document_id ?? null,
|
|
7612
|
+
user_id: row.user_id ?? null,
|
|
7613
|
+
char_offset: row.char_offset ?? null,
|
|
7614
|
+
page_number: row.page_number ?? null,
|
|
7615
|
+
source_path: row.source_path ?? null,
|
|
7616
|
+
source_type: row.source_type ?? null
|
|
7617
|
+
}));
|
|
7618
|
+
}
|
|
7619
|
+
async function attachDocumentMetadata(records) {
|
|
7620
|
+
const docIds = [
|
|
7621
|
+
...new Set(
|
|
7622
|
+
records.map((r) => r.document_id).filter((id) => typeof id === "string" && id.length > 0)
|
|
7623
|
+
)
|
|
7624
|
+
];
|
|
7625
|
+
if (docIds.length === 0) return records;
|
|
7626
|
+
try {
|
|
7627
|
+
const client = getClient();
|
|
7628
|
+
const placeholders = docIds.map(() => "?").join(",");
|
|
7629
|
+
const result2 = await client.execute({
|
|
7630
|
+
sql: `SELECT id, filename, mime, source_type, uploaded_at
|
|
7631
|
+
FROM documents
|
|
7632
|
+
WHERE id IN (${placeholders})`,
|
|
7633
|
+
args: docIds
|
|
7634
|
+
});
|
|
7635
|
+
const byId = /* @__PURE__ */ new Map();
|
|
7636
|
+
for (const row of result2.rows) {
|
|
7637
|
+
const id = row.id;
|
|
7638
|
+
byId.set(id, {
|
|
7639
|
+
document_id: id,
|
|
7640
|
+
filename: row.filename,
|
|
7641
|
+
mime: row.mime ?? null,
|
|
7642
|
+
source_type: row.source_type ?? null,
|
|
7643
|
+
uploaded_at: row.uploaded_at
|
|
7644
|
+
});
|
|
7645
|
+
}
|
|
7646
|
+
for (const record of records) {
|
|
7647
|
+
if (!record.document_id) continue;
|
|
7648
|
+
record.document_metadata = byId.get(record.document_id) ?? null;
|
|
7649
|
+
}
|
|
7650
|
+
} catch {
|
|
7651
|
+
}
|
|
7652
|
+
return records;
|
|
7653
|
+
}
|
|
7654
|
+
async function flushTier3(agentId, options) {
|
|
7655
|
+
const client = getClient();
|
|
7656
|
+
const maxAge = options?.maxAgeHours ?? 72;
|
|
7657
|
+
const cutoff = new Date(Date.now() - maxAge * 36e5).toISOString();
|
|
7658
|
+
if (options?.dryRun) {
|
|
7659
|
+
const result3 = await client.execute({
|
|
7660
|
+
sql: `SELECT COUNT(*) as cnt FROM memories
|
|
7661
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
7662
|
+
args: [agentId, cutoff]
|
|
7663
|
+
});
|
|
7664
|
+
return { archived: Number(result3.rows[0]?.cnt ?? 0) };
|
|
7665
|
+
}
|
|
7666
|
+
const result2 = await client.execute({
|
|
7667
|
+
sql: `UPDATE memories SET status = 'archived'
|
|
7668
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
7669
|
+
args: [agentId, cutoff]
|
|
7670
|
+
});
|
|
7671
|
+
return { archived: result2.rowsAffected };
|
|
7672
|
+
}
|
|
7673
|
+
async function disposeStore() {
|
|
7674
|
+
if (_flushTimer !== null) {
|
|
7675
|
+
clearInterval(_flushTimer);
|
|
7676
|
+
_flushTimer = null;
|
|
7677
|
+
}
|
|
7678
|
+
if (_pendingRecords.length > 0) {
|
|
7679
|
+
await flushBatch();
|
|
7680
|
+
}
|
|
7681
|
+
await disposeTurso();
|
|
7682
|
+
_pendingRecords = [];
|
|
7683
|
+
_nextVersion = 1;
|
|
7684
|
+
}
|
|
7685
|
+
function vectorToBlob(vector) {
|
|
7686
|
+
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
7687
|
+
return JSON.stringify(Array.from(f32));
|
|
7688
|
+
}
|
|
7689
|
+
async function updateMemoryStatus(id, status) {
|
|
7690
|
+
const client = getClient();
|
|
7691
|
+
await client.execute({
|
|
7692
|
+
sql: `UPDATE memories SET status = ? WHERE id = ?`,
|
|
7693
|
+
args: [status, id]
|
|
7694
|
+
});
|
|
7695
|
+
}
|
|
7696
|
+
function reserveVersions(count) {
|
|
7697
|
+
const reserved = [];
|
|
7698
|
+
for (let i = 0; i < count; i++) {
|
|
7699
|
+
reserved.push(_nextVersion++);
|
|
7700
|
+
}
|
|
7701
|
+
return reserved;
|
|
7702
|
+
}
|
|
7703
|
+
async function getMemoryCardinality(agentId) {
|
|
7704
|
+
try {
|
|
7705
|
+
const client = getClient();
|
|
7706
|
+
const result2 = await client.execute({
|
|
7707
|
+
sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND COALESCE(status, 'active') = 'active'`,
|
|
7708
|
+
args: [agentId]
|
|
7709
|
+
});
|
|
7710
|
+
return Number(result2.rows[0]?.cnt) || 0;
|
|
7711
|
+
} catch {
|
|
7712
|
+
return 0;
|
|
7713
|
+
}
|
|
7714
|
+
}
|
|
7715
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
7716
|
+
var init_store = __esm({
|
|
7717
|
+
"src/lib/store.ts"() {
|
|
7718
|
+
"use strict";
|
|
7719
|
+
init_memory();
|
|
7720
|
+
init_database();
|
|
7721
|
+
init_keychain();
|
|
7722
|
+
init_config();
|
|
7723
|
+
init_state_bus();
|
|
7724
|
+
INIT_MAX_RETRIES = 3;
|
|
7725
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
7726
|
+
_pendingRecords = [];
|
|
7727
|
+
_batchSize = 20;
|
|
7728
|
+
_flushIntervalMs = 1e4;
|
|
7729
|
+
_flushTimer = null;
|
|
7730
|
+
_flushing = false;
|
|
7731
|
+
_nextVersion = 1;
|
|
7732
|
+
}
|
|
7733
|
+
});
|
|
7734
|
+
|
|
7735
|
+
// src/bin/exe-dispatch.ts
|
|
7736
|
+
init_tmux_routing();
|
|
7737
|
+
init_tasks_crud();
|
|
7738
|
+
|
|
7739
|
+
// src/bin/fast-db-init.ts
|
|
7740
|
+
async function fastDbInit() {
|
|
7741
|
+
const { isInitialized: isInitialized2, getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
7742
|
+
if (isInitialized2()) {
|
|
7743
|
+
return getClient2();
|
|
7744
|
+
}
|
|
7745
|
+
try {
|
|
7746
|
+
const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
|
|
7747
|
+
const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
|
|
7748
|
+
await connectEmbedDaemon2();
|
|
7749
|
+
if (isClientConnected2()) {
|
|
7750
|
+
const daemonClient = {
|
|
7751
|
+
async execute(stmt) {
|
|
7752
|
+
const sql = typeof stmt === "string" ? stmt : stmt.sql;
|
|
7753
|
+
const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
|
|
7754
|
+
const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
|
|
7755
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
7756
|
+
if (resp.db) return deserializeResultSet2(resp.db);
|
|
7757
|
+
throw new Error("Unexpected daemon response");
|
|
7758
|
+
},
|
|
7759
|
+
async batch(stmts, mode) {
|
|
7760
|
+
const statements = stmts.map((s) => {
|
|
7761
|
+
const sql = typeof s === "string" ? s : s.sql;
|
|
7762
|
+
const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
|
|
7763
|
+
return { sql, args };
|
|
7764
|
+
});
|
|
7765
|
+
const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
|
|
7766
|
+
if (resp.error) throw new Error(String(resp.error));
|
|
7767
|
+
const batchResults = resp["db-batch"];
|
|
7768
|
+
if (batchResults) return batchResults.map(deserializeResultSet2);
|
|
7769
|
+
throw new Error("Unexpected daemon batch response");
|
|
7770
|
+
},
|
|
7771
|
+
async transaction(_mode) {
|
|
7772
|
+
throw new Error("Transactions not supported via daemon socket");
|
|
7773
|
+
},
|
|
7774
|
+
async executeMultiple(_sql) {
|
|
7775
|
+
throw new Error("executeMultiple not supported via daemon socket");
|
|
7776
|
+
},
|
|
7777
|
+
async migrate(_stmts) {
|
|
7778
|
+
throw new Error("migrate not supported via daemon socket");
|
|
7779
|
+
},
|
|
7780
|
+
sync() {
|
|
7781
|
+
return Promise.resolve(void 0);
|
|
7782
|
+
},
|
|
7783
|
+
close() {
|
|
7784
|
+
},
|
|
7785
|
+
get closed() {
|
|
7786
|
+
return false;
|
|
7787
|
+
},
|
|
7788
|
+
get protocol() {
|
|
7789
|
+
return "file";
|
|
7790
|
+
}
|
|
7791
|
+
};
|
|
7792
|
+
return daemonClient;
|
|
7793
|
+
}
|
|
7794
|
+
} catch {
|
|
7795
|
+
}
|
|
7796
|
+
const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
7797
|
+
await initStore2({ lightweight: true });
|
|
7798
|
+
return getClient2();
|
|
7799
|
+
}
|
|
6204
7800
|
|
|
6205
7801
|
// src/bin/exe-dispatch.ts
|
|
6206
7802
|
init_employees();
|
|
@@ -6220,7 +7816,7 @@ if (!exeSession) {
|
|
|
6220
7816
|
process.exit(1);
|
|
6221
7817
|
}
|
|
6222
7818
|
try {
|
|
6223
|
-
await
|
|
7819
|
+
await fastDbInit();
|
|
6224
7820
|
await createTaskCore({
|
|
6225
7821
|
title: `Dispatch: ${employeeName} (CLI)`,
|
|
6226
7822
|
assignedTo: employeeName,
|