@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
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -2201,10 +2201,10 @@ async function disposeEmbedder() {
|
|
|
2201
2201
|
async function embedDirect(text) {
|
|
2202
2202
|
const llamaCpp = await import("node-llama-cpp");
|
|
2203
2203
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2204
|
-
const { existsSync:
|
|
2205
|
-
const
|
|
2206
|
-
const modelPath =
|
|
2207
|
-
if (!
|
|
2204
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
2205
|
+
const path21 = await import("path");
|
|
2206
|
+
const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
2207
|
+
if (!existsSync17(modelPath)) {
|
|
2208
2208
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2209
2209
|
}
|
|
2210
2210
|
const llama = await llamaCpp.getLlama();
|
|
@@ -3292,8 +3292,8 @@ __export(wiki_client_exports, {
|
|
|
3292
3292
|
listDocuments: () => listDocuments,
|
|
3293
3293
|
listWorkspaces: () => listWorkspaces
|
|
3294
3294
|
});
|
|
3295
|
-
async function wikiFetch(config2,
|
|
3296
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
3295
|
+
async function wikiFetch(config2, path21, method = "GET", body) {
|
|
3296
|
+
const url = `${config2.baseUrl}/api/v1${path21}`;
|
|
3297
3297
|
const headers = {
|
|
3298
3298
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
3299
3299
|
"Content-Type": "application/json"
|
|
@@ -3326,7 +3326,7 @@ async function wikiFetch(config2, path20, method = "GET", body) {
|
|
|
3326
3326
|
}
|
|
3327
3327
|
}
|
|
3328
3328
|
if (!response.ok) {
|
|
3329
|
-
throw new Error(`Wiki API ${method} ${
|
|
3329
|
+
throw new Error(`Wiki API ${method} ${path21}: ${response.status} ${response.statusText}`);
|
|
3330
3330
|
}
|
|
3331
3331
|
return response.json();
|
|
3332
3332
|
} finally {
|
|
@@ -5916,9 +5916,9 @@ __export(webhook_exports, {
|
|
|
5916
5916
|
WebhookAdapter: () => WebhookAdapter
|
|
5917
5917
|
});
|
|
5918
5918
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
5919
|
-
function resolvePath(obj,
|
|
5919
|
+
function resolvePath(obj, path21) {
|
|
5920
5920
|
let current = obj;
|
|
5921
|
-
for (const segment of
|
|
5921
|
+
for (const segment of path21.split(".")) {
|
|
5922
5922
|
if (current == null || typeof current !== "object") return void 0;
|
|
5923
5923
|
current = current[segment];
|
|
5924
5924
|
}
|
|
@@ -6315,18 +6315,69 @@ var init_provider_table = __esm({
|
|
|
6315
6315
|
}
|
|
6316
6316
|
});
|
|
6317
6317
|
|
|
6318
|
-
// src/lib/
|
|
6319
|
-
|
|
6318
|
+
// src/lib/runtime-table.ts
|
|
6319
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
6320
|
+
var init_runtime_table = __esm({
|
|
6321
|
+
"src/lib/runtime-table.ts"() {
|
|
6322
|
+
"use strict";
|
|
6323
|
+
RUNTIME_TABLE = {
|
|
6324
|
+
codex: {
|
|
6325
|
+
binary: "codex",
|
|
6326
|
+
launchMode: "exec",
|
|
6327
|
+
autoApproveFlag: "--full-auto",
|
|
6328
|
+
inlineFlag: "--no-alt-screen",
|
|
6329
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
6330
|
+
defaultModel: "gpt-5.4"
|
|
6331
|
+
}
|
|
6332
|
+
};
|
|
6333
|
+
DEFAULT_RUNTIME = "claude";
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
|
|
6337
|
+
// src/lib/agent-config.ts
|
|
6338
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
6320
6339
|
import path9 from "path";
|
|
6340
|
+
function loadAgentConfig() {
|
|
6341
|
+
if (!existsSync8(AGENT_CONFIG_PATH)) return {};
|
|
6342
|
+
try {
|
|
6343
|
+
return JSON.parse(readFileSync7(AGENT_CONFIG_PATH, "utf-8"));
|
|
6344
|
+
} catch {
|
|
6345
|
+
return {};
|
|
6346
|
+
}
|
|
6347
|
+
}
|
|
6348
|
+
function getAgentRuntime(agentId) {
|
|
6349
|
+
const config2 = loadAgentConfig();
|
|
6350
|
+
const entry = config2[agentId];
|
|
6351
|
+
if (entry) return entry;
|
|
6352
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
6353
|
+
}
|
|
6354
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
6355
|
+
var init_agent_config = __esm({
|
|
6356
|
+
"src/lib/agent-config.ts"() {
|
|
6357
|
+
"use strict";
|
|
6358
|
+
init_config();
|
|
6359
|
+
init_runtime_table();
|
|
6360
|
+
AGENT_CONFIG_PATH = path9.join(EXE_AI_DIR, "agent-config.json");
|
|
6361
|
+
DEFAULT_MODELS = {
|
|
6362
|
+
claude: "claude-opus-4",
|
|
6363
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
6364
|
+
opencode: "minimax-m2.7"
|
|
6365
|
+
};
|
|
6366
|
+
}
|
|
6367
|
+
});
|
|
6368
|
+
|
|
6369
|
+
// src/lib/intercom-queue.ts
|
|
6370
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
6371
|
+
import path10 from "path";
|
|
6321
6372
|
import os6 from "os";
|
|
6322
6373
|
function ensureDir() {
|
|
6323
|
-
const dir =
|
|
6324
|
-
if (!
|
|
6374
|
+
const dir = path10.dirname(QUEUE_PATH);
|
|
6375
|
+
if (!existsSync9(dir)) mkdirSync6(dir, { recursive: true });
|
|
6325
6376
|
}
|
|
6326
6377
|
function readQueue() {
|
|
6327
6378
|
try {
|
|
6328
|
-
if (!
|
|
6329
|
-
return JSON.parse(
|
|
6379
|
+
if (!existsSync9(QUEUE_PATH)) return [];
|
|
6380
|
+
return JSON.parse(readFileSync8(QUEUE_PATH, "utf8"));
|
|
6330
6381
|
} catch {
|
|
6331
6382
|
return [];
|
|
6332
6383
|
}
|
|
@@ -6334,7 +6385,7 @@ function readQueue() {
|
|
|
6334
6385
|
function writeQueue(queue) {
|
|
6335
6386
|
ensureDir();
|
|
6336
6387
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
6337
|
-
|
|
6388
|
+
writeFileSync5(tmp, JSON.stringify(queue, null, 2));
|
|
6338
6389
|
renameSync3(tmp, QUEUE_PATH);
|
|
6339
6390
|
}
|
|
6340
6391
|
function queueIntercom(targetSession, reason) {
|
|
@@ -6358,19 +6409,19 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
6358
6409
|
var init_intercom_queue = __esm({
|
|
6359
6410
|
"src/lib/intercom-queue.ts"() {
|
|
6360
6411
|
"use strict";
|
|
6361
|
-
QUEUE_PATH =
|
|
6412
|
+
QUEUE_PATH = path10.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
6362
6413
|
TTL_MS = 60 * 60 * 1e3;
|
|
6363
|
-
INTERCOM_LOG =
|
|
6414
|
+
INTERCOM_LOG = path10.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
6364
6415
|
}
|
|
6365
6416
|
});
|
|
6366
6417
|
|
|
6367
6418
|
// src/lib/plan-limits.ts
|
|
6368
|
-
import { readFileSync as
|
|
6369
|
-
import
|
|
6419
|
+
import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
|
|
6420
|
+
import path11 from "path";
|
|
6370
6421
|
function getLicenseSync() {
|
|
6371
6422
|
try {
|
|
6372
|
-
if (!
|
|
6373
|
-
const raw = JSON.parse(
|
|
6423
|
+
if (!existsSync10(CACHE_PATH2)) return freeLicense();
|
|
6424
|
+
const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
|
|
6374
6425
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
6375
6426
|
const parts = raw.token.split(".");
|
|
6376
6427
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -6408,8 +6459,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
6408
6459
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
6409
6460
|
let count = 0;
|
|
6410
6461
|
try {
|
|
6411
|
-
if (
|
|
6412
|
-
const raw =
|
|
6462
|
+
if (existsSync10(filePath)) {
|
|
6463
|
+
const raw = readFileSync9(filePath, "utf8");
|
|
6413
6464
|
const employees = JSON.parse(raw);
|
|
6414
6465
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
6415
6466
|
}
|
|
@@ -6438,19 +6489,19 @@ var init_plan_limits = __esm({
|
|
|
6438
6489
|
this.name = "PlanLimitError";
|
|
6439
6490
|
}
|
|
6440
6491
|
};
|
|
6441
|
-
CACHE_PATH2 =
|
|
6492
|
+
CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
6442
6493
|
}
|
|
6443
6494
|
});
|
|
6444
6495
|
|
|
6445
6496
|
// src/lib/notifications.ts
|
|
6446
6497
|
import crypto3 from "crypto";
|
|
6447
|
-
import
|
|
6498
|
+
import path12 from "path";
|
|
6448
6499
|
import os7 from "os";
|
|
6449
6500
|
import {
|
|
6450
|
-
readFileSync as
|
|
6501
|
+
readFileSync as readFileSync10,
|
|
6451
6502
|
readdirSync as readdirSync2,
|
|
6452
6503
|
unlinkSync as unlinkSync3,
|
|
6453
|
-
existsSync as
|
|
6504
|
+
existsSync as existsSync11,
|
|
6454
6505
|
rmdirSync
|
|
6455
6506
|
} from "fs";
|
|
6456
6507
|
async function writeNotification(notification) {
|
|
@@ -6554,11 +6605,11 @@ var init_task_scope = __esm({
|
|
|
6554
6605
|
|
|
6555
6606
|
// src/lib/tasks-crud.ts
|
|
6556
6607
|
import crypto5 from "crypto";
|
|
6557
|
-
import
|
|
6608
|
+
import path13 from "path";
|
|
6558
6609
|
import os8 from "os";
|
|
6559
6610
|
import { execSync as execSync4 } from "child_process";
|
|
6560
6611
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
6561
|
-
import { existsSync as
|
|
6612
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
6562
6613
|
async function writeCheckpoint(input) {
|
|
6563
6614
|
const client = getClient();
|
|
6564
6615
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -6733,8 +6784,8 @@ ${laneWarning}` : laneWarning;
|
|
|
6733
6784
|
}
|
|
6734
6785
|
if (input.baseDir) {
|
|
6735
6786
|
try {
|
|
6736
|
-
await mkdir4(
|
|
6737
|
-
await mkdir4(
|
|
6787
|
+
await mkdir4(path13.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
6788
|
+
await mkdir4(path13.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
6738
6789
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
6739
6790
|
await ensureGitignoreExe(input.baseDir);
|
|
6740
6791
|
} catch {
|
|
@@ -6770,10 +6821,10 @@ ${laneWarning}` : laneWarning;
|
|
|
6770
6821
|
});
|
|
6771
6822
|
if (input.baseDir) {
|
|
6772
6823
|
try {
|
|
6773
|
-
const EXE_OS_DIR =
|
|
6774
|
-
const mdPath =
|
|
6775
|
-
const mdDir =
|
|
6776
|
-
if (!
|
|
6824
|
+
const EXE_OS_DIR = path13.join(os8.homedir(), ".exe-os");
|
|
6825
|
+
const mdPath = path13.join(EXE_OS_DIR, taskFile);
|
|
6826
|
+
const mdDir = path13.dirname(mdPath);
|
|
6827
|
+
if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
|
|
6777
6828
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
6778
6829
|
const mdContent = `# ${input.title}
|
|
6779
6830
|
|
|
@@ -6798,7 +6849,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
|
|
|
6798
6849
|
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
6799
6850
|
`;
|
|
6800
6851
|
await writeFile4(mdPath, mdContent, "utf-8");
|
|
6801
|
-
} catch {
|
|
6852
|
+
} catch (err) {
|
|
6853
|
+
process.stderr.write(
|
|
6854
|
+
`[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
|
|
6855
|
+
`
|
|
6856
|
+
);
|
|
6802
6857
|
}
|
|
6803
6858
|
}
|
|
6804
6859
|
return {
|
|
@@ -7058,9 +7113,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
7058
7113
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
7059
7114
|
}
|
|
7060
7115
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
7061
|
-
const archPath =
|
|
7116
|
+
const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
7062
7117
|
try {
|
|
7063
|
-
if (
|
|
7118
|
+
if (existsSync12(archPath)) return;
|
|
7064
7119
|
const template = [
|
|
7065
7120
|
`# ${projectName} \u2014 System Architecture`,
|
|
7066
7121
|
"",
|
|
@@ -7093,10 +7148,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
7093
7148
|
}
|
|
7094
7149
|
}
|
|
7095
7150
|
async function ensureGitignoreExe(baseDir) {
|
|
7096
|
-
const gitignorePath =
|
|
7151
|
+
const gitignorePath = path13.join(baseDir, ".gitignore");
|
|
7097
7152
|
try {
|
|
7098
|
-
if (
|
|
7099
|
-
const content =
|
|
7153
|
+
if (existsSync12(gitignorePath)) {
|
|
7154
|
+
const content = readFileSync11(gitignorePath, "utf-8");
|
|
7100
7155
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
7101
7156
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
7102
7157
|
} else {
|
|
@@ -7127,8 +7182,8 @@ var init_tasks_crud = __esm({
|
|
|
7127
7182
|
});
|
|
7128
7183
|
|
|
7129
7184
|
// src/lib/tasks-review.ts
|
|
7130
|
-
import
|
|
7131
|
-
import { existsSync as
|
|
7185
|
+
import path14 from "path";
|
|
7186
|
+
import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
7132
7187
|
async function countPendingReviews(sessionScope) {
|
|
7133
7188
|
const client = getClient();
|
|
7134
7189
|
if (sessionScope) {
|
|
@@ -7309,11 +7364,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
7309
7364
|
);
|
|
7310
7365
|
}
|
|
7311
7366
|
try {
|
|
7312
|
-
const cacheDir =
|
|
7313
|
-
if (
|
|
7367
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
7368
|
+
if (existsSync13(cacheDir)) {
|
|
7314
7369
|
for (const f of readdirSync3(cacheDir)) {
|
|
7315
7370
|
if (f.startsWith("review-notified-")) {
|
|
7316
|
-
unlinkSync4(
|
|
7371
|
+
unlinkSync4(path14.join(cacheDir, f));
|
|
7317
7372
|
}
|
|
7318
7373
|
}
|
|
7319
7374
|
}
|
|
@@ -7334,7 +7389,7 @@ var init_tasks_review = __esm({
|
|
|
7334
7389
|
});
|
|
7335
7390
|
|
|
7336
7391
|
// src/lib/tasks-chain.ts
|
|
7337
|
-
import
|
|
7392
|
+
import path15 from "path";
|
|
7338
7393
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
7339
7394
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
7340
7395
|
const client = getClient();
|
|
@@ -7351,7 +7406,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
7351
7406
|
});
|
|
7352
7407
|
for (const ur of unblockedRows.rows) {
|
|
7353
7408
|
try {
|
|
7354
|
-
const ubFile =
|
|
7409
|
+
const ubFile = path15.join(baseDir, String(ur.task_file));
|
|
7355
7410
|
let ubContent = await readFile4(ubFile, "utf-8");
|
|
7356
7411
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
7357
7412
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -7420,7 +7475,7 @@ var init_tasks_chain = __esm({
|
|
|
7420
7475
|
|
|
7421
7476
|
// src/lib/project-name.ts
|
|
7422
7477
|
import { execSync as execSync5 } from "child_process";
|
|
7423
|
-
import
|
|
7478
|
+
import path16 from "path";
|
|
7424
7479
|
function getProjectName(cwd) {
|
|
7425
7480
|
const dir = cwd ?? process.cwd();
|
|
7426
7481
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -7433,7 +7488,7 @@ function getProjectName(cwd) {
|
|
|
7433
7488
|
timeout: 2e3,
|
|
7434
7489
|
stdio: ["pipe", "pipe", "pipe"]
|
|
7435
7490
|
}).trim();
|
|
7436
|
-
repoRoot =
|
|
7491
|
+
repoRoot = path16.dirname(gitCommonDir);
|
|
7437
7492
|
} catch {
|
|
7438
7493
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
7439
7494
|
cwd: dir,
|
|
@@ -7442,11 +7497,11 @@ function getProjectName(cwd) {
|
|
|
7442
7497
|
stdio: ["pipe", "pipe", "pipe"]
|
|
7443
7498
|
}).trim();
|
|
7444
7499
|
}
|
|
7445
|
-
_cached2 =
|
|
7500
|
+
_cached2 = path16.basename(repoRoot);
|
|
7446
7501
|
_cachedCwd = dir;
|
|
7447
7502
|
return _cached2;
|
|
7448
7503
|
} catch {
|
|
7449
|
-
_cached2 =
|
|
7504
|
+
_cached2 = path16.basename(dir);
|
|
7450
7505
|
_cachedCwd = dir;
|
|
7451
7506
|
return _cached2;
|
|
7452
7507
|
}
|
|
@@ -7919,8 +7974,8 @@ __export(tasks_exports, {
|
|
|
7919
7974
|
updateTaskStatus: () => updateTaskStatus,
|
|
7920
7975
|
writeCheckpoint: () => writeCheckpoint
|
|
7921
7976
|
});
|
|
7922
|
-
import
|
|
7923
|
-
import { writeFileSync as
|
|
7977
|
+
import path17 from "path";
|
|
7978
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
7924
7979
|
async function createTask(input) {
|
|
7925
7980
|
const result = await createTaskCore(input);
|
|
7926
7981
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -7939,11 +7994,11 @@ async function updateTask(input) {
|
|
|
7939
7994
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
7940
7995
|
try {
|
|
7941
7996
|
const agent = String(row.assigned_to);
|
|
7942
|
-
const cacheDir =
|
|
7943
|
-
const cachePath =
|
|
7997
|
+
const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
|
|
7998
|
+
const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
|
|
7944
7999
|
if (input.status === "in_progress") {
|
|
7945
|
-
|
|
7946
|
-
|
|
8000
|
+
mkdirSync7(cacheDir, { recursive: true });
|
|
8001
|
+
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
7947
8002
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
7948
8003
|
try {
|
|
7949
8004
|
unlinkSync5(cachePath);
|
|
@@ -8410,13 +8465,13 @@ __export(tmux_routing_exports, {
|
|
|
8410
8465
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
8411
8466
|
});
|
|
8412
8467
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
8413
|
-
import { readFileSync as
|
|
8414
|
-
import
|
|
8468
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, existsSync as existsSync14, appendFileSync } from "fs";
|
|
8469
|
+
import path18 from "path";
|
|
8415
8470
|
import os9 from "os";
|
|
8416
8471
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8417
8472
|
import { unlinkSync as unlinkSync6 } from "fs";
|
|
8418
8473
|
function spawnLockPath(sessionName) {
|
|
8419
|
-
return
|
|
8474
|
+
return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
8420
8475
|
}
|
|
8421
8476
|
function isProcessAlive(pid) {
|
|
8422
8477
|
try {
|
|
@@ -8427,13 +8482,13 @@ function isProcessAlive(pid) {
|
|
|
8427
8482
|
}
|
|
8428
8483
|
}
|
|
8429
8484
|
function acquireSpawnLock2(sessionName) {
|
|
8430
|
-
if (!
|
|
8431
|
-
|
|
8485
|
+
if (!existsSync14(SPAWN_LOCK_DIR)) {
|
|
8486
|
+
mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
|
|
8432
8487
|
}
|
|
8433
8488
|
const lockFile = spawnLockPath(sessionName);
|
|
8434
|
-
if (
|
|
8489
|
+
if (existsSync14(lockFile)) {
|
|
8435
8490
|
try {
|
|
8436
|
-
const lock = JSON.parse(
|
|
8491
|
+
const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
|
|
8437
8492
|
const age = Date.now() - lock.timestamp;
|
|
8438
8493
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
8439
8494
|
return false;
|
|
@@ -8441,7 +8496,7 @@ function acquireSpawnLock2(sessionName) {
|
|
|
8441
8496
|
} catch {
|
|
8442
8497
|
}
|
|
8443
8498
|
}
|
|
8444
|
-
|
|
8499
|
+
writeFileSync7(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
8445
8500
|
return true;
|
|
8446
8501
|
}
|
|
8447
8502
|
function releaseSpawnLock2(sessionName) {
|
|
@@ -8453,13 +8508,13 @@ function releaseSpawnLock2(sessionName) {
|
|
|
8453
8508
|
function resolveBehaviorsExporterScript() {
|
|
8454
8509
|
try {
|
|
8455
8510
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
8456
|
-
const scriptPath =
|
|
8457
|
-
|
|
8511
|
+
const scriptPath = path18.join(
|
|
8512
|
+
path18.dirname(thisFile),
|
|
8458
8513
|
"..",
|
|
8459
8514
|
"bin",
|
|
8460
8515
|
"exe-export-behaviors.js"
|
|
8461
8516
|
);
|
|
8462
|
-
return
|
|
8517
|
+
return existsSync14(scriptPath) ? scriptPath : null;
|
|
8463
8518
|
} catch {
|
|
8464
8519
|
return null;
|
|
8465
8520
|
}
|
|
@@ -8525,12 +8580,12 @@ function extractRootExe(name) {
|
|
|
8525
8580
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8526
8581
|
}
|
|
8527
8582
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
8528
|
-
if (!
|
|
8529
|
-
|
|
8583
|
+
if (!existsSync14(SESSION_CACHE)) {
|
|
8584
|
+
mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
8530
8585
|
}
|
|
8531
8586
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
8532
|
-
const filePath =
|
|
8533
|
-
|
|
8587
|
+
const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
8588
|
+
writeFileSync7(filePath, JSON.stringify({
|
|
8534
8589
|
parentExe: rootExe,
|
|
8535
8590
|
dispatchedBy: dispatchedBy || rootExe,
|
|
8536
8591
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -8538,7 +8593,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
8538
8593
|
}
|
|
8539
8594
|
function getParentExe(sessionKey) {
|
|
8540
8595
|
try {
|
|
8541
|
-
const data = JSON.parse(
|
|
8596
|
+
const data = JSON.parse(readFileSync12(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
8542
8597
|
return data.parentExe || null;
|
|
8543
8598
|
} catch {
|
|
8544
8599
|
return null;
|
|
@@ -8546,8 +8601,8 @@ function getParentExe(sessionKey) {
|
|
|
8546
8601
|
}
|
|
8547
8602
|
function getDispatchedBy(sessionKey) {
|
|
8548
8603
|
try {
|
|
8549
|
-
const data = JSON.parse(
|
|
8550
|
-
|
|
8604
|
+
const data = JSON.parse(readFileSync12(
|
|
8605
|
+
path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
8551
8606
|
"utf8"
|
|
8552
8607
|
));
|
|
8553
8608
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -8608,32 +8663,50 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
8608
8663
|
}
|
|
8609
8664
|
function readDebounceState() {
|
|
8610
8665
|
try {
|
|
8611
|
-
if (!
|
|
8612
|
-
|
|
8666
|
+
if (!existsSync14(DEBOUNCE_FILE)) return {};
|
|
8667
|
+
const raw = JSON.parse(readFileSync12(DEBOUNCE_FILE, "utf8"));
|
|
8668
|
+
const state = {};
|
|
8669
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
8670
|
+
if (typeof val === "number") {
|
|
8671
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
8672
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
8673
|
+
state[key] = val;
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8676
|
+
return state;
|
|
8613
8677
|
} catch {
|
|
8614
8678
|
return {};
|
|
8615
8679
|
}
|
|
8616
8680
|
}
|
|
8617
8681
|
function writeDebounceState(state) {
|
|
8618
8682
|
try {
|
|
8619
|
-
if (!
|
|
8620
|
-
|
|
8683
|
+
if (!existsSync14(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
8684
|
+
writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
|
|
8621
8685
|
} catch {
|
|
8622
8686
|
}
|
|
8623
8687
|
}
|
|
8624
8688
|
function isDebounced(targetSession) {
|
|
8625
8689
|
const state = readDebounceState();
|
|
8626
|
-
const
|
|
8627
|
-
|
|
8690
|
+
const entry = state[targetSession];
|
|
8691
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
8692
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
8693
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
8694
|
+
state[targetSession].pending++;
|
|
8695
|
+
writeDebounceState(state);
|
|
8696
|
+
return true;
|
|
8697
|
+
}
|
|
8698
|
+
return false;
|
|
8628
8699
|
}
|
|
8629
8700
|
function recordDebounce(targetSession) {
|
|
8630
8701
|
const state = readDebounceState();
|
|
8631
|
-
state[targetSession]
|
|
8702
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
8703
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
8632
8704
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
8633
8705
|
for (const key of Object.keys(state)) {
|
|
8634
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
8706
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
8635
8707
|
}
|
|
8636
8708
|
writeDebounceState(state);
|
|
8709
|
+
return batched;
|
|
8637
8710
|
}
|
|
8638
8711
|
function logIntercom(msg) {
|
|
8639
8712
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -8678,7 +8751,7 @@ function sendIntercom(targetSession) {
|
|
|
8678
8751
|
return "skipped_exe";
|
|
8679
8752
|
}
|
|
8680
8753
|
if (isDebounced(targetSession)) {
|
|
8681
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
8754
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
8682
8755
|
return "debounced";
|
|
8683
8756
|
}
|
|
8684
8757
|
try {
|
|
@@ -8690,14 +8763,14 @@ function sendIntercom(targetSession) {
|
|
|
8690
8763
|
const sessionState = getSessionState(targetSession);
|
|
8691
8764
|
if (sessionState === "no_claude") {
|
|
8692
8765
|
queueIntercom(targetSession, "claude not running in session");
|
|
8693
|
-
recordDebounce(targetSession);
|
|
8694
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
8766
|
+
const batched2 = recordDebounce(targetSession);
|
|
8767
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
8695
8768
|
return "queued";
|
|
8696
8769
|
}
|
|
8697
8770
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
8698
8771
|
queueIntercom(targetSession, "session busy at send time");
|
|
8699
|
-
recordDebounce(targetSession);
|
|
8700
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
8772
|
+
const batched2 = recordDebounce(targetSession);
|
|
8773
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
8701
8774
|
return "queued";
|
|
8702
8775
|
}
|
|
8703
8776
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -8705,8 +8778,8 @@ function sendIntercom(targetSession) {
|
|
|
8705
8778
|
transport.sendKeys(targetSession, "q");
|
|
8706
8779
|
}
|
|
8707
8780
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
8708
|
-
recordDebounce(targetSession);
|
|
8709
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
8781
|
+
const batched = recordDebounce(targetSession);
|
|
8782
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
8710
8783
|
return "delivered";
|
|
8711
8784
|
} catch {
|
|
8712
8785
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -8808,26 +8881,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8808
8881
|
const transport = getTransport();
|
|
8809
8882
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
8810
8883
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
8811
|
-
const logDir =
|
|
8812
|
-
const logFile =
|
|
8813
|
-
if (!
|
|
8814
|
-
|
|
8884
|
+
const logDir = path18.join(os9.homedir(), ".exe-os", "session-logs");
|
|
8885
|
+
const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
8886
|
+
if (!existsSync14(logDir)) {
|
|
8887
|
+
mkdirSync8(logDir, { recursive: true });
|
|
8815
8888
|
}
|
|
8816
8889
|
transport.kill(sessionName);
|
|
8817
8890
|
let cleanupSuffix = "";
|
|
8818
8891
|
try {
|
|
8819
8892
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
8820
|
-
const cleanupScript =
|
|
8821
|
-
if (
|
|
8893
|
+
const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
8894
|
+
if (existsSync14(cleanupScript)) {
|
|
8822
8895
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
8823
8896
|
}
|
|
8824
8897
|
} catch {
|
|
8825
8898
|
}
|
|
8826
8899
|
try {
|
|
8827
|
-
const claudeJsonPath =
|
|
8900
|
+
const claudeJsonPath = path18.join(os9.homedir(), ".claude.json");
|
|
8828
8901
|
let claudeJson = {};
|
|
8829
8902
|
try {
|
|
8830
|
-
claudeJson = JSON.parse(
|
|
8903
|
+
claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
|
|
8831
8904
|
} catch {
|
|
8832
8905
|
}
|
|
8833
8906
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -8835,17 +8908,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8835
8908
|
const trustDir = opts?.cwd ?? projectDir;
|
|
8836
8909
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
8837
8910
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
8838
|
-
|
|
8911
|
+
writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
8839
8912
|
} catch {
|
|
8840
8913
|
}
|
|
8841
8914
|
try {
|
|
8842
|
-
const settingsDir =
|
|
8915
|
+
const settingsDir = path18.join(os9.homedir(), ".claude", "projects");
|
|
8843
8916
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
8844
|
-
const projSettingsDir =
|
|
8845
|
-
const settingsPath =
|
|
8917
|
+
const projSettingsDir = path18.join(settingsDir, normalizedKey);
|
|
8918
|
+
const settingsPath = path18.join(projSettingsDir, "settings.json");
|
|
8846
8919
|
let settings = {};
|
|
8847
8920
|
try {
|
|
8848
|
-
settings = JSON.parse(
|
|
8921
|
+
settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
|
|
8849
8922
|
} catch {
|
|
8850
8923
|
}
|
|
8851
8924
|
const perms = settings.permissions ?? {};
|
|
@@ -8873,20 +8946,23 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8873
8946
|
if (changed) {
|
|
8874
8947
|
perms.allow = allow;
|
|
8875
8948
|
settings.permissions = perms;
|
|
8876
|
-
|
|
8877
|
-
|
|
8949
|
+
mkdirSync8(projSettingsDir, { recursive: true });
|
|
8950
|
+
writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
8878
8951
|
}
|
|
8879
8952
|
} catch {
|
|
8880
8953
|
}
|
|
8881
8954
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
8882
8955
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
8883
|
-
const
|
|
8956
|
+
const agentRtConfig = getAgentRuntime(employeeName);
|
|
8957
|
+
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
8958
|
+
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
8959
|
+
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
8884
8960
|
const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
|
|
8885
8961
|
let identityFlag = "";
|
|
8886
8962
|
let behaviorsFlag = "";
|
|
8887
8963
|
let legacyFallbackWarned = false;
|
|
8888
8964
|
if (!useExeAgent && !useBinSymlink) {
|
|
8889
|
-
const identityPath =
|
|
8965
|
+
const identityPath = path18.join(
|
|
8890
8966
|
os9.homedir(),
|
|
8891
8967
|
".exe-os",
|
|
8892
8968
|
"identity",
|
|
@@ -8896,13 +8972,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8896
8972
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
8897
8973
|
if (hasAgentFlag) {
|
|
8898
8974
|
identityFlag = ` --agent ${employeeName}`;
|
|
8899
|
-
} else if (
|
|
8975
|
+
} else if (existsSync14(identityPath)) {
|
|
8900
8976
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
8901
8977
|
legacyFallbackWarned = true;
|
|
8902
8978
|
}
|
|
8903
8979
|
const behaviorsFile = exportBehaviorsSync(
|
|
8904
8980
|
employeeName,
|
|
8905
|
-
|
|
8981
|
+
path18.basename(spawnCwd),
|
|
8906
8982
|
sessionName
|
|
8907
8983
|
);
|
|
8908
8984
|
if (behaviorsFile) {
|
|
@@ -8917,16 +8993,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8917
8993
|
}
|
|
8918
8994
|
let sessionContextFlag = "";
|
|
8919
8995
|
try {
|
|
8920
|
-
const ctxDir =
|
|
8921
|
-
|
|
8922
|
-
const ctxFile =
|
|
8996
|
+
const ctxDir = path18.join(os9.homedir(), ".exe-os", "session-cache");
|
|
8997
|
+
mkdirSync8(ctxDir, { recursive: true });
|
|
8998
|
+
const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
|
|
8923
8999
|
const ctxContent = [
|
|
8924
9000
|
`## Session Context`,
|
|
8925
9001
|
`You are running in tmux session: ${sessionName}.`,
|
|
8926
9002
|
`Your parent coordinator session is ${exeSession}.`,
|
|
8927
9003
|
`Your employees (if any) use the -${exeSession} suffix.`
|
|
8928
9004
|
].join("\n");
|
|
8929
|
-
|
|
9005
|
+
writeFileSync7(ctxFile, ctxContent);
|
|
8930
9006
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
8931
9007
|
} catch {
|
|
8932
9008
|
}
|
|
@@ -8940,9 +9016,48 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8940
9016
|
}
|
|
8941
9017
|
}
|
|
8942
9018
|
}
|
|
9019
|
+
if (useCodex) {
|
|
9020
|
+
const codexCfg = RUNTIME_TABLE.codex;
|
|
9021
|
+
if (codexCfg?.apiKeyEnv) {
|
|
9022
|
+
const keyVal = process.env[codexCfg.apiKeyEnv];
|
|
9023
|
+
if (keyVal) {
|
|
9024
|
+
envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
|
|
9025
|
+
}
|
|
9026
|
+
}
|
|
9027
|
+
envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
|
|
9028
|
+
}
|
|
9029
|
+
if (useOpencode) {
|
|
9030
|
+
const ocCfg = PROVIDER_TABLE.opencode;
|
|
9031
|
+
if (ocCfg?.apiKeyEnv) {
|
|
9032
|
+
const keyVal = process.env[ocCfg.apiKeyEnv];
|
|
9033
|
+
if (keyVal) {
|
|
9034
|
+
envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
9038
|
+
}
|
|
9039
|
+
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
9040
|
+
const defaultClaudeModel = DEFAULT_MODELS.claude;
|
|
9041
|
+
if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
|
|
9042
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
8943
9045
|
let spawnCommand;
|
|
8944
9046
|
if (useExeAgent) {
|
|
8945
9047
|
spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
|
|
9048
|
+
} else if (useCodex) {
|
|
9049
|
+
process.stderr.write(
|
|
9050
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
|
|
9051
|
+
`
|
|
9052
|
+
);
|
|
9053
|
+
spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
|
|
9054
|
+
} else if (useOpencode) {
|
|
9055
|
+
const binName = `${employeeName}-opencode`;
|
|
9056
|
+
process.stderr.write(
|
|
9057
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
|
|
9058
|
+
`
|
|
9059
|
+
);
|
|
9060
|
+
spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
|
|
8946
9061
|
} else if (useBinSymlink) {
|
|
8947
9062
|
const binName = `${employeeName}-${ccProvider}`;
|
|
8948
9063
|
process.stderr.write(
|
|
@@ -8964,11 +9079,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8964
9079
|
transport.pipeLog(sessionName, logFile);
|
|
8965
9080
|
try {
|
|
8966
9081
|
const mySession = getMySession();
|
|
8967
|
-
const dispatchInfo =
|
|
8968
|
-
|
|
9082
|
+
const dispatchInfo = path18.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
9083
|
+
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
8969
9084
|
dispatchedBy: mySession,
|
|
8970
9085
|
rootExe: exeSession,
|
|
8971
|
-
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
|
|
9086
|
+
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
9087
|
+
runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
|
|
9088
|
+
model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
|
|
8972
9089
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8973
9090
|
}));
|
|
8974
9091
|
} catch {
|
|
@@ -8986,6 +9103,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8986
9103
|
booted = true;
|
|
8987
9104
|
break;
|
|
8988
9105
|
}
|
|
9106
|
+
} else if (useCodex) {
|
|
9107
|
+
if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
|
|
9108
|
+
booted = true;
|
|
9109
|
+
break;
|
|
9110
|
+
}
|
|
8989
9111
|
} else {
|
|
8990
9112
|
if (pane.includes("Claude Code") || pane.includes("\u276F")) {
|
|
8991
9113
|
booted = true;
|
|
@@ -8997,9 +9119,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8997
9119
|
}
|
|
8998
9120
|
if (!booted) {
|
|
8999
9121
|
releaseSpawnLock2(sessionName);
|
|
9000
|
-
|
|
9122
|
+
const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
|
|
9123
|
+
return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
|
|
9001
9124
|
}
|
|
9002
|
-
if (!useExeAgent) {
|
|
9125
|
+
if (!useExeAgent && !useCodex) {
|
|
9003
9126
|
try {
|
|
9004
9127
|
transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
|
|
9005
9128
|
} catch {
|
|
@@ -9026,17 +9149,19 @@ var init_tmux_routing = __esm({
|
|
|
9026
9149
|
init_cc_agent_support();
|
|
9027
9150
|
init_mcp_prefix();
|
|
9028
9151
|
init_provider_table();
|
|
9152
|
+
init_agent_config();
|
|
9153
|
+
init_runtime_table();
|
|
9029
9154
|
init_intercom_queue();
|
|
9030
9155
|
init_plan_limits();
|
|
9031
9156
|
init_employees();
|
|
9032
|
-
SPAWN_LOCK_DIR =
|
|
9033
|
-
SESSION_CACHE =
|
|
9157
|
+
SPAWN_LOCK_DIR = path18.join(os9.homedir(), ".exe-os", "spawn-locks");
|
|
9158
|
+
SESSION_CACHE = path18.join(os9.homedir(), ".exe-os", "session-cache");
|
|
9034
9159
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
9035
9160
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
9036
9161
|
VERIFY_PANE_LINES = 200;
|
|
9037
9162
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
9038
|
-
INTERCOM_LOG2 =
|
|
9039
|
-
DEBOUNCE_FILE =
|
|
9163
|
+
INTERCOM_LOG2 = path18.join(os9.homedir(), ".exe-os", "intercom.log");
|
|
9164
|
+
DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
|
|
9040
9165
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
9041
9166
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
9042
9167
|
}
|
|
@@ -9294,9 +9419,9 @@ var init_messaging = __esm({
|
|
|
9294
9419
|
});
|
|
9295
9420
|
|
|
9296
9421
|
// src/automation/trigger-engine.ts
|
|
9297
|
-
import { readFileSync as
|
|
9422
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, existsSync as existsSync15, mkdirSync as mkdirSync9 } from "fs";
|
|
9298
9423
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
9299
|
-
import
|
|
9424
|
+
import path19 from "path";
|
|
9300
9425
|
import os10 from "os";
|
|
9301
9426
|
function substituteTemplate(template, record) {
|
|
9302
9427
|
return template.replace(
|
|
@@ -9350,9 +9475,9 @@ function evaluateConditions(conditions, record) {
|
|
|
9350
9475
|
return conditions.every((c) => evaluateCondition(c, record));
|
|
9351
9476
|
}
|
|
9352
9477
|
function loadTriggers(project) {
|
|
9353
|
-
if (!
|
|
9478
|
+
if (!existsSync15(TRIGGERS_PATH)) return [];
|
|
9354
9479
|
try {
|
|
9355
|
-
const raw =
|
|
9480
|
+
const raw = readFileSync13(TRIGGERS_PATH, "utf-8");
|
|
9356
9481
|
const all = JSON.parse(raw);
|
|
9357
9482
|
if (!Array.isArray(all)) return [];
|
|
9358
9483
|
if (project) {
|
|
@@ -9592,7 +9717,7 @@ var TRIGGERS_PATH, GRAPH_API_VERSION;
|
|
|
9592
9717
|
var init_trigger_engine = __esm({
|
|
9593
9718
|
"src/automation/trigger-engine.ts"() {
|
|
9594
9719
|
"use strict";
|
|
9595
|
-
TRIGGERS_PATH =
|
|
9720
|
+
TRIGGERS_PATH = path19.join(os10.homedir(), ".exe-os", "triggers.json");
|
|
9596
9721
|
GRAPH_API_VERSION = "v21.0";
|
|
9597
9722
|
}
|
|
9598
9723
|
});
|
|
@@ -9655,8 +9780,8 @@ var init_crm_webhook = __esm({
|
|
|
9655
9780
|
});
|
|
9656
9781
|
|
|
9657
9782
|
// src/bin/exe-gateway.ts
|
|
9658
|
-
import { existsSync as
|
|
9659
|
-
import
|
|
9783
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
9784
|
+
import path20 from "path";
|
|
9660
9785
|
import os11 from "os";
|
|
9661
9786
|
|
|
9662
9787
|
// src/gateway/webhook-server.ts
|
|
@@ -10623,18 +10748,18 @@ var BotRegistry = class {
|
|
|
10623
10748
|
|
|
10624
10749
|
// src/bin/exe-gateway.ts
|
|
10625
10750
|
init_employees();
|
|
10626
|
-
var CONFIG_DIR =
|
|
10627
|
-
var CONFIG_PATH3 =
|
|
10751
|
+
var CONFIG_DIR = path20.join(os11.homedir(), ".exe-os");
|
|
10752
|
+
var CONFIG_PATH3 = path20.join(CONFIG_DIR, "gateway.json");
|
|
10628
10753
|
var DEFAULT_PORT = 3100;
|
|
10629
10754
|
function loadConfig2() {
|
|
10630
|
-
if (!
|
|
10755
|
+
if (!existsSync16(CONFIG_PATH3)) {
|
|
10631
10756
|
console.log(
|
|
10632
10757
|
`[exe-gateway] No config at ${CONFIG_PATH3} \u2014 using defaults (port ${DEFAULT_PORT})`
|
|
10633
10758
|
);
|
|
10634
10759
|
return {};
|
|
10635
10760
|
}
|
|
10636
10761
|
try {
|
|
10637
|
-
const raw =
|
|
10762
|
+
const raw = readFileSync14(CONFIG_PATH3, "utf-8");
|
|
10638
10763
|
return JSON.parse(raw);
|
|
10639
10764
|
} catch (err) {
|
|
10640
10765
|
console.error(
|