@askexenow/exe-os 0.8.83 → 0.8.86
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 +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +154 -21
- package/dist/bin/cli.js +14678 -12676
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +100 -91
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1420 -485
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +572 -271
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +102 -3
- package/dist/bin/exe-gateway.js +796 -292
- package/dist/bin/exe-healthcheck.js +134 -1
- package/dist/bin/exe-heartbeat.js +172 -36
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +927 -82
- package/dist/bin/exe-new-employee.js +60 -8
- package/dist/bin/exe-pending-messages.js +151 -19
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +155 -22
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +995 -228
- package/dist/bin/exe-session-cleanup.js +4930 -1664
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +154 -21
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +1180 -363
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +60 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +1185 -367
- package/dist/bin/setup.js +914 -270
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +792 -285
- package/dist/hooks/bug-report-worker.js +445 -135
- package/dist/hooks/commit-complete.js +1178 -361
- package/dist/hooks/error-recall.js +994 -228
- package/dist/hooks/ingest-worker.js +1799 -1234
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +757 -109
- package/dist/hooks/pre-compact.js +1061 -244
- package/dist/hooks/pre-tool-use.js +787 -130
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +1121 -299
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +4063 -397
- package/dist/hooks/session-start.js +1071 -254
- package/dist/hooks/stop.js +768 -120
- package/dist/hooks/subagent-stop.js +757 -109
- package/dist/hooks/summary-worker.js +1706 -1011
- package/dist/index.js +1821 -1098
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +932 -88
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +2733 -1575
- package/dist/lib/hybrid-search.js +995 -228
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +103 -40
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +348 -134
- package/dist/lib/tmux-routing.js +422 -208
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5742 -696
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +375 -152
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +99 -31
- package/dist/mcp/tools/send-message.js +108 -45
- package/dist/mcp/tools/update-task.js +162 -77
- package/dist/runtime/index.js +1075 -258
- package/dist/tui/App.js +1333 -506
- package/package.json +6 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -311,6 +311,12 @@ function getClient() {
|
|
|
311
311
|
if (!_resilientClient) {
|
|
312
312
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
313
313
|
}
|
|
314
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
315
|
+
return _resilientClient;
|
|
316
|
+
}
|
|
317
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
318
|
+
return _daemonClient;
|
|
319
|
+
}
|
|
314
320
|
return _resilientClient;
|
|
315
321
|
}
|
|
316
322
|
function getRawClient() {
|
|
@@ -799,6 +805,12 @@ async function ensureSchema() {
|
|
|
799
805
|
} catch {
|
|
800
806
|
}
|
|
801
807
|
}
|
|
808
|
+
try {
|
|
809
|
+
await client.execute(
|
|
810
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
811
|
+
);
|
|
812
|
+
} catch {
|
|
813
|
+
}
|
|
802
814
|
await client.executeMultiple(`
|
|
803
815
|
CREATE TABLE IF NOT EXISTS entities (
|
|
804
816
|
id TEXT PRIMARY KEY,
|
|
@@ -851,7 +863,30 @@ async function ensureSchema() {
|
|
|
851
863
|
entity_id TEXT NOT NULL,
|
|
852
864
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
853
865
|
);
|
|
866
|
+
|
|
867
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
868
|
+
name,
|
|
869
|
+
content=entities,
|
|
870
|
+
content_rowid=rowid
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
874
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
875
|
+
END;
|
|
876
|
+
|
|
877
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
878
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
879
|
+
END;
|
|
880
|
+
|
|
881
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
882
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
883
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
884
|
+
END;
|
|
854
885
|
`);
|
|
886
|
+
try {
|
|
887
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
888
|
+
} catch {
|
|
889
|
+
}
|
|
855
890
|
await client.executeMultiple(`
|
|
856
891
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
857
892
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1032,6 +1067,33 @@ async function ensureSchema() {
|
|
|
1032
1067
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1033
1068
|
ON conversations(channel_id);
|
|
1034
1069
|
`);
|
|
1070
|
+
await client.executeMultiple(`
|
|
1071
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1072
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1073
|
+
agent_id TEXT NOT NULL,
|
|
1074
|
+
session_name TEXT,
|
|
1075
|
+
task_id TEXT,
|
|
1076
|
+
project_name TEXT,
|
|
1077
|
+
started_at TEXT NOT NULL
|
|
1078
|
+
);
|
|
1079
|
+
|
|
1080
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1081
|
+
ON session_agent_map(agent_id);
|
|
1082
|
+
`);
|
|
1083
|
+
try {
|
|
1084
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1085
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1086
|
+
await client.execute({
|
|
1087
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1088
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1089
|
+
FROM memories
|
|
1090
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1091
|
+
GROUP BY session_id, agent_id`,
|
|
1092
|
+
args: []
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
1035
1097
|
try {
|
|
1036
1098
|
await client.execute({
|
|
1037
1099
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1165,8 +1227,30 @@ async function ensureSchema() {
|
|
|
1165
1227
|
});
|
|
1166
1228
|
} catch {
|
|
1167
1229
|
}
|
|
1230
|
+
for (const col of [
|
|
1231
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1232
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1233
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1234
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1235
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1236
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1237
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1238
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1239
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1240
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1241
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1242
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1243
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1244
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1245
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1246
|
+
]) {
|
|
1247
|
+
try {
|
|
1248
|
+
await client.execute(col);
|
|
1249
|
+
} catch {
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1168
1252
|
}
|
|
1169
|
-
var _client, _resilientClient, initTurso;
|
|
1253
|
+
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1170
1254
|
var init_database = __esm({
|
|
1171
1255
|
"src/lib/database.ts"() {
|
|
1172
1256
|
"use strict";
|
|
@@ -1174,6 +1258,7 @@ var init_database = __esm({
|
|
|
1174
1258
|
init_employees();
|
|
1175
1259
|
_client = null;
|
|
1176
1260
|
_resilientClient = null;
|
|
1261
|
+
_daemonClient = null;
|
|
1177
1262
|
initTurso = initDatabase;
|
|
1178
1263
|
}
|
|
1179
1264
|
});
|
|
@@ -1604,210 +1689,13 @@ ${p.content}`).join("\n\n");
|
|
|
1604
1689
|
}
|
|
1605
1690
|
});
|
|
1606
1691
|
|
|
1607
|
-
// src/lib/store.ts
|
|
1608
|
-
init_database();
|
|
1609
|
-
|
|
1610
|
-
// src/lib/keychain.ts
|
|
1611
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1612
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1613
|
-
import path3 from "path";
|
|
1614
|
-
import os3 from "os";
|
|
1615
|
-
var SERVICE = "exe-mem";
|
|
1616
|
-
var ACCOUNT = "master-key";
|
|
1617
|
-
function getKeyDir() {
|
|
1618
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os3.homedir(), ".exe-os");
|
|
1619
|
-
}
|
|
1620
|
-
function getKeyPath() {
|
|
1621
|
-
return path3.join(getKeyDir(), "master.key");
|
|
1622
|
-
}
|
|
1623
|
-
async function tryKeytar() {
|
|
1624
|
-
try {
|
|
1625
|
-
return await import("keytar");
|
|
1626
|
-
} catch {
|
|
1627
|
-
return null;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
async function getMasterKey() {
|
|
1631
|
-
const keytar = await tryKeytar();
|
|
1632
|
-
if (keytar) {
|
|
1633
|
-
try {
|
|
1634
|
-
const stored = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
1635
|
-
if (stored) {
|
|
1636
|
-
return Buffer.from(stored, "base64");
|
|
1637
|
-
}
|
|
1638
|
-
} catch {
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
const keyPath = getKeyPath();
|
|
1642
|
-
if (!existsSync3(keyPath)) {
|
|
1643
|
-
return null;
|
|
1644
|
-
}
|
|
1645
|
-
try {
|
|
1646
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
1647
|
-
return Buffer.from(content.trim(), "base64");
|
|
1648
|
-
} catch {
|
|
1649
|
-
return null;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
// src/lib/store.ts
|
|
1654
|
-
init_config();
|
|
1655
|
-
|
|
1656
|
-
// src/lib/state-bus.ts
|
|
1657
|
-
var StateBus = class {
|
|
1658
|
-
handlers = /* @__PURE__ */ new Map();
|
|
1659
|
-
globalHandlers = /* @__PURE__ */ new Set();
|
|
1660
|
-
/** Emit an event to all subscribers */
|
|
1661
|
-
emit(event) {
|
|
1662
|
-
const typeHandlers = this.handlers.get(event.type);
|
|
1663
|
-
if (typeHandlers) {
|
|
1664
|
-
for (const handler of typeHandlers) {
|
|
1665
|
-
try {
|
|
1666
|
-
handler(event);
|
|
1667
|
-
} catch {
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
for (const handler of this.globalHandlers) {
|
|
1672
|
-
try {
|
|
1673
|
-
handler(event);
|
|
1674
|
-
} catch {
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
/** Subscribe to a specific event type */
|
|
1679
|
-
on(type, handler) {
|
|
1680
|
-
if (!this.handlers.has(type)) {
|
|
1681
|
-
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
1682
|
-
}
|
|
1683
|
-
this.handlers.get(type).add(handler);
|
|
1684
|
-
}
|
|
1685
|
-
/** Subscribe to ALL events */
|
|
1686
|
-
onAny(handler) {
|
|
1687
|
-
this.globalHandlers.add(handler);
|
|
1688
|
-
}
|
|
1689
|
-
/** Unsubscribe from a specific event type */
|
|
1690
|
-
off(type, handler) {
|
|
1691
|
-
this.handlers.get(type)?.delete(handler);
|
|
1692
|
-
}
|
|
1693
|
-
/** Unsubscribe from ALL events */
|
|
1694
|
-
offAny(handler) {
|
|
1695
|
-
this.globalHandlers.delete(handler);
|
|
1696
|
-
}
|
|
1697
|
-
/** Remove all listeners */
|
|
1698
|
-
clear() {
|
|
1699
|
-
this.handlers.clear();
|
|
1700
|
-
this.globalHandlers.clear();
|
|
1701
|
-
}
|
|
1702
|
-
};
|
|
1703
|
-
var orgBus = new StateBus();
|
|
1704
|
-
|
|
1705
|
-
// src/lib/store.ts
|
|
1706
|
-
var INIT_MAX_RETRIES = 3;
|
|
1707
|
-
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1708
|
-
function isBusyError2(err) {
|
|
1709
|
-
if (err instanceof Error) {
|
|
1710
|
-
const msg = err.message.toLowerCase();
|
|
1711
|
-
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1712
|
-
}
|
|
1713
|
-
return false;
|
|
1714
|
-
}
|
|
1715
|
-
async function retryOnBusy2(fn, label) {
|
|
1716
|
-
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1717
|
-
try {
|
|
1718
|
-
return await fn();
|
|
1719
|
-
} catch (err) {
|
|
1720
|
-
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1721
|
-
process.stderr.write(
|
|
1722
|
-
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1723
|
-
`
|
|
1724
|
-
);
|
|
1725
|
-
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
throw new Error("unreachable");
|
|
1729
|
-
}
|
|
1730
|
-
var _pendingRecords = [];
|
|
1731
|
-
var _batchSize = 20;
|
|
1732
|
-
var _flushIntervalMs = 1e4;
|
|
1733
|
-
var _flushTimer = null;
|
|
1734
|
-
var _flushing = false;
|
|
1735
|
-
var _nextVersion = 1;
|
|
1736
|
-
async function initStore(options) {
|
|
1737
|
-
if (_flushTimer !== null) {
|
|
1738
|
-
clearInterval(_flushTimer);
|
|
1739
|
-
_flushTimer = null;
|
|
1740
|
-
}
|
|
1741
|
-
_pendingRecords = [];
|
|
1742
|
-
_flushing = false;
|
|
1743
|
-
_batchSize = options?.batchSize ?? 20;
|
|
1744
|
-
_flushIntervalMs = options?.flushIntervalMs ?? 1e4;
|
|
1745
|
-
let dbPath = options?.dbPath;
|
|
1746
|
-
if (!dbPath) {
|
|
1747
|
-
const config = await loadConfig();
|
|
1748
|
-
dbPath = config.dbPath;
|
|
1749
|
-
}
|
|
1750
|
-
let masterKey = options?.masterKey ?? null;
|
|
1751
|
-
if (!masterKey) {
|
|
1752
|
-
masterKey = await getMasterKey();
|
|
1753
|
-
if (!masterKey) {
|
|
1754
|
-
throw new Error(
|
|
1755
|
-
"No encryption key found. Run /exe-setup to generate one."
|
|
1756
|
-
);
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
const hexKey = masterKey.toString("hex");
|
|
1760
|
-
await initTurso({
|
|
1761
|
-
dbPath,
|
|
1762
|
-
encryptionKey: hexKey
|
|
1763
|
-
});
|
|
1764
|
-
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1765
|
-
try {
|
|
1766
|
-
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1767
|
-
initShardManager2(hexKey);
|
|
1768
|
-
} catch {
|
|
1769
|
-
}
|
|
1770
|
-
const client = getClient();
|
|
1771
|
-
const vResult = await retryOnBusy2(
|
|
1772
|
-
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1773
|
-
"version-query"
|
|
1774
|
-
);
|
|
1775
|
-
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1776
|
-
try {
|
|
1777
|
-
const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
|
|
1778
|
-
await loadGlobalProcedures2();
|
|
1779
|
-
} catch {
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
function vectorToBlob(vector) {
|
|
1783
|
-
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
1784
|
-
return JSON.stringify(Array.from(f32));
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
// src/bin/backfill-vectors.ts
|
|
1788
|
-
init_database();
|
|
1789
|
-
|
|
1790
1692
|
// src/lib/exe-daemon-client.ts
|
|
1791
|
-
init_config();
|
|
1792
1693
|
import net from "net";
|
|
1793
1694
|
import { spawn } from "child_process";
|
|
1794
1695
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1795
1696
|
import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
1796
1697
|
import path5 from "path";
|
|
1797
1698
|
import { fileURLToPath } from "url";
|
|
1798
|
-
var SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
|
|
1799
|
-
var PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
|
|
1800
|
-
var SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1801
|
-
var SPAWN_LOCK_STALE_MS = 3e4;
|
|
1802
|
-
var CONNECT_TIMEOUT_MS = 15e3;
|
|
1803
|
-
var REQUEST_TIMEOUT_MS = 3e4;
|
|
1804
|
-
var _socket = null;
|
|
1805
|
-
var _connected = false;
|
|
1806
|
-
var _buffer = "";
|
|
1807
|
-
var _requestCount = 0;
|
|
1808
|
-
var HEALTH_CHECK_INTERVAL = 100;
|
|
1809
|
-
var _pending = /* @__PURE__ */ new Map();
|
|
1810
|
-
var MAX_BUFFER = 1e7;
|
|
1811
1699
|
function handleData(chunk) {
|
|
1812
1700
|
_buffer += chunk.toString();
|
|
1813
1701
|
if (_buffer.length > MAX_BUFFER) {
|
|
@@ -1821,10 +1709,12 @@ function handleData(chunk) {
|
|
|
1821
1709
|
if (!line) continue;
|
|
1822
1710
|
try {
|
|
1823
1711
|
const response = JSON.parse(line);
|
|
1824
|
-
const
|
|
1712
|
+
const id = response.id;
|
|
1713
|
+
if (!id) continue;
|
|
1714
|
+
const entry = _pending.get(id);
|
|
1825
1715
|
if (entry) {
|
|
1826
1716
|
clearTimeout(entry.timer);
|
|
1827
|
-
_pending.delete(
|
|
1717
|
+
_pending.delete(id);
|
|
1828
1718
|
entry.resolve(response);
|
|
1829
1719
|
}
|
|
1830
1720
|
} catch {
|
|
@@ -1995,6 +1885,9 @@ async function connectEmbedDaemon() {
|
|
|
1995
1885
|
return false;
|
|
1996
1886
|
}
|
|
1997
1887
|
function sendRequest(texts, priority) {
|
|
1888
|
+
return sendDaemonRequest({ texts, priority });
|
|
1889
|
+
}
|
|
1890
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
1998
1891
|
return new Promise((resolve) => {
|
|
1999
1892
|
if (!_socket || !_connected) {
|
|
2000
1893
|
resolve({ error: "Not connected" });
|
|
@@ -2004,10 +1897,10 @@ function sendRequest(texts, priority) {
|
|
|
2004
1897
|
const timer = setTimeout(() => {
|
|
2005
1898
|
_pending.delete(id);
|
|
2006
1899
|
resolve({ error: "Request timeout" });
|
|
2007
|
-
},
|
|
1900
|
+
}, timeoutMs);
|
|
2008
1901
|
_pending.set(id, { resolve, timer });
|
|
2009
1902
|
try {
|
|
2010
|
-
_socket.write(JSON.stringify({ id,
|
|
1903
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
2011
1904
|
} catch {
|
|
2012
1905
|
clearTimeout(timer);
|
|
2013
1906
|
_pending.delete(id);
|
|
@@ -2017,30 +1910,11 @@ function sendRequest(texts, priority) {
|
|
|
2017
1910
|
}
|
|
2018
1911
|
async function pingDaemon() {
|
|
2019
1912
|
if (!_socket || !_connected) return null;
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
}, 5e3);
|
|
2026
|
-
_pending.set(id, {
|
|
2027
|
-
resolve: (data) => {
|
|
2028
|
-
if (data.health) {
|
|
2029
|
-
resolve(data.health);
|
|
2030
|
-
} else {
|
|
2031
|
-
resolve(null);
|
|
2032
|
-
}
|
|
2033
|
-
},
|
|
2034
|
-
timer
|
|
2035
|
-
});
|
|
2036
|
-
try {
|
|
2037
|
-
_socket.write(JSON.stringify({ id, type: "health" }) + "\n");
|
|
2038
|
-
} catch {
|
|
2039
|
-
clearTimeout(timer);
|
|
2040
|
-
_pending.delete(id);
|
|
2041
|
-
resolve(null);
|
|
2042
|
-
}
|
|
2043
|
-
});
|
|
1913
|
+
const response = await sendDaemonRequest({ type: "health" }, 5e3);
|
|
1914
|
+
if (response.health) {
|
|
1915
|
+
return response.health;
|
|
1916
|
+
}
|
|
1917
|
+
return null;
|
|
2044
1918
|
}
|
|
2045
1919
|
function killAndRespawnDaemon() {
|
|
2046
1920
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
@@ -2112,8 +1986,219 @@ async function embedViaClient(text, priority = "high") {
|
|
|
2112
1986
|
}
|
|
2113
1987
|
return null;
|
|
2114
1988
|
}
|
|
1989
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
|
|
1990
|
+
var init_exe_daemon_client = __esm({
|
|
1991
|
+
"src/lib/exe-daemon-client.ts"() {
|
|
1992
|
+
"use strict";
|
|
1993
|
+
init_config();
|
|
1994
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
|
|
1995
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
|
|
1996
|
+
SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1997
|
+
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1998
|
+
CONNECT_TIMEOUT_MS = 15e3;
|
|
1999
|
+
REQUEST_TIMEOUT_MS = 3e4;
|
|
2000
|
+
_socket = null;
|
|
2001
|
+
_connected = false;
|
|
2002
|
+
_buffer = "";
|
|
2003
|
+
_requestCount = 0;
|
|
2004
|
+
HEALTH_CHECK_INTERVAL = 100;
|
|
2005
|
+
_pending = /* @__PURE__ */ new Map();
|
|
2006
|
+
MAX_BUFFER = 1e7;
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
// src/lib/store.ts
|
|
2011
|
+
import { createHash } from "crypto";
|
|
2012
|
+
init_database();
|
|
2013
|
+
|
|
2014
|
+
// src/lib/keychain.ts
|
|
2015
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2016
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2017
|
+
import path3 from "path";
|
|
2018
|
+
import os3 from "os";
|
|
2019
|
+
var SERVICE = "exe-mem";
|
|
2020
|
+
var ACCOUNT = "master-key";
|
|
2021
|
+
function getKeyDir() {
|
|
2022
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os3.homedir(), ".exe-os");
|
|
2023
|
+
}
|
|
2024
|
+
function getKeyPath() {
|
|
2025
|
+
return path3.join(getKeyDir(), "master.key");
|
|
2026
|
+
}
|
|
2027
|
+
async function tryKeytar() {
|
|
2028
|
+
try {
|
|
2029
|
+
return await import("keytar");
|
|
2030
|
+
} catch {
|
|
2031
|
+
return null;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
async function getMasterKey() {
|
|
2035
|
+
const keytar = await tryKeytar();
|
|
2036
|
+
if (keytar) {
|
|
2037
|
+
try {
|
|
2038
|
+
const stored = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
2039
|
+
if (stored) {
|
|
2040
|
+
return Buffer.from(stored, "base64");
|
|
2041
|
+
}
|
|
2042
|
+
} catch {
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
const keyPath = getKeyPath();
|
|
2046
|
+
if (!existsSync3(keyPath)) {
|
|
2047
|
+
process.stderr.write(
|
|
2048
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2049
|
+
`
|
|
2050
|
+
);
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2053
|
+
try {
|
|
2054
|
+
const content = await readFile3(keyPath, "utf-8");
|
|
2055
|
+
return Buffer.from(content.trim(), "base64");
|
|
2056
|
+
} catch (err) {
|
|
2057
|
+
process.stderr.write(
|
|
2058
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
2059
|
+
`
|
|
2060
|
+
);
|
|
2061
|
+
return null;
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/lib/store.ts
|
|
2066
|
+
init_config();
|
|
2067
|
+
|
|
2068
|
+
// src/lib/state-bus.ts
|
|
2069
|
+
var StateBus = class {
|
|
2070
|
+
handlers = /* @__PURE__ */ new Map();
|
|
2071
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
2072
|
+
/** Emit an event to all subscribers */
|
|
2073
|
+
emit(event) {
|
|
2074
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
2075
|
+
if (typeHandlers) {
|
|
2076
|
+
for (const handler of typeHandlers) {
|
|
2077
|
+
try {
|
|
2078
|
+
handler(event);
|
|
2079
|
+
} catch {
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
for (const handler of this.globalHandlers) {
|
|
2084
|
+
try {
|
|
2085
|
+
handler(event);
|
|
2086
|
+
} catch {
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
/** Subscribe to a specific event type */
|
|
2091
|
+
on(type, handler) {
|
|
2092
|
+
if (!this.handlers.has(type)) {
|
|
2093
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
2094
|
+
}
|
|
2095
|
+
this.handlers.get(type).add(handler);
|
|
2096
|
+
}
|
|
2097
|
+
/** Subscribe to ALL events */
|
|
2098
|
+
onAny(handler) {
|
|
2099
|
+
this.globalHandlers.add(handler);
|
|
2100
|
+
}
|
|
2101
|
+
/** Unsubscribe from a specific event type */
|
|
2102
|
+
off(type, handler) {
|
|
2103
|
+
this.handlers.get(type)?.delete(handler);
|
|
2104
|
+
}
|
|
2105
|
+
/** Unsubscribe from ALL events */
|
|
2106
|
+
offAny(handler) {
|
|
2107
|
+
this.globalHandlers.delete(handler);
|
|
2108
|
+
}
|
|
2109
|
+
/** Remove all listeners */
|
|
2110
|
+
clear() {
|
|
2111
|
+
this.handlers.clear();
|
|
2112
|
+
this.globalHandlers.clear();
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
var orgBus = new StateBus();
|
|
2116
|
+
|
|
2117
|
+
// src/lib/store.ts
|
|
2118
|
+
var INIT_MAX_RETRIES = 3;
|
|
2119
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
2120
|
+
function isBusyError2(err) {
|
|
2121
|
+
if (err instanceof Error) {
|
|
2122
|
+
const msg = err.message.toLowerCase();
|
|
2123
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2124
|
+
}
|
|
2125
|
+
return false;
|
|
2126
|
+
}
|
|
2127
|
+
async function retryOnBusy2(fn, label) {
|
|
2128
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2129
|
+
try {
|
|
2130
|
+
return await fn();
|
|
2131
|
+
} catch (err) {
|
|
2132
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2133
|
+
process.stderr.write(
|
|
2134
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2135
|
+
`
|
|
2136
|
+
);
|
|
2137
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
throw new Error("unreachable");
|
|
2141
|
+
}
|
|
2142
|
+
var _pendingRecords = [];
|
|
2143
|
+
var _batchSize = 20;
|
|
2144
|
+
var _flushIntervalMs = 1e4;
|
|
2145
|
+
var _flushTimer = null;
|
|
2146
|
+
var _flushing = false;
|
|
2147
|
+
var _nextVersion = 1;
|
|
2148
|
+
async function initStore(options) {
|
|
2149
|
+
if (_flushTimer !== null) {
|
|
2150
|
+
clearInterval(_flushTimer);
|
|
2151
|
+
_flushTimer = null;
|
|
2152
|
+
}
|
|
2153
|
+
_pendingRecords = [];
|
|
2154
|
+
_flushing = false;
|
|
2155
|
+
_batchSize = options?.batchSize ?? 20;
|
|
2156
|
+
_flushIntervalMs = options?.flushIntervalMs ?? 1e4;
|
|
2157
|
+
let dbPath = options?.dbPath;
|
|
2158
|
+
if (!dbPath) {
|
|
2159
|
+
const config = await loadConfig();
|
|
2160
|
+
dbPath = config.dbPath;
|
|
2161
|
+
}
|
|
2162
|
+
let masterKey = options?.masterKey ?? null;
|
|
2163
|
+
if (!masterKey) {
|
|
2164
|
+
masterKey = await getMasterKey();
|
|
2165
|
+
if (!masterKey) {
|
|
2166
|
+
throw new Error(
|
|
2167
|
+
"No encryption key found. Run /exe-setup to generate one."
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
const hexKey = masterKey.toString("hex");
|
|
2172
|
+
await initTurso({
|
|
2173
|
+
dbPath,
|
|
2174
|
+
encryptionKey: hexKey
|
|
2175
|
+
});
|
|
2176
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2177
|
+
try {
|
|
2178
|
+
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2179
|
+
initShardManager2(hexKey);
|
|
2180
|
+
} catch {
|
|
2181
|
+
}
|
|
2182
|
+
const client = getClient();
|
|
2183
|
+
const vResult = await retryOnBusy2(
|
|
2184
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2185
|
+
"version-query"
|
|
2186
|
+
);
|
|
2187
|
+
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2188
|
+
try {
|
|
2189
|
+
const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
|
|
2190
|
+
await loadGlobalProcedures2();
|
|
2191
|
+
} catch {
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
function vectorToBlob(vector) {
|
|
2195
|
+
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
2196
|
+
return JSON.stringify(Array.from(f32));
|
|
2197
|
+
}
|
|
2115
2198
|
|
|
2116
2199
|
// src/bin/backfill-vectors.ts
|
|
2200
|
+
init_database();
|
|
2201
|
+
init_exe_daemon_client();
|
|
2117
2202
|
init_config();
|
|
2118
2203
|
|
|
2119
2204
|
// src/lib/is-main.ts
|
|
@@ -2121,6 +2206,7 @@ import { realpathSync } from "fs";
|
|
|
2121
2206
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2122
2207
|
function isMainModule(importMetaUrl) {
|
|
2123
2208
|
if (process.argv[1] == null) return false;
|
|
2209
|
+
if (process.argv[1].includes("mcp/server")) return false;
|
|
2124
2210
|
try {
|
|
2125
2211
|
const scriptPath = realpathSync(process.argv[1]);
|
|
2126
2212
|
const modulePath = realpathSync(fileURLToPath2(importMetaUrl));
|