@askexenow/exe-os 0.9.119 → 0.9.121
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/cli.js +11 -7
- package/dist/bin/exe-boot.js +9 -6
- package/dist/bin/exe-dispatch.js +9 -6
- package/dist/bin/exe-gateway.js +9 -6
- package/dist/bin/exe-session-cleanup.js +9 -6
- package/dist/bin/git-sweep.js +9 -6
- package/dist/bin/intercom-check.js +42 -6
- package/dist/bin/scan-tasks.js +9 -6
- package/dist/gateway/index.js +9 -6
- package/dist/hooks/bug-report-worker.js +9 -6
- package/dist/hooks/codex-stop-task-finalizer.js +9 -6
- package/dist/hooks/commit-complete.js +9 -6
- package/dist/hooks/ingest.js +9 -6
- package/dist/hooks/pre-compact.js +9 -6
- package/dist/hooks/prompt-submit.js +69 -7
- package/dist/hooks/session-end.js +9 -6
- package/dist/index.js +42 -6
- package/dist/lib/consolidation.js +1 -1
- package/dist/lib/exe-daemon.js +45 -8
- package/dist/lib/skill-learning.js +9 -6
- package/dist/lib/tasks.js +9 -6
- package/dist/lib/tmux-routing.js +9 -6
- package/dist/mcp/register-tools.js +485 -324
- package/dist/mcp/server.js +485 -324
- package/dist/mcp/tools/create-task.js +9 -6
- package/dist/mcp/tools/update-task.js +9 -6
- package/dist/runtime/index.js +42 -6
- package/dist/tui/App.js +9 -6
- package/package.json +1 -1
|
@@ -9614,7 +9614,7 @@ async function dedupCluster(client, cluster, embedFn) {
|
|
|
9614
9614
|
const vectors = [];
|
|
9615
9615
|
for (const mem of cluster.memories) {
|
|
9616
9616
|
try {
|
|
9617
|
-
const v = await embedFn(mem.raw_text
|
|
9617
|
+
const v = await embedFn(mem.raw_text);
|
|
9618
9618
|
vectors.push({ id: mem.id, vector: v });
|
|
9619
9619
|
} catch {
|
|
9620
9620
|
}
|
|
@@ -9722,7 +9722,15 @@ var init_consolidation = __esm({
|
|
|
9722
9722
|
});
|
|
9723
9723
|
|
|
9724
9724
|
// src/lib/session-registry.ts
|
|
9725
|
+
var session_registry_exports = {};
|
|
9726
|
+
__export(session_registry_exports, {
|
|
9727
|
+
listSessions: () => listSessions,
|
|
9728
|
+
pruneStaleSessions: () => pruneStaleSessions,
|
|
9729
|
+
refreshSessionProject: () => refreshSessionProject,
|
|
9730
|
+
registerSession: () => registerSession
|
|
9731
|
+
});
|
|
9725
9732
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync14 } from "fs";
|
|
9733
|
+
import { execSync as execSync8 } from "child_process";
|
|
9726
9734
|
import path17 from "path";
|
|
9727
9735
|
import os7 from "os";
|
|
9728
9736
|
function registerSession(entry) {
|
|
@@ -9739,6 +9747,16 @@ function registerSession(entry) {
|
|
|
9739
9747
|
}
|
|
9740
9748
|
writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
9741
9749
|
}
|
|
9750
|
+
function refreshSessionProject(windowName, projectDir) {
|
|
9751
|
+
const sessions = listSessions();
|
|
9752
|
+
const entry = sessions.find((s) => s.windowName === windowName);
|
|
9753
|
+
if (!entry || entry.projectDir === projectDir) return;
|
|
9754
|
+
entry.projectDir = projectDir;
|
|
9755
|
+
try {
|
|
9756
|
+
writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
9757
|
+
} catch {
|
|
9758
|
+
}
|
|
9759
|
+
}
|
|
9742
9760
|
function listSessions() {
|
|
9743
9761
|
try {
|
|
9744
9762
|
const raw = readFileSync10(REGISTRY_PATH, "utf8");
|
|
@@ -9747,6 +9765,25 @@ function listSessions() {
|
|
|
9747
9765
|
return [];
|
|
9748
9766
|
}
|
|
9749
9767
|
}
|
|
9768
|
+
function pruneStaleSessions() {
|
|
9769
|
+
const sessions = listSessions();
|
|
9770
|
+
if (sessions.length === 0) return 0;
|
|
9771
|
+
let liveSessions = [];
|
|
9772
|
+
try {
|
|
9773
|
+
liveSessions = execSync8("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
9774
|
+
encoding: "utf8"
|
|
9775
|
+
}).trim().split("\n").filter(Boolean);
|
|
9776
|
+
} catch {
|
|
9777
|
+
return 0;
|
|
9778
|
+
}
|
|
9779
|
+
const liveSet = new Set(liveSessions);
|
|
9780
|
+
const alive = sessions.filter((s) => liveSet.has(s.windowName));
|
|
9781
|
+
const pruned = sessions.length - alive.length;
|
|
9782
|
+
if (pruned > 0) {
|
|
9783
|
+
writeFileSync8(REGISTRY_PATH, JSON.stringify(alive, null, 2));
|
|
9784
|
+
}
|
|
9785
|
+
return pruned;
|
|
9786
|
+
}
|
|
9750
9787
|
var REGISTRY_PATH;
|
|
9751
9788
|
var init_session_registry = __esm({
|
|
9752
9789
|
"src/lib/session-registry.ts"() {
|
|
@@ -9873,14 +9910,14 @@ var init_transport = __esm({
|
|
|
9873
9910
|
});
|
|
9874
9911
|
|
|
9875
9912
|
// src/lib/cc-agent-support.ts
|
|
9876
|
-
import { execSync as
|
|
9913
|
+
import { execSync as execSync9 } from "child_process";
|
|
9877
9914
|
function _resetCcAgentSupportCache() {
|
|
9878
9915
|
_cachedSupport = null;
|
|
9879
9916
|
}
|
|
9880
9917
|
function claudeSupportsAgentFlag() {
|
|
9881
9918
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
9882
9919
|
try {
|
|
9883
|
-
const helpOutput =
|
|
9920
|
+
const helpOutput = execSync9("claude --help 2>&1", {
|
|
9884
9921
|
encoding: "utf-8",
|
|
9885
9922
|
timeout: 5e3
|
|
9886
9923
|
});
|
|
@@ -10844,7 +10881,7 @@ __export(tmux_routing_exports, {
|
|
|
10844
10881
|
spawnEmployee: () => spawnEmployee,
|
|
10845
10882
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
10846
10883
|
});
|
|
10847
|
-
import { execFileSync as execFileSync2, execSync as
|
|
10884
|
+
import { execFileSync as execFileSync2, execSync as execSync10 } from "child_process";
|
|
10848
10885
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9, existsSync as existsSync18, appendFileSync, readdirSync as readdirSync5 } from "fs";
|
|
10849
10886
|
import path21 from "path";
|
|
10850
10887
|
import os10 from "os";
|
|
@@ -11681,7 +11718,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
11681
11718
|
let booted = false;
|
|
11682
11719
|
for (let i = 0; i < 30; i++) {
|
|
11683
11720
|
try {
|
|
11684
|
-
|
|
11721
|
+
execSync10("sleep 0.5");
|
|
11685
11722
|
} catch {
|
|
11686
11723
|
}
|
|
11687
11724
|
try {
|
|
@@ -12120,7 +12157,7 @@ __export(tasks_crud_exports, {
|
|
|
12120
12157
|
import crypto7 from "crypto";
|
|
12121
12158
|
import path23 from "path";
|
|
12122
12159
|
import os12 from "os";
|
|
12123
|
-
import { execSync as
|
|
12160
|
+
import { execSync as execSync11 } from "child_process";
|
|
12124
12161
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
12125
12162
|
import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
|
|
12126
12163
|
async function writeCheckpoint(input) {
|
|
@@ -12484,14 +12521,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
12484
12521
|
if (!identifier || identifier === "unknown") return true;
|
|
12485
12522
|
try {
|
|
12486
12523
|
if (identifier.startsWith("%")) {
|
|
12487
|
-
const output =
|
|
12524
|
+
const output = execSync11("tmux list-panes -a -F '#{pane_id}'", {
|
|
12488
12525
|
timeout: 2e3,
|
|
12489
12526
|
encoding: "utf8",
|
|
12490
12527
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12491
12528
|
});
|
|
12492
12529
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
12493
12530
|
} else {
|
|
12494
|
-
|
|
12531
|
+
execSync11(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
12495
12532
|
timeout: 2e3,
|
|
12496
12533
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12497
12534
|
});
|
|
@@ -12500,7 +12537,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
12500
12537
|
} catch {
|
|
12501
12538
|
if (identifier.startsWith("%")) return true;
|
|
12502
12539
|
try {
|
|
12503
|
-
|
|
12540
|
+
execSync11("tmux list-sessions", {
|
|
12504
12541
|
timeout: 2e3,
|
|
12505
12542
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12506
12543
|
});
|
|
@@ -12515,12 +12552,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
12515
12552
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
12516
12553
|
try {
|
|
12517
12554
|
const since = new Date(taskCreatedAt).toISOString();
|
|
12518
|
-
const branch =
|
|
12555
|
+
const branch = execSync11(
|
|
12519
12556
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
12520
12557
|
{ encoding: "utf8", timeout: 3e3 }
|
|
12521
12558
|
).trim();
|
|
12522
12559
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
12523
|
-
const commitCount =
|
|
12560
|
+
const commitCount = execSync11(
|
|
12524
12561
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
12525
12562
|
{ encoding: "utf8", timeout: 5e3 }
|
|
12526
12563
|
).trim();
|
|
@@ -12931,15 +12968,18 @@ var init_tasks_notify = __esm({
|
|
|
12931
12968
|
import crypto8 from "crypto";
|
|
12932
12969
|
async function storeBehavior(opts) {
|
|
12933
12970
|
try {
|
|
12934
|
-
const { loadEmployeesSync: loadEmployeesSync2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
12971
|
+
const { loadEmployeesSync: loadEmployeesSync2, baseAgentName: baseAgentName2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
12935
12972
|
const roster = loadEmployeesSync2();
|
|
12936
|
-
if (roster.length > 0
|
|
12937
|
-
|
|
12938
|
-
|
|
12973
|
+
if (roster.length > 0) {
|
|
12974
|
+
const base = baseAgentName2(opts.agentId, roster);
|
|
12975
|
+
if (!roster.some((e) => e.name === opts.agentId || e.name === base)) {
|
|
12976
|
+
process.stderr.write(
|
|
12977
|
+
`[behaviors] WARNING: Agent "${opts.agentId}" not found in roster. Storing behavior anyway \u2014 may be orphaned.
|
|
12978
|
+
`
|
|
12979
|
+
);
|
|
12939
12980
|
}
|
|
12940
12981
|
}
|
|
12941
|
-
} catch
|
|
12942
|
-
if (e instanceof Error && e.message.includes("not found in roster")) throw e;
|
|
12982
|
+
} catch {
|
|
12943
12983
|
}
|
|
12944
12984
|
const client = getClient();
|
|
12945
12985
|
const id = crypto8.randomUUID();
|
|
@@ -14527,6 +14567,275 @@ var init_worker_gate = __esm({
|
|
|
14527
14567
|
}
|
|
14528
14568
|
});
|
|
14529
14569
|
|
|
14570
|
+
// src/lib/tmux-status.ts
|
|
14571
|
+
var tmux_status_exports = {};
|
|
14572
|
+
__export(tmux_status_exports, {
|
|
14573
|
+
capturePaneLines: () => capturePaneLines,
|
|
14574
|
+
formatStatusAll: () => formatStatusAll,
|
|
14575
|
+
formatStatusDeep: () => formatStatusDeep,
|
|
14576
|
+
formatTeamCondensed: () => formatTeamCondensed,
|
|
14577
|
+
getEmployeeStatuses: () => getEmployeeStatuses,
|
|
14578
|
+
getPaneCwd: () => getPaneCwd,
|
|
14579
|
+
inTmux: () => inTmux,
|
|
14580
|
+
listTmuxSessions: () => listTmuxSessions,
|
|
14581
|
+
listTmuxWindows: () => listTmuxWindows,
|
|
14582
|
+
parseActivity: () => parseActivity,
|
|
14583
|
+
parseContextPercentage: () => parseContextPercentage
|
|
14584
|
+
});
|
|
14585
|
+
import { execSync as execSync13 } from "child_process";
|
|
14586
|
+
function inTmux() {
|
|
14587
|
+
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
14588
|
+
const term = process.env.TERM ?? "";
|
|
14589
|
+
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
14590
|
+
try {
|
|
14591
|
+
execSync13("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
14592
|
+
encoding: "utf8",
|
|
14593
|
+
timeout: 2e3
|
|
14594
|
+
});
|
|
14595
|
+
return true;
|
|
14596
|
+
} catch {
|
|
14597
|
+
}
|
|
14598
|
+
try {
|
|
14599
|
+
let pid = process.ppid;
|
|
14600
|
+
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
14601
|
+
const comm = execSync13(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
14602
|
+
encoding: "utf8",
|
|
14603
|
+
timeout: 1e3
|
|
14604
|
+
}).trim();
|
|
14605
|
+
if (/tmux/.test(comm)) return true;
|
|
14606
|
+
const ppid = execSync13(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
14607
|
+
encoding: "utf8",
|
|
14608
|
+
timeout: 1e3
|
|
14609
|
+
}).trim();
|
|
14610
|
+
pid = parseInt(ppid, 10);
|
|
14611
|
+
if (isNaN(pid)) break;
|
|
14612
|
+
}
|
|
14613
|
+
} catch {
|
|
14614
|
+
}
|
|
14615
|
+
return false;
|
|
14616
|
+
}
|
|
14617
|
+
function listTmuxSessions() {
|
|
14618
|
+
try {
|
|
14619
|
+
const out = execSync13("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
14620
|
+
encoding: "utf8",
|
|
14621
|
+
timeout: 3e3
|
|
14622
|
+
});
|
|
14623
|
+
return out.trim().split("\n").filter(Boolean);
|
|
14624
|
+
} catch {
|
|
14625
|
+
return [];
|
|
14626
|
+
}
|
|
14627
|
+
}
|
|
14628
|
+
function capturePaneLines(windowName, lines = 10) {
|
|
14629
|
+
try {
|
|
14630
|
+
const out = execSync13(
|
|
14631
|
+
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
14632
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
14633
|
+
);
|
|
14634
|
+
return out.split("\n").filter((l) => l.trim());
|
|
14635
|
+
} catch {
|
|
14636
|
+
return [];
|
|
14637
|
+
}
|
|
14638
|
+
}
|
|
14639
|
+
function getPaneCwd(windowName) {
|
|
14640
|
+
try {
|
|
14641
|
+
const out = execSync13(
|
|
14642
|
+
`tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
|
|
14643
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
14644
|
+
);
|
|
14645
|
+
return out.trim() || void 0;
|
|
14646
|
+
} catch {
|
|
14647
|
+
return void 0;
|
|
14648
|
+
}
|
|
14649
|
+
}
|
|
14650
|
+
function projectFromPath(dir) {
|
|
14651
|
+
try {
|
|
14652
|
+
const root = execSync13("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
|
|
14653
|
+
encoding: "utf8",
|
|
14654
|
+
timeout: 3e3
|
|
14655
|
+
}).trim();
|
|
14656
|
+
return root.split("/").pop() ?? dir.split("/").pop() ?? "unknown";
|
|
14657
|
+
} catch {
|
|
14658
|
+
return dir.split("/").pop() ?? "unknown";
|
|
14659
|
+
}
|
|
14660
|
+
}
|
|
14661
|
+
function parseActivity(lines) {
|
|
14662
|
+
const joined = lines.join("\n");
|
|
14663
|
+
if (/npm\s+test|vitest|jest|pytest|cargo\s+test/i.test(joined)) {
|
|
14664
|
+
const passMatch = joined.match(/(\d+)\s*passed/i);
|
|
14665
|
+
if (passMatch) return `Running tests \u2014 ${passMatch[1]} passed`;
|
|
14666
|
+
return "Running tests...";
|
|
14667
|
+
}
|
|
14668
|
+
if (/Edit\(|Edit\s*\{/.test(joined)) {
|
|
14669
|
+
const fileMatch = joined.match(/file_path['":\s]+([^\s'"}\]]+)/);
|
|
14670
|
+
if (fileMatch) return `Editing ${fileMatch[1].split("/").slice(-2).join("/")}`;
|
|
14671
|
+
return "Editing code...";
|
|
14672
|
+
}
|
|
14673
|
+
if (/Write\(|Write\s*\{/.test(joined)) {
|
|
14674
|
+
const fileMatch = joined.match(/file_path['":\s]+([^\s'"}\]]+)/);
|
|
14675
|
+
if (fileMatch) return `Writing ${fileMatch[1].split("/").slice(-2).join("/")}`;
|
|
14676
|
+
return "Writing file...";
|
|
14677
|
+
}
|
|
14678
|
+
if (/Bash\(|Bash\s*\{/.test(joined)) {
|
|
14679
|
+
const cmdMatch = joined.match(/command['":\s]+([^\n'"}{]{1,60})/);
|
|
14680
|
+
if (cmdMatch) return `Running: ${cmdMatch[1].trim().slice(0, 50)}`;
|
|
14681
|
+
return "Running command...";
|
|
14682
|
+
}
|
|
14683
|
+
if (/git\s+commit/.test(joined)) return "Committing...";
|
|
14684
|
+
if (/MANDATORY|START WORKING NOW/.test(joined)) return "Starting new task...";
|
|
14685
|
+
if (/All tasks complete|No open tasks/.test(joined)) return "Idle \u2014 queue empty";
|
|
14686
|
+
if (/store_memory|recall_my_memory/.test(joined)) return "Accessing memory...";
|
|
14687
|
+
if (/Agent\(/.test(joined)) return "Spawning sub-agent...";
|
|
14688
|
+
if (/Read\(|Read\s*\{/.test(joined)) return "Reading files...";
|
|
14689
|
+
const lastLine = lines.filter((l) => l.trim()).pop();
|
|
14690
|
+
if (lastLine && lastLine.trim().length > 5) {
|
|
14691
|
+
return lastLine.trim().slice(0, 60);
|
|
14692
|
+
}
|
|
14693
|
+
return "Working...";
|
|
14694
|
+
}
|
|
14695
|
+
function parseContextPercentage(sessionName) {
|
|
14696
|
+
const lines = capturePaneLines(sessionName, 3);
|
|
14697
|
+
for (const line of lines) {
|
|
14698
|
+
const match = line.match(/[█░]+\s*(\d+)%/);
|
|
14699
|
+
if (match) {
|
|
14700
|
+
return parseInt(match[1], 10);
|
|
14701
|
+
}
|
|
14702
|
+
}
|
|
14703
|
+
return null;
|
|
14704
|
+
}
|
|
14705
|
+
function getEmployeeStatuses(employeeNames) {
|
|
14706
|
+
if (!inTmux() || process.env.VITEST) {
|
|
14707
|
+
return employeeNames.map((name) => ({
|
|
14708
|
+
name,
|
|
14709
|
+
hasWindow: false,
|
|
14710
|
+
icon: "\u26AA"
|
|
14711
|
+
}));
|
|
14712
|
+
}
|
|
14713
|
+
const sessions = new Set(listTmuxSessions());
|
|
14714
|
+
return employeeNames.map((name) => {
|
|
14715
|
+
const sessionName = [...sessions].find((s) => s.startsWith(`${name}-`));
|
|
14716
|
+
if (!sessionName) {
|
|
14717
|
+
return { name, hasWindow: false, icon: "\u26AA" };
|
|
14718
|
+
}
|
|
14719
|
+
let paneAlive = true;
|
|
14720
|
+
try {
|
|
14721
|
+
const paneStatus = execSync13(
|
|
14722
|
+
`tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
|
|
14723
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
14724
|
+
).trim();
|
|
14725
|
+
if (paneStatus === "1") paneAlive = false;
|
|
14726
|
+
} catch {
|
|
14727
|
+
paneAlive = false;
|
|
14728
|
+
}
|
|
14729
|
+
if (!paneAlive) {
|
|
14730
|
+
return { name, hasWindow: false, icon: "\u26AA" };
|
|
14731
|
+
}
|
|
14732
|
+
const rawLines = capturePaneLines(sessionName, 10);
|
|
14733
|
+
const cwd = getPaneCwd(sessionName);
|
|
14734
|
+
const project = cwd ? projectFromPath(cwd) : void 0;
|
|
14735
|
+
const activity = rawLines.length > 0 ? parseActivity(rawLines) : "Session active";
|
|
14736
|
+
return {
|
|
14737
|
+
name,
|
|
14738
|
+
hasWindow: true,
|
|
14739
|
+
project,
|
|
14740
|
+
activity,
|
|
14741
|
+
rawLines,
|
|
14742
|
+
icon: "\u{1F7E2}"
|
|
14743
|
+
};
|
|
14744
|
+
});
|
|
14745
|
+
}
|
|
14746
|
+
function formatTeamCondensed(statuses) {
|
|
14747
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
14748
|
+
for (const s of statuses) {
|
|
14749
|
+
const proj = s.project ?? "(no session)";
|
|
14750
|
+
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
14751
|
+
byProject.get(proj).push(s);
|
|
14752
|
+
}
|
|
14753
|
+
const lines = [];
|
|
14754
|
+
for (const [proj, emps] of byProject) {
|
|
14755
|
+
const parts = emps.map((e) => {
|
|
14756
|
+
if (!e.hasWindow) return `${e.name} offline`;
|
|
14757
|
+
return `${e.name} ${e.activity?.toLowerCase().slice(0, 40) ?? "active"}`;
|
|
14758
|
+
});
|
|
14759
|
+
lines.push(` ${proj}: ${parts.join(", ")}`);
|
|
14760
|
+
}
|
|
14761
|
+
return lines;
|
|
14762
|
+
}
|
|
14763
|
+
function formatStatusAll(statuses, tasks, roles) {
|
|
14764
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
14765
|
+
for (const s of statuses) {
|
|
14766
|
+
const proj = s.project ?? "(no session)";
|
|
14767
|
+
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
14768
|
+
byProject.get(proj).push(s);
|
|
14769
|
+
}
|
|
14770
|
+
const lines = [];
|
|
14771
|
+
lines.push("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
14772
|
+
lines.push("\u2502 REAL-TIME STATUS \u2502");
|
|
14773
|
+
lines.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
14774
|
+
lines.push("");
|
|
14775
|
+
for (const [proj, emps] of byProject) {
|
|
14776
|
+
lines.push(`\u250C\u2500 ${proj} ${"\u2500".repeat(Math.max(0, 66 - proj.length))}\u2510`);
|
|
14777
|
+
if (emps.every((e) => !e.hasWindow)) {
|
|
14778
|
+
lines.push("\u2502 No active employees" + " ".repeat(49) + "\u2502");
|
|
14779
|
+
} else {
|
|
14780
|
+
for (let i = 0; i < emps.length; i++) {
|
|
14781
|
+
const e = emps[i];
|
|
14782
|
+
const role = roles.get(e.name) ?? "";
|
|
14783
|
+
const roleSuffix = role ? ` (${role})` : "";
|
|
14784
|
+
const nameCol = `${e.name}${roleSuffix}`.padEnd(14);
|
|
14785
|
+
const task = tasks.get(e.name);
|
|
14786
|
+
if (!e.hasWindow) {
|
|
14787
|
+
const statusLine = `\u2502 ${nameCol} \u2502 \u26AA No tmux session`;
|
|
14788
|
+
lines.push(statusLine + " ".repeat(Math.max(0, 70 - statusLine.length)) + "\u2502");
|
|
14789
|
+
} else {
|
|
14790
|
+
const actLine = `\u2502 ${nameCol} \u2502 ${e.icon} ${(e.activity ?? "Active").slice(0, 45)}`;
|
|
14791
|
+
lines.push(actLine + " ".repeat(Math.max(0, 70 - actLine.length)) + "\u2502");
|
|
14792
|
+
if (task) {
|
|
14793
|
+
const taskLine = `\u2502${" ".repeat(16)}\u2502 Task: "${task.title.slice(0, 40)}" [${task.priority.toUpperCase()}]`;
|
|
14794
|
+
lines.push(taskLine + " ".repeat(Math.max(0, 70 - taskLine.length)) + "\u2502");
|
|
14795
|
+
}
|
|
14796
|
+
}
|
|
14797
|
+
if (i < emps.length - 1) {
|
|
14798
|
+
lines.push("\u251C" + "\u2500".repeat(16) + "\u253C" + "\u2500".repeat(52) + "\u2524");
|
|
14799
|
+
}
|
|
14800
|
+
}
|
|
14801
|
+
}
|
|
14802
|
+
lines.push("\u2514" + "\u2500".repeat(16) + "\u2534" + "\u2500".repeat(52) + "\u2518");
|
|
14803
|
+
lines.push("");
|
|
14804
|
+
}
|
|
14805
|
+
return lines.join("\n");
|
|
14806
|
+
}
|
|
14807
|
+
function formatStatusDeep(status2, task, role) {
|
|
14808
|
+
const lines = [];
|
|
14809
|
+
const header = `${status2.name} (${role}) \u2014 ${status2.project ?? "unknown project"}`;
|
|
14810
|
+
lines.push(`\u250C\u2500 ${header} ${"\u2500".repeat(Math.max(0, 66 - header.length))}\u2510`);
|
|
14811
|
+
if (task) {
|
|
14812
|
+
const taskLine = `\u2502 Task: "${task.title.slice(0, 50)}" [${task.priority.toUpperCase()}]`;
|
|
14813
|
+
lines.push(taskLine + " ".repeat(Math.max(0, 70 - taskLine.length)) + "\u2502");
|
|
14814
|
+
lines.push("\u251C" + "\u2500".repeat(69) + "\u2524");
|
|
14815
|
+
}
|
|
14816
|
+
if (!status2.hasWindow) {
|
|
14817
|
+
lines.push("\u2502 No tmux session" + " ".repeat(53) + "\u2502");
|
|
14818
|
+
} else if (status2.rawLines && status2.rawLines.length > 0) {
|
|
14819
|
+
lines.push("\u2502 Recent activity:" + " ".repeat(52) + "\u2502");
|
|
14820
|
+
for (const line of status2.rawLines.slice(-10)) {
|
|
14821
|
+
const trimmed = line.slice(0, 65);
|
|
14822
|
+
const padded = `\u2502 ${trimmed}`;
|
|
14823
|
+
lines.push(padded + " ".repeat(Math.max(0, 70 - padded.length)) + "\u2502");
|
|
14824
|
+
}
|
|
14825
|
+
} else {
|
|
14826
|
+
lines.push("\u2502 Session active \u2014 no recent output" + " ".repeat(35) + "\u2502");
|
|
14827
|
+
}
|
|
14828
|
+
lines.push("\u2514" + "\u2500".repeat(69) + "\u2518");
|
|
14829
|
+
return lines.join("\n");
|
|
14830
|
+
}
|
|
14831
|
+
var listTmuxWindows;
|
|
14832
|
+
var init_tmux_status = __esm({
|
|
14833
|
+
"src/lib/tmux-status.ts"() {
|
|
14834
|
+
"use strict";
|
|
14835
|
+
listTmuxWindows = listTmuxSessions;
|
|
14836
|
+
}
|
|
14837
|
+
});
|
|
14838
|
+
|
|
14530
14839
|
// src/lib/key-backup-status.ts
|
|
14531
14840
|
var key_backup_status_exports = {};
|
|
14532
14841
|
__export(key_backup_status_exports, {
|
|
@@ -14905,307 +15214,81 @@ function readAllBehaviors() {
|
|
|
14905
15214
|
priority: entry.get("priority"),
|
|
14906
15215
|
created_at: entry.get("created_at"),
|
|
14907
15216
|
updated_at: entry.get("updated_at")
|
|
14908
|
-
});
|
|
14909
|
-
});
|
|
14910
|
-
return records;
|
|
14911
|
-
}
|
|
14912
|
-
function onUpdate(callback) {
|
|
14913
|
-
const d = initCrdtDoc();
|
|
14914
|
-
const handler = (update) => callback(update);
|
|
14915
|
-
d.on("update", handler);
|
|
14916
|
-
return () => d.off("update", handler);
|
|
14917
|
-
}
|
|
14918
|
-
function persistState() {
|
|
14919
|
-
if (!doc) return;
|
|
14920
|
-
try {
|
|
14921
|
-
const sp = getStatePath();
|
|
14922
|
-
const dir = path36.dirname(sp);
|
|
14923
|
-
if (!existsSync32(dir)) mkdirSync16(dir, { recursive: true });
|
|
14924
|
-
const state = Y.encodeStateAsUpdate(doc);
|
|
14925
|
-
writeFileSync17(sp, Buffer.from(state));
|
|
14926
|
-
} catch {
|
|
14927
|
-
}
|
|
14928
|
-
}
|
|
14929
|
-
function isCrdtSyncEnabled() {
|
|
14930
|
-
return process.env.EXE_CRDT_SYNC !== "0";
|
|
14931
|
-
}
|
|
14932
|
-
async function rebuildFromDb() {
|
|
14933
|
-
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
14934
|
-
const client = getClient2();
|
|
14935
|
-
const result3 = await client.execute(
|
|
14936
|
-
"SELECT id, agent_id, agent_role, session_id, timestamp, tool_name, project_name, has_error, raw_text, version, author_device_id, scope FROM memories"
|
|
14937
|
-
);
|
|
14938
|
-
const memories = result3.rows.map((row) => ({
|
|
14939
|
-
id: String(row.id),
|
|
14940
|
-
agent_id: row.agent_id,
|
|
14941
|
-
agent_role: row.agent_role,
|
|
14942
|
-
session_id: row.session_id,
|
|
14943
|
-
timestamp: row.timestamp,
|
|
14944
|
-
tool_name: row.tool_name,
|
|
14945
|
-
project_name: row.project_name,
|
|
14946
|
-
has_error: row.has_error,
|
|
14947
|
-
raw_text: row.raw_text,
|
|
14948
|
-
version: row.version,
|
|
14949
|
-
author_device_id: row.author_device_id,
|
|
14950
|
-
scope: row.scope
|
|
14951
|
-
}));
|
|
14952
|
-
const count = importExistingMemories(memories);
|
|
14953
|
-
persistState();
|
|
14954
|
-
return count;
|
|
14955
|
-
}
|
|
14956
|
-
function destroyCrdtDoc() {
|
|
14957
|
-
if (doc) {
|
|
14958
|
-
doc.destroy();
|
|
14959
|
-
doc = null;
|
|
14960
|
-
}
|
|
14961
|
-
}
|
|
14962
|
-
var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
14963
|
-
var init_crdt_sync = __esm({
|
|
14964
|
-
"src/lib/crdt-sync.ts"() {
|
|
14965
|
-
"use strict";
|
|
14966
|
-
DEFAULT_STATE_PATH = path36.join(homedir7(), ".exe-os", "crdt-state.bin");
|
|
14967
|
-
_statePathOverride = null;
|
|
14968
|
-
doc = null;
|
|
14969
|
-
}
|
|
14970
|
-
});
|
|
14971
|
-
|
|
14972
|
-
// src/lib/pg-ssl.ts
|
|
14973
|
-
var pg_ssl_exports = {};
|
|
14974
|
-
__export(pg_ssl_exports, {
|
|
14975
|
-
pgSslConfig: () => pgSslConfig
|
|
14976
|
-
});
|
|
14977
|
-
function pgSslConfig() {
|
|
14978
|
-
if (process.env.EXE_DB_SSL_DISABLED === "true") return {};
|
|
14979
|
-
return { ssl: { rejectUnauthorized: process.env.EXE_DB_SSL_ALLOW_SELFSIGNED !== "true" } };
|
|
14980
|
-
}
|
|
14981
|
-
var init_pg_ssl = __esm({
|
|
14982
|
-
"src/lib/pg-ssl.ts"() {
|
|
14983
|
-
"use strict";
|
|
14984
|
-
}
|
|
14985
|
-
});
|
|
14986
|
-
|
|
14987
|
-
// src/lib/tmux-status.ts
|
|
14988
|
-
import { execSync as execSync13 } from "child_process";
|
|
14989
|
-
function inTmux() {
|
|
14990
|
-
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
14991
|
-
const term = process.env.TERM ?? "";
|
|
14992
|
-
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
14993
|
-
try {
|
|
14994
|
-
execSync13("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
14995
|
-
encoding: "utf8",
|
|
14996
|
-
timeout: 2e3
|
|
14997
|
-
});
|
|
14998
|
-
return true;
|
|
14999
|
-
} catch {
|
|
15000
|
-
}
|
|
15001
|
-
try {
|
|
15002
|
-
let pid = process.ppid;
|
|
15003
|
-
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
15004
|
-
const comm = execSync13(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
15005
|
-
encoding: "utf8",
|
|
15006
|
-
timeout: 1e3
|
|
15007
|
-
}).trim();
|
|
15008
|
-
if (/tmux/.test(comm)) return true;
|
|
15009
|
-
const ppid = execSync13(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
15010
|
-
encoding: "utf8",
|
|
15011
|
-
timeout: 1e3
|
|
15012
|
-
}).trim();
|
|
15013
|
-
pid = parseInt(ppid, 10);
|
|
15014
|
-
if (isNaN(pid)) break;
|
|
15015
|
-
}
|
|
15016
|
-
} catch {
|
|
15017
|
-
}
|
|
15018
|
-
return false;
|
|
15019
|
-
}
|
|
15020
|
-
function listTmuxSessions() {
|
|
15021
|
-
try {
|
|
15022
|
-
const out = execSync13("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
15023
|
-
encoding: "utf8",
|
|
15024
|
-
timeout: 3e3
|
|
15025
|
-
});
|
|
15026
|
-
return out.trim().split("\n").filter(Boolean);
|
|
15027
|
-
} catch {
|
|
15028
|
-
return [];
|
|
15029
|
-
}
|
|
15030
|
-
}
|
|
15031
|
-
function capturePaneLines(windowName, lines = 10) {
|
|
15032
|
-
try {
|
|
15033
|
-
const out = execSync13(
|
|
15034
|
-
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
15035
|
-
{ encoding: "utf8", timeout: 3e3 }
|
|
15036
|
-
);
|
|
15037
|
-
return out.split("\n").filter((l) => l.trim());
|
|
15038
|
-
} catch {
|
|
15039
|
-
return [];
|
|
15040
|
-
}
|
|
15217
|
+
});
|
|
15218
|
+
});
|
|
15219
|
+
return records;
|
|
15041
15220
|
}
|
|
15042
|
-
function
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
);
|
|
15048
|
-
return out.trim() || void 0;
|
|
15049
|
-
} catch {
|
|
15050
|
-
return void 0;
|
|
15051
|
-
}
|
|
15221
|
+
function onUpdate(callback) {
|
|
15222
|
+
const d = initCrdtDoc();
|
|
15223
|
+
const handler = (update) => callback(update);
|
|
15224
|
+
d.on("update", handler);
|
|
15225
|
+
return () => d.off("update", handler);
|
|
15052
15226
|
}
|
|
15053
|
-
function
|
|
15227
|
+
function persistState() {
|
|
15228
|
+
if (!doc) return;
|
|
15054
15229
|
try {
|
|
15055
|
-
const
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15230
|
+
const sp = getStatePath();
|
|
15231
|
+
const dir = path36.dirname(sp);
|
|
15232
|
+
if (!existsSync32(dir)) mkdirSync16(dir, { recursive: true });
|
|
15233
|
+
const state = Y.encodeStateAsUpdate(doc);
|
|
15234
|
+
writeFileSync17(sp, Buffer.from(state));
|
|
15060
15235
|
} catch {
|
|
15061
|
-
return dir.split("/").pop() ?? "unknown";
|
|
15062
15236
|
}
|
|
15063
15237
|
}
|
|
15064
|
-
function
|
|
15065
|
-
|
|
15066
|
-
if (/npm\s+test|vitest|jest|pytest|cargo\s+test/i.test(joined)) {
|
|
15067
|
-
const passMatch = joined.match(/(\d+)\s*passed/i);
|
|
15068
|
-
if (passMatch) return `Running tests \u2014 ${passMatch[1]} passed`;
|
|
15069
|
-
return "Running tests...";
|
|
15070
|
-
}
|
|
15071
|
-
if (/Edit\(|Edit\s*\{/.test(joined)) {
|
|
15072
|
-
const fileMatch = joined.match(/file_path['":\s]+([^\s'"}\]]+)/);
|
|
15073
|
-
if (fileMatch) return `Editing ${fileMatch[1].split("/").slice(-2).join("/")}`;
|
|
15074
|
-
return "Editing code...";
|
|
15075
|
-
}
|
|
15076
|
-
if (/Write\(|Write\s*\{/.test(joined)) {
|
|
15077
|
-
const fileMatch = joined.match(/file_path['":\s]+([^\s'"}\]]+)/);
|
|
15078
|
-
if (fileMatch) return `Writing ${fileMatch[1].split("/").slice(-2).join("/")}`;
|
|
15079
|
-
return "Writing file...";
|
|
15080
|
-
}
|
|
15081
|
-
if (/Bash\(|Bash\s*\{/.test(joined)) {
|
|
15082
|
-
const cmdMatch = joined.match(/command['":\s]+([^\n'"}{]{1,60})/);
|
|
15083
|
-
if (cmdMatch) return `Running: ${cmdMatch[1].trim().slice(0, 50)}`;
|
|
15084
|
-
return "Running command...";
|
|
15085
|
-
}
|
|
15086
|
-
if (/git\s+commit/.test(joined)) return "Committing...";
|
|
15087
|
-
if (/MANDATORY|START WORKING NOW/.test(joined)) return "Starting new task...";
|
|
15088
|
-
if (/All tasks complete|No open tasks/.test(joined)) return "Idle \u2014 queue empty";
|
|
15089
|
-
if (/store_memory|recall_my_memory/.test(joined)) return "Accessing memory...";
|
|
15090
|
-
if (/Agent\(/.test(joined)) return "Spawning sub-agent...";
|
|
15091
|
-
if (/Read\(|Read\s*\{/.test(joined)) return "Reading files...";
|
|
15092
|
-
const lastLine = lines.filter((l) => l.trim()).pop();
|
|
15093
|
-
if (lastLine && lastLine.trim().length > 5) {
|
|
15094
|
-
return lastLine.trim().slice(0, 60);
|
|
15095
|
-
}
|
|
15096
|
-
return "Working...";
|
|
15238
|
+
function isCrdtSyncEnabled() {
|
|
15239
|
+
return process.env.EXE_CRDT_SYNC !== "0";
|
|
15097
15240
|
}
|
|
15098
|
-
function
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
}
|
|
15122
|
-
if (!paneAlive) {
|
|
15123
|
-
return { name, hasWindow: false, icon: "\u26AA" };
|
|
15124
|
-
}
|
|
15125
|
-
const rawLines = capturePaneLines(sessionName, 10);
|
|
15126
|
-
const cwd = getPaneCwd(sessionName);
|
|
15127
|
-
const project = cwd ? projectFromPath(cwd) : void 0;
|
|
15128
|
-
const activity = rawLines.length > 0 ? parseActivity(rawLines) : "Session active";
|
|
15129
|
-
return {
|
|
15130
|
-
name,
|
|
15131
|
-
hasWindow: true,
|
|
15132
|
-
project,
|
|
15133
|
-
activity,
|
|
15134
|
-
rawLines,
|
|
15135
|
-
icon: "\u{1F7E2}"
|
|
15136
|
-
};
|
|
15137
|
-
});
|
|
15241
|
+
async function rebuildFromDb() {
|
|
15242
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
15243
|
+
const client = getClient2();
|
|
15244
|
+
const result3 = await client.execute(
|
|
15245
|
+
"SELECT id, agent_id, agent_role, session_id, timestamp, tool_name, project_name, has_error, raw_text, version, author_device_id, scope FROM memories"
|
|
15246
|
+
);
|
|
15247
|
+
const memories = result3.rows.map((row) => ({
|
|
15248
|
+
id: String(row.id),
|
|
15249
|
+
agent_id: row.agent_id,
|
|
15250
|
+
agent_role: row.agent_role,
|
|
15251
|
+
session_id: row.session_id,
|
|
15252
|
+
timestamp: row.timestamp,
|
|
15253
|
+
tool_name: row.tool_name,
|
|
15254
|
+
project_name: row.project_name,
|
|
15255
|
+
has_error: row.has_error,
|
|
15256
|
+
raw_text: row.raw_text,
|
|
15257
|
+
version: row.version,
|
|
15258
|
+
author_device_id: row.author_device_id,
|
|
15259
|
+
scope: row.scope
|
|
15260
|
+
}));
|
|
15261
|
+
const count = importExistingMemories(memories);
|
|
15262
|
+
persistState();
|
|
15263
|
+
return count;
|
|
15138
15264
|
}
|
|
15139
|
-
function
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
15144
|
-
byProject.get(proj).push(s);
|
|
15145
|
-
}
|
|
15146
|
-
const lines = [];
|
|
15147
|
-
lines.push("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
15148
|
-
lines.push("\u2502 REAL-TIME STATUS \u2502");
|
|
15149
|
-
lines.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
15150
|
-
lines.push("");
|
|
15151
|
-
for (const [proj, emps] of byProject) {
|
|
15152
|
-
lines.push(`\u250C\u2500 ${proj} ${"\u2500".repeat(Math.max(0, 66 - proj.length))}\u2510`);
|
|
15153
|
-
if (emps.every((e) => !e.hasWindow)) {
|
|
15154
|
-
lines.push("\u2502 No active employees" + " ".repeat(49) + "\u2502");
|
|
15155
|
-
} else {
|
|
15156
|
-
for (let i = 0; i < emps.length; i++) {
|
|
15157
|
-
const e = emps[i];
|
|
15158
|
-
const role = roles.get(e.name) ?? "";
|
|
15159
|
-
const roleSuffix = role ? ` (${role})` : "";
|
|
15160
|
-
const nameCol = `${e.name}${roleSuffix}`.padEnd(14);
|
|
15161
|
-
const task = tasks.get(e.name);
|
|
15162
|
-
if (!e.hasWindow) {
|
|
15163
|
-
const statusLine = `\u2502 ${nameCol} \u2502 \u26AA No tmux session`;
|
|
15164
|
-
lines.push(statusLine + " ".repeat(Math.max(0, 70 - statusLine.length)) + "\u2502");
|
|
15165
|
-
} else {
|
|
15166
|
-
const actLine = `\u2502 ${nameCol} \u2502 ${e.icon} ${(e.activity ?? "Active").slice(0, 45)}`;
|
|
15167
|
-
lines.push(actLine + " ".repeat(Math.max(0, 70 - actLine.length)) + "\u2502");
|
|
15168
|
-
if (task) {
|
|
15169
|
-
const taskLine = `\u2502${" ".repeat(16)}\u2502 Task: "${task.title.slice(0, 40)}" [${task.priority.toUpperCase()}]`;
|
|
15170
|
-
lines.push(taskLine + " ".repeat(Math.max(0, 70 - taskLine.length)) + "\u2502");
|
|
15171
|
-
}
|
|
15172
|
-
}
|
|
15173
|
-
if (i < emps.length - 1) {
|
|
15174
|
-
lines.push("\u251C" + "\u2500".repeat(16) + "\u253C" + "\u2500".repeat(52) + "\u2524");
|
|
15175
|
-
}
|
|
15176
|
-
}
|
|
15177
|
-
}
|
|
15178
|
-
lines.push("\u2514" + "\u2500".repeat(16) + "\u2534" + "\u2500".repeat(52) + "\u2518");
|
|
15179
|
-
lines.push("");
|
|
15265
|
+
function destroyCrdtDoc() {
|
|
15266
|
+
if (doc) {
|
|
15267
|
+
doc.destroy();
|
|
15268
|
+
doc = null;
|
|
15180
15269
|
}
|
|
15181
|
-
return lines.join("\n");
|
|
15182
15270
|
}
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
lines.push("\u251C" + "\u2500".repeat(69) + "\u2524");
|
|
15191
|
-
}
|
|
15192
|
-
if (!status2.hasWindow) {
|
|
15193
|
-
lines.push("\u2502 No tmux session" + " ".repeat(53) + "\u2502");
|
|
15194
|
-
} else if (status2.rawLines && status2.rawLines.length > 0) {
|
|
15195
|
-
lines.push("\u2502 Recent activity:" + " ".repeat(52) + "\u2502");
|
|
15196
|
-
for (const line of status2.rawLines.slice(-10)) {
|
|
15197
|
-
const trimmed = line.slice(0, 65);
|
|
15198
|
-
const padded = `\u2502 ${trimmed}`;
|
|
15199
|
-
lines.push(padded + " ".repeat(Math.max(0, 70 - padded.length)) + "\u2502");
|
|
15200
|
-
}
|
|
15201
|
-
} else {
|
|
15202
|
-
lines.push("\u2502 Session active \u2014 no recent output" + " ".repeat(35) + "\u2502");
|
|
15271
|
+
var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
15272
|
+
var init_crdt_sync = __esm({
|
|
15273
|
+
"src/lib/crdt-sync.ts"() {
|
|
15274
|
+
"use strict";
|
|
15275
|
+
DEFAULT_STATE_PATH = path36.join(homedir7(), ".exe-os", "crdt-state.bin");
|
|
15276
|
+
_statePathOverride = null;
|
|
15277
|
+
doc = null;
|
|
15203
15278
|
}
|
|
15204
|
-
|
|
15205
|
-
|
|
15279
|
+
});
|
|
15280
|
+
|
|
15281
|
+
// src/lib/pg-ssl.ts
|
|
15282
|
+
var pg_ssl_exports = {};
|
|
15283
|
+
__export(pg_ssl_exports, {
|
|
15284
|
+
pgSslConfig: () => pgSslConfig
|
|
15285
|
+
});
|
|
15286
|
+
function pgSslConfig() {
|
|
15287
|
+
if (process.env.EXE_DB_SSL_DISABLED === "true") return {};
|
|
15288
|
+
return { ssl: { rejectUnauthorized: process.env.EXE_DB_SSL_ALLOW_SELFSIGNED !== "true" } };
|
|
15206
15289
|
}
|
|
15207
|
-
var
|
|
15208
|
-
"src/lib/
|
|
15290
|
+
var init_pg_ssl = __esm({
|
|
15291
|
+
"src/lib/pg-ssl.ts"() {
|
|
15209
15292
|
"use strict";
|
|
15210
15293
|
}
|
|
15211
15294
|
});
|
|
@@ -17471,6 +17554,23 @@ function registerStoreBehavior(server) {
|
|
|
17471
17554
|
} else {
|
|
17472
17555
|
resolvedProject = getProjectName();
|
|
17473
17556
|
}
|
|
17557
|
+
try {
|
|
17558
|
+
const { loadEmployeesSync: loadEmployeesSync2, baseAgentName: baseAgentName2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
17559
|
+
const roster = loadEmployeesSync2();
|
|
17560
|
+
if (roster.length > 0) {
|
|
17561
|
+
const base = baseAgentName2(resolvedAgent, roster);
|
|
17562
|
+
if (!roster.some((e) => e.name === resolvedAgent || e.name === base)) {
|
|
17563
|
+
return {
|
|
17564
|
+
content: [{
|
|
17565
|
+
type: "text",
|
|
17566
|
+
text: `Error: Agent "${resolvedAgent}" not found in roster. Cannot store behavior for non-existent agent. Available agents: ${roster.map((e) => e.name).join(", ")}`
|
|
17567
|
+
}],
|
|
17568
|
+
isError: true
|
|
17569
|
+
};
|
|
17570
|
+
}
|
|
17571
|
+
}
|
|
17572
|
+
} catch {
|
|
17573
|
+
}
|
|
17474
17574
|
const id = await storeBehavior({
|
|
17475
17575
|
agentId: resolvedAgent,
|
|
17476
17576
|
content,
|
|
@@ -19969,7 +20069,8 @@ function summarizeChunk(chunk, filePath) {
|
|
|
19969
20069
|
}
|
|
19970
20070
|
}
|
|
19971
20071
|
function isChunkable(filePath) {
|
|
19972
|
-
|
|
20072
|
+
const lang = languageForFile(filePath);
|
|
20073
|
+
return lang === "typescript" || lang === "javascript";
|
|
19973
20074
|
}
|
|
19974
20075
|
|
|
19975
20076
|
// src/lib/graph-rag.ts
|
|
@@ -21138,7 +21239,7 @@ import { z as z55 } from "zod";
|
|
|
21138
21239
|
init_tmux_routing();
|
|
21139
21240
|
init_task_scope();
|
|
21140
21241
|
init_employees();
|
|
21141
|
-
import { execSync as
|
|
21242
|
+
import { execSync as execSync12 } from "child_process";
|
|
21142
21243
|
import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
21143
21244
|
import { homedir as homedir6 } from "os";
|
|
21144
21245
|
import { join as join4 } from "path";
|
|
@@ -21273,12 +21374,50 @@ function countAliveWorkers() {
|
|
|
21273
21374
|
}
|
|
21274
21375
|
return { alive, stale, reservations };
|
|
21275
21376
|
}
|
|
21377
|
+
async function getAgentSessionLoad() {
|
|
21378
|
+
const sessions = [];
|
|
21379
|
+
try {
|
|
21380
|
+
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
21381
|
+
const { listTmuxSessions: listTmuxSessions2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
21382
|
+
const { isCoordinatorName: isCoordinatorName2, baseAgentName: baseAgentName2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
21383
|
+
const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
21384
|
+
const registered = listSessions2();
|
|
21385
|
+
const liveTmux = new Set(listTmuxSessions2());
|
|
21386
|
+
const liveAgentSessions = registered.filter(
|
|
21387
|
+
(s) => liveTmux.has(s.windowName) && !isCoordinatorName2(s.agentId) && !isExeSession2(s.windowName)
|
|
21388
|
+
);
|
|
21389
|
+
if (liveAgentSessions.length === 0) {
|
|
21390
|
+
return { sessions: [], totalLive: 0, busySessions: 0, idleSessions: 0 };
|
|
21391
|
+
}
|
|
21392
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
21393
|
+
const client = getClient2();
|
|
21394
|
+
for (const s of liveAgentSessions) {
|
|
21395
|
+
const agent = baseAgentName2(s.agentId);
|
|
21396
|
+
const result3 = await client.execute({
|
|
21397
|
+
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
21398
|
+
WHERE assigned_to = ? AND status IN ('open', 'in_progress')`,
|
|
21399
|
+
args: [agent]
|
|
21400
|
+
});
|
|
21401
|
+
const taskCount = Number(result3.rows[0]?.cnt ?? 0);
|
|
21402
|
+
sessions.push({
|
|
21403
|
+
agentId: s.agentId,
|
|
21404
|
+
sessionName: s.windowName,
|
|
21405
|
+
taskCount,
|
|
21406
|
+
idle: taskCount === 0
|
|
21407
|
+
});
|
|
21408
|
+
}
|
|
21409
|
+
} catch {
|
|
21410
|
+
}
|
|
21411
|
+
const busySessions = sessions.filter((s) => !s.idle).length;
|
|
21412
|
+
const idleSessions = sessions.filter((s) => s.idle).length;
|
|
21413
|
+
return { sessions, totalLive: sessions.length, busySessions, idleSessions };
|
|
21414
|
+
}
|
|
21276
21415
|
function registerGetWorkerGate(server) {
|
|
21277
21416
|
server.registerTool(
|
|
21278
21417
|
"get_worker_gate",
|
|
21279
21418
|
{
|
|
21280
21419
|
title: "Get Worker Gate",
|
|
21281
|
-
description: "Check worker concurrency gate
|
|
21420
|
+
description: "Check worker concurrency gate and agent session utilization. Reports embed/summary worker slots AND live agent sessions with task load. Idle sessions (alive tmux, zero tasks) are excluded from the effective session count \u2014 they should not block new dispatches.",
|
|
21282
21421
|
inputSchema: {
|
|
21283
21422
|
_placeholder: z56.string().optional().describe("No input required")
|
|
21284
21423
|
}
|
|
@@ -21287,7 +21426,7 @@ function registerGetWorkerGate(server) {
|
|
|
21287
21426
|
try {
|
|
21288
21427
|
const { alive, stale, reservations } = countAliveWorkers();
|
|
21289
21428
|
const totalActive = alive + reservations;
|
|
21290
|
-
const
|
|
21429
|
+
const canSpawnWorker = totalActive < MAX_CONCURRENT_WORKERS;
|
|
21291
21430
|
const lines = [];
|
|
21292
21431
|
lines.push("## Worker Gate Status\n");
|
|
21293
21432
|
lines.push("| Metric | Value |");
|
|
@@ -21296,7 +21435,29 @@ function registerGetWorkerGate(server) {
|
|
|
21296
21435
|
lines.push(`| Pending reservations | ${reservations} |`);
|
|
21297
21436
|
lines.push(`| Stale PID files | ${stale} |`);
|
|
21298
21437
|
lines.push(`| Max concurrent | ${MAX_CONCURRENT_WORKERS} |`);
|
|
21299
|
-
lines.push(`| Can spawn new worker | ${
|
|
21438
|
+
lines.push(`| Can spawn new worker | ${canSpawnWorker ? "yes" : "no"} |`);
|
|
21439
|
+
const load = await getAgentSessionLoad();
|
|
21440
|
+
if (load.totalLive > 0) {
|
|
21441
|
+
lines.push("");
|
|
21442
|
+
lines.push("## Agent Session Load\n");
|
|
21443
|
+
lines.push("| Session | Agent | Tasks | Status |");
|
|
21444
|
+
lines.push("|---------|-------|-------|--------|");
|
|
21445
|
+
for (const s of load.sessions) {
|
|
21446
|
+
const status2 = s.idle ? "idle (no tasks)" : `busy (${s.taskCount} task${s.taskCount === 1 ? "" : "s"})`;
|
|
21447
|
+
lines.push(`| ${s.sessionName} | ${s.agentId} | ${s.taskCount} | ${status2} |`);
|
|
21448
|
+
}
|
|
21449
|
+
lines.push("");
|
|
21450
|
+
lines.push(`| Total live sessions | ${load.totalLive} |`);
|
|
21451
|
+
lines.push(`| Busy (with tasks) | ${load.busySessions} |`);
|
|
21452
|
+
lines.push(`| Idle (no tasks) | ${load.idleSessions} |`);
|
|
21453
|
+
lines.push("");
|
|
21454
|
+
lines.push(
|
|
21455
|
+
`**Effective session load: ${load.busySessions}** (idle sessions excluded). ${load.idleSessions > 0 ? `${load.idleSessions} idle session${load.idleSessions === 1 ? "" : "s"} can be reused or killed before spawning new agents.` : "All sessions are actively working."}`
|
|
21456
|
+
);
|
|
21457
|
+
} else {
|
|
21458
|
+
lines.push("");
|
|
21459
|
+
lines.push("No live agent sessions.");
|
|
21460
|
+
}
|
|
21300
21461
|
return {
|
|
21301
21462
|
content: [{ type: "text", text: lines.join("\n") }]
|
|
21302
21463
|
};
|
|
@@ -25613,7 +25774,7 @@ function isScheduledTrigger(trigger) {
|
|
|
25613
25774
|
init_database();
|
|
25614
25775
|
init_store();
|
|
25615
25776
|
import crypto16 from "crypto";
|
|
25616
|
-
import { execSync as
|
|
25777
|
+
import { execSync as execSync14 } from "child_process";
|
|
25617
25778
|
var CRON_FIELD = /^[\d*/,\-]+$/;
|
|
25618
25779
|
function isValidCron(cron) {
|
|
25619
25780
|
const fields = cron.trim().split(/\s+/);
|
|
@@ -25739,7 +25900,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
25739
25900
|
const cwd = projectDir ? `cd ${JSON.stringify(projectDir)} && ` : "";
|
|
25740
25901
|
const escapedPrompt = prompt.replace(/"/g, '\\"');
|
|
25741
25902
|
const entry = `${cron} ${cwd}claude -p --dangerously-skip-permissions "${escapedPrompt}" # exe-schedule:${id}`;
|
|
25742
|
-
|
|
25903
|
+
execSync14(
|
|
25743
25904
|
`(crontab -l 2>/dev/null; echo ${JSON.stringify(entry)}) | crontab -`,
|
|
25744
25905
|
{ timeout: 5e3, stdio: "ignore" }
|
|
25745
25906
|
);
|
|
@@ -29421,7 +29582,7 @@ if (isMainModule(import.meta.url)) {
|
|
|
29421
29582
|
// src/bin/exe-healthcheck.ts
|
|
29422
29583
|
import { existsSync as existsSync40, readFileSync as readFileSync33, readdirSync as readdirSync14 } from "fs";
|
|
29423
29584
|
import path52 from "path";
|
|
29424
|
-
import { execSync as
|
|
29585
|
+
import { execSync as execSync15 } from "child_process";
|
|
29425
29586
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
29426
29587
|
init_config();
|
|
29427
29588
|
function findPackageRoot2() {
|
|
@@ -29519,7 +29680,7 @@ function checkTaskSystem(pkgRoot) {
|
|
|
29519
29680
|
return results;
|
|
29520
29681
|
}
|
|
29521
29682
|
try {
|
|
29522
|
-
|
|
29683
|
+
execSync15(`node "${scannerPath}" /tmp/nonexistent-healthcheck-test --format=json 2>/dev/null`, {
|
|
29523
29684
|
timeout: 1e4,
|
|
29524
29685
|
encoding: "utf-8"
|
|
29525
29686
|
});
|
|
@@ -29542,7 +29703,7 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
29542
29703
|
return results;
|
|
29543
29704
|
}
|
|
29544
29705
|
try {
|
|
29545
|
-
|
|
29706
|
+
execSync15(`node --check "${workerPath}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
29546
29707
|
results.push({ name: "workers/ingest-worker", pass: true, detail: "ingest-worker.js parses OK" });
|
|
29547
29708
|
} catch (err) {
|
|
29548
29709
|
results.push({
|
|
@@ -29558,7 +29719,7 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
29558
29719
|
const hooksFailed = [];
|
|
29559
29720
|
for (const hook of hookFiles) {
|
|
29560
29721
|
try {
|
|
29561
|
-
|
|
29722
|
+
execSync15(`node --check "${path52.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
29562
29723
|
hooksPassed++;
|
|
29563
29724
|
} catch {
|
|
29564
29725
|
hooksFailed.push(hook);
|
|
@@ -29600,7 +29761,7 @@ function checkMcpTransport() {
|
|
|
29600
29761
|
if (daemonAlive && existsSync40(tokenPath)) {
|
|
29601
29762
|
try {
|
|
29602
29763
|
const token = readFileSync33(tokenPath, "utf8").trim();
|
|
29603
|
-
const response =
|
|
29764
|
+
const response = execSync15(
|
|
29604
29765
|
`curl -sS -i -m 2 -H "Authorization: Bearer ${token}" -H 'Accept: application/json, text/event-stream' http://127.0.0.1:48739/mcp`,
|
|
29605
29766
|
{ encoding: "utf8", timeout: 3e3 }
|
|
29606
29767
|
);
|
|
@@ -29651,7 +29812,7 @@ function checkClaudeCodeInstall() {
|
|
|
29651
29812
|
});
|
|
29652
29813
|
}
|
|
29653
29814
|
try {
|
|
29654
|
-
const claudePath =
|
|
29815
|
+
const claudePath = execSync15("which claude 2>/dev/null || true", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
29655
29816
|
if (!claudePath) {
|
|
29656
29817
|
results.push({
|
|
29657
29818
|
name: "cc/cli-binary",
|
|
@@ -29661,7 +29822,7 @@ function checkClaudeCodeInstall() {
|
|
|
29661
29822
|
} else {
|
|
29662
29823
|
let resolved = claudePath;
|
|
29663
29824
|
try {
|
|
29664
|
-
resolved =
|
|
29825
|
+
resolved = execSync15(`readlink -f "${claudePath}" 2>/dev/null || readlink "${claudePath}" 2>/dev/null || echo "${claudePath}"`, {
|
|
29665
29826
|
encoding: "utf8",
|
|
29666
29827
|
timeout: 5e3
|
|
29667
29828
|
}).trim();
|
|
@@ -29745,7 +29906,7 @@ function checkClaudeCodeInstall() {
|
|
|
29745
29906
|
});
|
|
29746
29907
|
}
|
|
29747
29908
|
try {
|
|
29748
|
-
const ccVersion =
|
|
29909
|
+
const ccVersion = execSync15("claude --version 2>/dev/null || echo unknown", {
|
|
29749
29910
|
encoding: "utf8",
|
|
29750
29911
|
timeout: 5e3
|
|
29751
29912
|
}).trim();
|
|
@@ -29793,7 +29954,7 @@ if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-healt
|
|
|
29793
29954
|
}
|
|
29794
29955
|
|
|
29795
29956
|
// src/lib/update-check.ts
|
|
29796
|
-
import { execSync as
|
|
29957
|
+
import { execSync as execSync16 } from "child_process";
|
|
29797
29958
|
import { readFileSync as readFileSync34 } from "fs";
|
|
29798
29959
|
import path53 from "path";
|
|
29799
29960
|
function getLocalVersion(packageRoot) {
|
|
@@ -29803,7 +29964,7 @@ function getLocalVersion(packageRoot) {
|
|
|
29803
29964
|
}
|
|
29804
29965
|
function getRemoteVersion() {
|
|
29805
29966
|
try {
|
|
29806
|
-
const output =
|
|
29967
|
+
const output = execSync16("npm view @askexenow/exe-os version", {
|
|
29807
29968
|
encoding: "utf-8",
|
|
29808
29969
|
timeout: 15e3,
|
|
29809
29970
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -31291,7 +31452,7 @@ var ToolCapabilityIndex = class {
|
|
|
31291
31452
|
let vector = null;
|
|
31292
31453
|
if (embedFn) {
|
|
31293
31454
|
try {
|
|
31294
|
-
vector = await embedFn(capabilityDoc
|
|
31455
|
+
vector = await embedFn(capabilityDoc);
|
|
31295
31456
|
} catch {
|
|
31296
31457
|
}
|
|
31297
31458
|
}
|