@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
|
@@ -412,39 +412,75 @@ var init_provider_table = __esm({
|
|
|
412
412
|
}
|
|
413
413
|
});
|
|
414
414
|
|
|
415
|
-
// src/lib/
|
|
416
|
-
|
|
415
|
+
// src/lib/runtime-table.ts
|
|
416
|
+
var RUNTIME_TABLE;
|
|
417
|
+
var init_runtime_table = __esm({
|
|
418
|
+
"src/lib/runtime-table.ts"() {
|
|
419
|
+
"use strict";
|
|
420
|
+
RUNTIME_TABLE = {
|
|
421
|
+
codex: {
|
|
422
|
+
binary: "codex",
|
|
423
|
+
launchMode: "exec",
|
|
424
|
+
autoApproveFlag: "--full-auto",
|
|
425
|
+
inlineFlag: "--no-alt-screen",
|
|
426
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
427
|
+
defaultModel: "gpt-5.4"
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// src/lib/agent-config.ts
|
|
434
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync } from "fs";
|
|
417
435
|
import path5 from "path";
|
|
436
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
437
|
+
var init_agent_config = __esm({
|
|
438
|
+
"src/lib/agent-config.ts"() {
|
|
439
|
+
"use strict";
|
|
440
|
+
init_config();
|
|
441
|
+
init_runtime_table();
|
|
442
|
+
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
443
|
+
DEFAULT_MODELS = {
|
|
444
|
+
claude: "claude-opus-4",
|
|
445
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
446
|
+
opencode: "minimax-m2.7"
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// src/lib/intercom-queue.ts
|
|
452
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
453
|
+
import path6 from "path";
|
|
418
454
|
import os5 from "os";
|
|
419
455
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
420
456
|
var init_intercom_queue = __esm({
|
|
421
457
|
"src/lib/intercom-queue.ts"() {
|
|
422
458
|
"use strict";
|
|
423
|
-
QUEUE_PATH =
|
|
459
|
+
QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
424
460
|
TTL_MS = 60 * 60 * 1e3;
|
|
425
|
-
INTERCOM_LOG =
|
|
461
|
+
INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
426
462
|
}
|
|
427
463
|
});
|
|
428
464
|
|
|
429
465
|
// src/lib/license.ts
|
|
430
|
-
import { readFileSync as
|
|
466
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
431
467
|
import { randomUUID } from "crypto";
|
|
432
|
-
import
|
|
468
|
+
import path7 from "path";
|
|
433
469
|
import { jwtVerify, importSPKI } from "jose";
|
|
434
470
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
435
471
|
var init_license = __esm({
|
|
436
472
|
"src/lib/license.ts"() {
|
|
437
473
|
"use strict";
|
|
438
474
|
init_config();
|
|
439
|
-
LICENSE_PATH =
|
|
440
|
-
CACHE_PATH =
|
|
441
|
-
DEVICE_ID_PATH =
|
|
475
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
476
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
477
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
442
478
|
}
|
|
443
479
|
});
|
|
444
480
|
|
|
445
481
|
// src/lib/plan-limits.ts
|
|
446
|
-
import { readFileSync as
|
|
447
|
-
import
|
|
482
|
+
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
|
|
483
|
+
import path8 from "path";
|
|
448
484
|
var CACHE_PATH2;
|
|
449
485
|
var init_plan_limits = __esm({
|
|
450
486
|
"src/lib/plan-limits.ts"() {
|
|
@@ -453,13 +489,13 @@ var init_plan_limits = __esm({
|
|
|
453
489
|
init_employees();
|
|
454
490
|
init_license();
|
|
455
491
|
init_config();
|
|
456
|
-
CACHE_PATH2 =
|
|
492
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
457
493
|
}
|
|
458
494
|
});
|
|
459
495
|
|
|
460
496
|
// src/lib/tmux-routing.ts
|
|
461
|
-
import { readFileSync as
|
|
462
|
-
import
|
|
497
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync } from "fs";
|
|
498
|
+
import path9 from "path";
|
|
463
499
|
import os6 from "os";
|
|
464
500
|
import { fileURLToPath } from "url";
|
|
465
501
|
function getMySession() {
|
|
@@ -473,7 +509,7 @@ function extractRootExe(name) {
|
|
|
473
509
|
}
|
|
474
510
|
function getParentExe(sessionKey) {
|
|
475
511
|
try {
|
|
476
|
-
const data = JSON.parse(
|
|
512
|
+
const data = JSON.parse(readFileSync8(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
477
513
|
return data.parentExe || null;
|
|
478
514
|
} catch {
|
|
479
515
|
return null;
|
|
@@ -502,13 +538,15 @@ var init_tmux_routing = __esm({
|
|
|
502
538
|
init_cc_agent_support();
|
|
503
539
|
init_mcp_prefix();
|
|
504
540
|
init_provider_table();
|
|
541
|
+
init_agent_config();
|
|
542
|
+
init_runtime_table();
|
|
505
543
|
init_intercom_queue();
|
|
506
544
|
init_plan_limits();
|
|
507
545
|
init_employees();
|
|
508
|
-
SPAWN_LOCK_DIR =
|
|
509
|
-
SESSION_CACHE =
|
|
510
|
-
INTERCOM_LOG2 =
|
|
511
|
-
DEBOUNCE_FILE =
|
|
546
|
+
SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
547
|
+
SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
|
|
548
|
+
INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
549
|
+
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
512
550
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
513
551
|
}
|
|
514
552
|
});
|
|
@@ -539,11 +577,11 @@ var init_task_scope = __esm({
|
|
|
539
577
|
|
|
540
578
|
// src/lib/tasks-crud.ts
|
|
541
579
|
import crypto2 from "crypto";
|
|
542
|
-
import
|
|
580
|
+
import path10 from "path";
|
|
543
581
|
import os7 from "os";
|
|
544
582
|
import { execSync as execSync4 } from "child_process";
|
|
545
583
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
546
|
-
import { existsSync as
|
|
584
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
547
585
|
function buildKeywordIndex() {
|
|
548
586
|
const idx = /* @__PURE__ */ new Map();
|
|
549
587
|
for (const [role, keywords] of Object.entries(LANE_KEYWORDS)) {
|
|
@@ -625,8 +663,8 @@ var init_tasks_crud = __esm({
|
|
|
625
663
|
});
|
|
626
664
|
|
|
627
665
|
// src/lib/tasks-review.ts
|
|
628
|
-
import
|
|
629
|
-
import { existsSync as
|
|
666
|
+
import path11 from "path";
|
|
667
|
+
import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
630
668
|
var init_tasks_review = __esm({
|
|
631
669
|
"src/lib/tasks-review.ts"() {
|
|
632
670
|
"use strict";
|
|
@@ -641,7 +679,7 @@ var init_tasks_review = __esm({
|
|
|
641
679
|
});
|
|
642
680
|
|
|
643
681
|
// src/lib/tasks-chain.ts
|
|
644
|
-
import
|
|
682
|
+
import path12 from "path";
|
|
645
683
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
646
684
|
var init_tasks_chain = __esm({
|
|
647
685
|
"src/lib/tasks-chain.ts"() {
|
|
@@ -665,8 +703,8 @@ var init_tasks_notify = __esm({
|
|
|
665
703
|
});
|
|
666
704
|
|
|
667
705
|
// src/lib/tasks.ts
|
|
668
|
-
import
|
|
669
|
-
import { writeFileSync as
|
|
706
|
+
import path13 from "path";
|
|
707
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
670
708
|
var init_tasks = __esm({
|
|
671
709
|
"src/lib/tasks.ts"() {
|
|
672
710
|
"use strict";
|
|
@@ -686,7 +724,7 @@ var init_tasks = __esm({
|
|
|
686
724
|
|
|
687
725
|
// src/lib/project-name.ts
|
|
688
726
|
import { execSync as execSync5 } from "child_process";
|
|
689
|
-
import
|
|
727
|
+
import path14 from "path";
|
|
690
728
|
function getProjectName(cwd) {
|
|
691
729
|
const dir = cwd ?? process.cwd();
|
|
692
730
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -699,7 +737,7 @@ function getProjectName(cwd) {
|
|
|
699
737
|
timeout: 2e3,
|
|
700
738
|
stdio: ["pipe", "pipe", "pipe"]
|
|
701
739
|
}).trim();
|
|
702
|
-
repoRoot =
|
|
740
|
+
repoRoot = path14.dirname(gitCommonDir);
|
|
703
741
|
} catch {
|
|
704
742
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
705
743
|
cwd: dir,
|
|
@@ -708,11 +746,11 @@ function getProjectName(cwd) {
|
|
|
708
746
|
stdio: ["pipe", "pipe", "pipe"]
|
|
709
747
|
}).trim();
|
|
710
748
|
}
|
|
711
|
-
_cached2 =
|
|
749
|
+
_cached2 = path14.basename(repoRoot);
|
|
712
750
|
_cachedCwd = dir;
|
|
713
751
|
return _cached2;
|
|
714
752
|
} catch {
|
|
715
|
-
_cached2 =
|
|
753
|
+
_cached2 = path14.basename(dir);
|
|
716
754
|
_cachedCwd = dir;
|
|
717
755
|
return _cached2;
|
|
718
756
|
}
|
|
@@ -364,18 +364,54 @@ var init_provider_table = __esm({
|
|
|
364
364
|
}
|
|
365
365
|
});
|
|
366
366
|
|
|
367
|
-
// src/lib/
|
|
368
|
-
|
|
367
|
+
// src/lib/runtime-table.ts
|
|
368
|
+
var RUNTIME_TABLE;
|
|
369
|
+
var init_runtime_table = __esm({
|
|
370
|
+
"src/lib/runtime-table.ts"() {
|
|
371
|
+
"use strict";
|
|
372
|
+
RUNTIME_TABLE = {
|
|
373
|
+
codex: {
|
|
374
|
+
binary: "codex",
|
|
375
|
+
launchMode: "exec",
|
|
376
|
+
autoApproveFlag: "--full-auto",
|
|
377
|
+
inlineFlag: "--no-alt-screen",
|
|
378
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
379
|
+
defaultModel: "gpt-5.4"
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// src/lib/agent-config.ts
|
|
386
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
|
|
369
387
|
import path4 from "path";
|
|
388
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
389
|
+
var init_agent_config = __esm({
|
|
390
|
+
"src/lib/agent-config.ts"() {
|
|
391
|
+
"use strict";
|
|
392
|
+
init_config();
|
|
393
|
+
init_runtime_table();
|
|
394
|
+
AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
|
|
395
|
+
DEFAULT_MODELS = {
|
|
396
|
+
claude: "claude-opus-4",
|
|
397
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
398
|
+
opencode: "minimax-m2.7"
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// src/lib/intercom-queue.ts
|
|
404
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
405
|
+
import path5 from "path";
|
|
370
406
|
import os4 from "os";
|
|
371
407
|
function ensureDir() {
|
|
372
|
-
const dir =
|
|
373
|
-
if (!
|
|
408
|
+
const dir = path5.dirname(QUEUE_PATH);
|
|
409
|
+
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
374
410
|
}
|
|
375
411
|
function readQueue() {
|
|
376
412
|
try {
|
|
377
|
-
if (!
|
|
378
|
-
return JSON.parse(
|
|
413
|
+
if (!existsSync4(QUEUE_PATH)) return [];
|
|
414
|
+
return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
|
|
379
415
|
} catch {
|
|
380
416
|
return [];
|
|
381
417
|
}
|
|
@@ -383,7 +419,7 @@ function readQueue() {
|
|
|
383
419
|
function writeQueue(queue) {
|
|
384
420
|
ensureDir();
|
|
385
421
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
386
|
-
|
|
422
|
+
writeFileSync3(tmp, JSON.stringify(queue, null, 2));
|
|
387
423
|
renameSync3(tmp, QUEUE_PATH);
|
|
388
424
|
}
|
|
389
425
|
function queueIntercom(targetSession, reason) {
|
|
@@ -407,31 +443,31 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
407
443
|
var init_intercom_queue = __esm({
|
|
408
444
|
"src/lib/intercom-queue.ts"() {
|
|
409
445
|
"use strict";
|
|
410
|
-
QUEUE_PATH =
|
|
446
|
+
QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
411
447
|
TTL_MS = 60 * 60 * 1e3;
|
|
412
|
-
INTERCOM_LOG =
|
|
448
|
+
INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
413
449
|
}
|
|
414
450
|
});
|
|
415
451
|
|
|
416
452
|
// src/lib/license.ts
|
|
417
|
-
import { readFileSync as
|
|
453
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
418
454
|
import { randomUUID } from "crypto";
|
|
419
|
-
import
|
|
455
|
+
import path6 from "path";
|
|
420
456
|
import { jwtVerify, importSPKI } from "jose";
|
|
421
457
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
422
458
|
var init_license = __esm({
|
|
423
459
|
"src/lib/license.ts"() {
|
|
424
460
|
"use strict";
|
|
425
461
|
init_config();
|
|
426
|
-
LICENSE_PATH =
|
|
427
|
-
CACHE_PATH =
|
|
428
|
-
DEVICE_ID_PATH =
|
|
462
|
+
LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
463
|
+
CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
464
|
+
DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
429
465
|
}
|
|
430
466
|
});
|
|
431
467
|
|
|
432
468
|
// src/lib/plan-limits.ts
|
|
433
|
-
import { readFileSync as
|
|
434
|
-
import
|
|
469
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
470
|
+
import path7 from "path";
|
|
435
471
|
var CACHE_PATH2;
|
|
436
472
|
var init_plan_limits = __esm({
|
|
437
473
|
"src/lib/plan-limits.ts"() {
|
|
@@ -440,13 +476,13 @@ var init_plan_limits = __esm({
|
|
|
440
476
|
init_employees();
|
|
441
477
|
init_license();
|
|
442
478
|
init_config();
|
|
443
|
-
CACHE_PATH2 =
|
|
479
|
+
CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
444
480
|
}
|
|
445
481
|
});
|
|
446
482
|
|
|
447
483
|
// src/lib/tmux-routing.ts
|
|
448
|
-
import { readFileSync as
|
|
449
|
-
import
|
|
484
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
|
|
485
|
+
import path8 from "path";
|
|
450
486
|
import os5 from "os";
|
|
451
487
|
import { fileURLToPath } from "url";
|
|
452
488
|
function getMySession() {
|
|
@@ -487,7 +523,7 @@ function extractRootExe(name) {
|
|
|
487
523
|
}
|
|
488
524
|
function getParentExe(sessionKey) {
|
|
489
525
|
try {
|
|
490
|
-
const data = JSON.parse(
|
|
526
|
+
const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
491
527
|
return data.parentExe || null;
|
|
492
528
|
} catch {
|
|
493
529
|
return null;
|
|
@@ -511,32 +547,50 @@ function isEmployeeAlive(sessionName) {
|
|
|
511
547
|
}
|
|
512
548
|
function readDebounceState() {
|
|
513
549
|
try {
|
|
514
|
-
if (!
|
|
515
|
-
|
|
550
|
+
if (!existsSync7(DEBOUNCE_FILE)) return {};
|
|
551
|
+
const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
|
|
552
|
+
const state = {};
|
|
553
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
554
|
+
if (typeof val === "number") {
|
|
555
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
556
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
557
|
+
state[key] = val;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return state;
|
|
516
561
|
} catch {
|
|
517
562
|
return {};
|
|
518
563
|
}
|
|
519
564
|
}
|
|
520
565
|
function writeDebounceState(state) {
|
|
521
566
|
try {
|
|
522
|
-
if (!
|
|
523
|
-
|
|
567
|
+
if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
|
|
568
|
+
writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
|
|
524
569
|
} catch {
|
|
525
570
|
}
|
|
526
571
|
}
|
|
527
572
|
function isDebounced(targetSession) {
|
|
528
573
|
const state = readDebounceState();
|
|
529
|
-
const
|
|
530
|
-
|
|
574
|
+
const entry = state[targetSession];
|
|
575
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
576
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
577
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
578
|
+
state[targetSession].pending++;
|
|
579
|
+
writeDebounceState(state);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
return false;
|
|
531
583
|
}
|
|
532
584
|
function recordDebounce(targetSession) {
|
|
533
585
|
const state = readDebounceState();
|
|
534
|
-
state[targetSession]
|
|
586
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
587
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
535
588
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
536
589
|
for (const key of Object.keys(state)) {
|
|
537
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
590
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
538
591
|
}
|
|
539
592
|
writeDebounceState(state);
|
|
593
|
+
return batched;
|
|
540
594
|
}
|
|
541
595
|
function logIntercom(msg) {
|
|
542
596
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -577,7 +631,7 @@ function sendIntercom(targetSession) {
|
|
|
577
631
|
return "skipped_exe";
|
|
578
632
|
}
|
|
579
633
|
if (isDebounced(targetSession)) {
|
|
580
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
634
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
581
635
|
return "debounced";
|
|
582
636
|
}
|
|
583
637
|
try {
|
|
@@ -589,14 +643,14 @@ function sendIntercom(targetSession) {
|
|
|
589
643
|
const sessionState = getSessionState(targetSession);
|
|
590
644
|
if (sessionState === "no_claude") {
|
|
591
645
|
queueIntercom(targetSession, "claude not running in session");
|
|
592
|
-
recordDebounce(targetSession);
|
|
593
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
646
|
+
const batched2 = recordDebounce(targetSession);
|
|
647
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
594
648
|
return "queued";
|
|
595
649
|
}
|
|
596
650
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
597
651
|
queueIntercom(targetSession, "session busy at send time");
|
|
598
|
-
recordDebounce(targetSession);
|
|
599
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
652
|
+
const batched2 = recordDebounce(targetSession);
|
|
653
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
600
654
|
return "queued";
|
|
601
655
|
}
|
|
602
656
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -604,8 +658,8 @@ function sendIntercom(targetSession) {
|
|
|
604
658
|
transport.sendKeys(targetSession, "q");
|
|
605
659
|
}
|
|
606
660
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
607
|
-
recordDebounce(targetSession);
|
|
608
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
661
|
+
const batched = recordDebounce(targetSession);
|
|
662
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
609
663
|
return "delivered";
|
|
610
664
|
} catch {
|
|
611
665
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -622,15 +676,17 @@ var init_tmux_routing = __esm({
|
|
|
622
676
|
init_cc_agent_support();
|
|
623
677
|
init_mcp_prefix();
|
|
624
678
|
init_provider_table();
|
|
679
|
+
init_agent_config();
|
|
680
|
+
init_runtime_table();
|
|
625
681
|
init_intercom_queue();
|
|
626
682
|
init_plan_limits();
|
|
627
683
|
init_employees();
|
|
628
|
-
SPAWN_LOCK_DIR =
|
|
629
|
-
SESSION_CACHE =
|
|
684
|
+
SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
685
|
+
SESSION_CACHE = path8.join(os5.homedir(), ".exe-os", "session-cache");
|
|
630
686
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
631
687
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
632
|
-
INTERCOM_LOG2 =
|
|
633
|
-
DEBOUNCE_FILE =
|
|
688
|
+
INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
689
|
+
DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
|
|
634
690
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
635
691
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
636
692
|
}
|
|
@@ -783,16 +839,16 @@ async function markFailed(messageId, reason) {
|
|
|
783
839
|
|
|
784
840
|
// src/adapters/claude/active-agent.ts
|
|
785
841
|
init_config();
|
|
786
|
-
import { readFileSync as
|
|
842
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
787
843
|
import { execSync as execSync4 } from "child_process";
|
|
788
|
-
import
|
|
844
|
+
import path9 from "path";
|
|
789
845
|
|
|
790
846
|
// src/adapters/claude/session-key.ts
|
|
791
847
|
init_session_key();
|
|
792
848
|
|
|
793
849
|
// src/adapters/claude/active-agent.ts
|
|
794
850
|
init_employees();
|
|
795
|
-
var CACHE_DIR =
|
|
851
|
+
var CACHE_DIR = path9.join(EXE_AI_DIR, "session-cache");
|
|
796
852
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
797
853
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
798
854
|
if (candidate === baseName) return true;
|
|
@@ -837,12 +893,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
837
893
|
return null;
|
|
838
894
|
}
|
|
839
895
|
function getMarkerPath() {
|
|
840
|
-
return
|
|
896
|
+
return path9.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
841
897
|
}
|
|
842
898
|
function getActiveAgent() {
|
|
843
899
|
try {
|
|
844
900
|
const markerPath = getMarkerPath();
|
|
845
|
-
const raw =
|
|
901
|
+
const raw = readFileSync8(markerPath, "utf8");
|
|
846
902
|
const data = JSON.parse(raw);
|
|
847
903
|
if (data.agentId) {
|
|
848
904
|
if (data.startedAt) {
|