@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.
Files changed (71) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +2 -2
  2. package/dist/bin/agentic-reflection-backfill.js +2 -2
  3. package/dist/bin/agentic-semantic-label.js +2 -2
  4. package/dist/bin/backfill-conversations.js +2 -2
  5. package/dist/bin/backfill-responses.js +2 -2
  6. package/dist/bin/backfill-vectors.js +2 -2
  7. package/dist/bin/bulk-sync-postgres.js +2 -2
  8. package/dist/bin/cleanup-stale-review-tasks.js +2 -2
  9. package/dist/bin/cli.js +6 -3
  10. package/dist/bin/customer-readiness.js +4 -0
  11. package/dist/bin/exe-agent.js +2 -2
  12. package/dist/bin/exe-assign.js +2 -2
  13. package/dist/bin/exe-boot.js +2 -2
  14. package/dist/bin/exe-call.js +2 -2
  15. package/dist/bin/exe-cloud.js +2 -2
  16. package/dist/bin/exe-dispatch.js +2 -2
  17. package/dist/bin/exe-doctor.js +2 -2
  18. package/dist/bin/exe-export-behaviors.js +2 -2
  19. package/dist/bin/exe-forget.js +2 -2
  20. package/dist/bin/exe-gateway.js +2 -2
  21. package/dist/bin/exe-heartbeat.js +2 -2
  22. package/dist/bin/exe-kill.js +2 -2
  23. package/dist/bin/exe-launch-agent.js +2 -2
  24. package/dist/bin/exe-new-employee.js +2 -2
  25. package/dist/bin/exe-pending-messages.js +2 -2
  26. package/dist/bin/exe-pending-notifications.js +2 -2
  27. package/dist/bin/exe-pending-reviews.js +2 -2
  28. package/dist/bin/exe-rename.js +2 -2
  29. package/dist/bin/exe-review.js +2 -2
  30. package/dist/bin/exe-search.js +2 -2
  31. package/dist/bin/exe-session-cleanup.js +2 -2
  32. package/dist/bin/exe-start-codex.js +2 -2
  33. package/dist/bin/exe-start-opencode.js +2 -2
  34. package/dist/bin/exe-status.js +2 -2
  35. package/dist/bin/exe-support.js +4 -1
  36. package/dist/bin/exe-team.js +2 -2
  37. package/dist/bin/git-sweep.js +2 -2
  38. package/dist/bin/graph-backfill.js +2 -2
  39. package/dist/bin/graph-export.js +2 -2
  40. package/dist/bin/intercom-check.js +2 -2
  41. package/dist/bin/scan-tasks.js +2 -2
  42. package/dist/bin/setup.js +2 -2
  43. package/dist/bin/shard-migrate.js +2 -2
  44. package/dist/gateway/index.js +2 -2
  45. package/dist/hooks/bug-report-worker.js +2 -2
  46. package/dist/hooks/codex-stop-task-finalizer.js +2 -2
  47. package/dist/hooks/commit-complete.js +2 -2
  48. package/dist/hooks/error-recall.js +2 -2
  49. package/dist/hooks/ingest.js +2 -2
  50. package/dist/hooks/instructions-loaded.js +2 -2
  51. package/dist/hooks/notification.js +2 -2
  52. package/dist/hooks/post-compact.js +2 -2
  53. package/dist/hooks/post-tool-combined.js +2 -2
  54. package/dist/hooks/pre-compact.js +2 -2
  55. package/dist/hooks/pre-tool-use.js +2 -2
  56. package/dist/hooks/prompt-submit.js +2 -2
  57. package/dist/hooks/session-end.js +2 -2
  58. package/dist/hooks/session-start.js +2 -2
  59. package/dist/hooks/stop.js +2 -2
  60. package/dist/hooks/subagent-stop.js +2 -2
  61. package/dist/hooks/summary-worker.js +2 -2
  62. package/dist/index.js +2 -2
  63. package/dist/lib/employee-templates.js +2 -2
  64. package/dist/lib/exe-daemon.js +431 -140
  65. package/dist/lib/hybrid-search.js +2 -2
  66. package/dist/lib/schedules.js +2 -2
  67. package/dist/lib/store.js +2 -2
  68. package/dist/mcp/server.js +368 -88
  69. package/dist/runtime/index.js +2 -2
  70. package/dist/tui/App.js +2 -2
  71. package/package.json +1 -1
@@ -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 path52 = await import("path");
881
- const modelPath = path52.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
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: readFileSync34 } = __require("fs");
3725
- return readFileSync34("/etc/machine-id", "utf-8").trim();
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, run `exe-os support test` and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues. 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."
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, run `exe-os support test` from the terminal to verify local file write, license auth, support endpoint health, and upstream POST."
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 path52 = await import("path");
7306
+ const path53 = await import("path");
7307
7307
  const os21 = await import("os");
