@askexenow/exe-os 0.9.79 → 0.9.80
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 +2 -2
- package/dist/bin/agentic-reflection-backfill.js +2 -2
- package/dist/bin/agentic-semantic-label.js +2 -2
- package/dist/bin/backfill-conversations.js +2 -2
- package/dist/bin/backfill-responses.js +2 -2
- package/dist/bin/backfill-vectors.js +2 -2
- package/dist/bin/bulk-sync-postgres.js +2 -2
- package/dist/bin/cleanup-stale-review-tasks.js +2 -2
- package/dist/bin/cli.js +6 -3
- package/dist/bin/customer-readiness.js +4 -0
- package/dist/bin/exe-agent.js +2 -2
- package/dist/bin/exe-assign.js +2 -2
- package/dist/bin/exe-boot.js +2 -2
- package/dist/bin/exe-call.js +2 -2
- package/dist/bin/exe-cloud.js +2 -2
- package/dist/bin/exe-dispatch.js +2 -2
- package/dist/bin/exe-doctor.js +2 -2
- package/dist/bin/exe-export-behaviors.js +2 -2
- package/dist/bin/exe-forget.js +2 -2
- package/dist/bin/exe-gateway.js +2 -2
- package/dist/bin/exe-heartbeat.js +2 -2
- package/dist/bin/exe-kill.js +2 -2
- package/dist/bin/exe-launch-agent.js +2 -2
- package/dist/bin/exe-new-employee.js +2 -2
- package/dist/bin/exe-pending-messages.js +2 -2
- package/dist/bin/exe-pending-notifications.js +2 -2
- package/dist/bin/exe-pending-reviews.js +2 -2
- package/dist/bin/exe-rename.js +2 -2
- package/dist/bin/exe-review.js +2 -2
- package/dist/bin/exe-search.js +2 -2
- package/dist/bin/exe-session-cleanup.js +2 -2
- package/dist/bin/exe-start-codex.js +2 -2
- package/dist/bin/exe-start-opencode.js +2 -2
- package/dist/bin/exe-status.js +2 -2
- package/dist/bin/exe-support.js +4 -1
- package/dist/bin/exe-team.js +2 -2
- package/dist/bin/git-sweep.js +2 -2
- package/dist/bin/graph-backfill.js +2 -2
- package/dist/bin/graph-export.js +2 -2
- package/dist/bin/intercom-check.js +2 -2
- package/dist/bin/scan-tasks.js +2 -2
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +2 -2
- package/dist/gateway/index.js +2 -2
- package/dist/hooks/bug-report-worker.js +2 -2
- package/dist/hooks/codex-stop-task-finalizer.js +2 -2
- package/dist/hooks/commit-complete.js +2 -2
- package/dist/hooks/error-recall.js +2 -2
- package/dist/hooks/ingest.js +2 -2
- package/dist/hooks/instructions-loaded.js +2 -2
- package/dist/hooks/notification.js +2 -2
- package/dist/hooks/post-compact.js +2 -2
- package/dist/hooks/post-tool-combined.js +2 -2
- package/dist/hooks/pre-compact.js +2 -2
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prompt-submit.js +2 -2
- package/dist/hooks/session-end.js +2 -2
- package/dist/hooks/session-start.js +2 -2
- package/dist/hooks/stop.js +2 -2
- package/dist/hooks/subagent-stop.js +2 -2
- package/dist/hooks/summary-worker.js +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/employee-templates.js +2 -2
- package/dist/lib/exe-daemon.js +431 -140
- package/dist/lib/hybrid-search.js +2 -2
- package/dist/lib/schedules.js +2 -2
- package/dist/lib/store.js +2 -2
- package/dist/mcp/server.js +368 -88
- package/dist/runtime/index.js +2 -2
- package/dist/tui/App.js +2 -2
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -877,8 +877,8 @@ async function embedDirect(text3) {
|
|
|
877
877
|
const llamaCpp = await import("node-llama-cpp");
|
|
878
878
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
879
879
|
const { existsSync: existsSync41 } = await import("fs");
|
|
880
|
-
const
|
|
881
|
-
const modelPath =
|
|
880
|
+
const path53 = await import("path");
|
|
881
|
+
const modelPath = path53.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
882
882
|
if (!existsSync41(modelPath)) {
|
|
883
883
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
884
884
|
}
|
|
@@ -3721,8 +3721,8 @@ function deriveMachineKey() {
|
|
|
3721
3721
|
}
|
|
3722
3722
|
function readMachineId() {
|
|
3723
3723
|
try {
|
|
3724
|
-
const { readFileSync:
|
|
3725
|
-
return
|
|
3724
|
+
const { readFileSync: readFileSync35 } = __require("fs");
|
|
3725
|
+
return readFileSync35("/etc/machine-id", "utf-8").trim();
|
|
3726
3726
|
} catch {
|
|
3727
3727
|
return "";
|
|
3728
3728
|
}
|
|
@@ -4781,7 +4781,7 @@ var init_platform_procedures = __esm({
|
|
|
4781
4781
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4782
4782
|
domain: "support",
|
|
4783
4783
|
priority: "p0",
|
|
4784
|
-
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,
|
|
4784
|
+
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."
|
|
4785
4785
|
},
|
|
4786
4786
|
// --- Operations ---
|
|
4787
4787
|
{
|
|
@@ -4863,7 +4863,7 @@ var init_platform_procedures = __esm({
|
|
|
4863
4863
|
title: "MCP tools \u2014 identity, behavior, and decisions",
|
|
4864
4864
|
domain: "tool-use",
|
|
4865
4865
|
priority: "p1",
|
|
4866
|
-
content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query. create_bug_report: customer-facing bug/support intake; use whenever an Exe OS bug or emergency hotfix is encountered so the report reaches AskExe directly. Customers only get report access; internal list/get/triage support tools are AskExe-only. If a customer-side agent cannot send upstream,
|
|
4866
|
+
content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query. create_bug_report: customer-facing bug/support intake; use whenever an Exe OS bug or emergency hotfix is encountered so the report reaches AskExe directly. support_health: check local support readiness and AskExe support server health without filing a report. support_test: file a safe end-to-end smoke report. Customers only get report/test access; internal list/get/triage support tools are AskExe-only. If a customer-side agent cannot send upstream, call support_test first; only fall back to the terminal command `exe-os support test` when MCP is disconnected."
|
|
4867
4867
|
},
|
|
4868
4868
|
{
|
|
4869
4869
|
title: "MCP tools \u2014 communication and messaging",
|
|
@@ -7303,10 +7303,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
7303
7303
|
};
|
|
7304
7304
|
try {
|
|
7305
7305
|
const fs = await import("fs");
|
|
7306
|
-
const
|
|
7306
|
+
const path53 = await import("path");
|
|
7307
7307
|
const os21 = await import("os");
|
|
7308
|
-
const logPath =
|
|
7309
|
-
fs.mkdirSync(
|
|
7308
|
+
const logPath = path53.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
|
|
7309
|
+
fs.mkdirSync(path53.dirname(logPath), { recursive: true });
|
|
7310
7310
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
7311
7311
|
} catch {
|
|
7312
7312
|
}
|
|
@@ -8599,8 +8599,8 @@ __export(wiki_client_exports, {
|
|
|
8599
8599
|
listDocuments: () => listDocuments,
|
|
8600
8600
|
listWorkspaces: () => listWorkspaces
|
|
8601
8601
|
});
|
|
8602
|
-
async function wikiFetch(config2,
|
|
8603
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8602
|
+
async function wikiFetch(config2, path53, method = "GET", body) {
|
|
8603
|
+
const url = `${config2.baseUrl}/api/v1${path53}`;
|
|
8604
8604
|
const headers = {
|
|
8605
8605
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
8606
8606
|
"Content-Type": "application/json"
|
|
@@ -8633,7 +8633,7 @@ async function wikiFetch(config2, path52, method = "GET", body) {
|
|
|
8633
8633
|
}
|
|
8634
8634
|
}
|
|
8635
8635
|
if (!response.ok) {
|
|
8636
|
-
throw new Error(`Wiki API ${method} ${
|
|
8636
|
+
throw new Error(`Wiki API ${method} ${path53}: ${response.status} ${response.statusText}`);
|
|
8637
8637
|
}
|
|
8638
8638
|
return response.json();
|
|
8639
8639
|
} finally {
|
|
@@ -13963,8 +13963,8 @@ init_database();
|
|
|
13963
13963
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13964
13964
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13965
13965
|
import { spawn as spawn4 } from "child_process";
|
|
13966
|
-
import { existsSync as existsSync40, openSync as openSync4, mkdirSync as
|
|
13967
|
-
import
|
|
13966
|
+
import { existsSync as existsSync40, openSync as openSync4, mkdirSync as mkdirSync23, closeSync as closeSync4, readFileSync as readFileSync34 } from "fs";
|
|
13967
|
+
import path52 from "path";
|
|
13968
13968
|
import os20 from "os";
|
|
13969
13969
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
13970
13970
|
|
|
@@ -15350,7 +15350,7 @@ function registerCreateTask(server2) {
|
|
|
15350
15350
|
skipDispatch: true
|
|
15351
15351
|
});
|
|
15352
15352
|
try {
|
|
15353
|
-
const { existsSync: existsSync41, mkdirSync:
|
|
15353
|
+
const { existsSync: existsSync41, mkdirSync: mkdirSync24, writeFileSync: writeFileSync25 } = await import("fs");
|
|
15354
15354
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
15355
15355
|
const idPath = identityPath2(assigned_to);
|
|
15356
15356
|
if (!existsSync41(idPath)) {
|
|
@@ -15362,8 +15362,8 @@ function registerCreateTask(server2) {
|
|
|
15362
15362
|
const template = getTemplateForTitle2(emp.role);
|
|
15363
15363
|
if (template) {
|
|
15364
15364
|
const dir = (await import("path")).dirname(idPath);
|
|
15365
|
-
if (!existsSync41(dir))
|
|
15366
|
-
|
|
15365
|
+
if (!existsSync41(dir)) mkdirSync24(dir, { recursive: true });
|
|
15366
|
+
writeFileSync25(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
15367
15367
|
}
|
|
15368
15368
|
}
|
|
15369
15369
|
}
|
|
@@ -18337,12 +18337,12 @@ function registerExportGraph(server2) {
|
|
|
18337
18337
|
}
|
|
18338
18338
|
const html = await exportGraphHTML(client);
|
|
18339
18339
|
const fs = await import("fs");
|
|
18340
|
-
const
|
|
18340
|
+
const path53 = await import("path");
|
|
18341
18341
|
const os21 = await import("os");
|
|
18342
|
-
const outDir =
|
|
18342
|
+
const outDir = path53.join(os21.homedir(), ".exe-os", "exports");
|
|
18343
18343
|
fs.mkdirSync(outDir, { recursive: true });
|
|
18344
18344
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
18345
|
-
const filePath =
|
|
18345
|
+
const filePath = path53.join(outDir, `graph-${timestamp}.html`);
|
|
18346
18346
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
18347
18347
|
return {
|
|
18348
18348
|
content: [
|
|
@@ -23321,9 +23321,9 @@ var HostingerApiClient = class {
|
|
|
23321
23321
|
}
|
|
23322
23322
|
this.lastRequestTime = Date.now();
|
|
23323
23323
|
}
|
|
23324
|
-
async request(method,
|
|
23324
|
+
async request(method, path53, body) {
|
|
23325
23325
|
await this.rateLimit();
|
|
23326
|
-
const url = `${this.baseUrl}${
|
|
23326
|
+
const url = `${this.baseUrl}${path53}`;
|
|
23327
23327
|
const headers = {
|
|
23328
23328
|
Authorization: `Bearer ${this.apiKey}`,
|
|
23329
23329
|
"Content-Type": "application/json",
|
|
@@ -23396,8 +23396,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
23396
23396
|
}
|
|
23397
23397
|
return envelope.result;
|
|
23398
23398
|
}
|
|
23399
|
-
function buildUrl(zoneId,
|
|
23400
|
-
const normalizedPath =
|
|
23399
|
+
function buildUrl(zoneId, path53 = "/dns_records", query) {
|
|
23400
|
+
const normalizedPath = path53.startsWith("/") ? path53 : `/${path53}`;
|
|
23401
23401
|
const url = new URL(
|
|
23402
23402
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
23403
23403
|
);
|
|
@@ -27042,15 +27042,293 @@ Upstream status: ${upstreamStatus}`
|
|
|
27042
27042
|
);
|
|
27043
27043
|
}
|
|
27044
27044
|
|
|
27045
|
+
// src/mcp/tools/support.ts
|
|
27046
|
+
import { z as z88 } from "zod";
|
|
27047
|
+
|
|
27048
|
+
// src/bin/exe-support.ts
|
|
27049
|
+
init_config();
|
|
27050
|
+
init_license();
|
|
27051
|
+
import { mkdirSync as mkdirSync21, readFileSync as readFileSync32, unlinkSync as unlinkSync12, writeFileSync as writeFileSync23 } from "fs";
|
|
27052
|
+
import path50 from "path";
|
|
27053
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
27054
|
+
var DEFAULT_BUG_ENDPOINT = "https://askexe.com/v1/support/bug-reports";
|
|
27055
|
+
var DEFAULT_ADMIN_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
27056
|
+
async function runHealth() {
|
|
27057
|
+
const checks = [];
|
|
27058
|
+
const endpoints = await resolveEndpoints();
|
|
27059
|
+
checks.push(checkLocalWrite());
|
|
27060
|
+
checks.push({
|
|
27061
|
+
check: "license_key_present",
|
|
27062
|
+
level: loadLicense() ? "pass" : "fail",
|
|
27063
|
+
detail: loadLicense() ? "license.key found" : "missing ~/.exe-os/license.key; run exe-os setup or exe-os cloud setup",
|
|
27064
|
+
next: loadLicense() ? void 0 : "Run `exe-os setup` or ask AskExe for the customer license key."
|
|
27065
|
+
});
|
|
27066
|
+
checks.push({
|
|
27067
|
+
check: "license_token_cached",
|
|
27068
|
+
level: readCachedLicenseToken() ? "pass" : "warn",
|
|
27069
|
+
detail: readCachedLicenseToken() ? "cached license token found" : "no cached token yet; support can still use license.key",
|
|
27070
|
+
next: readCachedLicenseToken() ? void 0 : "This is OK if license.key exists. It refreshes after cloud/license validation."
|
|
27071
|
+
});
|
|
27072
|
+
try {
|
|
27073
|
+
const res = await fetch(endpoints.healthEndpoint, { method: "GET", signal: AbortSignal.timeout(1e4) });
|
|
27074
|
+
const body = await safeJson2(res);
|
|
27075
|
+
checks.push({
|
|
27076
|
+
check: "support_health_endpoint",
|
|
27077
|
+
level: res.ok && body?.status !== "down" ? "pass" : "fail",
|
|
27078
|
+
detail: `${res.status} ${body?.status ?? res.statusText}`,
|
|
27079
|
+
next: res.ok ? void 0 : "Check internet access, DNS, or AskExe support status."
|
|
27080
|
+
});
|
|
27081
|
+
for (const remote of body?.checks ?? []) {
|
|
27082
|
+
const name = remote.name ?? "unknown";
|
|
27083
|
+
checks.push({
|
|
27084
|
+
check: `server_${name}`,
|
|
27085
|
+
level: remote.ok === true ? "pass" : name === "admin_inbox_configured" ? "warn" : "fail",
|
|
27086
|
+
detail: remote.detail ?? (remote.ok ? "ok" : "failed"),
|
|
27087
|
+
next: remote.ok ? void 0 : "AskExe must fix this server-side."
|
|
27088
|
+
});
|
|
27089
|
+
}
|
|
27090
|
+
} catch (err) {
|
|
27091
|
+
checks.push({
|
|
27092
|
+
check: "support_health_endpoint",
|
|
27093
|
+
level: "fail",
|
|
27094
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
27095
|
+
next: "Check internet access, then run `exe-os support health` again."
|
|
27096
|
+
});
|
|
27097
|
+
}
|
|
27098
|
+
return checks;
|
|
27099
|
+
}
|
|
27100
|
+
async function runTest(project) {
|
|
27101
|
+
const checks = await runHealth();
|
|
27102
|
+
const endpoints = await resolveEndpoints();
|
|
27103
|
+
const licenseKey = loadLicense();
|
|
27104
|
+
const licenseToken = readCachedLicenseToken();
|
|
27105
|
+
const id = randomUUID9();
|
|
27106
|
+
const version = readPackageVersion2();
|
|
27107
|
+
const reportPath = writeLocalTestReport(id, project, version);
|
|
27108
|
+
checks.push({ check: "local_report_file", level: "pass", detail: reportPath });
|
|
27109
|
+
if (!licenseKey && !licenseToken) {
|
|
27110
|
+
checks.push({
|
|
27111
|
+
check: "upstream_post",
|
|
27112
|
+
level: "fail",
|
|
27113
|
+
detail: "not sent because this device has no license key/token",
|
|
27114
|
+
next: "Run `exe-os setup` or ask AskExe to provision this customer device."
|
|
27115
|
+
});
|
|
27116
|
+
return checks;
|
|
27117
|
+
}
|
|
27118
|
+
const payload = {
|
|
27119
|
+
id,
|
|
27120
|
+
title: `TEST \u2014 ${project} support intake (${version})`,
|
|
27121
|
+
classification: "unclear",
|
|
27122
|
+
severity: "p3",
|
|
27123
|
+
summary: "Synthetic exe-os support intake smoke test. Safe to close.",
|
|
27124
|
+
customer_impact: "No customer impact; diagnostic only.",
|
|
27125
|
+
reproduction_steps: ["Run exe-os support test"],
|
|
27126
|
+
expected: "The report reaches AskExe support intake and can be triaged.",
|
|
27127
|
+
actual: "Smoke test submitted by exe-os support test.",
|
|
27128
|
+
package_version: `@askexenow/exe-os@${version}`,
|
|
27129
|
+
project_name: project,
|
|
27130
|
+
agent_id: "support-test",
|
|
27131
|
+
agent_role: "diagnostic",
|
|
27132
|
+
report_path: reportPath,
|
|
27133
|
+
markdown: readFileSync32(reportPath, "utf8")
|
|
27134
|
+
};
|
|
27135
|
+
try {
|
|
27136
|
+
const headers = { "content-type": "application/json" };
|
|
27137
|
+
if (licenseKey) headers["x-exe-license-key"] = licenseKey;
|
|
27138
|
+
if (licenseToken) headers["x-exe-license-token"] = licenseToken;
|
|
27139
|
+
const res = await fetch(endpoints.bugEndpoint, {
|
|
27140
|
+
method: "POST",
|
|
27141
|
+
headers,
|
|
27142
|
+
body: JSON.stringify(payload),
|
|
27143
|
+
signal: AbortSignal.timeout(15e3)
|
|
27144
|
+
});
|
|
27145
|
+
const data = await safeJson2(res);
|
|
27146
|
+
checks.push({
|
|
27147
|
+
check: "upstream_post",
|
|
27148
|
+
level: res.ok ? "pass" : "fail",
|
|
27149
|
+
detail: res.ok ? `sent id=${String(data?.id ?? id)}` : summarizeHttpFailure(res.status, data),
|
|
27150
|
+
next: res.ok ? void 0 : nextForPostFailure(res.status)
|
|
27151
|
+
});
|
|
27152
|
+
if (res.ok) {
|
|
27153
|
+
checks.push(await maybeCloseAdmin(String(data?.id ?? id), endpoints.adminEndpoint, version));
|
|
27154
|
+
}
|
|
27155
|
+
} catch (err) {
|
|
27156
|
+
checks.push({
|
|
27157
|
+
check: "upstream_post",
|
|
27158
|
+
level: "fail",
|
|
27159
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
27160
|
+
next: "Check internet access, then run `exe-os support test` again."
|
|
27161
|
+
});
|
|
27162
|
+
}
|
|
27163
|
+
return checks;
|
|
27164
|
+
}
|
|
27165
|
+
async function resolveEndpoints() {
|
|
27166
|
+
const config2 = await loadConfig();
|
|
27167
|
+
const bugEndpoint = process.env.EXE_SUPPORT_BUG_REPORT_ENDPOINT ?? config2.support?.bugReportEndpoint ?? DEFAULT_BUG_ENDPOINT;
|
|
27168
|
+
const healthEndpoint = process.env.EXE_SUPPORT_HEALTH_ENDPOINT ?? bugEndpoint.replace(/\/bug-reports\/?$/, "/health");
|
|
27169
|
+
const adminEndpoint = process.env.ASKEXE_SUPPORT_ADMIN_ENDPOINT ?? process.env.EXE_SUPPORT_ADMIN_ENDPOINT ?? DEFAULT_ADMIN_ENDPOINT;
|
|
27170
|
+
return { bugEndpoint, healthEndpoint, adminEndpoint };
|
|
27171
|
+
}
|
|
27172
|
+
function checkLocalWrite() {
|
|
27173
|
+
const dir = path50.join(EXE_AI_DIR, "bug-reports");
|
|
27174
|
+
const testPath = path50.join(dir, ".support-write-test");
|
|
27175
|
+
try {
|
|
27176
|
+
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
27177
|
+
writeFileSync23(testPath, "ok\n", { mode: 384 });
|
|
27178
|
+
unlinkSync12(testPath);
|
|
27179
|
+
return { check: "local_bug_report_dir_writable", level: "pass", detail: dir };
|
|
27180
|
+
} catch (err) {
|
|
27181
|
+
return {
|
|
27182
|
+
check: "local_bug_report_dir_writable",
|
|
27183
|
+
level: "fail",
|
|
27184
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
27185
|
+
next: "Fix permissions on ~/.exe-os or rerun setup on a writable user account."
|
|
27186
|
+
};
|
|
27187
|
+
}
|
|
27188
|
+
}
|
|
27189
|
+
function writeLocalTestReport(id, project, version) {
|
|
27190
|
+
const dir = path50.join(EXE_AI_DIR, "bug-reports");
|
|
27191
|
+
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
27192
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
27193
|
+
const filePath = path50.join(dir, `${date}-support-intake-test-${id.slice(0, 8)}.md`);
|
|
27194
|
+
writeFileSync23(filePath, `# TEST \u2014 ${project} support intake
|
|
27195
|
+
|
|
27196
|
+
Report ID: ${id}
|
|
27197
|
+
Package: @askexenow/exe-os@${version}
|
|
27198
|
+
|
|
27199
|
+
Synthetic smoke test from \`exe-os support test\`. Safe to close.
|
|
27200
|
+
`, { mode: 384 });
|
|
27201
|
+
return filePath;
|
|
27202
|
+
}
|
|
27203
|
+
async function maybeCloseAdmin(id, adminEndpoint, version) {
|
|
27204
|
+
const token = process.env.ASKEXE_SUPPORT_ADMIN_TOKEN ?? process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
27205
|
+
if (!token) {
|
|
27206
|
+
return { check: "askexe_admin_autoclose", level: "warn", detail: "skipped; admin token is AskExe-only" };
|
|
27207
|
+
}
|
|
27208
|
+
try {
|
|
27209
|
+
const res = await fetch(`${adminEndpoint}/${encodeURIComponent(id)}`, {
|
|
27210
|
+
method: "PATCH",
|
|
27211
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
27212
|
+
body: JSON.stringify({
|
|
27213
|
+
status: "closed",
|
|
27214
|
+
triage_notes: "Auto-closed synthetic support smoke test.",
|
|
27215
|
+
fixed_version: version
|
|
27216
|
+
}),
|
|
27217
|
+
signal: AbortSignal.timeout(1e4)
|
|
27218
|
+
});
|
|
27219
|
+
return {
|
|
27220
|
+
check: "askexe_admin_autoclose",
|
|
27221
|
+
level: res.ok ? "pass" : "warn",
|
|
27222
|
+
detail: res.ok ? "closed" : `${res.status} ${await res.text()}`,
|
|
27223
|
+
next: res.ok ? void 0 : "Report was sent; AskExe can close the smoke report manually."
|
|
27224
|
+
};
|
|
27225
|
+
} catch (err) {
|
|
27226
|
+
return {
|
|
27227
|
+
check: "askexe_admin_autoclose",
|
|
27228
|
+
level: "warn",
|
|
27229
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
27230
|
+
next: "Report was sent; AskExe can close the smoke report manually."
|
|
27231
|
+
};
|
|
27232
|
+
}
|
|
27233
|
+
}
|
|
27234
|
+
function readPackageVersion2() {
|
|
27235
|
+
let dir = path50.dirname(new URL(import.meta.url).pathname);
|
|
27236
|
+
for (let i = 0; i < 6; i++) {
|
|
27237
|
+
const pkg = path50.join(dir, "package.json");
|
|
27238
|
+
try {
|
|
27239
|
+
const parsed = JSON.parse(readFileSync32(pkg, "utf8"));
|
|
27240
|
+
if (parsed.version) return parsed.version;
|
|
27241
|
+
} catch {
|
|
27242
|
+
}
|
|
27243
|
+
dir = path50.dirname(dir);
|
|
27244
|
+
}
|
|
27245
|
+
return "unknown";
|
|
27246
|
+
}
|
|
27247
|
+
async function safeJson2(res) {
|
|
27248
|
+
try {
|
|
27249
|
+
return await res.json();
|
|
27250
|
+
} catch {
|
|
27251
|
+
return null;
|
|
27252
|
+
}
|
|
27253
|
+
}
|
|
27254
|
+
function hasFailures(rows) {
|
|
27255
|
+
return rows.some((row) => row.level === "fail");
|
|
27256
|
+
}
|
|
27257
|
+
function summarizeHttpFailure(status, data) {
|
|
27258
|
+
const error = data?.error;
|
|
27259
|
+
return `${status} ${error?.message ?? JSON.stringify(data)}`;
|
|
27260
|
+
}
|
|
27261
|
+
function nextForPostFailure(status) {
|
|
27262
|
+
if (status === 401) return "License credentials were not sent. Run `exe-os support health` and check license_key_present.";
|
|
27263
|
+
if (status === 403) return "License is valid locally but not accepted by support intake. AskExe must check server-side license provisioning.";
|
|
27264
|
+
if (status >= 500) return "AskExe support intake is unhealthy server-side. Try again shortly and report the local file path.";
|
|
27265
|
+
return "Run `exe-os support health`; if it passes, send this output to AskExe.";
|
|
27266
|
+
}
|
|
27267
|
+
|
|
27268
|
+
// src/mcp/tools/support.ts
|
|
27269
|
+
function formatRows(rows, mode) {
|
|
27270
|
+
const lines = [`exe-os support ${mode}`, ""];
|
|
27271
|
+
for (const row of rows) {
|
|
27272
|
+
const icon = row.level === "pass" ? "\u2705" : row.level === "warn" ? "\u26A0\uFE0F" : "\u274C";
|
|
27273
|
+
lines.push(`${icon} ${row.check}: ${row.detail}`);
|
|
27274
|
+
if (row.next) lines.push(` \u2192 ${row.next}`);
|
|
27275
|
+
}
|
|
27276
|
+
lines.push("");
|
|
27277
|
+
if (hasFailures(rows)) {
|
|
27278
|
+
lines.push("Result: not ready. Fix the failed item(s), then rerun this tool.");
|
|
27279
|
+
} else if (rows.some((row) => row.level === "warn")) {
|
|
27280
|
+
lines.push("Result: ready with warnings. Bug reports can be sent; warnings are informational unless AskExe asked for stricter validation.");
|
|
27281
|
+
} else {
|
|
27282
|
+
lines.push(mode === "test" ? "Result: ready. AskExe received the test report." : "Result: ready. Use support_test for an end-to-end send test.");
|
|
27283
|
+
}
|
|
27284
|
+
return lines.join("\n");
|
|
27285
|
+
}
|
|
27286
|
+
function registerSupportTools(server2) {
|
|
27287
|
+
server2.registerTool(
|
|
27288
|
+
"support_health",
|
|
27289
|
+
{
|
|
27290
|
+
title: "Support Health",
|
|
27291
|
+
description: "Customer-safe support intake health check. Verifies local bug-report directory, license presence, and AskExe support server health without filing a report.",
|
|
27292
|
+
inputSchema: {}
|
|
27293
|
+
},
|
|
27294
|
+
async () => {
|
|
27295
|
+
const checks = await runHealth();
|
|
27296
|
+
return {
|
|
27297
|
+
content: [{ type: "text", text: formatRows(checks, "health") }],
|
|
27298
|
+
structuredContent: { ok: !hasFailures(checks), checks },
|
|
27299
|
+
isError: hasFailures(checks)
|
|
27300
|
+
};
|
|
27301
|
+
}
|
|
27302
|
+
);
|
|
27303
|
+
server2.registerTool(
|
|
27304
|
+
"support_test",
|
|
27305
|
+
{
|
|
27306
|
+
title: "Support Test",
|
|
27307
|
+
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.",
|
|
27308
|
+
inputSchema: {
|
|
27309
|
+
project: z88.string().default("support-smoke").describe("Customer/project name, e.g. hygo")
|
|
27310
|
+
}
|
|
27311
|
+
},
|
|
27312
|
+
async ({ project }) => {
|
|
27313
|
+
const checks = await runTest(project);
|
|
27314
|
+
return {
|
|
27315
|
+
content: [{ type: "text", text: formatRows(checks, "test") }],
|
|
27316
|
+
structuredContent: { ok: !hasFailures(checks), checks },
|
|
27317
|
+
isError: hasFailures(checks)
|
|
27318
|
+
};
|
|
27319
|
+
}
|
|
27320
|
+
);
|
|
27321
|
+
}
|
|
27322
|
+
|
|
27045
27323
|
// src/mcp/tools/get-session-events.ts
|
|
27046
27324
|
init_active_agent();
|
|
27047
27325
|
init_fast_db_init();
|
|
27048
|
-
import { z as
|
|
27326
|
+
import { z as z89 } from "zod";
|
|
27049
27327
|
|
|
27050
27328
|
// src/lib/session-events.ts
|
|
27051
27329
|
init_task_scope();
|
|
27052
27330
|
init_project_name();
|
|
27053
|
-
import { randomUUID as
|
|
27331
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
27054
27332
|
async function ensureSessionEventsTable(client) {
|
|
27055
27333
|
await client.execute(`
|
|
27056
27334
|
CREATE TABLE IF NOT EXISTS session_events (
|
|
@@ -27132,7 +27410,7 @@ async function listRecentSessionEvents(client, options) {
|
|
|
27132
27410
|
}
|
|
27133
27411
|
|
|
27134
27412
|
// src/mcp/tools/get-session-events.ts
|
|
27135
|
-
var EVENT_TYPE =
|
|
27413
|
+
var EVENT_TYPE = z89.enum([
|
|
27136
27414
|
"user_prompt",
|
|
27137
27415
|
"assistant_response",
|
|
27138
27416
|
"tool_call",
|
|
@@ -27162,11 +27440,11 @@ function registerGetSessionEvents(server2) {
|
|
|
27162
27440
|
title: "Get Session Events",
|
|
27163
27441
|
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.",
|
|
27164
27442
|
inputSchema: {
|
|
27165
|
-
agent_id:
|
|
27166
|
-
session_id:
|
|
27443
|
+
agent_id: z89.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
27444
|
+
session_id: z89.string().optional().describe("Optional exact runtime session id."),
|
|
27167
27445
|
event_type: EVENT_TYPE.optional().describe("Filter to one event type."),
|
|
27168
|
-
project_name:
|
|
27169
|
-
limit:
|
|
27446
|
+
project_name: z89.string().optional().describe("Optional project filter. Pass 'all' for all projects."),
|
|
27447
|
+
limit: z89.number().int().min(1).max(100).default(20).describe("Number of events to return.")
|
|
27170
27448
|
}
|
|
27171
27449
|
},
|
|
27172
27450
|
async ({ agent_id, session_id, event_type, project_name, limit }) => {
|
|
@@ -27202,8 +27480,8 @@ function registerGetLastAssistantResponse(server2) {
|
|
|
27202
27480
|
title: "Get Last Assistant Response",
|
|
27203
27481
|
description: "Return the exact last assistant response for an agent from the session event journal. Use for 'what was the last thing you said?'",
|
|
27204
27482
|
inputSchema: {
|
|
27205
|
-
agent_id:
|
|
27206
|
-
project_name:
|
|
27483
|
+
agent_id: z89.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
27484
|
+
project_name: z89.string().optional().describe("Optional project filter. Pass 'all' for all projects.")
|
|
27207
27485
|
}
|
|
27208
27486
|
},
|
|
27209
27487
|
async ({ agent_id, project_name }) => {
|
|
@@ -27233,32 +27511,32 @@ function registerGetLastAssistantResponse(server2) {
|
|
|
27233
27511
|
}
|
|
27234
27512
|
|
|
27235
27513
|
// src/mcp/tools/code-context.ts
|
|
27236
|
-
import { z as
|
|
27514
|
+
import { z as z90 } from "zod";
|
|
27237
27515
|
|
|
27238
27516
|
// src/lib/code-context-index.ts
|
|
27239
27517
|
init_config();
|
|
27240
27518
|
import crypto19 from "crypto";
|
|
27241
|
-
import
|
|
27242
|
-
import { existsSync as existsSync39, mkdirSync as
|
|
27519
|
+
import path51 from "path";
|
|
27520
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync22, readFileSync as readFileSync33, readdirSync as readdirSync14, statSync as statSync9, writeFileSync as writeFileSync24 } from "fs";
|
|
27243
27521
|
import { spawnSync } from "child_process";
|
|
27244
27522
|
var INDEX_VERSION = 2;
|
|
27245
27523
|
var DEFAULT_MAX_FILES = 5e3;
|
|
27246
27524
|
var IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
27247
27525
|
function normalizeProjectRoot(projectRoot) {
|
|
27248
|
-
return
|
|
27526
|
+
return path51.resolve(projectRoot || process.cwd());
|
|
27249
27527
|
}
|
|
27250
27528
|
function hashText(text3) {
|
|
27251
27529
|
return crypto19.createHash("sha256").update(text3).digest("hex");
|
|
27252
27530
|
}
|
|
27253
27531
|
function indexDir() {
|
|
27254
|
-
const dir =
|
|
27255
|
-
|
|
27532
|
+
const dir = path51.join(EXE_AI_DIR, "code-context");
|
|
27533
|
+
mkdirSync22(dir, { recursive: true });
|
|
27256
27534
|
return dir;
|
|
27257
27535
|
}
|
|
27258
27536
|
function getCodeContextIndexPath(projectRoot) {
|
|
27259
27537
|
const root = normalizeProjectRoot(projectRoot);
|
|
27260
27538
|
const rootHash = hashText(root).slice(0, 16);
|
|
27261
|
-
return
|
|
27539
|
+
return path51.join(indexDir(), `${rootHash}.json`);
|
|
27262
27540
|
}
|
|
27263
27541
|
function currentBranch(projectRoot) {
|
|
27264
27542
|
const result2 = spawnSync("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
@@ -27271,8 +27549,8 @@ function shouldIgnore(relPath) {
|
|
|
27271
27549
|
}
|
|
27272
27550
|
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
27273
27551
|
for (const entry of readdirSync14(dir, { withFileTypes: true })) {
|
|
27274
|
-
const abs =
|
|
27275
|
-
const rel =
|
|
27552
|
+
const abs = path51.join(dir, entry.name);
|
|
27553
|
+
const rel = path51.relative(projectRoot, abs).replaceAll(path51.sep, "/");
|
|
27276
27554
|
if (shouldIgnore(rel)) continue;
|
|
27277
27555
|
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
27278
27556
|
else if (entry.isFile()) out.push(rel);
|
|
@@ -27288,7 +27566,7 @@ function listCodeFiles(projectRoot, maxFiles) {
|
|
|
27288
27566
|
const rg = spawnSync("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
27289
27567
|
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
27290
27568
|
}
|
|
27291
|
-
return files.map((file) => file.replaceAll(
|
|
27569
|
+
return files.map((file) => file.replaceAll(path51.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
27292
27570
|
}
|
|
27293
27571
|
function parseImportPaths(importText) {
|
|
27294
27572
|
const paths = [];
|
|
@@ -27301,13 +27579,13 @@ function parseImportPaths(importText) {
|
|
|
27301
27579
|
}
|
|
27302
27580
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
27303
27581
|
if (!importPath.startsWith(".")) return null;
|
|
27304
|
-
const base =
|
|
27582
|
+
const base = path51.posix.normalize(path51.posix.join(path51.posix.dirname(fromFile.replaceAll(path51.sep, "/")), importPath));
|
|
27305
27583
|
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
27306
27584
|
const candidates = [base];
|
|
27307
27585
|
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"]) {
|
|
27308
27586
|
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
27309
27587
|
}
|
|
27310
|
-
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(
|
|
27588
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path51.posix.join(base, indexName));
|
|
27311
27589
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
27312
27590
|
}
|
|
27313
27591
|
function symbolId(filePath, chunk) {
|
|
@@ -27317,7 +27595,7 @@ function loadIndex(projectRoot) {
|
|
|
27317
27595
|
const file = getCodeContextIndexPath(projectRoot);
|
|
27318
27596
|
if (!existsSync39(file)) return null;
|
|
27319
27597
|
try {
|
|
27320
|
-
const parsed = JSON.parse(
|
|
27598
|
+
const parsed = JSON.parse(readFileSync33(file, "utf8"));
|
|
27321
27599
|
if (parsed.version !== INDEX_VERSION || parsed.projectRoot !== projectRoot) return null;
|
|
27322
27600
|
return parsed;
|
|
27323
27601
|
} catch {
|
|
@@ -27325,10 +27603,10 @@ function loadIndex(projectRoot) {
|
|
|
27325
27603
|
}
|
|
27326
27604
|
}
|
|
27327
27605
|
function saveIndex(index) {
|
|
27328
|
-
|
|
27606
|
+
writeFileSync24(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
|
|
27329
27607
|
}
|
|
27330
27608
|
function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
27331
|
-
const absPath =
|
|
27609
|
+
const absPath = path51.join(projectRoot, relPath);
|
|
27332
27610
|
let stat;
|
|
27333
27611
|
try {
|
|
27334
27612
|
stat = statSync9(absPath);
|
|
@@ -27338,7 +27616,7 @@ function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
|
27338
27616
|
if (!stat.isFile()) return { record: null, reused: false };
|
|
27339
27617
|
const language = languageForFile(relPath);
|
|
27340
27618
|
if (!language || !isChunkable(relPath)) return { record: null, reused: false };
|
|
27341
|
-
const source =
|
|
27619
|
+
const source = readFileSync33(absPath, "utf8");
|
|
27342
27620
|
const hash = hashText(source);
|
|
27343
27621
|
if (previous && previous.hash === hash && previous.mtimeMs === stat.mtimeMs && previous.size === stat.size && previous.language === language) {
|
|
27344
27622
|
return { record: previous, reused: true };
|
|
@@ -27366,13 +27644,13 @@ function buildCodeContextIndex(options = {}) {
|
|
|
27366
27644
|
const branch = currentBranch(projectRoot);
|
|
27367
27645
|
const previous = options.force ? null : loadIndex(projectRoot);
|
|
27368
27646
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
27369
|
-
const allFiles = new Set(files.map((file) => file.replaceAll(
|
|
27647
|
+
const allFiles = new Set(files.map((file) => file.replaceAll(path51.sep, "/")));
|
|
27370
27648
|
const fileRecords = {};
|
|
27371
27649
|
let rebuiltFiles = 0;
|
|
27372
27650
|
let reusedFiles = 0;
|
|
27373
27651
|
let skippedFiles = 0;
|
|
27374
27652
|
for (const rel of files) {
|
|
27375
|
-
const normalized = rel.replaceAll(
|
|
27653
|
+
const normalized = rel.replaceAll(path51.sep, "/");
|
|
27376
27654
|
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
27377
27655
|
if (record) {
|
|
27378
27656
|
fileRecords[normalized] = record;
|
|
@@ -27401,11 +27679,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
27401
27679
|
if (loaded) {
|
|
27402
27680
|
const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
|
|
27403
27681
|
const unchanged = currentFiles.every((rel) => {
|
|
27404
|
-
const normalized = rel.replaceAll(
|
|
27682
|
+
const normalized = rel.replaceAll(path51.sep, "/");
|
|
27405
27683
|
const existing = loaded.files[normalized];
|
|
27406
27684
|
if (!existing) return false;
|
|
27407
27685
|
try {
|
|
27408
|
-
const stat = statSync9(
|
|
27686
|
+
const stat = statSync9(path51.join(projectRoot, normalized));
|
|
27409
27687
|
return stat.mtimeMs === existing.mtimeMs && stat.size === existing.size;
|
|
27410
27688
|
} catch {
|
|
27411
27689
|
return false;
|
|
@@ -27458,9 +27736,9 @@ function globToRegex(pattern) {
|
|
|
27458
27736
|
}
|
|
27459
27737
|
function matchesPath(filePath, patterns) {
|
|
27460
27738
|
if (!patterns || patterns.length === 0) return true;
|
|
27461
|
-
const normalized = filePath.replaceAll(
|
|
27739
|
+
const normalized = filePath.replaceAll(path51.sep, "/");
|
|
27462
27740
|
return patterns.some((pattern) => {
|
|
27463
|
-
const p = pattern.replaceAll(
|
|
27741
|
+
const p = pattern.replaceAll(path51.sep, "/").replace(/^\.\//, "");
|
|
27464
27742
|
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
27465
27743
|
});
|
|
27466
27744
|
}
|
|
@@ -27578,7 +27856,7 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
27578
27856
|
}
|
|
27579
27857
|
function resolveTargetFile(index, input) {
|
|
27580
27858
|
if (input.filePath) {
|
|
27581
|
-
const normalized = input.filePath.replaceAll(
|
|
27859
|
+
const normalized = input.filePath.replaceAll(path51.sep, "/").replace(/^\.\//, "");
|
|
27582
27860
|
if (index.files[normalized]) return { filePath: normalized, target: normalized };
|
|
27583
27861
|
const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
|
|
27584
27862
|
if (suffix) return { filePath: suffix, target: input.filePath };
|
|
@@ -27608,7 +27886,7 @@ function analyzeBlastRadius(input) {
|
|
|
27608
27886
|
}
|
|
27609
27887
|
}
|
|
27610
27888
|
}
|
|
27611
|
-
const targetBase =
|
|
27889
|
+
const targetBase = path51.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
|
|
27612
27890
|
const symbolLower = input.symbol?.toLowerCase();
|
|
27613
27891
|
const tests = Object.keys(index.files).filter((file) => {
|
|
27614
27892
|
const lower = file.toLowerCase();
|
|
@@ -27649,19 +27927,19 @@ function registerCodeContext(server2) {
|
|
|
27649
27927
|
title: "Code Context",
|
|
27650
27928
|
description: "Persistent codebase context engine. One consolidated tool to avoid MCP bloat. Actions: index, search, trace, blast_radius, stats.",
|
|
27651
27929
|
inputSchema: {
|
|
27652
|
-
action:
|
|
27653
|
-
project_root:
|
|
27654
|
-
query:
|
|
27655
|
-
symbol:
|
|
27656
|
-
file_path:
|
|
27657
|
-
force:
|
|
27658
|
-
limit:
|
|
27659
|
-
offset:
|
|
27660
|
-
refresh_index:
|
|
27661
|
-
languages:
|
|
27662
|
-
paths:
|
|
27663
|
-
depth:
|
|
27664
|
-
max_files:
|
|
27930
|
+
action: z90.enum(["index", "search", "trace", "blast_radius", "stats"]).describe("Code context operation"),
|
|
27931
|
+
project_root: z90.string().optional().describe("Repository root. Defaults to current working directory."),
|
|
27932
|
+
query: z90.string().optional().describe("Search query for action=search"),
|
|
27933
|
+
symbol: z90.string().optional().describe("Symbol/function/class/type name for trace or blast_radius"),
|
|
27934
|
+
file_path: z90.string().optional().describe("File path for blast_radius"),
|
|
27935
|
+
force: z90.boolean().optional().describe("Force rebuild before answering"),
|
|
27936
|
+
limit: z90.coerce.number().int().min(1).max(100).optional().describe("Max results"),
|
|
27937
|
+
offset: z90.coerce.number().int().min(0).optional().describe("Search pagination offset"),
|
|
27938
|
+
refresh_index: z90.boolean().optional().describe("Refresh/rebuild index before searching"),
|
|
27939
|
+
languages: z90.array(z90.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
|
|
27940
|
+
paths: z90.array(z90.string()).optional().describe("Path/glob filters"),
|
|
27941
|
+
depth: z90.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
|
|
27942
|
+
max_files: z90.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index")
|
|
27665
27943
|
}
|
|
27666
27944
|
}, async ({ action, project_root, query, symbol, file_path, force, limit, offset, refresh_index, languages, paths, depth, max_files }) => {
|
|
27667
27945
|
const opts = { projectRoot: project_root, force, maxFiles: max_files };
|
|
@@ -27706,9 +27984,9 @@ function registerCodeContext(server2) {
|
|
|
27706
27984
|
}
|
|
27707
27985
|
|
|
27708
27986
|
// src/mcp/tools/support-inbox.ts
|
|
27709
|
-
import { z as
|
|
27987
|
+
import { z as z91 } from "zod";
|
|
27710
27988
|
var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
27711
|
-
var STATUS =
|
|
27989
|
+
var STATUS = z91.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
27712
27990
|
function adminToken() {
|
|
27713
27991
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
27714
27992
|
}
|
|
@@ -27747,9 +28025,9 @@ function registerListBugReports(server2) {
|
|
|
27747
28025
|
title: "List Bug Reports",
|
|
27748
28026
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
27749
28027
|
inputSchema: {
|
|
27750
|
-
status:
|
|
27751
|
-
severity:
|
|
27752
|
-
limit:
|
|
28028
|
+
status: z91.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
28029
|
+
severity: z91.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
28030
|
+
limit: z91.number().int().min(1).max(100).default(25)
|
|
27753
28031
|
}
|
|
27754
28032
|
},
|
|
27755
28033
|
async ({ status, severity, limit }) => {
|
|
@@ -27768,7 +28046,7 @@ function registerGetBugReport(server2) {
|
|
|
27768
28046
|
{
|
|
27769
28047
|
title: "Get Bug Report",
|
|
27770
28048
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
27771
|
-
inputSchema: { id:
|
|
28049
|
+
inputSchema: { id: z91.string().min(8) }
|
|
27772
28050
|
},
|
|
27773
28051
|
async ({ id }) => {
|
|
27774
28052
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -27783,12 +28061,12 @@ function registerTriageBugReport(server2) {
|
|
|
27783
28061
|
title: "Triage Bug Report",
|
|
27784
28062
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
27785
28063
|
inputSchema: {
|
|
27786
|
-
id:
|
|
28064
|
+
id: z91.string().min(8),
|
|
27787
28065
|
status: STATUS.optional(),
|
|
27788
|
-
triage_notes:
|
|
27789
|
-
linked_task_id:
|
|
27790
|
-
linked_commit:
|
|
27791
|
-
fixed_version:
|
|
28066
|
+
triage_notes: z91.string().optional(),
|
|
28067
|
+
linked_task_id: z91.string().optional(),
|
|
28068
|
+
linked_commit: z91.string().optional(),
|
|
28069
|
+
fixed_version: z91.string().optional()
|
|
27792
28070
|
}
|
|
27793
28071
|
},
|
|
27794
28072
|
async ({ id, status, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -27851,6 +28129,7 @@ var TOOL_CATEGORIES = {
|
|
|
27851
28129
|
registerStoreDecision: "core",
|
|
27852
28130
|
registerGetDecision: "core",
|
|
27853
28131
|
registerCreateBugReport: "core",
|
|
28132
|
+
registerSupportTools: "core",
|
|
27854
28133
|
registerGetSessionEvents: "core",
|
|
27855
28134
|
registerGetLastAssistantResponse: "core",
|
|
27856
28135
|
registerCodeContext: "graph-read",
|
|
@@ -28120,6 +28399,7 @@ function registerAllTools(server2) {
|
|
|
28120
28399
|
gate("registerStoreDecision", registerStoreDecision);
|
|
28121
28400
|
gate("registerGetDecision", registerGetDecision);
|
|
28122
28401
|
gate("registerCreateBugReport", registerCreateBugReport);
|
|
28402
|
+
gate("registerSupportTools", registerSupportTools);
|
|
28123
28403
|
gate("registerGetSessionEvents", registerGetSessionEvents);
|
|
28124
28404
|
gate("registerGetLastAssistantResponse", registerGetLastAssistantResponse);
|
|
28125
28405
|
gate("registerCodeContext", registerCodeContext);
|
|
@@ -28293,16 +28573,16 @@ try {
|
|
|
28293
28573
|
}
|
|
28294
28574
|
}, 3e4);
|
|
28295
28575
|
_ppidWatchdog.unref();
|
|
28296
|
-
const MCP_VERSION_PATH =
|
|
28576
|
+
const MCP_VERSION_PATH = path52.join(os20.homedir(), ".exe-os", "mcp-version");
|
|
28297
28577
|
let _currentMcpVersion = null;
|
|
28298
28578
|
try {
|
|
28299
|
-
_currentMcpVersion = existsSync40(MCP_VERSION_PATH) ?
|
|
28579
|
+
_currentMcpVersion = existsSync40(MCP_VERSION_PATH) ? readFileSync34(MCP_VERSION_PATH, "utf8").trim() : null;
|
|
28300
28580
|
} catch {
|
|
28301
28581
|
}
|
|
28302
28582
|
const _versionWatchdog = setInterval(() => {
|
|
28303
28583
|
try {
|
|
28304
28584
|
if (!existsSync40(MCP_VERSION_PATH)) return;
|
|
28305
|
-
const diskVersion =
|
|
28585
|
+
const diskVersion = readFileSync34(MCP_VERSION_PATH, "utf8").trim();
|
|
28306
28586
|
if (_currentMcpVersion && diskVersion !== _currentMcpVersion) {
|
|
28307
28587
|
process.stderr.write(
|
|
28308
28588
|
`[exe-os] MCP version changed (${_currentMcpVersion} \u2192 ${diskVersion}). Hot-reloading...
|
|
@@ -28335,14 +28615,14 @@ try {
|
|
|
28335
28615
|
`
|
|
28336
28616
|
);
|
|
28337
28617
|
const thisFile = fileURLToPath6(import.meta.url);
|
|
28338
|
-
const backfillPath =
|
|
28339
|
-
|
|
28618
|
+
const backfillPath = path52.resolve(
|
|
28619
|
+
path52.dirname(thisFile),
|
|
28340
28620
|
"../bin/backfill-vectors.js"
|
|
28341
28621
|
);
|
|
28342
28622
|
if (existsSync40(backfillPath)) {
|
|
28343
28623
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
28344
|
-
const logPath =
|
|
28345
|
-
|
|
28624
|
+
const logPath = path52.join(exeDir, "workers.log");
|
|
28625
|
+
mkdirSync23(path52.dirname(logPath), { recursive: true });
|
|
28346
28626
|
let logFd = "ignore";
|
|
28347
28627
|
try {
|
|
28348
28628
|
logFd = openSync4(logPath, "a");
|