@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
|
@@ -59,34 +59,34 @@ var init_mcp_prefix = __esm({
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
// src/lib/project-name.ts
|
|
62
|
-
import { execSync
|
|
63
|
-
import
|
|
62
|
+
import { execSync } from "child_process";
|
|
63
|
+
import path from "path";
|
|
64
64
|
function getProjectName(cwd) {
|
|
65
65
|
const dir = cwd ?? process.cwd();
|
|
66
66
|
if (_cached && _cachedCwd === dir) return _cached;
|
|
67
67
|
try {
|
|
68
68
|
let repoRoot;
|
|
69
69
|
try {
|
|
70
|
-
const gitCommonDir =
|
|
70
|
+
const gitCommonDir = execSync("git rev-parse --path-format=absolute --git-common-dir", {
|
|
71
71
|
cwd: dir,
|
|
72
72
|
encoding: "utf8",
|
|
73
73
|
timeout: 2e3,
|
|
74
74
|
stdio: ["pipe", "pipe", "pipe"]
|
|
75
75
|
}).trim();
|
|
76
|
-
repoRoot =
|
|
76
|
+
repoRoot = path.dirname(gitCommonDir);
|
|
77
77
|
} catch {
|
|
78
|
-
repoRoot =
|
|
78
|
+
repoRoot = execSync("git rev-parse --show-toplevel", {
|
|
79
79
|
cwd: dir,
|
|
80
80
|
encoding: "utf8",
|
|
81
81
|
timeout: 2e3,
|
|
82
82
|
stdio: ["pipe", "pipe", "pipe"]
|
|
83
83
|
}).trim();
|
|
84
84
|
}
|
|
85
|
-
_cached =
|
|
85
|
+
_cached = path.basename(repoRoot);
|
|
86
86
|
_cachedCwd = dir;
|
|
87
87
|
return _cached;
|
|
88
88
|
} catch {
|
|
89
|
-
_cached =
|
|
89
|
+
_cached = path.basename(dir);
|
|
90
90
|
_cachedCwd = dir;
|
|
91
91
|
return _cached;
|
|
92
92
|
}
|
|
@@ -181,15 +181,15 @@ __export(config_exports, {
|
|
|
181
181
|
saveConfig: () => saveConfig
|
|
182
182
|
});
|
|
183
183
|
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
184
|
-
import { readFileSync
|
|
185
|
-
import
|
|
186
|
-
import
|
|
184
|
+
import { readFileSync, existsSync, renameSync } from "fs";
|
|
185
|
+
import path2 from "path";
|
|
186
|
+
import os from "os";
|
|
187
187
|
function resolveDataDir() {
|
|
188
188
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
189
189
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
190
|
-
const newDir =
|
|
191
|
-
const legacyDir =
|
|
192
|
-
if (!
|
|
190
|
+
const newDir = path2.join(os.homedir(), ".exe-os");
|
|
191
|
+
const legacyDir = path2.join(os.homedir(), ".exe-mem");
|
|
192
|
+
if (!existsSync(newDir) && existsSync(legacyDir)) {
|
|
193
193
|
try {
|
|
194
194
|
renameSync(legacyDir, newDir);
|
|
195
195
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -253,9 +253,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
253
253
|
async function loadConfig() {
|
|
254
254
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
255
255
|
await mkdir(dir, { recursive: true });
|
|
256
|
-
const configPath =
|
|
257
|
-
if (!
|
|
258
|
-
return { ...DEFAULT_CONFIG, dbPath:
|
|
256
|
+
const configPath = path2.join(dir, "config.json");
|
|
257
|
+
if (!existsSync(configPath)) {
|
|
258
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
259
259
|
}
|
|
260
260
|
const raw = await readFile(configPath, "utf-8");
|
|
261
261
|
try {
|
|
@@ -273,38 +273,38 @@ async function loadConfig() {
|
|
|
273
273
|
normalizeScalingRoadmap(migratedCfg);
|
|
274
274
|
normalizeSessionLifecycle(migratedCfg);
|
|
275
275
|
normalizeAutoUpdate(migratedCfg);
|
|
276
|
-
const config = { ...DEFAULT_CONFIG, dbPath:
|
|
276
|
+
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
277
277
|
if (config.dbPath.startsWith("~")) {
|
|
278
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
278
|
+
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
279
279
|
}
|
|
280
280
|
return config;
|
|
281
281
|
} catch {
|
|
282
|
-
return { ...DEFAULT_CONFIG, dbPath:
|
|
282
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
function loadConfigSync() {
|
|
286
286
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
287
|
-
const configPath =
|
|
288
|
-
if (!
|
|
289
|
-
return { ...DEFAULT_CONFIG, dbPath:
|
|
287
|
+
const configPath = path2.join(dir, "config.json");
|
|
288
|
+
if (!existsSync(configPath)) {
|
|
289
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
290
290
|
}
|
|
291
291
|
try {
|
|
292
|
-
const raw =
|
|
292
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
293
293
|
let parsed = JSON.parse(raw);
|
|
294
294
|
parsed = migrateLegacyConfig(parsed);
|
|
295
295
|
const { config: migratedCfg } = migrateConfig(parsed);
|
|
296
296
|
normalizeScalingRoadmap(migratedCfg);
|
|
297
297
|
normalizeSessionLifecycle(migratedCfg);
|
|
298
298
|
normalizeAutoUpdate(migratedCfg);
|
|
299
|
-
return { ...DEFAULT_CONFIG, dbPath:
|
|
299
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
300
300
|
} catch {
|
|
301
|
-
return { ...DEFAULT_CONFIG, dbPath:
|
|
301
|
+
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
async function saveConfig(config) {
|
|
305
305
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
306
306
|
await mkdir(dir, { recursive: true });
|
|
307
|
-
const configPath =
|
|
307
|
+
const configPath = path2.join(dir, "config.json");
|
|
308
308
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
309
309
|
if (config.cloud?.apiKey) {
|
|
310
310
|
await chmod(configPath, 384);
|
|
@@ -329,10 +329,10 @@ var init_config = __esm({
|
|
|
329
329
|
"src/lib/config.ts"() {
|
|
330
330
|
"use strict";
|
|
331
331
|
EXE_AI_DIR = resolveDataDir();
|
|
332
|
-
DB_PATH =
|
|
333
|
-
MODELS_DIR =
|
|
334
|
-
CONFIG_PATH =
|
|
335
|
-
LEGACY_LANCE_PATH =
|
|
332
|
+
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
333
|
+
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
334
|
+
CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
|
|
335
|
+
LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
|
|
336
336
|
CURRENT_CONFIG_VERSION = 1;
|
|
337
337
|
DEFAULT_CONFIG = {
|
|
338
338
|
config_version: CURRENT_CONFIG_VERSION,
|
|
@@ -406,10 +406,10 @@ var init_config = __esm({
|
|
|
406
406
|
|
|
407
407
|
// src/lib/employees.ts
|
|
408
408
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
409
|
-
import { existsSync as
|
|
410
|
-
import { execSync as
|
|
411
|
-
import
|
|
412
|
-
import
|
|
409
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
410
|
+
import { execSync as execSync2 } from "child_process";
|
|
411
|
+
import path3 from "path";
|
|
412
|
+
import os2 from "os";
|
|
413
413
|
function normalizeRole(role) {
|
|
414
414
|
return (role ?? "").trim().toLowerCase();
|
|
415
415
|
}
|
|
@@ -430,9 +430,9 @@ function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
|
430
430
|
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
431
431
|
}
|
|
432
432
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
433
|
-
if (!
|
|
433
|
+
if (!existsSync2(employeesPath)) return [];
|
|
434
434
|
try {
|
|
435
|
-
return JSON.parse(
|
|
435
|
+
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
436
436
|
} catch {
|
|
437
437
|
return [];
|
|
438
438
|
}
|
|
@@ -451,7 +451,7 @@ var init_employees = __esm({
|
|
|
451
451
|
"src/lib/employees.ts"() {
|
|
452
452
|
"use strict";
|
|
453
453
|
init_config();
|
|
454
|
-
EMPLOYEES_PATH =
|
|
454
|
+
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
455
455
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
456
456
|
COORDINATOR_ROLE = "COO";
|
|
457
457
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
@@ -462,8 +462,8 @@ var init_employees = __esm({
|
|
|
462
462
|
import net from "net";
|
|
463
463
|
import { spawn } from "child_process";
|
|
464
464
|
import { randomUUID } from "crypto";
|
|
465
|
-
import { existsSync as
|
|
466
|
-
import
|
|
465
|
+
import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
466
|
+
import path4 from "path";
|
|
467
467
|
import { fileURLToPath } from "url";
|
|
468
468
|
function handleData(chunk) {
|
|
469
469
|
_buffer += chunk.toString();
|
|
@@ -491,9 +491,9 @@ function handleData(chunk) {
|
|
|
491
491
|
}
|
|
492
492
|
}
|
|
493
493
|
function cleanupStaleFiles() {
|
|
494
|
-
if (
|
|
494
|
+
if (existsSync3(PID_PATH)) {
|
|
495
495
|
try {
|
|
496
|
-
const pid = parseInt(
|
|
496
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
497
497
|
if (pid > 0) {
|
|
498
498
|
try {
|
|
499
499
|
process.kill(pid, 0);
|
|
@@ -514,11 +514,11 @@ function cleanupStaleFiles() {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
function findPackageRoot() {
|
|
517
|
-
let dir =
|
|
518
|
-
const { root } =
|
|
517
|
+
let dir = path4.dirname(fileURLToPath(import.meta.url));
|
|
518
|
+
const { root } = path4.parse(dir);
|
|
519
519
|
while (dir !== root) {
|
|
520
|
-
if (
|
|
521
|
-
dir =
|
|
520
|
+
if (existsSync3(path4.join(dir, "package.json"))) return dir;
|
|
521
|
+
dir = path4.dirname(dir);
|
|
522
522
|
}
|
|
523
523
|
return null;
|
|
524
524
|
}
|
|
@@ -528,8 +528,8 @@ function spawnDaemon() {
|
|
|
528
528
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
529
529
|
return;
|
|
530
530
|
}
|
|
531
|
-
const daemonPath =
|
|
532
|
-
if (!
|
|
531
|
+
const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
532
|
+
if (!existsSync3(daemonPath)) {
|
|
533
533
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
534
534
|
`);
|
|
535
535
|
return;
|
|
@@ -537,7 +537,7 @@ function spawnDaemon() {
|
|
|
537
537
|
const resolvedPath = daemonPath;
|
|
538
538
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
539
539
|
`);
|
|
540
|
-
const logPath =
|
|
540
|
+
const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
|
|
541
541
|
let stderrFd = "ignore";
|
|
542
542
|
try {
|
|
543
543
|
stderrFd = openSync(logPath, "a");
|
|
@@ -571,7 +571,7 @@ function acquireSpawnLock() {
|
|
|
571
571
|
return true;
|
|
572
572
|
} catch {
|
|
573
573
|
try {
|
|
574
|
-
const stat =
|
|
574
|
+
const stat = statSync(SPAWN_LOCK_PATH);
|
|
575
575
|
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
576
576
|
try {
|
|
577
577
|
unlinkSync2(SPAWN_LOCK_PATH);
|
|
@@ -687,9 +687,9 @@ async function pingDaemon() {
|
|
|
687
687
|
}
|
|
688
688
|
function killAndRespawnDaemon() {
|
|
689
689
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
690
|
-
if (
|
|
690
|
+
if (existsSync3(PID_PATH)) {
|
|
691
691
|
try {
|
|
692
|
-
const pid = parseInt(
|
|
692
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
693
693
|
if (pid > 0) {
|
|
694
694
|
try {
|
|
695
695
|
process.kill(pid, "SIGKILL");
|
|
@@ -776,9 +776,9 @@ var init_exe_daemon_client = __esm({
|
|
|
776
776
|
"src/lib/exe-daemon-client.ts"() {
|
|
777
777
|
"use strict";
|
|
778
778
|
init_config();
|
|
779
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
780
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
781
|
-
SPAWN_LOCK_PATH =
|
|
779
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
|
|
780
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
|
|
781
|
+
SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
782
782
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
783
783
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
784
784
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -2072,12 +2072,12 @@ __export(shard_manager_exports, {
|
|
|
2072
2072
|
listShards: () => listShards,
|
|
2073
2073
|
shardExists: () => shardExists
|
|
2074
2074
|
});
|
|
2075
|
-
import
|
|
2076
|
-
import { existsSync as
|
|
2075
|
+
import path6 from "path";
|
|
2076
|
+
import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
|
|
2077
2077
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2078
2078
|
function initShardManager(encryptionKey) {
|
|
2079
2079
|
_encryptionKey = encryptionKey;
|
|
2080
|
-
if (!
|
|
2080
|
+
if (!existsSync5(SHARDS_DIR)) {
|
|
2081
2081
|
mkdirSync(SHARDS_DIR, { recursive: true });
|
|
2082
2082
|
}
|
|
2083
2083
|
_shardingEnabled = true;
|
|
@@ -2098,7 +2098,7 @@ function getShardClient(projectName) {
|
|
|
2098
2098
|
}
|
|
2099
2099
|
const cached = _shards.get(safeName);
|
|
2100
2100
|
if (cached) return cached;
|
|
2101
|
-
const dbPath =
|
|
2101
|
+
const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
|
|
2102
2102
|
const client = createClient2({
|
|
2103
2103
|
url: `file:${dbPath}`,
|
|
2104
2104
|
encryptionKey: _encryptionKey
|
|
@@ -2108,11 +2108,11 @@ function getShardClient(projectName) {
|
|
|
2108
2108
|
}
|
|
2109
2109
|
function shardExists(projectName) {
|
|
2110
2110
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2111
|
-
return
|
|
2111
|
+
return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
|
|
2112
2112
|
}
|
|
2113
2113
|
function listShards() {
|
|
2114
|
-
if (!
|
|
2115
|
-
return
|
|
2114
|
+
if (!existsSync5(SHARDS_DIR)) return [];
|
|
2115
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
2116
2116
|
}
|
|
2117
2117
|
async function ensureShardSchema(client) {
|
|
2118
2118
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -2297,7 +2297,7 @@ var init_shard_manager = __esm({
|
|
|
2297
2297
|
"src/lib/shard-manager.ts"() {
|
|
2298
2298
|
"use strict";
|
|
2299
2299
|
init_config();
|
|
2300
|
-
SHARDS_DIR =
|
|
2300
|
+
SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
|
|
2301
2301
|
_shards = /* @__PURE__ */ new Map();
|
|
2302
2302
|
_encryptionKey = null;
|
|
2303
2303
|
_shardingEnabled = false;
|
|
@@ -2487,13 +2487,13 @@ ${p.content}`).join("\n\n");
|
|
|
2487
2487
|
|
|
2488
2488
|
// src/lib/notifications.ts
|
|
2489
2489
|
import crypto2 from "crypto";
|
|
2490
|
-
import
|
|
2491
|
-
import
|
|
2490
|
+
import path7 from "path";
|
|
2491
|
+
import os4 from "os";
|
|
2492
2492
|
import {
|
|
2493
|
-
readFileSync as
|
|
2494
|
-
readdirSync as
|
|
2493
|
+
readFileSync as readFileSync4,
|
|
2494
|
+
readdirSync as readdirSync2,
|
|
2495
2495
|
unlinkSync as unlinkSync3,
|
|
2496
|
-
existsSync as
|
|
2496
|
+
existsSync as existsSync6,
|
|
2497
2497
|
rmdirSync
|
|
2498
2498
|
} from "fs";
|
|
2499
2499
|
async function writeNotification(notification) {
|
|
@@ -2538,9 +2538,9 @@ var init_notifications = __esm({
|
|
|
2538
2538
|
});
|
|
2539
2539
|
|
|
2540
2540
|
// src/lib/license.ts
|
|
2541
|
-
import { readFileSync as
|
|
2541
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
|
|
2542
2542
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2543
|
-
import
|
|
2543
|
+
import path8 from "path";
|
|
2544
2544
|
import { jwtVerify, importSPKI } from "jose";
|
|
2545
2545
|
async function fetchRetry(url, init) {
|
|
2546
2546
|
try {
|
|
@@ -2551,17 +2551,17 @@ async function fetchRetry(url, init) {
|
|
|
2551
2551
|
}
|
|
2552
2552
|
}
|
|
2553
2553
|
function loadDeviceId() {
|
|
2554
|
-
const deviceJsonPath =
|
|
2554
|
+
const deviceJsonPath = path8.join(EXE_AI_DIR, "device.json");
|
|
2555
2555
|
try {
|
|
2556
|
-
if (
|
|
2557
|
-
const data = JSON.parse(
|
|
2556
|
+
if (existsSync7(deviceJsonPath)) {
|
|
2557
|
+
const data = JSON.parse(readFileSync5(deviceJsonPath, "utf8"));
|
|
2558
2558
|
if (data.deviceId) return data.deviceId;
|
|
2559
2559
|
}
|
|
2560
2560
|
} catch {
|
|
2561
2561
|
}
|
|
2562
2562
|
try {
|
|
2563
|
-
if (
|
|
2564
|
-
const id2 =
|
|
2563
|
+
if (existsSync7(DEVICE_ID_PATH)) {
|
|
2564
|
+
const id2 = readFileSync5(DEVICE_ID_PATH, "utf8").trim();
|
|
2565
2565
|
if (id2) return id2;
|
|
2566
2566
|
}
|
|
2567
2567
|
} catch {
|
|
@@ -2573,8 +2573,8 @@ function loadDeviceId() {
|
|
|
2573
2573
|
}
|
|
2574
2574
|
function loadLicense() {
|
|
2575
2575
|
try {
|
|
2576
|
-
if (!
|
|
2577
|
-
return
|
|
2576
|
+
if (!existsSync7(LICENSE_PATH)) return null;
|
|
2577
|
+
return readFileSync5(LICENSE_PATH, "utf8").trim();
|
|
2578
2578
|
} catch {
|
|
2579
2579
|
return null;
|
|
2580
2580
|
}
|
|
@@ -2607,8 +2607,8 @@ async function verifyLicenseJwt(token) {
|
|
|
2607
2607
|
}
|
|
2608
2608
|
async function getCachedLicense() {
|
|
2609
2609
|
try {
|
|
2610
|
-
if (!
|
|
2611
|
-
const raw = JSON.parse(
|
|
2610
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2611
|
+
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2612
2612
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
2613
2613
|
return await verifyLicenseJwt(raw.token);
|
|
2614
2614
|
} catch {
|
|
@@ -2617,8 +2617,8 @@ async function getCachedLicense() {
|
|
|
2617
2617
|
}
|
|
2618
2618
|
function readCachedToken() {
|
|
2619
2619
|
try {
|
|
2620
|
-
if (!
|
|
2621
|
-
const raw = JSON.parse(
|
|
2620
|
+
if (!existsSync7(CACHE_PATH)) return null;
|
|
2621
|
+
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2622
2622
|
return typeof raw.token === "string" ? raw.token : null;
|
|
2623
2623
|
} catch {
|
|
2624
2624
|
return null;
|
|
@@ -2705,8 +2705,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
2705
2705
|
}
|
|
2706
2706
|
function getCacheAgeMs() {
|
|
2707
2707
|
try {
|
|
2708
|
-
const { statSync:
|
|
2709
|
-
const s =
|
|
2708
|
+
const { statSync: statSync2 } = __require("fs");
|
|
2709
|
+
const s = statSync2(CACHE_PATH);
|
|
2710
2710
|
return Date.now() - s.mtimeMs;
|
|
2711
2711
|
} catch {
|
|
2712
2712
|
return Infinity;
|
|
@@ -2716,9 +2716,9 @@ async function checkLicense() {
|
|
|
2716
2716
|
let key = loadLicense();
|
|
2717
2717
|
if (!key) {
|
|
2718
2718
|
try {
|
|
2719
|
-
const configPath =
|
|
2720
|
-
if (
|
|
2721
|
-
const raw = JSON.parse(
|
|
2719
|
+
const configPath = path8.join(EXE_AI_DIR, "config.json");
|
|
2720
|
+
if (existsSync7(configPath)) {
|
|
2721
|
+
const raw = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
2722
2722
|
const cloud = raw.cloud;
|
|
2723
2723
|
if (cloud?.apiKey) {
|
|
2724
2724
|
key = cloud.apiKey;
|
|
@@ -2739,9 +2739,9 @@ var init_license = __esm({
|
|
|
2739
2739
|
"src/lib/license.ts"() {
|
|
2740
2740
|
"use strict";
|
|
2741
2741
|
init_config();
|
|
2742
|
-
LICENSE_PATH =
|
|
2743
|
-
CACHE_PATH =
|
|
2744
|
-
DEVICE_ID_PATH =
|
|
2742
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
2743
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
2744
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
2745
2745
|
API_BASE = "https://askexe.com/cloud";
|
|
2746
2746
|
RETRY_DELAY_MS = 500;
|
|
2747
2747
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -2770,12 +2770,12 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2770
2770
|
});
|
|
2771
2771
|
|
|
2772
2772
|
// src/lib/plan-limits.ts
|
|
2773
|
-
import { readFileSync as
|
|
2774
|
-
import
|
|
2773
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
|
|
2774
|
+
import path9 from "path";
|
|
2775
2775
|
function getLicenseSync() {
|
|
2776
2776
|
try {
|
|
2777
|
-
if (!
|
|
2778
|
-
const raw = JSON.parse(
|
|
2777
|
+
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
2778
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
|
|
2779
2779
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
2780
2780
|
const parts = raw.token.split(".");
|
|
2781
2781
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -2832,8 +2832,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
2832
2832
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
2833
2833
|
let count = 0;
|
|
2834
2834
|
try {
|
|
2835
|
-
if (
|
|
2836
|
-
const raw =
|
|
2835
|
+
if (existsSync8(filePath)) {
|
|
2836
|
+
const raw = readFileSync6(filePath, "utf8");
|
|
2837
2837
|
const employees = JSON.parse(raw);
|
|
2838
2838
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
2839
2839
|
}
|
|
@@ -2862,7 +2862,7 @@ var init_plan_limits = __esm({
|
|
|
2862
2862
|
this.name = "PlanLimitError";
|
|
2863
2863
|
}
|
|
2864
2864
|
};
|
|
2865
|
-
CACHE_PATH2 =
|
|
2865
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
2866
2866
|
}
|
|
2867
2867
|
});
|
|
2868
2868
|
|
|
@@ -2935,12 +2935,12 @@ var init_embedder = __esm({
|
|
|
2935
2935
|
});
|
|
2936
2936
|
|
|
2937
2937
|
// src/lib/session-registry.ts
|
|
2938
|
-
import { readFileSync as
|
|
2939
|
-
import
|
|
2940
|
-
import
|
|
2938
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync9 } from "fs";
|
|
2939
|
+
import path10 from "path";
|
|
2940
|
+
import os5 from "os";
|
|
2941
2941
|
function registerSession(entry) {
|
|
2942
|
-
const dir =
|
|
2943
|
-
if (!
|
|
2942
|
+
const dir = path10.dirname(REGISTRY_PATH);
|
|
2943
|
+
if (!existsSync9(dir)) {
|
|
2944
2944
|
mkdirSync3(dir, { recursive: true });
|
|
2945
2945
|
}
|
|
2946
2946
|
const sessions = listSessions();
|
|
@@ -2954,7 +2954,7 @@ function registerSession(entry) {
|
|
|
2954
2954
|
}
|
|
2955
2955
|
function listSessions() {
|
|
2956
2956
|
try {
|
|
2957
|
-
const raw =
|
|
2957
|
+
const raw = readFileSync7(REGISTRY_PATH, "utf8");
|
|
2958
2958
|
return JSON.parse(raw);
|
|
2959
2959
|
} catch {
|
|
2960
2960
|
return [];
|
|
@@ -2964,18 +2964,18 @@ var REGISTRY_PATH;
|
|
|
2964
2964
|
var init_session_registry = __esm({
|
|
2965
2965
|
"src/lib/session-registry.ts"() {
|
|
2966
2966
|
"use strict";
|
|
2967
|
-
REGISTRY_PATH =
|
|
2967
|
+
REGISTRY_PATH = path10.join(os5.homedir(), ".exe-os", "session-registry.json");
|
|
2968
2968
|
}
|
|
2969
2969
|
});
|
|
2970
2970
|
|
|
2971
2971
|
// src/lib/session-key.ts
|
|
2972
|
-
import { execSync as
|
|
2972
|
+
import { execSync as execSync3 } from "child_process";
|
|
2973
2973
|
function getSessionKey() {
|
|
2974
2974
|
if (_cached2) return _cached2;
|
|
2975
2975
|
let pid = process.ppid;
|
|
2976
2976
|
for (let i = 0; i < 10; i++) {
|
|
2977
2977
|
try {
|
|
2978
|
-
const info =
|
|
2978
|
+
const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
|
|
2979
2979
|
encoding: "utf8",
|
|
2980
2980
|
timeout: 2e3
|
|
2981
2981
|
}).trim();
|
|
@@ -3111,14 +3111,14 @@ var init_transport = __esm({
|
|
|
3111
3111
|
});
|
|
3112
3112
|
|
|
3113
3113
|
// src/lib/cc-agent-support.ts
|
|
3114
|
-
import { execSync as
|
|
3114
|
+
import { execSync as execSync4 } from "child_process";
|
|
3115
3115
|
function _resetCcAgentSupportCache() {
|
|
3116
3116
|
_cachedSupport = null;
|
|
3117
3117
|
}
|
|
3118
3118
|
function claudeSupportsAgentFlag() {
|
|
3119
3119
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
3120
3120
|
try {
|
|
3121
|
-
const helpOutput =
|
|
3121
|
+
const helpOutput = execSync4("claude --help 2>&1", {
|
|
3122
3122
|
encoding: "utf-8",
|
|
3123
3123
|
timeout: 5e3
|
|
3124
3124
|
});
|
|
@@ -3160,13 +3160,64 @@ var init_provider_table = __esm({
|
|
|
3160
3160
|
}
|
|
3161
3161
|
});
|
|
3162
3162
|
|
|
3163
|
+
// src/lib/runtime-table.ts
|
|
3164
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
3165
|
+
var init_runtime_table = __esm({
|
|
3166
|
+
"src/lib/runtime-table.ts"() {
|
|
3167
|
+
"use strict";
|
|
3168
|
+
RUNTIME_TABLE = {
|
|
3169
|
+
codex: {
|
|
3170
|
+
binary: "codex",
|
|
3171
|
+
launchMode: "exec",
|
|
3172
|
+
autoApproveFlag: "--full-auto",
|
|
3173
|
+
inlineFlag: "--no-alt-screen",
|
|
3174
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
3175
|
+
defaultModel: "gpt-5.4"
|
|
3176
|
+
}
|
|
3177
|
+
};
|
|
3178
|
+
DEFAULT_RUNTIME = "claude";
|
|
3179
|
+
}
|
|
3180
|
+
});
|
|
3181
|
+
|
|
3182
|
+
// src/lib/agent-config.ts
|
|
3183
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
|
|
3184
|
+
import path11 from "path";
|
|
3185
|
+
function loadAgentConfig() {
|
|
3186
|
+
if (!existsSync10(AGENT_CONFIG_PATH)) return {};
|
|
3187
|
+
try {
|
|
3188
|
+
return JSON.parse(readFileSync8(AGENT_CONFIG_PATH, "utf-8"));
|
|
3189
|
+
} catch {
|
|
3190
|
+
return {};
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
function getAgentRuntime(agentId) {
|
|
3194
|
+
const config = loadAgentConfig();
|
|
3195
|
+
const entry = config[agentId];
|
|
3196
|
+
if (entry) return entry;
|
|
3197
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
3198
|
+
}
|
|
3199
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
3200
|
+
var init_agent_config = __esm({
|
|
3201
|
+
"src/lib/agent-config.ts"() {
|
|
3202
|
+
"use strict";
|
|
3203
|
+
init_config();
|
|
3204
|
+
init_runtime_table();
|
|
3205
|
+
AGENT_CONFIG_PATH = path11.join(EXE_AI_DIR, "agent-config.json");
|
|
3206
|
+
DEFAULT_MODELS = {
|
|
3207
|
+
claude: "claude-opus-4",
|
|
3208
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
3209
|
+
opencode: "minimax-m2.7"
|
|
3210
|
+
};
|
|
3211
|
+
}
|
|
3212
|
+
});
|
|
3213
|
+
|
|
3163
3214
|
// src/lib/intercom-queue.ts
|
|
3164
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
3215
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
|
|
3165
3216
|
import path12 from "path";
|
|
3166
|
-
import
|
|
3217
|
+
import os6 from "os";
|
|
3167
3218
|
function ensureDir() {
|
|
3168
3219
|
const dir = path12.dirname(QUEUE_PATH);
|
|
3169
|
-
if (!existsSync11(dir))
|
|
3220
|
+
if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
|
|
3170
3221
|
}
|
|
3171
3222
|
function readQueue() {
|
|
3172
3223
|
try {
|
|
@@ -3179,7 +3230,7 @@ function readQueue() {
|
|
|
3179
3230
|
function writeQueue(queue) {
|
|
3180
3231
|
ensureDir();
|
|
3181
3232
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
3182
|
-
|
|
3233
|
+
writeFileSync5(tmp, JSON.stringify(queue, null, 2));
|
|
3183
3234
|
renameSync3(tmp, QUEUE_PATH);
|
|
3184
3235
|
}
|
|
3185
3236
|
function queueIntercom(targetSession, reason) {
|
|
@@ -3203,9 +3254,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
3203
3254
|
var init_intercom_queue = __esm({
|
|
3204
3255
|
"src/lib/intercom-queue.ts"() {
|
|
3205
3256
|
"use strict";
|
|
3206
|
-
QUEUE_PATH = path12.join(
|
|
3257
|
+
QUEUE_PATH = path12.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
3207
3258
|
TTL_MS = 60 * 60 * 1e3;
|
|
3208
|
-
INTERCOM_LOG = path12.join(
|
|
3259
|
+
INTERCOM_LOG = path12.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
3209
3260
|
}
|
|
3210
3261
|
});
|
|
3211
3262
|
|
|
@@ -3552,10 +3603,10 @@ __export(tmux_routing_exports, {
|
|
|
3552
3603
|
spawnEmployee: () => spawnEmployee,
|
|
3553
3604
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
3554
3605
|
});
|
|
3555
|
-
import { execFileSync as execFileSync2, execSync as
|
|
3556
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
3606
|
+
import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
|
|
3607
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
3557
3608
|
import path13 from "path";
|
|
3558
|
-
import
|
|
3609
|
+
import os7 from "os";
|
|
3559
3610
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3560
3611
|
import { unlinkSync as unlinkSync4 } from "fs";
|
|
3561
3612
|
function spawnLockPath(sessionName) {
|
|
@@ -3571,7 +3622,7 @@ function isProcessAlive(pid) {
|
|
|
3571
3622
|
}
|
|
3572
3623
|
function acquireSpawnLock2(sessionName) {
|
|
3573
3624
|
if (!existsSync12(SPAWN_LOCK_DIR)) {
|
|
3574
|
-
|
|
3625
|
+
mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
|
|
3575
3626
|
}
|
|
3576
3627
|
const lockFile = spawnLockPath(sessionName);
|
|
3577
3628
|
if (existsSync12(lockFile)) {
|
|
@@ -3584,7 +3635,7 @@ function acquireSpawnLock2(sessionName) {
|
|
|
3584
3635
|
} catch {
|
|
3585
3636
|
}
|
|
3586
3637
|
}
|
|
3587
|
-
|
|
3638
|
+
writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
3588
3639
|
return true;
|
|
3589
3640
|
}
|
|
3590
3641
|
function releaseSpawnLock2(sessionName) {
|
|
@@ -3669,11 +3720,11 @@ function extractRootExe(name) {
|
|
|
3669
3720
|
}
|
|
3670
3721
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
3671
3722
|
if (!existsSync12(SESSION_CACHE)) {
|
|
3672
|
-
|
|
3723
|
+
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3673
3724
|
}
|
|
3674
3725
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3675
3726
|
const filePath = path13.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3676
|
-
|
|
3727
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3677
3728
|
parentExe: rootExe,
|
|
3678
3729
|
dispatchedBy: dispatchedBy || rootExe,
|
|
3679
3730
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -3752,31 +3803,49 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
3752
3803
|
function readDebounceState() {
|
|
3753
3804
|
try {
|
|
3754
3805
|
if (!existsSync12(DEBOUNCE_FILE)) return {};
|
|
3755
|
-
|
|
3806
|
+
const raw = JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
|
|
3807
|
+
const state = {};
|
|
3808
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
3809
|
+
if (typeof val === "number") {
|
|
3810
|
+
state[key] = { lastSent: val, pending: 0 };
|
|
3811
|
+
} else if (val && typeof val === "object" && "lastSent" in val) {
|
|
3812
|
+
state[key] = val;
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
return state;
|
|
3756
3816
|
} catch {
|
|
3757
3817
|
return {};
|
|
3758
3818
|
}
|
|
3759
3819
|
}
|
|
3760
3820
|
function writeDebounceState(state) {
|
|
3761
3821
|
try {
|
|
3762
|
-
if (!existsSync12(SESSION_CACHE))
|
|
3763
|
-
|
|
3822
|
+
if (!existsSync12(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3823
|
+
writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
|
|
3764
3824
|
} catch {
|
|
3765
3825
|
}
|
|
3766
3826
|
}
|
|
3767
3827
|
function isDebounced(targetSession) {
|
|
3768
3828
|
const state = readDebounceState();
|
|
3769
|
-
const
|
|
3770
|
-
|
|
3829
|
+
const entry = state[targetSession];
|
|
3830
|
+
const lastSent = entry?.lastSent ?? 0;
|
|
3831
|
+
if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
|
|
3832
|
+
if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
|
|
3833
|
+
state[targetSession].pending++;
|
|
3834
|
+
writeDebounceState(state);
|
|
3835
|
+
return true;
|
|
3836
|
+
}
|
|
3837
|
+
return false;
|
|
3771
3838
|
}
|
|
3772
3839
|
function recordDebounce(targetSession) {
|
|
3773
3840
|
const state = readDebounceState();
|
|
3774
|
-
state[targetSession]
|
|
3841
|
+
const batched = state[targetSession]?.pending ?? 0;
|
|
3842
|
+
state[targetSession] = { lastSent: Date.now(), pending: 0 };
|
|
3775
3843
|
const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
|
|
3776
3844
|
for (const key of Object.keys(state)) {
|
|
3777
|
-
if ((state[key] ?? 0) < cutoff) delete state[key];
|
|
3845
|
+
if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
|
|
3778
3846
|
}
|
|
3779
3847
|
writeDebounceState(state);
|
|
3848
|
+
return batched;
|
|
3780
3849
|
}
|
|
3781
3850
|
function logIntercom(msg) {
|
|
3782
3851
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
@@ -3821,7 +3890,7 @@ function sendIntercom(targetSession) {
|
|
|
3821
3890
|
return "skipped_exe";
|
|
3822
3891
|
}
|
|
3823
3892
|
if (isDebounced(targetSession)) {
|
|
3824
|
-
logIntercom(`DEBOUNCE \u2192 ${targetSession} (
|
|
3893
|
+
logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
|
|
3825
3894
|
return "debounced";
|
|
3826
3895
|
}
|
|
3827
3896
|
try {
|
|
@@ -3833,14 +3902,14 @@ function sendIntercom(targetSession) {
|
|
|
3833
3902
|
const sessionState = getSessionState(targetSession);
|
|
3834
3903
|
if (sessionState === "no_claude") {
|
|
3835
3904
|
queueIntercom(targetSession, "claude not running in session");
|
|
3836
|
-
recordDebounce(targetSession);
|
|
3837
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process
|
|
3905
|
+
const batched2 = recordDebounce(targetSession);
|
|
3906
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
3838
3907
|
return "queued";
|
|
3839
3908
|
}
|
|
3840
3909
|
if (sessionState === "thinking" || sessionState === "tool") {
|
|
3841
3910
|
queueIntercom(targetSession, "session busy at send time");
|
|
3842
|
-
recordDebounce(targetSession);
|
|
3843
|
-
logIntercom(`QUEUED \u2192 ${targetSession} (session busy
|
|
3911
|
+
const batched2 = recordDebounce(targetSession);
|
|
3912
|
+
logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
|
|
3844
3913
|
return "queued";
|
|
3845
3914
|
}
|
|
3846
3915
|
if (transport.isPaneInCopyMode(targetSession)) {
|
|
@@ -3848,8 +3917,8 @@ function sendIntercom(targetSession) {
|
|
|
3848
3917
|
transport.sendKeys(targetSession, "q");
|
|
3849
3918
|
}
|
|
3850
3919
|
transport.sendKeys(targetSession, "/exe-intercom");
|
|
3851
|
-
recordDebounce(targetSession);
|
|
3852
|
-
logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
|
|
3920
|
+
const batched = recordDebounce(targetSession);
|
|
3921
|
+
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
3853
3922
|
return "delivered";
|
|
3854
3923
|
} catch {
|
|
3855
3924
|
logIntercom(`FAIL \u2192 ${targetSession}`);
|
|
@@ -3951,10 +4020,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3951
4020
|
const transport = getTransport();
|
|
3952
4021
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3953
4022
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3954
|
-
const logDir = path13.join(
|
|
4023
|
+
const logDir = path13.join(os7.homedir(), ".exe-os", "session-logs");
|
|
3955
4024
|
const logFile = path13.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3956
4025
|
if (!existsSync12(logDir)) {
|
|
3957
|
-
|
|
4026
|
+
mkdirSync6(logDir, { recursive: true });
|
|
3958
4027
|
}
|
|
3959
4028
|
transport.kill(sessionName);
|
|
3960
4029
|
let cleanupSuffix = "";
|
|
@@ -3967,7 +4036,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3967
4036
|
} catch {
|
|
3968
4037
|
}
|
|
3969
4038
|
try {
|
|
3970
|
-
const claudeJsonPath = path13.join(
|
|
4039
|
+
const claudeJsonPath = path13.join(os7.homedir(), ".claude.json");
|
|
3971
4040
|
let claudeJson = {};
|
|
3972
4041
|
try {
|
|
3973
4042
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3978,11 +4047,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3978
4047
|
const trustDir = opts?.cwd ?? projectDir;
|
|
3979
4048
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
3980
4049
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
3981
|
-
|
|
4050
|
+
writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
3982
4051
|
} catch {
|
|
3983
4052
|
}
|
|
3984
4053
|
try {
|
|
3985
|
-
const settingsDir = path13.join(
|
|
4054
|
+
const settingsDir = path13.join(os7.homedir(), ".claude", "projects");
|
|
3986
4055
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3987
4056
|
const projSettingsDir = path13.join(settingsDir, normalizedKey);
|
|
3988
4057
|
const settingsPath = path13.join(projSettingsDir, "settings.json");
|
|
@@ -4016,21 +4085,24 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4016
4085
|
if (changed) {
|
|
4017
4086
|
perms.allow = allow;
|
|
4018
4087
|
settings.permissions = perms;
|
|
4019
|
-
|
|
4020
|
-
|
|
4088
|
+
mkdirSync6(projSettingsDir, { recursive: true });
|
|
4089
|
+
writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
4021
4090
|
}
|
|
4022
4091
|
} catch {
|
|
4023
4092
|
}
|
|
4024
4093
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
4025
4094
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
4026
|
-
const
|
|
4095
|
+
const agentRtConfig = getAgentRuntime(employeeName);
|
|
4096
|
+
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
4097
|
+
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
4098
|
+
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
4027
4099
|
const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
|
|
4028
4100
|
let identityFlag = "";
|
|
4029
4101
|
let behaviorsFlag = "";
|
|
4030
4102
|
let legacyFallbackWarned = false;
|
|
4031
4103
|
if (!useExeAgent && !useBinSymlink) {
|
|
4032
4104
|
const identityPath = path13.join(
|
|
4033
|
-
|
|
4105
|
+
os7.homedir(),
|
|
4034
4106
|
".exe-os",
|
|
4035
4107
|
"identity",
|
|
4036
4108
|
`${employeeName}.md`
|
|
@@ -4060,8 +4132,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4060
4132
|
}
|
|
4061
4133
|
let sessionContextFlag = "";
|
|
4062
4134
|
try {
|
|
4063
|
-
const ctxDir = path13.join(
|
|
4064
|
-
|
|
4135
|
+
const ctxDir = path13.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4136
|
+
mkdirSync6(ctxDir, { recursive: true });
|
|
4065
4137
|
const ctxFile = path13.join(ctxDir, `session-context-${sessionName}.md`);
|
|
4066
4138
|
const ctxContent = [
|
|
4067
4139
|
`## Session Context`,
|
|
@@ -4069,7 +4141,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4069
4141
|
`Your parent coordinator session is ${exeSession}.`,
|
|
4070
4142
|
`Your employees (if any) use the -${exeSession} suffix.`
|
|
4071
4143
|
].join("\n");
|
|
4072
|
-
|
|
4144
|
+
writeFileSync6(ctxFile, ctxContent);
|
|
4073
4145
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
4074
4146
|
} catch {
|
|
4075
4147
|
}
|
|
@@ -4083,9 +4155,48 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4083
4155
|
}
|
|
4084
4156
|
}
|
|
4085
4157
|
}
|
|
4158
|
+
if (useCodex) {
|
|
4159
|
+
const codexCfg = RUNTIME_TABLE.codex;
|
|
4160
|
+
if (codexCfg?.apiKeyEnv) {
|
|
4161
|
+
const keyVal = process.env[codexCfg.apiKeyEnv];
|
|
4162
|
+
if (keyVal) {
|
|
4163
|
+
envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
|
|
4167
|
+
}
|
|
4168
|
+
if (useOpencode) {
|
|
4169
|
+
const ocCfg = PROVIDER_TABLE.opencode;
|
|
4170
|
+
if (ocCfg?.apiKeyEnv) {
|
|
4171
|
+
const keyVal = process.env[ocCfg.apiKeyEnv];
|
|
4172
|
+
if (keyVal) {
|
|
4173
|
+
envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
4177
|
+
}
|
|
4178
|
+
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
4179
|
+
const defaultClaudeModel = DEFAULT_MODELS.claude;
|
|
4180
|
+
if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
|
|
4181
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
|
|
4182
|
+
}
|
|
4183
|
+
}
|
|
4086
4184
|
let spawnCommand;
|
|
4087
4185
|
if (useExeAgent) {
|
|
4088
4186
|
spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
|
|
4187
|
+
} else if (useCodex) {
|
|
4188
|
+
process.stderr.write(
|
|
4189
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
|
|
4190
|
+
`
|
|
4191
|
+
);
|
|
4192
|
+
spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
|
|
4193
|
+
} else if (useOpencode) {
|
|
4194
|
+
const binName = `${employeeName}-opencode`;
|
|
4195
|
+
process.stderr.write(
|
|
4196
|
+
`[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
|
|
4197
|
+
`
|
|
4198
|
+
);
|
|
4199
|
+
spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
|
|
4089
4200
|
} else if (useBinSymlink) {
|
|
4090
4201
|
const binName = `${employeeName}-${ccProvider}`;
|
|
4091
4202
|
process.stderr.write(
|
|
@@ -4108,10 +4219,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4108
4219
|
try {
|
|
4109
4220
|
const mySession = getMySession();
|
|
4110
4221
|
const dispatchInfo = path13.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
4111
|
-
|
|
4222
|
+
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
4112
4223
|
dispatchedBy: mySession,
|
|
4113
4224
|
rootExe: exeSession,
|
|
4114
|
-
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
|
|
4225
|
+
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
4226
|
+
runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
|
|
4227
|
+
model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
|
|
4115
4228
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4116
4229
|
}));
|
|
4117
4230
|
} catch {
|
|
@@ -4119,7 +4232,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4119
4232
|
let booted = false;
|
|
4120
4233
|
for (let i = 0; i < 30; i++) {
|
|
4121
4234
|
try {
|
|
4122
|
-
|
|
4235
|
+
execSync5("sleep 0.5");
|
|
4123
4236
|
} catch {
|
|
4124
4237
|
}
|
|
4125
4238
|
try {
|
|
@@ -4129,6 +4242,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4129
4242
|
booted = true;
|
|
4130
4243
|
break;
|
|
4131
4244
|
}
|
|
4245
|
+
} else if (useCodex) {
|
|
4246
|
+
if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
|
|
4247
|
+
booted = true;
|
|
4248
|
+
break;
|
|
4249
|
+
}
|
|
4132
4250
|
} else {
|
|
4133
4251
|
if (pane.includes("Claude Code") || pane.includes("\u276F")) {
|
|
4134
4252
|
booted = true;
|
|
@@ -4140,9 +4258,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4140
4258
|
}
|
|
4141
4259
|
if (!booted) {
|
|
4142
4260
|
releaseSpawnLock2(sessionName);
|
|
4143
|
-
|
|
4261
|
+
const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
|
|
4262
|
+
return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
|
|
4144
4263
|
}
|
|
4145
|
-
if (!useExeAgent) {
|
|
4264
|
+
if (!useExeAgent && !useCodex) {
|
|
4146
4265
|
try {
|
|
4147
4266
|
transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
|
|
4148
4267
|
} catch {
|
|
@@ -4169,16 +4288,18 @@ var init_tmux_routing = __esm({
|
|
|
4169
4288
|
init_cc_agent_support();
|
|
4170
4289
|
init_mcp_prefix();
|
|
4171
4290
|
init_provider_table();
|
|
4291
|
+
init_agent_config();
|
|
4292
|
+
init_runtime_table();
|
|
4172
4293
|
init_intercom_queue();
|
|
4173
4294
|
init_plan_limits();
|
|
4174
4295
|
init_employees();
|
|
4175
|
-
SPAWN_LOCK_DIR = path13.join(
|
|
4176
|
-
SESSION_CACHE = path13.join(
|
|
4296
|
+
SPAWN_LOCK_DIR = path13.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
4297
|
+
SESSION_CACHE = path13.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4177
4298
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4178
4299
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4179
4300
|
VERIFY_PANE_LINES = 200;
|
|
4180
4301
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4181
|
-
INTERCOM_LOG2 = path13.join(
|
|
4302
|
+
INTERCOM_LOG2 = path13.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
4182
4303
|
DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
|
|
4183
4304
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
4184
4305
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4212,8 +4333,8 @@ var init_task_scope = __esm({
|
|
|
4212
4333
|
// src/lib/tasks-crud.ts
|
|
4213
4334
|
import crypto4 from "crypto";
|
|
4214
4335
|
import path14 from "path";
|
|
4215
|
-
import
|
|
4216
|
-
import { execSync as
|
|
4336
|
+
import os8 from "os";
|
|
4337
|
+
import { execSync as execSync6 } from "child_process";
|
|
4217
4338
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
4218
4339
|
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
4219
4340
|
async function writeCheckpoint(input2) {
|
|
@@ -4427,7 +4548,7 @@ ${laneWarning}` : laneWarning;
|
|
|
4427
4548
|
});
|
|
4428
4549
|
if (input2.baseDir) {
|
|
4429
4550
|
try {
|
|
4430
|
-
const EXE_OS_DIR = path14.join(
|
|
4551
|
+
const EXE_OS_DIR = path14.join(os8.homedir(), ".exe-os");
|
|
4431
4552
|
const mdPath = path14.join(EXE_OS_DIR, taskFile);
|
|
4432
4553
|
const mdDir = path14.dirname(mdPath);
|
|
4433
4554
|
if (!existsSync13(mdDir)) await mkdir4(mdDir, { recursive: true });
|
|
@@ -4455,7 +4576,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
|
|
|
4455
4576
|
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
4456
4577
|
`;
|
|
4457
4578
|
await writeFile4(mdPath, mdContent, "utf-8");
|
|
4458
|
-
} catch {
|
|
4579
|
+
} catch (err) {
|
|
4580
|
+
process.stderr.write(
|
|
4581
|
+
`[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
|
|
4582
|
+
`
|
|
4583
|
+
);
|
|
4459
4584
|
}
|
|
4460
4585
|
}
|
|
4461
4586
|
return {
|
|
@@ -4530,14 +4655,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
4530
4655
|
if (!identifier || identifier === "unknown") return true;
|
|
4531
4656
|
try {
|
|
4532
4657
|
if (identifier.startsWith("%")) {
|
|
4533
|
-
const output =
|
|
4658
|
+
const output = execSync6("tmux list-panes -a -F '#{pane_id}'", {
|
|
4534
4659
|
timeout: 2e3,
|
|
4535
4660
|
encoding: "utf8",
|
|
4536
4661
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4537
4662
|
});
|
|
4538
4663
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
4539
4664
|
} else {
|
|
4540
|
-
|
|
4665
|
+
execSync6(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
4541
4666
|
timeout: 2e3,
|
|
4542
4667
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4543
4668
|
});
|
|
@@ -4546,7 +4671,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
4546
4671
|
} catch {
|
|
4547
4672
|
if (identifier.startsWith("%")) return true;
|
|
4548
4673
|
try {
|
|
4549
|
-
|
|
4674
|
+
execSync6("tmux list-sessions", {
|
|
4550
4675
|
timeout: 2e3,
|
|
4551
4676
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4552
4677
|
});
|
|
@@ -4561,12 +4686,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
4561
4686
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
4562
4687
|
try {
|
|
4563
4688
|
const since = new Date(taskCreatedAt).toISOString();
|
|
4564
|
-
const branch =
|
|
4689
|
+
const branch = execSync6(
|
|
4565
4690
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
4566
4691
|
{ encoding: "utf8", timeout: 3e3 }
|
|
4567
4692
|
).trim();
|
|
4568
4693
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
4569
|
-
const commitCount =
|
|
4694
|
+
const commitCount = execSync6(
|
|
4570
4695
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
4571
4696
|
{ encoding: "utf8", timeout: 5e3 }
|
|
4572
4697
|
).trim();
|
|
@@ -4785,7 +4910,7 @@ var init_tasks_crud = __esm({
|
|
|
4785
4910
|
|
|
4786
4911
|
// src/lib/tasks-review.ts
|
|
4787
4912
|
import path15 from "path";
|
|
4788
|
-
import { existsSync as existsSync14, readdirSync as
|
|
4913
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, unlinkSync as unlinkSync5 } from "fs";
|
|
4789
4914
|
async function countPendingReviews(sessionScope) {
|
|
4790
4915
|
const client = getClient();
|
|
4791
4916
|
if (sessionScope) {
|
|
@@ -4968,7 +5093,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
4968
5093
|
try {
|
|
4969
5094
|
const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
|
|
4970
5095
|
if (existsSync14(cacheDir)) {
|
|
4971
|
-
for (const f of
|
|
5096
|
+
for (const f of readdirSync3(cacheDir)) {
|
|
4972
5097
|
if (f.startsWith("review-notified-")) {
|
|
4973
5098
|
unlinkSync5(path15.join(cacheDir, f));
|
|
4974
5099
|
}
|
|
@@ -5535,7 +5660,7 @@ __export(tasks_exports, {
|
|
|
5535
5660
|
writeCheckpoint: () => writeCheckpoint
|
|
5536
5661
|
});
|
|
5537
5662
|
import path17 from "path";
|
|
5538
|
-
import { writeFileSync as
|
|
5663
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6 } from "fs";
|
|
5539
5664
|
async function createTask(input2) {
|
|
5540
5665
|
const result = await createTaskCore(input2);
|
|
5541
5666
|
if (!input2.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -5557,8 +5682,8 @@ async function updateTask(input2) {
|
|
|
5557
5682
|
const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
|
|
5558
5683
|
const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
|
|
5559
5684
|
if (input2.status === "in_progress") {
|
|
5560
|
-
|
|
5561
|
-
|
|
5685
|
+
mkdirSync7(cacheDir, { recursive: true });
|
|
5686
|
+
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
5562
5687
|
} else if (input2.status === "done" || input2.status === "blocked" || input2.status === "cancelled") {
|
|
5563
5688
|
try {
|
|
5564
5689
|
unlinkSync6(cachePath);
|
|
@@ -5725,15 +5850,15 @@ __export(worker_gate_exports, {
|
|
|
5725
5850
|
tryAcquireBackfillLock: () => tryAcquireBackfillLock,
|
|
5726
5851
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
5727
5852
|
});
|
|
5728
|
-
import { readdirSync as
|
|
5853
|
+
import { readdirSync as readdirSync4, writeFileSync as writeFileSync8, unlinkSync as unlinkSync7, mkdirSync as mkdirSync8, existsSync as existsSync15 } from "fs";
|
|
5729
5854
|
import path18 from "path";
|
|
5730
5855
|
function tryAcquireWorkerSlot() {
|
|
5731
5856
|
try {
|
|
5732
|
-
|
|
5857
|
+
mkdirSync8(WORKER_PID_DIR, { recursive: true });
|
|
5733
5858
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
5734
5859
|
const reservationPath = path18.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
5735
|
-
|
|
5736
|
-
const files =
|
|
5860
|
+
writeFileSync8(reservationPath, String(process.pid));
|
|
5861
|
+
const files = readdirSync4(WORKER_PID_DIR);
|
|
5737
5862
|
let alive = 0;
|
|
5738
5863
|
for (const f of files) {
|
|
5739
5864
|
if (!f.endsWith(".pid")) continue;
|
|
@@ -5772,8 +5897,8 @@ function tryAcquireWorkerSlot() {
|
|
|
5772
5897
|
}
|
|
5773
5898
|
function registerWorkerPid(pid) {
|
|
5774
5899
|
try {
|
|
5775
|
-
|
|
5776
|
-
|
|
5900
|
+
mkdirSync8(WORKER_PID_DIR, { recursive: true });
|
|
5901
|
+
writeFileSync8(path18.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
5777
5902
|
} catch {
|
|
5778
5903
|
}
|
|
5779
5904
|
}
|
|
@@ -5785,7 +5910,7 @@ function cleanupWorkerPid() {
|
|
|
5785
5910
|
}
|
|
5786
5911
|
function tryAcquireBackfillLock() {
|
|
5787
5912
|
try {
|
|
5788
|
-
|
|
5913
|
+
mkdirSync8(WORKER_PID_DIR, { recursive: true });
|
|
5789
5914
|
if (existsSync15(BACKFILL_LOCK)) {
|
|
5790
5915
|
try {
|
|
5791
5916
|
const pid = parseInt(
|
|
@@ -5802,7 +5927,7 @@ function tryAcquireBackfillLock() {
|
|
|
5802
5927
|
} catch {
|
|
5803
5928
|
}
|
|
5804
5929
|
}
|
|
5805
|
-
|
|
5930
|
+
writeFileSync8(BACKFILL_LOCK, String(process.pid));
|
|
5806
5931
|
return true;
|
|
5807
5932
|
} catch {
|
|
5808
5933
|
return true;
|
|
@@ -5827,8 +5952,8 @@ var init_worker_gate = __esm({
|
|
|
5827
5952
|
|
|
5828
5953
|
// src/adapters/claude/hooks/ingest-worker.ts
|
|
5829
5954
|
import crypto7 from "crypto";
|
|
5830
|
-
import { execSync as
|
|
5831
|
-
import { mkdirSync as
|
|
5955
|
+
import { execSync as execSync7 } from "child_process";
|
|
5956
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
5832
5957
|
import path19 from "path";
|
|
5833
5958
|
|
|
5834
5959
|
// src/lib/error-detector.ts
|
|
@@ -5926,10 +6051,6 @@ function detectError(data) {
|
|
|
5926
6051
|
}
|
|
5927
6052
|
|
|
5928
6053
|
// src/lib/task-scanner.ts
|
|
5929
|
-
import { readdirSync, readFileSync, existsSync, statSync } from "fs";
|
|
5930
|
-
import { execSync } from "child_process";
|
|
5931
|
-
import path from "path";
|
|
5932
|
-
import os from "os";
|
|
5933
6054
|
var STATUS_RE = /^\*\*Status:\*\*\s*(\w+)/m;
|
|
5934
6055
|
var TITLE_RE = /^# (.+)/m;
|
|
5935
6056
|
|
|
@@ -5943,16 +6064,16 @@ import { createHash } from "crypto";
|
|
|
5943
6064
|
|
|
5944
6065
|
// src/lib/keychain.ts
|
|
5945
6066
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
5946
|
-
import { existsSync as
|
|
5947
|
-
import
|
|
5948
|
-
import
|
|
6067
|
+
import { existsSync as existsSync4 } from "fs";
|
|
6068
|
+
import path5 from "path";
|
|
6069
|
+
import os3 from "os";
|
|
5949
6070
|
var SERVICE = "exe-mem";
|
|
5950
6071
|
var ACCOUNT = "master-key";
|
|
5951
6072
|
function getKeyDir() {
|
|
5952
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
6073
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os3.homedir(), ".exe-os");
|
|
5953
6074
|
}
|
|
5954
6075
|
function getKeyPath() {
|
|
5955
|
-
return
|
|
6076
|
+
return path5.join(getKeyDir(), "master.key");
|
|
5956
6077
|
}
|
|
5957
6078
|
async function tryKeytar() {
|
|
5958
6079
|
try {
|
|
@@ -5973,9 +6094,9 @@ async function getMasterKey() {
|
|
|
5973
6094
|
}
|
|
5974
6095
|
}
|
|
5975
6096
|
const keyPath = getKeyPath();
|
|
5976
|
-
if (!
|
|
6097
|
+
if (!existsSync4(keyPath)) {
|
|
5977
6098
|
process.stderr.write(
|
|
5978
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
6099
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
5979
6100
|
`
|
|
5980
6101
|
);
|
|
5981
6102
|
return null;
|
|
@@ -6631,7 +6752,7 @@ process.stdin.on("end", async () => {
|
|
|
6631
6752
|
try {
|
|
6632
6753
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6633
6754
|
const flagPath = path19.join(exeDir, "session-cache", "needs-backfill");
|
|
6634
|
-
|
|
6755
|
+
writeFileSync9(flagPath, "1");
|
|
6635
6756
|
} catch (err) {
|
|
6636
6757
|
process.stderr.write(`[ingest-worker] backfill flag write failed: ${err instanceof Error ? err.message : String(err)}
|
|
6637
6758
|
`);
|
|
@@ -6659,9 +6780,9 @@ process.stdin.on("end", async () => {
|
|
|
6659
6780
|
if (status === "done") {
|
|
6660
6781
|
const cwd = data.cwd ?? process.cwd();
|
|
6661
6782
|
try {
|
|
6662
|
-
|
|
6783
|
+
execSync7("git add -u", { cwd, timeout: 1e4, stdio: "ignore" });
|
|
6663
6784
|
const msg = `task(${agentId}): ${title}`;
|
|
6664
|
-
|
|
6785
|
+
execSync7(`git commit --no-verify -m ${JSON.stringify(msg)}`, { cwd, timeout: 3e4, stdio: "ignore" });
|
|
6665
6786
|
} catch (err) {
|
|
6666
6787
|
process.stderr.write(`[ingest-worker] auto-commit failed: ${err instanceof Error ? err.message : String(err)}
|
|
6667
6788
|
`);
|
|
@@ -6742,8 +6863,8 @@ process.stdin.on("end", async () => {
|
|
|
6742
6863
|
}
|
|
6743
6864
|
const cwd = data.cwd ?? process.cwd();
|
|
6744
6865
|
try {
|
|
6745
|
-
|
|
6746
|
-
|
|
6866
|
+
mkdirSync9(path19.join(cwd, "exe/output"), { recursive: true });
|
|
6867
|
+
mkdirSync9(path19.join(cwd, "exe/research"), { recursive: true });
|
|
6747
6868
|
const { ensureGitignoreExe: ensureGitignoreExe2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
6748
6869
|
await ensureGitignoreExe2(cwd);
|
|
6749
6870
|
} catch (err) {
|