@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/lib/exe-daemon.js
CHANGED
|
@@ -5350,7 +5350,7 @@ async function tryKeytar() {
|
|
|
5350
5350
|
}
|
|
5351
5351
|
function deriveMachineKey() {
|
|
5352
5352
|
try {
|
|
5353
|
-
const
|
|
5353
|
+
const crypto24 = __require("crypto");
|
|
5354
5354
|
const material = [
|
|
5355
5355
|
os6.hostname(),
|
|
5356
5356
|
os6.userInfo().username,
|
|
@@ -5359,7 +5359,7 @@ function deriveMachineKey() {
|
|
|
5359
5359
|
// Machine ID on Linux (stable across reboots)
|
|
5360
5360
|
process.platform === "linux" ? readMachineId() : ""
|
|
5361
5361
|
].join("|");
|
|
5362
|
-
return
|
|
5362
|
+
return crypto24.createHash("sha256").update(material).digest();
|
|
5363
5363
|
} catch {
|
|
5364
5364
|
return null;
|
|
5365
5365
|
}
|
|
@@ -5373,9 +5373,9 @@ function readMachineId() {
|
|
|
5373
5373
|
}
|
|
5374
5374
|
}
|
|
5375
5375
|
function encryptWithMachineKey(plaintext, machineKey) {
|
|
5376
|
-
const
|
|
5377
|
-
const iv =
|
|
5378
|
-
const cipher =
|
|
5376
|
+
const crypto24 = __require("crypto");
|
|
5377
|
+
const iv = crypto24.randomBytes(12);
|
|
5378
|
+
const cipher = crypto24.createCipheriv("aes-256-gcm", machineKey, iv);
|
|
5379
5379
|
let encrypted = cipher.update(plaintext, "utf-8", "base64");
|
|
5380
5380
|
encrypted += cipher.final("base64");
|
|
5381
5381
|
const authTag = cipher.getAuthTag().toString("base64");
|
|
@@ -5384,13 +5384,13 @@ function encryptWithMachineKey(plaintext, machineKey) {
|
|
|
5384
5384
|
function decryptWithMachineKey(encrypted, machineKey) {
|
|
5385
5385
|
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
5386
5386
|
try {
|
|
5387
|
-
const
|
|
5387
|
+
const crypto24 = __require("crypto");
|
|
5388
5388
|
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
5389
5389
|
if (parts.length !== 3) return null;
|
|
5390
5390
|
const [ivB64, tagB64, cipherB64] = parts;
|
|
5391
5391
|
const iv = Buffer.from(ivB64, "base64");
|
|
5392
5392
|
const authTag = Buffer.from(tagB64, "base64");
|
|
5393
|
-
const decipher =
|
|
5393
|
+
const decipher = crypto24.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
5394
5394
|
decipher.setAuthTag(authTag);
|
|
5395
5395
|
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
5396
5396
|
decrypted += decipher.final("utf-8");
|
|
@@ -5819,6 +5819,24 @@ var init_platform_procedures = __esm({
|
|
|
5819
5819
|
priority: "p0",
|
|
5820
5820
|
content: "When an agent encounters a suspected Exe OS bug, update breakage, MCP/tool failure, installer issue, memory/orchestration defect, or customer-local patch need, it MUST use create_bug_report. Do this before or alongside any local workaround so the report reaches AskExe support directly via the customer's license. Do NOT ask the founder for permission to file a required bug report. If create_bug_report is deferred/lazy-loaded, load it and call it. If it is unavailable in the live MCP surface, report 'create_bug_report unavailable in this session' and save a local report in exe/output \u2014 never claim the tool does not exist unless the live MCP surface was checked. If upstream delivery fails, call support_test (MCP) and include its result in the local report so AskExe can distinguish customer setup, license provisioning, and server intake issues; only ask the founder to run `exe-os support test` if MCP is disconnected/unavailable. Classify first: upstream_bug = reproducible exe-os/platform defect; customer_customization = identity, behavior, procedure, config, branding, workflow preference that belongs in customer-owned layers; emergency_hotfix = temporary local patch. For upstream bugs/emergency hotfixes include version, repro steps, expected/actual, files changed, workaround, and local diff summary. Avoid permanent platform-code patches unless founder approves; if a hotfix is unavoidable, document it in the bug report and re-check after npm update."
|
|
5821
5821
|
},
|
|
5822
|
+
{
|
|
5823
|
+
title: "Bug report status check \u2014 surface available fixes on boot",
|
|
5824
|
+
domain: "support",
|
|
5825
|
+
priority: "p1",
|
|
5826
|
+
content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
5827
|
+
},
|
|
5828
|
+
{
|
|
5829
|
+
title: "Feature request triage \u2014 upstream feature vs local customization",
|
|
5830
|
+
domain: "support",
|
|
5831
|
+
priority: "p0",
|
|
5832
|
+
content: "When an agent or founder identifies a desired capability that exe-os does not yet provide, the COO (or equivalent coordinator) must decide: is this a local customization (identity, behavior, procedure, config, branding, workflow preference that can be configured in customer-owned layers) or an upstream feature request (a platform capability that requires changes to exe-os code, shipped via npm update)? Local customizations: implement immediately using store_behavior, update_identity, company_procedure, or config changes. Upstream features: use create_feature_request to submit to AskExe. Include use case, business impact, and current workaround. Do NOT ask the founder for permission to file a feature request \u2014 file it proactively when the need is clear."
|
|
5833
|
+
},
|
|
5834
|
+
{
|
|
5835
|
+
title: "Feature request status check \u2014 surface shipped features on boot",
|
|
5836
|
+
domain: "support",
|
|
5837
|
+
priority: "p1",
|
|
5838
|
+
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
5839
|
+
},
|
|
5822
5840
|
// --- Operations ---
|
|
5823
5841
|
{
|
|
5824
5842
|
title: "Managers must supervise deployed workers",
|
|
@@ -7193,8 +7211,8 @@ async function embedDirect(text3) {
|
|
|
7193
7211
|
const llamaCpp = await import("node-llama-cpp");
|
|
7194
7212
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
7195
7213
|
const { existsSync: existsSync48 } = await import("fs");
|
|
7196
|
-
const
|
|
7197
|
-
const modelPath =
|
|
7214
|
+
const path63 = await import("path");
|
|
7215
|
+
const modelPath = path63.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
7198
7216
|
if (!existsSync48(modelPath)) {
|
|
7199
7217
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
7200
7218
|
}
|
|
@@ -8286,10 +8304,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
8286
8304
|
};
|
|
8287
8305
|
try {
|
|
8288
8306
|
const fs = await import("fs");
|
|
8289
|
-
const
|
|
8307
|
+
const path63 = await import("path");
|
|
8290
8308
|
const os25 = await import("os");
|
|
8291
|
-
const logPath =
|
|
8292
|
-
fs.mkdirSync(
|
|
8309
|
+
const logPath = path63.join(os25.homedir(), ".exe-os", "search-quality.jsonl");
|
|
8310
|
+
fs.mkdirSync(path63.dirname(logPath), { recursive: true });
|
|
8293
8311
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
8294
8312
|
} catch {
|
|
8295
8313
|
}
|
|
@@ -9922,8 +9940,8 @@ __export(wiki_client_exports, {
|
|
|
9922
9940
|
listDocuments: () => listDocuments,
|
|
9923
9941
|
listWorkspaces: () => listWorkspaces
|
|
9924
9942
|
});
|
|
9925
|
-
async function wikiFetch(config2,
|
|
9926
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
9943
|
+
async function wikiFetch(config2, path63, method = "GET", body) {
|
|
9944
|
+
const url = `${config2.baseUrl}/api/v1${path63}`;
|
|
9927
9945
|
const headers = {
|
|
9928
9946
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
9929
9947
|
"Content-Type": "application/json"
|
|
@@ -9956,7 +9974,7 @@ async function wikiFetch(config2, path62, method = "GET", body) {
|
|
|
9956
9974
|
}
|
|
9957
9975
|
}
|
|
9958
9976
|
if (!response.ok) {
|
|
9959
|
-
throw new Error(`Wiki API ${method} ${
|
|
9977
|
+
throw new Error(`Wiki API ${method} ${path63}: ${response.status} ${response.statusText}`);
|
|
9960
9978
|
}
|
|
9961
9979
|
return response.json();
|
|
9962
9980
|
} finally {
|
|
@@ -15037,12 +15055,14 @@ On EVERY new conversation, before doing anything else:
|
|
|
15037
15055
|
1. **Memory scan**: Run recall_my_memory with broad queries \u2014 "project", "client", "pipeline", "campaign", "deal", "decision", "blocker". Summarize what you find.
|
|
15038
15056
|
2. **Task scan**: Run list_tasks to see what's open, in progress, blocked, or needs review across all employees.
|
|
15039
15057
|
3. **Team check**: Run ask_team_memory for recent activity from CTO/CMO/engineers.
|
|
15040
|
-
4. **
|
|
15058
|
+
4. **Bug fix check** (one-time, never repeat): Call list_my_bug_reports to see if AskExe has fixed any previously filed bugs. If any have status "fixed" with a fixed_version, tell the founder: "\u{1F527} N bug fix(es) available \u2014 run \`exe-os update\` to get version X.Y.Z." Skip silently if none or if the call fails.
|
|
15059
|
+
5. **Present the brief**: Give the founder a concise status report:
|
|
15041
15060
|
- What's active and progressing
|
|
15042
15061
|
- What's blocked and needs attention
|
|
15043
15062
|
- What decisions are pending
|
|
15063
|
+
- Available bug fixes (from step 4, if any)
|
|
15044
15064
|
- What you recommend doing next
|
|
15045
|
-
|
|
15065
|
+
6. Then ask: "What's the priority?"
|
|
15046
15066
|
|
|
15047
15067
|
If this is your FIRST ever conversation (few or no prior memories):
|
|
15048
15068
|
- Search more broadly: "product", "SEO", "meeting", "strategy", "revenue"
|
|
@@ -15062,6 +15082,8 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
15062
15082
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
15063
15083
|
- **set_agent_config** \u2014 view or change which tool (Claude Code, Codex, OpenCode) and model each agent uses. Call with no args to show all agents' current settings. Call with agent_id + runtime + model to change.
|
|
15064
15084
|
- **send_message** \u2014 direct intercom to employees
|
|
15085
|
+
- **create_bug_report** \u2014 file a bug when you encounter an Exe OS platform issue
|
|
15086
|
+
- **list_my_bug_reports** \u2014 check status of filed bugs (boot check: surface available fixes to founder)
|
|
15065
15087
|
${PLAN_MODE_COMPAT}
|
|
15066
15088
|
## Completion Workflow
|
|
15067
15089
|
|
|
@@ -19058,12 +19080,12 @@ function registerExportGraph(server) {
|
|
|
19058
19080
|
}
|
|
19059
19081
|
const html = await exportGraphHTML(client);
|
|
19060
19082
|
const fs = await import("fs");
|
|
19061
|
-
const
|
|
19083
|
+
const path63 = await import("path");
|
|
19062
19084
|
const os25 = await import("os");
|
|
19063
|
-
const outDir =
|
|
19085
|
+
const outDir = path63.join(os25.homedir(), ".exe-os", "exports");
|
|
19064
19086
|
fs.mkdirSync(outDir, { recursive: true });
|
|
19065
19087
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
19066
|
-
const filePath =
|
|
19088
|
+
const filePath = path63.join(outDir, `graph-${timestamp}.html`);
|
|
19067
19089
|
fs.writeFileSync(filePath, html, "utf-8");
|
|
19068
19090
|
return {
|
|
19069
19091
|
content: [
|
|
@@ -26148,9 +26170,9 @@ var init_hostinger_api = __esm({
|
|
|
26148
26170
|
}
|
|
26149
26171
|
this.lastRequestTime = Date.now();
|
|
26150
26172
|
}
|
|
26151
|
-
async request(method,
|
|
26173
|
+
async request(method, path63, body) {
|
|
26152
26174
|
await this.rateLimit();
|
|
26153
|
-
const url = `${this.baseUrl}${
|
|
26175
|
+
const url = `${this.baseUrl}${path63}`;
|
|
26154
26176
|
const headers = {
|
|
26155
26177
|
Authorization: `Bearer ${this.apiKey}`,
|
|
26156
26178
|
"Content-Type": "application/json",
|
|
@@ -26219,8 +26241,8 @@ async function requestCloudflare(cfApiToken, zoneId, options) {
|
|
|
26219
26241
|
}
|
|
26220
26242
|
return envelope.result;
|
|
26221
26243
|
}
|
|
26222
|
-
function buildUrl(zoneId,
|
|
26223
|
-
const normalizedPath =
|
|
26244
|
+
function buildUrl(zoneId, path63 = "/dns_records", query) {
|
|
26245
|
+
const normalizedPath = path63.startsWith("/") ? path63 : `/${path63}`;
|
|
26224
26246
|
const url = new URL(
|
|
26225
26247
|
`${CLOUDFLARE_API_BASE_URL}/zones/${zoneId}${normalizedPath}`
|
|
26226
26248
|
);
|
|
@@ -30179,9 +30201,207 @@ var init_create_bug_report = __esm({
|
|
|
30179
30201
|
}
|
|
30180
30202
|
});
|
|
30181
30203
|
|
|
30204
|
+
// src/mcp/tools/create-feature-request.ts
|
|
30205
|
+
import { z as z89 } from "zod";
|
|
30206
|
+
import crypto20 from "crypto";
|
|
30207
|
+
import { mkdir as mkdir7, writeFile as writeFile8 } from "fs/promises";
|
|
30208
|
+
import path54 from "path";
|
|
30209
|
+
function slugify3(input) {
|
|
30210
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "feature-request";
|
|
30211
|
+
}
|
|
30212
|
+
function section2(title, body) {
|
|
30213
|
+
return `## ${title}
|
|
30214
|
+
|
|
30215
|
+
${body?.trim() || "Not provided"}`;
|
|
30216
|
+
}
|
|
30217
|
+
function buildMarkdown2(input) {
|
|
30218
|
+
return [
|
|
30219
|
+
`# Feature Request \u2014 ${input.title}`,
|
|
30220
|
+
"",
|
|
30221
|
+
`id: ${input.id}`,
|
|
30222
|
+
`category: ${input.category}`,
|
|
30223
|
+
`priority: ${input.priority}`,
|
|
30224
|
+
`filed_by: ${input.agentId} (${input.agentRole})`,
|
|
30225
|
+
`package_version: ${input.packageVersion}`,
|
|
30226
|
+
`project: ${input.projectName ?? "unknown"}`,
|
|
30227
|
+
`created_at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
30228
|
+
"",
|
|
30229
|
+
section2("Description", input.description),
|
|
30230
|
+
section2("Use Case", input.useCase),
|
|
30231
|
+
section2("Current Workaround", input.currentWorkaround),
|
|
30232
|
+
section2("Proposed Solution", input.proposedSolution),
|
|
30233
|
+
section2("Business Impact", input.businessImpact)
|
|
30234
|
+
].join("\n");
|
|
30235
|
+
}
|
|
30236
|
+
async function maybeSendUpstream2(payload) {
|
|
30237
|
+
const config2 = await loadConfig();
|
|
30238
|
+
const routerUrl = process.env.API_ROUTER_URL?.replace(/\/+$/, "");
|
|
30239
|
+
const endpoint2 = config2.support?.featureRequestEndpoint || process.env.EXE_FEATURE_REQUEST_ENDPOINT || (routerUrl ? `${routerUrl}/v1/support/feature-requests` : "https://askexe.com/v1/support/feature-requests");
|
|
30240
|
+
const token = config2.support?.featureRequestToken || process.env.EXE_FEATURE_REQUEST_TOKEN;
|
|
30241
|
+
const licenseKey = loadLicense() || process.env.EXE_LICENSE_KEY || config2.cloud?.apiKey;
|
|
30242
|
+
const licenseToken = readCachedLicenseToken();
|
|
30243
|
+
if (!endpoint2) {
|
|
30244
|
+
return "not_configured";
|
|
30245
|
+
}
|
|
30246
|
+
try {
|
|
30247
|
+
const parsed = new URL(endpoint2);
|
|
30248
|
+
if (parsed.protocol !== "https:" && !["localhost", "127.0.0.1", "::1"].includes(parsed.hostname)) {
|
|
30249
|
+
return "failed: insecure endpoint rejected";
|
|
30250
|
+
}
|
|
30251
|
+
const response = await fetch(parsed, {
|
|
30252
|
+
method: "POST",
|
|
30253
|
+
headers: {
|
|
30254
|
+
"content-type": "application/json",
|
|
30255
|
+
...token ? { authorization: `Bearer ${token}` } : {},
|
|
30256
|
+
...licenseKey ? { "x-exe-license-key": licenseKey } : {},
|
|
30257
|
+
...licenseToken ? { "x-exe-license-token": licenseToken } : {}
|
|
30258
|
+
},
|
|
30259
|
+
body: JSON.stringify(payload),
|
|
30260
|
+
signal: AbortSignal.timeout(1e4)
|
|
30261
|
+
});
|
|
30262
|
+
if (!response.ok) return `failed: HTTP ${response.status}`;
|
|
30263
|
+
return "sent";
|
|
30264
|
+
} catch (err) {
|
|
30265
|
+
return `failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
30266
|
+
}
|
|
30267
|
+
}
|
|
30268
|
+
function registerCreateFeatureRequest(server) {
|
|
30269
|
+
server.registerTool(
|
|
30270
|
+
"create_feature_request",
|
|
30271
|
+
{
|
|
30272
|
+
title: "Create Feature Request",
|
|
30273
|
+
description: "File a feature request for exe-os: upstream_feature (requires platform changes), local_customization (configurable in customer layers), integration (third-party), or unclear. Writes a local report, stores memory, and optionally sends to AskExe.",
|
|
30274
|
+
inputSchema: {
|
|
30275
|
+
title: z89.string().min(3).describe("Short descriptive title"),
|
|
30276
|
+
category: CATEGORY.describe(
|
|
30277
|
+
"upstream_feature = platform capability change; local_customization = configurable in customer layers; integration = third-party connector; unclear = needs product triage"
|
|
30278
|
+
),
|
|
30279
|
+
priority: PRIORITY.default("p2").describe("p0 critical \u2192 p3 low"),
|
|
30280
|
+
description: z89.string().min(10).describe("What capability is needed and why"),
|
|
30281
|
+
use_case: z89.string().optional().describe("Concrete scenario where this feature would be used"),
|
|
30282
|
+
current_workaround: z89.string().optional().describe("How the need is currently addressed, if at all"),
|
|
30283
|
+
proposed_solution: z89.string().optional().describe("Suggested implementation approach"),
|
|
30284
|
+
business_impact: z89.string().optional().describe("Impact on business/workflow if this ships"),
|
|
30285
|
+
package_version: z89.string().optional().describe("Installed @askexenow/exe-os version"),
|
|
30286
|
+
project_name: z89.string().optional().describe("Project/customer context"),
|
|
30287
|
+
send_upstream: z89.boolean().default(true).describe("Attempt to POST to configured AskExe support endpoint")
|
|
30288
|
+
}
|
|
30289
|
+
},
|
|
30290
|
+
async ({
|
|
30291
|
+
title,
|
|
30292
|
+
category,
|
|
30293
|
+
priority,
|
|
30294
|
+
description,
|
|
30295
|
+
use_case,
|
|
30296
|
+
current_workaround,
|
|
30297
|
+
proposed_solution,
|
|
30298
|
+
business_impact,
|
|
30299
|
+
package_version,
|
|
30300
|
+
project_name,
|
|
30301
|
+
send_upstream
|
|
30302
|
+
}) => {
|
|
30303
|
+
const { agentId, agentRole } = getActiveAgent();
|
|
30304
|
+
const id = crypto20.randomUUID();
|
|
30305
|
+
const version = package_version ?? "unknown";
|
|
30306
|
+
const markdown = buildMarkdown2({
|
|
30307
|
+
id,
|
|
30308
|
+
title,
|
|
30309
|
+
category,
|
|
30310
|
+
priority,
|
|
30311
|
+
agentId,
|
|
30312
|
+
agentRole,
|
|
30313
|
+
packageVersion: version,
|
|
30314
|
+
description,
|
|
30315
|
+
useCase: use_case,
|
|
30316
|
+
currentWorkaround: current_workaround,
|
|
30317
|
+
proposedSolution: proposed_solution,
|
|
30318
|
+
businessImpact: business_impact,
|
|
30319
|
+
projectName: project_name
|
|
30320
|
+
});
|
|
30321
|
+
const outDir = path54.join(EXE_AI_DIR, "feature-requests");
|
|
30322
|
+
await mkdir7(outDir, { recursive: true });
|
|
30323
|
+
const reportPath = path54.join(outDir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}-${slugify3(title)}-${id.slice(0, 8)}.md`);
|
|
30324
|
+
await writeFile8(reportPath, markdown, "utf-8");
|
|
30325
|
+
let vector = null;
|
|
30326
|
+
try {
|
|
30327
|
+
vector = await embed(markdown);
|
|
30328
|
+
} catch {
|
|
30329
|
+
vector = null;
|
|
30330
|
+
}
|
|
30331
|
+
await writeMemory({
|
|
30332
|
+
id,
|
|
30333
|
+
agent_id: agentId,
|
|
30334
|
+
agent_role: agentRole,
|
|
30335
|
+
session_id: process.env.SESSION_ID ?? "manual",
|
|
30336
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30337
|
+
tool_name: "create_feature_request",
|
|
30338
|
+
project_name: project_name ?? "support",
|
|
30339
|
+
has_error: false,
|
|
30340
|
+
raw_text: markdown,
|
|
30341
|
+
vector,
|
|
30342
|
+
source_path: reportPath,
|
|
30343
|
+
source_type: "feature_request",
|
|
30344
|
+
memory_type: "feature_request",
|
|
30345
|
+
tier: 1,
|
|
30346
|
+
importance: priority === "p0" ? 10 : priority === "p1" ? 9 : priority === "p2" ? 7 : 5,
|
|
30347
|
+
intent: "request",
|
|
30348
|
+
domain: "support",
|
|
30349
|
+
file_paths: null
|
|
30350
|
+
});
|
|
30351
|
+
await flushBatch();
|
|
30352
|
+
const upstreamStatus = send_upstream ? await maybeSendUpstream2({
|
|
30353
|
+
id,
|
|
30354
|
+
title,
|
|
30355
|
+
category,
|
|
30356
|
+
priority,
|
|
30357
|
+
description,
|
|
30358
|
+
use_case,
|
|
30359
|
+
current_workaround,
|
|
30360
|
+
proposed_solution,
|
|
30361
|
+
business_impact,
|
|
30362
|
+
package_version: version,
|
|
30363
|
+
project_name,
|
|
30364
|
+
agent_id: agentId,
|
|
30365
|
+
agent_role: agentRole
|
|
30366
|
+
}) : "skipped";
|
|
30367
|
+
return {
|
|
30368
|
+
content: [
|
|
30369
|
+
{
|
|
30370
|
+
type: "text",
|
|
30371
|
+
text: `Feature request created.
|
|
30372
|
+
ID: ${id}
|
|
30373
|
+
Category: ${category}
|
|
30374
|
+
Local report: ${reportPath}
|
|
30375
|
+
Memory stored: ${id}
|
|
30376
|
+
Upstream status: ${upstreamStatus}`
|
|
30377
|
+
}
|
|
30378
|
+
]
|
|
30379
|
+
};
|
|
30380
|
+
}
|
|
30381
|
+
);
|
|
30382
|
+
}
|
|
30383
|
+
var CATEGORY, PRIORITY;
|
|
30384
|
+
var init_create_feature_request = __esm({
|
|
30385
|
+
"src/mcp/tools/create-feature-request.ts"() {
|
|
30386
|
+
"use strict";
|
|
30387
|
+
init_embedder();
|
|
30388
|
+
init_active_agent();
|
|
30389
|
+
init_config();
|
|
30390
|
+
init_license();
|
|
30391
|
+
init_store();
|
|
30392
|
+
CATEGORY = z89.enum([
|
|
30393
|
+
"upstream_feature",
|
|
30394
|
+
"local_customization",
|
|
30395
|
+
"integration",
|
|
30396
|
+
"unclear"
|
|
30397
|
+
]);
|
|
30398
|
+
PRIORITY = z89.enum(["p0", "p1", "p2", "p3"]);
|
|
30399
|
+
}
|
|
30400
|
+
});
|
|
30401
|
+
|
|
30182
30402
|
// src/bin/exe-support.ts
|
|
30183
30403
|
import { mkdirSync as mkdirSync21, readFileSync as readFileSync35, unlinkSync as unlinkSync13, writeFileSync as writeFileSync24 } from "fs";
|
|
30184
|
-
import
|
|
30404
|
+
import path55 from "path";
|
|
30185
30405
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
30186
30406
|
async function runHealth() {
|
|
30187
30407
|
const checks = [];
|
|
@@ -30300,8 +30520,8 @@ async function resolveEndpoints() {
|
|
|
30300
30520
|
return { bugEndpoint, healthEndpoint, adminEndpoint };
|
|
30301
30521
|
}
|
|
30302
30522
|
function checkLocalWrite() {
|
|
30303
|
-
const dir =
|
|
30304
|
-
const testPath =
|
|
30523
|
+
const dir = path55.join(EXE_AI_DIR, "bug-reports");
|
|
30524
|
+
const testPath = path55.join(dir, ".support-write-test");
|
|
30305
30525
|
try {
|
|
30306
30526
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
30307
30527
|
writeFileSync24(testPath, "ok\n", { mode: 384 });
|
|
@@ -30317,10 +30537,10 @@ function checkLocalWrite() {
|
|
|
30317
30537
|
}
|
|
30318
30538
|
}
|
|
30319
30539
|
function writeLocalTestReport(id, project, version) {
|
|
30320
|
-
const dir =
|
|
30540
|
+
const dir = path55.join(EXE_AI_DIR, "bug-reports");
|
|
30321
30541
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
30322
30542
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
30323
|
-
const filePath =
|
|
30543
|
+
const filePath = path55.join(dir, `${date}-support-intake-test-${id.slice(0, 8)}.md`);
|
|
30324
30544
|
writeFileSync24(filePath, `# TEST \u2014 ${project} support intake
|
|
30325
30545
|
|
|
30326
30546
|
Report ID: ${id}
|
|
@@ -30362,15 +30582,15 @@ async function maybeCloseAdmin(id, adminEndpoint, version) {
|
|
|
30362
30582
|
}
|
|
30363
30583
|
}
|
|
30364
30584
|
function readPackageVersion2() {
|
|
30365
|
-
let dir =
|
|
30585
|
+
let dir = path55.dirname(new URL(import.meta.url).pathname);
|
|
30366
30586
|
for (let i = 0; i < 6; i++) {
|
|
30367
|
-
const pkg =
|
|
30587
|
+
const pkg = path55.join(dir, "package.json");
|
|
30368
30588
|
try {
|
|
30369
30589
|
const parsed = JSON.parse(readFileSync35(pkg, "utf8"));
|
|
30370
30590
|
if (parsed.version) return parsed.version;
|
|
30371
30591
|
} catch {
|
|
30372
30592
|
}
|
|
30373
|
-
dir =
|
|
30593
|
+
dir = path55.dirname(dir);
|
|
30374
30594
|
}
|
|
30375
30595
|
return "unknown";
|
|
30376
30596
|
}
|
|
@@ -30406,7 +30626,7 @@ var init_exe_support = __esm({
|
|
|
30406
30626
|
});
|
|
30407
30627
|
|
|
30408
30628
|
// src/mcp/tools/support.ts
|
|
30409
|
-
import { z as
|
|
30629
|
+
import { z as z90 } from "zod";
|
|
30410
30630
|
function formatRows(rows, mode) {
|
|
30411
30631
|
const lines = [`exe-os support ${mode}`, ""];
|
|
30412
30632
|
for (const row of rows) {
|
|
@@ -30447,7 +30667,7 @@ function registerSupportTools(server) {
|
|
|
30447
30667
|
title: "Support Test",
|
|
30448
30668
|
description: "End-to-end support intake smoke test. Files a clearly marked test report upstream and auto-closes it on AskExe machines with admin credentials.",
|
|
30449
30669
|
inputSchema: {
|
|
30450
|
-
project:
|
|
30670
|
+
project: z90.string().default("support-smoke").describe("Customer/project name, e.g. hygo")
|
|
30451
30671
|
}
|
|
30452
30672
|
},
|
|
30453
30673
|
async ({ project }) => {
|
|
@@ -30465,8 +30685,8 @@ function registerSupportTools(server) {
|
|
|
30465
30685
|
title: "My Bug Reports",
|
|
30466
30686
|
description: "List bug reports you've filed, scoped to your license. Shows status (open/triaged/fixed/closed), severity, and fixed_version so you know when to update.",
|
|
30467
30687
|
inputSchema: {
|
|
30468
|
-
status:
|
|
30469
|
-
limit:
|
|
30688
|
+
status: z90.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("all").describe("Filter by status. Default: all"),
|
|
30689
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
30470
30690
|
}
|
|
30471
30691
|
},
|
|
30472
30692
|
async ({ status: status2, limit }) => {
|
|
@@ -30522,6 +30742,70 @@ function registerSupportTools(server) {
|
|
|
30522
30742
|
}
|
|
30523
30743
|
}
|
|
30524
30744
|
);
|
|
30745
|
+
server.registerTool(
|
|
30746
|
+
"list_my_feature_requests",
|
|
30747
|
+
{
|
|
30748
|
+
title: "My Feature Requests",
|
|
30749
|
+
description: "List feature requests you've filed, scoped to your license. Shows status (open/planned/in_progress/shipped/closed), priority, and shipped_version so you know when to update.",
|
|
30750
|
+
inputSchema: {
|
|
30751
|
+
status: z90.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("all").describe("Filter by status. Default: all"),
|
|
30752
|
+
limit: z90.number().min(1).max(50).default(25).describe("Max results")
|
|
30753
|
+
}
|
|
30754
|
+
},
|
|
30755
|
+
async ({ status: status2, limit }) => {
|
|
30756
|
+
const licenseKey = loadLicense();
|
|
30757
|
+
const licenseToken = readCachedLicenseToken();
|
|
30758
|
+
if (!licenseKey && !licenseToken) {
|
|
30759
|
+
return {
|
|
30760
|
+
content: [{ type: "text", text: "No license key found. Run `exe-os setup` or `exe-os cloud setup` first." }],
|
|
30761
|
+
isError: true
|
|
30762
|
+
};
|
|
30763
|
+
}
|
|
30764
|
+
const endpoint2 = new URL("https://askexe.com/v1/support/my-feature-requests");
|
|
30765
|
+
endpoint2.searchParams.set("status", status2);
|
|
30766
|
+
endpoint2.searchParams.set("limit", String(limit));
|
|
30767
|
+
const headers = { "content-type": "application/json" };
|
|
30768
|
+
if (licenseKey) headers["x-exe-license-key"] = licenseKey;
|
|
30769
|
+
if (licenseToken) headers["x-exe-license-token"] = licenseToken;
|
|
30770
|
+
try {
|
|
30771
|
+
const res = await fetch(endpoint2.toString(), { method: "GET", headers, signal: AbortSignal.timeout(15e3) });
|
|
30772
|
+
if (!res.ok) {
|
|
30773
|
+
const body = await res.text().catch(() => "");
|
|
30774
|
+
return {
|
|
30775
|
+
content: [{ type: "text", text: `Failed to fetch feature requests: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}` }],
|
|
30776
|
+
isError: true
|
|
30777
|
+
};
|
|
30778
|
+
}
|
|
30779
|
+
const data = await res.json();
|
|
30780
|
+
if (data.count === 0) {
|
|
30781
|
+
return {
|
|
30782
|
+
content: [{ type: "text", text: `No feature requests found${status2 !== "all" ? ` with status '${status2}'` : ""}.` }],
|
|
30783
|
+
structuredContent: { items: [], count: 0 }
|
|
30784
|
+
};
|
|
30785
|
+
}
|
|
30786
|
+
const lines = [`Feature requests (${data.count}):`, ""];
|
|
30787
|
+
for (const r of data.items) {
|
|
30788
|
+
const priIcon = r.priority === "p0" ? "\u{1F534}" : r.priority === "p1" ? "\u{1F534}" : r.priority === "p2" ? "\u{1F7E0}" : "\u{1F7E2}";
|
|
30789
|
+
const statusIcon = r.status === "shipped" ? "\u2705" : r.status === "closed" ? "\u2611\uFE0F" : r.status === "planned" ? "\u{1F4CB}" : r.status === "in_progress" ? "\u{1F528}" : r.status === "wontdo" ? "\u26D4" : "\u{1F535}";
|
|
30790
|
+
lines.push(`${priIcon} ${r.priority.toUpperCase()} ${statusIcon} ${r.status} \u2014 ${r.title}`);
|
|
30791
|
+
lines.push(` ID: ${r.id} | Filed: ${r.created_at?.slice(0, 10) ?? "?"}`);
|
|
30792
|
+
if (r.shipped_version) lines.push(` \u{1F680} Shipped in: ${r.shipped_version} \u2014 run \`exe-os update\` to get this feature`);
|
|
30793
|
+
if (r.target_version) lines.push(` \u{1F3AF} Target: ${r.target_version}`);
|
|
30794
|
+
if (r.response_notes) lines.push(` \u{1F4DD} AskExe: ${r.response_notes}`);
|
|
30795
|
+
lines.push("");
|
|
30796
|
+
}
|
|
30797
|
+
return {
|
|
30798
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
30799
|
+
structuredContent: data
|
|
30800
|
+
};
|
|
30801
|
+
} catch (err) {
|
|
30802
|
+
return {
|
|
30803
|
+
content: [{ type: "text", text: `Error fetching feature requests: ${err instanceof Error ? err.message : String(err)}` }],
|
|
30804
|
+
isError: true
|
|
30805
|
+
};
|
|
30806
|
+
}
|
|
30807
|
+
}
|
|
30808
|
+
);
|
|
30525
30809
|
}
|
|
30526
30810
|
var init_support = __esm({
|
|
30527
30811
|
"src/mcp/tools/support.ts"() {
|
|
@@ -30596,21 +30880,21 @@ var init_exe_status = __esm({
|
|
|
30596
30880
|
|
|
30597
30881
|
// src/bin/exe-healthcheck.ts
|
|
30598
30882
|
import { existsSync as existsSync43, readFileSync as readFileSync36, readdirSync as readdirSync14 } from "fs";
|
|
30599
|
-
import
|
|
30883
|
+
import path56 from "path";
|
|
30600
30884
|
import { execSync as execSync15 } from "child_process";
|
|
30601
30885
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
30602
30886
|
function findPackageRoot2() {
|
|
30603
|
-
let dir =
|
|
30604
|
-
const { root } =
|
|
30887
|
+
let dir = path56.dirname(fileURLToPath6(import.meta.url));
|
|
30888
|
+
const { root } = path56.parse(dir);
|
|
30605
30889
|
while (dir !== root) {
|
|
30606
|
-
if (existsSync43(
|
|
30607
|
-
dir =
|
|
30890
|
+
if (existsSync43(path56.join(dir, "package.json"))) return dir;
|
|
30891
|
+
dir = path56.dirname(dir);
|
|
30608
30892
|
}
|
|
30609
30893
|
throw new Error("Cannot find package root");
|
|
30610
30894
|
}
|
|
30611
30895
|
function checkBuildIntegrity(pkgRoot) {
|
|
30612
30896
|
const results = [];
|
|
30613
|
-
const tsupConfig =
|
|
30897
|
+
const tsupConfig = path56.join(pkgRoot, "tsup.config.ts");
|
|
30614
30898
|
if (!existsSync43(tsupConfig)) {
|
|
30615
30899
|
return [{ name: "build/tsup-config", pass: false, detail: "tsup.config.ts not found" }];
|
|
30616
30900
|
}
|
|
@@ -30620,7 +30904,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
30620
30904
|
let total = 0;
|
|
30621
30905
|
for (const match of entryMatches) {
|
|
30622
30906
|
const outputKey = match[1];
|
|
30623
|
-
const expectedPath =
|
|
30907
|
+
const expectedPath = path56.join(pkgRoot, "dist", `${outputKey}.js`);
|
|
30624
30908
|
total++;
|
|
30625
30909
|
if (!existsSync43(expectedPath)) {
|
|
30626
30910
|
missing.push(`dist/${outputKey}.js`);
|
|
@@ -30644,7 +30928,7 @@ function checkBuildIntegrity(pkgRoot) {
|
|
|
30644
30928
|
}
|
|
30645
30929
|
function checkEmbedPipeline(pkgRoot) {
|
|
30646
30930
|
const results = [];
|
|
30647
|
-
const daemonPath =
|
|
30931
|
+
const daemonPath = path56.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
30648
30932
|
if (!existsSync43(daemonPath)) {
|
|
30649
30933
|
results.push({
|
|
30650
30934
|
name: "exed/daemon-exists",
|
|
@@ -30656,17 +30940,17 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30656
30940
|
results.push({ name: "exed/daemon-exists", pass: true, detail: "dist/lib/exe-daemon.js exists" });
|
|
30657
30941
|
const entryDirs = ["dist/hooks", "dist/bin", "dist/mcp"];
|
|
30658
30942
|
for (const dir of entryDirs) {
|
|
30659
|
-
const fullDir =
|
|
30943
|
+
const fullDir = path56.join(pkgRoot, dir);
|
|
30660
30944
|
if (!existsSync43(fullDir)) continue;
|
|
30661
30945
|
let walkDir = fullDir;
|
|
30662
|
-
const { root } =
|
|
30946
|
+
const { root } = path56.parse(walkDir);
|
|
30663
30947
|
let foundRoot = null;
|
|
30664
30948
|
while (walkDir !== root) {
|
|
30665
|
-
if (existsSync43(
|
|
30949
|
+
if (existsSync43(path56.join(walkDir, "package.json"))) {
|
|
30666
30950
|
foundRoot = walkDir;
|
|
30667
30951
|
break;
|
|
30668
30952
|
}
|
|
30669
|
-
walkDir =
|
|
30953
|
+
walkDir = path56.dirname(walkDir);
|
|
30670
30954
|
}
|
|
30671
30955
|
if (!foundRoot) {
|
|
30672
30956
|
results.push({
|
|
@@ -30676,7 +30960,7 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30676
30960
|
});
|
|
30677
30961
|
continue;
|
|
30678
30962
|
}
|
|
30679
|
-
const resolvedDaemon =
|
|
30963
|
+
const resolvedDaemon = path56.join(foundRoot, "dist", "lib", "exe-daemon.js");
|
|
30680
30964
|
const reachable = existsSync43(resolvedDaemon);
|
|
30681
30965
|
results.push({
|
|
30682
30966
|
name: `exed/reachable-from-${dir}`,
|
|
@@ -30688,7 +30972,7 @@ function checkEmbedPipeline(pkgRoot) {
|
|
|
30688
30972
|
}
|
|
30689
30973
|
function checkTaskSystem(pkgRoot) {
|
|
30690
30974
|
const results = [];
|
|
30691
|
-
const scannerPath =
|
|
30975
|
+
const scannerPath = path56.join(pkgRoot, "dist", "bin", "scan-tasks.js");
|
|
30692
30976
|
if (!existsSync43(scannerPath)) {
|
|
30693
30977
|
results.push({ name: "tasks/scanner", pass: false, detail: "scan-tasks.js not found" });
|
|
30694
30978
|
return results;
|
|
@@ -30711,7 +30995,7 @@ function checkTaskSystem(pkgRoot) {
|
|
|
30711
30995
|
}
|
|
30712
30996
|
function checkWorkerSpawning(pkgRoot) {
|
|
30713
30997
|
const results = [];
|
|
30714
|
-
const workerPath =
|
|
30998
|
+
const workerPath = path56.join(pkgRoot, "dist", "hooks", "ingest-worker.js");
|
|
30715
30999
|
if (!existsSync43(workerPath)) {
|
|
30716
31000
|
results.push({ name: "workers/ingest-worker", pass: false, detail: "ingest-worker.js not found" });
|
|
30717
31001
|
return results;
|
|
@@ -30726,14 +31010,14 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
30726
31010
|
detail: `Parse error: ${err instanceof Error ? err.message.slice(0, 200) : String(err)}`
|
|
30727
31011
|
});
|
|
30728
31012
|
}
|
|
30729
|
-
const hooksDir =
|
|
31013
|
+
const hooksDir = path56.join(pkgRoot, "dist", "hooks");
|
|
30730
31014
|
if (existsSync43(hooksDir)) {
|
|
30731
31015
|
const hookFiles = readdirSync14(hooksDir).filter((f) => f.endsWith(".js") && !f.endsWith(".js.map"));
|
|
30732
31016
|
let hooksPassed = 0;
|
|
30733
31017
|
const hooksFailed = [];
|
|
30734
31018
|
for (const hook of hookFiles) {
|
|
30735
31019
|
try {
|
|
30736
|
-
execSync15(`node --check "${
|
|
31020
|
+
execSync15(`node --check "${path56.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
30737
31021
|
hooksPassed++;
|
|
30738
31022
|
} catch {
|
|
30739
31023
|
hooksFailed.push(hook);
|
|
@@ -30757,8 +31041,8 @@ function checkWorkerSpawning(pkgRoot) {
|
|
|
30757
31041
|
}
|
|
30758
31042
|
function checkMcpTransport() {
|
|
30759
31043
|
const results = [];
|
|
30760
|
-
const pidPath =
|
|
30761
|
-
const tokenPath =
|
|
31044
|
+
const pidPath = path56.join(EXE_AI_DIR, "exed.pid");
|
|
31045
|
+
const tokenPath = path56.join(EXE_AI_DIR, "exed.token");
|
|
30762
31046
|
let daemonAlive = false;
|
|
30763
31047
|
if (existsSync43(pidPath)) {
|
|
30764
31048
|
try {
|
|
@@ -30805,7 +31089,7 @@ function checkMcpTransport() {
|
|
|
30805
31089
|
results.push({
|
|
30806
31090
|
name: "mcp/monitor-summary",
|
|
30807
31091
|
pass: true,
|
|
30808
|
-
detail: `Privacy-safe local monitor summary: ${
|
|
31092
|
+
detail: `Privacy-safe local monitor summary: ${path56.join(EXE_AI_DIR, "monitor", "mcp-transport-summary.json")}`
|
|
30809
31093
|
});
|
|
30810
31094
|
return results;
|
|
30811
31095
|
}
|
|
@@ -30863,7 +31147,7 @@ function checkClaudeCodeInstall() {
|
|
|
30863
31147
|
detail: "Failed to check claude binary path"
|
|
30864
31148
|
});
|
|
30865
31149
|
}
|
|
30866
|
-
const versionsDir =
|
|
31150
|
+
const versionsDir = path56.join(
|
|
30867
31151
|
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
30868
31152
|
".local",
|
|
30869
31153
|
"share",
|
|
@@ -30984,9 +31268,9 @@ __export(update_check_exports, {
|
|
|
30984
31268
|
});
|
|
30985
31269
|
import { execSync as execSync16 } from "child_process";
|
|
30986
31270
|
import { readFileSync as readFileSync37 } from "fs";
|
|
30987
|
-
import
|
|
31271
|
+
import path57 from "path";
|
|
30988
31272
|
function getLocalVersion(packageRoot) {
|
|
30989
|
-
const pkgPath =
|
|
31273
|
+
const pkgPath = path57.join(packageRoot, "package.json");
|
|
30990
31274
|
const pkg = JSON.parse(readFileSync37(pkgPath, "utf-8"));
|
|
30991
31275
|
return pkg.version;
|
|
30992
31276
|
}
|
|
@@ -31026,7 +31310,7 @@ var init_update_check = __esm({
|
|
|
31026
31310
|
// src/mcp/tools/cli-parity.ts
|
|
31027
31311
|
import { execFile as execFile2 } from "child_process";
|
|
31028
31312
|
import { promisify as promisify2 } from "util";
|
|
31029
|
-
import { z as
|
|
31313
|
+
import { z as z91 } from "zod";
|
|
31030
31314
|
async function runCommand(command, args, timeout = 6e4) {
|
|
31031
31315
|
const printable = [command, ...args].join(" ");
|
|
31032
31316
|
try {
|
|
@@ -31061,12 +31345,12 @@ function registerCliParityTools(server) {
|
|
|
31061
31345
|
title: "Doctor",
|
|
31062
31346
|
description: "Run exe-os doctor audit. Defaults to read-only diagnostics; optional dry-run/fix flags mirror CLI.",
|
|
31063
31347
|
inputSchema: {
|
|
31064
|
-
agent:
|
|
31065
|
-
project:
|
|
31066
|
-
verbose:
|
|
31067
|
-
conflicts:
|
|
31068
|
-
dry_run:
|
|
31069
|
-
fix:
|
|
31348
|
+
agent: z91.string().optional(),
|
|
31349
|
+
project: z91.string().optional(),
|
|
31350
|
+
verbose: z91.boolean().default(false),
|
|
31351
|
+
conflicts: z91.boolean().default(false),
|
|
31352
|
+
dry_run: z91.boolean().default(false),
|
|
31353
|
+
fix: z91.boolean().default(false)
|
|
31070
31354
|
}
|
|
31071
31355
|
}, async ({ agent, project, verbose, conflicts, dry_run, fix }) => {
|
|
31072
31356
|
const args = [];
|
|
@@ -31083,9 +31367,9 @@ function registerCliParityTools(server) {
|
|
|
31083
31367
|
title: "Rename Employee",
|
|
31084
31368
|
description: "Rename an employee using the same path as `exe-os rename <old> <new>`. Use for customer roster/identity renames.",
|
|
31085
31369
|
inputSchema: {
|
|
31086
|
-
old_name:
|
|
31087
|
-
new_name:
|
|
31088
|
-
dry_run:
|
|
31370
|
+
old_name: z91.string().min(1),
|
|
31371
|
+
new_name: z91.string().min(1),
|
|
31372
|
+
dry_run: z91.boolean().default(false)
|
|
31089
31373
|
}
|
|
31090
31374
|
}, async ({ old_name, new_name, dry_run }) => {
|
|
31091
31375
|
if (dry_run) {
|
|
@@ -31098,7 +31382,7 @@ function registerCliParityTools(server) {
|
|
|
31098
31382
|
server.registerTool("status_brief", {
|
|
31099
31383
|
title: "Status Brief",
|
|
31100
31384
|
description: "Return current employee/tmux status. Mirrors `exe-status` and supports optional deep view for one employee.",
|
|
31101
|
-
inputSchema: { employee:
|
|
31385
|
+
inputSchema: { employee: z91.string().optional() }
|
|
31102
31386
|
}, async ({ employee }) => {
|
|
31103
31387
|
const text3 = await status(employee);
|
|
31104
31388
|
return result2(text3, { ok: true, employee: employee ?? null });
|
|
@@ -31106,7 +31390,7 @@ function registerCliParityTools(server) {
|
|
|
31106
31390
|
server.registerTool("pending_work_summary", {
|
|
31107
31391
|
title: "Pending Work Summary",
|
|
31108
31392
|
description: "Return pending reviews, messages, and notifications using the same summaries as the CLI tools.",
|
|
31109
|
-
inputSchema: { agent:
|
|
31393
|
+
inputSchema: { agent: z91.string().optional() }
|
|
31110
31394
|
}, async ({ agent }) => {
|
|
31111
31395
|
const parts = await Promise.all([
|
|
31112
31396
|
runCommand("exe-pending-reviews", [], 3e4),
|
|
@@ -31127,7 +31411,7 @@ function registerCliParityTools(server) {
|
|
|
31127
31411
|
server.registerTool("key_rotation_preflight", {
|
|
31128
31412
|
title: "Key Rotation Preflight",
|
|
31129
31413
|
description: "Dry-run key rotation/update preflight. No destructive changes.",
|
|
31130
|
-
inputSchema: { mode:
|
|
31414
|
+
inputSchema: { mode: z91.enum(["rotate", "update"]).default("rotate") }
|
|
31131
31415
|
}, async ({ mode }) => {
|
|
31132
31416
|
const out = await runCommand("exe-os", ["key", mode, "--dry-run"], 6e4);
|
|
31133
31417
|
return result2(out.text, { ok: out.ok, command: out.command, mode }, !out.ok);
|
|
@@ -31146,11 +31430,11 @@ function registerCliParityTools(server) {
|
|
|
31146
31430
|
title: "Stack Update Check",
|
|
31147
31431
|
description: "Plan/check a customer stack update without applying Docker changes. Mirrors `exe-os stack-update --check`.",
|
|
31148
31432
|
inputSchema: {
|
|
31149
|
-
target:
|
|
31150
|
-
manifest:
|
|
31151
|
-
compose_file:
|
|
31152
|
-
env_file:
|
|
31153
|
-
deployment_persona:
|
|
31433
|
+
target: z91.string().optional(),
|
|
31434
|
+
manifest: z91.string().optional(),
|
|
31435
|
+
compose_file: z91.string().optional(),
|
|
31436
|
+
env_file: z91.string().optional(),
|
|
31437
|
+
deployment_persona: z91.enum(["customer", "askexe-control-plane"]).default("customer")
|
|
31154
31438
|
}
|
|
31155
31439
|
}, async ({ target, manifest, compose_file, env_file, deployment_persona }) => {
|
|
31156
31440
|
const args = ["stack-update", "--check", "--deployment-persona", deployment_persona];
|
|
@@ -31271,7 +31555,7 @@ var init_session_events = __esm({
|
|
|
31271
31555
|
});
|
|
31272
31556
|
|
|
31273
31557
|
// src/mcp/tools/get-session-events.ts
|
|
31274
|
-
import { z as
|
|
31558
|
+
import { z as z92 } from "zod";
|
|
31275
31559
|
function canReadAgent(activeRole, activeAgent, requestedAgent) {
|
|
31276
31560
|
return requestedAgent === activeAgent || activeRole === "COO" || activeRole === "CTO";
|
|
31277
31561
|
}
|
|
@@ -31295,11 +31579,11 @@ function registerGetSessionEvents(server) {
|
|
|
31295
31579
|
title: "Get Session Events",
|
|
31296
31580
|
description: "Return exact recent chronological user prompts, assistant responses, and tool calls from the append-only session journal. Use this when asked what happened last, not semantic memory search.",
|
|
31297
31581
|
inputSchema: {
|
|
31298
|
-
agent_id:
|
|
31299
|
-
session_id:
|
|
31582
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
31583
|
+
session_id: z92.string().optional().describe("Optional exact runtime session id."),
|
|
31300
31584
|
event_type: EVENT_TYPE.optional().describe("Filter to one event type."),
|
|
31301
|
-
project_name:
|
|
31302
|
-
limit:
|
|
31585
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects."),
|
|
31586
|
+
limit: z92.number().int().min(1).max(100).default(20).describe("Number of events to return.")
|
|
31303
31587
|
}
|
|
31304
31588
|
},
|
|
31305
31589
|
async ({ agent_id, session_id, event_type, project_name, limit }) => {
|
|
@@ -31335,8 +31619,8 @@ function registerGetLastAssistantResponse(server) {
|
|
|
31335
31619
|
title: "Get Last Assistant Response",
|
|
31336
31620
|
description: "Return the exact last assistant response for an agent from the session event journal. Use for 'what was the last thing you said?'",
|
|
31337
31621
|
inputSchema: {
|
|
31338
|
-
agent_id:
|
|
31339
|
-
project_name:
|
|
31622
|
+
agent_id: z92.string().optional().describe("Agent to inspect. Defaults to active agent. COO/CTO may inspect others."),
|
|
31623
|
+
project_name: z92.string().optional().describe("Optional project filter. Pass 'all' for all projects.")
|
|
31340
31624
|
}
|
|
31341
31625
|
},
|
|
31342
31626
|
async ({ agent_id, project_name }) => {
|
|
@@ -31371,7 +31655,7 @@ var init_get_session_events = __esm({
|
|
|
31371
31655
|
init_active_agent();
|
|
31372
31656
|
init_fast_db_init();
|
|
31373
31657
|
init_session_events();
|
|
31374
|
-
EVENT_TYPE =
|
|
31658
|
+
EVENT_TYPE = z92.enum([
|
|
31375
31659
|
"user_prompt",
|
|
31376
31660
|
"assistant_response",
|
|
31377
31661
|
"tool_call",
|
|
@@ -31382,25 +31666,96 @@ var init_get_session_events = __esm({
|
|
|
31382
31666
|
});
|
|
31383
31667
|
|
|
31384
31668
|
// src/lib/code-context-index.ts
|
|
31385
|
-
import
|
|
31386
|
-
import
|
|
31669
|
+
import crypto21 from "crypto";
|
|
31670
|
+
import path58 from "path";
|
|
31387
31671
|
import { existsSync as existsSync44, mkdirSync as mkdirSync22, readFileSync as readFileSync38, readdirSync as readdirSync15, statSync as statSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
31388
31672
|
import { spawnSync } from "child_process";
|
|
31673
|
+
function vectorStorePath(projectRoot) {
|
|
31674
|
+
const rootHash = hashText(projectRoot).slice(0, 16);
|
|
31675
|
+
return path58.join(indexDir(), `${rootHash}.vectors.json`);
|
|
31676
|
+
}
|
|
31677
|
+
function loadVectorStore(projectRoot) {
|
|
31678
|
+
const file = vectorStorePath(projectRoot);
|
|
31679
|
+
if (!existsSync44(file)) return null;
|
|
31680
|
+
try {
|
|
31681
|
+
const parsed = JSON.parse(readFileSync38(file, "utf8"));
|
|
31682
|
+
if (parsed.version !== VECTOR_STORE_VERSION) return null;
|
|
31683
|
+
return parsed;
|
|
31684
|
+
} catch {
|
|
31685
|
+
return null;
|
|
31686
|
+
}
|
|
31687
|
+
}
|
|
31688
|
+
function saveVectorStore(projectRoot, store) {
|
|
31689
|
+
writeFileSync25(vectorStorePath(projectRoot), JSON.stringify(store));
|
|
31690
|
+
}
|
|
31691
|
+
function cosineSimilarity3(a, b) {
|
|
31692
|
+
let dot = 0, normA = 0, normB = 0;
|
|
31693
|
+
for (let i = 0; i < a.length; i++) {
|
|
31694
|
+
dot += a[i] * b[i];
|
|
31695
|
+
normA += a[i] * a[i];
|
|
31696
|
+
normB += b[i] * b[i];
|
|
31697
|
+
}
|
|
31698
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
31699
|
+
return denom === 0 ? 0 : dot / denom;
|
|
31700
|
+
}
|
|
31701
|
+
async function embedSymbols(index) {
|
|
31702
|
+
const rootHash = hashText(index.projectRoot).slice(0, 16);
|
|
31703
|
+
const existing = loadVectorStore(index.projectRoot);
|
|
31704
|
+
const store = {
|
|
31705
|
+
version: VECTOR_STORE_VERSION,
|
|
31706
|
+
projectRootHash: rootHash,
|
|
31707
|
+
vectors: {}
|
|
31708
|
+
};
|
|
31709
|
+
const allSymbols = [];
|
|
31710
|
+
for (const file of Object.values(index.files)) {
|
|
31711
|
+
for (const symbol of file.symbols) {
|
|
31712
|
+
if (existing?.vectors[symbol.id]) {
|
|
31713
|
+
store.vectors[symbol.id] = existing.vectors[symbol.id];
|
|
31714
|
+
} else {
|
|
31715
|
+
allSymbols.push({ id: symbol.id, text: symbol.summary || `${symbol.kind} ${symbol.name} in ${symbol.filePath}` });
|
|
31716
|
+
}
|
|
31717
|
+
}
|
|
31718
|
+
}
|
|
31719
|
+
if (allSymbols.length === 0) {
|
|
31720
|
+
saveVectorStore(index.projectRoot, store);
|
|
31721
|
+
return store;
|
|
31722
|
+
}
|
|
31723
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
31724
|
+
if (!connected) {
|
|
31725
|
+
saveVectorStore(index.projectRoot, store);
|
|
31726
|
+
return store;
|
|
31727
|
+
}
|
|
31728
|
+
for (let i = 0; i < allSymbols.length; i += EMBED_BATCH_SIZE) {
|
|
31729
|
+
const batch = allSymbols.slice(i, i + EMBED_BATCH_SIZE);
|
|
31730
|
+
const texts = batch.map((s) => s.text);
|
|
31731
|
+
try {
|
|
31732
|
+
const vectors = await embedBatchViaClient(texts, "low");
|
|
31733
|
+
if (vectors && vectors.length === batch.length) {
|
|
31734
|
+
for (let j = 0; j < batch.length; j++) {
|
|
31735
|
+
store.vectors[batch[j].id] = vectors[j];
|
|
31736
|
+
}
|
|
31737
|
+
}
|
|
31738
|
+
} catch {
|
|
31739
|
+
}
|
|
31740
|
+
}
|
|
31741
|
+
saveVectorStore(index.projectRoot, store);
|
|
31742
|
+
return store;
|
|
31743
|
+
}
|
|
31389
31744
|
function normalizeProjectRoot(projectRoot) {
|
|
31390
|
-
return
|
|
31745
|
+
return path58.resolve(projectRoot || process.cwd());
|
|
31391
31746
|
}
|
|
31392
31747
|
function hashText(text3) {
|
|
31393
|
-
return
|
|
31748
|
+
return crypto21.createHash("sha256").update(text3).digest("hex");
|
|
31394
31749
|
}
|
|
31395
31750
|
function indexDir() {
|
|
31396
|
-
const dir =
|
|
31751
|
+
const dir = path58.join(EXE_AI_DIR, "code-context");
|
|
31397
31752
|
mkdirSync22(dir, { recursive: true });
|
|
31398
31753
|
return dir;
|
|
31399
31754
|
}
|
|
31400
31755
|
function getCodeContextIndexPath(projectRoot) {
|
|
31401
31756
|
const root = normalizeProjectRoot(projectRoot);
|
|
31402
31757
|
const rootHash = hashText(root).slice(0, 16);
|
|
31403
|
-
return
|
|
31758
|
+
return path58.join(indexDir(), `${rootHash}.json`);
|
|
31404
31759
|
}
|
|
31405
31760
|
function currentBranch(projectRoot) {
|
|
31406
31761
|
const result3 = spawnSync("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
@@ -31413,8 +31768,8 @@ function shouldIgnore(relPath) {
|
|
|
31413
31768
|
}
|
|
31414
31769
|
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
31415
31770
|
for (const entry of readdirSync15(dir, { withFileTypes: true })) {
|
|
31416
|
-
const abs =
|
|
31417
|
-
const rel =
|
|
31771
|
+
const abs = path58.join(dir, entry.name);
|
|
31772
|
+
const rel = path58.relative(projectRoot, abs).replaceAll(path58.sep, "/");
|
|
31418
31773
|
if (shouldIgnore(rel)) continue;
|
|
31419
31774
|
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
31420
31775
|
else if (entry.isFile()) out.push(rel);
|
|
@@ -31430,7 +31785,7 @@ function listCodeFiles(projectRoot, maxFiles) {
|
|
|
31430
31785
|
const rg = spawnSync("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
31431
31786
|
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
31432
31787
|
}
|
|
31433
|
-
return files.map((file) => file.replaceAll(
|
|
31788
|
+
return files.map((file) => file.replaceAll(path58.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
31434
31789
|
}
|
|
31435
31790
|
function parseImportPaths2(importText) {
|
|
31436
31791
|
const paths = [];
|
|
@@ -31443,13 +31798,13 @@ function parseImportPaths2(importText) {
|
|
|
31443
31798
|
}
|
|
31444
31799
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
31445
31800
|
if (!importPath.startsWith(".")) return null;
|
|
31446
|
-
const base =
|
|
31801
|
+
const base = path58.posix.normalize(path58.posix.join(path58.posix.dirname(fromFile.replaceAll(path58.sep, "/")), importPath));
|
|
31447
31802
|
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
31448
31803
|
const candidates = [base];
|
|
31449
31804
|
for (const ext of ["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "cs", "cpp", "c", "rb", "php", "swift", "kt", "scala", "sql", "md", "json", "yaml", "yml"]) {
|
|
31450
31805
|
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
31451
31806
|
}
|
|
31452
|
-
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(
|
|
31807
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path58.posix.join(base, indexName));
|
|
31453
31808
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
31454
31809
|
}
|
|
31455
31810
|
function symbolId(filePath, chunk) {
|
|
@@ -31470,7 +31825,7 @@ function saveIndex(index) {
|
|
|
31470
31825
|
writeFileSync25(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
|
|
31471
31826
|
}
|
|
31472
31827
|
function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
31473
|
-
const absPath =
|
|
31828
|
+
const absPath = path58.join(projectRoot, relPath);
|
|
31474
31829
|
let stat;
|
|
31475
31830
|
try {
|
|
31476
31831
|
stat = statSync10(absPath);
|
|
@@ -31508,13 +31863,13 @@ function buildCodeContextIndex(options = {}) {
|
|
|
31508
31863
|
const branch = currentBranch(projectRoot);
|
|
31509
31864
|
const previous = options.force ? null : loadIndex(projectRoot);
|
|
31510
31865
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
31511
|
-
const allFiles = new Set(files.map((file) => file.replaceAll(
|
|
31866
|
+
const allFiles = new Set(files.map((file) => file.replaceAll(path58.sep, "/")));
|
|
31512
31867
|
const fileRecords = {};
|
|
31513
31868
|
let rebuiltFiles = 0;
|
|
31514
31869
|
let reusedFiles = 0;
|
|
31515
31870
|
let skippedFiles = 0;
|
|
31516
31871
|
for (const rel of files) {
|
|
31517
|
-
const normalized = rel.replaceAll(
|
|
31872
|
+
const normalized = rel.replaceAll(path58.sep, "/");
|
|
31518
31873
|
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
31519
31874
|
if (record) {
|
|
31520
31875
|
fileRecords[normalized] = record;
|
|
@@ -31543,11 +31898,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
31543
31898
|
if (loaded) {
|
|
31544
31899
|
const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
|
|
31545
31900
|
const unchanged = currentFiles.every((rel) => {
|
|
31546
|
-
const normalized = rel.replaceAll(
|
|
31901
|
+
const normalized = rel.replaceAll(path58.sep, "/");
|
|
31547
31902
|
const existing = loaded.files[normalized];
|
|
31548
31903
|
if (!existing) return false;
|
|
31549
31904
|
try {
|
|
31550
|
-
const stat = statSync10(
|
|
31905
|
+
const stat = statSync10(path58.join(projectRoot, normalized));
|
|
31551
31906
|
return stat.mtimeMs === existing.mtimeMs && stat.size === existing.size;
|
|
31552
31907
|
} catch {
|
|
31553
31908
|
return false;
|
|
@@ -31600,9 +31955,9 @@ function globToRegex(pattern) {
|
|
|
31600
31955
|
}
|
|
31601
31956
|
function matchesPath(filePath, patterns) {
|
|
31602
31957
|
if (!patterns || patterns.length === 0) return true;
|
|
31603
|
-
const normalized = filePath.replaceAll(
|
|
31958
|
+
const normalized = filePath.replaceAll(path58.sep, "/");
|
|
31604
31959
|
return patterns.some((pattern) => {
|
|
31605
|
-
const p = pattern.replaceAll(
|
|
31960
|
+
const p = pattern.replaceAll(path58.sep, "/").replace(/^\.\//, "");
|
|
31606
31961
|
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
31607
31962
|
});
|
|
31608
31963
|
}
|
|
@@ -31661,7 +32016,7 @@ function filteredFiles(index, options = {}) {
|
|
|
31661
32016
|
return matchesPath(file.path, options.paths);
|
|
31662
32017
|
});
|
|
31663
32018
|
}
|
|
31664
|
-
function
|
|
32019
|
+
function lexicalSearch(query, options = {}) {
|
|
31665
32020
|
const terms = tokenize(query);
|
|
31666
32021
|
if (terms.length === 0) return [];
|
|
31667
32022
|
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
@@ -31687,6 +32042,81 @@ function searchCodeContext(query, options = {}) {
|
|
|
31687
32042
|
const limit = options.limit ?? 20;
|
|
31688
32043
|
return results.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
31689
32044
|
}
|
|
32045
|
+
function searchCodeContext(query, options = {}) {
|
|
32046
|
+
return lexicalSearch(query, options);
|
|
32047
|
+
}
|
|
32048
|
+
async function searchCodeContextSemantic(query, options = {}) {
|
|
32049
|
+
const terms = tokenize(query);
|
|
32050
|
+
if (terms.length === 0) return [];
|
|
32051
|
+
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
32052
|
+
const projectRoot = normalizeProjectRoot(options.projectRoot);
|
|
32053
|
+
const vectorStore = loadVectorStore(projectRoot);
|
|
32054
|
+
if (!vectorStore || Object.keys(vectorStore.vectors).length === 0) {
|
|
32055
|
+
return lexicalSearch(query, options);
|
|
32056
|
+
}
|
|
32057
|
+
let queryVector = null;
|
|
32058
|
+
try {
|
|
32059
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
32060
|
+
if (connected) {
|
|
32061
|
+
const result3 = await embedBatchViaClient([query], "high");
|
|
32062
|
+
if (result3 && result3.length === 1) queryVector = result3[0];
|
|
32063
|
+
}
|
|
32064
|
+
} catch {
|
|
32065
|
+
}
|
|
32066
|
+
if (!queryVector) return lexicalSearch(query, options);
|
|
32067
|
+
const files = filteredFiles(index, options);
|
|
32068
|
+
const candidates = [];
|
|
32069
|
+
for (const file of files) {
|
|
32070
|
+
for (const symbol of file.symbols) {
|
|
32071
|
+
const lexical = scoreSymbol(symbol, terms);
|
|
32072
|
+
const vec = vectorStore.vectors[symbol.id];
|
|
32073
|
+
const vectorScore = vec ? cosineSimilarity3(queryVector, vec) : 0;
|
|
32074
|
+
if (lexical.score > 0 || vectorScore > 0.3) {
|
|
32075
|
+
candidates.push({
|
|
32076
|
+
symbol,
|
|
32077
|
+
lexicalScore: lexical.score,
|
|
32078
|
+
vectorScore,
|
|
32079
|
+
matches: lexical.matches
|
|
32080
|
+
});
|
|
32081
|
+
}
|
|
32082
|
+
}
|
|
32083
|
+
}
|
|
32084
|
+
const byLexical = [...candidates].sort((a, b) => b.lexicalScore - a.lexicalScore);
|
|
32085
|
+
const byVector = [...candidates].sort((a, b) => b.vectorScore - a.vectorScore);
|
|
32086
|
+
const lexicalRank = /* @__PURE__ */ new Map();
|
|
32087
|
+
const vectorRank = /* @__PURE__ */ new Map();
|
|
32088
|
+
byLexical.forEach((c, i) => lexicalRank.set(c.symbol.id, i + 1));
|
|
32089
|
+
byVector.forEach((c, i) => vectorRank.set(c.symbol.id, i + 1));
|
|
32090
|
+
const VECTOR_WEIGHT = 0.6;
|
|
32091
|
+
const LEXICAL_WEIGHT = 0.4;
|
|
32092
|
+
const fused = candidates.map((c) => {
|
|
32093
|
+
const lRank = lexicalRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
32094
|
+
const vRank = vectorRank.get(c.symbol.id) ?? candidates.length + 1;
|
|
32095
|
+
const rrfScore = VECTOR_WEIGHT * (1 / (RRF_K2 + vRank)) + LEXICAL_WEIGHT * (1 / (RRF_K2 + lRank));
|
|
32096
|
+
return {
|
|
32097
|
+
symbol: c.symbol,
|
|
32098
|
+
score: rrfScore,
|
|
32099
|
+
matches: c.vectorScore > 0.3 ? [...c.matches, `semantic=${c.vectorScore.toFixed(3)}`] : c.matches,
|
|
32100
|
+
filePath: c.symbol.filePath,
|
|
32101
|
+
language: c.symbol.language,
|
|
32102
|
+
content: c.symbol.text,
|
|
32103
|
+
startLine: c.symbol.startLine,
|
|
32104
|
+
endLine: c.symbol.endLine
|
|
32105
|
+
};
|
|
32106
|
+
});
|
|
32107
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
32108
|
+
const limit = options.limit ?? 20;
|
|
32109
|
+
return fused.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
32110
|
+
}
|
|
32111
|
+
async function buildCodeContextIndexWithEmbeddings(options = {}) {
|
|
32112
|
+
const index = buildCodeContextIndex(options);
|
|
32113
|
+
const existingStore = loadVectorStore(index.projectRoot);
|
|
32114
|
+
const existingCount = existingStore ? Object.keys(existingStore.vectors).length : 0;
|
|
32115
|
+
const store = await embedSymbols(index);
|
|
32116
|
+
const vectorCount = Object.keys(store.vectors).length;
|
|
32117
|
+
const newEmbeddings = vectorCount - Math.min(existingCount, vectorCount);
|
|
32118
|
+
return { index, vectorCount, newEmbeddings };
|
|
32119
|
+
}
|
|
31690
32120
|
function dependentsMap(index) {
|
|
31691
32121
|
const map = /* @__PURE__ */ new Map();
|
|
31692
32122
|
for (const file of Object.values(index.files)) {
|
|
@@ -31720,7 +32150,7 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
31720
32150
|
}
|
|
31721
32151
|
function resolveTargetFile(index, input) {
|
|
31722
32152
|
if (input.filePath) {
|
|
31723
|
-
const normalized = input.filePath.replaceAll(
|
|
32153
|
+
const normalized = input.filePath.replaceAll(path58.sep, "/").replace(/^\.\//, "");
|
|
31724
32154
|
if (index.files[normalized]) return { filePath: normalized, target: normalized };
|
|
31725
32155
|
const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
|
|
31726
32156
|
if (suffix) return { filePath: suffix, target: input.filePath };
|
|
@@ -31750,7 +32180,7 @@ function analyzeBlastRadius(input) {
|
|
|
31750
32180
|
}
|
|
31751
32181
|
}
|
|
31752
32182
|
}
|
|
31753
|
-
const targetBase =
|
|
32183
|
+
const targetBase = path58.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
|
|
31754
32184
|
const symbolLower = input.symbol?.toLowerCase();
|
|
31755
32185
|
const tests = Object.keys(index.files).filter((file) => {
|
|
31756
32186
|
const lower = file.toLowerCase();
|
|
@@ -31778,20 +32208,24 @@ function getCodeContextStats(options = {}) {
|
|
|
31778
32208
|
indexPath: getCodeContextIndexPath(index.projectRoot)
|
|
31779
32209
|
};
|
|
31780
32210
|
}
|
|
31781
|
-
var INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS;
|
|
32211
|
+
var VECTOR_STORE_VERSION, EMBED_BATCH_SIZE, INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS, RRF_K2;
|
|
31782
32212
|
var init_code_context_index = __esm({
|
|
31783
32213
|
"src/lib/code-context-index.ts"() {
|
|
31784
32214
|
"use strict";
|
|
31785
32215
|
init_config();
|
|
31786
32216
|
init_code_chunker();
|
|
32217
|
+
init_exe_daemon_client();
|
|
32218
|
+
VECTOR_STORE_VERSION = 1;
|
|
32219
|
+
EMBED_BATCH_SIZE = 64;
|
|
31787
32220
|
INDEX_VERSION = 2;
|
|
31788
32221
|
DEFAULT_MAX_FILES = 5e3;
|
|
31789
32222
|
IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
32223
|
+
RRF_K2 = 60;
|
|
31790
32224
|
}
|
|
31791
32225
|
});
|
|
31792
32226
|
|
|
31793
32227
|
// src/mcp/tools/code-context.ts
|
|
31794
|
-
import { z as
|
|
32228
|
+
import { z as z93 } from "zod";
|
|
31795
32229
|
function errorResult10(text3) {
|
|
31796
32230
|
return { content: [{ type: "text", text: text3 }], isError: true };
|
|
31797
32231
|
}
|
|
@@ -31801,23 +32235,24 @@ function jsonResult(value) {
|
|
|
31801
32235
|
function registerCodeContext(server) {
|
|
31802
32236
|
server.registerTool("code_context", {
|
|
31803
32237
|
title: "Code Context",
|
|
31804
|
-
description: "Persistent codebase context engine. One consolidated tool to avoid MCP bloat. Actions: index, search, trace, blast_radius, stats.",
|
|
32238
|
+
description: "Persistent codebase context engine with semantic vector search. One consolidated tool to avoid MCP bloat. Actions: index (structural only), index_embed (structural + vector embeddings), search (semantic+lexical hybrid), trace, blast_radius, stats. Search uses RRF fusion of Jina v5 embeddings (cosine similarity) + lexical scoring. Falls back to lexical if daemon unavailable.",
|
|
31805
32239
|
inputSchema: {
|
|
31806
|
-
action:
|
|
31807
|
-
project_root:
|
|
31808
|
-
query:
|
|
31809
|
-
symbol:
|
|
31810
|
-
file_path:
|
|
31811
|
-
force:
|
|
31812
|
-
limit:
|
|
31813
|
-
offset:
|
|
31814
|
-
refresh_index:
|
|
31815
|
-
languages:
|
|
31816
|
-
paths:
|
|
31817
|
-
depth:
|
|
31818
|
-
max_files:
|
|
31819
|
-
|
|
31820
|
-
|
|
32240
|
+
action: z93.enum(["index", "index_embed", "search", "trace", "blast_radius", "stats"]).describe("Code context operation. index_embed = index + generate embeddings for semantic search."),
|
|
32241
|
+
project_root: z93.string().optional().describe("Repository root. Defaults to current working directory."),
|
|
32242
|
+
query: z93.string().optional().describe("Natural language search query (e.g. 'authentication logic', 'database migration'). Semantic search finds conceptual matches, not just keywords."),
|
|
32243
|
+
symbol: z93.string().optional().describe("Symbol/function/class/type name for trace or blast_radius"),
|
|
32244
|
+
file_path: z93.string().optional().describe("File path for blast_radius"),
|
|
32245
|
+
force: z93.boolean().optional().describe("Force rebuild before answering"),
|
|
32246
|
+
limit: z93.coerce.number().int().min(1).max(100).optional().describe("Max results"),
|
|
32247
|
+
offset: z93.coerce.number().int().min(0).optional().describe("Search pagination offset"),
|
|
32248
|
+
refresh_index: z93.boolean().optional().describe("Refresh/rebuild index before searching"),
|
|
32249
|
+
languages: z93.array(z93.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
|
|
32250
|
+
paths: z93.array(z93.string()).optional().describe("Path/glob filters"),
|
|
32251
|
+
depth: z93.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
|
|
32252
|
+
max_files: z93.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index"),
|
|
32253
|
+
lexical_only: z93.boolean().optional().describe("Force lexical-only search (skip vector similarity). Default: false \u2014 uses semantic hybrid search.")
|
|
32254
|
+
}
|
|
32255
|
+
}, async ({ action, project_root, query, symbol, file_path, force, limit, offset, refresh_index, languages, paths, depth, max_files, lexical_only }) => {
|
|
31821
32256
|
const opts = { projectRoot: project_root, force, maxFiles: max_files };
|
|
31822
32257
|
if (action === "index") {
|
|
31823
32258
|
const index = buildCodeContextIndex(opts);
|
|
@@ -31827,7 +32262,24 @@ function registerCodeContext(server) {
|
|
|
31827
32262
|
indexedAt: index.indexedAt,
|
|
31828
32263
|
files: Object.keys(index.files).length,
|
|
31829
32264
|
symbols: Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0),
|
|
31830
|
-
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0)
|
|
32265
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
32266
|
+
note: "Structural index only. Use action=index_embed to also generate vector embeddings for semantic search."
|
|
32267
|
+
});
|
|
32268
|
+
}
|
|
32269
|
+
if (action === "index_embed") {
|
|
32270
|
+
const { index, vectorCount, newEmbeddings } = await buildCodeContextIndexWithEmbeddings(opts);
|
|
32271
|
+
const totalSymbols = Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0);
|
|
32272
|
+
return jsonResult({
|
|
32273
|
+
projectRoot: index.projectRoot,
|
|
32274
|
+
branch: index.branch,
|
|
32275
|
+
indexedAt: index.indexedAt,
|
|
32276
|
+
files: Object.keys(index.files).length,
|
|
32277
|
+
symbols: totalSymbols,
|
|
32278
|
+
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
32279
|
+
vectorCount,
|
|
32280
|
+
newEmbeddings,
|
|
32281
|
+
embeddingCoverage: totalSymbols > 0 ? `${(vectorCount / totalSymbols * 100).toFixed(1)}%` : "0%",
|
|
32282
|
+
note: "Structural index + vector embeddings. Semantic search is now available."
|
|
31831
32283
|
});
|
|
31832
32284
|
}
|
|
31833
32285
|
if (action === "stats") {
|
|
@@ -31835,14 +32287,28 @@ function registerCodeContext(server) {
|
|
|
31835
32287
|
}
|
|
31836
32288
|
if (action === "search") {
|
|
31837
32289
|
if (!query) return errorResult10('code_context action "search" requires query');
|
|
32290
|
+
const searchOpts = { ...opts, limit, offset, refreshIndex: refresh_index, languages, paths };
|
|
32291
|
+
if (lexical_only) {
|
|
32292
|
+
return jsonResult({
|
|
32293
|
+
query,
|
|
32294
|
+
mode: "lexical",
|
|
32295
|
+
limit: limit ?? 20,
|
|
32296
|
+
offset: offset ?? 0,
|
|
32297
|
+
languages: languages ?? [],
|
|
32298
|
+
paths: paths ?? [],
|
|
32299
|
+
results: searchCodeContext(query, searchOpts)
|
|
32300
|
+
});
|
|
32301
|
+
}
|
|
32302
|
+
const results = await searchCodeContextSemantic(query, searchOpts);
|
|
32303
|
+
const hasSemantic = results.some((r) => r.matches.some((m) => m.startsWith("semantic=")));
|
|
31838
32304
|
return jsonResult({
|
|
31839
32305
|
query,
|
|
32306
|
+
mode: hasSemantic ? "semantic+lexical" : "lexical-fallback",
|
|
31840
32307
|
limit: limit ?? 20,
|
|
31841
32308
|
offset: offset ?? 0,
|
|
31842
|
-
refresh_index: refresh_index ?? false,
|
|
31843
32309
|
languages: languages ?? [],
|
|
31844
32310
|
paths: paths ?? [],
|
|
31845
|
-
results
|
|
32311
|
+
results
|
|
31846
32312
|
});
|
|
31847
32313
|
}
|
|
31848
32314
|
if (action === "trace") {
|
|
@@ -31866,7 +32332,7 @@ var init_code_context = __esm({
|
|
|
31866
32332
|
});
|
|
31867
32333
|
|
|
31868
32334
|
// src/mcp/tools/support-inbox.ts
|
|
31869
|
-
import { z as
|
|
32335
|
+
import { z as z94 } from "zod";
|
|
31870
32336
|
function adminToken() {
|
|
31871
32337
|
return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN || process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
31872
32338
|
}
|
|
@@ -31905,9 +32371,9 @@ function registerListBugReports(server) {
|
|
|
31905
32371
|
title: "List Bug Reports",
|
|
31906
32372
|
description: "AskExe-internal only: list incoming customer bug reports from the support inbox.",
|
|
31907
32373
|
inputSchema: {
|
|
31908
|
-
status:
|
|
31909
|
-
severity:
|
|
31910
|
-
limit:
|
|
32374
|
+
status: z94.enum(["all", "open", "triaged", "fixed", "closed", "wontfix"]).default("open"),
|
|
32375
|
+
severity: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
32376
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
31911
32377
|
}
|
|
31912
32378
|
},
|
|
31913
32379
|
async ({ status: status2, severity, limit }) => {
|
|
@@ -31926,7 +32392,7 @@ function registerGetBugReport(server) {
|
|
|
31926
32392
|
{
|
|
31927
32393
|
title: "Get Bug Report",
|
|
31928
32394
|
description: "AskExe-internal only: fetch one customer bug report with full markdown payload.",
|
|
31929
|
-
inputSchema: { id:
|
|
32395
|
+
inputSchema: { id: z94.string().min(8) }
|
|
31930
32396
|
},
|
|
31931
32397
|
async ({ id }) => {
|
|
31932
32398
|
const data = await requestJson(`${endpoint()}/${encodeURIComponent(id)}`);
|
|
@@ -31941,12 +32407,12 @@ function registerTriageBugReport(server) {
|
|
|
31941
32407
|
title: "Triage Bug Report",
|
|
31942
32408
|
description: "AskExe-internal only: update bug report status and link task/commit/release metadata.",
|
|
31943
32409
|
inputSchema: {
|
|
31944
|
-
id:
|
|
32410
|
+
id: z94.string().min(8),
|
|
31945
32411
|
status: STATUS.optional(),
|
|
31946
|
-
triage_notes:
|
|
31947
|
-
linked_task_id:
|
|
31948
|
-
linked_commit:
|
|
31949
|
-
fixed_version:
|
|
32412
|
+
triage_notes: z94.string().optional(),
|
|
32413
|
+
linked_task_id: z94.string().optional(),
|
|
32414
|
+
linked_commit: z94.string().optional(),
|
|
32415
|
+
fixed_version: z94.string().optional()
|
|
31950
32416
|
}
|
|
31951
32417
|
},
|
|
31952
32418
|
async ({ id, status: status2, triage_notes, linked_task_id, linked_commit, fixed_version }) => {
|
|
@@ -31958,12 +32424,75 @@ function registerTriageBugReport(server) {
|
|
|
31958
32424
|
}
|
|
31959
32425
|
);
|
|
31960
32426
|
}
|
|
31961
|
-
|
|
32427
|
+
function featureEndpoint() {
|
|
32428
|
+
return endpoint().replace(/\/bug-reports\/?$/, "/feature-requests");
|
|
32429
|
+
}
|
|
32430
|
+
function registerListFeatureRequests(server) {
|
|
32431
|
+
server.registerTool(
|
|
32432
|
+
"list_feature_requests",
|
|
32433
|
+
{
|
|
32434
|
+
title: "List Feature Requests",
|
|
32435
|
+
description: "AskExe-internal only: list incoming customer feature requests from the support inbox.",
|
|
32436
|
+
inputSchema: {
|
|
32437
|
+
status: z94.enum(["all", "open", "planned", "in_progress", "shipped", "closed", "wontdo"]).default("open"),
|
|
32438
|
+
priority: z94.enum(["p0", "p1", "p2", "p3"]).optional(),
|
|
32439
|
+
limit: z94.number().int().min(1).max(100).default(25)
|
|
32440
|
+
}
|
|
32441
|
+
},
|
|
32442
|
+
async ({ status: status2, priority, limit }) => {
|
|
32443
|
+
const url = new URL(featureEndpoint());
|
|
32444
|
+
url.searchParams.set("status", status2);
|
|
32445
|
+
url.searchParams.set("limit", String(limit));
|
|
32446
|
+
if (priority) url.searchParams.set("priority", priority);
|
|
32447
|
+
const data = await requestJson(url.toString());
|
|
32448
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32449
|
+
}
|
|
32450
|
+
);
|
|
32451
|
+
}
|
|
32452
|
+
function registerGetFeatureRequest(server) {
|
|
32453
|
+
server.registerTool(
|
|
32454
|
+
"get_feature_request",
|
|
32455
|
+
{
|
|
32456
|
+
title: "Get Feature Request",
|
|
32457
|
+
description: "AskExe-internal only: fetch one customer feature request with full payload.",
|
|
32458
|
+
inputSchema: { id: z94.string().min(8) }
|
|
32459
|
+
},
|
|
32460
|
+
async ({ id }) => {
|
|
32461
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`);
|
|
32462
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32463
|
+
}
|
|
32464
|
+
);
|
|
32465
|
+
}
|
|
32466
|
+
function registerTriageFeatureRequest(server) {
|
|
32467
|
+
server.registerTool(
|
|
32468
|
+
"triage_feature_request",
|
|
32469
|
+
{
|
|
32470
|
+
title: "Triage Feature Request",
|
|
32471
|
+
description: "AskExe-internal only: update feature request status, response notes, and version metadata.",
|
|
32472
|
+
inputSchema: {
|
|
32473
|
+
id: z94.string().min(8),
|
|
32474
|
+
status: FEATURE_STATUS.optional(),
|
|
32475
|
+
response_notes: z94.string().optional(),
|
|
32476
|
+
target_version: z94.string().optional(),
|
|
32477
|
+
shipped_version: z94.string().optional()
|
|
32478
|
+
}
|
|
32479
|
+
},
|
|
32480
|
+
async ({ id, status: status2, response_notes, target_version, shipped_version }) => {
|
|
32481
|
+
const data = await requestJson(`${featureEndpoint()}/${encodeURIComponent(id)}`, {
|
|
32482
|
+
method: "PATCH",
|
|
32483
|
+
body: JSON.stringify({ status: status2, response_notes, target_version, shipped_version })
|
|
32484
|
+
});
|
|
32485
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
32486
|
+
}
|
|
32487
|
+
);
|
|
32488
|
+
}
|
|
32489
|
+
var DEFAULT_ENDPOINT, STATUS, FEATURE_STATUS;
|
|
31962
32490
|
var init_support_inbox = __esm({
|
|
31963
32491
|
"src/mcp/tools/support-inbox.ts"() {
|
|
31964
32492
|
"use strict";
|
|
31965
32493
|
DEFAULT_ENDPOINT = "https://askexe.com/admin/support/bug-reports";
|
|
31966
|
-
STATUS =
|
|
32494
|
+
STATUS = z94.enum(["open", "triaged", "fixed", "closed", "wontfix"]);
|
|
32495
|
+
FEATURE_STATUS = z94.enum(["open", "planned", "in_progress", "shipped", "closed", "wontdo"]);
|
|
31967
32496
|
}
|
|
31968
32497
|
});
|
|
31969
32498
|
|
|
@@ -32299,6 +32828,7 @@ function registerAllTools(server) {
|
|
|
32299
32828
|
gate("registerStoreDecision", registerStoreDecision);
|
|
32300
32829
|
gate("registerGetDecision", registerGetDecision);
|
|
32301
32830
|
gate("registerCreateBugReport", registerCreateBugReport);
|
|
32831
|
+
gate("registerCreateFeatureRequest", registerCreateFeatureRequest);
|
|
32302
32832
|
gate("registerSupportTools", registerSupportTools);
|
|
32303
32833
|
gate("registerCliParityTools", registerCliParityTools);
|
|
32304
32834
|
gate("registerGetSessionEvents", registerGetSessionEvents);
|
|
@@ -32308,6 +32838,9 @@ function registerAllTools(server) {
|
|
|
32308
32838
|
gate("registerListBugReports", registerListBugReports);
|
|
32309
32839
|
gate("registerGetBugReport", registerGetBugReport);
|
|
32310
32840
|
gate("registerTriageBugReport", registerTriageBugReport);
|
|
32841
|
+
gate("registerListFeatureRequests", registerListFeatureRequests);
|
|
32842
|
+
gate("registerGetFeatureRequest", registerGetFeatureRequest);
|
|
32843
|
+
gate("registerTriageFeatureRequest", registerTriageFeatureRequest);
|
|
32311
32844
|
}
|
|
32312
32845
|
if (exposeLegacyConfig) {
|
|
32313
32846
|
gate("registerGetAgentSpend", registerGetAgentSpend);
|
|
@@ -32450,6 +32983,7 @@ var init_register_tools = __esm({
|
|
|
32450
32983
|
init_query_company_brain();
|
|
32451
32984
|
init_company_actions();
|
|
32452
32985
|
init_create_bug_report();
|
|
32986
|
+
init_create_feature_request();
|
|
32453
32987
|
init_support();
|
|
32454
32988
|
init_cli_parity();
|
|
32455
32989
|
init_get_session_events();
|
|
@@ -32680,7 +33214,7 @@ __export(task_enforcement_exports, {
|
|
|
32680
33214
|
sendNudge: () => sendNudge
|
|
32681
33215
|
});
|
|
32682
33216
|
import { writeFileSync as writeFileSync26 } from "fs";
|
|
32683
|
-
import
|
|
33217
|
+
import path59 from "path";
|
|
32684
33218
|
function writeAuditEntry(entry) {
|
|
32685
33219
|
try {
|
|
32686
33220
|
const line = JSON.stringify(entry) + "\n";
|
|
@@ -32855,7 +33389,7 @@ var init_task_enforcement = __esm({
|
|
|
32855
33389
|
"What do you need?"
|
|
32856
33390
|
];
|
|
32857
33391
|
MANAGER_ROLES = ["COO", "CTO"];
|
|
32858
|
-
AUDIT_LOG_PATH =
|
|
33392
|
+
AUDIT_LOG_PATH = path59.join(
|
|
32859
33393
|
process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
|
|
32860
33394
|
".exe-os",
|
|
32861
33395
|
"enforcement-audit.jsonl"
|
|
@@ -32880,7 +33414,7 @@ __export(background_jobs_exports, {
|
|
|
32880
33414
|
import { existsSync as existsSync45, mkdirSync as mkdirSync23, readFileSync as readFileSync39, writeFileSync as writeFileSync27, unlinkSync as unlinkSync14 } from "fs";
|
|
32881
33415
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
32882
33416
|
import os22 from "os";
|
|
32883
|
-
import
|
|
33417
|
+
import path60 from "path";
|
|
32884
33418
|
function ensureDirs() {
|
|
32885
33419
|
mkdirSync23(LOCK_DIR, { recursive: true });
|
|
32886
33420
|
}
|
|
@@ -32926,7 +33460,7 @@ function listBackgroundJobs() {
|
|
|
32926
33460
|
return jobs;
|
|
32927
33461
|
}
|
|
32928
33462
|
function lockPath(type) {
|
|
32929
|
-
return
|
|
33463
|
+
return path60.join(LOCK_DIR, `${type.replace(/[^a-zA-Z0-9_.-]/g, "_")}.lock`);
|
|
32930
33464
|
}
|
|
32931
33465
|
function acquireJobLock(type, ttlMs = DEFAULT_LOCK_TTL_MS) {
|
|
32932
33466
|
ensureDirs();
|
|
@@ -33153,9 +33687,9 @@ var init_background_jobs = __esm({
|
|
|
33153
33687
|
"src/lib/background-jobs.ts"() {
|
|
33154
33688
|
"use strict";
|
|
33155
33689
|
init_config();
|
|
33156
|
-
JOB_DIR =
|
|
33157
|
-
JOBS_FILE =
|
|
33158
|
-
LOCK_DIR =
|
|
33690
|
+
JOB_DIR = path60.join(EXE_AI_DIR, "jobs");
|
|
33691
|
+
JOBS_FILE = path60.join(JOB_DIR, "jobs.json");
|
|
33692
|
+
LOCK_DIR = path60.join(JOB_DIR, "locks");
|
|
33159
33693
|
DEFAULT_LOCK_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
33160
33694
|
MAX_HISTORY = 200;
|
|
33161
33695
|
}
|
|
@@ -33168,16 +33702,16 @@ __export(ws_auth_exports, {
|
|
|
33168
33702
|
deriveWsAuthToken: () => deriveWsAuthToken,
|
|
33169
33703
|
hashAuthToken: () => hashAuthToken
|
|
33170
33704
|
});
|
|
33171
|
-
import
|
|
33705
|
+
import crypto22 from "crypto";
|
|
33172
33706
|
function deriveWsAuthToken(masterKey) {
|
|
33173
|
-
return Buffer.from(
|
|
33707
|
+
return Buffer.from(crypto22.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
|
|
33174
33708
|
}
|
|
33175
33709
|
function deriveOrgId(masterKey) {
|
|
33176
|
-
const raw = Buffer.from(
|
|
33177
|
-
return
|
|
33710
|
+
const raw = Buffer.from(crypto22.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
|
|
33711
|
+
return crypto22.createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
33178
33712
|
}
|
|
33179
33713
|
function hashAuthToken(token) {
|
|
33180
|
-
return
|
|
33714
|
+
return crypto22.createHash("sha256").update(token).digest("hex");
|
|
33181
33715
|
}
|
|
33182
33716
|
var WS_AUTH_HKDF_INFO, ORG_ID_HKDF_INFO;
|
|
33183
33717
|
var init_ws_auth = __esm({
|
|
@@ -33195,10 +33729,10 @@ __export(device_registry_exports, {
|
|
|
33195
33729
|
resolveTargetDevice: () => resolveTargetDevice,
|
|
33196
33730
|
setFriendlyName: () => setFriendlyName
|
|
33197
33731
|
});
|
|
33198
|
-
import
|
|
33732
|
+
import crypto23 from "crypto";
|
|
33199
33733
|
import os23 from "os";
|
|
33200
33734
|
import { readFileSync as readFileSync40, writeFileSync as writeFileSync28, mkdirSync as mkdirSync24, existsSync as existsSync46 } from "fs";
|
|
33201
|
-
import
|
|
33735
|
+
import path61 from "path";
|
|
33202
33736
|
function getDeviceInfo() {
|
|
33203
33737
|
if (existsSync46(DEVICE_JSON_PATH)) {
|
|
33204
33738
|
try {
|
|
@@ -33212,11 +33746,11 @@ function getDeviceInfo() {
|
|
|
33212
33746
|
}
|
|
33213
33747
|
const hostname = os23.hostname();
|
|
33214
33748
|
const info = {
|
|
33215
|
-
deviceId:
|
|
33749
|
+
deviceId: crypto23.randomUUID(),
|
|
33216
33750
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
33217
33751
|
hostname
|
|
33218
33752
|
};
|
|
33219
|
-
mkdirSync24(
|
|
33753
|
+
mkdirSync24(path61.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
33220
33754
|
writeFileSync28(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
33221
33755
|
return info;
|
|
33222
33756
|
}
|
|
@@ -33257,7 +33791,7 @@ var init_device_registry = __esm({
|
|
|
33257
33791
|
"src/lib/device-registry.ts"() {
|
|
33258
33792
|
"use strict";
|
|
33259
33793
|
init_config();
|
|
33260
|
-
DEVICE_JSON_PATH =
|
|
33794
|
+
DEVICE_JSON_PATH = path61.join(EXE_AI_DIR, "device.json");
|
|
33261
33795
|
}
|
|
33262
33796
|
});
|
|
33263
33797
|
|
|
@@ -33474,7 +34008,7 @@ import net2 from "net";
|
|
|
33474
34008
|
import { createServer as createHttpServer } from "http";
|
|
33475
34009
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
33476
34010
|
import { writeFileSync as writeFileSync29, unlinkSync as unlinkSync15, mkdirSync as mkdirSync25, existsSync as existsSync47, readFileSync as readFileSync41, chmodSync as chmodSync2 } from "fs";
|
|
33477
|
-
import
|
|
34011
|
+
import path62 from "path";
|
|
33478
34012
|
|
|
33479
34013
|
// src/lib/orchestration-metrics.ts
|
|
33480
34014
|
init_config();
|
|
@@ -33547,8 +34081,8 @@ function initMetrics() {
|
|
|
33547
34081
|
// src/lib/exe-daemon.ts
|
|
33548
34082
|
init_memory_write_governor();
|
|
33549
34083
|
init_mcp_transport_health();
|
|
33550
|
-
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
33551
|
-
var PID_PATH4 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
34084
|
+
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path62.join(EXE_AI_DIR, "exed.sock");
|
|
34085
|
+
var PID_PATH4 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path62.join(EXE_AI_DIR, "exed.pid");
|
|
33552
34086
|
var MODEL_FILE = "jina-embeddings-v5-small-q4_k_m.gguf";
|
|
33553
34087
|
var IDLE_TIMEOUT_MS2 = parseInt(process.env.EXE_DAEMON_IDLE_TIMEOUT_MS || "0", 10);
|
|
33554
34088
|
var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
@@ -33577,7 +34111,7 @@ function enqueue(queue, entry) {
|
|
|
33577
34111
|
queue.push(entry);
|
|
33578
34112
|
}
|
|
33579
34113
|
async function loadModel() {
|
|
33580
|
-
const modelPath =
|
|
34114
|
+
const modelPath = path62.join(MODELS_DIR, MODEL_FILE);
|
|
33581
34115
|
if (!existsSync47(modelPath)) {
|
|
33582
34116
|
process.stderr.write(`[exed] No model at ${modelPath} \u2014 running without embeddings (VPS mode).
|
|
33583
34117
|
`);
|
|
@@ -34019,14 +34553,14 @@ function startMemoryQueueDrain() {
|
|
|
34019
34553
|
`);
|
|
34020
34554
|
}
|
|
34021
34555
|
function startServer() {
|
|
34022
|
-
mkdirSync25(
|
|
34556
|
+
mkdirSync25(path62.dirname(SOCKET_PATH2), { recursive: true });
|
|
34023
34557
|
try {
|
|
34024
|
-
chmodSync2(
|
|
34558
|
+
chmodSync2(path62.dirname(SOCKET_PATH2), 448);
|
|
34025
34559
|
} catch {
|
|
34026
34560
|
}
|
|
34027
34561
|
_daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV2] ?? null);
|
|
34028
34562
|
for (const oldFile of ["embed.sock", "embed.pid"]) {
|
|
34029
|
-
const oldPath =
|
|
34563
|
+
const oldPath = path62.join(path62.dirname(SOCKET_PATH2), oldFile);
|
|
34030
34564
|
try {
|
|
34031
34565
|
if (oldFile.endsWith(".pid")) {
|
|
34032
34566
|
const pid = parseInt(readFileSync41(oldPath, "utf8").trim(), 10);
|
|
@@ -34151,6 +34685,7 @@ function startServer() {
|
|
|
34151
34685
|
void startMcpHttpServer();
|
|
34152
34686
|
}
|
|
34153
34687
|
async function startMcpHttpServer() {
|
|
34688
|
+
process.stderr.write("[exed] MCP HTTP: starting setup...\n");
|
|
34154
34689
|
try {
|
|
34155
34690
|
let parseDurationMs2 = function(value, fallback, options = {}) {
|
|
34156
34691
|
if (!value) return fallback;
|
|
@@ -34205,8 +34740,14 @@ async function startMcpHttpServer() {
|
|
|
34205
34740
|
const { isInitializeRequest } = await import("@modelcontextprotocol/sdk/types.js");
|
|
34206
34741
|
const { registerAllTools: registerAllTools2 } = await Promise.resolve().then(() => (init_register_tools(), register_tools_exports));
|
|
34207
34742
|
const { runWithAgent: runWithAgent2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
|
|
34208
|
-
const
|
|
34209
|
-
|
|
34743
|
+
const dbReady = await ensureStoreForPolling();
|
|
34744
|
+
if (!dbReady) {
|
|
34745
|
+
process.stderr.write(
|
|
34746
|
+
"[exed] MCP HTTP: DB init failed \u2014 MCP HTTP endpoint will NOT start. Run 'exe-os setup' to fix keychain/encryption.\n"
|
|
34747
|
+
);
|
|
34748
|
+
return;
|
|
34749
|
+
}
|
|
34750
|
+
process.stderr.write("[exed] MCP HTTP: DB ready\n");
|
|
34210
34751
|
const transports = /* @__PURE__ */ new Map();
|
|
34211
34752
|
const MCP_HTTP_PORT = parseInt(process.env.EXE_MCP_PORT || "48739", 10);
|
|
34212
34753
|
const MCP_SESSION_TTL_MS = parseDurationMs2(process.env.EXE_MCP_SESSION_TTL_MS, 4 * 60 * 60 * 1e3, { allowZero: true });
|
|
@@ -34391,8 +34932,10 @@ async function startMcpHttpServer() {
|
|
|
34391
34932
|
}
|
|
34392
34933
|
});
|
|
34393
34934
|
} catch (err) {
|
|
34394
|
-
|
|
34935
|
+
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
34936
|
+
process.stderr.write(`[exed] MCP HTTP setup FAILED: ${msg}
|
|
34395
34937
|
`);
|
|
34938
|
+
process.stderr.write("[exed] MCP HTTP endpoint will NOT be available this session.\n");
|
|
34396
34939
|
}
|
|
34397
34940
|
}
|
|
34398
34941
|
var _storeInitialized = false;
|
|
@@ -34660,7 +35203,7 @@ function startGraphExtraction() {
|
|
|
34660
35203
|
`);
|
|
34661
35204
|
}
|
|
34662
35205
|
var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
|
|
34663
|
-
var AGENT_STATS_PATH =
|
|
35206
|
+
var AGENT_STATS_PATH = path62.join(EXE_AI_DIR, "agent-stats.json");
|
|
34664
35207
|
async function writeAgentStats() {
|
|
34665
35208
|
fired("agent_stats");
|
|
34666
35209
|
if (!await ensureStoreForPolling()) return;
|
|
@@ -34837,11 +35380,11 @@ function startIntercomQueueDrain() {
|
|
|
34837
35380
|
const hasInProgressTask = (session) => {
|
|
34838
35381
|
try {
|
|
34839
35382
|
const { baseAgentName: ban } = (init_employees(), __toCommonJS(employees_exports));
|
|
34840
|
-
const
|
|
35383
|
+
const path63 = __require("path");
|
|
34841
35384
|
const { existsSync: existsSync48 } = __require("fs");
|
|
34842
35385
|
const os25 = __require("os");
|
|
34843
35386
|
const agent = ban(session.split("-")[0] ?? session);
|
|
34844
|
-
const markerPath =
|
|
35387
|
+
const markerPath = path63.join(os25.homedir(), ".exe-os", "session-cache", `current-task-${agent}.json`);
|
|
34845
35388
|
return existsSync48(markerPath);
|
|
34846
35389
|
} catch {
|
|
34847
35390
|
return false;
|