@askexenow/exe-os 0.9.6 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +668 -37
- package/dist/bin/cli.js +1399 -607
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +795 -155
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +703 -72
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1064 -273
- package/dist/bin/exe-heartbeat.js +676 -45
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +845 -152
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +668 -37
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +731 -91
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +735 -95
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1038 -247
- package/dist/hooks/bug-report-worker.js +902 -172
- package/dist/hooks/commit-complete.js +729 -89
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +851 -158
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +685 -45
- package/dist/hooks/pre-compact.js +729 -89
- package/dist/hooks/pre-tool-use.js +883 -127
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1071 -321
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +732 -92
- package/dist/hooks/session-start.js +1042 -209
- package/dist/hooks/stop.js +691 -51
- package/dist/hooks/subagent-stop.js +685 -45
- package/dist/hooks/summary-worker.js +827 -134
- package/dist/index.js +1026 -234
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +905 -164
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +66 -30
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +109 -73
- package/dist/lib/tmux-routing.js +98 -62
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1807 -472
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +301 -166
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +206 -40
- package/dist/mcp/tools/send-message.js +69 -33
- package/dist/mcp/tools/update-task.js +86 -50
- package/dist/runtime/index.js +731 -91
- package/dist/tui/App.js +864 -125
- package/package.json +3 -2
|
@@ -272,6 +272,118 @@ var init_config = __esm({
|
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
+
// src/lib/runtime-table.ts
|
|
276
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
277
|
+
var init_runtime_table = __esm({
|
|
278
|
+
"src/lib/runtime-table.ts"() {
|
|
279
|
+
"use strict";
|
|
280
|
+
RUNTIME_TABLE = {
|
|
281
|
+
codex: {
|
|
282
|
+
binary: "codex",
|
|
283
|
+
launchMode: "interactive",
|
|
284
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
285
|
+
inlineFlag: "--no-alt-screen",
|
|
286
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
287
|
+
defaultModel: "gpt-5.4"
|
|
288
|
+
},
|
|
289
|
+
opencode: {
|
|
290
|
+
binary: "opencode",
|
|
291
|
+
launchMode: "exec",
|
|
292
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
293
|
+
inlineFlag: "",
|
|
294
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
295
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
DEFAULT_RUNTIME = "claude";
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// src/lib/agent-config.ts
|
|
303
|
+
var agent_config_exports = {};
|
|
304
|
+
__export(agent_config_exports, {
|
|
305
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
306
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
307
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
308
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
309
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
310
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
311
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
312
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
313
|
+
setAgentRuntime: () => setAgentRuntime
|
|
314
|
+
});
|
|
315
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
316
|
+
import path2 from "path";
|
|
317
|
+
function loadAgentConfig() {
|
|
318
|
+
if (!existsSync2(AGENT_CONFIG_PATH)) return {};
|
|
319
|
+
try {
|
|
320
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
321
|
+
} catch {
|
|
322
|
+
return {};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function saveAgentConfig(config) {
|
|
326
|
+
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
327
|
+
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
|
|
328
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
329
|
+
}
|
|
330
|
+
function getAgentRuntime(agentId) {
|
|
331
|
+
const config = loadAgentConfig();
|
|
332
|
+
const entry = config[agentId];
|
|
333
|
+
if (entry) return entry;
|
|
334
|
+
const orgDefault = config["default"];
|
|
335
|
+
if (orgDefault) return orgDefault;
|
|
336
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
337
|
+
}
|
|
338
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
339
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
340
|
+
if (!knownModels) {
|
|
341
|
+
return {
|
|
342
|
+
ok: false,
|
|
343
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (!knownModels.includes(model)) {
|
|
347
|
+
return {
|
|
348
|
+
ok: false,
|
|
349
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
const config = loadAgentConfig();
|
|
353
|
+
config[agentId] = { runtime, model };
|
|
354
|
+
saveAgentConfig(config);
|
|
355
|
+
return { ok: true };
|
|
356
|
+
}
|
|
357
|
+
function clearAgentRuntime(agentId) {
|
|
358
|
+
const config = loadAgentConfig();
|
|
359
|
+
delete config[agentId];
|
|
360
|
+
saveAgentConfig(config);
|
|
361
|
+
}
|
|
362
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
363
|
+
var init_agent_config = __esm({
|
|
364
|
+
"src/lib/agent-config.ts"() {
|
|
365
|
+
"use strict";
|
|
366
|
+
init_config();
|
|
367
|
+
init_runtime_table();
|
|
368
|
+
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
369
|
+
KNOWN_RUNTIMES = {
|
|
370
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
371
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
372
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
373
|
+
};
|
|
374
|
+
RUNTIME_LABELS = {
|
|
375
|
+
claude: "Claude Code (Anthropic)",
|
|
376
|
+
codex: "Codex (OpenAI)",
|
|
377
|
+
opencode: "OpenCode (open source)"
|
|
378
|
+
};
|
|
379
|
+
DEFAULT_MODELS = {
|
|
380
|
+
claude: "claude-opus-4",
|
|
381
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
382
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
275
387
|
// src/lib/employees.ts
|
|
276
388
|
var employees_exports = {};
|
|
277
389
|
__export(employees_exports, {
|
|
@@ -287,6 +399,7 @@ __export(employees_exports, {
|
|
|
287
399
|
getEmployeeByRole: () => getEmployeeByRole,
|
|
288
400
|
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
289
401
|
hasRole: () => hasRole,
|
|
402
|
+
hireEmployee: () => hireEmployee,
|
|
290
403
|
isCoordinatorName: () => isCoordinatorName,
|
|
291
404
|
isCoordinatorRole: () => isCoordinatorRole,
|
|
292
405
|
isMultiInstance: () => isMultiInstance,
|
|
@@ -299,9 +412,9 @@ __export(employees_exports, {
|
|
|
299
412
|
validateEmployeeName: () => validateEmployeeName
|
|
300
413
|
});
|
|
301
414
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
302
|
-
import { existsSync as
|
|
415
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
303
416
|
import { execSync } from "child_process";
|
|
304
|
-
import
|
|
417
|
+
import path3 from "path";
|
|
305
418
|
import os2 from "os";
|
|
306
419
|
function normalizeRole(role) {
|
|
307
420
|
return (role ?? "").trim().toLowerCase();
|
|
@@ -338,7 +451,7 @@ function validateEmployeeName(name) {
|
|
|
338
451
|
return { valid: true };
|
|
339
452
|
}
|
|
340
453
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
341
|
-
if (!
|
|
454
|
+
if (!existsSync3(employeesPath)) {
|
|
342
455
|
return [];
|
|
343
456
|
}
|
|
344
457
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -349,13 +462,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
349
462
|
}
|
|
350
463
|
}
|
|
351
464
|
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
352
|
-
await mkdir2(
|
|
465
|
+
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
353
466
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
354
467
|
}
|
|
355
468
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
356
|
-
if (!
|
|
469
|
+
if (!existsSync3(employeesPath)) return [];
|
|
357
470
|
try {
|
|
358
|
-
return JSON.parse(
|
|
471
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
359
472
|
} catch {
|
|
360
473
|
return [];
|
|
361
474
|
}
|
|
@@ -397,6 +510,52 @@ function addEmployee(employees, employee) {
|
|
|
397
510
|
}
|
|
398
511
|
return [...employees, normalized];
|
|
399
512
|
}
|
|
513
|
+
function appendToCoordinatorTeam(employee) {
|
|
514
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
515
|
+
if (!coordinator) return;
|
|
516
|
+
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
517
|
+
if (!existsSync3(idPath)) return;
|
|
518
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
519
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
520
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
521
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
522
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
523
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
524
|
+
const entry = `
|
|
525
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
526
|
+
`;
|
|
527
|
+
let updated;
|
|
528
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
529
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
530
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
531
|
+
} else {
|
|
532
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
533
|
+
}
|
|
534
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
535
|
+
}
|
|
536
|
+
function capitalize(s) {
|
|
537
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
538
|
+
}
|
|
539
|
+
async function hireEmployee(employee) {
|
|
540
|
+
const employees = await loadEmployees();
|
|
541
|
+
const updated = addEmployee(employees, employee);
|
|
542
|
+
await saveEmployees(updated);
|
|
543
|
+
try {
|
|
544
|
+
appendToCoordinatorTeam(employee);
|
|
545
|
+
} catch {
|
|
546
|
+
}
|
|
547
|
+
try {
|
|
548
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
549
|
+
const config = loadAgentConfig2();
|
|
550
|
+
const name = employee.name.toLowerCase();
|
|
551
|
+
if (!config[name] && config["default"]) {
|
|
552
|
+
config[name] = { ...config["default"] };
|
|
553
|
+
saveAgentConfig2(config);
|
|
554
|
+
}
|
|
555
|
+
} catch {
|
|
556
|
+
}
|
|
557
|
+
return updated;
|
|
558
|
+
}
|
|
400
559
|
async function normalizeRosterCase(rosterPath) {
|
|
401
560
|
const employees = await loadEmployees(rosterPath);
|
|
402
561
|
let changed = false;
|
|
@@ -406,14 +565,14 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
406
565
|
emp.name = emp.name.toLowerCase();
|
|
407
566
|
changed = true;
|
|
408
567
|
try {
|
|
409
|
-
const identityDir =
|
|
410
|
-
const oldPath =
|
|
411
|
-
const newPath =
|
|
412
|
-
if (
|
|
568
|
+
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
569
|
+
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
570
|
+
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
571
|
+
if (existsSync3(oldPath) && !existsSync3(newPath)) {
|
|
413
572
|
renameSync2(oldPath, newPath);
|
|
414
|
-
} else if (
|
|
415
|
-
const content =
|
|
416
|
-
|
|
573
|
+
} else if (existsSync3(oldPath) && oldPath !== newPath) {
|
|
574
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
575
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
417
576
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
418
577
|
unlinkSync(oldPath);
|
|
419
578
|
}
|
|
@@ -443,7 +602,7 @@ function registerBinSymlinks(name) {
|
|
|
443
602
|
errors.push("Could not find 'exe-os' in PATH");
|
|
444
603
|
return { created, skipped, errors };
|
|
445
604
|
}
|
|
446
|
-
const binDir =
|
|
605
|
+
const binDir = path3.dirname(exeBinPath);
|
|
447
606
|
let target;
|
|
448
607
|
try {
|
|
449
608
|
target = readlinkSync(exeBinPath);
|
|
@@ -453,8 +612,8 @@ function registerBinSymlinks(name) {
|
|
|
453
612
|
}
|
|
454
613
|
for (const suffix of ["", "-opencode"]) {
|
|
455
614
|
const linkName = `${name}${suffix}`;
|
|
456
|
-
const linkPath =
|
|
457
|
-
if (
|
|
615
|
+
const linkPath = path3.join(binDir, linkName);
|
|
616
|
+
if (existsSync3(linkPath)) {
|
|
458
617
|
skipped.push(linkName);
|
|
459
618
|
continue;
|
|
460
619
|
}
|
|
@@ -467,24 +626,50 @@ function registerBinSymlinks(name) {
|
|
|
467
626
|
}
|
|
468
627
|
return { created, skipped, errors };
|
|
469
628
|
}
|
|
470
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
629
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
471
630
|
var init_employees = __esm({
|
|
472
631
|
"src/lib/employees.ts"() {
|
|
473
632
|
"use strict";
|
|
474
633
|
init_config();
|
|
475
|
-
EMPLOYEES_PATH =
|
|
634
|
+
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
476
635
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
477
636
|
COORDINATOR_ROLE = "COO";
|
|
478
637
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
638
|
+
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
639
|
+
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// src/lib/database-adapter.ts
|
|
644
|
+
import os3 from "os";
|
|
645
|
+
import path4 from "path";
|
|
646
|
+
import { createRequire } from "module";
|
|
647
|
+
import { pathToFileURL } from "url";
|
|
648
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
649
|
+
var init_database_adapter = __esm({
|
|
650
|
+
"src/lib/database-adapter.ts"() {
|
|
651
|
+
"use strict";
|
|
652
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
653
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
654
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
655
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
656
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
657
|
+
};
|
|
658
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
659
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
660
|
+
);
|
|
479
661
|
}
|
|
480
662
|
});
|
|
481
663
|
|
|
482
664
|
// src/lib/database.ts
|
|
483
665
|
import { createClient } from "@libsql/client";
|
|
484
666
|
function getClient() {
|
|
485
|
-
if (!
|
|
667
|
+
if (!_adapterClient) {
|
|
486
668
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
487
669
|
}
|
|
670
|
+
if (process.env.DATABASE_URL) {
|
|
671
|
+
return _adapterClient;
|
|
672
|
+
}
|
|
488
673
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
489
674
|
return _resilientClient;
|
|
490
675
|
}
|
|
@@ -493,26 +678,28 @@ function getClient() {
|
|
|
493
678
|
}
|
|
494
679
|
return _resilientClient;
|
|
495
680
|
}
|
|
496
|
-
var _resilientClient, _daemonClient;
|
|
681
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
497
682
|
var init_database = __esm({
|
|
498
683
|
"src/lib/database.ts"() {
|
|
499
684
|
"use strict";
|
|
500
685
|
init_db_retry();
|
|
501
686
|
init_employees();
|
|
687
|
+
init_database_adapter();
|
|
502
688
|
_resilientClient = null;
|
|
503
689
|
_daemonClient = null;
|
|
690
|
+
_adapterClient = null;
|
|
504
691
|
}
|
|
505
692
|
});
|
|
506
693
|
|
|
507
694
|
// src/lib/notifications.ts
|
|
508
695
|
import crypto from "crypto";
|
|
509
|
-
import
|
|
510
|
-
import
|
|
696
|
+
import path5 from "path";
|
|
697
|
+
import os4 from "os";
|
|
511
698
|
import {
|
|
512
|
-
readFileSync as
|
|
699
|
+
readFileSync as readFileSync4,
|
|
513
700
|
readdirSync,
|
|
514
701
|
unlinkSync as unlinkSync2,
|
|
515
|
-
existsSync as
|
|
702
|
+
existsSync as existsSync4,
|
|
516
703
|
rmdirSync
|
|
517
704
|
} from "fs";
|
|
518
705
|
async function writeNotification(notification) {
|
|
@@ -612,13 +799,13 @@ var init_state_bus = __esm({
|
|
|
612
799
|
});
|
|
613
800
|
|
|
614
801
|
// src/lib/session-registry.ts
|
|
615
|
-
import { readFileSync as
|
|
616
|
-
import
|
|
617
|
-
import
|
|
802
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
|
|
803
|
+
import path6 from "path";
|
|
804
|
+
import os5 from "os";
|
|
618
805
|
function registerSession(entry) {
|
|
619
|
-
const dir =
|
|
620
|
-
if (!
|
|
621
|
-
|
|
806
|
+
const dir = path6.dirname(REGISTRY_PATH);
|
|
807
|
+
if (!existsSync5(dir)) {
|
|
808
|
+
mkdirSync2(dir, { recursive: true });
|
|
622
809
|
}
|
|
623
810
|
const sessions = listSessions();
|
|
624
811
|
const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
|
|
@@ -627,11 +814,11 @@ function registerSession(entry) {
|
|
|
627
814
|
} else {
|
|
628
815
|
sessions.push(entry);
|
|
629
816
|
}
|
|
630
|
-
|
|
817
|
+
writeFileSync3(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
631
818
|
}
|
|
632
819
|
function listSessions() {
|
|
633
820
|
try {
|
|
634
|
-
const raw =
|
|
821
|
+
const raw = readFileSync5(REGISTRY_PATH, "utf8");
|
|
635
822
|
return JSON.parse(raw);
|
|
636
823
|
} catch {
|
|
637
824
|
return [];
|
|
@@ -641,7 +828,7 @@ var REGISTRY_PATH;
|
|
|
641
828
|
var init_session_registry = __esm({
|
|
642
829
|
"src/lib/session-registry.ts"() {
|
|
643
830
|
"use strict";
|
|
644
|
-
REGISTRY_PATH =
|
|
831
|
+
REGISTRY_PATH = path6.join(os5.homedir(), ".exe-os", "session-registry.json");
|
|
645
832
|
}
|
|
646
833
|
});
|
|
647
834
|
|
|
@@ -893,67 +1080,6 @@ var init_provider_table = __esm({
|
|
|
893
1080
|
}
|
|
894
1081
|
});
|
|
895
1082
|
|
|
896
|
-
// src/lib/runtime-table.ts
|
|
897
|
-
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
898
|
-
var init_runtime_table = __esm({
|
|
899
|
-
"src/lib/runtime-table.ts"() {
|
|
900
|
-
"use strict";
|
|
901
|
-
RUNTIME_TABLE = {
|
|
902
|
-
codex: {
|
|
903
|
-
binary: "codex",
|
|
904
|
-
launchMode: "interactive",
|
|
905
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
906
|
-
inlineFlag: "--no-alt-screen",
|
|
907
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
908
|
-
defaultModel: "gpt-5.4"
|
|
909
|
-
},
|
|
910
|
-
opencode: {
|
|
911
|
-
binary: "opencode",
|
|
912
|
-
launchMode: "exec",
|
|
913
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
914
|
-
inlineFlag: "",
|
|
915
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
916
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
DEFAULT_RUNTIME = "claude";
|
|
920
|
-
}
|
|
921
|
-
});
|
|
922
|
-
|
|
923
|
-
// src/lib/agent-config.ts
|
|
924
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
925
|
-
import path5 from "path";
|
|
926
|
-
function loadAgentConfig() {
|
|
927
|
-
if (!existsSync5(AGENT_CONFIG_PATH)) return {};
|
|
928
|
-
try {
|
|
929
|
-
return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
|
|
930
|
-
} catch {
|
|
931
|
-
return {};
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
function getAgentRuntime(agentId) {
|
|
935
|
-
const config = loadAgentConfig();
|
|
936
|
-
const entry = config[agentId];
|
|
937
|
-
if (entry) return entry;
|
|
938
|
-
const orgDefault = config["default"];
|
|
939
|
-
if (orgDefault) return orgDefault;
|
|
940
|
-
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
941
|
-
}
|
|
942
|
-
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
943
|
-
var init_agent_config = __esm({
|
|
944
|
-
"src/lib/agent-config.ts"() {
|
|
945
|
-
"use strict";
|
|
946
|
-
init_config();
|
|
947
|
-
init_runtime_table();
|
|
948
|
-
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
949
|
-
DEFAULT_MODELS = {
|
|
950
|
-
claude: "claude-opus-4",
|
|
951
|
-
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
952
|
-
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
|
|
957
1083
|
// src/lib/intercom-queue.ts
|
|
958
1084
|
var intercom_queue_exports = {};
|
|
959
1085
|
__export(intercom_queue_exports, {
|
|
@@ -964,10 +1090,10 @@ __export(intercom_queue_exports, {
|
|
|
964
1090
|
readQueue: () => readQueue
|
|
965
1091
|
});
|
|
966
1092
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
967
|
-
import
|
|
968
|
-
import
|
|
1093
|
+
import path7 from "path";
|
|
1094
|
+
import os6 from "os";
|
|
969
1095
|
function ensureDir() {
|
|
970
|
-
const dir =
|
|
1096
|
+
const dir = path7.dirname(QUEUE_PATH);
|
|
971
1097
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
972
1098
|
}
|
|
973
1099
|
function readQueue() {
|
|
@@ -1073,26 +1199,26 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
|
1073
1199
|
var init_intercom_queue = __esm({
|
|
1074
1200
|
"src/lib/intercom-queue.ts"() {
|
|
1075
1201
|
"use strict";
|
|
1076
|
-
QUEUE_PATH =
|
|
1202
|
+
QUEUE_PATH = path7.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
1077
1203
|
MAX_RETRIES = 5;
|
|
1078
1204
|
TTL_MS = 60 * 60 * 1e3;
|
|
1079
|
-
INTERCOM_LOG =
|
|
1205
|
+
INTERCOM_LOG = path7.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
1080
1206
|
}
|
|
1081
1207
|
});
|
|
1082
1208
|
|
|
1083
1209
|
// src/lib/license.ts
|
|
1084
1210
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
1085
1211
|
import { randomUUID } from "crypto";
|
|
1086
|
-
import
|
|
1212
|
+
import path8 from "path";
|
|
1087
1213
|
import { jwtVerify, importSPKI } from "jose";
|
|
1088
1214
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
1089
1215
|
var init_license = __esm({
|
|
1090
1216
|
"src/lib/license.ts"() {
|
|
1091
1217
|
"use strict";
|
|
1092
1218
|
init_config();
|
|
1093
|
-
LICENSE_PATH =
|
|
1094
|
-
CACHE_PATH =
|
|
1095
|
-
DEVICE_ID_PATH =
|
|
1219
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
1220
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1221
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
1096
1222
|
PLAN_LIMITS = {
|
|
1097
1223
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
1098
1224
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -1105,7 +1231,7 @@ var init_license = __esm({
|
|
|
1105
1231
|
|
|
1106
1232
|
// src/lib/plan-limits.ts
|
|
1107
1233
|
import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
|
|
1108
|
-
import
|
|
1234
|
+
import path9 from "path";
|
|
1109
1235
|
function getLicenseSync() {
|
|
1110
1236
|
try {
|
|
1111
1237
|
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
@@ -1177,7 +1303,7 @@ var init_plan_limits = __esm({
|
|
|
1177
1303
|
this.name = "PlanLimitError";
|
|
1178
1304
|
}
|
|
1179
1305
|
};
|
|
1180
|
-
CACHE_PATH2 =
|
|
1306
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
1181
1307
|
}
|
|
1182
1308
|
});
|
|
1183
1309
|
|
|
@@ -1526,12 +1652,12 @@ __export(tmux_routing_exports, {
|
|
|
1526
1652
|
});
|
|
1527
1653
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
1528
1654
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync9, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
1529
|
-
import
|
|
1530
|
-
import
|
|
1655
|
+
import path10 from "path";
|
|
1656
|
+
import os7 from "os";
|
|
1531
1657
|
import { fileURLToPath } from "url";
|
|
1532
1658
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
1533
1659
|
function spawnLockPath(sessionName) {
|
|
1534
|
-
return
|
|
1660
|
+
return path10.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
1535
1661
|
}
|
|
1536
1662
|
function isProcessAlive(pid) {
|
|
1537
1663
|
try {
|
|
@@ -1568,8 +1694,8 @@ function releaseSpawnLock(sessionName) {
|
|
|
1568
1694
|
function resolveBehaviorsExporterScript() {
|
|
1569
1695
|
try {
|
|
1570
1696
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1571
|
-
const scriptPath =
|
|
1572
|
-
|
|
1697
|
+
const scriptPath = path10.join(
|
|
1698
|
+
path10.dirname(thisFile),
|
|
1573
1699
|
"..",
|
|
1574
1700
|
"bin",
|
|
1575
1701
|
"exe-export-behaviors.js"
|
|
@@ -1644,7 +1770,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1644
1770
|
mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
1645
1771
|
}
|
|
1646
1772
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
1647
|
-
const filePath =
|
|
1773
|
+
const filePath = path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
1648
1774
|
writeFileSync6(filePath, JSON.stringify({
|
|
1649
1775
|
parentExe: rootExe,
|
|
1650
1776
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -1653,7 +1779,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1653
1779
|
}
|
|
1654
1780
|
function getParentExe(sessionKey) {
|
|
1655
1781
|
try {
|
|
1656
|
-
const data = JSON.parse(readFileSync9(
|
|
1782
|
+
const data = JSON.parse(readFileSync9(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1657
1783
|
return data.parentExe || null;
|
|
1658
1784
|
} catch {
|
|
1659
1785
|
return null;
|
|
@@ -1662,7 +1788,7 @@ function getParentExe(sessionKey) {
|
|
|
1662
1788
|
function getDispatchedBy(sessionKey) {
|
|
1663
1789
|
try {
|
|
1664
1790
|
const data = JSON.parse(readFileSync9(
|
|
1665
|
-
|
|
1791
|
+
path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
1666
1792
|
"utf8"
|
|
1667
1793
|
));
|
|
1668
1794
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -1673,15 +1799,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
1673
1799
|
function resolveExeSession() {
|
|
1674
1800
|
const mySession = getMySession();
|
|
1675
1801
|
if (!mySession) return null;
|
|
1802
|
+
const fromSessionName = extractRootExe(mySession);
|
|
1676
1803
|
try {
|
|
1677
1804
|
const key = getSessionKey();
|
|
1678
1805
|
const parentExe = getParentExe(key);
|
|
1679
1806
|
if (parentExe) {
|
|
1680
|
-
|
|
1807
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
1808
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
1809
|
+
process.stderr.write(
|
|
1810
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
1811
|
+
`
|
|
1812
|
+
);
|
|
1813
|
+
return fromSessionName;
|
|
1814
|
+
}
|
|
1815
|
+
return fromCache;
|
|
1681
1816
|
}
|
|
1682
1817
|
} catch {
|
|
1683
1818
|
}
|
|
1684
|
-
return
|
|
1819
|
+
return fromSessionName ?? mySession;
|
|
1685
1820
|
}
|
|
1686
1821
|
function isEmployeeAlive(sessionName) {
|
|
1687
1822
|
return getTransport().isAlive(sessionName);
|
|
@@ -1839,7 +1974,7 @@ function sendIntercom(targetSession) {
|
|
|
1839
1974
|
try {
|
|
1840
1975
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1841
1976
|
const agent = baseAgentName(rawAgent);
|
|
1842
|
-
const markerPath =
|
|
1977
|
+
const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
1843
1978
|
if (existsSync9(markerPath)) {
|
|
1844
1979
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
1845
1980
|
return "debounced";
|
|
@@ -1849,7 +1984,7 @@ function sendIntercom(targetSession) {
|
|
|
1849
1984
|
try {
|
|
1850
1985
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1851
1986
|
const agent = baseAgentName(rawAgent);
|
|
1852
|
-
const taskDir =
|
|
1987
|
+
const taskDir = path10.join(process.cwd(), "exe", agent);
|
|
1853
1988
|
if (existsSync9(taskDir)) {
|
|
1854
1989
|
const files = readdirSync2(taskDir).filter(
|
|
1855
1990
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -1983,8 +2118,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1983
2118
|
const transport = getTransport();
|
|
1984
2119
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
1985
2120
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
1986
|
-
const logDir =
|
|
1987
|
-
const logFile =
|
|
2121
|
+
const logDir = path10.join(os7.homedir(), ".exe-os", "session-logs");
|
|
2122
|
+
const logFile = path10.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
1988
2123
|
if (!existsSync9(logDir)) {
|
|
1989
2124
|
mkdirSync5(logDir, { recursive: true });
|
|
1990
2125
|
}
|
|
@@ -1992,14 +2127,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1992
2127
|
let cleanupSuffix = "";
|
|
1993
2128
|
try {
|
|
1994
2129
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1995
|
-
const cleanupScript =
|
|
2130
|
+
const cleanupScript = path10.join(path10.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
1996
2131
|
if (existsSync9(cleanupScript)) {
|
|
1997
2132
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
1998
2133
|
}
|
|
1999
2134
|
} catch {
|
|
2000
2135
|
}
|
|
2001
2136
|
try {
|
|
2002
|
-
const claudeJsonPath =
|
|
2137
|
+
const claudeJsonPath = path10.join(os7.homedir(), ".claude.json");
|
|
2003
2138
|
let claudeJson = {};
|
|
2004
2139
|
try {
|
|
2005
2140
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -2014,10 +2149,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2014
2149
|
} catch {
|
|
2015
2150
|
}
|
|
2016
2151
|
try {
|
|
2017
|
-
const settingsDir =
|
|
2152
|
+
const settingsDir = path10.join(os7.homedir(), ".claude", "projects");
|
|
2018
2153
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
2019
|
-
const projSettingsDir =
|
|
2020
|
-
const settingsPath =
|
|
2154
|
+
const projSettingsDir = path10.join(settingsDir, normalizedKey);
|
|
2155
|
+
const settingsPath = path10.join(projSettingsDir, "settings.json");
|
|
2021
2156
|
let settings = {};
|
|
2022
2157
|
try {
|
|
2023
2158
|
settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
|
|
@@ -2064,8 +2199,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2064
2199
|
let behaviorsFlag = "";
|
|
2065
2200
|
let legacyFallbackWarned = false;
|
|
2066
2201
|
if (!useExeAgent && !useBinSymlink) {
|
|
2067
|
-
const identityPath2 =
|
|
2068
|
-
|
|
2202
|
+
const identityPath2 = path10.join(
|
|
2203
|
+
os7.homedir(),
|
|
2069
2204
|
".exe-os",
|
|
2070
2205
|
"identity",
|
|
2071
2206
|
`${employeeName}.md`
|
|
@@ -2080,7 +2215,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2080
2215
|
}
|
|
2081
2216
|
const behaviorsFile = exportBehaviorsSync(
|
|
2082
2217
|
employeeName,
|
|
2083
|
-
|
|
2218
|
+
path10.basename(spawnCwd),
|
|
2084
2219
|
sessionName
|
|
2085
2220
|
);
|
|
2086
2221
|
if (behaviorsFile) {
|
|
@@ -2095,9 +2230,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2095
2230
|
}
|
|
2096
2231
|
let sessionContextFlag = "";
|
|
2097
2232
|
try {
|
|
2098
|
-
const ctxDir =
|
|
2233
|
+
const ctxDir = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2099
2234
|
mkdirSync5(ctxDir, { recursive: true });
|
|
2100
|
-
const ctxFile =
|
|
2235
|
+
const ctxFile = path10.join(ctxDir, `session-context-${sessionName}.md`);
|
|
2101
2236
|
const ctxContent = [
|
|
2102
2237
|
`## Session Context`,
|
|
2103
2238
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -2181,7 +2316,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2181
2316
|
transport.pipeLog(sessionName, logFile);
|
|
2182
2317
|
try {
|
|
2183
2318
|
const mySession = getMySession();
|
|
2184
|
-
const dispatchInfo =
|
|
2319
|
+
const dispatchInfo = path10.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
2185
2320
|
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
2186
2321
|
dispatchedBy: mySession,
|
|
2187
2322
|
rootExe: exeSession,
|
|
@@ -2256,15 +2391,15 @@ var init_tmux_routing = __esm({
|
|
|
2256
2391
|
init_intercom_queue();
|
|
2257
2392
|
init_plan_limits();
|
|
2258
2393
|
init_employees();
|
|
2259
|
-
SPAWN_LOCK_DIR =
|
|
2260
|
-
SESSION_CACHE =
|
|
2394
|
+
SPAWN_LOCK_DIR = path10.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
2395
|
+
SESSION_CACHE = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2261
2396
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
2262
2397
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
2263
2398
|
VERIFY_PANE_LINES = 200;
|
|
2264
2399
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2265
2400
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
2266
|
-
INTERCOM_LOG2 =
|
|
2267
|
-
DEBOUNCE_FILE =
|
|
2401
|
+
INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
2402
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2268
2403
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2269
2404
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
2270
2405
|
}
|
|
@@ -2296,8 +2431,8 @@ var init_task_scope = __esm({
|
|
|
2296
2431
|
|
|
2297
2432
|
// src/lib/tasks-crud.ts
|
|
2298
2433
|
import crypto3 from "crypto";
|
|
2299
|
-
import
|
|
2300
|
-
import
|
|
2434
|
+
import path11 from "path";
|
|
2435
|
+
import os8 from "os";
|
|
2301
2436
|
import { execSync as execSync5 } from "child_process";
|
|
2302
2437
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2303
2438
|
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
@@ -2475,8 +2610,8 @@ ${laneWarning}` : laneWarning;
|
|
|
2475
2610
|
}
|
|
2476
2611
|
if (input.baseDir) {
|
|
2477
2612
|
try {
|
|
2478
|
-
await mkdir3(
|
|
2479
|
-
await mkdir3(
|
|
2613
|
+
await mkdir3(path11.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
2614
|
+
await mkdir3(path11.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
2480
2615
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
2481
2616
|
await ensureGitignoreExe(input.baseDir);
|
|
2482
2617
|
} catch {
|
|
@@ -2512,9 +2647,9 @@ ${laneWarning}` : laneWarning;
|
|
|
2512
2647
|
});
|
|
2513
2648
|
if (input.baseDir) {
|
|
2514
2649
|
try {
|
|
2515
|
-
const EXE_OS_DIR =
|
|
2516
|
-
const mdPath =
|
|
2517
|
-
const mdDir =
|
|
2650
|
+
const EXE_OS_DIR = path11.join(os8.homedir(), ".exe-os");
|
|
2651
|
+
const mdPath = path11.join(EXE_OS_DIR, taskFile);
|
|
2652
|
+
const mdDir = path11.dirname(mdPath);
|
|
2518
2653
|
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
2519
2654
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
2520
2655
|
const mdContent = `# ${input.title}
|
|
@@ -2815,7 +2950,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2815
2950
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
2816
2951
|
}
|
|
2817
2952
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2818
|
-
const archPath =
|
|
2953
|
+
const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2819
2954
|
try {
|
|
2820
2955
|
if (existsSync10(archPath)) return;
|
|
2821
2956
|
const template = [
|
|
@@ -2850,7 +2985,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2850
2985
|
}
|
|
2851
2986
|
}
|
|
2852
2987
|
async function ensureGitignoreExe(baseDir) {
|
|
2853
|
-
const gitignorePath =
|
|
2988
|
+
const gitignorePath = path11.join(baseDir, ".gitignore");
|
|
2854
2989
|
try {
|
|
2855
2990
|
if (existsSync10(gitignorePath)) {
|
|
2856
2991
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
@@ -2884,13 +3019,13 @@ var init_tasks_crud = __esm({
|
|
|
2884
3019
|
});
|
|
2885
3020
|
|
|
2886
3021
|
// src/lib/tasks-review.ts
|
|
2887
|
-
import
|
|
3022
|
+
import path12 from "path";
|
|
2888
3023
|
import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
2889
3024
|
async function countPendingReviews(sessionScope) {
|
|
2890
3025
|
const client = getClient();
|
|
2891
3026
|
if (sessionScope) {
|
|
2892
3027
|
const result2 = await client.execute({
|
|
2893
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
3028
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
2894
3029
|
args: [sessionScope]
|
|
2895
3030
|
});
|
|
2896
3031
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -3066,11 +3201,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3066
3201
|
);
|
|
3067
3202
|
}
|
|
3068
3203
|
try {
|
|
3069
|
-
const cacheDir =
|
|
3204
|
+
const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
|
|
3070
3205
|
if (existsSync11(cacheDir)) {
|
|
3071
3206
|
for (const f of readdirSync3(cacheDir)) {
|
|
3072
3207
|
if (f.startsWith("review-notified-")) {
|
|
3073
|
-
unlinkSync4(
|
|
3208
|
+
unlinkSync4(path12.join(cacheDir, f));
|
|
3074
3209
|
}
|
|
3075
3210
|
}
|
|
3076
3211
|
}
|
|
@@ -3091,7 +3226,7 @@ var init_tasks_review = __esm({
|
|
|
3091
3226
|
});
|
|
3092
3227
|
|
|
3093
3228
|
// src/lib/tasks-chain.ts
|
|
3094
|
-
import
|
|
3229
|
+
import path13 from "path";
|
|
3095
3230
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
3096
3231
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
3097
3232
|
const client = getClient();
|
|
@@ -3108,7 +3243,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
3108
3243
|
});
|
|
3109
3244
|
for (const ur of unblockedRows.rows) {
|
|
3110
3245
|
try {
|
|
3111
|
-
const ubFile =
|
|
3246
|
+
const ubFile = path13.join(baseDir, String(ur.task_file));
|
|
3112
3247
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
3113
3248
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
3114
3249
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -3177,7 +3312,7 @@ var init_tasks_chain = __esm({
|
|
|
3177
3312
|
|
|
3178
3313
|
// src/lib/project-name.ts
|
|
3179
3314
|
import { execSync as execSync6 } from "child_process";
|
|
3180
|
-
import
|
|
3315
|
+
import path14 from "path";
|
|
3181
3316
|
function getProjectName(cwd) {
|
|
3182
3317
|
const dir = cwd ?? process.cwd();
|
|
3183
3318
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -3190,7 +3325,7 @@ function getProjectName(cwd) {
|
|
|
3190
3325
|
timeout: 2e3,
|
|
3191
3326
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3192
3327
|
}).trim();
|
|
3193
|
-
repoRoot =
|
|
3328
|
+
repoRoot = path14.dirname(gitCommonDir);
|
|
3194
3329
|
} catch {
|
|
3195
3330
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
3196
3331
|
cwd: dir,
|
|
@@ -3199,11 +3334,11 @@ function getProjectName(cwd) {
|
|
|
3199
3334
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3200
3335
|
}).trim();
|
|
3201
3336
|
}
|
|
3202
|
-
_cached2 =
|
|
3337
|
+
_cached2 = path14.basename(repoRoot);
|
|
3203
3338
|
_cachedCwd = dir;
|
|
3204
3339
|
return _cached2;
|
|
3205
3340
|
} catch {
|
|
3206
|
-
_cached2 =
|
|
3341
|
+
_cached2 = path14.basename(dir);
|
|
3207
3342
|
_cachedCwd = dir;
|
|
3208
3343
|
return _cached2;
|
|
3209
3344
|
}
|
|
@@ -3676,7 +3811,7 @@ __export(tasks_exports, {
|
|
|
3676
3811
|
updateTaskStatus: () => updateTaskStatus,
|
|
3677
3812
|
writeCheckpoint: () => writeCheckpoint
|
|
3678
3813
|
});
|
|
3679
|
-
import
|
|
3814
|
+
import path15 from "path";
|
|
3680
3815
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
3681
3816
|
async function createTask(input) {
|
|
3682
3817
|
const result = await createTaskCore(input);
|
|
@@ -3696,8 +3831,8 @@ async function updateTask(input) {
|
|
|
3696
3831
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
3697
3832
|
try {
|
|
3698
3833
|
const agent = String(row.assigned_to);
|
|
3699
|
-
const cacheDir =
|
|
3700
|
-
const cachePath =
|
|
3834
|
+
const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
|
|
3835
|
+
const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
|
|
3701
3836
|
if (input.status === "in_progress") {
|
|
3702
3837
|
mkdirSync6(cacheDir, { recursive: true });
|
|
3703
3838
|
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -3868,15 +4003,15 @@ __export(identity_exports, {
|
|
|
3868
4003
|
});
|
|
3869
4004
|
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
3870
4005
|
import { readdirSync as readdirSync5 } from "fs";
|
|
3871
|
-
import
|
|
4006
|
+
import path17 from "path";
|
|
3872
4007
|
import { createHash } from "crypto";
|
|
3873
4008
|
function ensureDir2() {
|
|
3874
|
-
if (!existsSync12(
|
|
3875
|
-
mkdirSync8(
|
|
4009
|
+
if (!existsSync12(IDENTITY_DIR2)) {
|
|
4010
|
+
mkdirSync8(IDENTITY_DIR2, { recursive: true });
|
|
3876
4011
|
}
|
|
3877
4012
|
}
|
|
3878
4013
|
function identityPath(agentId) {
|
|
3879
|
-
return
|
|
4014
|
+
return path17.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
3880
4015
|
}
|
|
3881
4016
|
function parseFrontmatter(raw) {
|
|
3882
4017
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -3949,7 +4084,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
3949
4084
|
}
|
|
3950
4085
|
function listIdentities() {
|
|
3951
4086
|
ensureDir2();
|
|
3952
|
-
const files = readdirSync5(
|
|
4087
|
+
const files = readdirSync5(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
3953
4088
|
const results = [];
|
|
3954
4089
|
for (const file of files) {
|
|
3955
4090
|
const agentId = file.replace(".md", "");
|
|
@@ -3982,13 +4117,13 @@ ${teamLines.join("\n")}`);
|
|
|
3982
4117
|
}
|
|
3983
4118
|
return parts.join("\n\n");
|
|
3984
4119
|
}
|
|
3985
|
-
var
|
|
4120
|
+
var IDENTITY_DIR2;
|
|
3986
4121
|
var init_identity = __esm({
|
|
3987
4122
|
"src/lib/identity.ts"() {
|
|
3988
4123
|
"use strict";
|
|
3989
4124
|
init_config();
|
|
3990
4125
|
init_database();
|
|
3991
|
-
|
|
4126
|
+
IDENTITY_DIR2 = path17.join(EXE_AI_DIR, "identity");
|
|
3992
4127
|
}
|
|
3993
4128
|
});
|
|
3994
4129
|
|
|
@@ -4543,8 +4678,8 @@ init_session_key();
|
|
|
4543
4678
|
init_employees();
|
|
4544
4679
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6, readdirSync as readdirSync4 } from "fs";
|
|
4545
4680
|
import { execSync as execSync7 } from "child_process";
|
|
4546
|
-
import
|
|
4547
|
-
var CACHE_DIR =
|
|
4681
|
+
import path16 from "path";
|
|
4682
|
+
var CACHE_DIR = path16.join(EXE_AI_DIR, "session-cache");
|
|
4548
4683
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
4549
4684
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
4550
4685
|
if (candidate === baseName) return true;
|
|
@@ -4589,7 +4724,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
4589
4724
|
return null;
|
|
4590
4725
|
}
|
|
4591
4726
|
function getMarkerPath() {
|
|
4592
|
-
return
|
|
4727
|
+
return path16.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
4593
4728
|
}
|
|
4594
4729
|
function getActiveAgent() {
|
|
4595
4730
|
try {
|