@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/lib/exe-daemon.js
CHANGED
|
@@ -1501,7 +1501,7 @@ __export(exe_daemon_client_exports, {
|
|
|
1501
1501
|
});
|
|
1502
1502
|
import net from "net";
|
|
1503
1503
|
import os4 from "os";
|
|
1504
|
-
import { spawn } from "child_process";
|
|
1504
|
+
import { spawn, execSync as execSync2 } from "child_process";
|
|
1505
1505
|
import { randomUUID } from "crypto";
|
|
1506
1506
|
import { existsSync as existsSync7, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
|
|
1507
1507
|
import path7 from "path";
|
|
@@ -1531,6 +1531,14 @@ function handleData(chunk) {
|
|
|
1531
1531
|
}
|
|
1532
1532
|
}
|
|
1533
1533
|
}
|
|
1534
|
+
function isZombie(pid) {
|
|
1535
|
+
try {
|
|
1536
|
+
const state = execSync2(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
1537
|
+
return state.startsWith("Z");
|
|
1538
|
+
} catch {
|
|
1539
|
+
return false;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1534
1542
|
function cleanupStaleFiles() {
|
|
1535
1543
|
if (existsSync7(PID_PATH)) {
|
|
1536
1544
|
try {
|
|
@@ -1538,7 +1546,11 @@ function cleanupStaleFiles() {
|
|
|
1538
1546
|
if (pid > 0) {
|
|
1539
1547
|
try {
|
|
1540
1548
|
process.kill(pid, 0);
|
|
1541
|
-
|
|
1549
|
+
if (!isZombie(pid)) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
|
|
1553
|
+
`);
|
|
1542
1554
|
} catch {
|
|
1543
1555
|
}
|
|
1544
1556
|
}
|
|
@@ -1566,8 +1578,8 @@ function findPackageRoot() {
|
|
|
1566
1578
|
function getAvailableMemoryGB() {
|
|
1567
1579
|
if (process.platform === "darwin") {
|
|
1568
1580
|
try {
|
|
1569
|
-
const { execSync:
|
|
1570
|
-
const vmstat =
|
|
1581
|
+
const { execSync: execSync18 } = __require("child_process");
|
|
1582
|
+
const vmstat = execSync18("vm_stat", { encoding: "utf8" });
|
|
1571
1583
|
const pageSize = 16384;
|
|
1572
1584
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1573
1585
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3458,6 +3470,12 @@ async function disposeDatabase() {
|
|
|
3458
3470
|
clearInterval(_walCheckpointTimer);
|
|
3459
3471
|
_walCheckpointTimer = null;
|
|
3460
3472
|
}
|
|
3473
|
+
if (_client) {
|
|
3474
|
+
try {
|
|
3475
|
+
await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
3476
|
+
} catch {
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3461
3479
|
if (_daemonClient) {
|
|
3462
3480
|
_daemonClient.close();
|
|
3463
3481
|
_daemonClient = null;
|
|
@@ -5198,7 +5216,7 @@ __export(keychain_exports, {
|
|
|
5198
5216
|
});
|
|
5199
5217
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
5200
5218
|
import { existsSync as existsSync11, statSync as statSync4 } from "fs";
|
|
5201
|
-
import { execSync as
|
|
5219
|
+
import { execSync as execSync3 } from "child_process";
|
|
5202
5220
|
import path11 from "path";
|
|
5203
5221
|
import os6 from "os";
|
|
5204
5222
|
function getKeyDir() {
|
|
@@ -5215,13 +5233,13 @@ function linuxSecretAvailable() {
|
|
|
5215
5233
|
if (process.platform !== "linux") return false;
|
|
5216
5234
|
if (linuxSecretAvailability !== null) return linuxSecretAvailability;
|
|
5217
5235
|
try {
|
|
5218
|
-
|
|
5236
|
+
execSync3("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
|
|
5219
5237
|
} catch {
|
|
5220
5238
|
linuxSecretAvailability = false;
|
|
5221
5239
|
return false;
|
|
5222
5240
|
}
|
|
5223
5241
|
try {
|
|
5224
|
-
|
|
5242
|
+
execSync3("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
|
|
5225
5243
|
linuxSecretAvailability = true;
|
|
5226
5244
|
} catch {
|
|
5227
5245
|
linuxSecretAvailability = false;
|
|
@@ -5245,7 +5263,7 @@ function macKeychainGet(service = SERVICE) {
|
|
|
5245
5263
|
if (!nativeKeychainAllowed()) return null;
|
|
5246
5264
|
if (process.platform !== "darwin") return null;
|
|
5247
5265
|
try {
|
|
5248
|
-
return
|
|
5266
|
+
return execSync3(
|
|
5249
5267
|
`security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
5250
5268
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
5251
5269
|
).trim();
|
|
@@ -5258,13 +5276,13 @@ function macKeychainSet(value, service = SERVICE) {
|
|
|
5258
5276
|
if (process.platform !== "darwin") return false;
|
|
5259
5277
|
try {
|
|
5260
5278
|
try {
|
|
5261
|
-
|
|
5279
|
+
execSync3(
|
|
5262
5280
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
5263
5281
|
{ timeout: 5e3 }
|
|
5264
5282
|
);
|
|
5265
5283
|
} catch {
|
|
5266
5284
|
}
|
|
5267
|
-
|
|
5285
|
+
execSync3(
|
|
5268
5286
|
`security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
|
|
5269
5287
|
{ timeout: 5e3 }
|
|
5270
5288
|
);
|
|
@@ -5277,7 +5295,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
5277
5295
|
if (!nativeKeychainAllowed()) return false;
|
|
5278
5296
|
if (process.platform !== "darwin") return false;
|
|
5279
5297
|
try {
|
|
5280
|
-
|
|
5298
|
+
execSync3(
|
|
5281
5299
|
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
5282
5300
|
{ timeout: 5e3 }
|
|
5283
5301
|
);
|
|
@@ -5289,7 +5307,7 @@ function macKeychainDelete(service = SERVICE) {
|
|
|
5289
5307
|
function linuxSecretGet(service = SERVICE) {
|
|
5290
5308
|
if (!linuxSecretAvailable()) return null;
|
|
5291
5309
|
try {
|
|
5292
|
-
return
|
|
5310
|
+
return execSync3(
|
|
5293
5311
|
`secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
5294
5312
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
5295
5313
|
).trim();
|
|
@@ -5300,7 +5318,7 @@ function linuxSecretGet(service = SERVICE) {
|
|
|
5300
5318
|
function linuxSecretSet(value, service = SERVICE) {
|
|
5301
5319
|
if (!linuxSecretAvailable()) return false;
|
|
5302
5320
|
try {
|
|
5303
|
-
|
|
5321
|
+
execSync3(
|
|
5304
5322
|
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
5305
5323
|
{ timeout: 5e3 }
|
|
5306
5324
|
);
|
|
@@ -5313,7 +5331,7 @@ function linuxSecretDelete(service = SERVICE) {
|
|
|
5313
5331
|
if (!nativeKeychainAllowed()) return false;
|
|
5314
5332
|
if (process.platform !== "linux") return false;
|
|
5315
5333
|
try {
|
|
5316
|
-
|
|
5334
|
+
execSync3(
|
|
5317
5335
|
`secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
5318
5336
|
{ timeout: 5e3 }
|
|
5319
5337
|
);
|
|
@@ -5332,7 +5350,7 @@ async function tryKeytar() {
|
|
|
5332
5350
|
}
|
|
5333
5351
|
function deriveMachineKey() {
|
|
5334
5352
|
try {
|
|
5335
|
-
const
|
|
5353
|
+
const crypto24 = __require("crypto");
|
|
5336
5354
|
const material = [
|
|
5337
5355
|
os6.hostname(),
|
|
5338
5356
|
os6.userInfo().username,
|
|
@@ -5341,7 +5359,7 @@ function deriveMachineKey() {
|
|
|
5341
5359
|
// Machine ID on Linux (stable across reboots)
|
|
5342
5360
|
process.platform === "linux" ? readMachineId() : ""
|
|
5343
5361
|
].join("|");
|
|
5344
|
-
return
|
|
5362
|
+
return crypto24.createHash("sha256").update(material).digest();
|
|
5345
5363
|
} catch {
|
|
5346
5364
|
return null;
|
|
5347
5365
|
}
|
|
@@ -5355,9 +5373,9 @@ function readMachineId() {
|
|
|
5355
5373
|
}
|
|
5356
5374
|
}
|
|
5357
5375
|
function encryptWithMachineKey(plaintext, machineKey) {
|
|
5358
|
-
const
|
|
5359
|
-
const iv =
|
|
5360
|
-
const cipher =
|
|
5376
|
+
const crypto24 = __require("crypto");
|
|
5377
|
+
const iv = crypto24.randomBytes(12);
|
|
5378
|
+
const cipher = crypto24.createCipheriv("aes-256-gcm", machineKey, iv);
|
|
5361
5379
|
let encrypted = cipher.update(plaintext, "utf-8", "base64");
|
|
5362
5380
|
encrypted += cipher.final("base64");
|
|
5363
5381
|
const authTag = cipher.getAuthTag().toString("base64");
|
|
@@ -5366,13 +5384,13 @@ function encryptWithMachineKey(plaintext, machineKey) {
|
|
|
5366
5384
|
function decryptWithMachineKey(encrypted, machineKey) {
|
|
5367
5385
|
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
5368
5386
|
try {
|
|
5369
|
-
const
|
|
5387
|
+
const crypto24 = __require("crypto");
|
|
5370
5388
|
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
5371
5389
|
if (parts.length !== 3) return null;
|
|
5372
5390
|
const [ivB64, tagB64, cipherB64] = parts;
|
|
5373
5391
|
const iv = Buffer.from(ivB64, "base64");
|
|
5374
5392
|
const authTag = Buffer.from(tagB64, "base64");
|
|
5375
|
-
const decipher =
|
|
5393
|
+
const decipher = crypto24.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
5376
5394
|
decipher.setAuthTag(authTag);
|
|
5377
5395
|
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
5378
5396
|
decrypted += decipher.final("utf-8");
|
|
@@ -5801,6 +5819,24 @@ var init_platform_procedures = __esm({
|
|
|
5801
5819
|
priority: "p0",
|
|
5802
5820
|
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."
|
|
5803
5821
|
},
|
|
5822
|
+
{
|
|
5823
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
5824
|
+
domain: "support",
|
|
5825
|
+
priority: "p1",
|
|
5826
|
+
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."
|
|
5827
|
+
},
|
|
5828
|
+
{
|
|
5829
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
5830
|
+
domain: "support",
|
|
5831
|
+
priority: "p0",
|
|
5832
|
+
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."
|
|
5833
|
+
},
|
|
5834
|
+
{
|
|
5835
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
5836
|
+
domain: "support",
|
|
5837
|
+
priority: "p1",
|
|
5838
|
+
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."
|
|
5839
|
+
},
|
|
5804
5840
|
// --- Operations ---
|
|
5805
5841
|
{
|
|
5806
5842
|
title: "Managers must supervise deployed workers",
|
|
@@ -7175,8 +7211,8 @@ async function embedDirect(text3) {
|
|
|
7175
7211
|
const llamaCpp = await import("node-llama-cpp");
|
|
7176
7212
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
7177
7213
|
const { existsSync: existsSync48 } = await import("fs");
|
|
7178
|
-
const
|
|
7179
|
-
const modelPath =
|
|
7214
|
+
const path63 = await import("path");
|
|
7215
|
+
const modelPath = path63.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
7180
7216
|
if (!existsSync48(modelPath)) {
|
|
7181
7217
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
7182
7218
|
}
|
|
@@ -7211,7 +7247,7 @@ __export(project_name_exports, {
|
|
|
7211
7247
|
_resetCache: () => _resetCache,
|
|
7212
7248
|
getProjectName: () => getProjectName
|
|
7213
7249
|
});
|
|
7214
|
-
import { execSync as
|
|
7250
|
+
import { execSync as execSync4 } from "child_process";
|
|
7215
7251
|
import path14 from "path";
|
|
7216
7252
|
function getProjectName(cwd) {
|
|
7217
7253
|
const dir = cwd ?? process.cwd();
|
|
@@ -7219,7 +7255,7 @@ function getProjectName(cwd) {
|
|
|
7219
7255
|
try {
|
|
7220
7256
|
let repoRoot;
|
|
7221
7257
|
try {
|
|
7222
|
-
const gitCommonDir =
|
|
7258
|
+
const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
|
|
7223
7259
|
cwd: dir,
|
|
7224
7260
|
encoding: "utf8",
|
|
7225
7261
|
timeout: 2e3,
|
|
@@ -7227,7 +7263,7 @@ function getProjectName(cwd) {
|
|
|
7227
7263
|
}).trim();
|
|
7228
7264
|
repoRoot = path14.dirname(gitCommonDir);
|
|
7229
7265
|
} catch {
|
|
7230
|
-
repoRoot =
|
|
7266
|
+
repoRoot = execSync4("git rev-parse --show-toplevel", {
|
|
7231
7267
|
cwd: dir,
|
|
7232
7268
|
encoding: "utf8",
|
|
7233
7269
|
timeout: 2e3,
|
|
@@ -7261,14 +7297,14 @@ var file_grep_exports = {};
|
|
|
7261
7297
|
__export(file_grep_exports, {
|
|
7262
7298
|
grepProjectFiles: () => grepProjectFiles
|
|
7263
7299
|
});
|
|
7264
|
-
import { execSync as
|
|
7300
|
+
import { execSync as execSync5 } from "child_process";
|
|
7265
7301
|
import { readFileSync as readFileSync9, readdirSync as readdirSync2, statSync as statSync6, existsSync as existsSync14 } from "fs";
|
|
7266
7302
|
import path15 from "path";
|
|
7267
7303
|
import crypto3 from "crypto";
|
|
7268
7304
|
function hasRipgrep() {
|
|
7269
7305
|
if (_hasRg === null) {
|
|
7270
7306
|
try {
|
|
7271
|
-
|
|
7307
|
+
execSync5("rg --version", { stdio: "ignore", timeout: 2e3 });
|
|
7272
7308
|
_hasRg = true;
|
|
7273
7309
|
} catch {
|
|
7274
7310
|
_hasRg = false;
|
|
@@ -7334,7 +7370,7 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
|
|
|
7334
7370
|
const globs = (patterns ?? DEFAULT_PATTERNS).map((p) => `--glob '${p}'`).join(" ");
|
|
7335
7371
|
const excludes = EXCLUDE_DIRS.map((d) => `--glob '!${d}'`).join(" ");
|
|
7336
7372
|
const cmd = `rg -i -c --hidden --no-config --no-ignore '${pattern.replace(/'/g, "\\'")}' . ${globs} ${excludes} --max-filesize ${MAX_FILE_SIZE} 2>/dev/null || true`;
|
|
7337
|
-
const output =
|
|
7373
|
+
const output = execSync5(cmd, {
|
|
7338
7374
|
cwd: projectRoot,
|
|
7339
7375
|
encoding: "utf8",
|
|
7340
7376
|
timeout: 3e3,
|
|
@@ -7349,12 +7385,12 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
|
|
|
7349
7385
|
const matchCount = parseInt(line.slice(colonIdx + 1));
|
|
7350
7386
|
if (isNaN(matchCount) || matchCount === 0) continue;
|
|
7351
7387
|
try {
|
|
7352
|
-
const firstMatch =
|
|
7388
|
+
const firstMatch = execSync5(
|
|
7353
7389
|
`rg -i -n --hidden '${pattern.replace(/'/g, "\\'")}' '${filePath}' --max-count 1 2>/dev/null | head -1`,
|
|
7354
7390
|
{ cwd: projectRoot, encoding: "utf8", timeout: 1e3 }
|
|
7355
7391
|
).trim();
|
|
7356
7392
|
const lineNum = parseInt(firstMatch.split(":")[0] ?? "1");
|
|
7357
|
-
const totalLines =
|
|
7393
|
+
const totalLines = execSync5(`wc -l < '${filePath}'`, {
|
|
7358
7394
|
cwd: projectRoot,
|
|
7359
7395
|
encoding: "utf8",
|
|
7360
7396
|
timeout: 1e3
|
|
@@ -8268,10 +8304,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
8268
8304
|
};
|
|
8269
8305
|
try {
|
|
8270
8306
|
const fs = await import("fs");
|
|
8271
|
-
const
|
|
8307
|
+
const path63 = await import("path");
|
|
8272
8308
|
const os25 = await import("os");
|
|
8273
|
-
const logPath =
|
|
8274
|
-
fs.mkdirSync(
|
|
8309
|
+
const logPath = path63.join(os25.homedir(), ".exe-os", "search-quality.jsonl");
|
|
8310
|
+
fs.mkdirSync(path63.dirname(logPath), { recursive: true });
|
|
8275
8311
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
8276
8312
|
} catch {
|
|
8277
8313
|
}
|
|
@@ -8705,7 +8741,7 @@ var init_hybrid_search = __esm({
|
|
|
8705
8741
|
});
|
|
8706
8742
|
|
|
8707
8743
|
// src/lib/session-key.ts
|
|
8708
|
-
import { execSync as
|
|
8744
|
+
import { execSync as execSync6 } from "child_process";
|
|
8709
8745
|
function normalizeCommand(command) {
|
|
8710
8746
|
const trimmed = command.trim().toLowerCase();
|
|
8711
8747
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -8724,7 +8760,7 @@ function resolveRuntimeProcess() {
|
|
|
8724
8760
|
let pid = process.ppid;
|
|
8725
8761
|
for (let i = 0; i < 10; i++) {
|
|
8726
8762
|
try {
|
|
8727
|
-
const info =
|
|
8763
|
+
const info = execSync6(`ps -p ${pid} -o ppid=,comm=`, {
|
|
8728
8764
|
encoding: "utf8",
|
|
8729
8765
|
timeout: 2e3
|
|
8730
8766
|
}).trim();
|
|
@@ -8804,7 +8840,7 @@ __export(active_agent_exports, {
|
|
|
8804
8840
|
writeActiveAgent: () => writeActiveAgent
|
|
8805
8841
|
});
|
|
8806
8842
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
8807
|
-
import { execSync as
|
|
8843
|
+
import { execSync as execSync7 } from "child_process";
|
|
8808
8844
|
import path16 from "path";
|
|
8809
8845
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
8810
8846
|
if (candidate === baseName) return true;
|
|
@@ -8898,7 +8934,7 @@ function getActiveAgent() {
|
|
|
8898
8934
|
} catch {
|
|
8899
8935
|
}
|
|
8900
8936
|
try {
|
|
8901
|
-
const sessionName =
|
|
8937
|
+
const sessionName = execSync7(
|
|
8902
8938
|
"tmux display-message -p '#{session_name}' 2>/dev/null",
|
|
8903
8939
|
{ encoding: "utf8", timeout: 2e3 }
|
|
8904
8940
|
).trim();
|
|
@@ -9904,8 +9940,8 @@ __export(wiki_client_exports, {
|
|
|
9904
9940
|
listDocuments: () => listDocuments,
|
|
9905
9941
|
listWorkspaces: () => listWorkspaces
|
|
9906
9942
|
});
|
|
9907
|
-
async function wikiFetch(config2,
|
|
9908
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
9943
|
+
async function wikiFetch(config2, path63, method = "GET", body) {
|
|
9944
|
+
const url = `${config2.baseUrl}/api/v1${path63}`;
|
|
9909
9945
|
const headers = {
|
|
9910
9946
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
9911
9947
|
"Content-Type": "application/json"
|
|
@@ -9938,7 +9974,7 @@ async function wikiFetch(config2, path62, method = "GET", body) {
|
|
|
9938
9974
|
}
|
|
9939
9975
|
}
|
|
9940
9976
|
if (!response.ok) {
|
|
9941
|
-
throw new Error(`Wiki API ${method} ${
|
|
9977
|
+
throw new Error(`Wiki API ${method} ${path63}: ${response.status} ${response.statusText}`);
|
|
9942
9978
|
}
|
|
9943
9979
|
return response.json();
|
|
9944
9980
|
} finally {
|
|
@@ -11308,7 +11344,7 @@ __export(session_registry_exports, {
|
|
|
11308
11344
|
registerSession: () => registerSession
|
|
11309
11345
|
});
|
|
11310
11346
|
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, mkdirSync as mkdirSync6, existsSync as existsSync17 } from "fs";
|
|
11311
|
-
import { execSync as
|
|
11347
|
+
import { execSync as execSync8 } from "child_process";
|
|
11312
11348
|
import path21 from "path";
|
|
11313
11349
|
import os8 from "os";
|
|
11314
11350
|
function registerSession(entry) {
|
|
@@ -11348,7 +11384,7 @@ function pruneStaleSessions() {
|
|
|
11348
11384
|
if (sessions.length === 0) return 0;
|
|
11349
11385
|
let liveSessions = [];
|
|
11350
11386
|
try {
|
|
11351
|
-
liveSessions =
|
|
11387
|
+
liveSessions = execSync8("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
11352
11388
|
encoding: "utf8"
|
|
11353
11389
|
}).trim().split("\n").filter(Boolean);
|
|
11354
11390
|
} catch {
|
|
@@ -11496,14 +11532,14 @@ var init_transport = __esm({
|
|
|
11496
11532
|
});
|
|
11497
11533
|
|
|
11498
11534
|
// src/lib/cc-agent-support.ts
|
|
11499
|
-
import { execSync as
|
|
11535
|
+
import { execSync as execSync9 } from "child_process";
|
|
11500
11536
|
function _resetCcAgentSupportCache() {
|
|
11501
11537
|
_cachedSupport = null;
|
|
11502
11538
|
}
|
|
11503
11539
|
function claudeSupportsAgentFlag() {
|
|
11504
11540
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
11505
11541
|
try {
|
|
11506
|
-
const helpOutput =
|
|
11542
|
+
const helpOutput = execSync9("claude --help 2>&1", {
|
|
11507
11543
|
encoding: "utf-8",
|
|
11508
11544
|
timeout: 5e3
|
|
11509
11545
|
});
|
|
@@ -12480,7 +12516,7 @@ __export(tmux_routing_exports, {
|
|
|
12480
12516
|
spawnEmployee: () => spawnEmployee,
|
|
12481
12517
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
12482
12518
|
});
|
|
12483
|
-
import { execFileSync as execFileSync2, execSync as
|
|
12519
|
+
import { execFileSync as execFileSync2, execSync as execSync10 } from "child_process";
|
|
12484
12520
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync12, mkdirSync as mkdirSync9, existsSync as existsSync21, appendFileSync as appendFileSync3, readdirSync as readdirSync5 } from "fs";
|
|
12485
12521
|
import path25 from "path";
|
|
12486
12522
|
import os11 from "os";
|
|
@@ -13201,7 +13237,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
13201
13237
|
let booted = false;
|
|
13202
13238
|
for (let i = 0; i < 30; i++) {
|
|
13203
13239
|
try {
|
|
13204
|
-
|
|
13240
|
+
execSync10("sleep 0.5");
|
|
13205
13241
|
} catch {
|
|
13206
13242
|
}
|
|
13207
13243
|
try {
|
|
@@ -13455,7 +13491,7 @@ __export(tasks_crud_exports, {
|
|
|
13455
13491
|
import crypto8 from "crypto";
|
|
13456
13492
|
import path27 from "path";
|
|
13457
13493
|
import os13 from "os";
|
|
13458
|
-
import { execSync as
|
|
13494
|
+
import { execSync as execSync11 } from "child_process";
|
|
13459
13495
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
13460
13496
|
import { existsSync as existsSync23, readFileSync as readFileSync17 } from "fs";
|
|
13461
13497
|
async function writeCheckpoint(input) {
|
|
@@ -13800,14 +13836,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
13800
13836
|
if (!identifier || identifier === "unknown") return true;
|
|
13801
13837
|
try {
|
|
13802
13838
|
if (identifier.startsWith("%")) {
|
|
13803
|
-
const output =
|
|
13839
|
+
const output = execSync11("tmux list-panes -a -F '#{pane_id}'", {
|
|
13804
13840
|
timeout: 2e3,
|
|
13805
13841
|
encoding: "utf8",
|
|
13806
13842
|
stdio: ["pipe", "pipe", "pipe"]
|
|
13807
13843
|
});
|
|
13808
13844
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
13809
13845
|
} else {
|
|
13810
|
-
|
|
13846
|
+
execSync11(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
13811
13847
|
timeout: 2e3,
|
|
13812
13848
|
stdio: ["pipe", "pipe", "pipe"]
|
|
13813
13849
|
});
|
|
@@ -13816,7 +13852,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
13816
13852
|
} catch {
|
|
13817
13853
|
if (identifier.startsWith("%")) return true;
|
|
13818
13854
|
try {
|
|
13819
|
-
|
|
13855
|
+
execSync11("tmux list-sessions", {
|
|
13820
13856
|
timeout: 2e3,
|
|
13821
13857
|
stdio: ["pipe", "pipe", "pipe"]
|
|
13822
13858
|
});
|
|
@@ -13831,12 +13867,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
13831
13867
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
13832
13868
|
try {
|
|
13833
13869
|
const since = new Date(taskCreatedAt).toISOString();
|
|
13834
|
-
const branch =
|
|
13870
|
+
const branch = execSync11(
|
|
13835
13871
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
13836
13872
|
{ encoding: "utf8", timeout: 3e3 }
|
|
13837
13873
|
).trim();
|
|
13838
13874
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
13839
|
-
const commitCount =
|
|
13875
|
+
const commitCount = execSync11(
|
|
13840
13876
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
13841
13877
|
{ encoding: "utf8", timeout: 5e3 }
|
|
13842
13878
|
).trim();
|
|
@@ -15019,12 +15055,14 @@ On EVERY new conversation, before doing anything else:
|
|
|
15019
15055
|
1. **Memory scan**: Run recall_my_memory with broad queries \u2014 "project", "client", "pipeline", "campaign", "deal", "decision", "blocker". Summarize what you find.
|
|
15020
15056
|
2. **Task scan**: Run list_tasks to see what's open, in progress, blocked, or needs review across all employees.
|
|
15021
15057
|
3. **Team check**: Run ask_team_memory for recent activity from CTO/CMO/engineers.
|
|
15022
|
-
4. **
|
|
15058
|
+
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.
|
|
15059
|
+
5. **Present the brief**: Give the founder a concise status report:
|
|
15023
15060
|
- What's active and progressing
|
|
15024
15061
|
- What's blocked and needs attention
|
|
15025
15062
|
- What decisions are pending
|
|
15063
|
+
- Available bug fixes (from step 4, if any)
|
|
15026
15064
|
- What you recommend doing next
|
|
15027
|
-
|
|
15065
|
+
6. Then ask: "What's the priority?"
|
|
15028
15066
|
|
|
15029
15067
|
If this is your FIRST ever conversation (few or no prior memories):
|
|
15030
15068
|
- Search more broadly: "product", "SEO", "meeting", "strategy", "revenue"
|
|
@@ -15044,6 +15082,8 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
15044
15082
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
15045
15083
|
- **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.
|
|
15046
15084
|
- **send_message** \u2014 direct intercom to employees
|
|
15085
|
+
- **create_bug_report** \u2014 file a bug when you encounter an Exe OS platform issue
|
|
15086
|
+
- **list_my_bug_reports** \u2014 check status of filed bugs (boot check: surface available fixes to founder)
|
|
15047
15087
|
${PLAN_MODE_COMPAT}
|
|
15048
15088
|
## Completion Workflow
|
|
15049
15089
|
|
|
@@ -19040,12 +19080,12 @@ function registerExportGraph(server) {
|
|
|
19040
19080
|
}
|
|
19041
19081
|
const html = await exportGraphHTML(client);
|
|
19042
19082
|
const fs = await import("fs");
|
|
19043
|
-
const
|
|
19083
|
+
const path63 = await import("path");
|
|
19044
19084
|
const os25 = await import("os");
|
|
19045
|
-
const outDir =
|
|
19085
|
+
const outDir = path63.join(os25.homedir(), ".exe-os", "exports");
|
|
19046
19086
|
fs.mkdirSync(outDir, { recursive: true });
|
|
19047
19087
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
19048
|
-
const filePath =
|
|
19088
|
+
const filePath = path63.join(outDir, `graph-${timestamp}.html`);
|
|
19049
19089
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
19050
19090
|
return {
|
|
19051
19091
|
content: [
|
|
@@ -20863,13 +20903,13 @@ __export(tmux_status_exports, {
|
|
|
20863
20903
|
parseActivity: () => parseActivity,
|
|
20864
20904
|
parseContextPercentage: () => parseContextPercentage
|
|
20865
20905
|
});
|
|
20866
|
-
import { execSync as
|
|
20906
|
+
import { execSync as execSync12 } from "child_process";
|
|
20867
20907
|
function inTmux() {
|
|
20868
20908
|
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
20869
20909
|
const term = process.env.TERM ?? "";
|
|
20870
20910
|
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
20871
20911
|
try {
|
|
20872
|
-
|
|
20912
|
+
execSync12("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
20873
20913
|
encoding: "utf8",
|
|
20874
20914
|
timeout: 2e3
|
|
20875
20915
|
});
|
|
@@ -20879,12 +20919,12 @@ function inTmux() {
|
|
|
20879
20919
|
try {
|
|
20880
20920
|
let pid = process.ppid;
|
|
20881
20921
|
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
20882
|
-
const comm =
|
|
20922
|
+
const comm = execSync12(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
20883
20923
|
encoding: "utf8",
|
|
20884
20924
|
timeout: 1e3
|
|
20885
20925
|
}).trim();
|
|
20886
20926
|
if (/tmux/.test(comm)) return true;
|
|
20887
|
-
const ppid =
|
|
20927
|
+
const ppid = execSync12(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
20888
20928
|
encoding: "utf8",
|
|
20889
20929
|
timeout: 1e3
|
|
20890
20930
|
}).trim();
|
|
@@ -20897,7 +20937,7 @@ function inTmux() {
|
|
|
20897
20937
|
}
|
|
20898
20938
|
function listTmuxSessions() {
|
|
20899
20939
|
try {
|
|
20900
|
-
const out =
|
|
20940
|
+
const out = execSync12("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
20901
20941
|
encoding: "utf8",
|
|
20902
20942
|
timeout: 3e3
|
|
20903
20943
|
});
|
|
@@ -20908,7 +20948,7 @@ function listTmuxSessions() {
|
|
|
20908
20948
|
}
|
|
20909
20949
|
function capturePaneLines(windowName, lines = 10) {
|
|
20910
20950
|
try {
|
|
20911
|
-
const out =
|
|
20951
|
+
const out = execSync12(
|
|
20912
20952
|
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
20913
20953
|
{ encoding: "utf8", timeout: 3e3 }
|
|
20914
20954
|
);
|
|
@@ -20919,7 +20959,7 @@ function capturePaneLines(windowName, lines = 10) {
|
|
|
20919
20959
|
}
|
|
20920
20960
|
function getPaneCwd(windowName) {
|
|
20921
20961
|
try {
|
|
20922
|
-
const out =
|
|
20962
|
+
const out = execSync12(
|
|
20923
20963
|
`tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
|
|
20924
20964
|
{ encoding: "utf8", timeout: 3e3 }
|
|
20925
20965
|
);
|
|
@@ -20930,7 +20970,7 @@ function getPaneCwd(windowName) {
|
|
|
20930
20970
|
}
|
|
20931
20971
|
function projectFromPath(dir) {
|
|
20932
20972
|
try {
|
|
20933
|
-
const root =
|
|
20973
|
+
const root = execSync12("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
|
|
20934
20974
|
encoding: "utf8",
|
|
20935
20975
|
timeout: 3e3
|
|
20936
20976
|
}).trim();
|
|
@@ -20999,7 +21039,7 @@ function getEmployeeStatuses(employeeNames) {
|
|
|
20999
21039
|
}
|
|
21000
21040
|
let paneAlive = true;
|
|
21001
21041
|
try {
|
|
21002
|
-
const paneStatus =
|
|
21042
|
+
const paneStatus = execSync12(
|
|
21003
21043
|
`tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
|
|
21004
21044
|
{ encoding: "utf8", timeout: 3e3 }
|
|
21005
21045
|
).trim();
|
|
@@ -21245,7 +21285,7 @@ __export(daemon_orchestration_exports, {
|
|
|
21245
21285
|
shouldKillSession: () => shouldKillSession,
|
|
21246
21286
|
shouldNudgeEmployee: () => shouldNudgeEmployee
|
|
21247
21287
|
});
|
|
21248
|
-
import { execSync as
|
|
21288
|
+
import { execSync as execSync13 } from "child_process";
|
|
21249
21289
|
import { existsSync as existsSync29, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
|
|
21250
21290
|
import { homedir as homedir5 } from "os";
|
|
21251
21291
|
import { join as join3 } from "path";
|
|
@@ -21563,7 +21603,7 @@ function createSessionTTLRealDeps(getClient2) {
|
|
|
21563
21603
|
},
|
|
21564
21604
|
getSessionCreatedEpoch: (sessionName) => {
|
|
21565
21605
|
try {
|
|
21566
|
-
const out =
|
|
21606
|
+
const out = execSync13(
|
|
21567
21607
|
`tmux display-message -t ${JSON.stringify(sessionName)} -p '#{session_created}' 2>/dev/null`,
|
|
21568
21608
|
{ encoding: "utf8", timeout: 3e3 }
|
|
21569
21609
|
).trim();
|
|
@@ -21790,7 +21830,7 @@ function reapOrphanedMcpProcesses(deps) {
|
|
|
21790
21830
|
function createOrphanReaperRealDeps() {
|
|
21791
21831
|
return {
|
|
21792
21832
|
listProcesses: () => {
|
|
21793
|
-
const output =
|
|
21833
|
+
const output = execSync13("ps -eo pid,ppid,args", {
|
|
21794
21834
|
encoding: "utf8",
|
|
21795
21835
|
timeout: 5e3
|
|
21796
21836
|
});
|
|
@@ -26130,9 +26170,9 @@ var init_hostinger_api = __esm({
|
|
|
26130
26170
|
}
|
|
26131
26171
|
this.lastRequestTime = Date.now();
|
|
26132
26172
|
}
|
|
26133
|
-
async request(method,
|
|
26173
|
+
async request(method, path63, body) {
|
|
26134
26174
|
await this.rateLimit();
|
|
26135
|
-
const url = `${this.baseUrl}${
|
|
26175
|
+
const url = `${this.baseUrl}${path63}`;
|
|
26136
26176
|
const headers = {
|
|
26137
26177
|
Authorization: `Bearer ${this.apiKey}`,
|
|
26138
26178
|
"Content-Type": "application/json",
|
|
@@ -26201,8 +26241,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
26201
26241
|
}
|
|
26202
26242
|
return envelope.result;
|
|
26203
26243
|
}
|
|
26204
|
-
function buildUrl(zoneId,
|
|
26205
|
-
const normalizedPath =
|
|
26244
|
+
function buildUrl(zoneId, path63 = "/dns_records", query) {
|
|
26245
|
+
const normalizedPath = path63.startsWith("/") ? path63 : `/${path63}`;
|
|
26206
26246
|
const url = new URL(
|
|
26207
26247
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
26208
26248
|
);
|
|
@@ -26901,7 +26941,7 @@ var init_trigger_engine = __esm({
|
|
|
26901
26941
|
|
|
26902
26942
|
// src/lib/schedules.ts
|
|
26903
26943
|
import crypto17 from "crypto";
|
|
26904
|
-
import { execSync as
|
|
26944
|
+
import { execSync as execSync14 } from "child_process";
|
|
26905
26945
|
function isValidCron(cron) {
|
|
26906
26946
|
const fields = cron.trim().split(/\s+/);
|
|
26907
26947
|
if (fields.length !== 5) return false;
|
|
@@ -27025,7 +27065,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
27025
27065
|
const cwd = projectDir ? `cd ${JSON.stringify(projectDir)} && ` : "";
|
|
27026
27066
|
const escapedPrompt = prompt.replace(/"/g, '\\"');
|
|
27027
27067
|
const entry = `${cron} ${cwd}claude -p --dangerously-skip-permissions "${escapedPrompt}" # exe-schedule:${id}`;
|
|
27028
|
-
|
|
27068
|
+
execSync14(
|
|
27029
27069
|
`(crontab -l 2>/dev/null; echo ${JSON.stringify(entry)}) | crontab -`,
|
|
27030
27070
|
{ timeout: 5e3, stdio: "ignore" }
|
|
27031
27071
|
);
|
|
@@ -30161,9 +30201,207 @@ var init_create_bug_report = __esm({
|
|
|
30161
30201
|
}
|
|
30162
30202
|
});
|
|
30163
30203
|
|
|
30204
|
+
// src/mcp/tools/create-feature-request.ts
|
|
30205
|
+
import { z as z89 } from "zod";
|
|
30206
|
+
import crypto20 from "crypto";
|
|
30207
|
+
import { mkdir as mkdir7, writeFile as writeFile8 } from "fs/promises";
|
|
30208
|
+
import path54 from "path";
|
|
30209
|
+
function slugify3(input) {
|
|
30210
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "feature-request";
|
|
30211
|
+
}
|
|
30212
|
+
function section2(title, body) {
|
|
30213
|
+
return `## ${title}
|
|
30214
|
+
|
|
30215
|
+
${body?.trim() || "Not provided"}`;
|
|
30216
|
+
}
|
|
30217
|
+
function buildMarkdown2(input) {
|
|
30218
|
+
return [
|
|
30219
|
+
`# Feature Request \u2014 ${input.title}`,
|
|
30220
|
+
"",
|
|
30221
|
+
`id: ${input.id}`,
|
|
30222
|
+
`category: ${input.category}`,
|
|
30223
|
+
`priority: ${input.priority}`,
|
|
30224
|
+
`filed_by: ${input.agentId} (${input.agentRole})`,
|
|
30225
|
+
`package_version: ${input.packageVersion}`,
|
|
30226
|
+
`project: ${input.projectName ?? "unknown"}`,
|
|
30227
|
+
`created_at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
30228
|
+
"",
|
|
30229
|
+
section2("Description", input.description),
|
|
30230
|
+
section2("Use Case", input.useCase),
|
|
30231
|
+
section2("Current Workaround", input.currentWorkaround),
|
|
30232
|
+
section2("Proposed Solution", input.proposedSolution),
|
|
30233
|
+
section2("Business Impact", input.businessImpact)
|
|
30234
|
+
].join("\n");
|
|
30235
|
+
}
|
|
30236
|
+
async function maybeSendUpstream2(payload) {
|
|
30237
|
+
const config2 = await loadConfig();
|
|
30238
|
+
const routerUrl = process.env.API_ROUTER_URL?.replace(/\/+$/, "");
|
|
30239
|
+
const endpoint2 = config2.support?.featureRequestEndpoint || process.env.EXE_FEATURE_REQUEST_ENDPOINT || (routerUrl ? `${routerUrl}/v1/support/feature-requests` : "https://askexe.com/v1/support/feature-requests");
|
|
30240
|
+
const token = config2.support?.featureRequestToken || process.env.EXE_FEATURE_REQUEST_TOKEN;
|
|
30241
|
+
const licenseKey = loadLicense() || process.env.EXE_LICENSE_KEY || config2.cloud?.apiKey;
|
|
30242
|
+
const licenseToken = readCachedLicenseToken();
|
|
30243
|
+
if (!endpoint2) {
|
|
30244
|
+
return "not_configured";
|
|
30245
|
+
}
|
|
30246
|
+
try {
|
|
30247
|
+
const parsed = new URL(endpoint2);
|
|
30248
|
+
if (parsed.protocol !== "https:" && !["localhost", "127.0.0.1", "::1"].includes(parsed.hostname)) {
|
|
30249
|
+
return "failed: insecure endpoint rejected";
|
|
30250
|
+
}
|
|
30251
|
+
const response = await fetch(parsed, {
|
|
30252
|
+
method: "POST",
|
|
30253
|
+
headers: {
|
|
30254
|
+
"content-type": "application/json",
|
|
30255
|
+
...token ? { authorization: `Bearer ${token}` } : {},
|
|
30256
|
+
...licenseKey ? { "x-exe-license-key": licenseKey } : {},
|
|
30257
|
+
...licenseToken ? { "x-exe-license-token": licenseToken } : {}
|
|
30258
|
+
},
|
|
30259
|
+
body: JSON.stringify(payload),
|
|
30260
|
+
signal: AbortSignal.timeout(1e4)
|
|
30261
|
+
});
|
|
30262
|
+
if (!response.ok) return `failed: HTTP ${response.status}`;
|
|
30263
|
+
return "sent";
|
|
30264
|
+
} catch (err) {
|
|
30265
|
+
return `failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
30266
|
+
}
|
|
30267
|
+
}
|
|
30268
|
+
function registerCreateFeatureRequest(server) {
|
|
30269
|
+
server.registerTool(
|
|
30270
|
+
"create_feature_request",
|
|
30271
|
+
{
|
|
30272
|
+
title: "Create Feature Request",
|
|
30273
|
+
description: "File a feature request for exe-os: upstream_feature (requires platform changes), local_customization (configurable in customer layers), integration (third-party), or unclear. Writes a local report, stores memory, and optionally sends to AskExe.",
|
|
30274
|
+
inputSchema: {
|
|
30275
|
+
title: z89.string().min(3).describe("Short descriptive title"),
|
|
30276
|
+
category: CATEGORY.describe(
|
|
30277
|
+
"upstream_feature = platform capability change; local_customization = configurable in customer layers; integration = third-party connector; unclear = needs product triage"
|
|
30278
|
+
),
|
|
30279
|
+
priority: PRIORITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
30280
|
+
description: z89.string().min(10).describe("What capability is needed and why"),
|
|
30281
|
+
use_case: z89.string().optional().describe("Concrete scenario where this feature would be used"),
|
|
30282
|
+
current_workaround: z89.string().optional().describe("How the need is currently addressed, if at all"),
|
|
30283
|
+
proposed_solution: z89.string().optional().describe("Suggested implementation approach"),
|
|
30284
|
+
business_impact: z89.string().optional().describe("Impact on business/workflow if this ships"),
|
|
30285
|
+
package_version: z89.string().optional().describe("Installed @askexenow/exe-os version"),
|
|
30286
|
+
project_name: z89.string().optional().describe("Project/customer context"),
|
|
30287
|
+
send_upstream: z89.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
|
|
30288
|
+
}
|
|
30289
|
+
},
|
|
30290
|
+
async ({
|
|
30291
|
+
title,
|
|
30292
|
+
category,
|
|
30293
|
+
priority,
|
|
30294
|
+
description,
|
|
30295
|
+
use_case,
|
|
30296
|
+
current_workaround,
|
|
30297
|
+
proposed_solution,
|
|
30298
|
+
business_impact,
|
|
30299
|
+
package_version,
|
|
30300
|
+
project_name,
|
|
30301
|
+
send_upstream
|
|
30302
|
+
}) => {
|
|
30303
|
+
const { agentId, agentRole } = getActiveAgent();
|
|
30304
|
+
const id = crypto20.randomUUID();
|
|
30305
|
+
const version = package_version ?? "unknown";
|
|
30306
|
+
const markdown = buildMarkdown2({
|
|
30307
|
+
id,
|
|
30308
|
+
title,
|
|
30309
|
+
category,
|
|
30310
|
+
priority,
|
|
30311
|
+
agentId,
|
|
30312
|
+
agentRole,
|
|
30313
|
+
packageVersion: version,
|
|
30314
|
+
description,
|
|
30315
|
+
useCase: use_case,
|
|
30316
|
+
currentWorkaround: current_workaround,
|
|
30317
|
+
proposedSolution: proposed_solution,
|
|
30318
|
+
businessImpact: business_impact,
|
|
30319
|
+
projectName: project_name
|
|
30320
|
+
});
|
|
30321
|
+
const outDir = path54.join(EXE_AI_DIR, "feature-requests");
|
|
30322
|
+
await mkdir7(outDir, { recursive: true });
|
|
30323
|
+
const reportPath = path54.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify3(title)}-${id.slice(0, 8)}.md`);
|
|
30324
|
+
await writeFile8(reportPath, markdown, "utf-8");
|
|
30325
|
+
let vector = null;
|
|
30326
|
+
try {
|
|
30327
|
+
vector = await embed(markdown);
|
|
30328
|
+
} catch {
|
|
30329
|
+
vector = null;
|
|
30330
|
+
}
|
|
30331
|
+
await writeMemory({
|
|
30332
|
+
id,
|
|
30333
|
+
agent_id: agentId,
|
|
30334
|
+
agent_role: agentRole,
|
|
30335
|
+
session_id: process.env.SESSION_ID ?? "manual",
|
|
30336
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30337
|
+
tool_name: "create_feature_request",
|
|
30338
|
+
project_name: project_name ?? "support",
|
|
30339
|
+
has_error: false,
|
|
30340
|
+
raw_text: markdown,
|
|
30341
|
+
vector,
|
|
30342
|
+
source_path: reportPath,
|
|
30343
|
+
source_type: "feature_request",
|
|
30344
|
+
memory_type: "feature_request",
|
|
30345
|
+
tier: 1,
|
|
30346
|
+
importance: priority === "p0" ? 10 : priority === "p1" ? 9 : priority === "p2" ? 7 : 5,
|
|
30347
|
+
intent: "request",
|
|
30348
|
+
domain: "support",
|
|
30349
|
+
file_paths: null
|
|
30350
|
+
});
|
|
30351
|
+
await flushBatch();
|
|
30352
|
+
const upstreamStatus = send_upstream ? await maybeSendUpstream2({
|
|
30353
|
+
id,
|
|
30354
|
+
title,
|
|
30355
|
+
category,
|
|
30356
|
+
priority,
|
|
30357
|
+
description,
|
|
30358
|
+
use_case,
|
|
30359
|
+
current_workaround,
|
|
30360
|
+
proposed_solution,
|
|
30361
|
+
business_impact,
|
|
30362
|
+
package_version: version,
|
|
30363
|
+
project_name,
|
|
30364
|
+
agent_id: agentId,
|
|
30365
|
+
agent_role: agentRole
|
|
30366
|
+
}) : "skipped";
|
|
30367
|
+
return {
|
|
30368
|
+
content: [
|
|
30369
|
+
{
|
|
30370
|
+
type: "text",
|
|
30371
|
+
text: `Feature request created.
|
|
30372
|
+
ID: ${id}
|
|
30373
|
+
Category: ${category}
|
|
30374
|
+
Local report: ${reportPath}
|
|
30375
|
+
Memory stored: ${id}
|
|
30376
|
+
Upstream status: ${upstreamStatus}`
|
|
30377
|
+
}
|
|
30378
|
+
]
|
|
30379
|
+
};
|
|
30380
|
+
}
|
|
30381
|
+
);
|
|
30382
|
+
}
|
|
30383
|
+
var CATEGORY, PRIORITY;
|
|
30384
|
+
var init_create_feature_request = __esm({
|
|
30385
|
+
"src/mcp/tools/create-feature-request.ts"() {
|
|
30386
|
+
"use strict";
|
|
30387
|
+
init_embedder();
|
|
30388
|
+
init_active_agent();
|
|
30389
|
+
init_config();
|
|
30390
|
+
init_license();
|
|
30391
|
+
init_store();
|
|
30392
|
+
CATEGORY = z89.enum([
|
|
30393
|
+
"upstream_feature",
|
|
30394
|
+
"local_customization",
|
|
30395
|
+
"integration",
|
|
30396
|
+
"unclear"
|
|
30397
|
+
]);
|
|
30398
|
+
PRIORITY = z89.enum(["p0", "p1", "p2", "p3"]);
|
|
30399
|
+
}
|
|
30400
|
+
});
|
|
30401
|
+
|
|
30164
30402
|
// src/bin/exe-support.ts
|
|
30165
30403
|
import { mkdirSync as mkdirSync21, readFileSync as readFileSync35, unlinkSync as unlinkSync13, writeFileSync as writeFileSync24 } from "fs";
|
|
30166
|
-
import
|
|
30404
|
+
import path55 from "path";
|
|
30167
30405
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
30168
30406
|
async function runHealth() {
|
|
30169
30407
|
const checks = [];
|
|
@@ -30282,8 +30520,8 @@ async function resolveEndpoints() {
|
|
|
30282
30520
|
return { bugEndpoint, healthEndpoint, adminEndpoint };
|
|
30283
30521
|
}
|
|
30284
30522
|
function checkLocalWrite() {
|
|
30285
|
-
const dir =
|
|
30286
|
-
const testPath =
|
|
30523
|
+
const dir = path55.join(EXE_AI_DIR, "bug-reports");
|
|
30524
|
+
const testPath = path55.join(dir, ".support-write-test");
|
|
30287
30525
|
try {
|
|
30288
30526
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
30289
30527
|
writeFileSync24(testPath, "ok\n", { mode: 384 });
|
|
@@ -30299,10 +30537,10 @@ function checkLocalWrite() {
|
|
|
30299
30537
|
}
|
|
30300
30538
|
}
|
|
30301
30539
|
function writeLocalTestReport(id, project, version) {
|
|
30302
|
-
const dir =
|
|
30540
|
+
const dir = path55.join(EXE_AI_DIR, "bug-reports");
|
|
30303
30541
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
30304
30542
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
30305
|
-
const filePath =
|
|
30543
|
+
const filePath = path55.join(dir, `${date}-support-intake-test-${id.slice(0, 8)}.md`);
|
|
30306
30544
|
writeFileSync24(filePath, `# TEST \u2014 ${project} support intake
|
|
30307
30545
|
|
|
30308
30546
|
Report ID: ${id}
|
|
@@ -30344,15 +30582,15 @@ async function maybeCloseAdmin(id, adminEndpoint, version) {
|
|
|
30344
30582
|
}
|
|
30345
30583
|
}
|
|
30346
30584
|
function readPackageVersion2() {
|
|
30347
|
-
let dir =
|
|
30585
|
+
let dir = path55.dirname(new URL(import.meta.url).pathname);
|
|
30348
30586
|
for (let i = 0; i < 6; i++) {
|
|
30349
|
-
const pkg =
|
|
30587
|
+
const pkg = path55.join(dir, "package.json");
|
|
30350
30588
|
try {
|
|
30351
30589
|
const parsed = JSON.parse(readFileSync35(pkg, "utf8"));
|
|
30352
30590
|
if (parsed.version) return parsed.version;
|
|
30353
30591
|
} catch {
|
|
30354
30592
|
}
|
|
30355
|
-
dir =
|
|
30593
|
+
dir = path55.dirname(dir);
|
|
30356
30594
|
}
|
|
30357
30595
|
return "unknown";
|
|
30358
30596
|
}
|
|
@@ -30388,7 +30626,7 @@ var init_exe_support = __esm({
|
|
|
30388
30626
|
});
|
|
30389
30627
|
|
|
30390
30628
|
// src/mcp/tools/support.ts
|
|
30391
|
-
import { z as
|
|
30629
|
+
import { z as z90 } from "zod";
|
|
30392
30630
|
function formatRows(rows, mode) {
|
|
30393
30631
|
const lines = [`exe-os support ${mode}`, ""];
|
|
30394
30632
|
for (const row of rows) {
|
|
@@ -30429,7 +30667,7 @@ function registerSupportTools(server) {
|
|
|
30429
30667
|
title: "Support Test",
|
|
30430
30668
|
description: "End-to-end support intake smoke test. Files a clearly marked test report upstream and auto-closes it on AskExe machines with admin credentials.",
|
|
30431
30669
|
inputSchema: {
|
|
30432
|
-
project:
|
|
30670
|
+
project: z90.string().default("support-smoke").describe("Customer/project name, e.g. hygo")
|
|
30433
30671
|
}
|
|
30434
30672
|
},
|
|
30435
30673
|
async ({ project }) => {
|
|
@@ -30441,11 +30679,139 @@ function registerSupportTools(server) {
|
|
|
30441
30679
|
};
|
|
30442
30680
|
}
|
|
30443
30681
|
);
|
|
30682
|
+
server.registerTool(
|
|
30683
|
+
"list_my_bug_reports",
|
|
30684
|
+
{
|
|
30685
|
+
title: "My Bug Reports",
|
|
30686
|
+
description: "List bug reports you've filed, scoped to your license. Shows status (open/triaged/fixed/closed), severity, and fixed_version so you know when to update.",
|
|
30687
|
+
inputSchema: {
|
|
30688
|
+
status: z90.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("all").describe("Filter by status. Default: all"),
|
|
30689
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
30690
|
+
}
|
|
30691
|
+
},
|
|
30692
|
+
async ({ status: status2, limit }) => {
|
|
30693
|
+
const licenseKey = loadLicense();
|
|
30694
|
+
const licenseToken = readCachedLicenseToken();
|
|
30695
|
+
if (!licenseKey && !licenseToken) {
|
|
30696
|
+
return {
|
|
30697
|
+
content: [{ type: "text", text: "No license key found. Run `exe-os setup` or `exe-os cloud setup` first." }],
|
|
30698
|
+
isError: true
|
|
30699
|
+
};
|
|
30700
|
+
}
|
|
30701
|
+
const endpoint2 = new URL("https://askexe.com/v1/support/my-reports");
|
|
30702
|
+
endpoint2.searchParams.set("status", status2);
|
|
30703
|
+
endpoint2.searchParams.set("limit", String(limit));
|
|
30704
|
+
const headers = { "content-type": "application/json" };
|
|
30705
|
+
if (licenseKey) headers["x-exe-license-key"] = licenseKey;
|
|
30706
|
+
if (licenseToken) headers["x-exe-license-token"] = licenseToken;
|
|
30707
|
+
try {
|
|
30708
|
+
const res = await fetch(endpoint2.toString(), { method: "GET", headers, signal: AbortSignal.timeout(15e3) });
|
|
30709
|
+
if (!res.ok) {
|
|
30710
|
+
const body = await res.text().catch(() => "");
|
|
30711
|
+
return {
|
|
30712
|
+
content: [{ type: "text", text: `Failed to fetch bug reports: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}` }],
|
|
30713
|
+
isError: true
|
|
30714
|
+
};
|
|
30715
|
+
}
|
|
30716
|
+
const data = await res.json();
|
|
30717
|
+
if (data.count === 0) {
|
|
30718
|
+
return {
|
|
30719
|
+
content: [{ type: "text", text: `No bug reports found${status2 !== "all" ? ` with status '${status2}'` : ""}.` }],
|
|
30720
|
+
structuredContent: { items: [], count: 0 }
|
|
30721
|
+
};
|
|
30722
|
+
}
|
|
30723
|
+
const lines = [`Bug reports (${data.count}):`, ""];
|
|
30724
|
+
for (const r of data.items) {
|
|
30725
|
+
const sevIcon = r.severity === "p0" ? "\u{1F534}" : r.severity === "p1" ? "\u{1F534}" : r.severity === "p2" ? "\u{1F7E0}" : "\u{1F7E2}";
|
|
30726
|
+
const statusIcon = r.status === "fixed" ? "\u2705" : r.status === "closed" ? "\u2611\uFE0F" : r.status === "triaged" ? "\u{1F50D}" : r.status === "wontfix" ? "\u26D4" : "\u{1F535}";
|
|
30727
|
+
lines.push(`${sevIcon} ${r.severity.toUpperCase()} ${statusIcon} ${r.status} \u2014 ${r.title}`);
|
|
30728
|
+
lines.push(` ID: ${r.id} | Filed: ${r.created_at?.slice(0, 10) ?? "?"}`);
|
|
30729
|
+
if (r.fixed_version) lines.push(` \u{1F527} Fixed in: ${r.fixed_version} \u2014 run \`exe-os update\` to get this fix`);
|
|
30730
|
+
if (r.triage_notes) lines.push(` \u{1F4DD} AskExe: ${r.triage_notes}`);
|
|
30731
|
+
lines.push("");
|
|
30732
|
+
}
|
|
30733
|
+
return {
|
|
30734
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
30735
|
+
structuredContent: data
|
|
30736
|
+
};
|
|
30737
|
+
} catch (err) {
|
|
30738
|
+
return {
|
|
30739
|
+
content: [{ type: "text", text: `Error fetching bug reports: ${err instanceof Error ? err.message : String(err)}` }],
|
|
30740
|
+
isError: true
|
|
30741
|
+
};
|
|
30742
|
+
}
|
|
30743
|
+
}
|
|
30744
|
+
);
|
|
30745
|
+
server.registerTool(
|
|
30746
|
+
"list_my_feature_requests",
|
|
30747
|
+
{
|
|
30748
|
+
title: "My Feature Requests",
|
|
30749
|
+
description: "List feature requests you've filed, scoped to your license. Shows status (open/planned/in_progress/shipped/closed), priority, and shipped_version so you know when to update.",
|
|
30750
|
+
inputSchema: {
|
|
30751
|
+
status: z90.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("all").describe("Filter by status. Default: all"),
|
|
30752
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
30753
|
+
}
|
|
30754
|
+
},
|
|
30755
|
+
async ({ status: status2, limit }) => {
|
|
30756
|
+
const licenseKey = loadLicense();
|
|
30757
|
+
const licenseToken = readCachedLicenseToken();
|
|
30758
|
+
if (!licenseKey && !licenseToken) {
|
|
30759
|
+
return {
|
|
30760
|
+
content: [{ type: "text", text: "No license key found. Run `exe-os setup` or `exe-os cloud setup` first." }],
|
|
30761
|
+
isError: true
|
|
30762
|
+
};
|
|
30763
|
+
}
|
|
30764
|
+
const endpoint2 = new URL("https://askexe.com/v1/support/my-feature-requests");
|
|
30765
|
+
endpoint2.searchParams.set("status", status2);
|
|
30766
|
+
endpoint2.searchParams.set("limit", String(limit));
|
|
30767
|
+
const headers = { "content-type": "application/json" };
|
|
30768
|
+
if (licenseKey) headers["x-exe-license-key"] = licenseKey;
|
|
30769
|
+
if (licenseToken) headers["x-exe-license-token"] = licenseToken;
|
|
30770
|
+
try {
|
|
30771
|
+
const res = await fetch(endpoint2.toString(), { method: "GET", headers, signal: AbortSignal.timeout(15e3) });
|
|
30772
|
+
if (!res.ok) {
|
|
30773
|
+
const body = await res.text().catch(() => "");
|
|
30774
|
+
return {
|
|
30775
|
+
content: [{ type: "text", text: `Failed to fetch feature requests: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}` }],
|
|
30776
|
+
isError: true
|
|
30777
|
+
};
|
|
30778
|
+
}
|
|
30779
|
+
const data = await res.json();
|
|
30780
|
+
if (data.count === 0) {
|
|
30781
|
+
return {
|
|
30782
|
+
content: [{ type: "text", text: `No feature requests found${status2 !== "all" ? ` with status '${status2}'` : ""}.` }],
|
|
30783
|
+
structuredContent: { items: [], count: 0 }
|
|
30784
|
+
};
|
|
30785
|
+
}
|
|
30786
|
+
const lines = [`Feature requests (${data.count}):`, ""];
|
|
30787
|
+
for (const r of data.items) {
|
|
30788
|
+
const priIcon = r.priority === "p0" ? "\u{1F534}" : r.priority === "p1" ? "\u{1F534}" : r.priority === "p2" ? "\u{1F7E0}" : "\u{1F7E2}";
|
|
30789
|
+
const statusIcon = r.status === "shipped" ? "\u2705" : r.status === "closed" ? "\u2611\uFE0F" : r.status === "planned" ? "\u{1F4CB}" : r.status === "in_progress" ? "\u{1F528}" : r.status === "wontdo" ? "\u26D4" : "\u{1F535}";
|
|
30790
|
+
lines.push(`${priIcon} ${r.priority.toUpperCase()} ${statusIcon} ${r.status} \u2014 ${r.title}`);
|
|
30791
|
+
lines.push(` ID: ${r.id} | Filed: ${r.created_at?.slice(0, 10) ?? "?"}`);
|
|
30792
|
+
if (r.shipped_version) lines.push(` \u{1F680} Shipped in: ${r.shipped_version} \u2014 run \`exe-os update\` to get this feature`);
|
|
30793
|
+
if (r.target_version) lines.push(` \u{1F3AF} Target: ${r.target_version}`);
|
|
30794
|
+
if (r.response_notes) lines.push(` \u{1F4DD} AskExe: ${r.response_notes}`);
|
|
30795
|
+
lines.push("");
|
|
30796
|
+
}
|
|
30797
|
+
return {
|
|
30798
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
30799
|
+
structuredContent: data
|
|
30800
|
+
};
|
|
30801
|
+
} catch (err) {
|
|
30802
|
+
return {
|
|
30803
|
+
content: [{ type: "text", text: `Error fetching feature requests: ${err instanceof Error ? err.message : String(err)}` }],
|
|
30804
|
+
isError: true
|
|
30805
|
+
};
|
|
30806
|
+
}
|
|
30807
|
+
}
|
|
30808
|
+
);
|
|
30444
30809
|
}
|
|
30445
30810
|
var init_support = __esm({
|
|
30446
30811
|
"src/mcp/tools/support.ts"() {
|
|
30447
30812
|
"use strict";
|
|
30448
30813
|
init_exe_support();
|
|
30814
|
+
init_license();
|
|
30449
30815
|
}
|
|
30450
30816
|
});
|
|
30451
30817
|
|
|
@@ -30514,21 +30880,21 @@ var init_exe_status = __esm({
|
|
|
30514
30880
|
|
|
30515
30881
|
// src/bin/exe-healthcheck.ts
|
|
30516
30882
|
import { existsSync as existsSync43, readFileSync as readFileSync36, readdirSync as readdirSync14 } from "fs";
|
|
30517
|
-
import
|
|
30518
|
-
import { execSync as
|
|
30883
|
+
import path56 from "path";
|
|
30884
|
+
import { execSync as execSync15 } from "child_process";
|
|
30519
30885
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
30520
30886
|
function findPackageRoot2() {
|
|
30521
|
-
let dir =
|
|
30522
|
-
const { root } =
|
|
30887
|
+
let dir = path56.dirname(fileURLToPath6(import.meta.url));
|
|
30888
|
+
const { root } = path56.parse(dir);
|
|
30523
30889
|
while (dir !== root) {
|
|
30524
|
-
if (existsSync43(
|
|
30525
|
-
dir =
|
|
30890
|
+
if (existsSync43(path56.join(dir, "package.json"))) return dir;
|
|
30891
|
+
dir = path56.dirname(dir);
|
|
30526
30892
|
}
|
|
30527
30893
|
throw new Error("Cannot find package root");
|
|
30528
30894
|
}
|
|
30529
30895
|
function checkBuildIntegrity(pkgRoot) {
|
|
30530
30896
|
const results = [];
|
|
30531
|
-
const tsupConfig =
|
|
30897
|
+
const tsupConfig = path56.join(pkgRoot, "tsup.config.ts");
|
|
30532
30898
|
if (!existsSync43(tsupConfig)) {
|
|
30533
30899
|
return [{ name: "build/tsup-config", pass: false, detail: "tsup.config.ts not found" }];
|
|
30534
30900
|
}
|
|
@@ -30538,7 +30904,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
30538
30904
|
let total = 0;
|
|
30539
30905
|
for (const match of entryMatches) {
|
|
30540
30906
|
const outputKey = match[1];
|
|
30541
|
-
const expectedPath =
|
|
30907
|
+
const expectedPath = path56.join(pkgRoot, "dist", `${outputKey}.js`);
|
|
30542
30908
|
total++;
|
|
30543
30909
|
if (!existsSync43(expectedPath)) {
|
|
30544
30910
|
missing.push(`dist/${outputKey}.js`);
|
|
@@ -30562,7 +30928,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
30562
30928
|
}
|
|
30563
30929
|
function checkEmbedPipeline(pkgRoot) {
|
|
30564
30930
|
const results = [];
|
|
30565
|
-
const daemonPath =
|
|
30931
|
+
const daemonPath = path56.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
30566
30932
|
if (!existsSync43(daemonPath)) {
|
|
30567
30933
|
results.push({
|
|
30568
30934
|
name: "exed/daemon-exists",
|
|
@@ -30574,17 +30940,17 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30574
30940
|
results.push({ name: "exed/daemon-exists", pass: true, detail: "dist/lib/exe-daemon.js exists" });
|
|
30575
30941
|
const entryDirs = ["dist/hooks", "dist/bin", "dist/mcp"];
|
|
30576
30942
|
for (const dir of entryDirs) {
|
|
30577
|
-
const fullDir =
|
|
30943
|
+
const fullDir = path56.join(pkgRoot, dir);
|
|
30578
30944
|
if (!existsSync43(fullDir)) continue;
|
|
30579
30945
|
let walkDir = fullDir;
|
|
30580
|
-
const { root } =
|
|
30946
|
+
const { root } = path56.parse(walkDir);
|
|
30581
30947
|
let foundRoot = null;
|
|
30582
30948
|
while (walkDir !== root) {
|
|
30583
|
-
if (existsSync43(
|
|
30949
|
+
if (existsSync43(path56.join(walkDir, "package.json"))) {
|
|
30584
30950
|
foundRoot = walkDir;
|
|
30585
30951
|
break;
|
|
30586
30952
|
}
|
|
30587
|
-
walkDir =
|
|
30953
|
+
walkDir = path56.dirname(walkDir);
|
|
30588
30954
|
}
|
|
30589
30955
|
if (!foundRoot) {
|
|
30590
30956
|
results.push({
|
|
@@ -30594,7 +30960,7 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30594
30960
|
});
|
|
30595
30961
|
continue;
|
|
30596
30962
|
}
|
|
30597
|
-
const resolvedDaemon =
|
|
30963
|
+
const resolvedDaemon = path56.join(foundRoot, "dist", "lib", "exe-daemon.js");
|
|
30598
30964
|
const reachable = existsSync43(resolvedDaemon);
|
|
30599
30965
|
results.push({
|
|
30600
30966
|
name: `exed/reachable-from-${dir}`,
|
|
@@ -30606,13 +30972,13 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30606
30972
|
}
|
|
30607
30973
|
function checkTaskSystem(pkgRoot) {
|
|
30608
30974
|
const results = [];
|
|
30609
|
-
const scannerPath =
|
|
30975
|
+
const scannerPath = path56.join(pkgRoot, "dist", "bin", "scan-tasks.js");
|
|
30610
30976
|
if (!existsSync43(scannerPath)) {
|
|
30611
30977
|
results.push({ name: "tasks/scanner", pass: false, detail: "scan-tasks.js not found" });
|
|
30612
30978
|
return results;
|
|
30613
30979
|
}
|
|
30614
30980
|
try {
|
|
30615
|
-
|
|
30981
|
+
execSync15(`node "${scannerPath}" /tmp/nonexistent-healthcheck-test --format=json 2>/dev/null`, {
|
|
30616
30982
|
timeout: 1e4,
|
|
30617
30983
|
encoding: "utf-8"
|
|
30618
30984
|
});
|
|
@@ -30629,13 +30995,13 @@ function checkTaskSystem(pkgRoot) {
|
|
|
30629
30995
|
}
|
|
30630
30996
|
function checkWorkerSpawning(pkgRoot) {
|
|
30631
30997
|
const results = [];
|
|
30632
|
-
const workerPath =
|
|
30998
|
+
const workerPath = path56.join(pkgRoot, "dist", "hooks", "ingest-worker.js");
|
|
30633
30999
|
if (!existsSync43(workerPath)) {
|
|
30634
31000
|
results.push({ name: "workers/ingest-worker", pass: false, detail: "ingest-worker.js not found" });
|
|
30635
31001
|
return results;
|
|
30636
31002
|
}
|
|
30637
31003
|
try {
|
|
30638
|
-
|
|
31004
|
+
execSync15(`node --check "${workerPath}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
30639
31005
|
results.push({ name: "workers/ingest-worker", pass: true, detail: "ingest-worker.js parses OK" });
|
|
30640
31006
|
} catch (err) {
|
|
30641
31007
|
results.push({
|
|
@@ -30644,14 +31010,14 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
30644
31010
|
detail: `Parse error: ${err instanceof Error ? err.message.slice(0, 200) : String(err)}`
|
|
30645
31011
|
});
|
|
30646
31012
|
}
|
|
30647
|
-
const hooksDir =
|
|
31013
|
+
const hooksDir = path56.join(pkgRoot, "dist", "hooks");
|
|
30648
31014
|
if (existsSync43(hooksDir)) {
|
|
30649
31015
|
const hookFiles = readdirSync14(hooksDir).filter((f) => f.endsWith(".js") && !f.endsWith(".js.map"));
|
|
30650
31016
|
let hooksPassed = 0;
|
|
30651
31017
|
const hooksFailed = [];
|
|
30652
31018
|
for (const hook of hookFiles) {
|
|
30653
31019
|
try {
|
|
30654
|
-
|
|
31020
|
+
execSync15(`node --check "${path56.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
30655
31021
|
hooksPassed++;
|
|
30656
31022
|
} catch {
|
|
30657
31023
|
hooksFailed.push(hook);
|
|
@@ -30675,8 +31041,8 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
30675
31041
|
}
|
|
30676
31042
|
function checkMcpTransport() {
|
|
30677
31043
|
const results = [];
|
|
30678
|
-
const pidPath =
|
|
30679
|
-
const tokenPath =
|
|
31044
|
+
const pidPath = path56.join(EXE_AI_DIR, "exed.pid");
|
|
31045
|
+
const tokenPath = path56.join(EXE_AI_DIR, "exed.token");
|
|
30680
31046
|
let daemonAlive = false;
|
|
30681
31047
|
if (existsSync43(pidPath)) {
|
|
30682
31048
|
try {
|
|
@@ -30693,7 +31059,7 @@ function checkMcpTransport() {
|
|
|
30693
31059
|
if (daemonAlive && existsSync43(tokenPath)) {
|
|
30694
31060
|
try {
|
|
30695
31061
|
const token = readFileSync36(tokenPath, "utf8").trim();
|
|
30696
|
-
const response =
|
|
31062
|
+
const response = execSync15(
|
|
30697
31063
|
`curl -sS -i -m 2 -H "Authorization: Bearer ${token}" -H 'Accept: application/json, text/event-stream' http://127.0.0.1:48739/mcp`,
|
|
30698
31064
|
{ encoding: "utf8", timeout: 3e3 }
|
|
30699
31065
|
);
|
|
@@ -30723,7 +31089,7 @@ function checkMcpTransport() {
|
|
|
30723
31089
|
results.push({
|
|
30724
31090
|
name: "mcp/monitor-summary",
|
|
30725
31091
|
pass: true,
|
|
30726
|
-
detail: `Privacy-safe local monitor summary: ${
|
|
31092
|
+
detail: `Privacy-safe local monitor summary: ${path56.join(EXE_AI_DIR, "monitor", "mcp-transport-summary.json")}`
|
|
30727
31093
|
});
|
|
30728
31094
|
return results;
|
|
30729
31095
|
}
|
|
@@ -30744,7 +31110,7 @@ function checkClaudeCodeInstall() {
|
|
|
30744
31110
|
});
|
|
30745
31111
|
}
|
|
30746
31112
|
try {
|
|
30747
|
-
const claudePath =
|
|
31113
|
+
const claudePath = execSync15("which claude 2>/dev/null || true", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
30748
31114
|
if (!claudePath) {
|
|
30749
31115
|
results.push({
|
|
30750
31116
|
name: "cc/cli-binary",
|
|
@@ -30754,7 +31120,7 @@ function checkClaudeCodeInstall() {
|
|
|
30754
31120
|
} else {
|
|
30755
31121
|
let resolved = claudePath;
|
|
30756
31122
|
try {
|
|
30757
|
-
resolved =
|
|
31123
|
+
resolved = execSync15(`readlink -f "${claudePath}" 2>/dev/null || readlink "${claudePath}" 2>/dev/null || echo "${claudePath}"`, {
|
|
30758
31124
|
encoding: "utf8",
|
|
30759
31125
|
timeout: 5e3
|
|
30760
31126
|
}).trim();
|
|
@@ -30781,7 +31147,7 @@ function checkClaudeCodeInstall() {
|
|
|
30781
31147
|
detail: "Failed to check claude binary path"
|
|
30782
31148
|
});
|
|
30783
31149
|
}
|
|
30784
|
-
const versionsDir =
|
|
31150
|
+
const versionsDir = path56.join(
|
|
30785
31151
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
30786
31152
|
".local",
|
|
30787
31153
|
"share",
|
|
@@ -30838,7 +31204,7 @@ function checkClaudeCodeInstall() {
|
|
|
30838
31204
|
});
|
|
30839
31205
|
}
|
|
30840
31206
|
try {
|
|
30841
|
-
const ccVersion =
|
|
31207
|
+
const ccVersion = execSync15("claude --version 2>/dev/null || echo unknown", {
|
|
30842
31208
|
encoding: "utf8",
|
|
30843
31209
|
timeout: 5e3
|
|
30844
31210
|
}).trim();
|
|
@@ -30900,17 +31266,17 @@ __export(update_check_exports, {
|
|
|
30900
31266
|
getLocalVersion: () => getLocalVersion,
|
|
30901
31267
|
getRemoteVersion: () => getRemoteVersion
|
|
30902
31268
|
});
|
|
30903
|
-
import { execSync as
|
|
31269
|
+
import { execSync as execSync16 } from "child_process";
|
|
30904
31270
|
import { readFileSync as readFileSync37 } from "fs";
|
|
30905
|
-
import
|
|
31271
|
+
import path57 from "path";
|
|
30906
31272
|
function getLocalVersion(packageRoot) {
|
|
30907
|
-
const pkgPath =
|
|
31273
|
+
const pkgPath = path57.join(packageRoot, "package.json");
|
|
30908
31274
|
const pkg = JSON.parse(readFileSync37(pkgPath, "utf-8"));
|
|
30909
31275
|
return pkg.version;
|
|
30910
31276
|
}
|
|
30911
31277
|
function getRemoteVersion() {
|
|
30912
31278
|
try {
|
|
30913
|
-
const output =
|
|
31279
|
+
const output = execSync16("npm view @askexenow/exe-os version", {
|
|
30914
31280
|
encoding: "utf-8",
|
|
30915
31281
|
timeout: 15e3,
|
|
30916
31282
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -30944,7 +31310,7 @@ var init_update_check = __esm({
|
|
|
30944
31310
|
// src/mcp/tools/cli-parity.ts
|
|
30945
31311
|
import { execFile as execFile2 } from "child_process";
|
|
30946
31312
|
import { promisify as promisify2 } from "util";
|
|
30947
|
-
import { z as
|
|
31313
|
+
import { z as z91 } from "zod";
|
|
30948
31314
|
async function runCommand(command, args, timeout = 6e4) {
|
|
30949
31315
|
const printable = [command, ...args].join(" ");
|
|
30950
31316
|
try {
|
|
@@ -30979,12 +31345,12 @@ function registerCliParityTools(server) {
|
|
|
30979
31345
|
title: "Doctor",
|
|
30980
31346
|
description: "Run exe-os doctor audit. Defaults to read-only diagnostics; optional dry-run/fix flags mirror CLI.",
|
|
30981
31347
|
inputSchema: {
|
|
30982
|
-
agent:
|
|
30983
|
-
project:
|
|
30984
|
-
verbose:
|
|
30985
|
-
conflicts:
|
|
30986
|
-
dry_run:
|
|
30987
|
-
fix:
|
|
31348
|
+
agent: z91.string().optional(),
|
|
31349
|
+
project: z91.string().optional(),
|
|
31350
|
+
verbose: z91.boolean().default(false),
|
|
31351
|
+
conflicts: z91.boolean().default(false),
|
|
31352
|
+
dry_run: z91.boolean().default(false),
|
|
31353
|
+
fix: z91.boolean().default(false)
|
|
30988
31354
|
}
|
|
30989
31355
|
}, async ({ agent, project, verbose, conflicts, dry_run, fix }) => {
|
|
30990
31356
|
const args = [];
|
|
@@ -31001,9 +31367,9 @@ function registerCliParityTools(server) {
|
|
|
31001
31367
|
title: "Rename Employee",
|
|
31002
31368
|
description: "Rename an employee using the same path as `exe-os rename <old> <new>`. Use for customer roster/identity renames.",
|
|
31003
31369
|
inputSchema: {
|
|
31004
|
-
old_name:
|
|
31005
|
-
new_name:
|
|
31006
|
-
dry_run:
|
|
31370
|
+
old_name: z91.string().min(1),
|
|
31371
|
+
new_name: z91.string().min(1),
|
|
31372
|
+
dry_run: z91.boolean().default(false)
|
|
31007
31373
|
}
|
|
31008
31374
|
}, async ({ old_name, new_name, dry_run }) => {
|
|
31009
31375
|
if (dry_run) {
|
|
@@ -31016,7 +31382,7 @@ function registerCliParityTools(server) {
|
|
|
31016
31382
|
server.registerTool("status_brief", {
|
|
31017
31383
|
title: "Status Brief",
|
|
31018
31384
|
description: "Return current employee/tmux status. Mirrors `exe-status` and supports optional deep view for one employee.",
|
|
31019
|
-
inputSchema: { employee:
|
|
31385
|
+
inputSchema: { employee: z91.string().optional() }
|
|
31020
31386
|
}, async ({ employee }) => {
|
|
31021
31387
|
const text3 = await status(employee);
|
|
31022
31388
|
return result2(text3, { ok: true, employee: employee ?? null });
|
|
@@ -31024,7 +31390,7 @@ function registerCliParityTools(server) {
|
|
|
31024
31390
|
server.registerTool("pending_work_summary", {
|
|
31025
31391
|
title: "Pending Work Summary",
|
|
31026
31392
|
description: "Return pending reviews, messages, and notifications using the same summaries as the CLI tools.",
|
|
31027
|
-
inputSchema: { agent:
|
|
31393
|
+
inputSchema: { agent: z91.string().optional() }
|
|
31028
31394
|
}, async ({ agent }) => {
|
|
31029
31395
|
const parts = await Promise.all([
|
|
31030
31396
|
runCommand("exe-pending-reviews", [], 3e4),
|
|
@@ -31045,7 +31411,7 @@ function registerCliParityTools(server) {
|
|
|
31045
31411
|
server.registerTool("key_rotation_preflight", {
|
|
31046
31412
|
title: "Key Rotation Preflight",
|
|
31047
31413
|
description: "Dry-run key rotation/update preflight. No destructive changes.",
|
|
31048
|
-
inputSchema: { mode:
|
|
31414
|
+
inputSchema: { mode: z91.enum(["rotate", "update"]).default("rotate") }
|
|
31049
31415
|
}, async ({ mode }) => {
|
|
31050
31416
|
const out = await runCommand("exe-os", ["key", mode, "--dry-run"], 6e4);
|
|
31051
31417
|
return result2(out.text, { ok: out.ok, command: out.command, mode }, !out.ok);
|
|
@@ -31064,11 +31430,11 @@ function registerCliParityTools(server) {
|
|
|
31064
31430
|
title: "Stack Update Check",
|
|
31065
31431
|
description: "Plan/check a customer stack update without applying Docker changes. Mirrors `exe-os stack-update --check`.",
|
|
31066
31432
|
inputSchema: {
|
|
31067
|
-
target:
|
|
31068
|
-
manifest:
|
|
31069
|
-
compose_file:
|
|
31070
|
-
env_file:
|
|
31071
|
-
deployment_persona:
|
|
31433
|
+
target: z91.string().optional(),
|
|
31434
|
+
manifest: z91.string().optional(),
|
|
31435
|
+
compose_file: z91.string().optional(),
|
|
31436
|
+
env_file: z91.string().optional(),
|
|
31437
|
+
deployment_persona: z91.enum(["customer", "askexe-control-plane"]).default("customer")
|
|
31072
31438
|
}
|
|
31073
31439
|
}, async ({ target, manifest, compose_file, env_file, deployment_persona }) => {
|
|
31074
31440
|
const args = ["stack-update", "--check", "--deployment-persona", deployment_persona];
|
|
@@ -31189,7 +31555,7 @@ var init_session_events = __esm({
|
|
|
31189
31555
|
});
|
|
31190
31556
|
|
|
31191
31557
|
// src/mcp/tools/get-session-events.ts
|
|
31192
|
-
import { z as
|
|
31558
|
+
import { z as z92 } from "zod";
|
|
31193
31559
|
function canReadAgent(activeRole, activeAgent, requestedAgent) {
|
|
31194
31560
|
return requestedAgent === activeAgent || activeRole === "COO" || activeRole === "CTO";
|
|
31195
31561
|
}
|
|
@@ -31213,11 +31579,11 @@ function registerGetSessionEvents(server) {
|
|
|
31213
31579
|
title: "Get Session Events",
|
|
31214
31580
|
description: "Return exact recent chronological user prompts, assistant responses, and tool calls from the append-only session journal. Use this when asked what happened last, not semantic memory search.",
|
|
31215
31581
|
inputSchema: {
|
|
31216
|
-
agent_id:
|
|
31217
|
-
session_id:
|
|
31582
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
31583
|
+
session_id: z92.string().optional().describe("Optional exact runtime session id."),
|
|
31218
31584
|
event_type: EVENT_TYPE.optional().describe("Filter to one event type."),
|
|
31219
|
-
project_name:
|
|
31220
|
-
limit:
|
|
31585
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects."),
|
|
31586
|
+
limit: z92.number().int().min(1).max(100).default(20).describe("Number of events to return.")
|
|
31221
31587
|
}
|
|
31222
31588
|
},
|
|
31223
31589
|
async ({ agent_id, session_id, event_type, project_name, limit }) => {
|
|
@@ -31253,8 +31619,8 @@ function registerGetLastAssistantResponse(server) {
|
|
|
31253
31619
|
title: "Get Last Assistant Response",
|
|
31254
31620
|
description: "Return the exact last assistant response for an agent from the session event journal. Use for 'what was the last thing you said?'",
|
|
31255
31621
|
inputSchema: {
|
|
31256
|
-
agent_id:
|
|
31257
|
-
project_name:
|
|
31622
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
31623
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects.")
|
|
31258
31624
|
}
|
|
31259
31625
|
},
|
|
31260
31626
|
async ({ agent_id, project_name }) => {
|
|
@@ -31289,7 +31655,7 @@ var init_get_session_events = __esm({
|
|
|
31289
31655
|
init_active_agent();
|
|
31290
31656
|
init_fast_db_init();
|
|
31291
31657
|
init_session_events();
|
|
31292
|
-
EVENT_TYPE =
|
|
31658
|
+
EVENT_TYPE = z92.enum([
|
|
31293
31659
|
"user_prompt",
|
|
31294
31660
|
"assistant_response",
|
|
31295
31661
|
"tool_call",
|
|
@@ -31300,25 +31666,96 @@ var init_get_session_events = __esm({
|
|
|
31300
31666
|
});
|
|
31301
31667
|
|
|
31302
31668
|
// src/lib/code-context-index.ts
|
|
31303
|
-
import
|
|
31304
|
-
import
|
|
31669
|
+
import crypto21 from "crypto";
|
|
31670
|
+
import path58 from "path";
|
|
31305
31671
|
import { existsSync as existsSync44, mkdirSync as mkdirSync22, readFileSync as readFileSync38, readdirSync as readdirSync15, statSync as statSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
31306
31672
|
import { spawnSync } from "child_process";
|
|
31673
|
+
function vectorStorePath(projectRoot) {
|
|
31674
|
+
const rootHash = hashText(projectRoot).slice(0, 16);
|
|
31675
|
+
return path58.join(indexDir(), `${rootHash}.vectors.json`);
|
|
31676
|
+
}
|
|
31677
|
+
function loadVectorStore(projectRoot) {
|
|
31678
|
+
const file = vectorStorePath(projectRoot);
|
|
31679
|
+
if (!existsSync44(file)) return null;
|
|
31680
|
+
try {
|
|
31681
|
+
const parsed = JSON.parse(readFileSync38(file, "utf8"));
|
|
31682
|
+
if (parsed.version !== VECTOR_STORE_VERSION) return null;
|
|
31683
|
+
return parsed;
|
|
31684
|
+
} catch {
|
|
31685
|
+
return null;
|
|
31686
|
+
}
|
|
31687
|
+
}
|
|
31688
|
+
function saveVectorStore(projectRoot, store) {
|
|
31689
|
+
writeFileSync25(vectorStorePath(projectRoot), JSON.stringify(store));
|
|
31690
|
+
}
|
|
31691
|
+
function cosineSimilarity3(a, b) {
|
|
31692
|
+
let dot = 0, normA = 0, normB = 0;
|
|
31693
|
+
for (let i = 0; i < a.length; i++) {
|
|
31694
|
+
dot += a[i] * b[i];
|
|
31695
|
+
normA += a[i] * a[i];
|
|
31696
|
+
normB += b[i] * b[i];
|
|
31697
|
+
}
|
|
31698
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
31699
|
+
return denom === 0 ? 0 : dot / denom;
|
|
31700
|
+
}
|
|
31701
|
+
async function embedSymbols(index) {
|
|
31702
|
+
const rootHash = hashText(index.projectRoot).slice(0, 16);
|
|
31703
|
+
const existing = loadVectorStore(index.projectRoot);
|
|
31704
|
+
const store = {
|
|
31705
|
+
version: VECTOR_STORE_VERSION,
|
|
31706
|
+
projectRootHash: rootHash,
|
|
31707
|
+
vectors: {}
|
|
31708
|
+
};
|
|
31709
|
+
const allSymbols = [];
|
|
31710
|
+
for (const file of Object.values(index.files)) {
|
|
31711
|
+
for (const symbol of file.symbols) {
|
|
31712
|
+
if (existing?.vectors[symbol.id]) {
|
|
31713
|
+
store.vectors[symbol.id] = existing.vectors[symbol.id];
|
|
31714
|
+
} else {
|
|
31715
|
+
allSymbols.push({ id: symbol.id, text: symbol.summary || `${symbol.kind} ${symbol.name} in ${symbol.filePath}` });
|
|
31716
|
+
}
|
|
31717
|
+
}
|
|
31718
|
+
}
|
|
31719
|
+
if (allSymbols.length === 0) {
|
|
31720
|
+
saveVectorStore(index.projectRoot, store);
|
|
31721
|
+
return store;
|
|
31722
|
+
}
|
|
31723
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
31724
|
+
if (!connected) {
|
|
31725
|
+
saveVectorStore(index.projectRoot, store);
|
|
31726
|
+
return store;
|
|
31727
|
+
}
|
|
31728
|
+
for (let i = 0; i < allSymbols.length; i += EMBED_BATCH_SIZE) {
|
|
31729
|
+
const batch = allSymbols.slice(i, i + EMBED_BATCH_SIZE);
|
|
31730
|
+
const texts = batch.map((s) => s.text);
|
|
31731
|
+
try {
|
|
31732
|
+
const vectors = await embedBatchViaClient(texts, "low");
|
|
31733
|
+
if (vectors && vectors.length === batch.length) {
|
|
31734
|
+
for (let j = 0; j < batch.length; j++) {
|
|
31735
|
+
store.vectors[batch[j].id] = vectors[j];
|
|
31736
|
+
}
|
|
31737
|
+
}
|
|
31738
|
+
} catch {
|
|
31739
|
+
}
|
|
31740
|
+
}
|
|
31741
|
+
saveVectorStore(index.projectRoot, store);
|
|
31742
|
+
return store;
|
|
31743
|
+
}
|
|
31307
31744
|
function normalizeProjectRoot(projectRoot) {
|
|
31308
|
-
return
|
|
31745
|
+
return path58.resolve(projectRoot || process.cwd());
|
|
31309
31746
|
}
|
|
31310
31747
|
function hashText(text3) {
|
|
31311
|
-
return
|
|
31748
|
+
return crypto21.createHash("sha256").update(text3).digest("hex");
|
|
31312
31749
|
}
|
|
31313
31750
|
function indexDir() {
|
|
31314
|
-
const dir =
|
|
31751
|
+
const dir = path58.join(EXE_AI_DIR, "code-context");
|
|
31315
31752
|
mkdirSync22(dir, { recursive: true });
|
|
31316
31753
|
return dir;
|
|
31317
31754
|
}
|
|
31318
31755
|
function getCodeContextIndexPath(projectRoot) {
|
|
31319
31756
|
const root = normalizeProjectRoot(projectRoot);
|
|
31320
31757
|
const rootHash = hashText(root).slice(0, 16);
|
|
31321
|
-
return
|
|
31758
|
+
return path58.join(indexDir(), `${rootHash}.json`);
|
|
31322
31759
|
}
|
|
31323
31760
|
function currentBranch(projectRoot) {
|
|
31324
31761
|
const result3 = spawnSync("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
@@ -31331,8 +31768,8 @@ function shouldIgnore(relPath) {
|
|
|
31331
31768
|
}
|
|
31332
31769
|
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
31333
31770
|
for (const entry of readdirSync15(dir, { withFileTypes: true })) {
|
|
31334
|
-
const abs =
|
|
31335
|
-
const rel =
|
|
31771
|
+
const abs = path58.join(dir, entry.name);
|
|
31772
|
+
const rel = path58.relative(projectRoot, abs).replaceAll(path58.sep, "/");
|
|
31336
31773
|
if (shouldIgnore(rel)) continue;
|
|
31337
31774
|
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
31338
31775
|
else if (entry.isFile()) out.push(rel);
|
|
@@ -31348,7 +31785,7 @@ function listCodeFiles(projectRoot, maxFiles) {
|
|
|
31348
31785
|
const rg = spawnSync("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
31349
31786
|
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
31350
31787
|
}
|
|
31351
|
-
return files.map((file) => file.replaceAll(
|
|
31788
|
+
return files.map((file) => file.replaceAll(path58.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
31352
31789
|
}
|
|
31353
31790
|
function parseImportPaths2(importText) {
|
|
31354
31791
|
const paths = [];
|
|
@@ -31361,13 +31798,13 @@ function parseImportPaths2(importText) {
|
|
|
31361
31798
|
}
|
|
31362
31799
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
31363
31800
|
if (!importPath.startsWith(".")) return null;
|
|
31364
|
-
const base =
|
|
31801
|
+
const base = path58.posix.normalize(path58.posix.join(path58.posix.dirname(fromFile.replaceAll(path58.sep, "/")), importPath));
|
|
31365
31802
|
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
31366
31803
|
const candidates = [base];
|
|
31367
31804
|
for (const ext of ["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "cs", "cpp", "c", "rb", "php", "swift", "kt", "scala", "sql", "md", "json", "yaml", "yml"]) {
|
|
31368
31805
|
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
31369
31806
|
}
|
|
31370
|
-
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(
|
|
31807
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path58.posix.join(base, indexName));
|
|
31371
31808
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
31372
31809
|
}
|
|
31373
31810
|
function symbolId(filePath, chunk) {
|
|
@@ -31388,7 +31825,7 @@ function saveIndex(index) {
|
|
|
31388
31825
|
writeFileSync25(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
|
|
31389
31826
|
}
|
|
31390
31827
|
function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
31391
|
-
const absPath =
|
|
31828
|
+
const absPath = path58.join(projectRoot, relPath);
|
|
31392
31829
|
let stat;
|
|
31393
31830
|
try {
|
|
31394
31831
|
stat = statSync10(absPath);
|
|
@@ -31426,13 +31863,13 @@ function buildCodeContextIndex(options = {}) {
|
|
|
31426
31863
|
const branch = currentBranch(projectRoot);
|
|
31427
31864
|
const previous = options.force ? null : loadIndex(projectRoot);
|
|
31428
31865
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
31429
|
-
const allFiles = new Set(files.map((file) => file.replaceAll(
|
|
31866
|
+
const allFiles = new Set(files.map((file) => file.replaceAll(path58.sep, "/")));
|
|
31430
31867
|
const fileRecords = {};
|
|
31431
31868
|
let rebuiltFiles = 0;
|
|
31432
31869
|
let reusedFiles = 0;
|
|
31433
31870
|
let skippedFiles = 0;
|
|
31434
31871
|
for (const rel of files) {
|
|
31435
|
-
const normalized = rel.replaceAll(
|
|
31872
|
+
const normalized = rel.replaceAll(path58.sep, "/");
|
|
31436
31873
|
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
31437
31874
|
if (record) {
|
|
31438
31875
|
fileRecords[normalized] = record;
|
|
@@ -31461,11 +31898,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
31461
31898
|
if (loaded) {
|
|
31462
31899
|
const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
|
|
31463
31900
|
const unchanged = currentFiles.every((rel) => {
|
|
31464
|
-
const normalized = rel.replaceAll(
|
|
31901
|
+
const normalized = rel.replaceAll(path58.sep, "/");
|
|
31465
31902
|
const existing = loaded.files[normalized];
|
|
31466
31903
|
if (!existing) return false;
|
|
31467
31904
|
try {
|
|
31468
|
-
const stat = statSync10(
|
|
31905
|
+
const stat = statSync10(path58.join(projectRoot, normalized));
|
|
31469
31906
|
return stat.mtimeMs === existing.mtimeMs && stat.size === existing.size;
|
|
31470
31907
|
} catch {
|
|
31471
31908
|
return false;
|
|
@@ -31518,9 +31955,9 @@ function globToRegex(pattern) {
|
|
|
31518
31955
|
}
|
|
31519
31956
|
function matchesPath(filePath, patterns) {
|
|
31520
31957
|
if (!patterns || patterns.length === 0) return true;
|
|
31521
|
-
const normalized = filePath.replaceAll(
|
|
31958
|
+
const normalized = filePath.replaceAll(path58.sep, "/");
|
|
31522
31959
|
return patterns.some((pattern) => {
|
|
31523
|
-
const p = pattern.replaceAll(
|
|
31960
|
+
const p = pattern.replaceAll(path58.sep, "/").replace(/^\.\//, "");
|
|
31524
31961
|
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
31525
31962
|
});
|
|
31526
31963
|
}
|
|
@@ -31579,7 +32016,7 @@ function filteredFiles(index, options = {}) {
|
|
|
31579
32016
|
return matchesPath(file.path, options.paths);
|
|
31580
32017
|
});
|
|
31581
32018
|
}
|
|
31582
|
-
function
|
|
32019
|
+
function lexicalSearch(query, options = {}) {
|
|
31583
32020
|
const terms = tokenize(query);
|
|
31584
32021
|
if (terms.length === 0) return [];
|
|
31585
32022
|
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
@@ -31605,6 +32042,81 @@ function searchCodeContext(query, options = {}) {
|
|
|
31605
32042
|
const limit = options.limit ?? 20;
|
|
31606
32043
|
return results.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
31607
32044
|
}
|
|
32045
|
+
function searchCodeContext(query, options = {}) {
|
|
32046
|
+
return lexicalSearch(query, options);
|
|
32047
|
+
}
|
|
32048
|
+
async function searchCodeContextSemantic(query, options = {}) {
|
|
32049
|
+
const terms = tokenize(query);
|
|
32050
|
+
if (terms.length === 0) return [];
|
|
32051
|
+
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
32052
|
+
const projectRoot = normalizeProjectRoot(options.projectRoot);
|
|
32053
|
+
const vectorStore = loadVectorStore(projectRoot);
|
|
32054
|
+
if (!vectorStore || Object.keys(vectorStore.vectors).length === 0) {
|
|
32055
|
+
return lexicalSearch(query, options);
|
|
32056
|
+
}
|
|
32057
|
+
let queryVector = null;
|
|
32058
|
+
try {
|
|
32059
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
32060
|
+
if (connected) {
|
|
32061
|
+
const result3 = await embedBatchViaClient([query], "high");
|
|
32062
|
+
if (result3 && result3.length === 1) queryVector = result3[0];
|
|
32063
|
+
}
|
|
32064
|
+
} catch {
|
|
32065
|
+
}
|
|
32066
|
+
if (!queryVector) return lexicalSearch(query, options);
|
|
32067
|
+
const files = filteredFiles(index, options);
|
|
32068
|
+
const candidates = [];
|
|
32069
|
+
for (const file of files) {
|
|
32070
|
+
for (const symbol of file.symbols) {
|
|
32071
|
+
const lexical = scoreSymbol(symbol, terms);
|
|
32072
|
+
const vec = vectorStore.vectors[symbol.id];
|
|
32073
|
+
const vectorScore = vec ? cosineSimilarity3(queryVector, vec) : 0;
|
|
32074
|
+
if (lexical.score > 0 || vectorScore > 0.3) {
|
|
32075
|
+
candidates.push({
|
|
32076
|
+
symbol,
|
|
32077
|
+
lexicalScore: lexical.score,
|
|
32078
|
+
vectorScore,
|
|
32079
|
+
matches: lexical.matches
|
|
32080
|
+
});
|
|
32081
|
+
}
|
|
32082
|
+
}
|
|
32083
|
+
}
|
|
32084
|
+
const byLexical = [...candidates].sort((a, b) => b.lexicalScore - a.lexicalScore);
|
|
32085
|
+
const byVector = [...candidates].sort((a, b) => b.vectorScore - a.vectorScore);
|
|
32086
|
+
const lexicalRank = /* @__PURE__ */ new Map();
|
|
32087
|
+
const vectorRank = /* @__PURE__ */ new Map();
|
|
32088
|
+
byLexical.forEach((c, i) => lexicalRank.set(c.symbol.id, i + 1));
|
|
32089
|
+
byVector.forEach((c, i) => vectorRank.set(c.symbol.id, i + 1));
|
|
32090
|
+
const VECTOR_WEIGHT = 0.6;
|
|
32091
|
+
const LEXICAL_WEIGHT = 0.4;
|
|
32092
|
+
const fused = candidates.map((c) => {
|
|
32093
|
+
const lRank = lexicalRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
32094
|
+
const vRank = vectorRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
32095
|
+
const rrfScore = VECTOR_WEIGHT * (1 / (RRF_K2 + vRank)) + LEXICAL_WEIGHT * (1 / (RRF_K2 + lRank));
|
|
32096
|
+
return {
|
|
32097
|
+
symbol: c.symbol,
|
|
32098
|
+
score: rrfScore,
|
|
32099
|
+
matches: c.vectorScore > 0.3 ? [...c.matches, `semantic=${c.vectorScore.toFixed(3)}`] : c.matches,
|
|
32100
|
+
filePath: c.symbol.filePath,
|
|
32101
|
+
language: c.symbol.language,
|
|
32102
|
+
content: c.symbol.text,
|
|
32103
|
+
startLine: c.symbol.startLine,
|
|
32104
|
+
endLine: c.symbol.endLine
|
|
32105
|
+
};
|
|
32106
|
+
});
|
|
32107
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
32108
|
+
const limit = options.limit ?? 20;
|
|
32109
|
+
return fused.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
32110
|
+
}
|
|
32111
|
+
async function buildCodeContextIndexWithEmbeddings(options = {}) {
|
|
32112
|
+
const index = buildCodeContextIndex(options);
|
|
32113
|
+
const existingStore = loadVectorStore(index.projectRoot);
|
|
32114
|
+
const existingCount = existingStore ? Object.keys(existingStore.vectors).length : 0;
|
|
32115
|
+
const store = await embedSymbols(index);
|
|
32116
|
+
const vectorCount = Object.keys(store.vectors).length;
|
|
32117
|
+
const newEmbeddings = vectorCount - Math.min(existingCount, vectorCount);
|
|
32118
|
+
return { index, vectorCount, newEmbeddings };
|
|
32119
|
+
}
|
|
31608
32120
|
function dependentsMap(index) {
|
|
31609
32121
|
const map = /* @__PURE__ */ new Map();
|
|
31610
32122
|
for (const file of Object.values(index.files)) {
|
|
@@ -31638,7 +32150,7 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
31638
32150
|
}
|
|
31639
32151
|
function resolveTargetFile(index, input) {
|
|
31640
32152
|
if (input.filePath) {
|
|
31641
|
-
const normalized = input.filePath.replaceAll(
|
|
32153
|
+
const normalized = input.filePath.replaceAll(path58.sep, "/").replace(/^\.\//, "");
|
|
31642
32154
|
if (index.files[normalized]) return { filePath: normalized, target: normalized };
|
|
31643
32155
|
const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
|
|
31644
32156
|
if (suffix) return { filePath: suffix, target: input.filePath };
|
|
@@ -31668,7 +32180,7 @@ function analyzeBlastRadius(input) {
|
|
|
31668
32180
|
}
|
|
31669
32181
|
}
|
|
31670
32182
|
}
|
|
31671
|
-
const targetBase =
|
|
32183
|
+
const targetBase = path58.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
|
|
31672
32184
|
const symbolLower = input.symbol?.toLowerCase();
|
|
31673
32185
|
const tests = Object.keys(index.files).filter((file) => {
|
|
31674
32186
|
const lower = file.toLowerCase();
|
|
@@ -31696,20 +32208,24 @@ function getCodeContextStats(options = {}) {
|
|
|
31696
32208
|
indexPath: getCodeContextIndexPath(index.projectRoot)
|
|
31697
32209
|
};
|
|
31698
32210
|
}
|
|
31699
|
-
var INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS;
|
|
32211
|
+
var VECTOR_STORE_VERSION, EMBED_BATCH_SIZE, INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS, RRF_K2;
|
|
31700
32212
|
var init_code_context_index = __esm({
|
|
31701
32213
|
"src/lib/code-context-index.ts"() {
|
|
31702
32214
|
"use strict";
|
|
31703
32215
|
init_config();
|
|
31704
32216
|
init_code_chunker();
|
|
32217
|
+
init_exe_daemon_client();
|
|
32218
|
+
VECTOR_STORE_VERSION = 1;
|
|
32219
|
+
EMBED_BATCH_SIZE = 64;
|
|
31705
32220
|
INDEX_VERSION = 2;
|
|
31706
32221
|
DEFAULT_MAX_FILES = 5e3;
|
|
31707
32222
|
IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
32223
|
+
RRF_K2 = 60;
|
|
31708
32224
|
}
|
|
31709
32225
|
});
|
|
31710
32226
|
|
|
31711
32227
|
// src/mcp/tools/code-context.ts
|
|
31712
|
-
import { z as
|
|
32228
|
+
import { z as z93 } from "zod";
|
|
31713
32229
|
function errorResult10(text3) {
|
|
31714
32230
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
31715
32231
|
}
|
|
@@ -31719,23 +32235,24 @@ function jsonResult(value) {
|
|
|
31719
32235
|
function registerCodeContext(server) {
|
|
31720
32236
|
server.registerTool("code_context", {
|
|
31721
32237
|
title: "Code Context",
|
|
31722
|
-
description: "Persistent codebase context engine. One consolidated tool to avoid MCP bloat. Actions: index, search, trace, blast_radius, stats.",
|
|
32238
|
+
description: "Persistent codebase context engine with semantic vector search. One consolidated tool to avoid MCP bloat. Actions: index (structural only), index_embed (structural + vector embeddings), search (semantic+lexical hybrid), trace, blast_radius, stats. Search uses RRF fusion of Jina v5 embeddings (cosine similarity) + lexical scoring. Falls back to lexical if daemon unavailable.",
|
|
31723
32239
|
inputSchema: {
|
|
31724
|
-
action:
|
|
31725
|
-
project_root:
|
|
31726
|
-
query:
|
|
31727
|
-
symbol:
|
|
31728
|
-
file_path:
|
|
31729
|
-
force:
|
|
31730
|
-
limit:
|
|
31731
|
-
offset:
|
|
31732
|
-
refresh_index:
|
|
31733
|
-
languages:
|
|
31734
|
-
paths:
|
|
31735
|
-
depth:
|
|
31736
|
-
max_files:
|
|
31737
|
-
|
|
31738
|
-
|
|
32240
|
+
action: z93.enum(["index", "index_embed", "search", "trace", "blast_radius", "stats"]).describe("Code context operation. index_embed = index + generate embeddings for semantic search."),
|
|
32241
|
+
project_root: z93.string().optional().describe("Repository root. Defaults to current working directory."),
|
|
32242
|
+
query: z93.string().optional().describe("Natural language search query (e.g. 'authentication logic', 'database migration'). Semantic search finds conceptual matches, not just keywords."),
|
|
32243
|
+
symbol: z93.string().optional().describe("Symbol/function/class/type name for trace or blast_radius"),
|
|
32244
|
+
file_path: z93.string().optional().describe("File path for blast_radius"),
|
|
32245
|
+
force: z93.boolean().optional().describe("Force rebuild before answering"),
|
|
32246
|
+
limit: z93.coerce.number().int().min(1).max(100).optional().describe("Max results"),
|
|
32247
|
+
offset: z93.coerce.number().int().min(0).optional().describe("Search pagination offset"),
|
|
32248
|
+
refresh_index: z93.boolean().optional().describe("Refresh/rebuild index before searching"),
|
|
32249
|
+
languages: z93.array(z93.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
|
|
32250
|
+
paths: z93.array(z93.string()).optional().describe("Path/glob filters"),
|
|
32251
|
+
depth: z93.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
|
|
32252
|
+
max_files: z93.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index"),
|
|
32253
|
+
lexical_only: z93.boolean().optional().describe("Force lexical-only search (skip vector similarity). Default: false \u2014 uses semantic hybrid search.")
|
|
32254
|
+
}
|
|
32255
|
+
}, async ({ action, project_root, query, symbol, file_path, force, limit, offset, refresh_index, languages, paths, depth, max_files, lexical_only }) => {
|
|
31739
32256
|
const opts = { projectRoot: project_root, force, maxFiles: max_files };
|
|
31740
32257
|
if (action === "index") {
|
|
31741
32258
|
const index = buildCodeContextIndex(opts);
|
|
@@ -31745,7 +32262,24 @@ function registerCodeContext(server) {
|
|
|
31745
32262
|
indexedAt: index.indexedAt,
|
|
31746
32263
|
files: Object.keys(index.files).length,
|
|
31747
32264
|
symbols: Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0),
|
|
31748
|
-
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0)
|
|
32265
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
32266
|
+
note: "Structural index only. Use action=index_embed to also generate vector embeddings for semantic search."
|
|
32267
|
+
});
|
|
32268
|
+
}
|
|
32269
|
+
if (action === "index_embed") {
|
|
32270
|
+
const { index, vectorCount, newEmbeddings } = await buildCodeContextIndexWithEmbeddings(opts);
|
|
32271
|
+
const totalSymbols = Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0);
|
|
32272
|
+
return jsonResult({
|
|
32273
|
+
projectRoot: index.projectRoot,
|
|
32274
|
+
branch: index.branch,
|
|
32275
|
+
indexedAt: index.indexedAt,
|
|
32276
|
+
files: Object.keys(index.files).length,
|
|
32277
|
+
symbols: totalSymbols,
|
|
32278
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
32279
|
+
vectorCount,
|
|
32280
|
+
newEmbeddings,
|
|
32281
|
+
embeddingCoverage: totalSymbols > 0 ? `${(vectorCount / totalSymbols * 100).toFixed(1)}%` : "0%",
|
|
32282
|
+
note: "Structural index + vector embeddings. Semantic search is now available."
|
|
31749
32283
|
});
|
|
31750
32284
|
}
|
|
31751
32285
|
if (action === "stats") {
|
|
@@ -31753,14 +32287,28 @@ function registerCodeContext(server) {
|
|
|
31753
32287
|
}
|
|
31754
32288
|
if (action === "search") {
|
|
31755
32289
|
if (!query) return errorResult10('code_context action "search" requires query');
|
|
32290
|
+
const searchOpts = { ...opts, limit, offset, refreshIndex: refresh_index, languages, paths };
|
|
32291
|
+
if (lexical_only) {
|
|
32292
|
+
return jsonResult({
|
|
32293
|
+
query,
|
|
32294
|
+
mode: "lexical",
|
|
32295
|
+
limit: limit ?? 20,
|
|
32296
|
+
offset: offset ?? 0,
|
|
32297
|
+
languages: languages ?? [],
|
|
32298
|
+
paths: paths ?? [],
|
|
32299
|
+
results: searchCodeContext(query, searchOpts)
|
|
32300
|
+
});
|
|
32301
|
+
}
|
|
32302
|
+
const results = await searchCodeContextSemantic(query, searchOpts);
|
|
32303
|
+
const hasSemantic = results.some((r) => r.matches.some((m) => m.startsWith("semantic=")));
|
|
31756
32304
|
return jsonResult({
|
|
31757
32305
|
query,
|
|
32306
|
+
mode: hasSemantic ? "semantic+lexical" : "lexical-fallback",
|
|
31758
32307
|
limit: limit ?? 20,
|
|
31759
32308
|
offset: offset ?? 0,
|
|
31760
|
-
refresh_index: refresh_index ?? false,
|
|
31761
32309
|
languages: languages ?? [],
|
|
31762
32310
|
paths: paths ?? [],
|
|
31763
|
-
results
|
|
32311
|
+
results
|
|
31764
32312
|
});
|
|
31765
32313
|
}
|
|
31766
32314
|
if (action === "trace") {
|
|
@@ -31784,7 +32332,7 @@ var init_code_context = __esm({
|
|
|
31784
32332
|
});
|
|
31785
32333
|
|
|
31786
32334
|
// src/mcp/tools/support-inbox.ts
|
|
31787
|
-
import { z as
|
|
32335
|
+
import { z as z94 } from "zod";
|
|
31788
32336
|
function adminToken() {
|
|
31789
32337
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
31790
32338
|
}
|
|
@@ -31823,9 +32371,9 @@ function registerListBugReports(server) {
|
|
|
31823
32371
|
title: "List Bug Reports",
|
|
31824
32372
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
31825
32373
|
inputSchema: {
|
|
31826
|
-
status:
|
|
31827
|
-
severity:
|
|
31828
|
-
limit:
|
|
32374
|
+
status: z94.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
32375
|
+
severity: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
32376
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
31829
32377
|
}
|
|
31830
32378
|
},
|
|
31831
32379
|
async ({ status: status2, severity, limit }) => {
|
|
@@ -31844,7 +32392,7 @@ function registerGetBugReport(server) {
|
|
|
31844
32392
|
{
|
|
31845
32393
|
title: "Get Bug Report",
|
|
31846
32394
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
31847
|
-
inputSchema: { id:
|
|
32395
|
+
inputSchema: { id: z94.string().min(8) }
|
|
31848
32396
|
},
|
|
31849
32397
|
async ({ id }) => {
|
|
31850
32398
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -31859,12 +32407,12 @@ function registerTriageBugReport(server) {
|
|
|
31859
32407
|
title: "Triage Bug Report",
|
|
31860
32408
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
31861
32409
|
inputSchema: {
|
|
31862
|
-
id:
|
|
32410
|
+
id: z94.string().min(8),
|
|
31863
32411
|
status: STATUS.optional(),
|
|
31864
|
-
triage_notes:
|
|
31865
|
-
linked_task_id:
|
|
31866
|
-
linked_commit:
|
|
31867
|
-
fixed_version:
|
|
32412
|
+
triage_notes: z94.string().optional(),
|
|
32413
|
+
linked_task_id: z94.string().optional(),
|
|
32414
|
+
linked_commit: z94.string().optional(),
|
|
32415
|
+
fixed_version: z94.string().optional()
|
|
31868
32416
|
}
|
|
31869
32417
|
},
|
|
31870
32418
|
async ({ id, status: status2, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -31876,12 +32424,75 @@ function registerTriageBugReport(server) {
|
|
|
31876
32424
|
}
|
|
31877
32425
|
);
|
|
31878
32426
|
}
|
|
31879
|
-
|
|
32427
|
+
function featureEndpoint() {
|
|
32428
|
+
return endpoint().replace(/\/bug-reports\/?$/, "/feature-requests");
|
|
32429
|
+
}
|
|
32430
|
+
function registerListFeatureRequests(server) {
|
|
32431
|
+
server.registerTool(
|
|
32432
|
+
"list_feature_requests",
|
|
32433
|
+
{
|
|
32434
|
+
title: "List Feature Requests",
|
|
32435
|
+
description: "AskExe-internal only: list incoming customer feature requests from the support inbox.",
|
|
32436
|
+
inputSchema: {
|
|
32437
|
+
status: z94.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("open"),
|
|
32438
|
+
priority: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
32439
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
32440
|
+
}
|
|
32441
|
+
},
|
|
32442
|
+
async ({ status: status2, priority, limit }) => {
|
|
32443
|
+
const url = new URL(featureEndpoint());
|
|
32444
|
+
url.searchParams.set("status", status2);
|
|
32445
|
+
url.searchParams.set("limit", String(limit));
|
|
32446
|
+
if (priority) url.searchParams.set("priority", priority);
|
|
32447
|
+
const data = await requestJson(url.toString());
|
|
32448
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32449
|
+
}
|
|
32450
|
+
);
|
|
32451
|
+
}
|
|
32452
|
+
function registerGetFeatureRequest(server) {
|
|
32453
|
+
server.registerTool(
|
|
32454
|
+
"get_feature_request",
|
|
32455
|
+
{
|
|
32456
|
+
title: "Get Feature Request",
|
|
32457
|
+
description: "AskExe-internal only: fetch one customer feature request with full payload.",
|
|
32458
|
+
inputSchema: { id: z94.string().min(8) }
|
|
32459
|
+
},
|
|
32460
|
+
async ({ id }) => {
|
|
32461
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`);
|
|
32462
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32463
|
+
}
|
|
32464
|
+
);
|
|
32465
|
+
}
|
|
32466
|
+
function registerTriageFeatureRequest(server) {
|
|
32467
|
+
server.registerTool(
|
|
32468
|
+
"triage_feature_request",
|
|
32469
|
+
{
|
|
32470
|
+
title: "Triage Feature Request",
|
|
32471
|
+
description: "AskExe-internal only: update feature request status, response notes, and version metadata.",
|
|
32472
|
+
inputSchema: {
|
|
32473
|
+
id: z94.string().min(8),
|
|
32474
|
+
status: FEATURE_STATUS.optional(),
|
|
32475
|
+
response_notes: z94.string().optional(),
|
|
32476
|
+
target_version: z94.string().optional(),
|
|
32477
|
+
shipped_version: z94.string().optional()
|
|
32478
|
+
}
|
|
32479
|
+
},
|
|
32480
|
+
async ({ id, status: status2, response_notes, target_version, shipped_version }) => {
|
|
32481
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`, {
|
|
32482
|
+
method: "PATCH",
|
|
32483
|
+
body: JSON.stringify({ status: status2, response_notes, target_version, shipped_version })
|
|
32484
|
+
});
|
|
32485
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32486
|
+
}
|
|
32487
|
+
);
|
|
32488
|
+
}
|
|
32489
|
+
var DEFAULT_ENDPOINT, STATUS, FEATURE_STATUS;
|
|
31880
32490
|
var init_support_inbox = __esm({
|
|
31881
32491
|
"src/mcp/tools/support-inbox.ts"() {
|
|
31882
32492
|
"use strict";
|
|
31883
32493
|
DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
31884
|
-
STATUS =
|
|
32494
|
+
STATUS = z94.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
32495
|
+
FEATURE_STATUS = z94.enum(["open", "planned", "in_progress", "shipped", "closed", "wontdo"]);
|
|
31885
32496
|
}
|
|
31886
32497
|
});
|
|
31887
32498
|
|
|
@@ -32217,6 +32828,7 @@ function registerAllTools(server) {
|
|
|
32217
32828
|
gate("registerStoreDecision", registerStoreDecision);
|
|
32218
32829
|
gate("registerGetDecision", registerGetDecision);
|
|
32219
32830
|
gate("registerCreateBugReport", registerCreateBugReport);
|
|
32831
|
+
gate("registerCreateFeatureRequest", registerCreateFeatureRequest);
|
|
32220
32832
|
gate("registerSupportTools", registerSupportTools);
|
|
32221
32833
|
gate("registerCliParityTools", registerCliParityTools);
|
|
32222
32834
|
gate("registerGetSessionEvents", registerGetSessionEvents);
|
|
@@ -32226,6 +32838,9 @@ function registerAllTools(server) {
|
|
|
32226
32838
|
gate("registerListBugReports", registerListBugReports);
|
|
32227
32839
|
gate("registerGetBugReport", registerGetBugReport);
|
|
32228
32840
|
gate("registerTriageBugReport", registerTriageBugReport);
|
|
32841
|
+
gate("registerListFeatureRequests", registerListFeatureRequests);
|
|
32842
|
+
gate("registerGetFeatureRequest", registerGetFeatureRequest);
|
|
32843
|
+
gate("registerTriageFeatureRequest", registerTriageFeatureRequest);
|
|
32229
32844
|
}
|
|
32230
32845
|
if (exposeLegacyConfig) {
|
|
32231
32846
|
gate("registerGetAgentSpend", registerGetAgentSpend);
|
|
@@ -32368,6 +32983,7 @@ var init_register_tools = __esm({
|
|
|
32368
32983
|
init_query_company_brain();
|
|
32369
32984
|
init_company_actions();
|
|
32370
32985
|
init_create_bug_report();
|
|
32986
|
+
init_create_feature_request();
|
|
32371
32987
|
init_support();
|
|
32372
32988
|
init_cli_parity();
|
|
32373
32989
|
init_get_session_events();
|
|
@@ -32383,7 +32999,7 @@ __export(review_polling_exports, {
|
|
|
32383
32999
|
createRealDeps: () => createRealDeps,
|
|
32384
33000
|
pollPendingReviews: () => pollPendingReviews
|
|
32385
33001
|
});
|
|
32386
|
-
import { execSync as
|
|
33002
|
+
import { execSync as execSync17 } from "child_process";
|
|
32387
33003
|
async function pollPendingReviews(deps, _state) {
|
|
32388
33004
|
let sessions;
|
|
32389
33005
|
try {
|
|
@@ -32490,7 +33106,7 @@ async function pollPendingReviews(deps, _state) {
|
|
|
32490
33106
|
function createRealDeps(getClient2) {
|
|
32491
33107
|
return {
|
|
32492
33108
|
listTmuxSessions: () => {
|
|
32493
|
-
return
|
|
33109
|
+
return execSync17("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
32494
33110
|
encoding: "utf8",
|
|
32495
33111
|
timeout: 3e3
|
|
32496
33112
|
}).trim().split("\n").filter(Boolean);
|
|
@@ -32598,7 +33214,7 @@ __export(task_enforcement_exports, {
|
|
|
32598
33214
|
sendNudge: () => sendNudge
|
|
32599
33215
|
});
|
|
32600
33216
|
import { writeFileSync as writeFileSync26 } from "fs";
|
|
32601
|
-
import
|
|
33217
|
+
import path59 from "path";
|
|
32602
33218
|
function writeAuditEntry(entry) {
|
|
32603
33219
|
try {
|
|
32604
33220
|
const line = JSON.stringify(entry) + "\n";
|
|
@@ -32773,7 +33389,7 @@ var init_task_enforcement = __esm({
|
|
|
32773
33389
|
"What do you need?"
|
|
32774
33390
|
];
|
|
32775
33391
|
MANAGER_ROLES = ["COO", "CTO"];
|
|
32776
|
-
AUDIT_LOG_PATH =
|
|
33392
|
+
AUDIT_LOG_PATH = path59.join(
|
|
32777
33393
|
process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
|
|
32778
33394
|
".exe-os",
|
|
32779
33395
|
"enforcement-audit.jsonl"
|
|
@@ -32798,7 +33414,7 @@ __export(background_jobs_exports, {
|
|
|
32798
33414
|
import { existsSync as existsSync45, mkdirSync as mkdirSync23, readFileSync as readFileSync39, writeFileSync as writeFileSync27, unlinkSync as unlinkSync14 } from "fs";
|
|
32799
33415
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
32800
33416
|
import os22 from "os";
|
|
32801
|
-
import
|
|
33417
|
+
import path60 from "path";
|
|
32802
33418
|
function ensureDirs() {
|
|
32803
33419
|
mkdirSync23(LOCK_DIR, { recursive: true });
|
|
32804
33420
|
}
|
|
@@ -32844,7 +33460,7 @@ function listBackgroundJobs() {
|
|
|
32844
33460
|
return jobs;
|
|
32845
33461
|
}
|
|
32846
33462
|
function lockPath(type) {
|
|
32847
|
-
return
|
|
33463
|
+
return path60.join(LOCK_DIR, `${type.replace(/[^a-zA-Z0-9_.-]/g, "_")}.lock`);
|
|
32848
33464
|
}
|
|
32849
33465
|
function acquireJobLock(type, ttlMs = DEFAULT_LOCK_TTL_MS) {
|
|
32850
33466
|
ensureDirs();
|
|
@@ -33071,9 +33687,9 @@ var init_background_jobs = __esm({
|
|
|
33071
33687
|
"src/lib/background-jobs.ts"() {
|
|
33072
33688
|
"use strict";
|
|
33073
33689
|
init_config();
|
|
33074
|
-
JOB_DIR =
|
|
33075
|
-
JOBS_FILE =
|
|
33076
|
-
LOCK_DIR =
|
|
33690
|
+
JOB_DIR = path60.join(EXE_AI_DIR, "jobs");
|
|
33691
|
+
JOBS_FILE = path60.join(JOB_DIR, "jobs.json");
|
|
33692
|
+
LOCK_DIR = path60.join(JOB_DIR, "locks");
|
|
33077
33693
|
DEFAULT_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
33078
33694
|
MAX_HISTORY = 200;
|
|
33079
33695
|
}
|
|
@@ -33086,16 +33702,16 @@ __export(ws_auth_exports, {
|
|
|
33086
33702
|
deriveWsAuthToken: () => deriveWsAuthToken,
|
|
33087
33703
|
hashAuthToken: () => hashAuthToken
|
|
33088
33704
|
});
|
|
33089
|
-
import
|
|
33705
|
+
import crypto22 from "crypto";
|
|
33090
33706
|
function deriveWsAuthToken(masterKey) {
|
|
33091
|
-
return Buffer.from(
|
|
33707
|
+
return Buffer.from(crypto22.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
|
|
33092
33708
|
}
|
|
33093
33709
|
function deriveOrgId(masterKey) {
|
|
33094
|
-
const raw = Buffer.from(
|
|
33095
|
-
return
|
|
33710
|
+
const raw = Buffer.from(crypto22.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
|
|
33711
|
+
return crypto22.createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
33096
33712
|
}
|
|
33097
33713
|
function hashAuthToken(token) {
|
|
33098
|
-
return
|
|
33714
|
+
return crypto22.createHash("sha256").update(token).digest("hex");
|
|
33099
33715
|
}
|
|
33100
33716
|
var WS_AUTH_HKDF_INFO, ORG_ID_HKDF_INFO;
|
|
33101
33717
|
var init_ws_auth = __esm({
|
|
@@ -33113,10 +33729,10 @@ __export(device_registry_exports, {
|
|
|
33113
33729
|
resolveTargetDevice: () => resolveTargetDevice,
|
|
33114
33730
|
setFriendlyName: () => setFriendlyName
|
|
33115
33731
|
});
|
|
33116
|
-
import
|
|
33732
|
+
import crypto23 from "crypto";
|
|
33117
33733
|
import os23 from "os";
|
|
33118
33734
|
import { readFileSync as readFileSync40, writeFileSync as writeFileSync28, mkdirSync as mkdirSync24, existsSync as existsSync46 } from "fs";
|
|
33119
|
-
import
|
|
33735
|
+
import path61 from "path";
|
|
33120
33736
|
function getDeviceInfo() {
|
|
33121
33737
|
if (existsSync46(DEVICE_JSON_PATH)) {
|
|
33122
33738
|
try {
|
|
@@ -33130,11 +33746,11 @@ function getDeviceInfo() {
|
|
|
33130
33746
|
}
|
|
33131
33747
|
const hostname = os23.hostname();
|
|
33132
33748
|
const info = {
|
|
33133
|
-
deviceId:
|
|
33749
|
+
deviceId: crypto23.randomUUID(),
|
|
33134
33750
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
33135
33751
|
hostname
|
|
33136
33752
|
};
|
|
33137
|
-
mkdirSync24(
|
|
33753
|
+
mkdirSync24(path61.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
33138
33754
|
writeFileSync28(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
33139
33755
|
return info;
|
|
33140
33756
|
}
|
|
@@ -33175,7 +33791,7 @@ var init_device_registry = __esm({
|
|
|
33175
33791
|
"src/lib/device-registry.ts"() {
|
|
33176
33792
|
"use strict";
|
|
33177
33793
|
init_config();
|
|
33178
|
-
DEVICE_JSON_PATH =
|
|
33794
|
+
DEVICE_JSON_PATH = path61.join(EXE_AI_DIR, "device.json");
|
|
33179
33795
|
}
|
|
33180
33796
|
});
|
|
33181
33797
|
|
|
@@ -33392,7 +34008,7 @@ import net2 from "net";
|
|
|
33392
34008
|
import { createServer as createHttpServer } from "http";
|
|
33393
34009
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
33394
34010
|
import { writeFileSync as writeFileSync29, unlinkSync as unlinkSync15, mkdirSync as mkdirSync25, existsSync as existsSync47, readFileSync as readFileSync41, chmodSync as chmodSync2 } from "fs";
|
|
33395
|
-
import
|
|
34011
|
+
import path62 from "path";
|
|
33396
34012
|
|
|
33397
34013
|
// src/lib/orchestration-metrics.ts
|
|
33398
34014
|
init_config();
|
|
@@ -33465,8 +34081,8 @@ function initMetrics() {
|
|
|
33465
34081
|
// src/lib/exe-daemon.ts
|
|
33466
34082
|
init_memory_write_governor();
|
|
33467
34083
|
init_mcp_transport_health();
|
|
33468
|
-
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
33469
|
-
var PID_PATH4 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
34084
|
+
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path62.join(EXE_AI_DIR, "exed.sock");
|
|
34085
|
+
var PID_PATH4 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path62.join(EXE_AI_DIR, "exed.pid");
|
|
33470
34086
|
var MODEL_FILE = "jina-embeddings-v5-small-q4_k_m.gguf";
|
|
33471
34087
|
var IDLE_TIMEOUT_MS2 = parseInt(process.env.EXE_DAEMON_IDLE_TIMEOUT_MS || "0", 10);
|
|
33472
34088
|
var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
@@ -33495,7 +34111,7 @@ function enqueue(queue, entry) {
|
|
|
33495
34111
|
queue.push(entry);
|
|
33496
34112
|
}
|
|
33497
34113
|
async function loadModel() {
|
|
33498
|
-
const modelPath =
|
|
34114
|
+
const modelPath = path62.join(MODELS_DIR, MODEL_FILE);
|
|
33499
34115
|
if (!existsSync47(modelPath)) {
|
|
33500
34116
|
process.stderr.write(`[exed] No model at ${modelPath} \u2014 running without embeddings (VPS mode).
|
|
33501
34117
|
`);
|
|
@@ -33937,14 +34553,14 @@ function startMemoryQueueDrain() {
|
|
|
33937
34553
|
`);
|
|
33938
34554
|
}
|
|
33939
34555
|
function startServer() {
|
|
33940
|
-
mkdirSync25(
|
|
34556
|
+
mkdirSync25(path62.dirname(SOCKET_PATH2), { recursive: true });
|
|
33941
34557
|
try {
|
|
33942
|
-
chmodSync2(
|
|
34558
|
+
chmodSync2(path62.dirname(SOCKET_PATH2), 448);
|
|
33943
34559
|
} catch {
|
|
33944
34560
|
}
|
|
33945
34561
|
_daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV2] ?? null);
|
|
33946
34562
|
for (const oldFile of ["embed.sock", "embed.pid"]) {
|
|
33947
|
-
const oldPath =
|
|
34563
|
+
const oldPath = path62.join(path62.dirname(SOCKET_PATH2), oldFile);
|
|
33948
34564
|
try {
|
|
33949
34565
|
if (oldFile.endsWith(".pid")) {
|
|
33950
34566
|
const pid = parseInt(readFileSync41(oldPath, "utf8").trim(), 10);
|
|
@@ -34069,6 +34685,7 @@ function startServer() {
|
|
|
34069
34685
|
void startMcpHttpServer();
|
|
34070
34686
|
}
|
|
34071
34687
|
async function startMcpHttpServer() {
|
|
34688
|
+
process.stderr.write("[exed] MCP HTTP: starting setup...\n");
|
|
34072
34689
|
try {
|
|
34073
34690
|
let parseDurationMs2 = function(value, fallback, options = {}) {
|
|
34074
34691
|
if (!value) return fallback;
|
|
@@ -34123,8 +34740,14 @@ async function startMcpHttpServer() {
|
|
|
34123
34740
|
const { isInitializeRequest } = await import("@modelcontextprotocol/sdk/types.js");
|
|
34124
34741
|
const { registerAllTools: registerAllTools2 } = await Promise.resolve().then(() => (init_register_tools(), register_tools_exports));
|
|
34125
34742
|
const { runWithAgent: runWithAgent2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
|
|
34126
|
-
const
|
|
34127
|
-
|
|
34743
|
+
const dbReady = await ensureStoreForPolling();
|
|
34744
|
+
if (!dbReady) {
|
|
34745
|
+
process.stderr.write(
|
|
34746
|
+
"[exed] MCP HTTP: DB init failed \u2014 MCP HTTP endpoint will NOT start. Run 'exe-os setup' to fix keychain/encryption.\n"
|
|
34747
|
+
);
|
|
34748
|
+
return;
|
|
34749
|
+
}
|
|
34750
|
+
process.stderr.write("[exed] MCP HTTP: DB ready\n");
|
|
34128
34751
|
const transports = /* @__PURE__ */ new Map();
|
|
34129
34752
|
const MCP_HTTP_PORT = parseInt(process.env.EXE_MCP_PORT || "48739", 10);
|
|
34130
34753
|
const MCP_SESSION_TTL_MS = parseDurationMs2(process.env.EXE_MCP_SESSION_TTL_MS, 4 * 60 * 60 * 1e3, { allowZero: true });
|
|
@@ -34309,8 +34932,10 @@ async function startMcpHttpServer() {
|
|
|
34309
34932
|
}
|
|
34310
34933
|
});
|
|
34311
34934
|
} catch (err) {
|
|
34312
|
-
|
|
34935
|
+
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
34936
|
+
process.stderr.write(`[exed] MCP HTTP setup FAILED: ${msg}
|
|
34313
34937
|
`);
|
|
34938
|
+
process.stderr.write("[exed] MCP HTTP endpoint will NOT be available this session.\n");
|
|
34314
34939
|
}
|
|
34315
34940
|
}
|
|
34316
34941
|
var _storeInitialized = false;
|
|
@@ -34578,7 +35203,7 @@ function startGraphExtraction() {
|
|
|
34578
35203
|
`);
|
|
34579
35204
|
}
|
|
34580
35205
|
var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
|
|
34581
|
-
var AGENT_STATS_PATH =
|
|
35206
|
+
var AGENT_STATS_PATH = path62.join(EXE_AI_DIR, "agent-stats.json");
|
|
34582
35207
|
async function writeAgentStats() {
|
|
34583
35208
|
fired("agent_stats");
|
|
34584
35209
|
if (!await ensureStoreForPolling()) return;
|
|
@@ -34755,11 +35380,11 @@ function startIntercomQueueDrain() {
|
|
|
34755
35380
|
const hasInProgressTask = (session) => {
|
|
34756
35381
|
try {
|
|
34757
35382
|
const { baseAgentName: ban } = (init_employees(), __toCommonJS(employees_exports));
|
|
34758
|
-
const
|
|
35383
|
+
const path63 = __require("path");
|
|
34759
35384
|
const { existsSync: existsSync48 } = __require("fs");
|
|
34760
35385
|
const os25 = __require("os");
|
|
34761
35386
|
const agent = ban(session.split("-")[0] ?? session);
|
|
34762
|
-
const markerPath =
|
|
35387
|
+
const markerPath = path63.join(os25.homedir(), ".exe-os", "session-cache", `current-task-${agent}.json`);
|
|
34763
35388
|
return existsSync48(markerPath);
|
|
34764
35389
|
} catch {
|
|
34765
35390
|
return false;
|
|
@@ -34983,6 +35608,23 @@ function checkExistingDaemon() {
|
|
|
34983
35608
|
return false;
|
|
34984
35609
|
}
|
|
34985
35610
|
process.kill(pid, 0);
|
|
35611
|
+
try {
|
|
35612
|
+
const state = __require("child_process").execSync(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
|
|
35613
|
+
if (state.startsWith("Z")) {
|
|
35614
|
+
process.stderr.write(`[exed] PID ${pid} is a zombie \u2014 cleaning up and proceeding.
|
|
35615
|
+
`);
|
|
35616
|
+
try {
|
|
35617
|
+
unlinkSync15(PID_PATH4);
|
|
35618
|
+
} catch {
|
|
35619
|
+
}
|
|
35620
|
+
try {
|
|
35621
|
+
unlinkSync15(SOCKET_PATH2);
|
|
35622
|
+
} catch {
|
|
35623
|
+
}
|
|
35624
|
+
return false;
|
|
35625
|
+
}
|
|
35626
|
+
} catch {
|
|
35627
|
+
}
|
|
34986
35628
|
process.stderr.write(`[exed] Another daemon is already running (PID ${pid}). Exiting.
|
|
34987
35629
|
`);
|
|
34988
35630
|
return true;
|
|
@@ -35018,8 +35660,8 @@ function startAutoUpdateCheck() {
|
|
|
35018
35660
|
);
|
|
35019
35661
|
if (autoInstall) {
|
|
35020
35662
|
process.stderr.write("[exed] Auto-installing update...\n");
|
|
35021
|
-
const { execSync:
|
|
35022
|
-
|
|
35663
|
+
const { execSync: execSync18 } = await import("child_process");
|
|
35664
|
+
execSync18("npm install -g @askexenow/exe-os@latest", {
|
|
35023
35665
|
timeout: 12e4,
|
|
35024
35666
|
stdio: ["pipe", "pipe", "pipe"]
|
|
35025
35667
|
});
|