@datasynx/agentic-crm 1.0.0 → 1.2.0
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/README.md +8 -1
- package/dist/{ask-D8iYqDAr.js → ask-CDysGnRg.js} +2 -2
- package/dist/{ask-D8iYqDAr.js.map → ask-CDysGnRg.js.map} +1 -1
- package/dist/attachments-CX2GAtsw.cjs +517 -0
- package/dist/attachments-CX2GAtsw.cjs.map +1 -0
- package/dist/attachments-D207gXfN.js +514 -0
- package/dist/attachments-D207gXfN.js.map +1 -0
- package/dist/attachments-rLa96rOK.js +514 -0
- package/dist/attachments-rLa96rOK.js.map +1 -0
- package/dist/chunk-BfDYWZQ8.cjs +32 -0
- package/dist/chunk-BfDYWZQ8.cjs.map +1 -0
- package/dist/chunk-BhUZmQg5.js +32 -0
- package/dist/chunk-BhUZmQg5.js.map +1 -0
- package/dist/chunk-ChC83jai.js +2 -0
- package/dist/chunk-e_w8qqtP.js +32 -0
- package/dist/chunk-e_w8qqtP.js.map +1 -0
- package/dist/cli.js +20 -18
- package/dist/cli.js.map +1 -1
- package/dist/daemon/worker.js +3 -3
- package/dist/{doctor-C14-vnJ1.js → doctor-BFeelnq8.js} +2 -2
- package/dist/{doctor-C14-vnJ1.js.map → doctor-BFeelnq8.js.map} +1 -1
- package/dist/doctor-CYDaNmFn.js +2 -0
- package/dist/email-body-BFSRa0AW.cjs +42 -0
- package/dist/email-body-BFSRa0AW.cjs.map +1 -0
- package/dist/email-body-BOd7U-D2.js +42 -0
- package/dist/email-body-BOd7U-D2.js.map +1 -0
- package/dist/{gmail-sync-DueE6tl5.js → gmail-sync-B4Iu3AQb.js} +45 -15
- package/dist/gmail-sync-B4Iu3AQb.js.map +1 -0
- package/dist/{gmail-sync-GEy3oVvw.cjs → gmail-sync-BpSVESSe.cjs} +45 -15
- package/dist/gmail-sync-BpSVESSe.cjs.map +1 -0
- package/dist/{gmail-sync-C-NmibzS.js → gmail-sync-DIbrPnTK.js} +45 -15
- package/dist/gmail-sync-DIbrPnTK.js.map +1 -0
- package/dist/{gmail-webhook-handler-kGKpbY9h.js → gmail-webhook-handler-BzOFbvgh.js} +2 -2
- package/dist/{gmail-webhook-handler-kGKpbY9h.js.map → gmail-webhook-handler-BzOFbvgh.js.map} +1 -1
- package/dist/{gmail-webhook-handler-B26COilD.js → gmail-webhook-handler-CvSDW_Js.js} +1 -1
- package/dist/{google-drive-sync-D1n7WKZn.js → google-drive-sync-B_I1d54Y.js} +2 -2
- package/dist/{google-drive-sync-D1n7WKZn.js.map → google-drive-sync-B_I1d54Y.js.map} +1 -1
- package/dist/html-BaeOCZKE.js +36 -0
- package/dist/html-BaeOCZKE.js.map +1 -0
- package/dist/html-CmOku6jS.cjs +47 -0
- package/dist/html-CmOku6jS.cjs.map +1 -0
- package/dist/{import-hubspot-DB4n89jy.js → import-hubspot-CTId9IGV.js} +2 -2
- package/dist/{import-hubspot-DB4n89jy.js.map → import-hubspot-CTId9IGV.js.map} +1 -1
- package/dist/{index-pY7tYXwH.d.cts → index-CLUKKfGb.d.cts} +12 -8
- package/dist/index-CLUKKfGb.d.cts.map +1 -0
- package/dist/{index-B0IMMrp_.d.ts → index-D8jJ1VIt.d.ts} +14 -10
- package/dist/index-D8jJ1VIt.d.ts.map +1 -0
- package/dist/index.d.cts +12 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +14 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/{interactions-writer-RJB8SWf2.js → interactions-writer-B2y-73lh.js} +1 -1
- package/dist/{interactions-writer-DbSyI2rt.js → interactions-writer-B8XAzdqR.js} +3 -2
- package/dist/interactions-writer-B8XAzdqR.js.map +1 -0
- package/dist/{interactions-writer-a2yzBd7T.cjs → interactions-writer-BRJNrefF.cjs} +3 -2
- package/dist/interactions-writer-BRJNrefF.cjs.map +1 -0
- package/dist/{interactions-writer-BZzUIgJd.js → interactions-writer-ZQcpFOh9.js} +3 -2
- package/dist/interactions-writer-ZQcpFOh9.js.map +1 -0
- package/dist/{knowledge-base-DHNc4hVj.js → knowledge-base-Bx2PKQR2.js} +10 -7
- package/dist/knowledge-base-Bx2PKQR2.js.map +1 -0
- package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
- package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
- package/dist/mcp.cjs +308 -150
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.d.cts.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +308 -150
- package/dist/mcp.js.map +1 -1
- package/dist/{microsoft-calendar-jIu9K5zX.js → microsoft-calendar-BgVR8GDv.js} +3 -3
- package/dist/{microsoft-calendar-jIu9K5zX.js.map → microsoft-calendar-BgVR8GDv.js.map} +1 -1
- package/dist/{microsoft-sync-R_r8HL-B.js → microsoft-sync-D30_XksI.js} +3 -3
- package/dist/{microsoft-sync-R_r8HL-B.js.map → microsoft-sync-D30_XksI.js.map} +1 -1
- package/dist/{nba-mTJ4yEqD.js → nba-DwdfM93s.js} +2 -2
- package/dist/{nba-mTJ4yEqD.js.map → nba-DwdfM93s.js.map} +1 -1
- package/dist/{server-DqSMYhSA.js → server-BhNLrnAD.js} +201 -145
- package/dist/server-BhNLrnAD.js.map +1 -0
- package/dist/{transcript-watcher-0mh2ZhmH.js → transcript-watcher-BoClrJAz.js} +2 -2
- package/dist/{transcript-watcher-0mh2ZhmH.js.map → transcript-watcher-BoClrJAz.js.map} +1 -1
- package/package.json +13 -2
- package/dist/gmail-sync-C-NmibzS.js.map +0 -1
- package/dist/gmail-sync-DueE6tl5.js.map +0 -1
- package/dist/gmail-sync-GEy3oVvw.cjs.map +0 -1
- package/dist/index-B0IMMrp_.d.ts.map +0 -1
- package/dist/index-pY7tYXwH.d.cts.map +0 -1
- package/dist/interactions-writer-BZzUIgJd.js.map +0 -1
- package/dist/interactions-writer-DbSyI2rt.js.map +0 -1
- package/dist/interactions-writer-a2yzBd7T.cjs.map +0 -1
- package/dist/knowledge-base-DHNc4hVj.js.map +0 -1
- package/dist/server-DqSMYhSA.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
|
2
2
|
import { A as writeMainFacts, C as writeJsonArray, D as ensureCustomerDir, E as customerExists, M as isSafePathSegment, O as listCustomerSlugs, S as readJsonFile, T as assertSafeSlug, a as customerVisibility, d as readAuditLog, f as writeAuditEntry, h as runBackup, i as canSeeCustomer, j as assertSafePathSegment, k as readMainFacts, l as filterAuditLog, m as readBackupLog, n as getSession, o as enforceRbac, p as listBackupsInDir, u as getActor, w as writeJsonFile, x as readJsonArray } from "./session-store-DWxJ5Pof.js";
|
|
3
3
|
import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
|
|
4
4
|
import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
|
|
5
|
-
import { n as formatInteractionEntry, t as appendInteraction } from "./interactions-writer-
|
|
5
|
+
import { n as formatInteractionEntry, t as appendInteraction } from "./interactions-writer-ZQcpFOh9.js";
|
|
6
6
|
import { n as queryLogs, r as summarizeLogs, t as logger } from "./logger-UaF5p9d1.js";
|
|
7
7
|
import { i as upsertDeal, n as readPipeline, r as readPipelineSync } from "./pipeline-writer-rDj-ni6q.js";
|
|
8
8
|
import { i as guardIsoDate, t as callLlm } from "./llm-BnSUBisu.js";
|
|
@@ -398,7 +398,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
398
398
|
| log_interaction | Write a new interaction entry (call, email, meeting, note) — immediately searchable | rep+ |
|
|
399
399
|
| update_deal | Create or update a deal in pipeline.md — upserts by deal name | rep+ |
|
|
400
400
|
| update_customer_facts | Update fields in customer profile (domain, contact, stage, tags) | admin |
|
|
401
|
-
| export_customer | Export all customer data as JSON or Markdown | admin |
|
|
401
|
+
| export_customer | Export all customer data (incl. attachment contents) as JSON or Markdown | admin |
|
|
402
402
|
| get_deal_health | Score deal health 0–100 (A–F grade) based on activity, velocity, close date, probability | any |
|
|
403
403
|
| get_pipeline_forecast | Aggregate weighted pipeline revenue across all customers grouped by stage | any |
|
|
404
404
|
| get_pipeline_stages | List all configured pipeline stages (defaults: lead, qualified, proposal, negotiation, won, lost) | any |
|
|
@@ -443,6 +443,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
443
443
|
| trigger_sync | Force immediate Gmail sync for one or all customers | rep+ |
|
|
444
444
|
| get_audit_log | Read audit log — all write operations with actor, tool, customer | admin |
|
|
445
445
|
| get_logs | Query/aggregate the structured application log (level, component, errors) | admin |
|
|
446
|
+
| get_diagnostics | Self-diagnostic health check (data integrity, temp files, log errors, backups) | admin |
|
|
446
447
|
| define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
|
|
447
448
|
| create_record | Create a record of a custom object (validated against its schema) | rep+ |
|
|
448
449
|
| list_records | List records of a custom object | any |
|
|
@@ -532,12 +533,14 @@ RBAC: admin
|
|
|
532
533
|
- Input: slug (required) + any combination of the optional fields
|
|
533
534
|
- Returns: { success: boolean, facts: object }
|
|
534
535
|
|
|
535
|
-
### export_customer({ slug, format? })
|
|
536
|
-
Export all customer data (main_facts + interactions
|
|
536
|
+
### export_customer({ slug, format?, includeAttachmentContent? })
|
|
537
|
+
Export all customer data (main_facts + interactions + pipeline + attachments).
|
|
538
|
+
Set includeAttachmentContent to inline every attachment's converted Markdown —
|
|
539
|
+
a single sendable bundle of all conversations and documents for the customer.
|
|
537
540
|
RBAC: admin
|
|
538
|
-
- Input: { slug: string, format?: "json" | "markdown" (default "json") }
|
|
539
|
-
- Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments }
|
|
540
|
-
- Returns (Markdown): Formatted document with all sections
|
|
541
|
+
- Input: { slug: string, format?: "json" | "markdown" (default "json"), includeAttachmentContent?: boolean (default false) }
|
|
542
|
+
- Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
|
|
543
|
+
- Returns (Markdown): Formatted document with all sections (and attachment contents when requested)
|
|
541
544
|
|
|
542
545
|
### get_deal_health({ slug })
|
|
543
546
|
Score the health of all deals for a customer based on activity recency, stage velocity,
|
|
@@ -1419,7 +1422,7 @@ async function buildContext(dataDir, slug) {
|
|
|
1419
1422
|
}
|
|
1420
1423
|
//#endregion
|
|
1421
1424
|
//#region src/mcp/tools/get-customer-context.ts
|
|
1422
|
-
const DATA_DIR$
|
|
1425
|
+
const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1423
1426
|
function triggerOnQuerySync(dataDir, slug) {
|
|
1424
1427
|
const auth = getGmailAuth();
|
|
1425
1428
|
if (!auth) return;
|
|
@@ -1432,7 +1435,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1432
1435
|
const sources = JSON.parse(fs.readFileSync(sourcesPath, "utf-8"));
|
|
1433
1436
|
if (!sources.gmail?.enabled || !sources.gmail.query) return;
|
|
1434
1437
|
const query = sources.gmail.query;
|
|
1435
|
-
import("./gmail-sync-
|
|
1438
|
+
import("./gmail-sync-DIbrPnTK.js").then(({ syncGmail }) => syncGmail({
|
|
1436
1439
|
slug,
|
|
1437
1440
|
dataDir,
|
|
1438
1441
|
auth,
|
|
@@ -1440,7 +1443,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1440
1443
|
}).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
|
|
1441
1444
|
} catch {}
|
|
1442
1445
|
}
|
|
1443
|
-
async function handleGetCustomerContext(input, dataDir = DATA_DIR$
|
|
1446
|
+
async function handleGetCustomerContext(input, dataDir = DATA_DIR$53) {
|
|
1444
1447
|
const targetSlug = input.slug ?? getSession()?.customerSlug;
|
|
1445
1448
|
if (!targetSlug) return {
|
|
1446
1449
|
content: [{
|
|
@@ -1576,8 +1579,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
|
|
|
1576
1579
|
}
|
|
1577
1580
|
//#endregion
|
|
1578
1581
|
//#region src/mcp/tools/search-customer-knowledge.ts
|
|
1579
|
-
const DATA_DIR$
|
|
1580
|
-
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$
|
|
1582
|
+
const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1583
|
+
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$52) {
|
|
1581
1584
|
const limit = input.limit ?? 5;
|
|
1582
1585
|
try {
|
|
1583
1586
|
const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
|
|
@@ -1625,14 +1628,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
|
|
|
1625
1628
|
}
|
|
1626
1629
|
//#endregion
|
|
1627
1630
|
//#region src/mcp/tools/list-customers.ts
|
|
1628
|
-
const DATA_DIR$
|
|
1631
|
+
const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1629
1632
|
function extractLastInteractionDate(interactionsPath) {
|
|
1630
1633
|
if (!fs.existsSync(interactionsPath)) return void 0;
|
|
1631
1634
|
const content = fs.readFileSync(interactionsPath, "utf-8");
|
|
1632
1635
|
const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
|
|
1633
1636
|
return match ? match[1] : void 0;
|
|
1634
1637
|
}
|
|
1635
|
-
async function handleListCustomers(input, dataDir = DATA_DIR$
|
|
1638
|
+
async function handleListCustomers(input, dataDir = DATA_DIR$51) {
|
|
1636
1639
|
const customersDir = path.join(dataDir, "customers");
|
|
1637
1640
|
const customers = [];
|
|
1638
1641
|
if (!fs.existsSync(customersDir)) return { content: [{
|
|
@@ -2145,8 +2148,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
|
|
|
2145
2148
|
}
|
|
2146
2149
|
//#endregion
|
|
2147
2150
|
//#region src/mcp/tools/log-interaction.ts
|
|
2148
|
-
const DATA_DIR$
|
|
2149
|
-
async function handleLogInteraction(input, dataDir = DATA_DIR$
|
|
2151
|
+
const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2152
|
+
async function handleLogInteraction(input, dataDir = DATA_DIR$50) {
|
|
2150
2153
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2151
2154
|
const interactionDate = input.date ?? today;
|
|
2152
2155
|
const sourceRef = input.source ?? `agent://log/${Date.now()}`;
|
|
@@ -2255,8 +2258,8 @@ var update_deal_exports = /* @__PURE__ */ __exportAll({
|
|
|
2255
2258
|
handleUpdateDeal: () => handleUpdateDeal,
|
|
2256
2259
|
registerUpdateDeal: () => registerUpdateDeal
|
|
2257
2260
|
});
|
|
2258
|
-
const DATA_DIR$
|
|
2259
|
-
async function handleUpdateDeal(input, dataDir = DATA_DIR$
|
|
2261
|
+
const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2262
|
+
async function handleUpdateDeal(input, dataDir = DATA_DIR$49) {
|
|
2260
2263
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2261
2264
|
const deal = {
|
|
2262
2265
|
name: input.dealName,
|
|
@@ -2339,12 +2342,12 @@ Returns: { success: boolean, deal: object }`,
|
|
|
2339
2342
|
}
|
|
2340
2343
|
//#endregion
|
|
2341
2344
|
//#region src/mcp/tools/export-customer.ts
|
|
2342
|
-
const DATA_DIR$
|
|
2345
|
+
const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2343
2346
|
function countInteractions(content) {
|
|
2344
2347
|
const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
2345
2348
|
return matches ? matches.length : 0;
|
|
2346
2349
|
}
|
|
2347
|
-
async function handleExportCustomer(input, dataDir = DATA_DIR$
|
|
2350
|
+
async function handleExportCustomer(input, dataDir = DATA_DIR$48) {
|
|
2348
2351
|
enforceRbac(dataDir, "export_customer");
|
|
2349
2352
|
const customerDir = path.join(dataDir, "customers", input.slug);
|
|
2350
2353
|
if (!fs.existsSync(customerDir)) return {
|
|
@@ -2371,14 +2374,27 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2371
2374
|
interactionsCount = countInteractions(interactionsContent);
|
|
2372
2375
|
}
|
|
2373
2376
|
const pipeline = await readPipeline(dataDir, input.slug);
|
|
2377
|
+
const includeAttachmentContent = input.includeAttachmentContent ?? false;
|
|
2374
2378
|
const attachmentsDir = path.join(customerDir, "attachments");
|
|
2375
2379
|
const attachments = [];
|
|
2380
|
+
const attachmentContents = {};
|
|
2376
2381
|
if (fs.existsSync(attachmentsDir)) try {
|
|
2377
2382
|
const files = fs.readdirSync(attachmentsDir);
|
|
2378
2383
|
for (const f of files) try {
|
|
2379
|
-
if (fs.statSync(path.join(attachmentsDir, f)).isFile())
|
|
2384
|
+
if (!fs.statSync(path.join(attachmentsDir, f)).isFile()) continue;
|
|
2385
|
+
attachments.push(f);
|
|
2386
|
+
if (includeAttachmentContent && f.endsWith(".md")) attachmentContents[f] = fs.readFileSync(path.join(attachmentsDir, f), "utf-8");
|
|
2380
2387
|
} catch {}
|
|
2381
2388
|
} catch {}
|
|
2389
|
+
const attachmentContentSection = () => {
|
|
2390
|
+
const entries = Object.entries(attachmentContents);
|
|
2391
|
+
if (!includeAttachmentContent || entries.length === 0) return [];
|
|
2392
|
+
return [
|
|
2393
|
+
"",
|
|
2394
|
+
`## Attachment Contents (${entries.length})`,
|
|
2395
|
+
...entries.map(([name, content]) => `\n### ${name}\n\n${content.trim()}`)
|
|
2396
|
+
];
|
|
2397
|
+
};
|
|
2382
2398
|
if (format === "markdown") return { content: [{
|
|
2383
2399
|
type: "text",
|
|
2384
2400
|
text: [
|
|
@@ -2397,7 +2413,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2397
2413
|
pipeline.length > 0 ? pipeline.map((d) => `- **${d.name}** · ${d.stage}${d.value !== void 0 ? ` · €${d.value}` : ""}${d.close_date ? ` · close: ${d.close_date}` : ""}`).join("\n") : "(no deals)",
|
|
2398
2414
|
"",
|
|
2399
2415
|
`## Attachments (${attachments.length})`,
|
|
2400
|
-
attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)"
|
|
2416
|
+
attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)",
|
|
2417
|
+
...attachmentContentSection()
|
|
2401
2418
|
].join("\n")
|
|
2402
2419
|
}] };
|
|
2403
2420
|
const exported = {
|
|
@@ -2406,7 +2423,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2406
2423
|
mainFacts,
|
|
2407
2424
|
interactionsCount,
|
|
2408
2425
|
pipeline,
|
|
2409
|
-
attachments
|
|
2426
|
+
attachments,
|
|
2427
|
+
...includeAttachmentContent ? { attachmentContents } : {}
|
|
2410
2428
|
};
|
|
2411
2429
|
return { content: [{
|
|
2412
2430
|
type: "text",
|
|
@@ -2416,29 +2434,34 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2416
2434
|
function registerExportCustomer(server) {
|
|
2417
2435
|
server.registerTool("export_customer", {
|
|
2418
2436
|
title: "Export Customer",
|
|
2419
|
-
description: `Export all customer data (main_facts + interactions
|
|
2420
|
-
Useful for reporting, audits, or creating
|
|
2437
|
+
description: `Export all customer data (main_facts + interactions + pipeline deals + attachments).
|
|
2438
|
+
Useful for reporting, audits, handoffs, or creating a complete sendable bundle
|
|
2439
|
+
of every conversation and document for a customer.
|
|
2421
2440
|
|
|
2422
2441
|
Args:
|
|
2423
2442
|
slug: Customer ID (e.g. "acme-corp")
|
|
2424
2443
|
format: Output format — "json" (default) or "markdown"
|
|
2444
|
+
includeAttachmentContent: Inline the converted Markdown of every attachment
|
|
2445
|
+
(default false). Use this to produce a single self-contained bundle.
|
|
2425
2446
|
|
|
2426
2447
|
Returns:
|
|
2427
|
-
JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline }
|
|
2428
|
-
Markdown: Formatted document with all sections`,
|
|
2448
|
+
JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
|
|
2449
|
+
Markdown: Formatted document with all sections (and attachment contents when requested)`,
|
|
2429
2450
|
inputSchema: z.object({
|
|
2430
2451
|
slug: z.string().describe("Customer slug (e.g. 'acme-corp')"),
|
|
2431
|
-
format: z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'")
|
|
2452
|
+
format: z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'"),
|
|
2453
|
+
includeAttachmentContent: z.boolean().optional().describe("Inline converted attachment Markdown into the export (default false)")
|
|
2432
2454
|
})
|
|
2433
|
-
}, async ({ slug, format }) => handleExportCustomer({
|
|
2455
|
+
}, async ({ slug, format, includeAttachmentContent }) => handleExportCustomer({
|
|
2434
2456
|
slug,
|
|
2435
|
-
...format !== void 0 ? { format } : {}
|
|
2457
|
+
...format !== void 0 ? { format } : {},
|
|
2458
|
+
...includeAttachmentContent !== void 0 ? { includeAttachmentContent } : {}
|
|
2436
2459
|
}));
|
|
2437
2460
|
}
|
|
2438
2461
|
//#endregion
|
|
2439
2462
|
//#region src/mcp/tools/update-customer-facts.ts
|
|
2440
|
-
const DATA_DIR$
|
|
2441
|
-
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$
|
|
2463
|
+
const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2464
|
+
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$47) {
|
|
2442
2465
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2443
2466
|
try {
|
|
2444
2467
|
enforceRbac(dataDir, "update_customer_facts");
|
|
@@ -2616,8 +2639,8 @@ function scoreDealForToday(deal, todayDate) {
|
|
|
2616
2639
|
}
|
|
2617
2640
|
//#endregion
|
|
2618
2641
|
//#region src/mcp/tools/get-deal-health.ts
|
|
2619
|
-
const DATA_DIR$
|
|
2620
|
-
async function handleGetDealHealth(input, dataDir = DATA_DIR$
|
|
2642
|
+
const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2643
|
+
async function handleGetDealHealth(input, dataDir = DATA_DIR$46) {
|
|
2621
2644
|
try {
|
|
2622
2645
|
const deals = await readPipeline(dataDir, input.slug);
|
|
2623
2646
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2666,8 +2689,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
|
|
|
2666
2689
|
}
|
|
2667
2690
|
//#endregion
|
|
2668
2691
|
//#region src/mcp/tools/get-pipeline-forecast.ts
|
|
2669
|
-
const DATA_DIR$
|
|
2670
|
-
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$
|
|
2692
|
+
const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2693
|
+
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$45) {
|
|
2671
2694
|
try {
|
|
2672
2695
|
const slugs = listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
|
|
2673
2696
|
const allDeals = [];
|
|
@@ -2728,8 +2751,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
|
|
|
2728
2751
|
}
|
|
2729
2752
|
//#endregion
|
|
2730
2753
|
//#region src/mcp/tools/summarize-meeting.ts
|
|
2731
|
-
const DATA_DIR$
|
|
2732
|
-
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$
|
|
2754
|
+
const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2755
|
+
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$44) {
|
|
2733
2756
|
try {
|
|
2734
2757
|
let summary = input.transcript.slice(0, 400);
|
|
2735
2758
|
let nextSteps = [];
|
|
@@ -2852,8 +2875,8 @@ function getPipelineStages(dataDir) {
|
|
|
2852
2875
|
}
|
|
2853
2876
|
//#endregion
|
|
2854
2877
|
//#region src/mcp/tools/get-pipeline-stages.ts
|
|
2855
|
-
const DATA_DIR$
|
|
2856
|
-
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$
|
|
2878
|
+
const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2879
|
+
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$43) {
|
|
2857
2880
|
const stages = getPipelineStages(dataDir);
|
|
2858
2881
|
return { content: [{
|
|
2859
2882
|
type: "text",
|
|
@@ -2881,8 +2904,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
|
|
|
2881
2904
|
}
|
|
2882
2905
|
//#endregion
|
|
2883
2906
|
//#region src/mcp/tools/get-market-intelligence.ts
|
|
2884
|
-
const DATA_DIR$
|
|
2885
|
-
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$
|
|
2907
|
+
const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2908
|
+
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$42) {
|
|
2886
2909
|
const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
|
|
2887
2910
|
const all = listCustomerSlugs(dataDir);
|
|
2888
2911
|
const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
|
|
@@ -2913,7 +2936,7 @@ function registerGetMarketIntelligence(server) {
|
|
|
2913
2936
|
}
|
|
2914
2937
|
//#endregion
|
|
2915
2938
|
//#region src/mcp/tools/get-relationship-graph.ts
|
|
2916
|
-
const DATA_DIR$
|
|
2939
|
+
const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2917
2940
|
function summarizeNode(n) {
|
|
2918
2941
|
return {
|
|
2919
2942
|
id: n.id,
|
|
@@ -2921,7 +2944,7 @@ function summarizeNode(n) {
|
|
|
2921
2944
|
email: n.properties["email"]
|
|
2922
2945
|
};
|
|
2923
2946
|
}
|
|
2924
|
-
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$
|
|
2947
|
+
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$41) {
|
|
2925
2948
|
try {
|
|
2926
2949
|
const graph = readGraph(dataDir, input.slug);
|
|
2927
2950
|
const stakeholders = getStakeholders(graph);
|
|
@@ -2989,9 +3012,9 @@ Returns: {
|
|
|
2989
3012
|
}
|
|
2990
3013
|
//#endregion
|
|
2991
3014
|
//#region src/mcp/tools/get-relationship-health.ts
|
|
2992
|
-
const DATA_DIR$
|
|
3015
|
+
const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2993
3016
|
const MAX_HEALTH_AGE_MS = 3600 * 1e3;
|
|
2994
|
-
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$
|
|
3017
|
+
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$40) {
|
|
2995
3018
|
try {
|
|
2996
3019
|
let health = readHealth(dataDir, input.slug);
|
|
2997
3020
|
if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
|
|
@@ -3541,7 +3564,7 @@ async function executeAction(action, dataDir) {
|
|
|
3541
3564
|
if (!slug) return "skipped";
|
|
3542
3565
|
switch (action.type) {
|
|
3543
3566
|
case "log_interaction": {
|
|
3544
|
-
const { appendInteraction } = await import("./interactions-writer-
|
|
3567
|
+
const { appendInteraction } = await import("./interactions-writer-ZQcpFOh9.js").then((n) => n.r);
|
|
3545
3568
|
await appendInteraction(dataDir, slug, {
|
|
3546
3569
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3547
3570
|
type: action.payload["type"] ?? "Note",
|
|
@@ -3554,7 +3577,7 @@ async function executeAction(action, dataDir) {
|
|
|
3554
3577
|
return "executed";
|
|
3555
3578
|
}
|
|
3556
3579
|
case "schedule_meeting": {
|
|
3557
|
-
const { appendInteraction } = await import("./interactions-writer-
|
|
3580
|
+
const { appendInteraction } = await import("./interactions-writer-ZQcpFOh9.js").then((n) => n.r);
|
|
3558
3581
|
await appendInteraction(dataDir, slug, {
|
|
3559
3582
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3560
3583
|
type: "Note",
|
|
@@ -3660,8 +3683,8 @@ async function runDealAgent(config, dataDir, llmFn = callLlm) {
|
|
|
3660
3683
|
}
|
|
3661
3684
|
//#endregion
|
|
3662
3685
|
//#region src/mcp/tools/run-deal-agent.ts
|
|
3663
|
-
const DATA_DIR$
|
|
3664
|
-
async function handleRunDealAgent(input, dataDir = DATA_DIR$
|
|
3686
|
+
const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3687
|
+
async function handleRunDealAgent(input, dataDir = DATA_DIR$39) {
|
|
3665
3688
|
try {
|
|
3666
3689
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3667
3690
|
const result = await runDealAgent({
|
|
@@ -3728,8 +3751,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
|
|
|
3728
3751
|
}
|
|
3729
3752
|
//#endregion
|
|
3730
3753
|
//#region src/mcp/tools/approve-agent-action.ts
|
|
3731
|
-
const DATA_DIR$
|
|
3732
|
-
async function handleApproveAgentAction(input, dataDir = DATA_DIR$
|
|
3754
|
+
const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3755
|
+
async function handleApproveAgentAction(input, dataDir = DATA_DIR$38) {
|
|
3733
3756
|
try {
|
|
3734
3757
|
const queue = readAgentQueue(dataDir, input.slug);
|
|
3735
3758
|
const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
|
|
@@ -3989,8 +4012,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
|
|
|
3989
4012
|
}
|
|
3990
4013
|
//#endregion
|
|
3991
4014
|
//#region src/mcp/tools/simulate-revenue.ts
|
|
3992
|
-
const DATA_DIR$
|
|
3993
|
-
async function handleSimulateRevenue(input, dataDir = DATA_DIR$
|
|
4015
|
+
const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4016
|
+
async function handleSimulateRevenue(input, dataDir = DATA_DIR$37) {
|
|
3994
4017
|
try {
|
|
3995
4018
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3996
4019
|
const horizon = input.horizon ?? "quarter";
|
|
@@ -4048,8 +4071,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
|
|
|
4048
4071
|
}
|
|
4049
4072
|
//#endregion
|
|
4050
4073
|
//#region src/mcp/tools/get-playbook.ts
|
|
4051
|
-
const DATA_DIR$
|
|
4052
|
-
async function handleGetPlaybook(input, dataDir = DATA_DIR$
|
|
4074
|
+
const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4075
|
+
async function handleGetPlaybook(input, dataDir = DATA_DIR$36) {
|
|
4053
4076
|
try {
|
|
4054
4077
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4055
4078
|
if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
|
|
@@ -4134,12 +4157,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
|
|
|
4134
4157
|
...healthScore !== void 0 ? { healthScore } : {},
|
|
4135
4158
|
...daysSinceContact !== void 0 ? { daysSinceContact } : {},
|
|
4136
4159
|
...championPresent !== void 0 ? { championPresent } : {}
|
|
4137
|
-
}, DATA_DIR$
|
|
4160
|
+
}, DATA_DIR$36));
|
|
4138
4161
|
}
|
|
4139
4162
|
//#endregion
|
|
4140
4163
|
//#region src/mcp/tools/create-playbook.ts
|
|
4141
|
-
const DATA_DIR$
|
|
4142
|
-
async function handleCreatePlaybook(input, dataDir = DATA_DIR$
|
|
4164
|
+
const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4165
|
+
async function handleCreatePlaybook(input, dataDir = DATA_DIR$35) {
|
|
4143
4166
|
try {
|
|
4144
4167
|
const name = toKebabCase(input.name);
|
|
4145
4168
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -4212,12 +4235,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
|
|
|
4212
4235
|
trigger,
|
|
4213
4236
|
content,
|
|
4214
4237
|
...successRate !== void 0 ? { successRate } : {}
|
|
4215
|
-
}, DATA_DIR$
|
|
4238
|
+
}, DATA_DIR$35));
|
|
4216
4239
|
}
|
|
4217
4240
|
//#endregion
|
|
4218
4241
|
//#region src/mcp/tools/list-playbooks.ts
|
|
4219
|
-
const DATA_DIR$
|
|
4220
|
-
async function handleListPlaybooks(input, dataDir = DATA_DIR$
|
|
4242
|
+
const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4243
|
+
async function handleListPlaybooks(input, dataDir = DATA_DIR$34) {
|
|
4221
4244
|
try {
|
|
4222
4245
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4223
4246
|
return { content: [{
|
|
@@ -4256,12 +4279,12 @@ Args:
|
|
|
4256
4279
|
|
|
4257
4280
|
Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
|
|
4258
4281
|
inputSchema: z.object({ slug: z.string().describe("Customer ID") })
|
|
4259
|
-
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$
|
|
4282
|
+
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$34));
|
|
4260
4283
|
}
|
|
4261
4284
|
//#endregion
|
|
4262
4285
|
//#region src/mcp/tools/distill-playbook.ts
|
|
4263
|
-
const DATA_DIR$
|
|
4264
|
-
async function handleDistillPlaybook(input, dataDir = DATA_DIR$
|
|
4286
|
+
const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4287
|
+
async function handleDistillPlaybook(input, dataDir = DATA_DIR$33, llmFn = callLlm) {
|
|
4265
4288
|
try {
|
|
4266
4289
|
const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
|
|
4267
4290
|
if (!result.ok) {
|
|
@@ -4320,7 +4343,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
|
|
|
4320
4343
|
slug,
|
|
4321
4344
|
dealName,
|
|
4322
4345
|
outcome
|
|
4323
|
-
}, DATA_DIR$
|
|
4346
|
+
}, DATA_DIR$33));
|
|
4324
4347
|
}
|
|
4325
4348
|
//#endregion
|
|
4326
4349
|
//#region src/core/goal-engine.ts
|
|
@@ -4538,8 +4561,8 @@ function getActiveGoals(dataDir) {
|
|
|
4538
4561
|
}
|
|
4539
4562
|
//#endregion
|
|
4540
4563
|
//#region src/mcp/tools/pursue-goal.ts
|
|
4541
|
-
const DATA_DIR$
|
|
4542
|
-
async function handlePursueGoal(input, dataDir = DATA_DIR$
|
|
4564
|
+
const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4565
|
+
async function handlePursueGoal(input, dataDir = DATA_DIR$32, options = {}) {
|
|
4543
4566
|
try {
|
|
4544
4567
|
enforceRbac(dataDir, "pursue_goal");
|
|
4545
4568
|
const goal = await pursueGoal(dataDir, {
|
|
@@ -4602,12 +4625,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
|
|
|
4602
4625
|
goal,
|
|
4603
4626
|
deadline,
|
|
4604
4627
|
...context !== void 0 ? { context } : {}
|
|
4605
|
-
}, DATA_DIR$
|
|
4628
|
+
}, DATA_DIR$32));
|
|
4606
4629
|
}
|
|
4607
4630
|
//#endregion
|
|
4608
4631
|
//#region src/mcp/tools/get-goal-status.ts
|
|
4609
|
-
const DATA_DIR$
|
|
4610
|
-
async function handleGetGoalStatus(input, dataDir = DATA_DIR$
|
|
4632
|
+
const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4633
|
+
async function handleGetGoalStatus(input, dataDir = DATA_DIR$31) {
|
|
4611
4634
|
try {
|
|
4612
4635
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4613
4636
|
const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
|
|
@@ -4666,17 +4689,17 @@ Args:
|
|
|
4666
4689
|
|
|
4667
4690
|
Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
|
|
4668
4691
|
inputSchema: z.object({ goalId: z.string().optional().describe("Specific goal ID (omit for all active goals)") })
|
|
4669
|
-
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$
|
|
4692
|
+
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$31));
|
|
4670
4693
|
}
|
|
4671
4694
|
//#endregion
|
|
4672
4695
|
//#region src/mcp/tools/register-push-subscription.ts
|
|
4673
|
-
const DATA_DIR$
|
|
4696
|
+
const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4674
4697
|
const VALID_PROVIDERS = [
|
|
4675
4698
|
"gmail",
|
|
4676
4699
|
"microsoft-graph",
|
|
4677
4700
|
"slack"
|
|
4678
4701
|
];
|
|
4679
|
-
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$
|
|
4702
|
+
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$30) {
|
|
4680
4703
|
try {
|
|
4681
4704
|
if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
|
|
4682
4705
|
type: "text",
|
|
@@ -4762,12 +4785,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
|
|
|
4762
4785
|
...microsoftResource !== void 0 ? { microsoftResource } : {},
|
|
4763
4786
|
...slackTeamId !== void 0 ? { slackTeamId } : {},
|
|
4764
4787
|
...slackChannelId !== void 0 ? { slackChannelId } : {}
|
|
4765
|
-
}, DATA_DIR$
|
|
4788
|
+
}, DATA_DIR$30));
|
|
4766
4789
|
}
|
|
4767
4790
|
//#endregion
|
|
4768
4791
|
//#region src/mcp/tools/get-push-status.ts
|
|
4769
|
-
const DATA_DIR$
|
|
4770
|
-
async function handleGetPushStatus(input, dataDir = DATA_DIR$
|
|
4792
|
+
const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4793
|
+
async function handleGetPushStatus(input, dataDir = DATA_DIR$29) {
|
|
4771
4794
|
try {
|
|
4772
4795
|
let subs = await readSubscriptions(dataDir);
|
|
4773
4796
|
if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
|
|
@@ -4839,7 +4862,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
|
|
|
4839
4862
|
}, async ({ slug, provider }) => handleGetPushStatus({
|
|
4840
4863
|
...slug !== void 0 ? { slug } : {},
|
|
4841
4864
|
...provider !== void 0 ? { provider } : {}
|
|
4842
|
-
}, DATA_DIR$
|
|
4865
|
+
}, DATA_DIR$29));
|
|
4843
4866
|
}
|
|
4844
4867
|
//#endregion
|
|
4845
4868
|
//#region src/core/org-intelligence.ts
|
|
@@ -4905,8 +4928,8 @@ function deriveRecommendation(people, missingRoles) {
|
|
|
4905
4928
|
}
|
|
4906
4929
|
//#endregion
|
|
4907
4930
|
//#region src/mcp/tools/get-org-intelligence.ts
|
|
4908
|
-
const DATA_DIR$
|
|
4909
|
-
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$
|
|
4931
|
+
const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4932
|
+
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$28) {
|
|
4910
4933
|
try {
|
|
4911
4934
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4912
4935
|
const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
|
|
@@ -5039,8 +5062,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
|
|
|
5039
5062
|
}
|
|
5040
5063
|
//#endregion
|
|
5041
5064
|
//#region src/mcp/tools/open-deal-room.ts
|
|
5042
|
-
const DATA_DIR$
|
|
5043
|
-
async function handleOpenDealRoom(input, dataDir = DATA_DIR$
|
|
5065
|
+
const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5066
|
+
async function handleOpenDealRoom(input, dataDir = DATA_DIR$27) {
|
|
5044
5067
|
try {
|
|
5045
5068
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5046
5069
|
const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
|
|
@@ -5123,8 +5146,8 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
5123
5146
|
}
|
|
5124
5147
|
//#endregion
|
|
5125
5148
|
//#region src/mcp/tools/get-proactive-briefing.ts
|
|
5126
|
-
const DATA_DIR$
|
|
5127
|
-
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$
|
|
5149
|
+
const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5150
|
+
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$26) {
|
|
5128
5151
|
try {
|
|
5129
5152
|
const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
5130
5153
|
return { content: [{
|
|
@@ -5224,15 +5247,15 @@ function getTemplate(dataDir, id) {
|
|
|
5224
5247
|
}
|
|
5225
5248
|
//#endregion
|
|
5226
5249
|
//#region src/mcp/tools/list-email-templates.ts
|
|
5227
|
-
const DATA_DIR$
|
|
5228
|
-
async function handleListEmailTemplates(input, dataDir = DATA_DIR$
|
|
5250
|
+
const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5251
|
+
async function handleListEmailTemplates(input, dataDir = DATA_DIR$25) {
|
|
5229
5252
|
const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
|
|
5230
5253
|
return { content: [{
|
|
5231
5254
|
type: "text",
|
|
5232
5255
|
text: JSON.stringify(summary, null, 2)
|
|
5233
5256
|
}] };
|
|
5234
5257
|
}
|
|
5235
|
-
function registerListEmailTemplates(server, dataDir = DATA_DIR$
|
|
5258
|
+
function registerListEmailTemplates(server, dataDir = DATA_DIR$25) {
|
|
5236
5259
|
server.registerTool("list_email_templates", {
|
|
5237
5260
|
description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
|
|
5238
5261
|
inputSchema: z.object({ category: z.string().optional().describe("Filter by category") })
|
|
@@ -5266,8 +5289,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
|
|
|
5266
5289
|
}
|
|
5267
5290
|
//#endregion
|
|
5268
5291
|
//#region src/mcp/tools/get-email-template.ts
|
|
5269
|
-
const DATA_DIR$
|
|
5270
|
-
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$
|
|
5292
|
+
const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5293
|
+
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$24) {
|
|
5271
5294
|
const tmpl = getTemplate(dataDir, input.id);
|
|
5272
5295
|
if (!tmpl) return { content: [{
|
|
5273
5296
|
type: "text",
|
|
@@ -5283,7 +5306,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
|
|
|
5283
5306
|
}, null, 2)
|
|
5284
5307
|
}] };
|
|
5285
5308
|
}
|
|
5286
|
-
function registerGetEmailTemplate(server, dataDir = DATA_DIR$
|
|
5309
|
+
function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
|
|
5287
5310
|
server.registerTool("get_email_template", {
|
|
5288
5311
|
description: "Get a specific email template by ID, including its body and detected variables.",
|
|
5289
5312
|
inputSchema: z.object({ id: z.string().describe("Template ID (e.g. 'enterprise-intro')") })
|
|
@@ -5291,8 +5314,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
|
|
|
5291
5314
|
}
|
|
5292
5315
|
//#endregion
|
|
5293
5316
|
//#region src/mcp/tools/draft-email.ts
|
|
5294
|
-
const DATA_DIR$
|
|
5295
|
-
async function handleDraftEmail(input, dataDir = DATA_DIR$
|
|
5317
|
+
const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5318
|
+
async function handleDraftEmail(input, dataDir = DATA_DIR$23) {
|
|
5296
5319
|
const tmpl = getTemplate(dataDir, input.templateId);
|
|
5297
5320
|
if (!tmpl) return { content: [{
|
|
5298
5321
|
type: "text",
|
|
@@ -5336,7 +5359,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
|
|
|
5336
5359
|
}, null, 2)
|
|
5337
5360
|
}] };
|
|
5338
5361
|
}
|
|
5339
|
-
function registerDraftEmail(server, dataDir = DATA_DIR$
|
|
5362
|
+
function registerDraftEmail(server, dataDir = DATA_DIR$23) {
|
|
5340
5363
|
server.registerTool("draft_email", {
|
|
5341
5364
|
description: `Draft a personalized email for a customer using a stored template.
|
|
5342
5365
|
Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
|
|
@@ -5444,8 +5467,8 @@ async function updateEnrollment(dataDir, id, updates) {
|
|
|
5444
5467
|
}
|
|
5445
5468
|
//#endregion
|
|
5446
5469
|
//#region src/mcp/tools/enroll-in-sequence.ts
|
|
5447
|
-
const DATA_DIR$
|
|
5448
|
-
async function handleEnrollInSequence(input, dataDir = DATA_DIR$
|
|
5470
|
+
const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5471
|
+
async function handleEnrollInSequence(input, dataDir = DATA_DIR$22) {
|
|
5449
5472
|
const sequence = getSequence(dataDir, input.sequenceId);
|
|
5450
5473
|
if (!sequence) return { content: [{
|
|
5451
5474
|
type: "text",
|
|
@@ -5477,7 +5500,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
|
|
|
5477
5500
|
})
|
|
5478
5501
|
}] };
|
|
5479
5502
|
}
|
|
5480
|
-
function registerEnrollInSequence(server, dataDir = DATA_DIR$
|
|
5503
|
+
function registerEnrollInSequence(server, dataDir = DATA_DIR$22) {
|
|
5481
5504
|
server.registerTool("enroll_in_sequence", {
|
|
5482
5505
|
description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
|
|
5483
5506
|
Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
@@ -5494,8 +5517,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
|
5494
5517
|
}
|
|
5495
5518
|
//#endregion
|
|
5496
5519
|
//#region src/mcp/tools/list-sequence-enrollments.ts
|
|
5497
|
-
const DATA_DIR$
|
|
5498
|
-
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$
|
|
5520
|
+
const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5521
|
+
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$21) {
|
|
5499
5522
|
let enrollments = readEnrollments(dataDir);
|
|
5500
5523
|
if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
|
|
5501
5524
|
if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
|
|
@@ -5504,7 +5527,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
|
|
|
5504
5527
|
text: JSON.stringify({ enrollments }, null, 2)
|
|
5505
5528
|
}] };
|
|
5506
5529
|
}
|
|
5507
|
-
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$
|
|
5530
|
+
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$21) {
|
|
5508
5531
|
server.registerTool("list_sequence_enrollments", {
|
|
5509
5532
|
description: `List email sequence enrollments. Filter by customer slug or status.
|
|
5510
5533
|
Returns: { enrollments: SequenceEnrollment[] }`,
|
|
@@ -5523,8 +5546,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
|
|
|
5523
5546
|
}
|
|
5524
5547
|
//#endregion
|
|
5525
5548
|
//#region src/mcp/tools/unenroll-from-sequence.ts
|
|
5526
|
-
const DATA_DIR$
|
|
5527
|
-
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$
|
|
5549
|
+
const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5550
|
+
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$20) {
|
|
5528
5551
|
if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
|
|
5529
5552
|
type: "text",
|
|
5530
5553
|
text: JSON.stringify({
|
|
@@ -5537,7 +5560,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
|
|
|
5537
5560
|
text: JSON.stringify({ success: true })
|
|
5538
5561
|
}] };
|
|
5539
5562
|
}
|
|
5540
|
-
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$
|
|
5563
|
+
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$20) {
|
|
5541
5564
|
server.registerTool("unenroll_from_sequence", {
|
|
5542
5565
|
description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
|
|
5543
5566
|
Returns: { success: boolean }`,
|
|
@@ -5546,8 +5569,8 @@ Returns: { success: boolean }`,
|
|
|
5546
5569
|
}
|
|
5547
5570
|
//#endregion
|
|
5548
5571
|
//#region src/mcp/tools/list-sequences.ts
|
|
5549
|
-
const DATA_DIR$
|
|
5550
|
-
async function handleListSequences(_input, dataDir = DATA_DIR$
|
|
5572
|
+
const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5573
|
+
async function handleListSequences(_input, dataDir = DATA_DIR$19) {
|
|
5551
5574
|
const sequences = listSequences(dataDir);
|
|
5552
5575
|
const enrollments = readEnrollments(dataDir);
|
|
5553
5576
|
const result = sequences.map((seq) => ({
|
|
@@ -5561,7 +5584,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
|
|
|
5561
5584
|
text: JSON.stringify({ sequences: result }, null, 2)
|
|
5562
5585
|
}] };
|
|
5563
5586
|
}
|
|
5564
|
-
function registerListSequences(server, dataDir = DATA_DIR$
|
|
5587
|
+
function registerListSequences(server, dataDir = DATA_DIR$19) {
|
|
5565
5588
|
server.registerTool("list_sequences", {
|
|
5566
5589
|
description: `List all email sequences with step count and enrollment count.
|
|
5567
5590
|
Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
|
|
@@ -5696,8 +5719,8 @@ async function generateQuote(dataDir, input) {
|
|
|
5696
5719
|
}
|
|
5697
5720
|
//#endregion
|
|
5698
5721
|
//#region src/mcp/tools/generate-quote.ts
|
|
5699
|
-
const DATA_DIR$
|
|
5700
|
-
async function handleGenerateQuote(input, dataDir = DATA_DIR$
|
|
5722
|
+
const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5723
|
+
async function handleGenerateQuote(input, dataDir = DATA_DIR$18) {
|
|
5701
5724
|
try {
|
|
5702
5725
|
const quote = await generateQuote(dataDir, input);
|
|
5703
5726
|
return { content: [{
|
|
@@ -5721,7 +5744,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
|
|
|
5721
5744
|
}] };
|
|
5722
5745
|
}
|
|
5723
5746
|
}
|
|
5724
|
-
function registerGenerateQuote(server, dataDir = DATA_DIR$
|
|
5747
|
+
function registerGenerateQuote(server, dataDir = DATA_DIR$18) {
|
|
5725
5748
|
server.registerTool("generate_quote", {
|
|
5726
5749
|
description: `Generate a professional HTML quote/offer for a customer deal.
|
|
5727
5750
|
Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
|
|
@@ -5749,8 +5772,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
|
|
|
5749
5772
|
}
|
|
5750
5773
|
//#endregion
|
|
5751
5774
|
//#region src/mcp/tools/get-quote-status.ts
|
|
5752
|
-
const DATA_DIR$
|
|
5753
|
-
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$
|
|
5775
|
+
const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5776
|
+
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$17) {
|
|
5754
5777
|
if (input.quoteNumber) {
|
|
5755
5778
|
const quote = readQuote(dataDir, input.quoteNumber);
|
|
5756
5779
|
if (!quote) return { content: [{
|
|
@@ -5768,7 +5791,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
|
|
|
5768
5791
|
text: JSON.stringify({ quotes }, null, 2)
|
|
5769
5792
|
}] };
|
|
5770
5793
|
}
|
|
5771
|
-
function registerGetQuoteStatus(server, dataDir = DATA_DIR$
|
|
5794
|
+
function registerGetQuoteStatus(server, dataDir = DATA_DIR$17) {
|
|
5772
5795
|
server.registerTool("get_quote_status", {
|
|
5773
5796
|
description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
|
|
5774
5797
|
Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
@@ -5783,7 +5806,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
|
5783
5806
|
}
|
|
5784
5807
|
//#endregion
|
|
5785
5808
|
//#region src/mcp/tools/get-booking-link.ts
|
|
5786
|
-
const DATA_DIR$
|
|
5809
|
+
const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5787
5810
|
function loadCalendlyConfig(dataDir) {
|
|
5788
5811
|
const p = path.join(dataDir, ".agentic", "integrations", "calendly.yaml");
|
|
5789
5812
|
if (!fs.existsSync(p)) return {};
|
|
@@ -5806,7 +5829,7 @@ function readCustomerFacts(dataDir, slug) {
|
|
|
5806
5829
|
...email ? { email } : {}
|
|
5807
5830
|
};
|
|
5808
5831
|
}
|
|
5809
|
-
async function handleGetBookingLink(input, dataDir = DATA_DIR$
|
|
5832
|
+
async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
|
|
5810
5833
|
const config = loadCalendlyConfig(dataDir);
|
|
5811
5834
|
const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
|
|
5812
5835
|
if (!apiKey) return { content: [{
|
|
@@ -5834,7 +5857,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
|
|
|
5834
5857
|
}] };
|
|
5835
5858
|
}
|
|
5836
5859
|
}
|
|
5837
|
-
function registerGetBookingLink(server, dataDir = DATA_DIR$
|
|
5860
|
+
function registerGetBookingLink(server, dataDir = DATA_DIR$16) {
|
|
5838
5861
|
server.registerTool("get_booking_link", {
|
|
5839
5862
|
description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
|
|
5840
5863
|
Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
|
|
@@ -6004,8 +6027,8 @@ function calcSlaDue(createdDate, priority, rules) {
|
|
|
6004
6027
|
}
|
|
6005
6028
|
//#endregion
|
|
6006
6029
|
//#region src/mcp/tools/create-ticket.ts
|
|
6007
|
-
const DATA_DIR$
|
|
6008
|
-
async function handleCreateTicket(input, dataDir = DATA_DIR$
|
|
6030
|
+
const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6031
|
+
async function handleCreateTicket(input, dataDir = DATA_DIR$15) {
|
|
6009
6032
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6010
6033
|
const rules = loadSlaRules(dataDir);
|
|
6011
6034
|
const priority = input.priority ?? "normal";
|
|
@@ -6027,7 +6050,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
|
|
|
6027
6050
|
text: JSON.stringify({ ticket }, null, 2)
|
|
6028
6051
|
}] };
|
|
6029
6052
|
}
|
|
6030
|
-
function registerCreateTicket(server, dataDir = DATA_DIR$
|
|
6053
|
+
function registerCreateTicket(server, dataDir = DATA_DIR$15) {
|
|
6031
6054
|
server.registerTool("create_ticket", {
|
|
6032
6055
|
description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
|
|
6033
6056
|
Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
@@ -6053,8 +6076,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
|
6053
6076
|
}
|
|
6054
6077
|
//#endregion
|
|
6055
6078
|
//#region src/mcp/tools/update-ticket.ts
|
|
6056
|
-
const DATA_DIR$
|
|
6057
|
-
async function handleUpdateTicket(input, dataDir = DATA_DIR$
|
|
6079
|
+
const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6080
|
+
async function handleUpdateTicket(input, dataDir = DATA_DIR$14) {
|
|
6058
6081
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6059
6082
|
if (!ticket) return { content: [{
|
|
6060
6083
|
type: "text",
|
|
@@ -6073,7 +6096,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
|
|
|
6073
6096
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6074
6097
|
}] };
|
|
6075
6098
|
}
|
|
6076
|
-
function registerUpdateTicket(server, dataDir = DATA_DIR$
|
|
6099
|
+
function registerUpdateTicket(server, dataDir = DATA_DIR$14) {
|
|
6077
6100
|
server.registerTool("update_ticket", {
|
|
6078
6101
|
description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
|
|
6079
6102
|
Returns: { ticket }`,
|
|
@@ -6098,8 +6121,8 @@ Returns: { ticket }`,
|
|
|
6098
6121
|
}
|
|
6099
6122
|
//#endregion
|
|
6100
6123
|
//#region src/mcp/tools/list-tickets.ts
|
|
6101
|
-
const DATA_DIR$
|
|
6102
|
-
async function handleListTickets(input, dataDir = DATA_DIR$
|
|
6124
|
+
const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6125
|
+
async function handleListTickets(input, dataDir = DATA_DIR$13) {
|
|
6103
6126
|
const results = await listAllTickets(dataDir, {
|
|
6104
6127
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
6105
6128
|
...input.status !== void 0 ? { status: input.status } : {},
|
|
@@ -6111,7 +6134,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$12) {
|
|
|
6111
6134
|
text: JSON.stringify({ tickets: results }, null, 2)
|
|
6112
6135
|
}] };
|
|
6113
6136
|
}
|
|
6114
|
-
function registerListTickets(server, dataDir = DATA_DIR$
|
|
6137
|
+
function registerListTickets(server, dataDir = DATA_DIR$13) {
|
|
6115
6138
|
server.registerTool("list_tickets", {
|
|
6116
6139
|
description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
|
|
6117
6140
|
Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
@@ -6141,8 +6164,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
|
6141
6164
|
}
|
|
6142
6165
|
//#endregion
|
|
6143
6166
|
//#region src/mcp/tools/close-ticket.ts
|
|
6144
|
-
const DATA_DIR$
|
|
6145
|
-
async function handleCloseTicket(input, dataDir = DATA_DIR$
|
|
6167
|
+
const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6168
|
+
async function handleCloseTicket(input, dataDir = DATA_DIR$12) {
|
|
6146
6169
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6147
6170
|
if (!ticket) return { content: [{
|
|
6148
6171
|
type: "text",
|
|
@@ -6169,7 +6192,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
|
|
|
6169
6192
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6170
6193
|
}] };
|
|
6171
6194
|
}
|
|
6172
|
-
function registerCloseTicket(server, dataDir = DATA_DIR$
|
|
6195
|
+
function registerCloseTicket(server, dataDir = DATA_DIR$12) {
|
|
6173
6196
|
server.registerTool("close_ticket", {
|
|
6174
6197
|
description: `Close a support ticket. Optionally logs the resolution as an interaction.
|
|
6175
6198
|
Returns: { ticket } with status=closed`,
|
|
@@ -6323,8 +6346,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
|
|
|
6323
6346
|
}
|
|
6324
6347
|
//#endregion
|
|
6325
6348
|
//#region src/mcp/tools/send-nps-survey.ts
|
|
6326
|
-
const DATA_DIR$
|
|
6327
|
-
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$
|
|
6349
|
+
const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6350
|
+
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$11) {
|
|
6328
6351
|
const survey = getSurvey(dataDir, input.surveyId);
|
|
6329
6352
|
if (!survey) return { content: [{
|
|
6330
6353
|
type: "text",
|
|
@@ -6345,7 +6368,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
|
|
|
6345
6368
|
}, null, 2)
|
|
6346
6369
|
}] };
|
|
6347
6370
|
}
|
|
6348
|
-
function registerSendNpsSurvey(server, dataDir = DATA_DIR$
|
|
6371
|
+
function registerSendNpsSurvey(server, dataDir = DATA_DIR$11) {
|
|
6349
6372
|
server.registerTool("send_nps_survey", {
|
|
6350
6373
|
description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
|
|
6351
6374
|
Does NOT send automatically — returns draft for review.
|
|
@@ -6365,8 +6388,8 @@ Returns: { token, subject, body, surveyUrl }`,
|
|
|
6365
6388
|
}
|
|
6366
6389
|
//#endregion
|
|
6367
6390
|
//#region src/mcp/tools/get-survey-results.ts
|
|
6368
|
-
const DATA_DIR$
|
|
6369
|
-
async function handleGetSurveyResults(input, dataDir = DATA_DIR$
|
|
6391
|
+
const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6392
|
+
async function handleGetSurveyResults(input, dataDir = DATA_DIR$10) {
|
|
6370
6393
|
const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
|
|
6371
6394
|
const nps = calcNpsScore(responses);
|
|
6372
6395
|
const promoters = responses.filter((r) => r.score >= 9).length;
|
|
@@ -6392,7 +6415,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
|
|
|
6392
6415
|
}, null, 2)
|
|
6393
6416
|
}] };
|
|
6394
6417
|
}
|
|
6395
|
-
function registerGetSurveyResults(server, dataDir = DATA_DIR$
|
|
6418
|
+
function registerGetSurveyResults(server, dataDir = DATA_DIR$10) {
|
|
6396
6419
|
server.registerTool("get_survey_results", {
|
|
6397
6420
|
description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
|
|
6398
6421
|
Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
|
|
@@ -6493,8 +6516,8 @@ function getKbMetaForExport(article) {
|
|
|
6493
6516
|
}
|
|
6494
6517
|
//#endregion
|
|
6495
6518
|
//#region src/mcp/tools/search-knowledge-base.ts
|
|
6496
|
-
const DATA_DIR$
|
|
6497
|
-
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$
|
|
6519
|
+
const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6520
|
+
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$9) {
|
|
6498
6521
|
const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
|
|
6499
6522
|
const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
|
|
6500
6523
|
return { content: [{
|
|
@@ -6509,7 +6532,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
|
|
|
6509
6532
|
}, null, 2)
|
|
6510
6533
|
}] };
|
|
6511
6534
|
}
|
|
6512
|
-
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$
|
|
6535
|
+
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$9) {
|
|
6513
6536
|
server.registerTool("search_knowledge_base", {
|
|
6514
6537
|
description: `Search the knowledge base for articles. Text search on title, body, and tags.
|
|
6515
6538
|
Returns: { count, articles[] } with excerpts`,
|
|
@@ -6528,8 +6551,8 @@ Returns: { count, articles[] } with excerpts`,
|
|
|
6528
6551
|
}
|
|
6529
6552
|
//#endregion
|
|
6530
6553
|
//#region src/mcp/tools/create-kb-article.ts
|
|
6531
|
-
const DATA_DIR$
|
|
6532
|
-
async function handleCreateKbArticle(input, dataDir = DATA_DIR$
|
|
6554
|
+
const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6555
|
+
async function handleCreateKbArticle(input, dataDir = DATA_DIR$8) {
|
|
6533
6556
|
if (getKbArticle(dataDir, input.id)) return { content: [{
|
|
6534
6557
|
type: "text",
|
|
6535
6558
|
text: JSON.stringify({ error: `Article '${input.id}' already exists` })
|
|
@@ -6557,7 +6580,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
|
|
|
6557
6580
|
}, null, 2)
|
|
6558
6581
|
}] };
|
|
6559
6582
|
}
|
|
6560
|
-
function registerCreateKbArticle(server, dataDir = DATA_DIR$
|
|
6583
|
+
function registerCreateKbArticle(server, dataDir = DATA_DIR$8) {
|
|
6561
6584
|
server.registerTool("create_kb_article", {
|
|
6562
6585
|
description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
|
|
6563
6586
|
Returns: { id, title, category, path }`,
|
|
@@ -6582,8 +6605,8 @@ Returns: { id, title, category, path }`,
|
|
|
6582
6605
|
}
|
|
6583
6606
|
//#endregion
|
|
6584
6607
|
//#region src/mcp/tools/backup-now.ts
|
|
6585
|
-
const DATA_DIR$
|
|
6586
|
-
async function handleBackupNow(input, dataDir = DATA_DIR$
|
|
6608
|
+
const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6609
|
+
async function handleBackupNow(input, dataDir = DATA_DIR$7) {
|
|
6587
6610
|
const zipPath = path.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
|
|
6588
6611
|
const manifest = await runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
|
|
6589
6612
|
if (!manifest) return { content: [{
|
|
@@ -6620,8 +6643,8 @@ function registerBackupNow(server) {
|
|
|
6620
6643
|
}
|
|
6621
6644
|
//#endregion
|
|
6622
6645
|
//#region src/mcp/tools/list-backups.ts
|
|
6623
|
-
const DATA_DIR$
|
|
6624
|
-
async function handleListBackups(input, dataDir = DATA_DIR$
|
|
6646
|
+
const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6647
|
+
async function handleListBackups(input, dataDir = DATA_DIR$6) {
|
|
6625
6648
|
const logEntries = readBackupLog(dataDir);
|
|
6626
6649
|
const fileEntries = listBackupsInDir(dataDir);
|
|
6627
6650
|
const entries = logEntries.length > 0 ? logEntries : fileEntries;
|
|
@@ -6655,8 +6678,8 @@ function registerListBackups(server) {
|
|
|
6655
6678
|
}
|
|
6656
6679
|
//#endregion
|
|
6657
6680
|
//#region src/mcp/tools/trigger-sync.ts
|
|
6658
|
-
const DATA_DIR$
|
|
6659
|
-
async function handleTriggerSync(input, dataDir = DATA_DIR$
|
|
6681
|
+
const DATA_DIR$5 = process.cwd();
|
|
6682
|
+
async function handleTriggerSync(input, dataDir = DATA_DIR$5) {
|
|
6660
6683
|
const auth = getGmailAuth();
|
|
6661
6684
|
if (!auth) return { content: [{
|
|
6662
6685
|
type: "text",
|
|
@@ -6691,7 +6714,7 @@ async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
|
|
|
6691
6714
|
try {
|
|
6692
6715
|
const sources = JSON.parse(fs.readFileSync(sourcesPath, "utf-8"));
|
|
6693
6716
|
if (!sources.gmail?.enabled || !sources.gmail.query) continue;
|
|
6694
|
-
const { syncGmail } = await import("./gmail-sync-
|
|
6717
|
+
const { syncGmail } = await import("./gmail-sync-DIbrPnTK.js");
|
|
6695
6718
|
const result = await syncGmail({
|
|
6696
6719
|
slug,
|
|
6697
6720
|
dataDir,
|
|
@@ -6750,8 +6773,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
|
|
|
6750
6773
|
}
|
|
6751
6774
|
//#endregion
|
|
6752
6775
|
//#region src/mcp/tools/get-audit-log.ts
|
|
6753
|
-
const DATA_DIR$
|
|
6754
|
-
async function handleGetAuditLog(input, dataDir = DATA_DIR$
|
|
6776
|
+
const DATA_DIR$4 = process.cwd();
|
|
6777
|
+
async function handleGetAuditLog(input, dataDir = DATA_DIR$4) {
|
|
6755
6778
|
const entries = readAuditLog(dataDir);
|
|
6756
6779
|
const filterOpts = { limit: input.limit ?? 50 };
|
|
6757
6780
|
if (input.slug !== void 0) filterOpts.slug = input.slug;
|
|
@@ -6793,8 +6816,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
|
|
|
6793
6816
|
}
|
|
6794
6817
|
//#endregion
|
|
6795
6818
|
//#region src/mcp/tools/get-logs.ts
|
|
6796
|
-
const DATA_DIR$
|
|
6797
|
-
async function handleGetLogs(input, dataDir = DATA_DIR$
|
|
6819
|
+
const DATA_DIR$3 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6820
|
+
async function handleGetLogs(input, dataDir = DATA_DIR$3) {
|
|
6798
6821
|
const query = {
|
|
6799
6822
|
...input.level !== void 0 ? { level: input.level } : {},
|
|
6800
6823
|
...input.component !== void 0 ? { component: input.component } : {},
|
|
@@ -6855,6 +6878,140 @@ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors
|
|
|
6855
6878
|
});
|
|
6856
6879
|
}
|
|
6857
6880
|
//#endregion
|
|
6881
|
+
//#region src/core/doctor.ts
|
|
6882
|
+
var doctor_exports = /* @__PURE__ */ __exportAll({
|
|
6883
|
+
cleanupTempFiles: () => cleanupTempFiles,
|
|
6884
|
+
runDiagnostics: () => runDiagnostics
|
|
6885
|
+
});
|
|
6886
|
+
/** Recursively collect files whose name matches the atomic-write temp pattern. */
|
|
6887
|
+
function findOrphanedTempFiles(dir, depth = 0) {
|
|
6888
|
+
if (depth > 3 || !fs.existsSync(dir)) return [];
|
|
6889
|
+
const out = [];
|
|
6890
|
+
let entries;
|
|
6891
|
+
try {
|
|
6892
|
+
entries = fs.readdirSync(dir);
|
|
6893
|
+
} catch {
|
|
6894
|
+
return [];
|
|
6895
|
+
}
|
|
6896
|
+
for (const entry of entries) {
|
|
6897
|
+
const full = path.join(dir, entry);
|
|
6898
|
+
let isDir = false;
|
|
6899
|
+
try {
|
|
6900
|
+
isDir = fs.statSync(full).isDirectory();
|
|
6901
|
+
} catch {
|
|
6902
|
+
continue;
|
|
6903
|
+
}
|
|
6904
|
+
if (isDir) out.push(...findOrphanedTempFiles(full, depth + 1));
|
|
6905
|
+
else if (/\.\d+\.[0-9a-f]+\.tmp$/.test(entry)) out.push(full);
|
|
6906
|
+
}
|
|
6907
|
+
return out;
|
|
6908
|
+
}
|
|
6909
|
+
/** Delete orphaned atomic-write temp files; returns the paths removed. */
|
|
6910
|
+
function cleanupTempFiles(dataDir) {
|
|
6911
|
+
const temps = [...findOrphanedTempFiles(path.join(dataDir, ".agentic")), ...findOrphanedTempFiles(path.join(dataDir, "customers"))];
|
|
6912
|
+
const removed = [];
|
|
6913
|
+
for (const f of temps) try {
|
|
6914
|
+
fs.rmSync(f, { force: true });
|
|
6915
|
+
removed.push(f);
|
|
6916
|
+
} catch {}
|
|
6917
|
+
return removed;
|
|
6918
|
+
}
|
|
6919
|
+
async function runDiagnostics(dataDir) {
|
|
6920
|
+
const checks = [];
|
|
6921
|
+
const agenticDir = path.join(dataDir, ".agentic");
|
|
6922
|
+
const customersDir = path.join(dataDir, "customers");
|
|
6923
|
+
if (!fs.existsSync(agenticDir) && !fs.existsSync(customersDir)) checks.push({
|
|
6924
|
+
name: "data directory",
|
|
6925
|
+
status: "fail",
|
|
6926
|
+
detail: `Neither .agentic/ nor customers/ found under ${dataDir} — run 'dxcrm init'`
|
|
6927
|
+
});
|
|
6928
|
+
else checks.push({
|
|
6929
|
+
name: "data directory",
|
|
6930
|
+
status: "ok",
|
|
6931
|
+
detail: dataDir
|
|
6932
|
+
});
|
|
6933
|
+
const slugs = listCustomerSlugs(dataDir);
|
|
6934
|
+
const invalid = [];
|
|
6935
|
+
for (const slug of slugs) try {
|
|
6936
|
+
await readMainFacts(dataDir, slug);
|
|
6937
|
+
} catch {
|
|
6938
|
+
invalid.push(slug);
|
|
6939
|
+
}
|
|
6940
|
+
checks.push({
|
|
6941
|
+
name: "customer data",
|
|
6942
|
+
status: invalid.length > 0 ? "fail" : "ok",
|
|
6943
|
+
detail: invalid.length > 0 ? `${invalid.length} of ${slugs.length} invalid: ${invalid.slice(0, 5).join(", ")}` : `${slugs.length} customer(s) valid`
|
|
6944
|
+
});
|
|
6945
|
+
const temps = [...findOrphanedTempFiles(agenticDir), ...findOrphanedTempFiles(customersDir)];
|
|
6946
|
+
checks.push({
|
|
6947
|
+
name: "temp files",
|
|
6948
|
+
status: temps.length > 0 ? "warn" : "ok",
|
|
6949
|
+
detail: temps.length > 0 ? `${temps.length} orphaned temp file(s) from interrupted writes — safe to delete` : "no orphaned temp files"
|
|
6950
|
+
});
|
|
6951
|
+
const summary = summarizeLogs(dataDir);
|
|
6952
|
+
const errorCount = summary.byLevel.error;
|
|
6953
|
+
checks.push({
|
|
6954
|
+
name: "logs",
|
|
6955
|
+
status: errorCount > 0 ? "warn" : "ok",
|
|
6956
|
+
detail: errorCount > 0 ? `${errorCount} error entr${errorCount === 1 ? "y" : "ies"} in the log (dxcrm logs --level error)` : `${summary.total} log entr${summary.total === 1 ? "y" : "ies"}, no errors`
|
|
6957
|
+
});
|
|
6958
|
+
const backupLogPath = path.join(agenticDir, "backup-log.json");
|
|
6959
|
+
if (fs.existsSync(backupLogPath)) try {
|
|
6960
|
+
const entries = JSON.parse(fs.readFileSync(backupLogPath, "utf-8"));
|
|
6961
|
+
const last = entries[entries.length - 1]?.createdAt;
|
|
6962
|
+
const ageDays = last ? Math.floor((Date.now() - new Date(last).getTime()) / 864e5) : Infinity;
|
|
6963
|
+
checks.push({
|
|
6964
|
+
name: "backups",
|
|
6965
|
+
status: ageDays > 7 ? "warn" : "ok",
|
|
6966
|
+
detail: last ? `last backup ${ageDays}d ago` : "no backups recorded"
|
|
6967
|
+
});
|
|
6968
|
+
} catch {
|
|
6969
|
+
checks.push({
|
|
6970
|
+
name: "backups",
|
|
6971
|
+
status: "warn",
|
|
6972
|
+
detail: "backup log unreadable"
|
|
6973
|
+
});
|
|
6974
|
+
}
|
|
6975
|
+
return {
|
|
6976
|
+
ok: !checks.some((c) => c.status === "fail"),
|
|
6977
|
+
checks
|
|
6978
|
+
};
|
|
6979
|
+
}
|
|
6980
|
+
//#endregion
|
|
6981
|
+
//#region src/mcp/tools/get-diagnostics.ts
|
|
6982
|
+
const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6983
|
+
async function handleGetDiagnostics(input, dataDir = DATA_DIR$2) {
|
|
6984
|
+
let cleaned = 0;
|
|
6985
|
+
if (input.fix) {
|
|
6986
|
+
const { cleanupTempFiles } = await Promise.resolve().then(() => doctor_exports);
|
|
6987
|
+
cleaned = cleanupTempFiles(dataDir).length;
|
|
6988
|
+
}
|
|
6989
|
+
const report = await runDiagnostics(dataDir);
|
|
6990
|
+
return { content: [{
|
|
6991
|
+
type: "text",
|
|
6992
|
+
text: JSON.stringify({
|
|
6993
|
+
ok: report.ok,
|
|
6994
|
+
...input.fix ? { tempFilesRemoved: cleaned } : {},
|
|
6995
|
+
checks: report.checks
|
|
6996
|
+
}, null, 2)
|
|
6997
|
+
}] };
|
|
6998
|
+
}
|
|
6999
|
+
function registerGetDiagnostics(server) {
|
|
7000
|
+
server.registerTool("get_diagnostics", {
|
|
7001
|
+
title: "Get Diagnostics",
|
|
7002
|
+
description: `Run a self-diagnostic health check of the CRM workspace.
|
|
7003
|
+
Verifies the data directory, validates every customer's profile, detects orphaned
|
|
7004
|
+
atomic-write temp files (a crash signature), surfaces recent log errors, and checks
|
|
7005
|
+
backup freshness. Use to answer "is everything healthy?" before/after bulk operations.
|
|
7006
|
+
|
|
7007
|
+
Args:
|
|
7008
|
+
fix: When true, first remove orphaned temp files (the only safely auto-fixable issue)
|
|
7009
|
+
|
|
7010
|
+
Returns: { ok: boolean, tempFilesRemoved?: number, checks: [{ name, status: "ok"|"warn"|"fail", detail }] }`,
|
|
7011
|
+
inputSchema: z.object({ fix: z.boolean().optional().describe("Clean orphaned temp files before reporting") })
|
|
7012
|
+
}, async ({ fix }) => handleGetDiagnostics(fix !== void 0 ? { fix } : {}));
|
|
7013
|
+
}
|
|
7014
|
+
//#endregion
|
|
6858
7015
|
//#region src/mcp/prompts.ts
|
|
6859
7016
|
/**
|
|
6860
7017
|
* CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
|
|
@@ -6949,7 +7106,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
|
|
|
6949
7106
|
description: "Newest-first interaction history for a customer",
|
|
6950
7107
|
mimeType: "text/markdown"
|
|
6951
7108
|
}, async (uri, variables) => {
|
|
6952
|
-
const { readInteractions } = await import("./interactions-writer-
|
|
7109
|
+
const { readInteractions } = await import("./interactions-writer-ZQcpFOh9.js").then((n) => n.r);
|
|
6953
7110
|
const text = await readInteractions(dataDir, String(variables["slug"]));
|
|
6954
7111
|
return { contents: [{
|
|
6955
7112
|
uri: uri.href,
|
|
@@ -7271,6 +7428,7 @@ function createMcpServer() {
|
|
|
7271
7428
|
registerTriggerSync(server);
|
|
7272
7429
|
registerGetAuditLog(server);
|
|
7273
7430
|
registerGetLogs(server);
|
|
7431
|
+
registerGetDiagnostics(server);
|
|
7274
7432
|
registerCustomObjectTools(server);
|
|
7275
7433
|
registerPrompts(server);
|
|
7276
7434
|
registerResources(server);
|