@askexenow/exe-os 0.9.86 → 0.9.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agentic-ontology-backfill.js +18 -0
- package/dist/bin/agentic-reflection-backfill.js +18 -0
- package/dist/bin/agentic-semantic-label.js +18 -0
- package/dist/bin/backfill-conversations.js +18 -0
- package/dist/bin/backfill-responses.js +18 -0
- package/dist/bin/backfill-vectors.js +18 -0
- package/dist/bin/bulk-sync-postgres.js +18 -0
- package/dist/bin/cleanup-stale-review-tasks.js +18 -0
- package/dist/bin/cli.js +187 -4
- package/dist/bin/exe-agent.js +18 -0
- package/dist/bin/exe-assign.js +18 -0
- package/dist/bin/exe-boot.js +18 -0
- package/dist/bin/exe-call.js +18 -0
- package/dist/bin/exe-cloud.js +18 -0
- package/dist/bin/exe-dispatch.js +18 -0
- package/dist/bin/exe-doctor.js +18 -0
- package/dist/bin/exe-export-behaviors.js +18 -0
- package/dist/bin/exe-forget.js +18 -0
- package/dist/bin/exe-gateway.js +18 -0
- package/dist/bin/exe-heartbeat.js +18 -0
- package/dist/bin/exe-kill.js +18 -0
- package/dist/bin/exe-launch-agent.js +18 -0
- package/dist/bin/exe-new-employee.js +33 -2
- package/dist/bin/exe-pending-messages.js +18 -0
- package/dist/bin/exe-pending-notifications.js +18 -0
- package/dist/bin/exe-pending-reviews.js +18 -0
- package/dist/bin/exe-rename.js +18 -0
- package/dist/bin/exe-review.js +18 -0
- package/dist/bin/exe-search.js +18 -0
- package/dist/bin/exe-session-cleanup.js +18 -0
- package/dist/bin/exe-start-codex.js +18 -0
- package/dist/bin/exe-start-opencode.js +18 -0
- package/dist/bin/exe-status.js +18 -0
- package/dist/bin/exe-team.js +18 -0
- package/dist/bin/git-sweep.js +18 -0
- package/dist/bin/graph-backfill.js +18 -0
- package/dist/bin/graph-export.js +18 -0
- package/dist/bin/install.js +9 -0
- package/dist/bin/intercom-check.js +18 -0
- package/dist/bin/scan-tasks.js +18 -0
- package/dist/bin/setup.js +24 -2
- package/dist/bin/shard-migrate.js +18 -0
- package/dist/gateway/index.js +18 -0
- package/dist/hooks/bug-report-worker.js +18 -0
- package/dist/hooks/codex-stop-task-finalizer.js +18 -0
- package/dist/hooks/commit-complete.js +18 -0
- package/dist/hooks/error-recall.js +18 -0
- package/dist/hooks/ingest.js +18 -0
- package/dist/hooks/instructions-loaded.js +18 -0
- package/dist/hooks/notification.js +18 -0
- package/dist/hooks/post-compact.js +18 -0
- package/dist/hooks/post-tool-combined.js +18 -0
- package/dist/hooks/pre-compact.js +18 -0
- package/dist/hooks/pre-tool-use.js +18 -0
- package/dist/hooks/prompt-submit.js +18 -0
- package/dist/hooks/session-end.js +18 -0
- package/dist/hooks/session-start.js +18 -0
- package/dist/hooks/stop.js +18 -0
- package/dist/hooks/subagent-stop.js +18 -0
- package/dist/hooks/summary-worker.js +18 -0
- package/dist/index.js +18 -0
- package/dist/lib/employee-templates.js +18 -0
- package/dist/lib/exe-daemon.js +712 -169
- package/dist/lib/hybrid-search.js +18 -0
- package/dist/lib/identity-templates.js +6 -2
- package/dist/lib/schedules.js +18 -0
- package/dist/lib/store.js +18 -0
- package/dist/mcp/server.js +670 -143
- package/dist/mcp/tools/create-task.js +6 -2
- package/dist/runtime/index.js +18 -0
- package/dist/tui/App.js +18 -0
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -889,8 +889,8 @@ async function embedDirect(text3) {
|
|
|
889
889
|
const llamaCpp = await import("node-llama-cpp");
|
|
890
890
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
891
891
|
const { existsSync: existsSync42 } = await import("fs");
|
|
892
|
-
const
|
|
893
|
-
const modelPath =
|
|
892
|
+
const path56 = await import("path");
|
|
893
|
+
const modelPath = path56.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
894
894
|
if (!existsSync42(modelPath)) {
|
|
895
895
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
896
896
|
}
|
|
@@ -3723,7 +3723,7 @@ async function tryKeytar() {
|
|
|
3723
3723
|
}
|
|
3724
3724
|
function deriveMachineKey() {
|
|
3725
3725
|
try {
|
|
3726
|
-
const
|
|
3726
|
+
const crypto21 = __require("crypto");
|
|
3727
3727
|
const material = [
|
|
3728
3728
|
os5.hostname(),
|
|
3729
3729
|
os5.userInfo().username,
|
|
@@ -3732,7 +3732,7 @@ function deriveMachineKey() {
|
|
|
3732
3732
|
// Machine ID on Linux (stable across reboots)
|
|
3733
3733
|
process.platform === "linux" ? readMachineId() : ""
|
|
3734
3734
|
].join("|");
|
|
3735
|
-
return
|
|
3735
|
+
return crypto21.createHash("sha256").update(material).digest();
|
|
3736
3736
|
} catch {
|
|
3737
3737
|
return null;
|
|
3738
3738
|
}
|
|
@@ -3746,9 +3746,9 @@ function readMachineId() {
|
|
|
3746
3746
|
}
|
|
3747
3747
|
}
|
|
3748
3748
|
function encryptWithMachineKey(plaintext, machineKey) {
|
|
3749
|
-
const
|
|
3750
|
-
const iv =
|
|
3751
|
-
const cipher =
|
|
3749
|
+
const crypto21 = __require("crypto");
|
|
3750
|
+
const iv = crypto21.randomBytes(12);
|
|
3751
|
+
const cipher = crypto21.createCipheriv("aes-256-gcm", machineKey, iv);
|
|
3752
3752
|
let encrypted = cipher.update(plaintext, "utf-8", "base64");
|
|
3753
3753
|
encrypted += cipher.final("base64");
|
|
3754
3754
|
const authTag = cipher.getAuthTag().toString("base64");
|
|
@@ -3757,13 +3757,13 @@ function encryptWithMachineKey(plaintext, machineKey) {
|
|
|
3757
3757
|
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3758
3758
|
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3759
3759
|
try {
|
|
3760
|
-
const
|
|
3760
|
+
const crypto21 = __require("crypto");
|
|
3761
3761
|
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3762
3762
|
if (parts.length !== 3) return null;
|
|
3763
3763
|
const [ivB64, tagB64, cipherB64] = parts;
|
|
3764
3764
|
const iv = Buffer.from(ivB64, "base64");
|
|
3765
3765
|
const authTag = Buffer.from(tagB64, "base64");
|
|
3766
|
-
const decipher =
|
|
3766
|
+
const decipher = crypto21.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3767
3767
|
decipher.setAuthTag(authTag);
|
|
3768
3768
|
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3769
3769
|
decrypted += decipher.final("utf-8");
|
|
@@ -4801,6 +4801,24 @@ var init_platform_procedures = __esm({
|
|
|
4801
4801
|
priority: "p0",
|
|
4802
4802
|
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."
|
|
4803
4803
|
},
|
|
4804
|
+
{
|
|
4805
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
4806
|
+
domain: "support",
|
|
4807
|
+
priority: "p1",
|
|
4808
|
+
content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
4809
|
+
},
|
|
4810
|
+
{
|
|
4811
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
4812
|
+
domain: "support",
|
|
4813
|
+
priority: "p0",
|
|
4814
|
+
content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
|
|
4815
|
+
},
|
|
4816
|
+
{
|
|
4817
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
4818
|
+
domain: "support",
|
|
4819
|
+
priority: "p1",
|
|
4820
|
+
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
4821
|
+
},
|
|
4804
4822
|
// --- Operations ---
|
|
4805
4823
|
{
|
|
4806
4824
|
title: "Managers must supervise deployed workers",
|
|
@@ -7321,10 +7339,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
7321
7339
|
};
|
|
7322
7340
|
try {
|
|
7323
7341
|
const fs = await import("fs");
|
|
7324
|
-
const
|
|
7342
|
+
const path56 = await import("path");
|
|
7325
7343
|
const os21 = await import("os");
|
|
7326
|
-
const logPath =
|
|
7327
|
-
fs.mkdirSync(
|
|
7344
|
+
const logPath = path56.join(os21.homedir(), ".exe-os", "search-quality.jsonl");
|
|
7345
|
+
fs.mkdirSync(path56.dirname(logPath), { recursive: true });
|
|
7328
7346
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
7329
7347
|
} catch {
|
|
7330
7348
|
}
|
|
@@ -8617,8 +8635,8 @@ __export(wiki_client_exports, {
|
|
|
8617
8635
|
listDocuments: () => listDocuments,
|
|
8618
8636
|
listWorkspaces: () => listWorkspaces
|
|
8619
8637
|
});
|
|
8620
|
-
async function wikiFetch(config2,
|
|
8621
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8638
|
+
async function wikiFetch(config2, path56, method = "GET", body) {
|
|
8639
|
+
const url = `${config2.baseUrl}/api/v1${path56}`;
|
|
8622
8640
|
const headers = {
|
|
8623
8641
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
8624
8642
|
"Content-Type": "application/json"
|
|
@@ -8651,7 +8669,7 @@ async function wikiFetch(config2, path55, method = "GET", body) {
|
|
|
8651
8669
|
}
|
|
8652
8670
|
}
|
|
8653
8671
|
if (!response.ok) {
|
|
8654
|
-
throw new Error(`Wiki API ${method} ${
|
|
8672
|
+
throw new Error(`Wiki API ${method} ${path56}: ${response.status} ${response.statusText}`);
|
|
8655
8673
|
}
|
|
8656
8674
|
return response.json();
|
|
8657
8675
|
} finally {
|
|
@@ -12786,12 +12804,14 @@ On EVERY new conversation, before doing anything else:
|
|
|
12786
12804
|
1. **Memory scan**: Run recall_my_memory with broad queries \u2014 "project", "client", "pipeline", "campaign", "deal", "decision", "blocker". Summarize what you find.
|
|
12787
12805
|
2. **Task scan**: Run list_tasks to see what's open, in progress, blocked, or needs review across all employees.
|
|
12788
12806
|
3. **Team check**: Run ask_team_memory for recent activity from CTO/CMO/engineers.
|
|
12789
|
-
4. **
|
|
12807
|
+
4. **Bug fix check** (one-time, never repeat): Call list_my_bug_reports to see if AskExe has fixed any previously filed bugs. If any have status "fixed" with a fixed_version, tell the founder: "\u{1F527} N bug fix(es) available \u2014 run \`exe-os update\` to get version X.Y.Z." Skip silently if none or if the call fails.
|
|
12808
|
+
5. **Present the brief**: Give the founder a concise status report:
|
|
12790
12809
|
- What's active and progressing
|
|
12791
12810
|
- What's blocked and needs attention
|
|
12792
12811
|
- What decisions are pending
|
|
12812
|
+
- Available bug fixes (from step 4, if any)
|
|
12793
12813
|
- What you recommend doing next
|
|
12794
|
-
|
|
12814
|
+
6. Then ask: "What's the priority?"
|
|
12795
12815
|
|
|
12796
12816
|
If this is your FIRST ever conversation (few or no prior memories):
|
|
12797
12817
|
- Search more broadly: "product", "SEO", "meeting", "strategy", "revenue"
|
|
@@ -12811,6 +12831,8 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
12811
12831
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
12812
12832
|
- **set_agent_config** \u2014 view or change which tool (Claude Code, Codex, OpenCode) and model each agent uses. Call with no args to show all agents' current settings. Call with agent_id + runtime + model to change.
|
|
12813
12833
|
- **send_message** \u2014 direct intercom to employees
|
|
12834
|
+
- **create_bug_report** \u2014 file a bug when you encounter an Exe OS platform issue
|
|
12835
|
+
- **list_my_bug_reports** \u2014 check status of filed bugs (boot check: surface available fixes to founder)
|
|
12814
12836
|
${PLAN_MODE_COMPAT}
|
|
12815
12837
|
## Completion Workflow
|
|
12816
12838
|
|
|
@@ -14208,7 +14230,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
14208
14230
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14209
14231
|
import { spawn as spawn4 } from "child_process";
|
|
14210
14232
|
import { existsSync as existsSync41, openSync as openSync4, mkdirSync as mkdirSync23, closeSync as closeSync4, readFileSync as readFileSync36 } from "fs";
|
|
14211
|
-
import
|
|
14233
|
+
import path55 from "path";
|
|
14212
14234
|
import os20 from "os";
|
|
14213
14235
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
14214
14236
|
|
|
@@ -18596,12 +18618,12 @@ function registerExportGraph(server2) {
|
|
|
18596
18618
|
}
|
|
18597
18619
|
const html = await exportGraphHTML(client);
|
|
18598
18620
|
const fs = await import("fs");
|
|
18599
|
-
const
|
|
18621
|
+
const path56 = await import("path");
|
|
18600
18622
|
const os21 = await import("os");
|
|
18601
|
-
const outDir =
|
|
18623
|
+
const outDir = path56.join(os21.homedir(), ".exe-os", "exports");
|
|
18602
18624
|
fs.mkdirSync(outDir, { recursive: true });
|
|
18603
18625
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
18604
|
-
const filePath =
|
|
18626
|
+
const filePath = path56.join(outDir, `graph-${timestamp}.html`);
|
|
18605
18627
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
18606
18628
|
return {
|
|
18607
18629
|
content: [
|
|
@@ -23580,9 +23602,9 @@ var HostingerApiClient = class {
|
|
|
23580
23602
|
}
|
|
23581
23603
|
this.lastRequestTime = Date.now();
|
|
23582
23604
|
}
|
|
23583
|
-
async request(method,
|
|
23605
|
+
async request(method, path56, body) {
|
|
23584
23606
|
await this.rateLimit();
|
|
23585
|
-
const url = `${this.baseUrl}${
|
|
23607
|
+
const url = `${this.baseUrl}${path56}`;
|
|
23586
23608
|
const headers = {
|
|
23587
23609
|
Authorization: `Bearer ${this.apiKey}`,
|
|
23588
23610
|
"Content-Type": "application/json",
|
|
@@ -23655,8 +23677,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
23655
23677
|
}
|
|
23656
23678
|
return envelope.result;
|
|
23657
23679
|
}
|
|
23658
|
-
function buildUrl(zoneId,
|
|
23659
|
-
const normalizedPath =
|
|
23680
|
+
function buildUrl(zoneId, path56 = "/dns_records", query) {
|
|
23681
|
+
const normalizedPath = path56.startsWith("/") ? path56 : `/${path56}`;
|
|
23660
23682
|
const url = new URL(
|
|
23661
23683
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
23662
23684
|
);
|
|
@@ -27367,14 +27389,206 @@ Upstream status: ${upstreamStatus}`
|
|
|
27367
27389
|
);
|
|
27368
27390
|
}
|
|
27369
27391
|
|
|
27370
|
-
// src/mcp/tools/
|
|
27392
|
+
// src/mcp/tools/create-feature-request.ts
|
|
27393
|
+
init_embedder();
|
|
27394
|
+
init_active_agent();
|
|
27395
|
+
init_config();
|
|
27396
|
+
init_license();
|
|
27397
|
+
init_store();
|
|
27371
27398
|
import { z as z89 } from "zod";
|
|
27399
|
+
import crypto19 from "crypto";
|
|
27400
|
+
import { mkdir as mkdir7, writeFile as writeFile8 } from "fs/promises";
|
|
27401
|
+
import path50 from "path";
|
|
27402
|
+
var CATEGORY = z89.enum([
|
|
27403
|
+
"upstream_feature",
|
|
27404
|
+
"local_customization",
|
|
27405
|
+
"integration",
|
|
27406
|
+
"unclear"
|
|
27407
|
+
]);
|
|
27408
|
+
var PRIORITY = z89.enum(["p0", "p1", "p2", "p3"]);
|
|
27409
|
+
function slugify3(input) {
|
|
27410
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "feature-request";
|
|
27411
|
+
}
|
|
27412
|
+
function section2(title, body) {
|
|
27413
|
+
return `## ${title}
|
|
27414
|
+
|
|
27415
|
+
${body?.trim() || "Not provided"}`;
|
|
27416
|
+
}
|
|
27417
|
+
function buildMarkdown2(input) {
|
|
27418
|
+
return [
|
|
27419
|
+
`# Feature Request \u2014 ${input.title}`,
|
|
27420
|
+
"",
|
|
27421
|
+
`id: ${input.id}`,
|
|
27422
|
+
`category: ${input.category}`,
|
|
27423
|
+
`priority: ${input.priority}`,
|
|
27424
|
+
`filed_by: ${input.agentId} (${input.agentRole})`,
|
|
27425
|
+
`package_version: ${input.packageVersion}`,
|
|
27426
|
+
`project: ${input.projectName ?? "unknown"}`,
|
|
27427
|
+
`created_at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
27428
|
+
"",
|
|
27429
|
+
section2("Description", input.description),
|
|
27430
|
+
section2("Use Case", input.useCase),
|
|
27431
|
+
section2("Current Workaround", input.currentWorkaround),
|
|
27432
|
+
section2("Proposed Solution", input.proposedSolution),
|
|
27433
|
+
section2("Business Impact", input.businessImpact)
|
|
27434
|
+
].join("\n");
|
|
27435
|
+
}
|
|
27436
|
+
async function maybeSendUpstream2(payload) {
|
|
27437
|
+
const config2 = await loadConfig();
|
|
27438
|
+
const routerUrl = process.env.API_ROUTER_URL?.replace(/\/+$/, "");
|
|
27439
|
+
const endpoint2 = config2.support?.featureRequestEndpoint || process.env.EXE_FEATURE_REQUEST_ENDPOINT || (routerUrl ? `${routerUrl}/v1/support/feature-requests` : "https://askexe.com/v1/support/feature-requests");
|
|
27440
|
+
const token = config2.support?.featureRequestToken || process.env.EXE_FEATURE_REQUEST_TOKEN;
|
|
27441
|
+
const licenseKey = loadLicense() || process.env.EXE_LICENSE_KEY || config2.cloud?.apiKey;
|
|
27442
|
+
const licenseToken = readCachedLicenseToken();
|
|
27443
|
+
if (!endpoint2) {
|
|
27444
|
+
return "not_configured";
|
|
27445
|
+
}
|
|
27446
|
+
try {
|
|
27447
|
+
const parsed = new URL(endpoint2);
|
|
27448
|
+
if (parsed.protocol !== "https:" && !["localhost", "127.0.0.1", "::1"].includes(parsed.hostname)) {
|
|
27449
|
+
return "failed: insecure endpoint rejected";
|
|
27450
|
+
}
|
|
27451
|
+
const response = await fetch(parsed, {
|
|
27452
|
+
method: "POST",
|
|
27453
|
+
headers: {
|
|
27454
|
+
"content-type": "application/json",
|
|
27455
|
+
...token ? { authorization: `Bearer ${token}` } : {},
|
|
27456
|
+
...licenseKey ? { "x-exe-license-key": licenseKey } : {},
|
|
27457
|
+
...licenseToken ? { "x-exe-license-token": licenseToken } : {}
|
|
27458
|
+
},
|
|
27459
|
+
body: JSON.stringify(payload),
|
|
27460
|
+
signal: AbortSignal.timeout(1e4)
|
|
27461
|
+
});
|
|
27462
|
+
if (!response.ok) return `failed: HTTP ${response.status}`;
|
|
27463
|
+
return "sent";
|
|
27464
|
+
} catch (err) {
|
|
27465
|
+
return `failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
27466
|
+
}
|
|
27467
|
+
}
|
|
27468
|
+
function registerCreateFeatureRequest(server2) {
|
|
27469
|
+
server2.registerTool(
|
|
27470
|
+
"create_feature_request",
|
|
27471
|
+
{
|
|
27472
|
+
title: "Create Feature Request",
|
|
27473
|
+
description: "File a feature request for exe-os: upstream_feature (requires platform changes), local_customization (configurable in customer layers), integration (third-party), or unclear. Writes a local report, stores memory, and optionally sends to AskExe.",
|
|
27474
|
+
inputSchema: {
|
|
27475
|
+
title: z89.string().min(3).describe("Short descriptive title"),
|
|
27476
|
+
category: CATEGORY.describe(
|
|
27477
|
+
"upstream_feature = platform capability change; local_customization = configurable in customer layers; integration = third-party connector; unclear = needs product triage"
|
|
27478
|
+
),
|
|
27479
|
+
priority: PRIORITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
27480
|
+
description: z89.string().min(10).describe("What capability is needed and why"),
|
|
27481
|
+
use_case: z89.string().optional().describe("Concrete scenario where this feature would be used"),
|
|
27482
|
+
current_workaround: z89.string().optional().describe("How the need is currently addressed, if at all"),
|
|
27483
|
+
proposed_solution: z89.string().optional().describe("Suggested implementation approach"),
|
|
27484
|
+
business_impact: z89.string().optional().describe("Impact on business/workflow if this ships"),
|
|
27485
|
+
package_version: z89.string().optional().describe("Installed @askexenow/exe-os version"),
|
|
27486
|
+
project_name: z89.string().optional().describe("Project/customer context"),
|
|
27487
|
+
send_upstream: z89.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
|
|
27488
|
+
}
|
|
27489
|
+
},
|
|
27490
|
+
async ({
|
|
27491
|
+
title,
|
|
27492
|
+
category,
|
|
27493
|
+
priority,
|
|
27494
|
+
description,
|
|
27495
|
+
use_case,
|
|
27496
|
+
current_workaround,
|
|
27497
|
+
proposed_solution,
|
|
27498
|
+
business_impact,
|
|
27499
|
+
package_version,
|
|
27500
|
+
project_name,
|
|
27501
|
+
send_upstream
|
|
27502
|
+
}) => {
|
|
27503
|
+
const { agentId, agentRole } = getActiveAgent();
|
|
27504
|
+
const id = crypto19.randomUUID();
|
|
27505
|
+
const version = package_version ?? "unknown";
|
|
27506
|
+
const markdown = buildMarkdown2({
|
|
27507
|
+
id,
|
|
27508
|
+
title,
|
|
27509
|
+
category,
|
|
27510
|
+
priority,
|
|
27511
|
+
agentId,
|
|
27512
|
+
agentRole,
|
|
27513
|
+
packageVersion: version,
|
|
27514
|
+
description,
|
|
27515
|
+
useCase: use_case,
|
|
27516
|
+
currentWorkaround: current_workaround,
|
|
27517
|
+
proposedSolution: proposed_solution,
|
|
27518
|
+
businessImpact: business_impact,
|
|
27519
|
+
projectName: project_name
|
|
27520
|
+
});
|
|
27521
|
+
const outDir = path50.join(EXE_AI_DIR, "feature-requests");
|
|
27522
|
+
await mkdir7(outDir, { recursive: true });
|
|
27523
|
+
const reportPath = path50.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify3(title)}-${id.slice(0, 8)}.md`);
|
|
27524
|
+
await writeFile8(reportPath, markdown, "utf-8");
|
|
27525
|
+
let vector = null;
|
|
27526
|
+
try {
|
|
27527
|
+
vector = await embed(markdown);
|
|
27528
|
+
} catch {
|
|
27529
|
+
vector = null;
|
|
27530
|
+
}
|
|
27531
|
+
await writeMemory({
|
|
27532
|
+
id,
|
|
27533
|
+
agent_id: agentId,
|
|
27534
|
+
agent_role: agentRole,
|
|
27535
|
+
session_id: process.env.SESSION_ID ?? "manual",
|
|
27536
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27537
|
+
tool_name: "create_feature_request",
|
|
27538
|
+
project_name: project_name ?? "support",
|
|
27539
|
+
has_error: false,
|
|
27540
|
+
raw_text: markdown,
|
|
27541
|
+
vector,
|
|
27542
|
+
source_path: reportPath,
|
|
27543
|
+
source_type: "feature_request",
|
|
27544
|
+
memory_type: "feature_request",
|
|
27545
|
+
tier: 1,
|
|
27546
|
+
importance: priority === "p0" ? 10 : priority === "p1" ? 9 : priority === "p2" ? 7 : 5,
|
|
27547
|
+
intent: "request",
|
|
27548
|
+
domain: "support",
|
|
27549
|
+
file_paths: null
|
|
27550
|
+
});
|
|
27551
|
+
await flushBatch();
|
|
27552
|
+
const upstreamStatus = send_upstream ? await maybeSendUpstream2({
|
|
27553
|
+
id,
|
|
27554
|
+
title,
|
|
27555
|
+
category,
|
|
27556
|
+
priority,
|
|
27557
|
+
description,
|
|
27558
|
+
use_case,
|
|
27559
|
+
current_workaround,
|
|
27560
|
+
proposed_solution,
|
|
27561
|
+
business_impact,
|
|
27562
|
+
package_version: version,
|
|
27563
|
+
project_name,
|
|
27564
|
+
agent_id: agentId,
|
|
27565
|
+
agent_role: agentRole
|
|
27566
|
+
}) : "skipped";
|
|
27567
|
+
return {
|
|
27568
|
+
content: [
|
|
27569
|
+
{
|
|
27570
|
+
type: "text",
|
|
27571
|
+
text: `Feature request created.
|
|
27572
|
+
ID: ${id}
|
|
27573
|
+
Category: ${category}
|
|
27574
|
+
Local report: ${reportPath}
|
|
27575
|
+
Memory stored: ${id}
|
|
27576
|
+
Upstream status: ${upstreamStatus}`
|
|
27577
|
+
}
|
|
27578
|
+
]
|
|
27579
|
+
};
|
|
27580
|
+
}
|
|
27581
|
+
);
|
|
27582
|
+
}
|
|
27583
|
+
|
|
27584
|
+
// src/mcp/tools/support.ts
|
|
27585
|
+
import { z as z90 } from "zod";
|
|
27372
27586
|
|
|
27373
27587
|
// src/bin/exe-support.ts
|
|
27374
27588
|
init_config();
|
|
27375
27589
|
init_license();
|
|
27376
27590
|
import { mkdirSync as mkdirSync21, readFileSync as readFileSync32, unlinkSync as unlinkSync12, writeFileSync as writeFileSync23 } from "fs";
|
|
27377
|
-
import
|
|
27591
|
+
import path51 from "path";
|
|
27378
27592
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
27379
27593
|
var DEFAULT_BUG_ENDPOINT = "https://askexe.com/v1/support/bug-reports";
|
|
27380
27594
|
var DEFAULT_ADMIN_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
@@ -27495,8 +27709,8 @@ async function resolveEndpoints() {
|
|
|
27495
27709
|
return { bugEndpoint, healthEndpoint, adminEndpoint };
|
|
27496
27710
|
}
|
|
27497
27711
|
function checkLocalWrite() {
|
|
27498
|
-
const dir =
|
|
27499
|
-
const testPath =
|
|
27712
|
+
const dir = path51.join(EXE_AI_DIR, "bug-reports");
|
|
27713
|
+
const testPath = path51.join(dir, ".support-write-test");
|
|
27500
27714
|
try {
|
|
27501
27715
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
27502
27716
|
writeFileSync23(testPath, "ok\n", { mode: 384 });
|
|
@@ -27512,10 +27726,10 @@ function checkLocalWrite() {
|
|
|
27512
27726
|
}
|
|
27513
27727
|
}
|
|
27514
27728
|
function writeLocalTestReport(id, project, version) {
|
|
27515
|
-
const dir =
|
|
27729
|
+
const dir = path51.join(EXE_AI_DIR, "bug-reports");
|
|
27516
27730
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
27517
27731
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
27518
|
-
const filePath =
|
|
27732
|
+
const filePath = path51.join(dir, `${date}-support-intake-test-${id.slice(0, 8)}.md`);
|
|
27519
27733
|
writeFileSync23(filePath, `# TEST \u2014 ${project} support intake
|
|
27520
27734
|
|
|
27521
27735
|
Report ID: ${id}
|
|
@@ -27557,15 +27771,15 @@ async function maybeCloseAdmin(id, adminEndpoint, version) {
|
|
|
27557
27771
|
}
|
|
27558
27772
|
}
|
|
27559
27773
|
function readPackageVersion2() {
|
|
27560
|
-
let dir =
|
|
27774
|
+
let dir = path51.dirname(new URL(import.meta.url).pathname);
|
|
27561
27775
|
for (let i = 0; i < 6; i++) {
|
|
27562
|
-
const pkg =
|
|
27776
|
+
const pkg = path51.join(dir, "package.json");
|
|
27563
27777
|
try {
|
|
27564
27778
|
const parsed = JSON.parse(readFileSync32(pkg, "utf8"));
|
|
27565
27779
|
if (parsed.version) return parsed.version;
|
|
27566
27780
|
} catch {
|
|
27567
27781
|
}
|
|
27568
|
-
dir =
|
|
27782
|
+
dir = path51.dirname(dir);
|
|
27569
27783
|
}
|
|
27570
27784
|
return "unknown";
|
|
27571
27785
|
}
|
|
@@ -27632,7 +27846,7 @@ function registerSupportTools(server2) {
|
|
|
27632
27846
|
title: "Support Test",
|
|
27633
27847
|
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.",
|
|
27634
27848
|
inputSchema: {
|
|
27635
|
-
project:
|
|
27849
|
+
project: z90.string().default("support-smoke").describe("Customer/project name, e.g. hygo")
|
|
27636
27850
|
}
|
|
27637
27851
|
},
|
|
27638
27852
|
async ({ project }) => {
|
|
@@ -27650,8 +27864,8 @@ function registerSupportTools(server2) {
|
|
|
27650
27864
|
title: "My Bug Reports",
|
|
27651
27865
|
description: "List bug reports you've filed, scoped to your license. Shows status (open/triaged/fixed/closed), severity, and fixed_version so you know when to update.",
|
|
27652
27866
|
inputSchema: {
|
|
27653
|
-
status:
|
|
27654
|
-
limit:
|
|
27867
|
+
status: z90.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("all").describe("Filter by status. Default: all"),
|
|
27868
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
27655
27869
|
}
|
|
27656
27870
|
},
|
|
27657
27871
|
async ({ status: status2, limit }) => {
|
|
@@ -27707,12 +27921,76 @@ function registerSupportTools(server2) {
|
|
|
27707
27921
|
}
|
|
27708
27922
|
}
|
|
27709
27923
|
);
|
|
27924
|
+
server2.registerTool(
|
|
27925
|
+
"list_my_feature_requests",
|
|
27926
|
+
{
|
|
27927
|
+
title: "My Feature Requests",
|
|
27928
|
+
description: "List feature requests you've filed, scoped to your license. Shows status (open/planned/in_progress/shipped/closed), priority, and shipped_version so you know when to update.",
|
|
27929
|
+
inputSchema: {
|
|
27930
|
+
status: z90.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("all").describe("Filter by status. Default: all"),
|
|
27931
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
27932
|
+
}
|
|
27933
|
+
},
|
|
27934
|
+
async ({ status: status2, limit }) => {
|
|
27935
|
+
const licenseKey = loadLicense();
|
|
27936
|
+
const licenseToken = readCachedLicenseToken();
|
|
27937
|
+
if (!licenseKey && !licenseToken) {
|
|
27938
|
+
return {
|
|
27939
|
+
content: [{ type: "text", text: "No license key found. Run `exe-os setup` or `exe-os cloud setup` first." }],
|
|
27940
|
+
isError: true
|
|
27941
|
+
};
|
|
27942
|
+
}
|
|
27943
|
+
const endpoint2 = new URL("https://askexe.com/v1/support/my-feature-requests");
|
|
27944
|
+
endpoint2.searchParams.set("status", status2);
|
|
27945
|
+
endpoint2.searchParams.set("limit", String(limit));
|
|
27946
|
+
const headers = { "content-type": "application/json" };
|
|
27947
|
+
if (licenseKey) headers["x-exe-license-key"] = licenseKey;
|
|
27948
|
+
if (licenseToken) headers["x-exe-license-token"] = licenseToken;
|
|
27949
|
+
try {
|
|
27950
|
+
const res = await fetch(endpoint2.toString(), { method: "GET", headers, signal: AbortSignal.timeout(15e3) });
|
|
27951
|
+
if (!res.ok) {
|
|
27952
|
+
const body = await res.text().catch(() => "");
|
|
27953
|
+
return {
|
|
27954
|
+
content: [{ type: "text", text: `Failed to fetch feature requests: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}` }],
|
|
27955
|
+
isError: true
|
|
27956
|
+
};
|
|
27957
|
+
}
|
|
27958
|
+
const data = await res.json();
|
|
27959
|
+
if (data.count === 0) {
|
|
27960
|
+
return {
|
|
27961
|
+
content: [{ type: "text", text: `No feature requests found${status2 !== "all" ? ` with status '${status2}'` : ""}.` }],
|
|
27962
|
+
structuredContent: { items: [], count: 0 }
|
|
27963
|
+
};
|
|
27964
|
+
}
|
|
27965
|
+
const lines = [`Feature requests (${data.count}):`, ""];
|
|
27966
|
+
for (const r of data.items) {
|
|
27967
|
+
const priIcon = r.priority === "p0" ? "\u{1F534}" : r.priority === "p1" ? "\u{1F534}" : r.priority === "p2" ? "\u{1F7E0}" : "\u{1F7E2}";
|
|
27968
|
+
const statusIcon = r.status === "shipped" ? "\u2705" : r.status === "closed" ? "\u2611\uFE0F" : r.status === "planned" ? "\u{1F4CB}" : r.status === "in_progress" ? "\u{1F528}" : r.status === "wontdo" ? "\u26D4" : "\u{1F535}";
|
|
27969
|
+
lines.push(`${priIcon} ${r.priority.toUpperCase()} ${statusIcon} ${r.status} \u2014 ${r.title}`);
|
|
27970
|
+
lines.push(` ID: ${r.id} | Filed: ${r.created_at?.slice(0, 10) ?? "?"}`);
|
|
27971
|
+
if (r.shipped_version) lines.push(` \u{1F680} Shipped in: ${r.shipped_version} \u2014 run \`exe-os update\` to get this feature`);
|
|
27972
|
+
if (r.target_version) lines.push(` \u{1F3AF} Target: ${r.target_version}`);
|
|
27973
|
+
if (r.response_notes) lines.push(` \u{1F4DD} AskExe: ${r.response_notes}`);
|
|
27974
|
+
lines.push("");
|
|
27975
|
+
}
|
|
27976
|
+
return {
|
|
27977
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
27978
|
+
structuredContent: data
|
|
27979
|
+
};
|
|
27980
|
+
} catch (err) {
|
|
27981
|
+
return {
|
|
27982
|
+
content: [{ type: "text", text: `Error fetching feature requests: ${err instanceof Error ? err.message : String(err)}` }],
|
|
27983
|
+
isError: true
|
|
27984
|
+
};
|
|
27985
|
+
}
|
|
27986
|
+
}
|
|
27987
|
+
);
|
|
27710
27988
|
}
|
|
27711
27989
|
|
|
27712
27990
|
// src/mcp/tools/cli-parity.ts
|
|
27713
27991
|
import { execFile as execFile2 } from "child_process";
|
|
27714
27992
|
import { promisify as promisify2 } from "util";
|
|
27715
|
-
import { z as
|
|
27993
|
+
import { z as z91 } from "zod";
|
|
27716
27994
|
|
|
27717
27995
|
// src/bin/exe-status.ts
|
|
27718
27996
|
init_employees();
|
|
@@ -27773,22 +28051,22 @@ if (isMainModule(import.meta.url)) {
|
|
|
27773
28051
|
|
|
27774
28052
|
// src/bin/exe-healthcheck.ts
|
|
27775
28053
|
import { existsSync as existsSync39, readFileSync as readFileSync33, readdirSync as readdirSync14 } from "fs";
|
|
27776
|
-
import
|
|
28054
|
+
import path52 from "path";
|
|
27777
28055
|
import { execSync as execSync14 } from "child_process";
|
|
27778
28056
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
27779
28057
|
init_config();
|
|
27780
28058
|
function findPackageRoot2() {
|
|
27781
|
-
let dir =
|
|
27782
|
-
const { root } =
|
|
28059
|
+
let dir = path52.dirname(fileURLToPath6(import.meta.url));
|
|
28060
|
+
const { root } = path52.parse(dir);
|
|
27783
28061
|
while (dir !== root) {
|
|
27784
|
-
if (existsSync39(
|
|
27785
|
-
dir =
|
|
28062
|
+
if (existsSync39(path52.join(dir, "package.json"))) return dir;
|
|
28063
|
+
dir = path52.dirname(dir);
|
|
27786
28064
|
}
|
|
27787
28065
|
throw new Error("Cannot find package root");
|
|
27788
28066
|
}
|
|
27789
28067
|
function checkBuildIntegrity(pkgRoot) {
|
|
27790
28068
|
const results = [];
|
|
27791
|
-
const tsupConfig =
|
|
28069
|
+
const tsupConfig = path52.join(pkgRoot, "tsup.config.ts");
|
|
27792
28070
|
if (!existsSync39(tsupConfig)) {
|
|
27793
28071
|
return [{ name: "build/tsup-config", pass: false, detail: "tsup.config.ts not found" }];
|
|
27794
28072
|
}
|
|
@@ -27798,7 +28076,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
27798
28076
|
let total = 0;
|
|
27799
28077
|
for (const match of entryMatches) {
|
|
27800
28078
|
const outputKey = match[1];
|
|
27801
|
-
const expectedPath =
|
|
28079
|
+
const expectedPath = path52.join(pkgRoot, "dist", `${outputKey}.js`);
|
|
27802
28080
|
total++;
|
|
27803
28081
|
if (!existsSync39(expectedPath)) {
|
|
27804
28082
|
missing.push(`dist/${outputKey}.js`);
|
|
@@ -27822,7 +28100,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
27822
28100
|
}
|
|
27823
28101
|
function checkEmbedPipeline(pkgRoot) {
|
|
27824
28102
|
const results = [];
|
|
27825
|
-
const daemonPath =
|
|
28103
|
+
const daemonPath = path52.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
27826
28104
|
if (!existsSync39(daemonPath)) {
|
|
27827
28105
|
results.push({
|
|
27828
28106
|
name: "exed/daemon-exists",
|
|
@@ -27834,17 +28112,17 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
27834
28112
|
results.push({ name: "exed/daemon-exists", pass: true, detail: "dist/lib/exe-daemon.js exists" });
|
|
27835
28113
|
const entryDirs = ["dist/hooks", "dist/bin", "dist/mcp"];
|
|
27836
28114
|
for (const dir of entryDirs) {
|
|
27837
|
-
const fullDir =
|
|
28115
|
+
const fullDir = path52.join(pkgRoot, dir);
|
|
27838
28116
|
if (!existsSync39(fullDir)) continue;
|
|
27839
28117
|
let walkDir = fullDir;
|
|
27840
|
-
const { root } =
|
|
28118
|
+
const { root } = path52.parse(walkDir);
|
|
27841
28119
|
let foundRoot = null;
|
|
27842
28120
|
while (walkDir !== root) {
|
|
27843
|
-
if (existsSync39(
|
|
28121
|
+
if (existsSync39(path52.join(walkDir, "package.json"))) {
|
|
27844
28122
|
foundRoot = walkDir;
|
|
27845
28123
|
break;
|
|
27846
28124
|
}
|
|
27847
|
-
walkDir =
|
|
28125
|
+
walkDir = path52.dirname(walkDir);
|
|
27848
28126
|
}
|
|
27849
28127
|
if (!foundRoot) {
|
|
27850
28128
|
results.push({
|
|
@@ -27854,7 +28132,7 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
27854
28132
|
});
|
|
27855
28133
|
continue;
|
|
27856
28134
|
}
|
|
27857
|
-
const resolvedDaemon =
|
|
28135
|
+
const resolvedDaemon = path52.join(foundRoot, "dist", "lib", "exe-daemon.js");
|
|
27858
28136
|
const reachable = existsSync39(resolvedDaemon);
|
|
27859
28137
|
results.push({
|
|
27860
28138
|
name: `exed/reachable-from-${dir}`,
|
|
@@ -27866,7 +28144,7 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
27866
28144
|
}
|
|
27867
28145
|
function checkTaskSystem(pkgRoot) {
|
|
27868
28146
|
const results = [];
|
|
27869
|
-
const scannerPath =
|
|
28147
|
+
const scannerPath = path52.join(pkgRoot, "dist", "bin", "scan-tasks.js");
|
|
27870
28148
|
if (!existsSync39(scannerPath)) {
|
|
27871
28149
|
results.push({ name: "tasks/scanner", pass: false, detail: "scan-tasks.js not found" });
|
|
27872
28150
|
return results;
|
|
@@ -27889,7 +28167,7 @@ function checkTaskSystem(pkgRoot) {
|
|
|
27889
28167
|
}
|
|
27890
28168
|
function checkWorkerSpawning(pkgRoot) {
|
|
27891
28169
|
const results = [];
|
|
27892
|
-
const workerPath =
|
|
28170
|
+
const workerPath = path52.join(pkgRoot, "dist", "hooks", "ingest-worker.js");
|
|
27893
28171
|
if (!existsSync39(workerPath)) {
|
|
27894
28172
|
results.push({ name: "workers/ingest-worker", pass: false, detail: "ingest-worker.js not found" });
|
|
27895
28173
|
return results;
|
|
@@ -27904,14 +28182,14 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
27904
28182
|
detail: `Parse error: ${err instanceof Error ? err.message.slice(0, 200) : String(err)}`
|
|
27905
28183
|
});
|
|
27906
28184
|
}
|
|
27907
|
-
const hooksDir =
|
|
28185
|
+
const hooksDir = path52.join(pkgRoot, "dist", "hooks");
|
|
27908
28186
|
if (existsSync39(hooksDir)) {
|
|
27909
28187
|
const hookFiles = readdirSync14(hooksDir).filter((f) => f.endsWith(".js") && !f.endsWith(".js.map"));
|
|
27910
28188
|
let hooksPassed = 0;
|
|
27911
28189
|
const hooksFailed = [];
|
|
27912
28190
|
for (const hook of hookFiles) {
|
|
27913
28191
|
try {
|
|
27914
|
-
execSync14(`node --check "${
|
|
28192
|
+
execSync14(`node --check "${path52.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
27915
28193
|
hooksPassed++;
|
|
27916
28194
|
} catch {
|
|
27917
28195
|
hooksFailed.push(hook);
|
|
@@ -27935,8 +28213,8 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
27935
28213
|
}
|
|
27936
28214
|
function checkMcpTransport() {
|
|
27937
28215
|
const results = [];
|
|
27938
|
-
const pidPath =
|
|
27939
|
-
const tokenPath =
|
|
28216
|
+
const pidPath = path52.join(EXE_AI_DIR, "exed.pid");
|
|
28217
|
+
const tokenPath = path52.join(EXE_AI_DIR, "exed.token");
|
|
27940
28218
|
let daemonAlive = false;
|
|
27941
28219
|
if (existsSync39(pidPath)) {
|
|
27942
28220
|
try {
|
|
@@ -27983,7 +28261,7 @@ function checkMcpTransport() {
|
|
|
27983
28261
|
results.push({
|
|
27984
28262
|
name: "mcp/monitor-summary",
|
|
27985
28263
|
pass: true,
|
|
27986
|
-
detail: `Privacy-safe local monitor summary: ${
|
|
28264
|
+
detail: `Privacy-safe local monitor summary: ${path52.join(EXE_AI_DIR, "monitor", "mcp-transport-summary.json")}`
|
|
27987
28265
|
});
|
|
27988
28266
|
return results;
|
|
27989
28267
|
}
|
|
@@ -28041,7 +28319,7 @@ function checkClaudeCodeInstall() {
|
|
|
28041
28319
|
detail: "Failed to check claude binary path"
|
|
28042
28320
|
});
|
|
28043
28321
|
}
|
|
28044
|
-
const versionsDir =
|
|
28322
|
+
const versionsDir = path52.join(
|
|
28045
28323
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
28046
28324
|
".local",
|
|
28047
28325
|
"share",
|
|
@@ -28148,9 +28426,9 @@ if (isMainModule(import.meta.url)) {
|
|
|
28148
28426
|
// src/lib/update-check.ts
|
|
28149
28427
|
import { execSync as execSync15 } from "child_process";
|
|
28150
28428
|
import { readFileSync as readFileSync34 } from "fs";
|
|
28151
|
-
import
|
|
28429
|
+
import path53 from "path";
|
|
28152
28430
|
function getLocalVersion(packageRoot) {
|
|
28153
|
-
const pkgPath =
|
|
28431
|
+
const pkgPath = path53.join(packageRoot, "package.json");
|
|
28154
28432
|
const pkg = JSON.parse(readFileSync34(pkgPath, "utf-8"));
|
|
28155
28433
|
return pkg.version;
|
|
28156
28434
|
}
|
|
@@ -28218,12 +28496,12 @@ function registerCliParityTools(server2) {
|
|
|
28218
28496
|
title: "Doctor",
|
|
28219
28497
|
description: "Run exe-os doctor audit. Defaults to read-only diagnostics; optional dry-run/fix flags mirror CLI.",
|
|
28220
28498
|
inputSchema: {
|
|
28221
|
-
agent:
|
|
28222
|
-
project:
|
|
28223
|
-
verbose:
|
|
28224
|
-
conflicts:
|
|
28225
|
-
dry_run:
|
|
28226
|
-
fix:
|
|
28499
|
+
agent: z91.string().optional(),
|
|
28500
|
+
project: z91.string().optional(),
|
|
28501
|
+
verbose: z91.boolean().default(false),
|
|
28502
|
+
conflicts: z91.boolean().default(false),
|
|
28503
|
+
dry_run: z91.boolean().default(false),
|
|
28504
|
+
fix: z91.boolean().default(false)
|
|
28227
28505
|
}
|
|
28228
28506
|
}, async ({ agent, project, verbose, conflicts, dry_run, fix }) => {
|
|
28229
28507
|
const args = [];
|
|
@@ -28240,9 +28518,9 @@ function registerCliParityTools(server2) {
|
|
|
28240
28518
|
title: "Rename Employee",
|
|
28241
28519
|
description: "Rename an employee using the same path as `exe-os rename <old> <new>`. Use for customer roster/identity renames.",
|
|
28242
28520
|
inputSchema: {
|
|
28243
|
-
old_name:
|
|
28244
|
-
new_name:
|
|
28245
|
-
dry_run:
|
|
28521
|
+
old_name: z91.string().min(1),
|
|
28522
|
+
new_name: z91.string().min(1),
|
|
28523
|
+
dry_run: z91.boolean().default(false)
|
|
28246
28524
|
}
|
|
28247
28525
|
}, async ({ old_name, new_name, dry_run }) => {
|
|
28248
28526
|
if (dry_run) {
|
|
@@ -28255,7 +28533,7 @@ function registerCliParityTools(server2) {
|
|
|
28255
28533
|
server2.registerTool("status_brief", {
|
|
28256
28534
|
title: "Status Brief",
|
|
28257
28535
|
description: "Return current employee/tmux status. Mirrors `exe-status` and supports optional deep view for one employee.",
|
|
28258
|
-
inputSchema: { employee:
|
|
28536
|
+
inputSchema: { employee: z91.string().optional() }
|
|
28259
28537
|
}, async ({ employee }) => {
|
|
28260
28538
|
const text3 = await status(employee);
|
|
28261
28539
|
return result2(text3, { ok: true, employee: employee ?? null });
|
|
@@ -28263,7 +28541,7 @@ function registerCliParityTools(server2) {
|
|
|
28263
28541
|
server2.registerTool("pending_work_summary", {
|
|
28264
28542
|
title: "Pending Work Summary",
|
|
28265
28543
|
description: "Return pending reviews, messages, and notifications using the same summaries as the CLI tools.",
|
|
28266
|
-
inputSchema: { agent:
|
|
28544
|
+
inputSchema: { agent: z91.string().optional() }
|
|
28267
28545
|
}, async ({ agent }) => {
|
|
28268
28546
|
const parts = await Promise.all([
|
|
28269
28547
|
runCommand("exe-pending-reviews", [], 3e4),
|
|
@@ -28284,7 +28562,7 @@ function registerCliParityTools(server2) {
|
|
|
28284
28562
|
server2.registerTool("key_rotation_preflight", {
|
|
28285
28563
|
title: "Key Rotation Preflight",
|
|
28286
28564
|
description: "Dry-run key rotation/update preflight. No destructive changes.",
|
|
28287
|
-
inputSchema: { mode:
|
|
28565
|
+
inputSchema: { mode: z91.enum(["rotate", "update"]).default("rotate") }
|
|
28288
28566
|
}, async ({ mode }) => {
|
|
28289
28567
|
const out = await runCommand("exe-os", ["key", mode, "--dry-run"], 6e4);
|
|
28290
28568
|
return result2(out.text, { ok: out.ok, command: out.command, mode }, !out.ok);
|
|
@@ -28303,11 +28581,11 @@ function registerCliParityTools(server2) {
|
|
|
28303
28581
|
title: "Stack Update Check",
|
|
28304
28582
|
description: "Plan/check a customer stack update without applying Docker changes. Mirrors `exe-os stack-update --check`.",
|
|
28305
28583
|
inputSchema: {
|
|
28306
|
-
target:
|
|
28307
|
-
manifest:
|
|
28308
|
-
compose_file:
|
|
28309
|
-
env_file:
|
|
28310
|
-
deployment_persona:
|
|
28584
|
+
target: z91.string().optional(),
|
|
28585
|
+
manifest: z91.string().optional(),
|
|
28586
|
+
compose_file: z91.string().optional(),
|
|
28587
|
+
env_file: z91.string().optional(),
|
|
28588
|
+
deployment_persona: z91.enum(["customer", "askexe-control-plane"]).default("customer")
|
|
28311
28589
|
}
|
|
28312
28590
|
}, async ({ target, manifest, compose_file, env_file, deployment_persona }) => {
|
|
28313
28591
|
const args = ["stack-update", "--check", "--deployment-persona", deployment_persona];
|
|
@@ -28331,7 +28609,7 @@ function registerCliParityTools(server2) {
|
|
|
28331
28609
|
// src/mcp/tools/get-session-events.ts
|
|
28332
28610
|
init_active_agent();
|
|
28333
28611
|
init_fast_db_init();
|
|
28334
|
-
import { z as
|
|
28612
|
+
import { z as z92 } from "zod";
|
|
28335
28613
|
|
|
28336
28614
|
// src/lib/session-events.ts
|
|
28337
28615
|
init_task_scope();
|
|
@@ -28418,7 +28696,7 @@ async function listRecentSessionEvents(client, options) {
|
|
|
28418
28696
|
}
|
|
28419
28697
|
|
|
28420
28698
|
// src/mcp/tools/get-session-events.ts
|
|
28421
|
-
var EVENT_TYPE =
|
|
28699
|
+
var EVENT_TYPE = z92.enum([
|
|
28422
28700
|
"user_prompt",
|
|
28423
28701
|
"assistant_response",
|
|
28424
28702
|
"tool_call",
|
|
@@ -28448,11 +28726,11 @@ function registerGetSessionEvents(server2) {
|
|
|
28448
28726
|
title: "Get Session Events",
|
|
28449
28727
|
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.",
|
|
28450
28728
|
inputSchema: {
|
|
28451
|
-
agent_id:
|
|
28452
|
-
session_id:
|
|
28729
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
28730
|
+
session_id: z92.string().optional().describe("Optional exact runtime session id."),
|
|
28453
28731
|
event_type: EVENT_TYPE.optional().describe("Filter to one event type."),
|
|
28454
|
-
project_name:
|
|
28455
|
-
limit:
|
|
28732
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects."),
|
|
28733
|
+
limit: z92.number().int().min(1).max(100).default(20).describe("Number of events to return.")
|
|
28456
28734
|
}
|
|
28457
28735
|
},
|
|
28458
28736
|
async ({ agent_id, session_id, event_type, project_name, limit }) => {
|
|
@@ -28488,8 +28766,8 @@ function registerGetLastAssistantResponse(server2) {
|
|
|
28488
28766
|
title: "Get Last Assistant Response",
|
|
28489
28767
|
description: "Return the exact last assistant response for an agent from the session event journal. Use for 'what was the last thing you said?'",
|
|
28490
28768
|
inputSchema: {
|
|
28491
|
-
agent_id:
|
|
28492
|
-
project_name:
|
|
28769
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
28770
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects.")
|
|
28493
28771
|
}
|
|
28494
28772
|
},
|
|
28495
28773
|
async ({ agent_id, project_name }) => {
|
|
@@ -28519,32 +28797,106 @@ function registerGetLastAssistantResponse(server2) {
|
|
|
28519
28797
|
}
|
|
28520
28798
|
|
|
28521
28799
|
// src/mcp/tools/code-context.ts
|
|
28522
|
-
import { z as
|
|
28800
|
+
import { z as z93 } from "zod";
|
|
28523
28801
|
|
|
28524
28802
|
// src/lib/code-context-index.ts
|
|
28525
28803
|
init_config();
|
|
28526
|
-
import
|
|
28527
|
-
import
|
|
28804
|
+
import crypto20 from "crypto";
|
|
28805
|
+
import path54 from "path";
|
|
28528
28806
|
import { existsSync as existsSync40, mkdirSync as mkdirSync22, readFileSync as readFileSync35, readdirSync as readdirSync15, statSync as statSync9, writeFileSync as writeFileSync24 } from "fs";
|
|
28529
28807
|
import { spawnSync } from "child_process";
|
|
28808
|
+
init_exe_daemon_client();
|
|
28809
|
+
var VECTOR_STORE_VERSION = 1;
|
|
28810
|
+
var EMBED_BATCH_SIZE = 64;
|
|
28811
|
+
function vectorStorePath(projectRoot) {
|
|
28812
|
+
const rootHash = hashText(projectRoot).slice(0, 16);
|
|
28813
|
+
return path54.join(indexDir(), `${rootHash}.vectors.json`);
|
|
28814
|
+
}
|
|
28815
|
+
function loadVectorStore(projectRoot) {
|
|
28816
|
+
const file = vectorStorePath(projectRoot);
|
|
28817
|
+
if (!existsSync40(file)) return null;
|
|
28818
|
+
try {
|
|
28819
|
+
const parsed = JSON.parse(readFileSync35(file, "utf8"));
|
|
28820
|
+
if (parsed.version !== VECTOR_STORE_VERSION) return null;
|
|
28821
|
+
return parsed;
|
|
28822
|
+
} catch {
|
|
28823
|
+
return null;
|
|
28824
|
+
}
|
|
28825
|
+
}
|
|
28826
|
+
function saveVectorStore(projectRoot, store) {
|
|
28827
|
+
writeFileSync24(vectorStorePath(projectRoot), JSON.stringify(store));
|
|
28828
|
+
}
|
|
28829
|
+
function cosineSimilarity3(a, b) {
|
|
28830
|
+
let dot = 0, normA = 0, normB = 0;
|
|
28831
|
+
for (let i = 0; i < a.length; i++) {
|
|
28832
|
+
dot += a[i] * b[i];
|
|
28833
|
+
normA += a[i] * a[i];
|
|
28834
|
+
normB += b[i] * b[i];
|
|
28835
|
+
}
|
|
28836
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
28837
|
+
return denom === 0 ? 0 : dot / denom;
|
|
28838
|
+
}
|
|
28839
|
+
async function embedSymbols(index) {
|
|
28840
|
+
const rootHash = hashText(index.projectRoot).slice(0, 16);
|
|
28841
|
+
const existing = loadVectorStore(index.projectRoot);
|
|
28842
|
+
const store = {
|
|
28843
|
+
version: VECTOR_STORE_VERSION,
|
|
28844
|
+
projectRootHash: rootHash,
|
|
28845
|
+
vectors: {}
|
|
28846
|
+
};
|
|
28847
|
+
const allSymbols = [];
|
|
28848
|
+
for (const file of Object.values(index.files)) {
|
|
28849
|
+
for (const symbol of file.symbols) {
|
|
28850
|
+
if (existing?.vectors[symbol.id]) {
|
|
28851
|
+
store.vectors[symbol.id] = existing.vectors[symbol.id];
|
|
28852
|
+
} else {
|
|
28853
|
+
allSymbols.push({ id: symbol.id, text: symbol.summary || `${symbol.kind} ${symbol.name} in ${symbol.filePath}` });
|
|
28854
|
+
}
|
|
28855
|
+
}
|
|
28856
|
+
}
|
|
28857
|
+
if (allSymbols.length === 0) {
|
|
28858
|
+
saveVectorStore(index.projectRoot, store);
|
|
28859
|
+
return store;
|
|
28860
|
+
}
|
|
28861
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
28862
|
+
if (!connected) {
|
|
28863
|
+
saveVectorStore(index.projectRoot, store);
|
|
28864
|
+
return store;
|
|
28865
|
+
}
|
|
28866
|
+
for (let i = 0; i < allSymbols.length; i += EMBED_BATCH_SIZE) {
|
|
28867
|
+
const batch = allSymbols.slice(i, i + EMBED_BATCH_SIZE);
|
|
28868
|
+
const texts = batch.map((s) => s.text);
|
|
28869
|
+
try {
|
|
28870
|
+
const vectors = await embedBatchViaClient(texts, "low");
|
|
28871
|
+
if (vectors && vectors.length === batch.length) {
|
|
28872
|
+
for (let j = 0; j < batch.length; j++) {
|
|
28873
|
+
store.vectors[batch[j].id] = vectors[j];
|
|
28874
|
+
}
|
|
28875
|
+
}
|
|
28876
|
+
} catch {
|
|
28877
|
+
}
|
|
28878
|
+
}
|
|
28879
|
+
saveVectorStore(index.projectRoot, store);
|
|
28880
|
+
return store;
|
|
28881
|
+
}
|
|
28530
28882
|
var INDEX_VERSION = 2;
|
|
28531
28883
|
var DEFAULT_MAX_FILES = 5e3;
|
|
28532
28884
|
var IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
28533
28885
|
function normalizeProjectRoot(projectRoot) {
|
|
28534
|
-
return
|
|
28886
|
+
return path54.resolve(projectRoot || process.cwd());
|
|
28535
28887
|
}
|
|
28536
28888
|
function hashText(text3) {
|
|
28537
|
-
return
|
|
28889
|
+
return crypto20.createHash("sha256").update(text3).digest("hex");
|
|
28538
28890
|
}
|
|
28539
28891
|
function indexDir() {
|
|
28540
|
-
const dir =
|
|
28892
|
+
const dir = path54.join(EXE_AI_DIR, "code-context");
|
|
28541
28893
|
mkdirSync22(dir, { recursive: true });
|
|
28542
28894
|
return dir;
|
|
28543
28895
|
}
|
|
28544
28896
|
function getCodeContextIndexPath(projectRoot) {
|
|
28545
28897
|
const root = normalizeProjectRoot(projectRoot);
|
|
28546
28898
|
const rootHash = hashText(root).slice(0, 16);
|
|
28547
|
-
return
|
|
28899
|
+
return path54.join(indexDir(), `${rootHash}.json`);
|
|
28548
28900
|
}
|
|
28549
28901
|
function currentBranch(projectRoot) {
|
|
28550
28902
|
const result3 = spawnSync("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
@@ -28557,8 +28909,8 @@ function shouldIgnore(relPath) {
|
|
|
28557
28909
|
}
|
|
28558
28910
|
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
28559
28911
|
for (const entry of readdirSync15(dir, { withFileTypes: true })) {
|
|
28560
|
-
const abs =
|
|
28561
|
-
const rel =
|
|
28912
|
+
const abs = path54.join(dir, entry.name);
|
|
28913
|
+
const rel = path54.relative(projectRoot, abs).replaceAll(path54.sep, "/");
|
|
28562
28914
|
if (shouldIgnore(rel)) continue;
|
|
28563
28915
|
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
28564
28916
|
else if (entry.isFile()) out.push(rel);
|
|
@@ -28574,7 +28926,7 @@ function listCodeFiles(projectRoot, maxFiles) {
|
|
|
28574
28926
|
const rg = spawnSync("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
28575
28927
|
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
28576
28928
|
}
|
|
28577
|
-
return files.map((file) => file.replaceAll(
|
|
28929
|
+
return files.map((file) => file.replaceAll(path54.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
28578
28930
|
}
|
|
28579
28931
|
function parseImportPaths(importText) {
|
|
28580
28932
|
const paths = [];
|
|
@@ -28587,13 +28939,13 @@ function parseImportPaths(importText) {
|
|
|
28587
28939
|
}
|
|
28588
28940
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
28589
28941
|
if (!importPath.startsWith(".")) return null;
|
|
28590
|
-
const base =
|
|
28942
|
+
const base = path54.posix.normalize(path54.posix.join(path54.posix.dirname(fromFile.replaceAll(path54.sep, "/")), importPath));
|
|
28591
28943
|
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
28592
28944
|
const candidates = [base];
|
|
28593
28945
|
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"]) {
|
|
28594
28946
|
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
28595
28947
|
}
|
|
28596
|
-
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(
|
|
28948
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path54.posix.join(base, indexName));
|
|
28597
28949
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
28598
28950
|
}
|
|
28599
28951
|
function symbolId(filePath, chunk) {
|
|
@@ -28614,7 +28966,7 @@ function saveIndex(index) {
|
|
|
28614
28966
|
writeFileSync24(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
|
|
28615
28967
|
}
|
|
28616
28968
|
function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
28617
|
-
const absPath =
|
|
28969
|
+
const absPath = path54.join(projectRoot, relPath);
|
|
28618
28970
|
let stat;
|
|
28619
28971
|
try {
|
|
28620
28972
|
stat = statSync9(absPath);
|
|
@@ -28652,13 +29004,13 @@ function buildCodeContextIndex(options = {}) {
|
|
|
28652
29004
|
const branch = currentBranch(projectRoot);
|
|
28653
29005
|
const previous = options.force ? null : loadIndex(projectRoot);
|
|
28654
29006
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
28655
|
-
const allFiles = new Set(files.map((file) => file.replaceAll(
|
|
29007
|
+
const allFiles = new Set(files.map((file) => file.replaceAll(path54.sep, "/")));
|
|
28656
29008
|
const fileRecords = {};
|
|
28657
29009
|
let rebuiltFiles = 0;
|
|
28658
29010
|
let reusedFiles = 0;
|
|
28659
29011
|
let skippedFiles = 0;
|
|
28660
29012
|
for (const rel of files) {
|
|
28661
|
-
const normalized = rel.replaceAll(
|
|
29013
|
+
const normalized = rel.replaceAll(path54.sep, "/");
|
|
28662
29014
|
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
28663
29015
|
if (record) {
|
|
28664
29016
|
fileRecords[normalized] = record;
|
|
@@ -28687,11 +29039,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
28687
29039
|
if (loaded) {
|
|
28688
29040
|
const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
|
|
28689
29041
|
const unchanged = currentFiles.every((rel) => {
|
|
28690
|
-
const normalized = rel.replaceAll(
|
|
29042
|
+
const normalized = rel.replaceAll(path54.sep, "/");
|
|
28691
29043
|
const existing = loaded.files[normalized];
|
|
28692
29044
|
if (!existing) return false;
|
|
28693
29045
|
try {
|
|
28694
|
-
const stat = statSync9(
|
|
29046
|
+
const stat = statSync9(path54.join(projectRoot, normalized));
|
|
28695
29047
|
return stat.mtimeMs === existing.mtimeMs && stat.size === existing.size;
|
|
28696
29048
|
} catch {
|
|
28697
29049
|
return false;
|
|
@@ -28744,9 +29096,9 @@ function globToRegex(pattern) {
|
|
|
28744
29096
|
}
|
|
28745
29097
|
function matchesPath(filePath, patterns) {
|
|
28746
29098
|
if (!patterns || patterns.length === 0) return true;
|
|
28747
|
-
const normalized = filePath.replaceAll(
|
|
29099
|
+
const normalized = filePath.replaceAll(path54.sep, "/");
|
|
28748
29100
|
return patterns.some((pattern) => {
|
|
28749
|
-
const p = pattern.replaceAll(
|
|
29101
|
+
const p = pattern.replaceAll(path54.sep, "/").replace(/^\.\//, "");
|
|
28750
29102
|
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
28751
29103
|
});
|
|
28752
29104
|
}
|
|
@@ -28805,7 +29157,7 @@ function filteredFiles(index, options = {}) {
|
|
|
28805
29157
|
return matchesPath(file.path, options.paths);
|
|
28806
29158
|
});
|
|
28807
29159
|
}
|
|
28808
|
-
function
|
|
29160
|
+
function lexicalSearch(query, options = {}) {
|
|
28809
29161
|
const terms = tokenize(query);
|
|
28810
29162
|
if (terms.length === 0) return [];
|
|
28811
29163
|
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
@@ -28831,6 +29183,82 @@ function searchCodeContext(query, options = {}) {
|
|
|
28831
29183
|
const limit = options.limit ?? 20;
|
|
28832
29184
|
return results.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
28833
29185
|
}
|
|
29186
|
+
function searchCodeContext(query, options = {}) {
|
|
29187
|
+
return lexicalSearch(query, options);
|
|
29188
|
+
}
|
|
29189
|
+
var RRF_K2 = 60;
|
|
29190
|
+
async function searchCodeContextSemantic(query, options = {}) {
|
|
29191
|
+
const terms = tokenize(query);
|
|
29192
|
+
if (terms.length === 0) return [];
|
|
29193
|
+
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
29194
|
+
const projectRoot = normalizeProjectRoot(options.projectRoot);
|
|
29195
|
+
const vectorStore = loadVectorStore(projectRoot);
|
|
29196
|
+
if (!vectorStore || Object.keys(vectorStore.vectors).length === 0) {
|
|
29197
|
+
return lexicalSearch(query, options);
|
|
29198
|
+
}
|
|
29199
|
+
let queryVector = null;
|
|
29200
|
+
try {
|
|
29201
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
29202
|
+
if (connected) {
|
|
29203
|
+
const result3 = await embedBatchViaClient([query], "high");
|
|
29204
|
+
if (result3 && result3.length === 1) queryVector = result3[0];
|
|
29205
|
+
}
|
|
29206
|
+
} catch {
|
|
29207
|
+
}
|
|
29208
|
+
if (!queryVector) return lexicalSearch(query, options);
|
|
29209
|
+
const files = filteredFiles(index, options);
|
|
29210
|
+
const candidates = [];
|
|
29211
|
+
for (const file of files) {
|
|
29212
|
+
for (const symbol of file.symbols) {
|
|
29213
|
+
const lexical = scoreSymbol(symbol, terms);
|
|
29214
|
+
const vec = vectorStore.vectors[symbol.id];
|
|
29215
|
+
const vectorScore = vec ? cosineSimilarity3(queryVector, vec) : 0;
|
|
29216
|
+
if (lexical.score > 0 || vectorScore > 0.3) {
|
|
29217
|
+
candidates.push({
|
|
29218
|
+
symbol,
|
|
29219
|
+
lexicalScore: lexical.score,
|
|
29220
|
+
vectorScore,
|
|
29221
|
+
matches: lexical.matches
|
|
29222
|
+
});
|
|
29223
|
+
}
|
|
29224
|
+
}
|
|
29225
|
+
}
|
|
29226
|
+
const byLexical = [...candidates].sort((a, b) => b.lexicalScore - a.lexicalScore);
|
|
29227
|
+
const byVector = [...candidates].sort((a, b) => b.vectorScore - a.vectorScore);
|
|
29228
|
+
const lexicalRank = /* @__PURE__ */ new Map();
|
|
29229
|
+
const vectorRank = /* @__PURE__ */ new Map();
|
|
29230
|
+
byLexical.forEach((c, i) => lexicalRank.set(c.symbol.id, i + 1));
|
|
29231
|
+
byVector.forEach((c, i) => vectorRank.set(c.symbol.id, i + 1));
|
|
29232
|
+
const VECTOR_WEIGHT = 0.6;
|
|
29233
|
+
const LEXICAL_WEIGHT = 0.4;
|
|
29234
|
+
const fused = candidates.map((c) => {
|
|
29235
|
+
const lRank = lexicalRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
29236
|
+
const vRank = vectorRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
29237
|
+
const rrfScore = VECTOR_WEIGHT * (1 / (RRF_K2 + vRank)) + LEXICAL_WEIGHT * (1 / (RRF_K2 + lRank));
|
|
29238
|
+
return {
|
|
29239
|
+
symbol: c.symbol,
|
|
29240
|
+
score: rrfScore,
|
|
29241
|
+
matches: c.vectorScore > 0.3 ? [...c.matches, `semantic=${c.vectorScore.toFixed(3)}`] : c.matches,
|
|
29242
|
+
filePath: c.symbol.filePath,
|
|
29243
|
+
language: c.symbol.language,
|
|
29244
|
+
content: c.symbol.text,
|
|
29245
|
+
startLine: c.symbol.startLine,
|
|
29246
|
+
endLine: c.symbol.endLine
|
|
29247
|
+
};
|
|
29248
|
+
});
|
|
29249
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
29250
|
+
const limit = options.limit ?? 20;
|
|
29251
|
+
return fused.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
29252
|
+
}
|
|
29253
|
+
async function buildCodeContextIndexWithEmbeddings(options = {}) {
|
|
29254
|
+
const index = buildCodeContextIndex(options);
|
|
29255
|
+
const existingStore = loadVectorStore(index.projectRoot);
|
|
29256
|
+
const existingCount = existingStore ? Object.keys(existingStore.vectors).length : 0;
|
|
29257
|
+
const store = await embedSymbols(index);
|
|
29258
|
+
const vectorCount = Object.keys(store.vectors).length;
|
|
29259
|
+
const newEmbeddings = vectorCount - Math.min(existingCount, vectorCount);
|
|
29260
|
+
return { index, vectorCount, newEmbeddings };
|
|
29261
|
+
}
|
|
28834
29262
|
function dependentsMap(index) {
|
|
28835
29263
|
const map = /* @__PURE__ */ new Map();
|
|
28836
29264
|
for (const file of Object.values(index.files)) {
|
|
@@ -28864,7 +29292,7 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
28864
29292
|
}
|
|
28865
29293
|
function resolveTargetFile(index, input) {
|
|
28866
29294
|
if (input.filePath) {
|
|
28867
|
-
const normalized = input.filePath.replaceAll(
|
|
29295
|
+
const normalized = input.filePath.replaceAll(path54.sep, "/").replace(/^\.\//, "");
|
|
28868
29296
|
if (index.files[normalized]) return { filePath: normalized, target: normalized };
|
|
28869
29297
|
const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
|
|
28870
29298
|
if (suffix) return { filePath: suffix, target: input.filePath };
|
|
@@ -28894,7 +29322,7 @@ function analyzeBlastRadius(input) {
|
|
|
28894
29322
|
}
|
|
28895
29323
|
}
|
|
28896
29324
|
}
|
|
28897
|
-
const targetBase =
|
|
29325
|
+
const targetBase = path54.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
|
|
28898
29326
|
const symbolLower = input.symbol?.toLowerCase();
|
|
28899
29327
|
const tests = Object.keys(index.files).filter((file) => {
|
|
28900
29328
|
const lower = file.toLowerCase();
|
|
@@ -28933,23 +29361,24 @@ function jsonResult(value) {
|
|
|
28933
29361
|
function registerCodeContext(server2) {
|
|
28934
29362
|
server2.registerTool("code_context", {
|
|
28935
29363
|
title: "Code Context",
|
|
28936
|
-
description: "Persistent codebase context engine. One consolidated tool to avoid MCP bloat. Actions: index, search, trace, blast_radius, stats.",
|
|
29364
|
+
description: "Persistent codebase context engine with semantic vector search. One consolidated tool to avoid MCP bloat. Actions: index (structural only), index_embed (structural + vector embeddings), search (semantic+lexical hybrid), trace, blast_radius, stats. Search uses RRF fusion of Jina v5 embeddings (cosine similarity) + lexical scoring. Falls back to lexical if daemon unavailable.",
|
|
28937
29365
|
inputSchema: {
|
|
28938
|
-
action:
|
|
28939
|
-
project_root:
|
|
28940
|
-
query:
|
|
28941
|
-
symbol:
|
|
28942
|
-
file_path:
|
|
28943
|
-
force:
|
|
28944
|
-
limit:
|
|
28945
|
-
offset:
|
|
28946
|
-
refresh_index:
|
|
28947
|
-
languages:
|
|
28948
|
-
paths:
|
|
28949
|
-
depth:
|
|
28950
|
-
max_files:
|
|
28951
|
-
|
|
28952
|
-
|
|
29366
|
+
action: z93.enum(["index", "index_embed", "search", "trace", "blast_radius", "stats"]).describe("Code context operation. index_embed = index + generate embeddings for semantic search."),
|
|
29367
|
+
project_root: z93.string().optional().describe("Repository root. Defaults to current working directory."),
|
|
29368
|
+
query: z93.string().optional().describe("Natural language search query (e.g. 'authentication logic', 'database migration'). Semantic search finds conceptual matches, not just keywords."),
|
|
29369
|
+
symbol: z93.string().optional().describe("Symbol/function/class/type name for trace or blast_radius"),
|
|
29370
|
+
file_path: z93.string().optional().describe("File path for blast_radius"),
|
|
29371
|
+
force: z93.boolean().optional().describe("Force rebuild before answering"),
|
|
29372
|
+
limit: z93.coerce.number().int().min(1).max(100).optional().describe("Max results"),
|
|
29373
|
+
offset: z93.coerce.number().int().min(0).optional().describe("Search pagination offset"),
|
|
29374
|
+
refresh_index: z93.boolean().optional().describe("Refresh/rebuild index before searching"),
|
|
29375
|
+
languages: z93.array(z93.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
|
|
29376
|
+
paths: z93.array(z93.string()).optional().describe("Path/glob filters"),
|
|
29377
|
+
depth: z93.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
|
|
29378
|
+
max_files: z93.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index"),
|
|
29379
|
+
lexical_only: z93.boolean().optional().describe("Force lexical-only search (skip vector similarity). Default: false \u2014 uses semantic hybrid search.")
|
|
29380
|
+
}
|
|
29381
|
+
}, async ({ action, project_root, query, symbol, file_path, force, limit, offset, refresh_index, languages, paths, depth, max_files, lexical_only }) => {
|
|
28953
29382
|
const opts = { projectRoot: project_root, force, maxFiles: max_files };
|
|
28954
29383
|
if (action === "index") {
|
|
28955
29384
|
const index = buildCodeContextIndex(opts);
|
|
@@ -28959,7 +29388,24 @@ function registerCodeContext(server2) {
|
|
|
28959
29388
|
indexedAt: index.indexedAt,
|
|
28960
29389
|
files: Object.keys(index.files).length,
|
|
28961
29390
|
symbols: Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0),
|
|
28962
|
-
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0)
|
|
29391
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
29392
|
+
note: "Structural index only. Use action=index_embed to also generate vector embeddings for semantic search."
|
|
29393
|
+
});
|
|
29394
|
+
}
|
|
29395
|
+
if (action === "index_embed") {
|
|
29396
|
+
const { index, vectorCount, newEmbeddings } = await buildCodeContextIndexWithEmbeddings(opts);
|
|
29397
|
+
const totalSymbols = Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0);
|
|
29398
|
+
return jsonResult({
|
|
29399
|
+
projectRoot: index.projectRoot,
|
|
29400
|
+
branch: index.branch,
|
|
29401
|
+
indexedAt: index.indexedAt,
|
|
29402
|
+
files: Object.keys(index.files).length,
|
|
29403
|
+
symbols: totalSymbols,
|
|
29404
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
29405
|
+
vectorCount,
|
|
29406
|
+
newEmbeddings,
|
|
29407
|
+
embeddingCoverage: totalSymbols > 0 ? `${(vectorCount / totalSymbols * 100).toFixed(1)}%` : "0%",
|
|
29408
|
+
note: "Structural index + vector embeddings. Semantic search is now available."
|
|
28963
29409
|
});
|
|
28964
29410
|
}
|
|
28965
29411
|
if (action === "stats") {
|
|
@@ -28967,14 +29413,28 @@ function registerCodeContext(server2) {
|
|
|
28967
29413
|
}
|
|
28968
29414
|
if (action === "search") {
|
|
28969
29415
|
if (!query) return errorResult10('code_context action "search" requires query');
|
|
29416
|
+
const searchOpts = { ...opts, limit, offset, refreshIndex: refresh_index, languages, paths };
|
|
29417
|
+
if (lexical_only) {
|
|
29418
|
+
return jsonResult({
|
|
29419
|
+
query,
|
|
29420
|
+
mode: "lexical",
|
|
29421
|
+
limit: limit ?? 20,
|
|
29422
|
+
offset: offset ?? 0,
|
|
29423
|
+
languages: languages ?? [],
|
|
29424
|
+
paths: paths ?? [],
|
|
29425
|
+
results: searchCodeContext(query, searchOpts)
|
|
29426
|
+
});
|
|
29427
|
+
}
|
|
29428
|
+
const results = await searchCodeContextSemantic(query, searchOpts);
|
|
29429
|
+
const hasSemantic = results.some((r) => r.matches.some((m) => m.startsWith("semantic=")));
|
|
28970
29430
|
return jsonResult({
|
|
28971
29431
|
query,
|
|
29432
|
+
mode: hasSemantic ? "semantic+lexical" : "lexical-fallback",
|
|
28972
29433
|
limit: limit ?? 20,
|
|
28973
29434
|
offset: offset ?? 0,
|
|
28974
|
-
refresh_index: refresh_index ?? false,
|
|
28975
29435
|
languages: languages ?? [],
|
|
28976
29436
|
paths: paths ?? [],
|
|
28977
|
-
results
|
|
29437
|
+
results
|
|
28978
29438
|
});
|
|
28979
29439
|
}
|
|
28980
29440
|
if (action === "trace") {
|
|
@@ -28992,9 +29452,9 @@ function registerCodeContext(server2) {
|
|
|
28992
29452
|
}
|
|
28993
29453
|
|
|
28994
29454
|
// src/mcp/tools/support-inbox.ts
|
|
28995
|
-
import { z as
|
|
29455
|
+
import { z as z94 } from "zod";
|
|
28996
29456
|
var DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
28997
|
-
var STATUS =
|
|
29457
|
+
var STATUS = z94.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
28998
29458
|
function adminToken() {
|
|
28999
29459
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
29000
29460
|
}
|
|
@@ -29033,9 +29493,9 @@ function registerListBugReports(server2) {
|
|
|
29033
29493
|
title: "List Bug Reports",
|
|
29034
29494
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
29035
29495
|
inputSchema: {
|
|
29036
|
-
status:
|
|
29037
|
-
severity:
|
|
29038
|
-
limit:
|
|
29496
|
+
status: z94.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
29497
|
+
severity: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
29498
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
29039
29499
|
}
|
|
29040
29500
|
},
|
|
29041
29501
|
async ({ status: status2, severity, limit }) => {
|
|
@@ -29054,7 +29514,7 @@ function registerGetBugReport(server2) {
|
|
|
29054
29514
|
{
|
|
29055
29515
|
title: "Get Bug Report",
|
|
29056
29516
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
29057
|
-
inputSchema: { id:
|
|
29517
|
+
inputSchema: { id: z94.string().min(8) }
|
|
29058
29518
|
},
|
|
29059
29519
|
async ({ id }) => {
|
|
29060
29520
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -29069,12 +29529,12 @@ function registerTriageBugReport(server2) {
|
|
|
29069
29529
|
title: "Triage Bug Report",
|
|
29070
29530
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
29071
29531
|
inputSchema: {
|
|
29072
|
-
id:
|
|
29532
|
+
id: z94.string().min(8),
|
|
29073
29533
|
status: STATUS.optional(),
|
|
29074
|
-
triage_notes:
|
|
29075
|
-
linked_task_id:
|
|
29076
|
-
linked_commit:
|
|
29077
|
-
fixed_version:
|
|
29534
|
+
triage_notes: z94.string().optional(),
|
|
29535
|
+
linked_task_id: z94.string().optional(),
|
|
29536
|
+
linked_commit: z94.string().optional(),
|
|
29537
|
+
fixed_version: z94.string().optional()
|
|
29078
29538
|
}
|
|
29079
29539
|
},
|
|
29080
29540
|
async ({ id, status: status2, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -29086,6 +29546,69 @@ function registerTriageBugReport(server2) {
|
|
|
29086
29546
|
}
|
|
29087
29547
|
);
|
|
29088
29548
|
}
|
|
29549
|
+
var FEATURE_STATUS = z94.enum(["open", "planned", "in_progress", "shipped", "closed", "wontdo"]);
|
|
29550
|
+
function featureEndpoint() {
|
|
29551
|
+
return endpoint().replace(/\/bug-reports\/?$/, "/feature-requests");
|
|
29552
|
+
}
|
|
29553
|
+
function registerListFeatureRequests(server2) {
|
|
29554
|
+
server2.registerTool(
|
|
29555
|
+
"list_feature_requests",
|
|
29556
|
+
{
|
|
29557
|
+
title: "List Feature Requests",
|
|
29558
|
+
description: "AskExe-internal only: list incoming customer feature requests from the support inbox.",
|
|
29559
|
+
inputSchema: {
|
|
29560
|
+
status: z94.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("open"),
|
|
29561
|
+
priority: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
29562
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
29563
|
+
}
|
|
29564
|
+
},
|
|
29565
|
+
async ({ status: status2, priority, limit }) => {
|
|
29566
|
+
const url = new URL(featureEndpoint());
|
|
29567
|
+
url.searchParams.set("status", status2);
|
|
29568
|
+
url.searchParams.set("limit", String(limit));
|
|
29569
|
+
if (priority) url.searchParams.set("priority", priority);
|
|
29570
|
+
const data = await requestJson(url.toString());
|
|
29571
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
29572
|
+
}
|
|
29573
|
+
);
|
|
29574
|
+
}
|
|
29575
|
+
function registerGetFeatureRequest(server2) {
|
|
29576
|
+
server2.registerTool(
|
|
29577
|
+
"get_feature_request",
|
|
29578
|
+
{
|
|
29579
|
+
title: "Get Feature Request",
|
|
29580
|
+
description: "AskExe-internal only: fetch one customer feature request with full payload.",
|
|
29581
|
+
inputSchema: { id: z94.string().min(8) }
|
|
29582
|
+
},
|
|
29583
|
+
async ({ id }) => {
|
|
29584
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`);
|
|
29585
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
29586
|
+
}
|
|
29587
|
+
);
|
|
29588
|
+
}
|
|
29589
|
+
function registerTriageFeatureRequest(server2) {
|
|
29590
|
+
server2.registerTool(
|
|
29591
|
+
"triage_feature_request",
|
|
29592
|
+
{
|
|
29593
|
+
title: "Triage Feature Request",
|
|
29594
|
+
description: "AskExe-internal only: update feature request status, response notes, and version metadata.",
|
|
29595
|
+
inputSchema: {
|
|
29596
|
+
id: z94.string().min(8),
|
|
29597
|
+
status: FEATURE_STATUS.optional(),
|
|
29598
|
+
response_notes: z94.string().optional(),
|
|
29599
|
+
target_version: z94.string().optional(),
|
|
29600
|
+
shipped_version: z94.string().optional()
|
|
29601
|
+
}
|
|
29602
|
+
},
|
|
29603
|
+
async ({ id, status: status2, response_notes, target_version, shipped_version }) => {
|
|
29604
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`, {
|
|
29605
|
+
method: "PATCH",
|
|
29606
|
+
body: JSON.stringify({ status: status2, response_notes, target_version, shipped_version })
|
|
29607
|
+
});
|
|
29608
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
29609
|
+
}
|
|
29610
|
+
);
|
|
29611
|
+
}
|
|
29089
29612
|
|
|
29090
29613
|
// src/mcp/tool-gates.ts
|
|
29091
29614
|
var TOOL_GATES = {
|
|
@@ -29409,6 +29932,7 @@ function registerAllTools(server2) {
|
|
|
29409
29932
|
gate("registerStoreDecision", registerStoreDecision);
|
|
29410
29933
|
gate("registerGetDecision", registerGetDecision);
|
|
29411
29934
|
gate("registerCreateBugReport", registerCreateBugReport);
|
|
29935
|
+
gate("registerCreateFeatureRequest", registerCreateFeatureRequest);
|
|
29412
29936
|
gate("registerSupportTools", registerSupportTools);
|
|
29413
29937
|
gate("registerCliParityTools", registerCliParityTools);
|
|
29414
29938
|
gate("registerGetSessionEvents", registerGetSessionEvents);
|
|
@@ -29418,6 +29942,9 @@ function registerAllTools(server2) {
|
|
|
29418
29942
|
gate("registerListBugReports", registerListBugReports);
|
|
29419
29943
|
gate("registerGetBugReport", registerGetBugReport);
|
|
29420
29944
|
gate("registerTriageBugReport", registerTriageBugReport);
|
|
29945
|
+
gate("registerListFeatureRequests", registerListFeatureRequests);
|
|
29946
|
+
gate("registerGetFeatureRequest", registerGetFeatureRequest);
|
|
29947
|
+
gate("registerTriageFeatureRequest", registerTriageFeatureRequest);
|
|
29421
29948
|
}
|
|
29422
29949
|
if (exposeLegacyConfig) {
|
|
29423
29950
|
gate("registerGetAgentSpend", registerGetAgentSpend);
|
|
@@ -29585,7 +30112,7 @@ try {
|
|
|
29585
30112
|
}
|
|
29586
30113
|
}, 3e4);
|
|
29587
30114
|
_ppidWatchdog.unref();
|
|
29588
|
-
const MCP_VERSION_PATH =
|
|
30115
|
+
const MCP_VERSION_PATH = path55.join(os20.homedir(), ".exe-os", "mcp-version");
|
|
29589
30116
|
let _currentMcpVersion = null;
|
|
29590
30117
|
try {
|
|
29591
30118
|
_currentMcpVersion = existsSync41(MCP_VERSION_PATH) ? readFileSync36(MCP_VERSION_PATH, "utf8").trim() : null;
|
|
@@ -29627,14 +30154,14 @@ try {
|
|
|
29627
30154
|
`
|
|
29628
30155
|
);
|
|
29629
30156
|
const thisFile = fileURLToPath7(import.meta.url);
|
|
29630
|
-
const backfillPath =
|
|
29631
|
-
|
|
30157
|
+
const backfillPath = path55.resolve(
|
|
30158
|
+
path55.dirname(thisFile),
|
|
29632
30159
|
"../bin/backfill-vectors.js"
|
|
29633
30160
|
);
|
|
29634
30161
|
if (existsSync41(backfillPath)) {
|
|
29635
30162
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
29636
|
-
const logPath =
|
|
29637
|
-
mkdirSync23(
|
|
30163
|
+
const logPath = path55.join(exeDir, "workers.log");
|
|
30164
|
+
mkdirSync23(path55.dirname(logPath), { recursive: true });
|
|
29638
30165
|
let logFd = "ignore";
|
|
29639
30166
|
try {
|
|
29640
30167
|
logFd = openSync4(logPath, "a");
|