@askexenow/exe-os 0.8.33 → 0.8.36
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 +332 -348
- package/dist/bin/backfill-responses.js +72 -12
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1491 -1095
- package/dist/bin/exe-assign.js +80 -18
- package/dist/bin/exe-boot.js +407 -88
- package/dist/bin/exe-call.js +61 -2
- package/dist/bin/exe-dispatch.js +18 -10
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +64 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +121 -36
- package/dist/bin/exe-heartbeat.js +77 -13
- package/dist/bin/exe-kill.js +64 -3
- package/dist/bin/exe-launch-agent.js +140 -13
- package/dist/bin/exe-link.js +946 -0
- package/dist/bin/exe-new-employee.js +98 -13
- package/dist/bin/exe-pending-messages.js +72 -7
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +75 -10
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +64 -4
- package/dist/bin/exe-search.js +79 -13
- package/dist/bin/exe-session-cleanup.js +91 -26
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +71 -4
- package/dist/bin/graph-backfill.js +64 -3
- package/dist/bin/graph-export.js +64 -3
- package/dist/bin/install.js +3 -3
- package/dist/bin/scan-tasks.js +71 -4
- package/dist/bin/setup.js +128 -10
- package/dist/bin/shard-migrate.js +64 -3
- package/dist/bin/wiki-sync.js +64 -3
- package/dist/gateway/index.js +122 -37
- package/dist/hooks/bug-report-worker.js +209 -23
- package/dist/hooks/commit-complete.js +71 -4
- package/dist/hooks/error-recall.js +79 -13
- package/dist/hooks/ingest-worker.js +129 -43
- package/dist/hooks/instructions-loaded.js +71 -4
- package/dist/hooks/notification.js +71 -4
- package/dist/hooks/post-compact.js +71 -4
- package/dist/hooks/pre-compact.js +71 -4
- package/dist/hooks/pre-tool-use.js +413 -194
- package/dist/hooks/prompt-ingest-worker.js +82 -22
- package/dist/hooks/prompt-submit.js +103 -37
- package/dist/hooks/response-ingest-worker.js +87 -22
- package/dist/hooks/session-end.js +71 -4
- package/dist/hooks/session-start.js +79 -13
- package/dist/hooks/stop.js +71 -4
- package/dist/hooks/subagent-stop.js +71 -4
- package/dist/hooks/summary-worker.js +303 -50
- package/dist/index.js +134 -46
- package/dist/lib/cloud-sync.js +209 -15
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +64 -2
- package/dist/lib/device-registry.js +70 -3
- package/dist/lib/employee-templates.js +26 -0
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +136 -53
- package/dist/lib/hybrid-search.js +79 -13
- package/dist/lib/identity-templates.js +51 -0
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +22 -14
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +63 -3
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/status-brief.js +63 -5
- package/dist/lib/store.js +64 -3
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +48 -21
- package/dist/lib/tmux-routing.js +47 -20
- package/dist/mcp/server.js +727 -58
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +151 -24
- package/dist/mcp/tools/deactivate-behavior.js +3 -3
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +17 -8
- package/dist/mcp/tools/send-message.js +24 -16
- package/dist/mcp/tools/update-task.js +25 -16
- package/dist/runtime/index.js +112 -24
- package/dist/tui/App.js +139 -36
- package/package.json +6 -2
- package/src/commands/exe/rename.md +12 -0
|
@@ -262,7 +262,7 @@ function listShards() {
|
|
|
262
262
|
}
|
|
263
263
|
async function ensureShardSchema(client) {
|
|
264
264
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
265
|
-
await client.execute("PRAGMA busy_timeout =
|
|
265
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
266
266
|
try {
|
|
267
267
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
268
268
|
} catch {
|
|
@@ -452,13 +452,18 @@ __export(employees_exports, {
|
|
|
452
452
|
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
453
453
|
addEmployee: () => addEmployee,
|
|
454
454
|
getEmployee: () => getEmployee,
|
|
455
|
+
getEmployeeByRole: () => getEmployeeByRole,
|
|
456
|
+
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
457
|
+
hasRole: () => hasRole,
|
|
458
|
+
isMultiInstance: () => isMultiInstance,
|
|
455
459
|
loadEmployees: () => loadEmployees,
|
|
460
|
+
loadEmployeesSync: () => loadEmployeesSync,
|
|
456
461
|
registerBinSymlinks: () => registerBinSymlinks,
|
|
457
462
|
saveEmployees: () => saveEmployees,
|
|
458
463
|
validateEmployeeName: () => validateEmployeeName
|
|
459
464
|
});
|
|
460
465
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
461
|
-
import { existsSync as existsSync5, symlinkSync, readlinkSync } from "fs";
|
|
466
|
+
import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
462
467
|
import { execSync as execSync2 } from "child_process";
|
|
463
468
|
import path5 from "path";
|
|
464
469
|
function validateEmployeeName(name) {
|
|
@@ -491,9 +496,36 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
491
496
|
await mkdir3(path5.dirname(employeesPath), { recursive: true });
|
|
492
497
|
await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
493
498
|
}
|
|
499
|
+
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
500
|
+
if (!existsSync5(employeesPath)) return [];
|
|
501
|
+
try {
|
|
502
|
+
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
503
|
+
} catch {
|
|
504
|
+
return [];
|
|
505
|
+
}
|
|
506
|
+
}
|
|
494
507
|
function getEmployee(employees, name) {
|
|
495
508
|
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
496
509
|
}
|
|
510
|
+
function getEmployeeByRole(employees, role) {
|
|
511
|
+
const lower = role.toLowerCase();
|
|
512
|
+
return employees.find((e) => e.role.toLowerCase() === lower);
|
|
513
|
+
}
|
|
514
|
+
function getEmployeeNamesByRole(employees, role) {
|
|
515
|
+
const lower = role.toLowerCase();
|
|
516
|
+
return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
|
|
517
|
+
}
|
|
518
|
+
function hasRole(agentName, role) {
|
|
519
|
+
const employees = loadEmployeesSync();
|
|
520
|
+
const emp = getEmployee(employees, agentName);
|
|
521
|
+
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
522
|
+
}
|
|
523
|
+
function isMultiInstance(agentName, employees) {
|
|
524
|
+
const roster = employees ?? loadEmployeesSync();
|
|
525
|
+
const emp = getEmployee(roster, agentName);
|
|
526
|
+
if (!emp) return false;
|
|
527
|
+
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
528
|
+
}
|
|
497
529
|
function addEmployee(employees, employee) {
|
|
498
530
|
const normalized = { ...employee, name: employee.name.toLowerCase() };
|
|
499
531
|
if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
|
|
@@ -536,12 +568,13 @@ function registerBinSymlinks(name) {
|
|
|
536
568
|
}
|
|
537
569
|
return { created, skipped, errors };
|
|
538
570
|
}
|
|
539
|
-
var EMPLOYEES_PATH;
|
|
571
|
+
var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
|
|
540
572
|
var init_employees = __esm({
|
|
541
573
|
"src/lib/employees.ts"() {
|
|
542
574
|
"use strict";
|
|
543
575
|
init_config();
|
|
544
576
|
EMPLOYEES_PATH = path5.join(EXE_AI_DIR, "exe-employees.json");
|
|
577
|
+
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
545
578
|
}
|
|
546
579
|
});
|
|
547
580
|
|
|
@@ -1026,6 +1059,32 @@ When you analyze a repo:
|
|
|
1026
1059
|
Every analysis must answer: "Should we build this? If yes, how hard? If no, why not?"
|
|
1027
1060
|
|
|
1028
1061
|
Maintain a clear separation between experimental (for evaluation) and production-ready (for shipping). Never recommend something you haven't read the source code for.`
|
|
1062
|
+
},
|
|
1063
|
+
bob: {
|
|
1064
|
+
name: "bob",
|
|
1065
|
+
role: "Staff Code Reviewer",
|
|
1066
|
+
systemPrompt: `You are bob, the Staff Code Reviewer and System Auditor. You are the last line of defense before code ships to customers. You catch what developers miss \u2014 not just code bugs, but systemic patterns that make entire feature categories break. You report to the COO.
|
|
1067
|
+
|
|
1068
|
+
Your core job: audit code, find bugs, verify fixes, and ensure customer-readiness. Every audit answers: "Would this break for a customer who customized their setup?"
|
|
1069
|
+
|
|
1070
|
+
The 7 Audit Patterns (MANDATORY \u2014 apply to EVERY audit):
|
|
1071
|
+
1. "Works on dev, breaks on user install" \u2014 verify scoped paths, npm resolution, dependencies
|
|
1072
|
+
2. "Two code paths, one untested" \u2014 binary symlink vs /exe-call, CLI vs MCP \u2014 verify BOTH
|
|
1073
|
+
3. "Case sensitivity kills non-technical users" \u2014 normalize all user inputs
|
|
1074
|
+
4. "Hardcoded names leak into user-facing content" \u2014 grep for employee names in runtime logic
|
|
1075
|
+
5. "Installer doesn't self-heal on update" \u2014 npm update must auto-fix stale hooks/paths
|
|
1076
|
+
6. "Data written but invisible to the agent" \u2014 verify query path retrieves stored data
|
|
1077
|
+
7. "Partial fixes that miss inline references" \u2014 before/after grep count is mandatory
|
|
1078
|
+
|
|
1079
|
+
Audit method:
|
|
1080
|
+
1. Read the actual source code \u2014 not summaries
|
|
1081
|
+
2. Send to Codex MCP for initial sweep
|
|
1082
|
+
3. Validate against ARCHITECTURE.md
|
|
1083
|
+
4. Trace full identity chain with a CUSTOM-NAMED employee (e.g., "jarvis" as CTO)
|
|
1084
|
+
5. Count matches before and after any claimed fix
|
|
1085
|
+
6. Write structured report with PASS/FAIL per item
|
|
1086
|
+
|
|
1087
|
+
After an audit, fix the findings yourself if you can. Don't hand off when you have the context.`
|
|
1029
1088
|
}
|
|
1030
1089
|
};
|
|
1031
1090
|
CLIENT_COO_TEMPLATE = `---
|
|
@@ -1181,7 +1240,7 @@ __export(active_agent_exports, {
|
|
|
1181
1240
|
getAllActiveAgents: () => getAllActiveAgents,
|
|
1182
1241
|
writeActiveAgent: () => writeActiveAgent
|
|
1183
1242
|
});
|
|
1184
|
-
import { readFileSync as
|
|
1243
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync2 } from "fs";
|
|
1185
1244
|
import { execSync as execSync4 } from "child_process";
|
|
1186
1245
|
import path6 from "path";
|
|
1187
1246
|
function getMarkerPath() {
|
|
@@ -1206,7 +1265,7 @@ function clearActiveAgent() {
|
|
|
1206
1265
|
function getActiveAgent() {
|
|
1207
1266
|
try {
|
|
1208
1267
|
const markerPath = getMarkerPath();
|
|
1209
|
-
const raw =
|
|
1268
|
+
const raw = readFileSync3(markerPath, "utf8");
|
|
1210
1269
|
const data = JSON.parse(raw);
|
|
1211
1270
|
if (data.agentId) {
|
|
1212
1271
|
if (data.startedAt) {
|
|
@@ -1259,7 +1318,7 @@ function getAllActiveAgents() {
|
|
|
1259
1318
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
1260
1319
|
if (key === "undefined") continue;
|
|
1261
1320
|
try {
|
|
1262
|
-
const raw =
|
|
1321
|
+
const raw = readFileSync3(path6.join(CACHE_DIR, file), "utf8");
|
|
1263
1322
|
const data = JSON.parse(raw);
|
|
1264
1323
|
if (!data.agentId) continue;
|
|
1265
1324
|
if (data.startedAt) {
|
|
@@ -1311,17 +1370,70 @@ var init_active_agent = __esm({
|
|
|
1311
1370
|
// src/bin/exe-launch-agent.ts
|
|
1312
1371
|
import os3 from "os";
|
|
1313
1372
|
import path7 from "path";
|
|
1314
|
-
import { existsSync as existsSync6, readFileSync as
|
|
1373
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, readdirSync as readdirSync3 } from "fs";
|
|
1315
1374
|
import { spawnSync } from "child_process";
|
|
1316
1375
|
|
|
1317
1376
|
// src/lib/database.ts
|
|
1318
1377
|
import { createClient } from "@libsql/client";
|
|
1378
|
+
|
|
1379
|
+
// src/lib/db-retry.ts
|
|
1380
|
+
var MAX_RETRIES = 3;
|
|
1381
|
+
var BASE_DELAY_MS = 200;
|
|
1382
|
+
var MAX_JITTER_MS = 300;
|
|
1383
|
+
function isBusyError(err) {
|
|
1384
|
+
if (err instanceof Error) {
|
|
1385
|
+
const msg = err.message.toLowerCase();
|
|
1386
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1387
|
+
}
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
function delay(ms) {
|
|
1391
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1392
|
+
}
|
|
1393
|
+
async function retryOnBusy(fn, label) {
|
|
1394
|
+
let lastError;
|
|
1395
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1396
|
+
try {
|
|
1397
|
+
return await fn();
|
|
1398
|
+
} catch (err) {
|
|
1399
|
+
lastError = err;
|
|
1400
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
1401
|
+
throw err;
|
|
1402
|
+
}
|
|
1403
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
1404
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
1405
|
+
process.stderr.write(
|
|
1406
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
1407
|
+
`
|
|
1408
|
+
);
|
|
1409
|
+
await delay(backoff + jitter);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
throw lastError;
|
|
1413
|
+
}
|
|
1414
|
+
function wrapWithRetry(client) {
|
|
1415
|
+
return new Proxy(client, {
|
|
1416
|
+
get(target, prop, receiver) {
|
|
1417
|
+
if (prop === "execute") {
|
|
1418
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
1419
|
+
}
|
|
1420
|
+
if (prop === "batch") {
|
|
1421
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
1422
|
+
}
|
|
1423
|
+
return Reflect.get(target, prop, receiver);
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// src/lib/database.ts
|
|
1319
1429
|
var _client = null;
|
|
1430
|
+
var _resilientClient = null;
|
|
1320
1431
|
var initTurso = initDatabase;
|
|
1321
1432
|
async function initDatabase(config) {
|
|
1322
1433
|
if (_client) {
|
|
1323
1434
|
_client.close();
|
|
1324
1435
|
_client = null;
|
|
1436
|
+
_resilientClient = null;
|
|
1325
1437
|
}
|
|
1326
1438
|
const opts = {
|
|
1327
1439
|
url: `file:${config.dbPath}`
|
|
@@ -1330,17 +1442,24 @@ async function initDatabase(config) {
|
|
|
1330
1442
|
opts.encryptionKey = config.encryptionKey;
|
|
1331
1443
|
}
|
|
1332
1444
|
_client = createClient(opts);
|
|
1445
|
+
_resilientClient = wrapWithRetry(_client);
|
|
1333
1446
|
}
|
|
1334
1447
|
function getClient() {
|
|
1448
|
+
if (!_resilientClient) {
|
|
1449
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1450
|
+
}
|
|
1451
|
+
return _resilientClient;
|
|
1452
|
+
}
|
|
1453
|
+
function getRawClient() {
|
|
1335
1454
|
if (!_client) {
|
|
1336
1455
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1337
1456
|
}
|
|
1338
1457
|
return _client;
|
|
1339
1458
|
}
|
|
1340
1459
|
async function ensureSchema() {
|
|
1341
|
-
const client =
|
|
1460
|
+
const client = getRawClient();
|
|
1342
1461
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1343
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1462
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1344
1463
|
try {
|
|
1345
1464
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1346
1465
|
} catch {
|
|
@@ -2134,6 +2253,7 @@ async function disposeDatabase() {
|
|
|
2134
2253
|
if (_client) {
|
|
2135
2254
|
_client.close();
|
|
2136
2255
|
_client = null;
|
|
2256
|
+
_resilientClient = null;
|
|
2137
2257
|
}
|
|
2138
2258
|
}
|
|
2139
2259
|
|
|
@@ -2512,7 +2632,13 @@ var PROVIDER_TABLE = {
|
|
|
2512
2632
|
var DEFAULT_PROVIDER = "default";
|
|
2513
2633
|
|
|
2514
2634
|
// src/bin/exe-launch-agent.ts
|
|
2515
|
-
|
|
2635
|
+
function getKnownAgents() {
|
|
2636
|
+
try {
|
|
2637
|
+
return loadEmployeesSync().map((e) => e.name);
|
|
2638
|
+
} catch {
|
|
2639
|
+
return ["exe"];
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2516
2642
|
function parseBasename(basename) {
|
|
2517
2643
|
const idx = basename.indexOf("-");
|
|
2518
2644
|
if (idx === -1) return { agent: basename, provider: DEFAULT_PROVIDER };
|
|
@@ -2538,7 +2664,8 @@ function resolveAgent(argv) {
|
|
|
2538
2664
|
return { agent, provider: DEFAULT_PROVIDER, passthrough };
|
|
2539
2665
|
}
|
|
2540
2666
|
async function isKnownAgent(agent) {
|
|
2541
|
-
|
|
2667
|
+
const knownAgents = getKnownAgents();
|
|
2668
|
+
if (knownAgents.some((a) => a.toLowerCase() === agent.toLowerCase())) return true;
|
|
2542
2669
|
try {
|
|
2543
2670
|
const employees = await loadEmployees();
|
|
2544
2671
|
return employees.some((e) => e.name.toLowerCase() === agent.toLowerCase());
|
|
@@ -2560,7 +2687,7 @@ function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _prov
|
|
|
2560
2687
|
const effectiveIdPath = existsSync6(idPath) ? idPath : existsSync6(ccAgentPath) ? ccAgentPath : null;
|
|
2561
2688
|
if (effectiveIdPath) {
|
|
2562
2689
|
try {
|
|
2563
|
-
const identity =
|
|
2690
|
+
const identity = readFileSync4(effectiveIdPath, "utf-8");
|
|
2564
2691
|
args.push("--system-prompt", identity);
|
|
2565
2692
|
} catch {
|
|
2566
2693
|
args.push("--append-system-prompt-file", effectiveIdPath);
|
|
@@ -2695,7 +2822,7 @@ async function main() {
|
|
|
2695
2822
|
if (sourceFile) {
|
|
2696
2823
|
try {
|
|
2697
2824
|
mkdirSync4(ccAgentDir, { recursive: true });
|
|
2698
|
-
let content =
|
|
2825
|
+
let content = readFileSync4(sourceFile, "utf-8");
|
|
2699
2826
|
content = content.replace(/\$\{agent_id\}/g, agent);
|
|
2700
2827
|
writeFileSync3(ccAgentFile, content, "utf-8");
|
|
2701
2828
|
process.stderr.write(
|