7308
- const logPath = path52.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
7309
- fs.mkdirSync(path52.dirname(logPath), { recursive: true });
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, path52, method = "GET", body) {
8603
- const url = `${config2.baseUrl}/api/v1${path52}`;
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} ${path52}: ${response.status} ${response.statusText}`);
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 mkdirSync22, closeSync as closeSync4, readFileSync as readFileSync33 } from "fs";
13967
- import path51 from "path";
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: mkdirSync23, writeFileSync: writeFileSync24 } = await import("fs");
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)) mkdirSync23(dir, { recursive: true });
15366
- writeFileSync24(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
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 path52 = await import("path");
18340
+ const path53 = await import("path");
18341
18341
  const os21 = await import("os");
18342
- const outDir = path52.join(os21.homedir(), ".exe-os", "exports");
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 = path52.join(outDir, `graph-${timestamp}.html`);
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, path52, body) {
23324
+ async request(method, path53, body) {
23325
23325
  await this.rateLimit();
23326
- const url = `${this.baseUrl}${path52}`;
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, path52 = "/dns_records", query) {
23400
- const normalizedPath = path52.startsWith("/") ? path52 : `/${path52}`;
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 z88 } from "zod";
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 randomUUID9 } from "crypto";
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 = z88.enum([
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: z88.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
27166
- session_id: z88.string().optional().describe("Optional exact runtime 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: z88.string().optional().describe("Optional project filter. Pass 'all' for all projects."),
27169
- limit: z88.number().int().min(1).max(100).default(20).describe("Number of events to return.")
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: z88.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
27206
- project_name: z88.string().optional().describe("Optional project filter. Pass 'all' for all projects.")
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 z89 } from "zod";
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 path50 from "path";
27242
- import { existsSync as existsSync39, mkdirSync as mkdirSync21, readFileSync as readFileSync32, readdirSync as readdirSync14, statSync as statSync9, writeFileSync as writeFileSync23 } from "fs";
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 path50.resolve(projectRoot || process.cwd());
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 = path50.join(EXE_AI_DIR, "code-context");
27255
- mkdirSync21(dir, { recursive: true });
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 path50.join(indexDir(), `${rootHash}.json`);
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 = path50.join(dir, entry.name);
27275
- const rel = path50.relative(projectRoot, abs).replaceAll(path50.sep, "/");
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(path50.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
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 = path50.posix.normalize(path50.posix.join(path50.posix.dirname(fromFile.replaceAll(path50.sep, "/")), importPath));
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(path50.posix.join(base, indexName));
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(readFileSync32(file, "utf8"));
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
- writeFileSync23(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
27606
+ writeFileSync24(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
27329
27607
  }
27330
27608
  function buildFileRecord(projectRoot, relPath, allFiles, previous) {
27331
- const absPath = path50.join(projectRoot, relPath);
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 = readFileSync32(absPath, "utf8");
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(path50.sep, "/")));
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(path50.sep, "/");
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(path50.sep, "/");
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(path50.join(projectRoot, normalized));
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(path50.sep, "/");
27739
+ const normalized = filePath.replaceAll(path51.sep, "/");
27462
27740
  return patterns.some((pattern) => {
27463
- const p = pattern.replaceAll(path50.sep, "/").replace(/^\.\//, "");
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(path50.sep, "/").replace(/^\.\//, "");
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 = path50.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
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: z89.enum(["index", "search", "trace", "blast_radius", "stats"]).describe("Code context operation"),
27653
- project_root: z89.string().optional().describe("Repository root. Defaults to current working directory."),
27654
- query: z89.string().optional().describe("Search query for action=search"),
27655
- symbol: z89.string().optional().describe("Symbol/function/class/type name for trace or blast_radius"),
27656
- file_path: z89.string().optional().describe("File path for blast_radius"),
27657
- force: z89.boolean().optional().describe("Force rebuild before answering"),
27658
- limit: z89.coerce.number().int().min(1).max(100).optional().describe("Max results"),
27659
- offset: z89.coerce.number().int().min(0).optional().describe("Search pagination offset"),
27660
- refresh_index: z89.boolean().optional().describe("Refresh/rebuild index before searching"),
27661
- languages: z89.array(z89.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
27662
- paths: z89.array(z89.string()).optional().describe("Path/glob filters"),
27663
- depth: z89.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
27664
- max_files: z89.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index")
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 z90 } from "zod";
27987
+ import { z as z91 } from "zod";
27710
27988
  var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
27711
- var STATUS = z90.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
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: z90.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
27751
- severity: z90.enum(["p0", "p1", "p2", "p3"]).optional(),
27752
- limit: z90.number().int().min(1).max(100).default(25)
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: z90.string().min(8) }
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: z90.string().min(8),
28064
+ id: z91.string().min(8),
27787
28065
  status: STATUS.optional(),
27788
- triage_notes: z90.string().optional(),
27789
- linked_task_id: z90.string().optional(),
27790
- linked_commit: z90.string().optional(),
27791
- fixed_version: z90.string().optional()
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 = path51.join(os20.homedir(), ".exe-os", "mcp-version");
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) ? readFileSync33(MCP_VERSION_PATH, "utf8").trim() : null;
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 = readFileSync33(MCP_VERSION_PATH, "utf8").trim();
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 = path51.resolve(
28339
- path51.dirname(thisFile),
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 = path51.join(exeDir, "workers.log");
28345
- mkdirSync22(path51.dirname(logPath), { recursive: true });
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");