@askexenow/exe-os 0.9.7 → 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 +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
package/dist/bin/update.js
CHANGED
|
@@ -15,9 +15,18 @@ var __export = (target, all) => {
|
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// src/lib/secure-files.ts
|
|
19
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
20
|
+
import { chmod, mkdir } from "fs/promises";
|
|
21
|
+
var init_secure_files = __esm({
|
|
22
|
+
"src/lib/secure-files.ts"() {
|
|
23
|
+
"use strict";
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
18
27
|
// src/lib/config.ts
|
|
19
|
-
import { readFile, writeFile
|
|
20
|
-
import { readFileSync as readFileSync2, existsSync, renameSync } from "fs";
|
|
28
|
+
import { readFile, writeFile } from "fs/promises";
|
|
29
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2, renameSync } from "fs";
|
|
21
30
|
import path2 from "path";
|
|
22
31
|
import os from "os";
|
|
23
32
|
function resolveDataDir() {
|
|
@@ -25,7 +34,7 @@ function resolveDataDir() {
|
|
|
25
34
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
26
35
|
const newDir = path2.join(os.homedir(), ".exe-os");
|
|
27
36
|
const legacyDir = path2.join(os.homedir(), ".exe-mem");
|
|
28
|
-
if (!
|
|
37
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
29
38
|
try {
|
|
30
39
|
renameSync(legacyDir, newDir);
|
|
31
40
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -40,6 +49,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
40
49
|
var init_config = __esm({
|
|
41
50
|
"src/lib/config.ts"() {
|
|
42
51
|
"use strict";
|
|
52
|
+
init_secure_files();
|
|
43
53
|
EXE_AI_DIR = resolveDataDir();
|
|
44
54
|
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
45
55
|
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
@@ -123,8 +133,11 @@ __export(license_exports, {
|
|
|
123
133
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
124
134
|
validateLicense: () => validateLicense
|
|
125
135
|
});
|
|
126
|
-
import { readFileSync as readFileSync3, writeFileSync, existsSync as
|
|
136
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
127
137
|
import { randomUUID } from "crypto";
|
|
138
|
+
import { createRequire } from "module";
|
|
139
|
+
import { pathToFileURL } from "url";
|
|
140
|
+
import os2 from "os";
|
|
128
141
|
import path3 from "path";
|
|
129
142
|
import { jwtVerify, importSPKI } from "jose";
|
|
130
143
|
async function fetchRetry(url, init) {
|
|
@@ -138,34 +151,34 @@ async function fetchRetry(url, init) {
|
|
|
138
151
|
function loadDeviceId() {
|
|
139
152
|
const deviceJsonPath = path3.join(EXE_AI_DIR, "device.json");
|
|
140
153
|
try {
|
|
141
|
-
if (
|
|
154
|
+
if (existsSync3(deviceJsonPath)) {
|
|
142
155
|
const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
|
|
143
156
|
if (data.deviceId) return data.deviceId;
|
|
144
157
|
}
|
|
145
158
|
} catch {
|
|
146
159
|
}
|
|
147
160
|
try {
|
|
148
|
-
if (
|
|
161
|
+
if (existsSync3(DEVICE_ID_PATH)) {
|
|
149
162
|
const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
|
|
150
163
|
if (id2) return id2;
|
|
151
164
|
}
|
|
152
165
|
} catch {
|
|
153
166
|
}
|
|
154
167
|
const id = randomUUID();
|
|
155
|
-
|
|
168
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
156
169
|
writeFileSync(DEVICE_ID_PATH, id, "utf8");
|
|
157
170
|
return id;
|
|
158
171
|
}
|
|
159
172
|
function loadLicense() {
|
|
160
173
|
try {
|
|
161
|
-
if (!
|
|
174
|
+
if (!existsSync3(LICENSE_PATH)) return null;
|
|
162
175
|
return readFileSync3(LICENSE_PATH, "utf8").trim();
|
|
163
176
|
} catch {
|
|
164
177
|
return null;
|
|
165
178
|
}
|
|
166
179
|
}
|
|
167
180
|
function saveLicense(apiKey) {
|
|
168
|
-
|
|
181
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
169
182
|
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
170
183
|
}
|
|
171
184
|
async function verifyLicenseJwt(token) {
|
|
@@ -192,7 +205,7 @@ async function verifyLicenseJwt(token) {
|
|
|
192
205
|
}
|
|
193
206
|
async function getCachedLicense() {
|
|
194
207
|
try {
|
|
195
|
-
if (!
|
|
208
|
+
if (!existsSync3(CACHE_PATH)) return null;
|
|
196
209
|
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
197
210
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
198
211
|
return await verifyLicenseJwt(raw.token);
|
|
@@ -202,7 +215,7 @@ async function getCachedLicense() {
|
|
|
202
215
|
}
|
|
203
216
|
function readCachedToken() {
|
|
204
217
|
try {
|
|
205
|
-
if (!
|
|
218
|
+
if (!existsSync3(CACHE_PATH)) return null;
|
|
206
219
|
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
207
220
|
return typeof raw.token === "string" ? raw.token : null;
|
|
208
221
|
} catch {
|
|
@@ -241,52 +254,126 @@ function cacheResponse(token) {
|
|
|
241
254
|
} catch {
|
|
242
255
|
}
|
|
243
256
|
}
|
|
244
|
-
|
|
245
|
-
|
|
257
|
+
function loadPrismaForLicense() {
|
|
258
|
+
if (_prismaFailed) return null;
|
|
259
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
260
|
+
if (!dbUrl) {
|
|
261
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os2.homedir(), "exe-db");
|
|
262
|
+
if (!existsSync3(path3.join(exeDbRoot, "package.json"))) {
|
|
263
|
+
_prismaFailed = true;
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!_prismaPromise) {
|
|
268
|
+
_prismaPromise = (async () => {
|
|
269
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
270
|
+
if (explicitPath) {
|
|
271
|
+
const mod2 = await import(pathToFileURL(explicitPath).href);
|
|
272
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
273
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
274
|
+
return new Ctor2();
|
|
275
|
+
}
|
|
276
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os2.homedir(), "exe-db");
|
|
277
|
+
const req = createRequire(path3.join(exeDbRoot, "package.json"));
|
|
278
|
+
const entry = req.resolve("@prisma/client");
|
|
279
|
+
const mod = await import(pathToFileURL(entry).href);
|
|
280
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
281
|
+
if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
|
|
282
|
+
return new Ctor();
|
|
283
|
+
})().catch((err) => {
|
|
284
|
+
_prismaFailed = true;
|
|
285
|
+
_prismaPromise = null;
|
|
286
|
+
throw err;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return _prismaPromise;
|
|
290
|
+
}
|
|
291
|
+
async function validateViaPostgres(apiKey) {
|
|
292
|
+
const loader = loadPrismaForLicense();
|
|
293
|
+
if (!loader) return null;
|
|
294
|
+
try {
|
|
295
|
+
const prisma = await loader;
|
|
296
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
297
|
+
`SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
|
|
298
|
+
FROM billing.licenses WHERE key = $1 LIMIT 1`,
|
|
299
|
+
apiKey
|
|
300
|
+
);
|
|
301
|
+
if (!rows || rows.length === 0) return null;
|
|
302
|
+
const row = rows[0];
|
|
303
|
+
if (row.status !== "active") return null;
|
|
304
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
|
|
305
|
+
const plan = row.plan;
|
|
306
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
307
|
+
return {
|
|
308
|
+
valid: true,
|
|
309
|
+
plan,
|
|
310
|
+
email: row.email,
|
|
311
|
+
expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
|
|
312
|
+
deviceLimit: row.device_limit ?? limits.devices,
|
|
313
|
+
employeeLimit: row.employee_limit ?? limits.employees,
|
|
314
|
+
memoryLimit: row.memory_limit ?? limits.memories
|
|
315
|
+
};
|
|
316
|
+
} catch {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function validateViaCFWorker(apiKey, deviceId) {
|
|
246
321
|
try {
|
|
247
322
|
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
248
323
|
method: "POST",
|
|
249
324
|
headers: { "Content-Type": "application/json" },
|
|
250
|
-
body: JSON.stringify({ apiKey, deviceId
|
|
325
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
251
326
|
signal: AbortSignal.timeout(1e4)
|
|
252
327
|
});
|
|
253
|
-
if (res.ok)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
328
|
+
if (!res.ok) return null;
|
|
329
|
+
const data = await res.json();
|
|
330
|
+
if (data.error === "device_limit_exceeded") return null;
|
|
331
|
+
if (!data.valid) return null;
|
|
332
|
+
if (data.token) {
|
|
333
|
+
cacheResponse(data.token);
|
|
334
|
+
const verified = await verifyLicenseJwt(data.token);
|
|
335
|
+
if (verified) return verified;
|
|
336
|
+
}
|
|
337
|
+
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
338
|
+
return {
|
|
339
|
+
valid: data.valid,
|
|
340
|
+
plan: data.plan,
|
|
341
|
+
email: data.email,
|
|
342
|
+
expiresAt: data.expiresAt,
|
|
343
|
+
deviceLimit: limits.devices,
|
|
344
|
+
employeeLimit: limits.employees,
|
|
345
|
+
memoryLimit: limits.memories
|
|
346
|
+
};
|
|
347
|
+
} catch {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async function validateLicense(apiKey, deviceId) {
|
|
352
|
+
const did = deviceId ?? loadDeviceId();
|
|
353
|
+
const pgResult = await validateViaPostgres(apiKey);
|
|
354
|
+
if (pgResult) {
|
|
355
|
+
try {
|
|
356
|
+
writeFileSync(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
return pgResult;
|
|
360
|
+
}
|
|
361
|
+
const cfResult = await validateViaCFWorker(apiKey, did);
|
|
362
|
+
if (cfResult) return cfResult;
|
|
363
|
+
const cached = await getCachedLicense();
|
|
364
|
+
if (cached) return cached;
|
|
365
|
+
try {
|
|
366
|
+
if (existsSync3(CACHE_PATH)) {
|
|
367
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
368
|
+
if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
|
|
369
|
+
return raw.pgLicense;
|
|
266
370
|
}
|
|
267
|
-
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
268
|
-
return {
|
|
269
|
-
valid: data.valid,
|
|
270
|
-
plan: data.plan,
|
|
271
|
-
email: data.email,
|
|
272
|
-
expiresAt: data.expiresAt,
|
|
273
|
-
deviceLimit: limits.devices,
|
|
274
|
-
employeeLimit: limits.employees,
|
|
275
|
-
memoryLimit: limits.memories
|
|
276
|
-
};
|
|
277
371
|
}
|
|
278
|
-
const cached = await getCachedLicense();
|
|
279
|
-
if (cached) return cached;
|
|
280
|
-
const raw = getRawCachedPlan();
|
|
281
|
-
if (raw) return raw;
|
|
282
|
-
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
283
372
|
} catch {
|
|
284
|
-
const cached = await getCachedLicense();
|
|
285
|
-
if (cached) return cached;
|
|
286
|
-
const rawFallback = getRawCachedPlan();
|
|
287
|
-
if (rawFallback) return rawFallback;
|
|
288
|
-
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
289
373
|
}
|
|
374
|
+
const rawFallback = getRawCachedPlan();
|
|
375
|
+
if (rawFallback) return rawFallback;
|
|
376
|
+
return { ...FREE_LICENSE, valid: false };
|
|
290
377
|
}
|
|
291
378
|
function getCacheAgeMs() {
|
|
292
379
|
try {
|
|
@@ -302,7 +389,7 @@ async function checkLicense() {
|
|
|
302
389
|
if (!key) {
|
|
303
390
|
try {
|
|
304
391
|
const configPath = path3.join(EXE_AI_DIR, "config.json");
|
|
305
|
-
if (
|
|
392
|
+
if (existsSync3(configPath)) {
|
|
306
393
|
const raw = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
307
394
|
const cloud = raw.cloud;
|
|
308
395
|
if (cloud?.apiKey) {
|
|
@@ -457,7 +544,7 @@ function stopLicenseRevalidation() {
|
|
|
457
544
|
_revalTimer = null;
|
|
458
545
|
}
|
|
459
546
|
}
|
|
460
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
|
|
547
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, _prismaPromise, _prismaFailed, CACHE_MAX_AGE_MS, _revalTimer;
|
|
461
548
|
var init_license = __esm({
|
|
462
549
|
"src/lib/license.ts"() {
|
|
463
550
|
"use strict";
|
|
@@ -488,6 +575,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
488
575
|
employeeLimit: 1,
|
|
489
576
|
memoryLimit: 5e3
|
|
490
577
|
};
|
|
578
|
+
_prismaPromise = null;
|
|
579
|
+
_prismaFailed = false;
|
|
491
580
|
CACHE_MAX_AGE_MS = 36e5;
|
|
492
581
|
_revalTimer = null;
|
|
493
582
|
}
|