@askexenow/exe-os 0.8.85 → 0.8.87
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/cleanup-stale-review-tasks.js +57 -19
- package/dist/bin/cli.js +510 -340
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +3 -3
- package/dist/bin/exe-boot.js +344 -346
- package/dist/bin/exe-dispatch.js +375 -250
- package/dist/bin/exe-forget.js +5 -1
- package/dist/bin/exe-gateway.js +260 -135
- package/dist/bin/exe-healthcheck.js +133 -1
- package/dist/bin/exe-heartbeat.js +72 -31
- package/dist/bin/exe-link.js +25 -2
- package/dist/bin/exe-new-employee.js +22 -0
- package/dist/bin/exe-pending-messages.js +55 -17
- package/dist/bin/exe-pending-reviews.js +57 -19
- package/dist/bin/exe-search.js +6 -2
- package/dist/bin/exe-session-cleanup.js +260 -135
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +57 -19
- package/dist/bin/git-sweep.js +391 -266
- package/dist/bin/install.js +22 -0
- package/dist/bin/scan-tasks.js +394 -269
- package/dist/bin/setup.js +50 -5
- package/dist/gateway/index.js +257 -132
- package/dist/hooks/bug-report-worker.js +242 -117
- package/dist/hooks/commit-complete.js +389 -264
- package/dist/hooks/error-recall.js +6 -2
- package/dist/hooks/ingest-worker.js +314 -193
- package/dist/hooks/post-compact.js +84 -46
- package/dist/hooks/pre-compact.js +272 -147
- package/dist/hooks/pre-tool-use.js +104 -66
- package/dist/hooks/prompt-submit.js +126 -66
- package/dist/hooks/session-end.js +277 -152
- package/dist/hooks/session-start.js +70 -28
- package/dist/hooks/stop.js +90 -52
- package/dist/hooks/subagent-stop.js +84 -46
- package/dist/hooks/summary-worker.js +175 -114
- package/dist/index.js +296 -171
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +25 -2
- package/dist/lib/exe-daemon.js +338 -213
- package/dist/lib/hybrid-search.js +7 -2
- package/dist/lib/messaging.js +95 -39
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/tasks.js +242 -117
- package/dist/lib/tmux-routing.js +314 -189
- package/dist/mcp/server.js +573 -274
- package/dist/mcp/tools/create-task.js +260 -135
- package/dist/mcp/tools/list-tasks.js +68 -30
- package/dist/mcp/tools/send-message.js +100 -44
- package/dist/mcp/tools/update-task.js +123 -67
- package/dist/runtime/index.js +276 -151
- package/dist/tui/App.js +479 -354
- package/package.json +1 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -3963,7 +3963,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3963
3963
|
process.stderr.write("[hybrid-search] Embed daemon unavailable \u2014 FTS-only mode\n");
|
|
3964
3964
|
}
|
|
3965
3965
|
let grepPromise = Promise.resolve([]);
|
|
3966
|
-
if (config.fileGrepEnabled
|
|
3966
|
+
if (config.fileGrepEnabled === true) {
|
|
3967
3967
|
try {
|
|
3968
3968
|
const { getProjectName: getProjectName2 } = await Promise.resolve().then(() => (init_project_name(), project_name_exports));
|
|
3969
3969
|
const projectRoot = process.cwd();
|
|
@@ -4232,7 +4232,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
4232
4232
|
source_type: row.source_type ?? null
|
|
4233
4233
|
}));
|
|
4234
4234
|
}
|
|
4235
|
-
async function recentRecords(agentId, options, limit) {
|
|
4235
|
+
async function recentRecords(agentId, options, limit, textFilter) {
|
|
4236
4236
|
const client = getClient();
|
|
4237
4237
|
const statusFilter = options?.includeArchived ? "" : `
|
|
4238
4238
|
AND COALESCE(status, 'active') = 'active'`;
|
|
@@ -4272,6 +4272,10 @@ async function recentRecords(agentId, options, limit) {
|
|
|
4272
4272
|
sql += ` AND memory_type = ?`;
|
|
4273
4273
|
args.push(options.memoryType);
|
|
4274
4274
|
}
|
|
4275
|
+
if (textFilter) {
|
|
4276
|
+
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
4277
|
+
args.push(textFilter);
|
|
4278
|
+
}
|
|
4275
4279
|
sql += ` ORDER BY timestamp DESC LIMIT ?`;
|
|
4276
4280
|
args.push(limit);
|
|
4277
4281
|
const result = await client.execute({ sql, args });
|
|
@@ -4386,6 +4390,7 @@ export {
|
|
|
4386
4390
|
estimateCardinality,
|
|
4387
4391
|
hybridSearch,
|
|
4388
4392
|
lightweightSearch,
|
|
4393
|
+
recentRecords,
|
|
4389
4394
|
rrfMerge,
|
|
4390
4395
|
rrfMergeMulti
|
|
4391
4396
|
};
|
package/dist/lib/messaging.js
CHANGED
|
@@ -361,18 +361,54 @@ var init_provider_table = __esm({
|
|
|
361
361
|
}
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
-
// src/lib/
|
|
365
|
-
|
|
364
|
+
// src/lib/runtime-table.ts
|
|
365
|
+
var RUNTIME_TABLE;
|
|
366
|
+
var init_runtime_table = __esm({
|
|
367
|
+
"src/lib/runtime-table.ts"() {
|
|
368
|
+
"use strict";
|
|
369
|
+
RUNTIME_TABLE = {
|
|
370
|
+
codex: {
|
|
371
|
+
binary: "codex",
|
|
372
|
+
launchMode: "exec",
|
|
373
|
+
autoApproveFlag: "--full-auto",
|
|
374
|
+
inlineFlag: "--no-alt-screen",
|
|
375
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
376
|
+
defaultModel: "gpt-5.4"
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// src/lib/agent-config.ts
|
|
383
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
|
|
366
384
|
import path4 from "path";
|
|
385
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
386
|
+
var init_agent_config = __esm({
|
|
387
|
+
"src/lib/agent-config.ts"() {
|
|
388
|
+
"use strict";
|
|
389
|
+
init_config();
|
|
390
|
+
init_runtime_table();
|
|
391
|
+
AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
|
|
392
|
+
DEFAULT_MODELS = {
|
|
393
|
+
claude: "claude-opus-4",
|
|
394
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
395
|
+
opencode: "minimax-m2.7"
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// src/lib/intercom-queue.ts
|
|
401
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
402
|
+
import path5 from "path";
|
|
367
403
|
import os4 from "os";
|
|
368
404
|
function ensureDir() {
|
|
369
|
-
const dir =
|
|
370
|
-
if (!
|
|
405
|
+
const dir = path5.dirname(QUEUE_PATH);
|
|
406
|
+
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
371
407
|
}
|
|
372
408
|
function readQueue() {
|
|
373
409
|
try {
|
|
374
|
-
if (!
|
|
375
|
-
return JSON.parse(
|
|
410
|
+
if (!existsSync4(QUEUE_PATH)) return [];
|
|
411
|
+
return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
|
|
376
412
|
} catch {
|
|
377
413
|
return [];
|
|
378
414
|
}
|
|
@@ -380,7 +416,7 @@ function readQueue() {
|
|
|
380
416
|
function writeQueue(queue) {
|
|
381
417
|
ensureDir();
|
|
382
418
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
383
|
-
|
|
419
|
+
writeFileSync3(tmp, JSON.stringify(queue, null, 2));
|
|
384
420
|
renameSync3(tmp, QUEUE_PATH);
|
|
385
421
|
}
|
|
386
422
|
function queueIntercom(targetSession, reason) {
|
|
@@ -404,31 +440,31 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
404
440
|
var init_intercom_queue = __esm({
|
|
405
441
|
"src/lib/intercom-queue.ts"() {
|
|
406
442
|
"use strict";
|
|
407
|
-
QUEUE_PATH =
|
|
443
|
+
QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
408
444
|
TTL_MS = 60 * 60 * 1e3;
|
|
409
|
-
INTERCOM_LOG =
|
|
445
|
+
INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
410
446
|
}
|
|
411
447
|
});
|
|
412
448
|
|
|
413
449
|
// src/lib/license.ts
|
|
414
|
-
import { readFileSync as
|
|
450
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
415
451
|
import { randomUUID } from "crypto";
|
|
416
|
-
import
|
|
452
|
+
import path6 from "path";
|
|
417
453
|
import { jwtVerify, importSPKI } from "jose";
|
|
418
454
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
419
455
|
var init_license = __esm({
|
|
420
456
|
"src/lib/license.ts"() {
|
|
421
457
|
"use strict";
|
|
422
458
|
init_config();
|
|
423
|
-
LICENSE_PATH =
|
|
424
|
-
CACHE_PATH =
|
|
425
|
-
DEVICE_ID_PATH =
|
|
459
|
+
LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
460
|
+
CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
461
|
+
DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
426
462
|
}
|
|
427
463
|
});
|
|
428
464
|
|
|
429
465
|
// src/lib/plan-limits.ts
|
|
430
|
-
import { readFileSync as
|
|
431
|
-
import
|
|
466
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
467
|
+
import path7 from "path";
|
|
432
468
|
var CACHE_PATH2;
|
|
433
469
|
var init_plan_limits = __esm({
|
|
434
470
|
"src/lib/plan-limits.ts"() {
|
|
@@ -437,13 +473,13 @@ var init_plan_limits = __esm({
|
|
|
437
473
|
init_employees();
|
|
438
474
|
init_license();
|
|
439
475
|
init_config();
|
|
440
|
-
CACHE_PATH2 =
|
|
476
|
+
CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
441
477
|
}
|
|
442
478
|
});
|
|
443
479
|
|
|
444
480
|
// src/lib/tmux-routing.ts
|
|
445
|
-
import { readFileSync as
|
|
446
|
-
import
|
|
481
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
|
|
482
|
+
import path8 from "path";
|
|
447
483
|
import os5 from "os";
|
|
448
484
|
import { fileURLToPath } from "url";
|
|
449
485
|
function getMySession() {
|
|
@@ -484,7 +520,7 @@ function extractRootExe(name) {
|
|
|
484
520
|
}
|
|
485
521
|
function getParentExe(sessionKey) {
|
|
486
522
|
try {
|
|
487
|
-
const data = JSON.parse(
|
|
523
|
+
const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
488
524
|
return data.parentExe || null;
|
|
489
525
|
} catch {
|
|
490
526
|
return null;
|
|
@@ -508,32 +544,50 @@ function isEmployeeAlive(sessionName) {
|
|
|
508
544
|
}
|
|
509
545
|
function readDebounceState() {
|
|
510
546
|
try {
|
|
511
|
-
if (!
|
|
512
|
-
|
|
547
|
+
if (!existsSync7(DEBOUNCE_FILE)) return {};
|
|
548
|
+
const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
|
|
549
|
+
const state = {};
|
|
550
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
551
|
+
if (typeof val === "number") {
|
|
552
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
553
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
554
|
+
state[key] = val;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return state;
|
|
513
558
|
} catch {
|
|
514
559
|
return {};
|
|
515
560
|
}
|
|
516
561
|
}
|
|
517
562
|
function writeDebounceState(state) {
|
|
518
563
|
try {
|
|
519
|
-
if (!
|
|
520
|
-
|
|
564
|
+
if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
|
|
565
|
+
writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
|
|
521
566
|
} catch {
|
|
522
567
|
}
|
|
523
568
|
}
|
|
524
569
|
function isDebounced(targetSession) {
|
|
525
570
|
const state = readDebounceState();
|
|
526
|
-
const
|
|
527
|
-
|
|
571
|
+
const entry = state[targetSession];
|
|
572
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
573
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
574
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
575
|
+
state[targetSession].pending++;
|
|
576
|
+
writeDebounceState(state);
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
528
580
|
}
|
|
529
581
|
function recordDebounce(targetSession) {
|
|
530
582
|
const state = readDebounceState();
|
|
531
|
-
state[targetSession]
|
|
583
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
584
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
532
585
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
533
586
|
for (const key of Object.keys(state)) {
|
|
534
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
587
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
535
588
|
}
|
|
536
589
|
writeDebounceState(state);
|
|
590
|
+
return batched;
|
|
537
591
|
}
|
|
538
592
|
function logIntercom(msg) {
|
|
539
593
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -574,7 +628,7 @@ function sendIntercom(targetSession) {
|
|
|
574
628
|
return "skipped_exe";
|
|
575
629
|
}
|
|
576
630
|
if (isDebounced(targetSession)) {
|
|
577
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
631
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
578
632
|
return "debounced";
|
|
579
633
|
}
|
|
580
634
|
try {
|
|
@@ -586,14 +640,14 @@ function sendIntercom(targetSession) {
|
|
|
586
640
|
const sessionState = getSessionState(targetSession);
|
|
587
641
|
if (sessionState === "no_claude") {
|
|
588
642
|
queueIntercom(targetSession, "claude not running in session");
|
|
589
|
-
recordDebounce(targetSession);
|
|
590
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
643
|
+
const batched2 = recordDebounce(targetSession);
|
|
644
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
591
645
|
return "queued";
|
|
592
646
|
}
|
|
593
647
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
594
648
|
queueIntercom(targetSession, "session busy at send time");
|
|
595
|
-
recordDebounce(targetSession);
|
|
596
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
649
|
+
const batched2 = recordDebounce(targetSession);
|
|
650
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
597
651
|
return "queued";
|
|
598
652
|
}
|
|
599
653
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -601,8 +655,8 @@ function sendIntercom(targetSession) {
|
|
|
601
655
|
transport.sendKeys(targetSession, "q");
|
|
602
656
|
}
|
|
603
657
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
604
|
-
recordDebounce(targetSession);
|
|
605
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
658
|
+
const batched = recordDebounce(targetSession);
|
|
659
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
606
660
|
return "delivered";
|
|
607
661
|
} catch {
|
|
608
662
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -619,15 +673,17 @@ var init_tmux_routing = __esm({
|
|
|
619
673
|
init_cc_agent_support();
|
|
620
674
|
init_mcp_prefix();
|
|
621
675
|
init_provider_table();
|
|
676
|
+
init_agent_config();
|
|
677
|
+
init_runtime_table();
|
|
622
678
|
init_intercom_queue();
|
|
623
679
|
init_plan_limits();
|
|
624
680
|
init_employees();
|
|
625
|
-
SPAWN_LOCK_DIR =
|
|
626
|
-
SESSION_CACHE =
|
|
681
|
+
SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
682
|
+
SESSION_CACHE = path8.join(os5.homedir(), ".exe-os", "session-cache");
|
|
627
683
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
628
684
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
629
|
-
INTERCOM_LOG2 =
|
|
630
|
-
DEBOUNCE_FILE =
|
|
685
|
+
INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
686
|
+
DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
|
|
631
687
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
632
688
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
633
689
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/lib/runtime-table.ts
|
|
2
|
+
var RUNTIME_TABLE = {
|
|
3
|
+
codex: {
|
|
4
|
+
binary: "codex",
|
|
5
|
+
launchMode: "exec",
|
|
6
|
+
autoApproveFlag: "--full-auto",
|
|
7
|
+
inlineFlag: "--no-alt-screen",
|
|
8
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
9
|
+
defaultModel: "gpt-5.4"
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var DEFAULT_RUNTIME = "claude";
|
|
13
|
+
export {
|
|
14
|
+
DEFAULT_RUNTIME,
|
|
15
|
+
RUNTIME_TABLE
|
|
16
|
+
};
|
|
@@ -63,6 +63,28 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
63
63
|
created++;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
const codexLauncherCandidates = [
|
|
67
|
+
path.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
|
|
68
|
+
path.join(packageRoot, "src", "bin", "exe-start-codex.ts")
|
|
69
|
+
];
|
|
70
|
+
let codexLauncher = null;
|
|
71
|
+
for (const c of codexLauncherCandidates) {
|
|
72
|
+
if (existsSync(c)) {
|
|
73
|
+
codexLauncher = c;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (codexLauncher) {
|
|
78
|
+
for (const emp of employees) {
|
|
79
|
+
const wrapperPath = path.join(binDir, `${emp.name}-codex`);
|
|
80
|
+
const content = `#!/bin/bash
|
|
81
|
+
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
82
|
+
`;
|
|
83
|
+
writeFileSync(wrapperPath, content);
|
|
84
|
+
chmodSync(wrapperPath, 493);
|
|
85
|
+
created++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
66
88
|
const pathConfigured = ensurePath(home, binDir);
|
|
67
89
|
return { created, pathConfigured };
|
|
68
90
|
}
|