@askexenow/exe-os 0.9.7 → 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 +657 -35
- package/dist/bin/cli.js +1388 -605
- 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 +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- 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 +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- 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 +834 -150
- 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 +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- 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 +724 -93
- 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 +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- 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 +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- 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 +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- 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 +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- 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 +290 -164
- 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 +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- 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;
|
|
@@ -1848,7 +1974,7 @@ function sendIntercom(targetSession) {
|
|
|
1848
1974
|
try {
|
|
1849
1975
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1850
1976
|
const agent = baseAgentName(rawAgent);
|
|
1851
|
-
const markerPath =
|
|
1977
|
+
const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
1852
1978
|
if (existsSync9(markerPath)) {
|
|
1853
1979
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
1854
1980
|
return "debounced";
|
|
@@ -1858,7 +1984,7 @@ function sendIntercom(targetSession) {
|
|
|
1858
1984
|
try {
|
|
1859
1985
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1860
1986
|
const agent = baseAgentName(rawAgent);
|
|
1861
|
-
const taskDir =
|
|
1987
|
+
const taskDir = path10.join(process.cwd(), "exe", agent);
|
|
1862
1988
|
if (existsSync9(taskDir)) {
|
|
1863
1989
|
const files = readdirSync2(taskDir).filter(
|
|
1864
1990
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -1992,8 +2118,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1992
2118
|
const transport = getTransport();
|
|
1993
2119
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
1994
2120
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
1995
|
-
const logDir =
|
|
1996
|
-
const logFile =
|
|
2121
|
+
const logDir = path10.join(os7.homedir(), ".exe-os", "session-logs");
|
|
2122
|
+
const logFile = path10.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
1997
2123
|
if (!existsSync9(logDir)) {
|
|
1998
2124
|
mkdirSync5(logDir, { recursive: true });
|
|
1999
2125
|
}
|
|
@@ -2001,14 +2127,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2001
2127
|
let cleanupSuffix = "";
|
|
2002
2128
|
try {
|
|
2003
2129
|
const thisFile = fileURLToPath(import.meta.url);
|
|
2004
|
-
const cleanupScript =
|
|
2130
|
+
const cleanupScript = path10.join(path10.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
2005
2131
|
if (existsSync9(cleanupScript)) {
|
|
2006
2132
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
2007
2133
|
}
|
|
2008
2134
|
} catch {
|
|
2009
2135
|
}
|
|
2010
2136
|
try {
|
|
2011
|
-
const claudeJsonPath =
|
|
2137
|
+
const claudeJsonPath = path10.join(os7.homedir(), ".claude.json");
|
|
2012
2138
|
let claudeJson = {};
|
|
2013
2139
|
try {
|
|
2014
2140
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -2023,10 +2149,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2023
2149
|
} catch {
|
|
2024
2150
|
}
|
|
2025
2151
|
try {
|
|
2026
|
-
const settingsDir =
|
|
2152
|
+
const settingsDir = path10.join(os7.homedir(), ".claude", "projects");
|
|
2027
2153
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
2028
|
-
const projSettingsDir =
|
|
2029
|
-
const settingsPath =
|
|
2154
|
+
const projSettingsDir = path10.join(settingsDir, normalizedKey);
|
|
2155
|
+
const settingsPath = path10.join(projSettingsDir, "settings.json");
|
|
2030
2156
|
let settings = {};
|
|
2031
2157
|
try {
|
|
2032
2158
|
settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
|
|
@@ -2073,8 +2199,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2073
2199
|
let behaviorsFlag = "";
|
|
2074
2200
|
let legacyFallbackWarned = false;
|
|
2075
2201
|
if (!useExeAgent && !useBinSymlink) {
|
|
2076
|
-
const identityPath2 =
|
|
2077
|
-
|
|
2202
|
+
const identityPath2 = path10.join(
|
|
2203
|
+
os7.homedir(),
|
|
2078
2204
|
".exe-os",
|
|
2079
2205
|
"identity",
|
|
2080
2206
|
`${employeeName}.md`
|
|
@@ -2089,7 +2215,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2089
2215
|
}
|
|
2090
2216
|
const behaviorsFile = exportBehaviorsSync(
|
|
2091
2217
|
employeeName,
|
|
2092
|
-
|
|
2218
|
+
path10.basename(spawnCwd),
|
|
2093
2219
|
sessionName
|
|
2094
2220
|
);
|
|
2095
2221
|
if (behaviorsFile) {
|
|
@@ -2104,9 +2230,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2104
2230
|
}
|
|
2105
2231
|
let sessionContextFlag = "";
|
|
2106
2232
|
try {
|
|
2107
|
-
const ctxDir =
|
|
2233
|
+
const ctxDir = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2108
2234
|
mkdirSync5(ctxDir, { recursive: true });
|
|
2109
|
-
const ctxFile =
|
|
2235
|
+
const ctxFile = path10.join(ctxDir, `session-context-${sessionName}.md`);
|
|
2110
2236
|
const ctxContent = [
|
|
2111
2237
|
`## Session Context`,
|
|
2112
2238
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -2190,7 +2316,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2190
2316
|
transport.pipeLog(sessionName, logFile);
|
|
2191
2317
|
try {
|
|
2192
2318
|
const mySession = getMySession();
|
|
2193
|
-
const dispatchInfo =
|
|
2319
|
+
const dispatchInfo = path10.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
2194
2320
|
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
2195
2321
|
dispatchedBy: mySession,
|
|
2196
2322
|
rootExe: exeSession,
|
|
@@ -2265,15 +2391,15 @@ var init_tmux_routing = __esm({
|
|
|
2265
2391
|
init_intercom_queue();
|
|
2266
2392
|
init_plan_limits();
|
|
2267
2393
|
init_employees();
|
|
2268
|
-
SPAWN_LOCK_DIR =
|
|
2269
|
-
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");
|
|
2270
2396
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
2271
2397
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
2272
2398
|
VERIFY_PANE_LINES = 200;
|
|
2273
2399
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2274
2400
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
2275
|
-
INTERCOM_LOG2 =
|
|
2276
|
-
DEBOUNCE_FILE =
|
|
2401
|
+
INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
2402
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2277
2403
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2278
2404
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
2279
2405
|
}
|
|
@@ -2305,8 +2431,8 @@ var init_task_scope = __esm({
|
|
|
2305
2431
|
|
|
2306
2432
|
// src/lib/tasks-crud.ts
|
|
2307
2433
|
import crypto3 from "crypto";
|
|
2308
|
-
import
|
|
2309
|
-
import
|
|
2434
|
+
import path11 from "path";
|
|
2435
|
+
import os8 from "os";
|
|
2310
2436
|
import { execSync as execSync5 } from "child_process";
|
|
2311
2437
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2312
2438
|
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
@@ -2484,8 +2610,8 @@ ${laneWarning}` : laneWarning;
|
|
|
2484
2610
|
}
|
|
2485
2611
|
if (input.baseDir) {
|
|
2486
2612
|
try {
|
|
2487
|
-
await mkdir3(
|
|
2488
|
-
await mkdir3(
|
|
2613
|
+
await mkdir3(path11.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
2614
|
+
await mkdir3(path11.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
2489
2615
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
2490
2616
|
await ensureGitignoreExe(input.baseDir);
|
|
2491
2617
|
} catch {
|
|
@@ -2521,9 +2647,9 @@ ${laneWarning}` : laneWarning;
|
|
|
2521
2647
|
});
|
|
2522
2648
|
if (input.baseDir) {
|
|
2523
2649
|
try {
|
|
2524
|
-
const EXE_OS_DIR =
|
|
2525
|
-
const mdPath =
|
|
2526
|
-
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);
|
|
2527
2653
|
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
2528
2654
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
2529
2655
|
const mdContent = `# ${input.title}
|
|
@@ -2824,7 +2950,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2824
2950
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
2825
2951
|
}
|
|
2826
2952
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2827
|
-
const archPath =
|
|
2953
|
+
const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2828
2954
|
try {
|
|
2829
2955
|
if (existsSync10(archPath)) return;
|
|
2830
2956
|
const template = [
|
|
@@ -2859,7 +2985,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2859
2985
|
}
|
|
2860
2986
|
}
|
|
2861
2987
|
async function ensureGitignoreExe(baseDir) {
|
|
2862
|
-
const gitignorePath =
|
|
2988
|
+
const gitignorePath = path11.join(baseDir, ".gitignore");
|
|
2863
2989
|
try {
|
|
2864
2990
|
if (existsSync10(gitignorePath)) {
|
|
2865
2991
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
@@ -2893,13 +3019,13 @@ var init_tasks_crud = __esm({
|
|
|
2893
3019
|
});
|
|
2894
3020
|
|
|
2895
3021
|
// src/lib/tasks-review.ts
|
|
2896
|
-
import
|
|
3022
|
+
import path12 from "path";
|
|
2897
3023
|
import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
2898
3024
|
async function countPendingReviews(sessionScope) {
|
|
2899
3025
|
const client = getClient();
|
|
2900
3026
|
if (sessionScope) {
|
|
2901
3027
|
const result2 = await client.execute({
|
|
2902
|
-
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 = ?",
|
|
2903
3029
|
args: [sessionScope]
|
|
2904
3030
|
});
|
|
2905
3031
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -3075,11 +3201,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3075
3201
|
);
|
|
3076
3202
|
}
|
|
3077
3203
|
try {
|
|
3078
|
-
const cacheDir =
|
|
3204
|
+
const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
|
|
3079
3205
|
if (existsSync11(cacheDir)) {
|
|
3080
3206
|
for (const f of readdirSync3(cacheDir)) {
|
|
3081
3207
|
if (f.startsWith("review-notified-")) {
|
|
3082
|
-
unlinkSync4(
|
|
3208
|
+
unlinkSync4(path12.join(cacheDir, f));
|
|
3083
3209
|
}
|
|
3084
3210
|
}
|
|
3085
3211
|
}
|
|
@@ -3100,7 +3226,7 @@ var init_tasks_review = __esm({
|
|
|
3100
3226
|
});
|
|
3101
3227
|
|
|
3102
3228
|
// src/lib/tasks-chain.ts
|
|
3103
|
-
import
|
|
3229
|
+
import path13 from "path";
|
|
3104
3230
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
3105
3231
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
3106
3232
|
const client = getClient();
|
|
@@ -3117,7 +3243,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
3117
3243
|
});
|
|
3118
3244
|
for (const ur of unblockedRows.rows) {
|
|
3119
3245
|
try {
|
|
3120
|
-
const ubFile =
|
|
3246
|
+
const ubFile = path13.join(baseDir, String(ur.task_file));
|
|
3121
3247
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
3122
3248
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
3123
3249
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -3186,7 +3312,7 @@ var init_tasks_chain = __esm({
|
|
|
3186
3312
|
|
|
3187
3313
|
// src/lib/project-name.ts
|
|
3188
3314
|
import { execSync as execSync6 } from "child_process";
|
|
3189
|
-
import
|
|
3315
|
+
import path14 from "path";
|
|
3190
3316
|
function getProjectName(cwd) {
|
|
3191
3317
|
const dir = cwd ?? process.cwd();
|
|
3192
3318
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -3199,7 +3325,7 @@ function getProjectName(cwd) {
|
|
|
3199
3325
|
timeout: 2e3,
|
|
3200
3326
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3201
3327
|
}).trim();
|
|
3202
|
-
repoRoot =
|
|
3328
|
+
repoRoot = path14.dirname(gitCommonDir);
|
|
3203
3329
|
} catch {
|
|
3204
3330
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
3205
3331
|
cwd: dir,
|
|
@@ -3208,11 +3334,11 @@ function getProjectName(cwd) {
|
|
|
3208
3334
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3209
3335
|
}).trim();
|
|
3210
3336
|
}
|
|
3211
|
-
_cached2 =
|
|
3337
|
+
_cached2 = path14.basename(repoRoot);
|
|
3212
3338
|
_cachedCwd = dir;
|
|
3213
3339
|
return _cached2;
|
|
3214
3340
|
} catch {
|
|
3215
|
-
_cached2 =
|
|
3341
|
+
_cached2 = path14.basename(dir);
|
|
3216
3342
|
_cachedCwd = dir;
|
|
3217
3343
|
return _cached2;
|
|
3218
3344
|
}
|
|
@@ -3685,7 +3811,7 @@ __export(tasks_exports, {
|
|
|
3685
3811
|
updateTaskStatus: () => updateTaskStatus,
|
|
3686
3812
|
writeCheckpoint: () => writeCheckpoint
|
|
3687
3813
|
});
|
|
3688
|
-
import
|
|
3814
|
+
import path15 from "path";
|
|
3689
3815
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
3690
3816
|
async function createTask(input) {
|
|
3691
3817
|
const result = await createTaskCore(input);
|
|
@@ -3705,8 +3831,8 @@ async function updateTask(input) {
|
|
|
3705
3831
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
3706
3832
|
try {
|
|
3707
3833
|
const agent = String(row.assigned_to);
|
|
3708
|
-
const cacheDir =
|
|
3709
|
-
const cachePath =
|
|
3834
|
+
const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
|
|
3835
|
+
const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
|
|
3710
3836
|
if (input.status === "in_progress") {
|
|
3711
3837
|
mkdirSync6(cacheDir, { recursive: true });
|
|
3712
3838
|
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -3877,15 +4003,15 @@ __export(identity_exports, {
|
|
|
3877
4003
|
});
|
|
3878
4004
|
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
3879
4005
|
import { readdirSync as readdirSync5 } from "fs";
|
|
3880
|
-
import
|
|
4006
|
+
import path17 from "path";
|
|
3881
4007
|
import { createHash } from "crypto";
|
|
3882
4008
|
function ensureDir2() {
|
|
3883
|
-
if (!existsSync12(
|
|
3884
|
-
mkdirSync8(
|
|
4009
|
+
if (!existsSync12(IDENTITY_DIR2)) {
|
|
4010
|
+
mkdirSync8(IDENTITY_DIR2, { recursive: true });
|
|
3885
4011
|
}
|
|
3886
4012
|
}
|
|
3887
4013
|
function identityPath(agentId) {
|
|
3888
|
-
return
|
|
4014
|
+
return path17.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
3889
4015
|
}
|
|
3890
4016
|
function parseFrontmatter(raw) {
|
|
3891
4017
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -3958,7 +4084,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
3958
4084
|
}
|
|
3959
4085
|
function listIdentities() {
|
|
3960
4086
|
ensureDir2();
|
|
3961
|
-
const files = readdirSync5(
|
|
4087
|
+
const files = readdirSync5(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
3962
4088
|
const results = [];
|
|
3963
4089
|
for (const file of files) {
|
|
3964
4090
|
const agentId = file.replace(".md", "");
|
|
@@ -3991,13 +4117,13 @@ ${teamLines.join("\n")}`);
|
|
|
3991
4117
|
}
|
|
3992
4118
|
return parts.join("\n\n");
|
|
3993
4119
|
}
|
|
3994
|
-
var
|
|
4120
|
+
var IDENTITY_DIR2;
|
|
3995
4121
|
var init_identity = __esm({
|
|
3996
4122
|
"src/lib/identity.ts"() {
|
|
3997
4123
|
"use strict";
|
|
3998
4124
|
init_config();
|
|
3999
4125
|
init_database();
|
|
4000
|
-
|
|
4126
|
+
IDENTITY_DIR2 = path17.join(EXE_AI_DIR, "identity");
|
|
4001
4127
|
}
|
|
4002
4128
|
});
|
|
4003
4129
|
|
|
@@ -4552,8 +4678,8 @@ init_session_key();
|
|
|
4552
4678
|
init_employees();
|
|
4553
4679
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6, readdirSync as readdirSync4 } from "fs";
|
|
4554
4680
|
import { execSync as execSync7 } from "child_process";
|
|
4555
|
-
import
|
|
4556
|
-
var CACHE_DIR =
|
|
4681
|
+
import path16 from "path";
|
|
4682
|
+
var CACHE_DIR = path16.join(EXE_AI_DIR, "session-cache");
|
|
4557
4683
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
4558
4684
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
4559
4685
|
if (candidate === baseName) return true;
|
|
@@ -4598,7 +4724,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
4598
4724
|
return null;
|
|
4599
4725
|
}
|
|
4600
4726
|
function getMarkerPath() {
|
|
4601
|
-
return
|
|
4727
|
+
return path16.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
4602
4728
|
}
|
|
4603
4729
|
function getActiveAgent() {
|
|
4604
4730
|
try {
|