@askexenow/exe-os 0.9.85 → 0.9.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agentic-ontology-backfill.js +50 -14
- package/dist/bin/agentic-reflection-backfill.js +50 -14
- package/dist/bin/agentic-semantic-label.js +50 -14
- package/dist/bin/backfill-conversations.js +50 -14
- package/dist/bin/backfill-responses.js +50 -14
- package/dist/bin/backfill-vectors.js +50 -14
- package/dist/bin/bulk-sync-postgres.js +50 -14
- package/dist/bin/cleanup-stale-review-tasks.js +53 -17
- package/dist/bin/cli.js +339 -81
- package/dist/bin/exe-agent.js +18 -0
- package/dist/bin/exe-assign.js +50 -14
- package/dist/bin/exe-boot.js +75 -39
- package/dist/bin/exe-call.js +18 -0
- package/dist/bin/exe-cloud.js +40 -4
- package/dist/bin/exe-dispatch.js +61 -25
- package/dist/bin/exe-doctor.js +40 -4
- package/dist/bin/exe-export-behaviors.js +50 -14
- package/dist/bin/exe-forget.js +50 -14
- package/dist/bin/exe-gateway.js +65 -29
- package/dist/bin/exe-heartbeat.js +55 -19
- package/dist/bin/exe-kill.js +54 -18
- package/dist/bin/exe-launch-agent.js +58 -22
- package/dist/bin/exe-new-employee.js +33 -2
- package/dist/bin/exe-pending-messages.js +53 -17
- package/dist/bin/exe-pending-notifications.js +53 -17
- package/dist/bin/exe-pending-reviews.js +55 -19
- package/dist/bin/exe-rename.js +52 -16
- package/dist/bin/exe-review.js +50 -14
- package/dist/bin/exe-search.js +58 -22
- package/dist/bin/exe-session-cleanup.js +85 -44
- package/dist/bin/exe-start-codex.js +57 -21
- package/dist/bin/exe-start-opencode.js +55 -19
- package/dist/bin/exe-status.js +62 -26
- package/dist/bin/exe-team.js +50 -14
- package/dist/bin/git-sweep.js +63 -27
- package/dist/bin/graph-backfill.js +50 -14
- package/dist/bin/graph-export.js +50 -14
- package/dist/bin/install.js +9 -0
- package/dist/bin/intercom-check.js +67 -31
- package/dist/bin/scan-tasks.js +63 -27
- package/dist/bin/setup.js +53 -13
- package/dist/bin/shard-migrate.js +50 -14
- package/dist/bin/stack-update.js +59 -2
- package/dist/bin/update.js +1 -1
- package/dist/gateway/index.js +65 -29
- package/dist/hooks/bug-report-worker.js +65 -29
- package/dist/hooks/codex-stop-task-finalizer.js +59 -23
- package/dist/hooks/commit-complete.js +64 -28
- package/dist/hooks/error-recall.js +62 -26
- package/dist/hooks/ingest-worker.js +4 -4
- package/dist/hooks/ingest.js +56 -20
- package/dist/hooks/instructions-loaded.js +50 -14
- package/dist/hooks/notification.js +50 -14
- package/dist/hooks/post-compact.js +50 -14
- package/dist/hooks/post-tool-combined.js +63 -27
- package/dist/hooks/pre-compact.js +61 -25
- package/dist/hooks/pre-tool-use.js +58 -22
- package/dist/hooks/prompt-submit.js +78 -42
- package/dist/hooks/session-end.js +66 -30
- package/dist/hooks/session-start.js +68 -32
- package/dist/hooks/stop.js +53 -17
- package/dist/hooks/subagent-stop.js +50 -14
- package/dist/hooks/summary-worker.js +55 -19
- package/dist/index.js +61 -25
- package/dist/lib/cloud-sync.js +32 -14
- package/dist/lib/database.js +22 -4
- package/dist/lib/db-daemon-client.js +16 -4
- package/dist/lib/db.js +22 -4
- package/dist/lib/device-registry.js +22 -4
- package/dist/lib/embedder.js +16 -4
- package/dist/lib/employee-templates.js +18 -0
- package/dist/lib/exe-daemon-client.js +16 -4
- package/dist/lib/exe-daemon.js +874 -232
- package/dist/lib/hybrid-search.js +58 -22
- package/dist/lib/identity-templates.js +6 -2
- package/dist/lib/schedules.js +53 -17
- package/dist/lib/skill-learning.js +16 -4
- package/dist/lib/store.js +50 -14
- package/dist/lib/tasks.js +16 -4
- package/dist/lib/tmux-routing.js +18 -6
- package/dist/mcp/server.js +809 -200
- package/dist/mcp/tools/create-task.js +24 -8
- package/dist/mcp/tools/update-task.js +18 -6
- package/dist/runtime/index.js +61 -25
- package/dist/tui/App.js +91 -55
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1229,6 +1229,15 @@ async function registerMcpServer(packageRoot, homeDir = os6.homedir()) {
|
|
|
1229
1229
|
delete claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
1230
1230
|
process.stderr.write("exe-os: migrated MCP server key exe-mem \u2192 exe-os\n");
|
|
1231
1231
|
}
|
|
1232
|
+
if (claudeJson.projects) {
|
|
1233
|
+
for (const [projectPath, projectConfig] of Object.entries(claudeJson.projects)) {
|
|
1234
|
+
if (projectConfig.mcpServers?.[MCP_LEGACY_KEY]) {
|
|
1235
|
+
delete projectConfig.mcpServers[MCP_LEGACY_KEY];
|
|
1236
|
+
process.stderr.write(`exe-os: removed stale project-level exe-mem from ${projectPath}
|
|
1237
|
+
`);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1232
1241
|
const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
1233
1242
|
const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
|
|
1234
1243
|
if (osMatches) {
|
|
@@ -3665,7 +3674,7 @@ __export(exe_daemon_client_exports, {
|
|
|
3665
3674
|
});
|
|
3666
3675
|
import net from "net";
|
|
3667
3676
|
import os10 from "os";
|
|
3668
|
-
import { spawn } from "child_process";
|
|
3677
|
+
import { spawn, execSync as execSync4 } from "child_process";
|
|
3669
3678
|
import { randomUUID } from "crypto";
|
|
3670
3679
|
import { existsSync as existsSync12, unlinkSync as unlinkSync3, readFileSync as readFileSync9, openSync, closeSync, statSync as statSync2 } from "fs";
|
|
3671
3680
|
import path12 from "path";
|
|
@@ -3695,6 +3704,14 @@ function handleData(chunk) {
|
|
|
3695
3704
|
}
|
|
3696
3705
|
}
|
|
3697
3706
|
}
|
|
3707
|
+
function isZombie(pid) {
|
|
3708
|
+
try {
|
|
3709
|
+
const state = execSync4(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
3710
|
+
return state.startsWith("Z");
|
|
3711
|
+
} catch {
|
|
3712
|
+
return false;
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3698
3715
|
function cleanupStaleFiles() {
|
|
3699
3716
|
if (existsSync12(PID_PATH)) {
|
|
3700
3717
|
try {
|
|
@@ -3702,7 +3719,11 @@ function cleanupStaleFiles() {
|
|
|
3702
3719
|
if (pid > 0) {
|
|
3703
3720
|
try {
|
|
3704
3721
|
process.kill(pid, 0);
|
|
3705
|
-
|
|
3722
|
+
if (!isZombie(pid)) {
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
3726
|
+
`);
|
|
3706
3727
|
} catch {
|
|
3707
3728
|
}
|
|
3708
3729
|
}
|
|
@@ -3730,8 +3751,8 @@ function findPackageRoot() {
|
|
|
3730
3751
|
function getAvailableMemoryGB() {
|
|
3731
3752
|
if (process.platform === "darwin") {
|
|
3732
3753
|
try {
|
|
3733
|
-
const { execSync:
|
|
3734
|
-
const vmstat =
|
|
3754
|
+
const { execSync: execSync19 } = __require("child_process");
|
|
3755
|
+
const vmstat = execSync19("vm_stat", { encoding: "utf8" });
|
|
3735
3756
|
const pageSize = 16384;
|
|
3736
3757
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
3737
3758
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -5686,6 +5707,12 @@ async function disposeDatabase() {
|
|
|
5686
5707
|
clearInterval(_walCheckpointTimer);
|
|
5687
5708
|
_walCheckpointTimer = null;
|
|
5688
5709
|
}
|
|
5710
|
+
if (_client) {
|
|
5711
|
+
try {
|
|
5712
|
+
await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
5713
|
+
} catch {
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5689
5716
|
if (_daemonClient) {
|
|
5690
5717
|
_daemonClient.close();
|
|
5691
5718
|
_daemonClient = null;
|
|
@@ -8701,6 +8728,24 @@ var init_platform_procedures = __esm({
|
|
|
8701
8728
|
priority: "p0",
|
|
8702
8729
|
content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
|
|
8703
8730
|
},
|
|
8731
|
+
{
|
|
8732
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
8733
|
+
domain: "support",
|
|
8734
|
+
priority: "p1",
|
|
8735
|
+
content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
8736
|
+
},
|
|
8737
|
+
{
|
|
8738
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
8739
|
+
domain: "support",
|
|
8740
|
+
priority: "p0",
|
|
8741
|
+
content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
|
|
8742
|
+
},
|
|
8743
|
+
{
|
|
8744
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
8745
|
+
domain: "support",
|
|
8746
|
+
priority: "p1",
|
|
8747
|
+
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
8748
|
+
},
|
|
8704
8749
|
// --- Operations ---
|
|
8705
8750
|
{
|
|
8706
8751
|
title: "Managers must supervise deployed workers",
|
|
@@ -10436,7 +10481,7 @@ import { createInterface as createInterface2 } from "readline";
|
|
|
10436
10481
|
import { existsSync as existsSync19, statSync as statSync6, mkdirSync as mkdirSync12, copyFileSync as copyFileSync3, renameSync as renameSync4, rmSync, writeFileSync as writeFileSync12 } from "fs";
|
|
10437
10482
|
import path19 from "path";
|
|
10438
10483
|
import os12 from "os";
|
|
10439
|
-
import { execSync as
|
|
10484
|
+
import { execSync as execSync5 } from "child_process";
|
|
10440
10485
|
import { createClient as createClient3 } from "@libsql/client";
|
|
10441
10486
|
function isInteractiveTerminal2() {
|
|
10442
10487
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
|
|
@@ -10467,7 +10512,7 @@ function dbSidecarPaths(dbPath) {
|
|
|
10467
10512
|
function daemonStatus() {
|
|
10468
10513
|
const pidPath = path19.join(dataDir(), "exed.pid");
|
|
10469
10514
|
if (!existsSync19(pidPath)) return { pid: null, alive: false };
|
|
10470
|
-
const pid =
|
|
10515
|
+
const pid = execSync5(`cat ${JSON.stringify(pidPath)}`, { encoding: "utf8" }).trim();
|
|
10471
10516
|
if (!pid) return { pid: null, alive: false };
|
|
10472
10517
|
try {
|
|
10473
10518
|
process.kill(Number(pid), 0);
|
|
@@ -10481,7 +10526,7 @@ async function stopDaemonIfAlive() {
|
|
|
10481
10526
|
if (!daemon.alive || !daemon.pid) return;
|
|
10482
10527
|
if (Number(daemon.pid) <= 1) {
|
|
10483
10528
|
try {
|
|
10484
|
-
|
|
10529
|
+
execSync5("docker inspect exed >/dev/null 2>&1 && docker stop exed >/dev/null", { timeout: 3e4 });
|
|
10485
10530
|
return;
|
|
10486
10531
|
} catch {
|
|
10487
10532
|
throw new Error("Refusing to signal PID 1. Stop the exed Docker container manually, then retry.");
|
|
@@ -12950,7 +12995,7 @@ __export(session_registry_exports, {
|
|
|
12950
12995
|
registerSession: () => registerSession
|
|
12951
12996
|
});
|
|
12952
12997
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync17, mkdirSync as mkdirSync17, existsSync as existsSync22 } from "fs";
|
|
12953
|
-
import { execSync as
|
|
12998
|
+
import { execSync as execSync6 } from "child_process";
|
|
12954
12999
|
import path25 from "path";
|
|
12955
13000
|
import os14 from "os";
|
|
12956
13001
|
function registerSession(entry) {
|
|
@@ -12990,7 +13035,7 @@ function pruneStaleSessions() {
|
|
|
12990
13035
|
if (sessions.length === 0) return 0;
|
|
12991
13036
|
let liveSessions = [];
|
|
12992
13037
|
try {
|
|
12993
|
-
liveSessions =
|
|
13038
|
+
liveSessions = execSync6("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
12994
13039
|
encoding: "utf8"
|
|
12995
13040
|
}).trim().split("\n").filter(Boolean);
|
|
12996
13041
|
} catch {
|
|
@@ -13013,7 +13058,7 @@ var init_session_registry = __esm({
|
|
|
13013
13058
|
});
|
|
13014
13059
|
|
|
13015
13060
|
// src/lib/session-key.ts
|
|
13016
|
-
import { execSync as
|
|
13061
|
+
import { execSync as execSync7 } from "child_process";
|
|
13017
13062
|
function normalizeCommand(command) {
|
|
13018
13063
|
const trimmed = command.trim().toLowerCase();
|
|
13019
13064
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -13032,7 +13077,7 @@ function resolveRuntimeProcess() {
|
|
|
13032
13077
|
let pid = process.ppid;
|
|
13033
13078
|
for (let i = 0; i < 10; i++) {
|
|
13034
13079
|
try {
|
|
13035
|
-
const info =
|
|
13080
|
+
const info = execSync7(`ps -p ${pid} -o ppid=,comm=`, {
|
|
13036
13081
|
encoding: "utf8",
|
|
13037
13082
|
timeout: 2e3
|
|
13038
13083
|
}).trim();
|
|
@@ -13206,14 +13251,14 @@ var init_transport = __esm({
|
|
|
13206
13251
|
});
|
|
13207
13252
|
|
|
13208
13253
|
// src/lib/cc-agent-support.ts
|
|
13209
|
-
import { execSync as
|
|
13254
|
+
import { execSync as execSync8 } from "child_process";
|
|
13210
13255
|
function _resetCcAgentSupportCache() {
|
|
13211
13256
|
_cachedSupport = null;
|
|
13212
13257
|
}
|
|
13213
13258
|
function claudeSupportsAgentFlag() {
|
|
13214
13259
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
13215
13260
|
try {
|
|
13216
|
-
const helpOutput =
|
|
13261
|
+
const helpOutput = execSync8("claude --help 2>&1", {
|
|
13217
13262
|
encoding: "utf-8",
|
|
13218
13263
|
timeout: 5e3
|
|
13219
13264
|
});
|
|
@@ -13590,7 +13635,7 @@ var init_session_kill_telemetry = __esm({
|
|
|
13590
13635
|
});
|
|
13591
13636
|
|
|
13592
13637
|
// src/lib/project-name.ts
|
|
13593
|
-
import { execSync as
|
|
13638
|
+
import { execSync as execSync9 } from "child_process";
|
|
13594
13639
|
import path29 from "path";
|
|
13595
13640
|
function getProjectName(cwd2) {
|
|
13596
13641
|
const dir = cwd2 ?? process.cwd();
|
|
@@ -13598,7 +13643,7 @@ function getProjectName(cwd2) {
|
|
|
13598
13643
|
try {
|
|
13599
13644
|
let repoRoot;
|
|
13600
13645
|
try {
|
|
13601
|
-
const gitCommonDir =
|
|
13646
|
+
const gitCommonDir = execSync9("git rev-parse --path-format=absolute --git-common-dir", {
|
|
13602
13647
|
cwd: dir,
|
|
13603
13648
|
encoding: "utf8",
|
|
13604
13649
|
timeout: 2e3,
|
|
@@ -13606,7 +13651,7 @@ function getProjectName(cwd2) {
|
|
|
13606
13651
|
}).trim();
|
|
13607
13652
|
repoRoot = path29.dirname(gitCommonDir);
|
|
13608
13653
|
} catch {
|
|
13609
|
-
repoRoot =
|
|
13654
|
+
repoRoot = execSync9("git rev-parse --show-toplevel", {
|
|
13610
13655
|
cwd: dir,
|
|
13611
13656
|
encoding: "utf8",
|
|
13612
13657
|
timeout: 2e3,
|
|
@@ -13713,7 +13758,7 @@ __export(tasks_crud_exports, {
|
|
|
13713
13758
|
import crypto9 from "crypto";
|
|
13714
13759
|
import path30 from "path";
|
|
13715
13760
|
import os17 from "os";
|
|
13716
|
-
import { execSync as
|
|
13761
|
+
import { execSync as execSync10 } from "child_process";
|
|
13717
13762
|
import { mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
|
|
13718
13763
|
import { existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
|
|
13719
13764
|
async function writeCheckpoint(input) {
|
|
@@ -14058,14 +14103,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
14058
14103
|
if (!identifier || identifier === "unknown") return true;
|
|
14059
14104
|
try {
|
|
14060
14105
|
if (identifier.startsWith("%")) {
|
|
14061
|
-
const output2 =
|
|
14106
|
+
const output2 = execSync10("tmux list-panes -a -F '#{pane_id}'", {
|
|
14062
14107
|
timeout: 2e3,
|
|
14063
14108
|
encoding: "utf8",
|
|
14064
14109
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14065
14110
|
});
|
|
14066
14111
|
return output2.split("\n").some((l) => l.trim() === identifier);
|
|
14067
14112
|
} else {
|
|
14068
|
-
|
|
14113
|
+
execSync10(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
14069
14114
|
timeout: 2e3,
|
|
14070
14115
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14071
14116
|
});
|
|
@@ -14074,7 +14119,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
14074
14119
|
} catch {
|
|
14075
14120
|
if (identifier.startsWith("%")) return true;
|
|
14076
14121
|
try {
|
|
14077
|
-
|
|
14122
|
+
execSync10("tmux list-sessions", {
|
|
14078
14123
|
timeout: 2e3,
|
|
14079
14124
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14080
14125
|
});
|
|
@@ -14089,12 +14134,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
14089
14134
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
14090
14135
|
try {
|
|
14091
14136
|
const since = new Date(taskCreatedAt).toISOString();
|
|
14092
|
-
const branch =
|
|
14137
|
+
const branch = execSync10(
|
|
14093
14138
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
14094
14139
|
{ encoding: "utf8", timeout: 3e3 }
|
|
14095
14140
|
).trim();
|
|
14096
14141
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
14097
|
-
const commitCount =
|
|
14142
|
+
const commitCount = execSync10(
|
|
14098
14143
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
14099
14144
|
{ encoding: "utf8", timeout: 5e3 }
|
|
14100
14145
|
).trim();
|
|
@@ -15693,7 +15738,7 @@ __export(tmux_routing_exports, {
|
|
|
15693
15738
|
spawnEmployee: () => spawnEmployee,
|
|
15694
15739
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
15695
15740
|
});
|
|
15696
|
-
import { execFileSync as execFileSync3, execSync as
|
|
15741
|
+
import { execFileSync as execFileSync3, execSync as execSync11 } from "child_process";
|
|
15697
15742
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync20, mkdirSync as mkdirSync20, existsSync as existsSync28, appendFileSync as appendFileSync2, readdirSync as readdirSync7 } from "fs";
|
|
15698
15743
|
import path34 from "path";
|
|
15699
15744
|
import os18 from "os";
|
|
@@ -16414,7 +16459,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
16414
16459
|
let booted = false;
|
|
16415
16460
|
for (let i = 0; i < 30; i++) {
|
|
16416
16461
|
try {
|
|
16417
|
-
|
|
16462
|
+
execSync11("sleep 0.5");
|
|
16418
16463
|
} catch {
|
|
16419
16464
|
}
|
|
16420
16465
|
try {
|
|
@@ -16787,7 +16832,7 @@ __export(active_agent_exports, {
|
|
|
16787
16832
|
writeActiveAgent: () => writeActiveAgent
|
|
16788
16833
|
});
|
|
16789
16834
|
import { readFileSync as readFileSync24, writeFileSync as writeFileSync21, mkdirSync as mkdirSync21, unlinkSync as unlinkSync12, readdirSync as readdirSync8 } from "fs";
|
|
16790
|
-
import { execSync as
|
|
16835
|
+
import { execSync as execSync12 } from "child_process";
|
|
16791
16836
|
import path35 from "path";
|
|
16792
16837
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
16793
16838
|
if (candidate === baseName) return true;
|
|
@@ -16881,7 +16926,7 @@ function getActiveAgent() {
|
|
|
16881
16926
|
} catch {
|
|
16882
16927
|
}
|
|
16883
16928
|
try {
|
|
16884
|
-
const sessionName =
|
|
16929
|
+
const sessionName = execSync12(
|
|
16885
16930
|
"tmux display-message -p '#{session_name}' 2>/dev/null",
|
|
16886
16931
|
{ encoding: "utf8", timeout: 2e3 }
|
|
16887
16932
|
).trim();
|
|
@@ -17606,7 +17651,7 @@ __export(exe_rename_exports, {
|
|
|
17606
17651
|
renameEmployee: () => renameEmployee
|
|
17607
17652
|
});
|
|
17608
17653
|
import { readFileSync as readFileSync25, writeFileSync as writeFileSync22, renameSync as renameSync6, unlinkSync as unlinkSync13, existsSync as existsSync29 } from "fs";
|
|
17609
|
-
import { execSync as
|
|
17654
|
+
import { execSync as execSync13 } from "child_process";
|
|
17610
17655
|
import path36 from "path";
|
|
17611
17656
|
import { homedir as homedir4 } from "os";
|
|
17612
17657
|
async function renameEmployee(oldName, newName, opts = {}) {
|
|
@@ -17747,7 +17792,7 @@ function rewriteRenamedEmployeeContent(content, oldName, newName) {
|
|
|
17747
17792
|
}
|
|
17748
17793
|
function findExeBin2() {
|
|
17749
17794
|
try {
|
|
17750
|
-
return
|
|
17795
|
+
return execSync13(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
17751
17796
|
} catch {
|
|
17752
17797
|
return null;
|
|
17753
17798
|
}
|
|
@@ -17999,12 +18044,14 @@ On EVERY new conversation, before doing anything else:
|
|
|
17999
18044
|
1. **Memory scan**: Run recall_my_memory with broad queries \u2014 "project", "client", "pipeline", "campaign", "deal", "decision", "blocker". Summarize what you find.
|
|
18000
18045
|
2. **Task scan**: Run list_tasks to see what's open, in progress, blocked, or needs review across all employees.
|
|
18001
18046
|
3. **Team check**: Run ask_team_memory for recent activity from CTO/CMO/engineers.
|
|
18002
|
-
4. **
|
|
18047
|
+
4. **Bug fix check** (one-time, never repeat): Call list_my_bug_reports to see if AskExe has fixed any previously filed bugs. If any have status "fixed" with a fixed_version, tell the founder: "\u{1F527} N bug fix(es) available \u2014 run \`exe-os update\` to get version X.Y.Z." Skip silently if none or if the call fails.
|
|
18048
|
+
5. **Present the brief**: Give the founder a concise status report:
|
|
18003
18049
|
- What's active and progressing
|
|
18004
18050
|
- What's blocked and needs attention
|
|
18005
18051
|
- What decisions are pending
|
|
18052
|
+
- Available bug fixes (from step 4, if any)
|
|
18006
18053
|
- What you recommend doing next
|
|
18007
|
-
|
|
18054
|
+
6. Then ask: "What's the priority?"
|
|
18008
18055
|
|
|
18009
18056
|
If this is your FIRST ever conversation (few or no prior memories):
|
|
18010
18057
|
- Search more broadly: "product", "SEO", "meeting", "strategy", "revenue"
|
|
@@ -18024,6 +18071,8 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
18024
18071
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
18025
18072
|
- **set_agent_config** \u2014 view or change which tool (Claude Code, Codex, OpenCode) and model each agent uses. Call with no args to show all agents' current settings. Call with agent_id + runtime + model to change.
|
|
18026
18073
|
- **send_message** \u2014 direct intercom to employees
|
|
18074
|
+
- **create_bug_report** \u2014 file a bug when you encounter an Exe OS platform issue
|
|
18075
|
+
- **list_my_bug_reports** \u2014 check status of filed bugs (boot check: surface available fixes to founder)
|
|
18027
18076
|
${PLAN_MODE_COMPAT}
|
|
18028
18077
|
## Completion Workflow
|
|
18029
18078
|
|
|
@@ -18453,7 +18502,7 @@ import {
|
|
|
18453
18502
|
readdirSync as readdirSync9,
|
|
18454
18503
|
unlinkSync as unlinkSync15
|
|
18455
18504
|
} from "fs";
|
|
18456
|
-
import { execSync as
|
|
18505
|
+
import { execSync as execSync14 } from "child_process";
|
|
18457
18506
|
import path38 from "path";
|
|
18458
18507
|
import { homedir as homedir5 } from "os";
|
|
18459
18508
|
function generateSessionWrappers(packageRoot, homeDir) {
|
|
@@ -18550,12 +18599,12 @@ function writeWrapper(wrapperPath, content) {
|
|
|
18550
18599
|
}
|
|
18551
18600
|
function resolveGlobalBinDir() {
|
|
18552
18601
|
try {
|
|
18553
|
-
const exeOsPath =
|
|
18602
|
+
const exeOsPath = execSync14("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
|
|
18554
18603
|
if (exeOsPath) return path38.dirname(exeOsPath);
|
|
18555
18604
|
} catch {
|
|
18556
18605
|
}
|
|
18557
18606
|
try {
|
|
18558
|
-
const prefix =
|
|
18607
|
+
const prefix = execSync14("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
|
|
18559
18608
|
if (prefix) return path38.join(prefix, "bin");
|
|
18560
18609
|
} catch {
|
|
18561
18610
|
}
|
|
@@ -18662,8 +18711,8 @@ function ask3(rl, prompt) {
|
|
|
18662
18711
|
function getAvailableMemoryGB2() {
|
|
18663
18712
|
if (process.platform === "darwin") {
|
|
18664
18713
|
try {
|
|
18665
|
-
const { execSync:
|
|
18666
|
-
const vmstat =
|
|
18714
|
+
const { execSync: execSync19 } = __require("child_process");
|
|
18715
|
+
const vmstat = execSync19("vm_stat", { encoding: "utf8" });
|
|
18667
18716
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
18668
18717
|
const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 16384;
|
|
18669
18718
|
const free = vmstat.match(/Pages free:\s+(\d+)/);
|
|
@@ -19524,7 +19573,7 @@ var init_update_backup = __esm({
|
|
|
19524
19573
|
});
|
|
19525
19574
|
|
|
19526
19575
|
// src/lib/update-check.ts
|
|
19527
|
-
import { execSync as
|
|
19576
|
+
import { execSync as execSync15 } from "child_process";
|
|
19528
19577
|
import { readFileSync as readFileSync28 } from "fs";
|
|
19529
19578
|
import path41 from "path";
|
|
19530
19579
|
function getLocalVersion(packageRoot) {
|
|
@@ -19534,7 +19583,7 @@ function getLocalVersion(packageRoot) {
|
|
|
19534
19583
|
}
|
|
19535
19584
|
function getRemoteVersion() {
|
|
19536
19585
|
try {
|
|
19537
|
-
const output2 =
|
|
19586
|
+
const output2 = execSync15("npm view @askexenow/exe-os version", {
|
|
19538
19587
|
encoding: "utf-8",
|
|
19539
19588
|
timeout: 15e3,
|
|
19540
19589
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -19573,7 +19622,7 @@ __export(update_exports, {
|
|
|
19573
19622
|
getRemoteVersion: () => getRemoteVersion,
|
|
19574
19623
|
runUpdate: () => runUpdate
|
|
19575
19624
|
});
|
|
19576
|
-
import { execSync as
|
|
19625
|
+
import { execSync as execSync16 } from "child_process";
|
|
19577
19626
|
import { createInterface as createInterface5 } from "readline";
|
|
19578
19627
|
async function runRestore() {
|
|
19579
19628
|
console.log("\n\u{1F504} Restoring from update backup...");
|
|
@@ -19584,7 +19633,7 @@ async function runRestore() {
|
|
|
19584
19633
|
console.log(`
|
|
19585
19634
|
\u{1F4E5} Reinstalling @askexenow/exe-os@${manifest.version}...`);
|
|
19586
19635
|
try {
|
|
19587
|
-
|
|
19636
|
+
execSync16(`npm install -g @askexenow/exe-os@${manifest.version}`, {
|
|
19588
19637
|
stdio: ["pipe", "pipe", "inherit"],
|
|
19589
19638
|
timeout: 3e5
|
|
19590
19639
|
});
|
|
@@ -19609,7 +19658,7 @@ async function runRestore() {
|
|
|
19609
19658
|
}
|
|
19610
19659
|
async function runUpdate(cliArgs) {
|
|
19611
19660
|
const args2 = cliArgs ?? process.argv.slice(2);
|
|
19612
|
-
const autoMode = args2.includes("--auto") || args2.includes("-y");
|
|
19661
|
+
const autoMode = args2.includes("--auto") || args2.includes("--yes") || args2.includes("-y");
|
|
19613
19662
|
const checkOnly = args2.includes("--check");
|
|
19614
19663
|
const restoreMode = args2.includes("--restore");
|
|
19615
19664
|
if (restoreMode) {
|
|
@@ -19661,7 +19710,7 @@ async function runUpdate(cliArgs) {
|
|
|
19661
19710
|
}
|
|
19662
19711
|
console.log("\u{1F9F9} Clearing npm cache...");
|
|
19663
19712
|
try {
|
|
19664
|
-
|
|
19713
|
+
execSync16("npm cache clean --force", { stdio: "pipe" });
|
|
19665
19714
|
console.log(" Done");
|
|
19666
19715
|
} catch {
|
|
19667
19716
|
console.log(" Skipped (non-critical)");
|
|
@@ -19669,7 +19718,7 @@ async function runUpdate(cliArgs) {
|
|
|
19669
19718
|
console.log("\u{1F4E5} Installing @askexenow/exe-os@latest...");
|
|
19670
19719
|
console.log(" This may take a minute...\n");
|
|
19671
19720
|
try {
|
|
19672
|
-
|
|
19721
|
+
execSync16("npm install -g @askexenow/exe-os@latest", {
|
|
19673
19722
|
stdio: ["pipe", "pipe", "inherit"],
|
|
19674
19723
|
timeout: 3e5
|
|
19675
19724
|
});
|
|
@@ -19687,7 +19736,7 @@ async function runUpdate(cliArgs) {
|
|
|
19687
19736
|
newVersion = getLocalVersion(packageRoot);
|
|
19688
19737
|
} catch {
|
|
19689
19738
|
try {
|
|
19690
|
-
const out =
|
|
19739
|
+
const out = execSync16("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
|
|
19691
19740
|
const match = out.match(/@askexenow\/exe-os@(\S+)/);
|
|
19692
19741
|
newVersion = match?.[1] ?? "unknown";
|
|
19693
19742
|
} catch {
|
|
@@ -19716,7 +19765,7 @@ async function runUpdate(cliArgs) {
|
|
|
19716
19765
|
}
|
|
19717
19766
|
console.log("\u{1F527} Re-registering MCP, hooks, wrappers, and daemon...");
|
|
19718
19767
|
try {
|
|
19719
|
-
|
|
19768
|
+
execSync16("exe-os-install --global", {
|
|
19720
19769
|
stdio: ["pipe", "inherit", "inherit"],
|
|
19721
19770
|
timeout: 3e5
|
|
19722
19771
|
});
|
|
@@ -19751,7 +19800,7 @@ async function runUpdate(cliArgs) {
|
|
|
19751
19800
|
}
|
|
19752
19801
|
try {
|
|
19753
19802
|
console.log("\u{1FA7A} Checking AskExe support intake...");
|
|
19754
|
-
|
|
19803
|
+
execSync16("exe-os support health", {
|
|
19755
19804
|
stdio: ["pipe", "inherit", "inherit"],
|
|
19756
19805
|
timeout: 3e4
|
|
19757
19806
|
});
|
|
@@ -20074,6 +20123,9 @@ function installDockerUbuntu(exec2) {
|
|
|
20074
20123
|
function randomSecret(bytes = 32) {
|
|
20075
20124
|
return randomBytes2(bytes).toString("base64url");
|
|
20076
20125
|
}
|
|
20126
|
+
function randomHexSecret(bytes = 24) {
|
|
20127
|
+
return randomBytes2(bytes).toString("hex");
|
|
20128
|
+
}
|
|
20077
20129
|
function hydrateEnv(raw, opts) {
|
|
20078
20130
|
let next = raw;
|
|
20079
20131
|
const license = opts.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense() || "";
|
|
@@ -20083,6 +20135,8 @@ function hydrateEnv(raw, opts) {
|
|
|
20083
20135
|
for (const [key, value] of env.entries()) {
|
|
20084
20136
|
if (!/CHANGEME/.test(value)) continue;
|
|
20085
20137
|
if (key === "EXE_LICENSE_KEY" && license) replacements[key] = license;
|
|
20138
|
+
else if (key === "MONITOR_AGENT_KEY") continue;
|
|
20139
|
+
else if (key === "EXE_GATEWAY_WS_RELAY_AUTH_TOKEN") replacements[key] = randomHexSecret(24);
|
|
20086
20140
|
else if (key.endsWith("_PASSWORD")) replacements[key] = randomSecret(24);
|
|
20087
20141
|
else if (key.endsWith("_SECRET") || key.endsWith("_TOKEN") || key.endsWith("_KEY") || key.endsWith("_SALT")) replacements[key] = value.replace(/CHANGEME[A-Z0-9_]*/g, randomSecret(32));
|
|
20088
20142
|
else if (key === "EXED_MCP_TOKEN") replacements[key] = randomSecret(32);
|
|
@@ -20342,7 +20396,9 @@ function defaultStackPaths() {
|
|
|
20342
20396
|
// Packaged manifests keep cold-start installs unblocked even before update-service entitlements are provisioned.
|
|
20343
20397
|
auditUrl: process.env.EXE_STACK_AUDIT_URL || (/^https?:\/\//.test(manifestRef) ? "https://update.askexe.com/v1/deploy-audits" : void 0),
|
|
20344
20398
|
imageCredentialsUrl: process.env.EXE_STACK_IMAGE_CREDENTIALS_URL || (/^https?:\/\//.test(manifestRef) ? "https://update.askexe.com/v1/image-credentials" : void 0),
|
|
20345
|
-
|
|
20399
|
+
// License key IS the auth token for update.askexe.com — no separate update token needed.
|
|
20400
|
+
// EXE_STACK_UPDATE_TOKEN kept as legacy fallback during migration.
|
|
20401
|
+
manifestAuthToken: process.env.EXE_LICENSE_KEY || loadLicense() || process.env.EXE_STACK_UPDATE_TOKEN || void 0,
|
|
20346
20402
|
manifestPublicKey: loadDefaultPublicKey()
|
|
20347
20403
|
};
|
|
20348
20404
|
}
|
|
@@ -20482,7 +20538,14 @@ function printChanges(changes, composeFile, envFile) {
|
|
|
20482
20538
|
if (changes.length === 0) {
|
|
20483
20539
|
const running = areCliContainersRunning(composeFile, envFile);
|
|
20484
20540
|
if (running) {
|
|
20485
|
-
console.log("
|
|
20541
|
+
console.log("Stack .env matches target manifest. Checking container health...\n");
|
|
20542
|
+
const unhealthy = printContainerHealth(composeFile, envFile);
|
|
20543
|
+
if (unhealthy > 0) {
|
|
20544
|
+
console.log(`
|
|
20545
|
+
\u{1F534} ${unhealthy} service(s) unhealthy or crashlooping. Run \`docker compose logs <service>\` to diagnose.`);
|
|
20546
|
+
} else {
|
|
20547
|
+
console.log("\n\u2705 Stack already matches target manifest. All services healthy.");
|
|
20548
|
+
}
|
|
20486
20549
|
} else {
|
|
20487
20550
|
console.log("\u26A0\uFE0F Stack .env matches target manifest but containers are not running. Will start them.");
|
|
20488
20551
|
}
|
|
@@ -20505,6 +20568,49 @@ function areCliContainersRunning(composeFile, envFile) {
|
|
|
20505
20568
|
return false;
|
|
20506
20569
|
}
|
|
20507
20570
|
}
|
|
20571
|
+
function getContainerHealth(composeFile, envFile) {
|
|
20572
|
+
try {
|
|
20573
|
+
const result = spawnSync2(
|
|
20574
|
+
"docker",
|
|
20575
|
+
["compose", "--file", composeFile, "--env-file", envFile, "ps", "--format", "json"],
|
|
20576
|
+
{ stdio: ["pipe", "pipe", "pipe"], timeout: 15e3 }
|
|
20577
|
+
);
|
|
20578
|
+
if (result.status !== 0) return [];
|
|
20579
|
+
const raw = result.stdout?.toString().trim() ?? "";
|
|
20580
|
+
if (!raw) return [];
|
|
20581
|
+
return raw.split("\n").filter(Boolean).map((line) => {
|
|
20582
|
+
try {
|
|
20583
|
+
const obj = JSON.parse(line);
|
|
20584
|
+
return {
|
|
20585
|
+
service: obj.Service ?? obj.Name ?? "unknown",
|
|
20586
|
+
state: obj.State ?? "unknown",
|
|
20587
|
+
health: obj.Health ?? "",
|
|
20588
|
+
restartCount: typeof obj.RestartCount === "number" ? obj.RestartCount : 0
|
|
20589
|
+
};
|
|
20590
|
+
} catch {
|
|
20591
|
+
return null;
|
|
20592
|
+
}
|
|
20593
|
+
}).filter((x) => x !== null);
|
|
20594
|
+
} catch {
|
|
20595
|
+
return [];
|
|
20596
|
+
}
|
|
20597
|
+
}
|
|
20598
|
+
function printContainerHealth(composeFile, envFile) {
|
|
20599
|
+
const containers = getContainerHealth(composeFile, envFile);
|
|
20600
|
+
if (containers.length === 0) return 0;
|
|
20601
|
+
let unhealthy = 0;
|
|
20602
|
+
for (const c of containers) {
|
|
20603
|
+
const isRestarting = c.state === "restarting" || c.restartCount > 2;
|
|
20604
|
+
const isUnhealthy = c.health === "unhealthy" || c.state === "dead" || c.state === "exited";
|
|
20605
|
+
if (isRestarting || isUnhealthy) {
|
|
20606
|
+
unhealthy++;
|
|
20607
|
+
console.log(` \u274C ${c.service}: ${c.state} (restarts: ${c.restartCount}${c.health ? `, health: ${c.health}` : ""})`);
|
|
20608
|
+
} else {
|
|
20609
|
+
console.log(` \u2705 ${c.service}: ${c.state}${c.health ? ` (${c.health})` : ""}`);
|
|
20610
|
+
}
|
|
20611
|
+
}
|
|
20612
|
+
return unhealthy;
|
|
20613
|
+
}
|
|
20508
20614
|
function printBreaking(changes) {
|
|
20509
20615
|
if (changes.length === 0) return;
|
|
20510
20616
|
console.log("\nBreaking-change notices:");
|
|
@@ -27253,13 +27359,13 @@ __export(tmux_status_exports, {
|
|
|
27253
27359
|
parseActivity: () => parseActivity,
|
|
27254
27360
|
parseContextPercentage: () => parseContextPercentage
|
|
27255
27361
|
});
|
|
27256
|
-
import { execSync as
|
|
27362
|
+
import { execSync as execSync17 } from "child_process";
|
|
27257
27363
|
function inTmux() {
|
|
27258
27364
|
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
27259
27365
|
const term = process.env.TERM ?? "";
|
|
27260
27366
|
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
27261
27367
|
try {
|
|
27262
|
-
|
|
27368
|
+
execSync17("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
27263
27369
|
encoding: "utf8",
|
|
27264
27370
|
timeout: 2e3
|
|
27265
27371
|
});
|
|
@@ -27269,12 +27375,12 @@ function inTmux() {
|
|
|
27269
27375
|
try {
|
|
27270
27376
|
let pid = process.ppid;
|
|
27271
27377
|
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
27272
|
-
const comm =
|
|
27378
|
+
const comm = execSync17(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
27273
27379
|
encoding: "utf8",
|
|
27274
27380
|
timeout: 1e3
|
|
27275
27381
|
}).trim();
|
|
27276
27382
|
if (/tmux/.test(comm)) return true;
|
|
27277
|
-
const ppid =
|
|
27383
|
+
const ppid = execSync17(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
27278
27384
|
encoding: "utf8",
|
|
27279
27385
|
timeout: 1e3
|
|
27280
27386
|
}).trim();
|
|
@@ -27287,7 +27393,7 @@ function inTmux() {
|
|
|
27287
27393
|
}
|
|
27288
27394
|
function listTmuxSessions() {
|
|
27289
27395
|
try {
|
|
27290
|
-
const out =
|
|
27396
|
+
const out = execSync17("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
27291
27397
|
encoding: "utf8",
|
|
27292
27398
|
timeout: 3e3
|
|
27293
27399
|
});
|
|
@@ -27298,7 +27404,7 @@ function listTmuxSessions() {
|
|
|
27298
27404
|
}
|
|
27299
27405
|
function capturePaneLines(windowName, lines = 10) {
|
|
27300
27406
|
try {
|
|
27301
|
-
const out =
|
|
27407
|
+
const out = execSync17(
|
|
27302
27408
|
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
27303
27409
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27304
27410
|
);
|
|
@@ -27309,7 +27415,7 @@ function capturePaneLines(windowName, lines = 10) {
|
|
|
27309
27415
|
}
|
|
27310
27416
|
function getPaneCwd(windowName) {
|
|
27311
27417
|
try {
|
|
27312
|
-
const out =
|
|
27418
|
+
const out = execSync17(
|
|
27313
27419
|
`tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
|
|
27314
27420
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27315
27421
|
);
|
|
@@ -27320,7 +27426,7 @@ function getPaneCwd(windowName) {
|
|
|
27320
27426
|
}
|
|
27321
27427
|
function projectFromPath(dir) {
|
|
27322
27428
|
try {
|
|
27323
|
-
const root =
|
|
27429
|
+
const root = execSync17("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
|
|
27324
27430
|
encoding: "utf8",
|
|
27325
27431
|
timeout: 3e3
|
|
27326
27432
|
}).trim();
|
|
@@ -27389,7 +27495,7 @@ function getEmployeeStatuses(employeeNames) {
|
|
|
27389
27495
|
}
|
|
27390
27496
|
let paneAlive = true;
|
|
27391
27497
|
try {
|
|
27392
|
-
const paneStatus =
|
|
27498
|
+
const paneStatus = execSync17(
|
|
27393
27499
|
`tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
|
|
27394
27500
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27395
27501
|
).trim();
|
|
@@ -27579,8 +27685,8 @@ function Footer() {
|
|
|
27579
27685
|
setSessions(allSessions.length);
|
|
27580
27686
|
if (!currentSession) {
|
|
27581
27687
|
try {
|
|
27582
|
-
const { execSync:
|
|
27583
|
-
const name =
|
|
27688
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
27689
|
+
const name = execSync19("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
27584
27690
|
encoding: "utf8",
|
|
27585
27691
|
timeout: 2e3
|
|
27586
27692
|
}).trim();
|
|
@@ -30934,8 +31040,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
30934
31040
|
}
|
|
30935
31041
|
const capture = () => {
|
|
30936
31042
|
try {
|
|
30937
|
-
const { execSync:
|
|
30938
|
-
const output2 =
|
|
31043
|
+
const { execSync: execSync19 } = __require("child_process");
|
|
31044
|
+
const output2 = execSync19(
|
|
30939
31045
|
`tmux capture-pane -t ${JSON.stringify(sessionName)} -p -e 2>/dev/null | tail -${CAPTURE_LINES}`,
|
|
30940
31046
|
{ encoding: "utf8", timeout: 3e3 }
|
|
30941
31047
|
);
|
|
@@ -30959,8 +31065,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
30959
31065
|
if (key.return) {
|
|
30960
31066
|
if (!demo && inputBuffer.trim()) {
|
|
30961
31067
|
try {
|
|
30962
|
-
const { execSync:
|
|
30963
|
-
|
|
31068
|
+
const { execSync: execSync19 } = __require("child_process");
|
|
31069
|
+
execSync19(
|
|
30964
31070
|
`tmux send-keys -t ${JSON.stringify(sessionName)} ${JSON.stringify(inputBuffer)} Enter`,
|
|
30965
31071
|
{ timeout: 2e3 }
|
|
30966
31072
|
);
|
|
@@ -30968,8 +31074,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
30968
31074
|
}
|
|
30969
31075
|
} else if (!demo) {
|
|
30970
31076
|
try {
|
|
30971
|
-
const { execSync:
|
|
30972
|
-
|
|
31077
|
+
const { execSync: execSync19 } = __require("child_process");
|
|
31078
|
+
execSync19(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
|
|
30973
31079
|
} catch {
|
|
30974
31080
|
}
|
|
30975
31081
|
}
|
|
@@ -31656,12 +31762,12 @@ function SessionsView({
|
|
|
31656
31762
|
return;
|
|
31657
31763
|
}
|
|
31658
31764
|
} else {
|
|
31659
|
-
const { execSync:
|
|
31765
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
31660
31766
|
const dir = projectDir || process.cwd();
|
|
31661
|
-
|
|
31662
|
-
|
|
31767
|
+
execSync19(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
|
|
31768
|
+
execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
|
|
31663
31769
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
31664
|
-
|
|
31770
|
+
execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
|
|
31665
31771
|
}
|
|
31666
31772
|
const updated = { ...entry, status: "active", activity: "Starting...", attached: false };
|
|
31667
31773
|
setViewingEmployee(updated);
|
|
@@ -31764,7 +31870,7 @@ function SessionsView({
|
|
|
31764
31870
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
31765
31871
|
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
31766
31872
|
const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
31767
|
-
const { execSync:
|
|
31873
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
31768
31874
|
if (!inTmux2()) {
|
|
31769
31875
|
setTmuxAvailable(false);
|
|
31770
31876
|
setProjects([]);
|
|
@@ -31773,7 +31879,7 @@ function SessionsView({
|
|
|
31773
31879
|
setTmuxAvailable(true);
|
|
31774
31880
|
const attachedMap = /* @__PURE__ */ new Map();
|
|
31775
31881
|
try {
|
|
31776
|
-
const out =
|
|
31882
|
+
const out = execSync19("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
|
|
31777
31883
|
encoding: "utf8",
|
|
31778
31884
|
timeout: 3e3
|
|
31779
31885
|
});
|
|
@@ -32809,8 +32915,8 @@ function upsertConversation(conversations, platform, senderId, message) {
|
|
|
32809
32915
|
async function loadGatewayConfig() {
|
|
32810
32916
|
const state = { running: false, port: 3100, adapters: [], agents: [], gatewayUrl: "" };
|
|
32811
32917
|
try {
|
|
32812
|
-
const { execSync:
|
|
32813
|
-
const ps =
|
|
32918
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
32919
|
+
const ps = execSync19("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
|
|
32814
32920
|
state.running = ps.trim().length > 0;
|
|
32815
32921
|
} catch {
|
|
32816
32922
|
state.running = false;
|
|
@@ -33287,10 +33393,10 @@ var init_Gateway = __esm({
|
|
|
33287
33393
|
});
|
|
33288
33394
|
|
|
33289
33395
|
// src/tui/utils/agent-status.ts
|
|
33290
|
-
import { execSync as
|
|
33396
|
+
import { execSync as execSync18 } from "child_process";
|
|
33291
33397
|
function getAgentStatus(agentId) {
|
|
33292
33398
|
try {
|
|
33293
|
-
const sessions =
|
|
33399
|
+
const sessions = execSync18("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
33294
33400
|
encoding: "utf8",
|
|
33295
33401
|
timeout: 2e3
|
|
33296
33402
|
}).trim().split("\n");
|
|
@@ -33301,7 +33407,7 @@ function getAgentStatus(agentId) {
|
|
|
33301
33407
|
return /^\d?-/.test(suffix) || /^\d+$/.test(suffix);
|
|
33302
33408
|
});
|
|
33303
33409
|
if (!agentSession) return { label: "offline", color: "gray" };
|
|
33304
|
-
const pane =
|
|
33410
|
+
const pane = execSync18(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
|
|
33305
33411
|
encoding: "utf8",
|
|
33306
33412
|
timeout: 2e3
|
|
33307
33413
|
});
|
|
@@ -34224,8 +34330,8 @@ function SettingsView({ onBack }) {
|
|
|
34224
34330
|
};
|
|
34225
34331
|
});
|
|
34226
34332
|
try {
|
|
34227
|
-
const { execSync:
|
|
34228
|
-
|
|
34333
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
34334
|
+
execSync19("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
|
|
34229
34335
|
providerList.push({ name: "Ollama", configured: true, detail: "localhost:11434" });
|
|
34230
34336
|
} catch {
|
|
34231
34337
|
providerList.push({ name: "Ollama", configured: false, detail: "not running" });
|
|
@@ -35115,16 +35221,89 @@ var code_context_index_exports = {};
|
|
|
35115
35221
|
__export(code_context_index_exports, {
|
|
35116
35222
|
analyzeBlastRadius: () => analyzeBlastRadius,
|
|
35117
35223
|
buildCodeContextIndex: () => buildCodeContextIndex,
|
|
35224
|
+
buildCodeContextIndexWithEmbeddings: () => buildCodeContextIndexWithEmbeddings,
|
|
35118
35225
|
getCodeContextIndexPath: () => getCodeContextIndexPath,
|
|
35119
35226
|
getCodeContextStats: () => getCodeContextStats,
|
|
35120
35227
|
loadOrBuildCodeContextIndex: () => loadOrBuildCodeContextIndex,
|
|
35121
35228
|
searchCodeContext: () => searchCodeContext,
|
|
35229
|
+
searchCodeContextSemantic: () => searchCodeContextSemantic,
|
|
35122
35230
|
traceCodeSymbol: () => traceCodeSymbol
|
|
35123
35231
|
});
|
|
35124
35232
|
import crypto14 from "crypto";
|
|
35125
35233
|
import path51 from "path";
|
|
35126
35234
|
import { existsSync as existsSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync32, readdirSync as readdirSync11, statSync as statSync7, writeFileSync as writeFileSync26 } from "fs";
|
|
35127
35235
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
35236
|
+
function vectorStorePath(projectRoot) {
|
|
35237
|
+
const rootHash = hashText(projectRoot).slice(0, 16);
|
|
35238
|
+
return path51.join(indexDir(), `${rootHash}.vectors.json`);
|
|
35239
|
+
}
|
|
35240
|
+
function loadVectorStore(projectRoot) {
|
|
35241
|
+
const file = vectorStorePath(projectRoot);
|
|
35242
|
+
if (!existsSync36(file)) return null;
|
|
35243
|
+
try {
|
|
35244
|
+
const parsed = JSON.parse(readFileSync32(file, "utf8"));
|
|
35245
|
+
if (parsed.version !== VECTOR_STORE_VERSION) return null;
|
|
35246
|
+
return parsed;
|
|
35247
|
+
} catch {
|
|
35248
|
+
return null;
|
|
35249
|
+
}
|
|
35250
|
+
}
|
|
35251
|
+
function saveVectorStore(projectRoot, store) {
|
|
35252
|
+
writeFileSync26(vectorStorePath(projectRoot), JSON.stringify(store));
|
|
35253
|
+
}
|
|
35254
|
+
function cosineSimilarity(a, b) {
|
|
35255
|
+
let dot = 0, normA = 0, normB = 0;
|
|
35256
|
+
for (let i = 0; i < a.length; i++) {
|
|
35257
|
+
dot += a[i] * b[i];
|
|
35258
|
+
normA += a[i] * a[i];
|
|
35259
|
+
normB += b[i] * b[i];
|
|
35260
|
+
}
|
|
35261
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
35262
|
+
return denom === 0 ? 0 : dot / denom;
|
|
35263
|
+
}
|
|
35264
|
+
async function embedSymbols(index) {
|
|
35265
|
+
const rootHash = hashText(index.projectRoot).slice(0, 16);
|
|
35266
|
+
const existing = loadVectorStore(index.projectRoot);
|
|
35267
|
+
const store = {
|
|
35268
|
+
version: VECTOR_STORE_VERSION,
|
|
35269
|
+
projectRootHash: rootHash,
|
|
35270
|
+
vectors: {}
|
|
35271
|
+
};
|
|
35272
|
+
const allSymbols = [];
|
|
35273
|
+
for (const file of Object.values(index.files)) {
|
|
35274
|
+
for (const symbol of file.symbols) {
|
|
35275
|
+
if (existing?.vectors[symbol.id]) {
|
|
35276
|
+
store.vectors[symbol.id] = existing.vectors[symbol.id];
|
|
35277
|
+
} else {
|
|
35278
|
+
allSymbols.push({ id: symbol.id, text: symbol.summary || `${symbol.kind} ${symbol.name} in ${symbol.filePath}` });
|
|
35279
|
+
}
|
|
35280
|
+
}
|
|
35281
|
+
}
|
|
35282
|
+
if (allSymbols.length === 0) {
|
|
35283
|
+
saveVectorStore(index.projectRoot, store);
|
|
35284
|
+
return store;
|
|
35285
|
+
}
|
|
35286
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
35287
|
+
if (!connected) {
|
|
35288
|
+
saveVectorStore(index.projectRoot, store);
|
|
35289
|
+
return store;
|
|
35290
|
+
}
|
|
35291
|
+
for (let i = 0; i < allSymbols.length; i += EMBED_BATCH_SIZE) {
|
|
35292
|
+
const batch = allSymbols.slice(i, i + EMBED_BATCH_SIZE);
|
|
35293
|
+
const texts = batch.map((s) => s.text);
|
|
35294
|
+
try {
|
|
35295
|
+
const vectors = await embedBatchViaClient(texts, "low");
|
|
35296
|
+
if (vectors && vectors.length === batch.length) {
|
|
35297
|
+
for (let j = 0; j < batch.length; j++) {
|
|
35298
|
+
store.vectors[batch[j].id] = vectors[j];
|
|
35299
|
+
}
|
|
35300
|
+
}
|
|
35301
|
+
} catch {
|
|
35302
|
+
}
|
|
35303
|
+
}
|
|
35304
|
+
saveVectorStore(index.projectRoot, store);
|
|
35305
|
+
return store;
|
|
35306
|
+
}
|
|
35128
35307
|
function normalizeProjectRoot(projectRoot) {
|
|
35129
35308
|
return path51.resolve(projectRoot || process.cwd());
|
|
35130
35309
|
}
|
|
@@ -35400,7 +35579,7 @@ function filteredFiles(index, options = {}) {
|
|
|
35400
35579
|
return matchesPath(file.path, options.paths);
|
|
35401
35580
|
});
|
|
35402
35581
|
}
|
|
35403
|
-
function
|
|
35582
|
+
function lexicalSearch(query, options = {}) {
|
|
35404
35583
|
const terms = tokenize2(query);
|
|
35405
35584
|
if (terms.length === 0) return [];
|
|
35406
35585
|
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
@@ -35426,6 +35605,81 @@ function searchCodeContext(query, options = {}) {
|
|
|
35426
35605
|
const limit = options.limit ?? 20;
|
|
35427
35606
|
return results.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
35428
35607
|
}
|
|
35608
|
+
function searchCodeContext(query, options = {}) {
|
|
35609
|
+
return lexicalSearch(query, options);
|
|
35610
|
+
}
|
|
35611
|
+
async function searchCodeContextSemantic(query, options = {}) {
|
|
35612
|
+
const terms = tokenize2(query);
|
|
35613
|
+
if (terms.length === 0) return [];
|
|
35614
|
+
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
35615
|
+
const projectRoot = normalizeProjectRoot(options.projectRoot);
|
|
35616
|
+
const vectorStore = loadVectorStore(projectRoot);
|
|
35617
|
+
if (!vectorStore || Object.keys(vectorStore.vectors).length === 0) {
|
|
35618
|
+
return lexicalSearch(query, options);
|
|
35619
|
+
}
|
|
35620
|
+
let queryVector = null;
|
|
35621
|
+
try {
|
|
35622
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
35623
|
+
if (connected) {
|
|
35624
|
+
const result = await embedBatchViaClient([query], "high");
|
|
35625
|
+
if (result && result.length === 1) queryVector = result[0];
|
|
35626
|
+
}
|
|
35627
|
+
} catch {
|
|
35628
|
+
}
|
|
35629
|
+
if (!queryVector) return lexicalSearch(query, options);
|
|
35630
|
+
const files = filteredFiles(index, options);
|
|
35631
|
+
const candidates = [];
|
|
35632
|
+
for (const file of files) {
|
|
35633
|
+
for (const symbol of file.symbols) {
|
|
35634
|
+
const lexical = scoreSymbol(symbol, terms);
|
|
35635
|
+
const vec = vectorStore.vectors[symbol.id];
|
|
35636
|
+
const vectorScore = vec ? cosineSimilarity(queryVector, vec) : 0;
|
|
35637
|
+
if (lexical.score > 0 || vectorScore > 0.3) {
|
|
35638
|
+
candidates.push({
|
|
35639
|
+
symbol,
|
|
35640
|
+
lexicalScore: lexical.score,
|
|
35641
|
+
vectorScore,
|
|
35642
|
+
matches: lexical.matches
|
|
35643
|
+
});
|
|
35644
|
+
}
|
|
35645
|
+
}
|
|
35646
|
+
}
|
|
35647
|
+
const byLexical = [...candidates].sort((a, b) => b.lexicalScore - a.lexicalScore);
|
|
35648
|
+
const byVector = [...candidates].sort((a, b) => b.vectorScore - a.vectorScore);
|
|
35649
|
+
const lexicalRank = /* @__PURE__ */ new Map();
|
|
35650
|
+
const vectorRank = /* @__PURE__ */ new Map();
|
|
35651
|
+
byLexical.forEach((c, i) => lexicalRank.set(c.symbol.id, i + 1));
|
|
35652
|
+
byVector.forEach((c, i) => vectorRank.set(c.symbol.id, i + 1));
|
|
35653
|
+
const VECTOR_WEIGHT = 0.6;
|
|
35654
|
+
const LEXICAL_WEIGHT = 0.4;
|
|
35655
|
+
const fused = candidates.map((c) => {
|
|
35656
|
+
const lRank = lexicalRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
35657
|
+
const vRank = vectorRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
35658
|
+
const rrfScore = VECTOR_WEIGHT * (1 / (RRF_K + vRank)) + LEXICAL_WEIGHT * (1 / (RRF_K + lRank));
|
|
35659
|
+
return {
|
|
35660
|
+
symbol: c.symbol,
|
|
35661
|
+
score: rrfScore,
|
|
35662
|
+
matches: c.vectorScore > 0.3 ? [...c.matches, `semantic=${c.vectorScore.toFixed(3)}`] : c.matches,
|
|
35663
|
+
filePath: c.symbol.filePath,
|
|
35664
|
+
language: c.symbol.language,
|
|
35665
|
+
content: c.symbol.text,
|
|
35666
|
+
startLine: c.symbol.startLine,
|
|
35667
|
+
endLine: c.symbol.endLine
|
|
35668
|
+
};
|
|
35669
|
+
});
|
|
35670
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
35671
|
+
const limit = options.limit ?? 20;
|
|
35672
|
+
return fused.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
35673
|
+
}
|
|
35674
|
+
async function buildCodeContextIndexWithEmbeddings(options = {}) {
|
|
35675
|
+
const index = buildCodeContextIndex(options);
|
|
35676
|
+
const existingStore = loadVectorStore(index.projectRoot);
|
|
35677
|
+
const existingCount = existingStore ? Object.keys(existingStore.vectors).length : 0;
|
|
35678
|
+
const store = await embedSymbols(index);
|
|
35679
|
+
const vectorCount = Object.keys(store.vectors).length;
|
|
35680
|
+
const newEmbeddings = vectorCount - Math.min(existingCount, vectorCount);
|
|
35681
|
+
return { index, vectorCount, newEmbeddings };
|
|
35682
|
+
}
|
|
35429
35683
|
function dependentsMap(index) {
|
|
35430
35684
|
const map = /* @__PURE__ */ new Map();
|
|
35431
35685
|
for (const file of Object.values(index.files)) {
|
|
@@ -35517,15 +35771,19 @@ function getCodeContextStats(options = {}) {
|
|
|
35517
35771
|
indexPath: getCodeContextIndexPath(index.projectRoot)
|
|
35518
35772
|
};
|
|
35519
35773
|
}
|
|
35520
|
-
var INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS;
|
|
35774
|
+
var VECTOR_STORE_VERSION, EMBED_BATCH_SIZE, INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS, RRF_K;
|
|
35521
35775
|
var init_code_context_index = __esm({
|
|
35522
35776
|
"src/lib/code-context-index.ts"() {
|
|
35523
35777
|
"use strict";
|
|
35524
35778
|
init_config();
|
|
35525
35779
|
init_code_chunker();
|
|
35780
|
+
init_exe_daemon_client();
|
|
35781
|
+
VECTOR_STORE_VERSION = 1;
|
|
35782
|
+
EMBED_BATCH_SIZE = 64;
|
|
35526
35783
|
INDEX_VERSION = 2;
|
|
35527
35784
|
DEFAULT_MAX_FILES = 5e3;
|
|
35528
35785
|
IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
35786
|
+
RRF_K = 60;
|
|
35529
35787
|
}
|
|
35530
35788
|
});
|
|
35531
35789
|
|
|
@@ -37024,10 +37282,10 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37024
37282
|
}
|
|
37025
37283
|
}
|
|
37026
37284
|
try {
|
|
37027
|
-
const { execSync:
|
|
37285
|
+
const { execSync: execSync19 } = await import("child_process");
|
|
37028
37286
|
const findExeBin3 = () => {
|
|
37029
37287
|
try {
|
|
37030
|
-
return
|
|
37288
|
+
return execSync19(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
37031
37289
|
} catch {
|
|
37032
37290
|
return null;
|
|
37033
37291
|
}
|