@askexenow/exe-os 0.9.8 → 0.9.9
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 +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
|
@@ -75,9 +75,34 @@ var init_db_retry = __esm({
|
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
// src/lib/secure-files.ts
|
|
79
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
80
|
+
import { chmod, mkdir } from "fs/promises";
|
|
81
|
+
async function ensurePrivateDir(dirPath) {
|
|
82
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
83
|
+
try {
|
|
84
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function enforcePrivateFile(filePath) {
|
|
89
|
+
try {
|
|
90
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
95
|
+
var init_secure_files = __esm({
|
|
96
|
+
"src/lib/secure-files.ts"() {
|
|
97
|
+
"use strict";
|
|
98
|
+
PRIVATE_DIR_MODE = 448;
|
|
99
|
+
PRIVATE_FILE_MODE = 384;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
78
103
|
// src/lib/config.ts
|
|
79
|
-
import { readFile, writeFile
|
|
80
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
104
|
+
import { readFile, writeFile } from "fs/promises";
|
|
105
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
81
106
|
import path from "path";
|
|
82
107
|
import os from "os";
|
|
83
108
|
function resolveDataDir() {
|
|
@@ -85,7 +110,7 @@ function resolveDataDir() {
|
|
|
85
110
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
86
111
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
87
112
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
88
|
-
if (!
|
|
113
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
89
114
|
try {
|
|
90
115
|
renameSync(legacyDir, newDir);
|
|
91
116
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -148,9 +173,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
148
173
|
}
|
|
149
174
|
async function loadConfig() {
|
|
150
175
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
151
|
-
await
|
|
176
|
+
await ensurePrivateDir(dir);
|
|
152
177
|
const configPath = path.join(dir, "config.json");
|
|
153
|
-
if (!
|
|
178
|
+
if (!existsSync2(configPath)) {
|
|
154
179
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
155
180
|
}
|
|
156
181
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -163,6 +188,7 @@ async function loadConfig() {
|
|
|
163
188
|
`);
|
|
164
189
|
try {
|
|
165
190
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
191
|
+
await enforcePrivateFile(configPath);
|
|
166
192
|
} catch {
|
|
167
193
|
}
|
|
168
194
|
}
|
|
@@ -181,7 +207,7 @@ async function loadConfig() {
|
|
|
181
207
|
function loadConfigSync() {
|
|
182
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
183
209
|
const configPath = path.join(dir, "config.json");
|
|
184
|
-
if (!
|
|
210
|
+
if (!existsSync2(configPath)) {
|
|
185
211
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
186
212
|
}
|
|
187
213
|
try {
|
|
@@ -201,6 +227,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
201
227
|
var init_config = __esm({
|
|
202
228
|
"src/lib/config.ts"() {
|
|
203
229
|
"use strict";
|
|
230
|
+
init_secure_files();
|
|
204
231
|
EXE_AI_DIR = resolveDataDir();
|
|
205
232
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
206
233
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -279,7 +306,7 @@ var init_config = __esm({
|
|
|
279
306
|
|
|
280
307
|
// src/lib/employees.ts
|
|
281
308
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
282
|
-
import { existsSync as
|
|
309
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
283
310
|
import { execSync } from "child_process";
|
|
284
311
|
import path2 from "path";
|
|
285
312
|
import os2 from "os";
|
|
@@ -296,7 +323,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
|
296
323
|
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
297
324
|
}
|
|
298
325
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
299
|
-
if (!
|
|
326
|
+
if (!existsSync3(employeesPath)) return [];
|
|
300
327
|
try {
|
|
301
328
|
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
302
329
|
} catch {
|
|
@@ -1241,6 +1268,7 @@ async function ensureSchema() {
|
|
|
1241
1268
|
project TEXT NOT NULL,
|
|
1242
1269
|
summary TEXT NOT NULL,
|
|
1243
1270
|
task_file TEXT,
|
|
1271
|
+
session_scope TEXT,
|
|
1244
1272
|
read INTEGER NOT NULL DEFAULT 0,
|
|
1245
1273
|
created_at TEXT NOT NULL
|
|
1246
1274
|
);
|
|
@@ -1249,7 +1277,7 @@ async function ensureSchema() {
|
|
|
1249
1277
|
ON notifications(read);
|
|
1250
1278
|
|
|
1251
1279
|
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
1252
|
-
ON notifications(agent_id);
|
|
1280
|
+
ON notifications(agent_id, session_scope);
|
|
1253
1281
|
|
|
1254
1282
|
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
1255
1283
|
ON notifications(task_file);
|
|
@@ -1287,6 +1315,7 @@ async function ensureSchema() {
|
|
|
1287
1315
|
target_agent TEXT NOT NULL,
|
|
1288
1316
|
target_project TEXT,
|
|
1289
1317
|
target_device TEXT NOT NULL DEFAULT 'local',
|
|
1318
|
+
session_scope TEXT,
|
|
1290
1319
|
content TEXT NOT NULL,
|
|
1291
1320
|
priority TEXT DEFAULT 'normal',
|
|
1292
1321
|
status TEXT DEFAULT 'pending',
|
|
@@ -1300,10 +1329,31 @@ async function ensureSchema() {
|
|
|
1300
1329
|
);
|
|
1301
1330
|
|
|
1302
1331
|
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
1303
|
-
ON messages(target_agent, status);
|
|
1332
|
+
ON messages(target_agent, session_scope, status);
|
|
1304
1333
|
|
|
1305
1334
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
1306
|
-
ON messages(target_agent, from_agent, server_seq);
|
|
1335
|
+
ON messages(target_agent, session_scope, from_agent, server_seq);
|
|
1336
|
+
`);
|
|
1337
|
+
try {
|
|
1338
|
+
await client.execute({
|
|
1339
|
+
sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
|
|
1340
|
+
args: []
|
|
1341
|
+
});
|
|
1342
|
+
} catch {
|
|
1343
|
+
}
|
|
1344
|
+
try {
|
|
1345
|
+
await client.execute({
|
|
1346
|
+
sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
|
|
1347
|
+
args: []
|
|
1348
|
+
});
|
|
1349
|
+
} catch {
|
|
1350
|
+
}
|
|
1351
|
+
await client.executeMultiple(`
|
|
1352
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
|
|
1353
|
+
ON notifications(agent_id, session_scope, read, created_at);
|
|
1354
|
+
|
|
1355
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
|
|
1356
|
+
ON messages(target_agent, session_scope, status, created_at);
|
|
1307
1357
|
`);
|
|
1308
1358
|
try {
|
|
1309
1359
|
await client.execute({
|
|
@@ -1887,6 +1937,13 @@ async function ensureSchema() {
|
|
|
1887
1937
|
} catch {
|
|
1888
1938
|
}
|
|
1889
1939
|
}
|
|
1940
|
+
try {
|
|
1941
|
+
await client.execute({
|
|
1942
|
+
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
1943
|
+
args: []
|
|
1944
|
+
});
|
|
1945
|
+
} catch {
|
|
1946
|
+
}
|
|
1890
1947
|
}
|
|
1891
1948
|
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso;
|
|
1892
1949
|
var init_database = __esm({
|
|
@@ -1964,6 +2021,7 @@ var shard_manager_exports = {};
|
|
|
1964
2021
|
__export(shard_manager_exports, {
|
|
1965
2022
|
disposeShards: () => disposeShards,
|
|
1966
2023
|
ensureShardSchema: () => ensureShardSchema,
|
|
2024
|
+
getOpenShardCount: () => getOpenShardCount,
|
|
1967
2025
|
getReadyShardClient: () => getReadyShardClient,
|
|
1968
2026
|
getShardClient: () => getShardClient,
|
|
1969
2027
|
getShardsDir: () => getShardsDir,
|
|
@@ -1973,14 +2031,17 @@ __export(shard_manager_exports, {
|
|
|
1973
2031
|
shardExists: () => shardExists
|
|
1974
2032
|
});
|
|
1975
2033
|
import path5 from "path";
|
|
1976
|
-
import { existsSync as
|
|
2034
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
1977
2035
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1978
2036
|
function initShardManager(encryptionKey) {
|
|
1979
2037
|
_encryptionKey = encryptionKey;
|
|
1980
|
-
if (!
|
|
1981
|
-
|
|
2038
|
+
if (!existsSync5(SHARDS_DIR)) {
|
|
2039
|
+
mkdirSync2(SHARDS_DIR, { recursive: true });
|
|
1982
2040
|
}
|
|
1983
2041
|
_shardingEnabled = true;
|
|
2042
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
2043
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
2044
|
+
_evictionTimer.unref();
|
|
1984
2045
|
}
|
|
1985
2046
|
function isShardingEnabled() {
|
|
1986
2047
|
return _shardingEnabled;
|
|
@@ -1997,21 +2058,28 @@ function getShardClient(projectName) {
|
|
|
1997
2058
|
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
1998
2059
|
}
|
|
1999
2060
|
const cached = _shards.get(safeName);
|
|
2000
|
-
if (cached)
|
|
2061
|
+
if (cached) {
|
|
2062
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
2063
|
+
return cached;
|
|
2064
|
+
}
|
|
2065
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
2066
|
+
evictLRU();
|
|
2067
|
+
}
|
|
2001
2068
|
const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
|
|
2002
2069
|
const client = createClient2({
|
|
2003
2070
|
url: `file:${dbPath}`,
|
|
2004
2071
|
encryptionKey: _encryptionKey
|
|
2005
2072
|
});
|
|
2006
2073
|
_shards.set(safeName, client);
|
|
2074
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
2007
2075
|
return client;
|
|
2008
2076
|
}
|
|
2009
2077
|
function shardExists(projectName) {
|
|
2010
2078
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2011
|
-
return
|
|
2079
|
+
return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
|
|
2012
2080
|
}
|
|
2013
2081
|
function listShards() {
|
|
2014
|
-
if (!
|
|
2082
|
+
if (!existsSync5(SHARDS_DIR)) return [];
|
|
2015
2083
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
2016
2084
|
}
|
|
2017
2085
|
async function ensureShardSchema(client) {
|
|
@@ -2063,6 +2131,8 @@ async function ensureShardSchema(client) {
|
|
|
2063
2131
|
for (const col of [
|
|
2064
2132
|
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
2065
2133
|
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
2134
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
2135
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
2066
2136
|
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
2067
2137
|
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
2068
2138
|
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
@@ -2200,21 +2270,69 @@ async function getReadyShardClient(projectName) {
|
|
|
2200
2270
|
await ensureShardSchema(client);
|
|
2201
2271
|
return client;
|
|
2202
2272
|
}
|
|
2273
|
+
function evictLRU() {
|
|
2274
|
+
let oldest = null;
|
|
2275
|
+
let oldestTime = Infinity;
|
|
2276
|
+
for (const [name, time] of _shardLastAccess) {
|
|
2277
|
+
if (time < oldestTime) {
|
|
2278
|
+
oldestTime = time;
|
|
2279
|
+
oldest = name;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
if (oldest) {
|
|
2283
|
+
const client = _shards.get(oldest);
|
|
2284
|
+
if (client) {
|
|
2285
|
+
client.close();
|
|
2286
|
+
}
|
|
2287
|
+
_shards.delete(oldest);
|
|
2288
|
+
_shardLastAccess.delete(oldest);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
function evictIdleShards() {
|
|
2292
|
+
const now = Date.now();
|
|
2293
|
+
const toEvict = [];
|
|
2294
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
2295
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
2296
|
+
toEvict.push(name);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
for (const name of toEvict) {
|
|
2300
|
+
const client = _shards.get(name);
|
|
2301
|
+
if (client) {
|
|
2302
|
+
client.close();
|
|
2303
|
+
}
|
|
2304
|
+
_shards.delete(name);
|
|
2305
|
+
_shardLastAccess.delete(name);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
function getOpenShardCount() {
|
|
2309
|
+
return _shards.size;
|
|
2310
|
+
}
|
|
2203
2311
|
function disposeShards() {
|
|
2312
|
+
if (_evictionTimer) {
|
|
2313
|
+
clearInterval(_evictionTimer);
|
|
2314
|
+
_evictionTimer = null;
|
|
2315
|
+
}
|
|
2204
2316
|
for (const [, client] of _shards) {
|
|
2205
2317
|
client.close();
|
|
2206
2318
|
}
|
|
2207
2319
|
_shards.clear();
|
|
2320
|
+
_shardLastAccess.clear();
|
|
2208
2321
|
_shardingEnabled = false;
|
|
2209
2322
|
_encryptionKey = null;
|
|
2210
2323
|
}
|
|
2211
|
-
var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
|
|
2324
|
+
var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
|
|
2212
2325
|
var init_shard_manager = __esm({
|
|
2213
2326
|
"src/lib/shard-manager.ts"() {
|
|
2214
2327
|
"use strict";
|
|
2215
2328
|
init_config();
|
|
2216
2329
|
SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
|
|
2330
|
+
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
2331
|
+
MAX_OPEN_SHARDS = 10;
|
|
2332
|
+
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
2217
2333
|
_shards = /* @__PURE__ */ new Map();
|
|
2334
|
+
_shardLastAccess = /* @__PURE__ */ new Map();
|
|
2335
|
+
_evictionTimer = null;
|
|
2218
2336
|
_encryptionKey = null;
|
|
2219
2337
|
_shardingEnabled = false;
|
|
2220
2338
|
}
|
|
@@ -2407,32 +2525,14 @@ ${p.content}`).join("\n\n");
|
|
|
2407
2525
|
}
|
|
2408
2526
|
});
|
|
2409
2527
|
|
|
2410
|
-
// src/lib/
|
|
2411
|
-
import crypto from "crypto";
|
|
2528
|
+
// src/lib/session-registry.ts
|
|
2412
2529
|
import path6 from "path";
|
|
2413
2530
|
import os5 from "os";
|
|
2414
|
-
import {
|
|
2415
|
-
readFileSync as readFileSync3,
|
|
2416
|
-
readdirSync as readdirSync2,
|
|
2417
|
-
unlinkSync as unlinkSync2,
|
|
2418
|
-
existsSync as existsSync5,
|
|
2419
|
-
rmdirSync
|
|
2420
|
-
} from "fs";
|
|
2421
|
-
var init_notifications = __esm({
|
|
2422
|
-
"src/lib/notifications.ts"() {
|
|
2423
|
-
"use strict";
|
|
2424
|
-
init_database();
|
|
2425
|
-
}
|
|
2426
|
-
});
|
|
2427
|
-
|
|
2428
|
-
// src/lib/session-registry.ts
|
|
2429
|
-
import path7 from "path";
|
|
2430
|
-
import os6 from "os";
|
|
2431
2531
|
var REGISTRY_PATH;
|
|
2432
2532
|
var init_session_registry = __esm({
|
|
2433
2533
|
"src/lib/session-registry.ts"() {
|
|
2434
2534
|
"use strict";
|
|
2435
|
-
REGISTRY_PATH =
|
|
2535
|
+
REGISTRY_PATH = path6.join(os5.homedir(), ".exe-os", "session-registry.json");
|
|
2436
2536
|
}
|
|
2437
2537
|
});
|
|
2438
2538
|
|
|
@@ -2667,15 +2767,16 @@ var init_runtime_table = __esm({
|
|
|
2667
2767
|
});
|
|
2668
2768
|
|
|
2669
2769
|
// src/lib/agent-config.ts
|
|
2670
|
-
import { readFileSync as
|
|
2671
|
-
import
|
|
2770
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync6 } from "fs";
|
|
2771
|
+
import path7 from "path";
|
|
2672
2772
|
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
2673
2773
|
var init_agent_config = __esm({
|
|
2674
2774
|
"src/lib/agent-config.ts"() {
|
|
2675
2775
|
"use strict";
|
|
2676
2776
|
init_config();
|
|
2677
2777
|
init_runtime_table();
|
|
2678
|
-
|
|
2778
|
+
init_secure_files();
|
|
2779
|
+
AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
|
|
2679
2780
|
DEFAULT_MODELS = {
|
|
2680
2781
|
claude: "claude-opus-4",
|
|
2681
2782
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -2685,38 +2786,41 @@ var init_agent_config = __esm({
|
|
|
2685
2786
|
});
|
|
2686
2787
|
|
|
2687
2788
|
// src/lib/intercom-queue.ts
|
|
2688
|
-
import { readFileSync as
|
|
2689
|
-
import
|
|
2690
|
-
import
|
|
2789
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
2790
|
+
import path8 from "path";
|
|
2791
|
+
import os6 from "os";
|
|
2691
2792
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
2692
2793
|
var init_intercom_queue = __esm({
|
|
2693
2794
|
"src/lib/intercom-queue.ts"() {
|
|
2694
2795
|
"use strict";
|
|
2695
|
-
QUEUE_PATH =
|
|
2796
|
+
QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
2696
2797
|
TTL_MS = 60 * 60 * 1e3;
|
|
2697
|
-
INTERCOM_LOG =
|
|
2798
|
+
INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2698
2799
|
}
|
|
2699
2800
|
});
|
|
2700
2801
|
|
|
2701
2802
|
// src/lib/license.ts
|
|
2702
|
-
import { readFileSync as
|
|
2803
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
2703
2804
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2704
|
-
import
|
|
2805
|
+
import { createRequire as createRequire2 } from "module";
|
|
2806
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2807
|
+
import os7 from "os";
|
|
2808
|
+
import path9 from "path";
|
|
2705
2809
|
import { jwtVerify, importSPKI } from "jose";
|
|
2706
2810
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
2707
2811
|
var init_license = __esm({
|
|
2708
2812
|
"src/lib/license.ts"() {
|
|
2709
2813
|
"use strict";
|
|
2710
2814
|
init_config();
|
|
2711
|
-
LICENSE_PATH =
|
|
2712
|
-
CACHE_PATH =
|
|
2713
|
-
DEVICE_ID_PATH =
|
|
2815
|
+
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
2816
|
+
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
2817
|
+
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
2714
2818
|
}
|
|
2715
2819
|
});
|
|
2716
2820
|
|
|
2717
2821
|
// src/lib/plan-limits.ts
|
|
2718
|
-
import { readFileSync as
|
|
2719
|
-
import
|
|
2822
|
+
import { readFileSync as readFileSync6, existsSync as existsSync9 } from "fs";
|
|
2823
|
+
import path10 from "path";
|
|
2720
2824
|
var CACHE_PATH2;
|
|
2721
2825
|
var init_plan_limits = __esm({
|
|
2722
2826
|
"src/lib/plan-limits.ts"() {
|
|
@@ -2725,13 +2829,13 @@ var init_plan_limits = __esm({
|
|
|
2725
2829
|
init_employees();
|
|
2726
2830
|
init_license();
|
|
2727
2831
|
init_config();
|
|
2728
|
-
CACHE_PATH2 =
|
|
2832
|
+
CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2729
2833
|
}
|
|
2730
2834
|
});
|
|
2731
2835
|
|
|
2732
2836
|
// src/lib/tmux-routing.ts
|
|
2733
|
-
import { readFileSync as
|
|
2734
|
-
import
|
|
2837
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
2838
|
+
import path11 from "path";
|
|
2735
2839
|
import os8 from "os";
|
|
2736
2840
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2737
2841
|
function getMySession() {
|
|
@@ -2745,7 +2849,7 @@ function extractRootExe(name) {
|
|
|
2745
2849
|
}
|
|
2746
2850
|
function getParentExe(sessionKey) {
|
|
2747
2851
|
try {
|
|
2748
|
-
const data = JSON.parse(
|
|
2852
|
+
const data = JSON.parse(readFileSync7(path11.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2749
2853
|
return data.parentExe || null;
|
|
2750
2854
|
} catch {
|
|
2751
2855
|
return null;
|
|
@@ -2793,34 +2897,70 @@ var init_tmux_routing = __esm({
|
|
|
2793
2897
|
init_intercom_queue();
|
|
2794
2898
|
init_plan_limits();
|
|
2795
2899
|
init_employees();
|
|
2796
|
-
SPAWN_LOCK_DIR =
|
|
2797
|
-
SESSION_CACHE =
|
|
2798
|
-
INTERCOM_LOG2 =
|
|
2799
|
-
DEBOUNCE_FILE =
|
|
2900
|
+
SPAWN_LOCK_DIR = path11.join(os8.homedir(), ".exe-os", "spawn-locks");
|
|
2901
|
+
SESSION_CACHE = path11.join(os8.homedir(), ".exe-os", "session-cache");
|
|
2902
|
+
INTERCOM_LOG2 = path11.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
2903
|
+
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2800
2904
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2801
2905
|
}
|
|
2802
2906
|
});
|
|
2803
2907
|
|
|
2908
|
+
// src/lib/task-scope.ts
|
|
2909
|
+
function getCurrentSessionScope() {
|
|
2910
|
+
try {
|
|
2911
|
+
return resolveExeSession();
|
|
2912
|
+
} catch {
|
|
2913
|
+
return null;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
2917
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
2918
|
+
if (!scope) return { sql: "", args: [] };
|
|
2919
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
2920
|
+
return {
|
|
2921
|
+
sql: ` AND ${col} = ?`,
|
|
2922
|
+
args: [scope]
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
var init_task_scope = __esm({
|
|
2926
|
+
"src/lib/task-scope.ts"() {
|
|
2927
|
+
"use strict";
|
|
2928
|
+
init_tmux_routing();
|
|
2929
|
+
}
|
|
2930
|
+
});
|
|
2931
|
+
|
|
2932
|
+
// src/lib/notifications.ts
|
|
2933
|
+
import crypto from "crypto";
|
|
2934
|
+
import path12 from "path";
|
|
2935
|
+
import os9 from "os";
|
|
2936
|
+
import {
|
|
2937
|
+
readFileSync as readFileSync8,
|
|
2938
|
+
readdirSync as readdirSync3,
|
|
2939
|
+
unlinkSync as unlinkSync2,
|
|
2940
|
+
existsSync as existsSync11,
|
|
2941
|
+
rmdirSync
|
|
2942
|
+
} from "fs";
|
|
2943
|
+
var init_notifications = __esm({
|
|
2944
|
+
"src/lib/notifications.ts"() {
|
|
2945
|
+
"use strict";
|
|
2946
|
+
init_database();
|
|
2947
|
+
init_task_scope();
|
|
2948
|
+
}
|
|
2949
|
+
});
|
|
2950
|
+
|
|
2804
2951
|
// src/lib/tasks-review.ts
|
|
2805
2952
|
import path13 from "path";
|
|
2806
|
-
import { existsSync as
|
|
2953
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
2807
2954
|
async function listPendingReviews(limit, sessionScope) {
|
|
2808
2955
|
const client = getClient();
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
WHERE status = 'needs_review'
|
|
2813
|
-
AND session_scope = ?
|
|
2814
|
-
ORDER BY updated_at ASC LIMIT ?`,
|
|
2815
|
-
args: [sessionScope, limit]
|
|
2816
|
-
});
|
|
2817
|
-
return result2.rows;
|
|
2818
|
-
}
|
|
2956
|
+
const scope = strictSessionScopeFilter(
|
|
2957
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
2958
|
+
);
|
|
2819
2959
|
const result = await client.execute({
|
|
2820
2960
|
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
2821
|
-
WHERE status = 'needs_review'
|
|
2961
|
+
WHERE status = 'needs_review'${scope.sql}
|
|
2822
2962
|
ORDER BY updated_at ASC LIMIT ?`,
|
|
2823
|
-
args: [limit]
|
|
2963
|
+
args: [...scope.args, limit]
|
|
2824
2964
|
});
|
|
2825
2965
|
return result.rows;
|
|
2826
2966
|
}
|
|
@@ -2834,37 +2974,14 @@ var init_tasks_review = __esm({
|
|
|
2834
2974
|
init_tmux_routing();
|
|
2835
2975
|
init_session_key();
|
|
2836
2976
|
init_state_bus();
|
|
2837
|
-
|
|
2838
|
-
});
|
|
2839
|
-
|
|
2840
|
-
// src/lib/task-scope.ts
|
|
2841
|
-
function getCurrentSessionScope() {
|
|
2842
|
-
try {
|
|
2843
|
-
return resolveExeSession();
|
|
2844
|
-
} catch {
|
|
2845
|
-
return null;
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
2849
|
-
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
2850
|
-
if (!scope) return { sql: "", args: [] };
|
|
2851
|
-
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
2852
|
-
return {
|
|
2853
|
-
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
2854
|
-
args: [scope]
|
|
2855
|
-
};
|
|
2856
|
-
}
|
|
2857
|
-
var init_task_scope = __esm({
|
|
2858
|
-
"src/lib/task-scope.ts"() {
|
|
2859
|
-
"use strict";
|
|
2860
|
-
init_tmux_routing();
|
|
2977
|
+
init_task_scope();
|
|
2861
2978
|
}
|
|
2862
2979
|
});
|
|
2863
2980
|
|
|
2864
2981
|
// src/bin/exe-heartbeat.ts
|
|
2865
2982
|
import { createHash as createHash2 } from "crypto";
|
|
2866
2983
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
2867
|
-
import
|
|
2984
|
+
import os10 from "os";
|
|
2868
2985
|
import path14 from "path";
|
|
2869
2986
|
|
|
2870
2987
|
// src/lib/store.ts
|
|
@@ -2873,7 +2990,7 @@ init_database();
|
|
|
2873
2990
|
|
|
2874
2991
|
// src/lib/keychain.ts
|
|
2875
2992
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2876
|
-
import { existsSync as
|
|
2993
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2877
2994
|
import path4 from "path";
|
|
2878
2995
|
import os4 from "os";
|
|
2879
2996
|
var SERVICE = "exe-mem";
|
|
@@ -2903,7 +3020,7 @@ async function getMasterKey() {
|
|
|
2903
3020
|
}
|
|
2904
3021
|
}
|
|
2905
3022
|
const keyPath = getKeyPath();
|
|
2906
|
-
if (!
|
|
3023
|
+
if (!existsSync4(keyPath)) {
|
|
2907
3024
|
process.stderr.write(
|
|
2908
3025
|
`[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2909
3026
|
`
|
|
@@ -3038,7 +3155,7 @@ var MESSAGE_PREVIEW_CHARS = 80;
|
|
|
3038
3155
|
var MARKER_FILENAME = "exe-heartbeat-marker.json";
|
|
3039
3156
|
var SESSION_CACHE_SUBDIR = "session-cache";
|
|
3040
3157
|
function resolveExeOsDir() {
|
|
3041
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path14.join(
|
|
3158
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path14.join(os10.homedir(), ".exe-os");
|
|
3042
3159
|
}
|
|
3043
3160
|
function getMarkerDir() {
|
|
3044
3161
|
return path14.join(resolveExeOsDir(), SESSION_CACHE_SUBDIR);
|
|
@@ -3087,12 +3204,13 @@ async function queryPendingReviews() {
|
|
|
3087
3204
|
}
|
|
3088
3205
|
async function queryUnreadMessages() {
|
|
3089
3206
|
const client = getClient();
|
|
3207
|
+
const hbScope = strictSessionScopeFilter();
|
|
3090
3208
|
const placeholders = UNREAD_MESSAGE_STATUSES.map(() => "?").join(", ");
|
|
3091
3209
|
const result = await client.execute({
|
|
3092
3210
|
sql: `SELECT from_agent, content FROM messages
|
|
3093
|
-
WHERE target_agent = 'exe' AND status IN (${placeholders})
|
|
3211
|
+
WHERE target_agent = 'exe' AND status IN (${placeholders})${hbScope.sql}
|
|
3094
3212
|
ORDER BY created_at ASC LIMIT ?`,
|
|
3095
|
-
args: [...UNREAD_MESSAGE_STATUSES, UNREAD_MESSAGE_LIMIT]
|
|
3213
|
+
args: [...UNREAD_MESSAGE_STATUSES, ...hbScope.args, UNREAD_MESSAGE_LIMIT]
|
|
3096
3214
|
});
|
|
3097
3215
|
if (result.rows.length === 0) return "";
|
|
3098
3216
|
const lines = [`\u{1F4E8} ${result.rows.length} unread message(s):`];
|
|
@@ -3116,7 +3234,7 @@ function formatRelative(updatedAtIso) {
|
|
|
3116
3234
|
}
|
|
3117
3235
|
async function queryStaleInProgress(thresholdHours) {
|
|
3118
3236
|
const client = getClient();
|
|
3119
|
-
const hbScope =
|
|
3237
|
+
const hbScope = strictSessionScopeFilter();
|
|
3120
3238
|
const result = await client.execute({
|
|
3121
3239
|
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
3122
3240
|
WHERE status = 'in_progress'
|
|
@@ -3133,7 +3251,7 @@ async function queryStaleInProgress(thresholdHours) {
|
|
|
3133
3251
|
}
|
|
3134
3252
|
async function queryNewErrors(sinceIso) {
|
|
3135
3253
|
const client = getClient();
|
|
3136
|
-
const erScope =
|
|
3254
|
+
const erScope = strictSessionScopeFilter();
|
|
3137
3255
|
const result = await client.execute({
|
|
3138
3256
|
sql: erScope.args.length > 0 ? `SELECT COUNT(*) as cnt FROM memories
|
|
3139
3257
|
WHERE has_error = 1 AND timestamp > ?
|
|
@@ -3178,10 +3296,11 @@ async function runHeartbeat() {
|
|
|
3178
3296
|
writeMarker({ lastFiredAt: new Date(now).toISOString(), lastSurfaceHash: hash });
|
|
3179
3297
|
try {
|
|
3180
3298
|
const client = getClient();
|
|
3299
|
+
const ackScope = strictSessionScopeFilter();
|
|
3181
3300
|
await client.execute({
|
|
3182
3301
|
sql: `UPDATE messages SET status = 'acknowledged', processed_at = datetime('now')
|
|
3183
|
-
WHERE target_agent = 'exe' AND status IN ('pending', 'delivered')`,
|
|
3184
|
-
args: []
|
|
3302
|
+
WHERE target_agent = 'exe' AND status IN ('pending', 'delivered')${ackScope.sql}`,
|
|
3303
|
+
args: [...ackScope.args]
|
|
3185
3304
|
});
|
|
3186
3305
|
} catch {
|
|
3187
3306
|
}
|