@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.cjs
CHANGED
|
@@ -3,7 +3,7 @@ const require_chunk = require("./chunk-DakpK96I.cjs");
|
|
|
3
3
|
const require_session_store = require("./session-store-yfwnj0OC.cjs");
|
|
4
4
|
const require_atomic_write = require("./atomic-write-BYmF-ThH.cjs");
|
|
5
5
|
const require_write_queue = require("./write-queue-BDolUxfs.cjs");
|
|
6
|
-
const require_interactions_writer = require("./interactions-writer-
|
|
6
|
+
const require_interactions_writer = require("./interactions-writer-BRJNrefF.cjs");
|
|
7
7
|
const require_logger = require("./logger-BkInaGoV.cjs");
|
|
8
8
|
const require_pipeline_writer = require("./pipeline-writer-B1tRAhuD.cjs");
|
|
9
9
|
const require_llm = require("./llm-CXycmEl9.cjs");
|
|
@@ -405,7 +405,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
405
405
|
| log_interaction | Write a new interaction entry (call, email, meeting, note) — immediately searchable | rep+ |
|
|
406
406
|
| update_deal | Create or update a deal in pipeline.md — upserts by deal name | rep+ |
|
|
407
407
|
| update_customer_facts | Update fields in customer profile (domain, contact, stage, tags) | admin |
|
|
408
|
-
| export_customer | Export all customer data as JSON or Markdown | admin |
|
|
408
|
+
| export_customer | Export all customer data (incl. attachment contents) as JSON or Markdown | admin |
|
|
409
409
|
| get_deal_health | Score deal health 0–100 (A–F grade) based on activity, velocity, close date, probability | any |
|
|
410
410
|
| get_pipeline_forecast | Aggregate weighted pipeline revenue across all customers grouped by stage | any |
|
|
411
411
|
| get_pipeline_stages | List all configured pipeline stages (defaults: lead, qualified, proposal, negotiation, won, lost) | any |
|
|
@@ -450,6 +450,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
450
450
|
| trigger_sync | Force immediate Gmail sync for one or all customers | rep+ |
|
|
451
451
|
| get_audit_log | Read audit log — all write operations with actor, tool, customer | admin |
|
|
452
452
|
| get_logs | Query/aggregate the structured application log (level, component, errors) | admin |
|
|
453
|
+
| get_diagnostics | Self-diagnostic health check (data integrity, temp files, log errors, backups) | admin |
|
|
453
454
|
| define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
|
|
454
455
|
| create_record | Create a record of a custom object (validated against its schema) | rep+ |
|
|
455
456
|
| list_records | List records of a custom object | any |
|
|
@@ -539,12 +540,14 @@ RBAC: admin
|
|
|
539
540
|
- Input: slug (required) + any combination of the optional fields
|
|
540
541
|
- Returns: { success: boolean, facts: object }
|
|
541
542
|
|
|
542
|
-
### export_customer({ slug, format? })
|
|
543
|
-
Export all customer data (main_facts + interactions
|
|
543
|
+
### export_customer({ slug, format?, includeAttachmentContent? })
|
|
544
|
+
Export all customer data (main_facts + interactions + pipeline + attachments).
|
|
545
|
+
Set includeAttachmentContent to inline every attachment's converted Markdown —
|
|
546
|
+
a single sendable bundle of all conversations and documents for the customer.
|
|
544
547
|
RBAC: admin
|
|
545
|
-
- Input: { slug: string, format?: "json" | "markdown" (default "json") }
|
|
546
|
-
- Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments }
|
|
547
|
-
- Returns (Markdown): Formatted document with all sections
|
|
548
|
+
- Input: { slug: string, format?: "json" | "markdown" (default "json"), includeAttachmentContent?: boolean (default false) }
|
|
549
|
+
- Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
|
|
550
|
+
- Returns (Markdown): Formatted document with all sections (and attachment contents when requested)
|
|
548
551
|
|
|
549
552
|
### get_deal_health({ slug })
|
|
550
553
|
Score the health of all deals for a customer based on activity recency, stage velocity,
|
|
@@ -1426,7 +1429,7 @@ async function buildContext(dataDir, slug) {
|
|
|
1426
1429
|
}
|
|
1427
1430
|
//#endregion
|
|
1428
1431
|
//#region src/mcp/tools/get-customer-context.ts
|
|
1429
|
-
const DATA_DIR$
|
|
1432
|
+
const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1430
1433
|
function triggerOnQuerySync(dataDir, slug) {
|
|
1431
1434
|
const auth = getGmailAuth();
|
|
1432
1435
|
if (!auth) return;
|
|
@@ -1439,7 +1442,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1439
1442
|
const sources = JSON.parse(fs.default.readFileSync(sourcesPath, "utf-8"));
|
|
1440
1443
|
if (!sources.gmail?.enabled || !sources.gmail.query) return;
|
|
1441
1444
|
const query = sources.gmail.query;
|
|
1442
|
-
Promise.resolve().then(() => require("./gmail-sync-
|
|
1445
|
+
Promise.resolve().then(() => require("./gmail-sync-BpSVESSe.cjs")).then(({ syncGmail }) => syncGmail({
|
|
1443
1446
|
slug,
|
|
1444
1447
|
dataDir,
|
|
1445
1448
|
auth,
|
|
@@ -1447,7 +1450,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1447
1450
|
}).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
|
|
1448
1451
|
} catch {}
|
|
1449
1452
|
}
|
|
1450
|
-
async function handleGetCustomerContext(input, dataDir = DATA_DIR$
|
|
1453
|
+
async function handleGetCustomerContext(input, dataDir = DATA_DIR$53) {
|
|
1451
1454
|
const targetSlug = input.slug ?? require_session_store.getSession()?.customerSlug;
|
|
1452
1455
|
if (!targetSlug) return {
|
|
1453
1456
|
content: [{
|
|
@@ -1583,8 +1586,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
|
|
|
1583
1586
|
}
|
|
1584
1587
|
//#endregion
|
|
1585
1588
|
//#region src/mcp/tools/search-customer-knowledge.ts
|
|
1586
|
-
const DATA_DIR$
|
|
1587
|
-
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$
|
|
1589
|
+
const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1590
|
+
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$52) {
|
|
1588
1591
|
const limit = input.limit ?? 5;
|
|
1589
1592
|
try {
|
|
1590
1593
|
const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
|
|
@@ -1632,14 +1635,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
|
|
|
1632
1635
|
}
|
|
1633
1636
|
//#endregion
|
|
1634
1637
|
//#region src/mcp/tools/list-customers.ts
|
|
1635
|
-
const DATA_DIR$
|
|
1638
|
+
const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1636
1639
|
function extractLastInteractionDate(interactionsPath) {
|
|
1637
1640
|
if (!fs.default.existsSync(interactionsPath)) return void 0;
|
|
1638
1641
|
const content = fs.default.readFileSync(interactionsPath, "utf-8");
|
|
1639
1642
|
const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
|
|
1640
1643
|
return match ? match[1] : void 0;
|
|
1641
1644
|
}
|
|
1642
|
-
async function handleListCustomers(input, dataDir = DATA_DIR$
|
|
1645
|
+
async function handleListCustomers(input, dataDir = DATA_DIR$51) {
|
|
1643
1646
|
const customersDir = path.default.join(dataDir, "customers");
|
|
1644
1647
|
const customers = [];
|
|
1645
1648
|
if (!fs.default.existsSync(customersDir)) return { content: [{
|
|
@@ -2152,8 +2155,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
|
|
|
2152
2155
|
}
|
|
2153
2156
|
//#endregion
|
|
2154
2157
|
//#region src/mcp/tools/log-interaction.ts
|
|
2155
|
-
const DATA_DIR$
|
|
2156
|
-
async function handleLogInteraction(input, dataDir = DATA_DIR$
|
|
2158
|
+
const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2159
|
+
async function handleLogInteraction(input, dataDir = DATA_DIR$50) {
|
|
2157
2160
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2158
2161
|
const interactionDate = input.date ?? today;
|
|
2159
2162
|
const sourceRef = input.source ?? `agent://log/${Date.now()}`;
|
|
@@ -2262,8 +2265,8 @@ var update_deal_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
|
2262
2265
|
handleUpdateDeal: () => handleUpdateDeal,
|
|
2263
2266
|
registerUpdateDeal: () => registerUpdateDeal
|
|
2264
2267
|
});
|
|
2265
|
-
const DATA_DIR$
|
|
2266
|
-
async function handleUpdateDeal(input, dataDir = DATA_DIR$
|
|
2268
|
+
const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2269
|
+
async function handleUpdateDeal(input, dataDir = DATA_DIR$49) {
|
|
2267
2270
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2268
2271
|
const deal = {
|
|
2269
2272
|
name: input.dealName,
|
|
@@ -2346,12 +2349,12 @@ Returns: { success: boolean, deal: object }`,
|
|
|
2346
2349
|
}
|
|
2347
2350
|
//#endregion
|
|
2348
2351
|
//#region src/mcp/tools/export-customer.ts
|
|
2349
|
-
const DATA_DIR$
|
|
2352
|
+
const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2350
2353
|
function countInteractions(content) {
|
|
2351
2354
|
const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
2352
2355
|
return matches ? matches.length : 0;
|
|
2353
2356
|
}
|
|
2354
|
-
async function handleExportCustomer(input, dataDir = DATA_DIR$
|
|
2357
|
+
async function handleExportCustomer(input, dataDir = DATA_DIR$48) {
|
|
2355
2358
|
require_session_store.enforceRbac(dataDir, "export_customer");
|
|
2356
2359
|
const customerDir = path.default.join(dataDir, "customers", input.slug);
|
|
2357
2360
|
if (!fs.default.existsSync(customerDir)) return {
|
|
@@ -2378,14 +2381,27 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2378
2381
|
interactionsCount = countInteractions(interactionsContent);
|
|
2379
2382
|
}
|
|
2380
2383
|
const pipeline = await require_pipeline_writer.readPipeline(dataDir, input.slug);
|
|
2384
|
+
const includeAttachmentContent = input.includeAttachmentContent ?? false;
|
|
2381
2385
|
const attachmentsDir = path.default.join(customerDir, "attachments");
|
|
2382
2386
|
const attachments = [];
|
|
2387
|
+
const attachmentContents = {};
|
|
2383
2388
|
if (fs.default.existsSync(attachmentsDir)) try {
|
|
2384
2389
|
const files = fs.default.readdirSync(attachmentsDir);
|
|
2385
2390
|
for (const f of files) try {
|
|
2386
|
-
if (fs.default.statSync(path.default.join(attachmentsDir, f)).isFile())
|
|
2391
|
+
if (!fs.default.statSync(path.default.join(attachmentsDir, f)).isFile()) continue;
|
|
2392
|
+
attachments.push(f);
|
|
2393
|
+
if (includeAttachmentContent && f.endsWith(".md")) attachmentContents[f] = fs.default.readFileSync(path.default.join(attachmentsDir, f), "utf-8");
|
|
2387
2394
|
} catch {}
|
|
2388
2395
|
} catch {}
|
|
2396
|
+
const attachmentContentSection = () => {
|
|
2397
|
+
const entries = Object.entries(attachmentContents);
|
|
2398
|
+
if (!includeAttachmentContent || entries.length === 0) return [];
|
|
2399
|
+
return [
|
|
2400
|
+
"",
|
|
2401
|
+
`## Attachment Contents (${entries.length})`,
|
|
2402
|
+
...entries.map(([name, content]) => `\n### ${name}\n\n${content.trim()}`)
|
|
2403
|
+
];
|
|
2404
|
+
};
|
|
2389
2405
|
if (format === "markdown") return { content: [{
|
|
2390
2406
|
type: "text",
|
|
2391
2407
|
text: [
|
|
@@ -2404,7 +2420,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2404
2420
|
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)",
|
|
2405
2421
|
"",
|
|
2406
2422
|
`## Attachments (${attachments.length})`,
|
|
2407
|
-
attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)"
|
|
2423
|
+
attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)",
|
|
2424
|
+
...attachmentContentSection()
|
|
2408
2425
|
].join("\n")
|
|
2409
2426
|
}] };
|
|
2410
2427
|
const exported = {
|
|
@@ -2413,7 +2430,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2413
2430
|
mainFacts,
|
|
2414
2431
|
interactionsCount,
|
|
2415
2432
|
pipeline,
|
|
2416
|
-
attachments
|
|
2433
|
+
attachments,
|
|
2434
|
+
...includeAttachmentContent ? { attachmentContents } : {}
|
|
2417
2435
|
};
|
|
2418
2436
|
return { content: [{
|
|
2419
2437
|
type: "text",
|
|
@@ -2423,29 +2441,34 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
|
|
|
2423
2441
|
function registerExportCustomer(server) {
|
|
2424
2442
|
server.registerTool("export_customer", {
|
|
2425
2443
|
title: "Export Customer",
|
|
2426
|
-
description: `Export all customer data (main_facts + interactions
|
|
2427
|
-
Useful for reporting, audits, or creating
|
|
2444
|
+
description: `Export all customer data (main_facts + interactions + pipeline deals + attachments).
|
|
2445
|
+
Useful for reporting, audits, handoffs, or creating a complete sendable bundle
|
|
2446
|
+
of every conversation and document for a customer.
|
|
2428
2447
|
|
|
2429
2448
|
Args:
|
|
2430
2449
|
slug: Customer ID (e.g. "acme-corp")
|
|
2431
2450
|
format: Output format — "json" (default) or "markdown"
|
|
2451
|
+
includeAttachmentContent: Inline the converted Markdown of every attachment
|
|
2452
|
+
(default false). Use this to produce a single self-contained bundle.
|
|
2432
2453
|
|
|
2433
2454
|
Returns:
|
|
2434
|
-
JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline }
|
|
2435
|
-
Markdown: Formatted document with all sections`,
|
|
2455
|
+
JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
|
|
2456
|
+
Markdown: Formatted document with all sections (and attachment contents when requested)`,
|
|
2436
2457
|
inputSchema: zod.z.object({
|
|
2437
2458
|
slug: zod.z.string().describe("Customer slug (e.g. 'acme-corp')"),
|
|
2438
|
-
format: zod.z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'")
|
|
2459
|
+
format: zod.z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'"),
|
|
2460
|
+
includeAttachmentContent: zod.z.boolean().optional().describe("Inline converted attachment Markdown into the export (default false)")
|
|
2439
2461
|
})
|
|
2440
|
-
}, async ({ slug, format }) => handleExportCustomer({
|
|
2462
|
+
}, async ({ slug, format, includeAttachmentContent }) => handleExportCustomer({
|
|
2441
2463
|
slug,
|
|
2442
|
-
...format !== void 0 ? { format } : {}
|
|
2464
|
+
...format !== void 0 ? { format } : {},
|
|
2465
|
+
...includeAttachmentContent !== void 0 ? { includeAttachmentContent } : {}
|
|
2443
2466
|
}));
|
|
2444
2467
|
}
|
|
2445
2468
|
//#endregion
|
|
2446
2469
|
//#region src/mcp/tools/update-customer-facts.ts
|
|
2447
|
-
const DATA_DIR$
|
|
2448
|
-
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$
|
|
2470
|
+
const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2471
|
+
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$47) {
|
|
2449
2472
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2450
2473
|
try {
|
|
2451
2474
|
require_session_store.enforceRbac(dataDir, "update_customer_facts");
|
|
@@ -2623,8 +2646,8 @@ function scoreDealForToday(deal, todayDate) {
|
|
|
2623
2646
|
}
|
|
2624
2647
|
//#endregion
|
|
2625
2648
|
//#region src/mcp/tools/get-deal-health.ts
|
|
2626
|
-
const DATA_DIR$
|
|
2627
|
-
async function handleGetDealHealth(input, dataDir = DATA_DIR$
|
|
2649
|
+
const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2650
|
+
async function handleGetDealHealth(input, dataDir = DATA_DIR$46) {
|
|
2628
2651
|
try {
|
|
2629
2652
|
const deals = await require_pipeline_writer.readPipeline(dataDir, input.slug);
|
|
2630
2653
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2673,8 +2696,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
|
|
|
2673
2696
|
}
|
|
2674
2697
|
//#endregion
|
|
2675
2698
|
//#region src/mcp/tools/get-pipeline-forecast.ts
|
|
2676
|
-
const DATA_DIR$
|
|
2677
|
-
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$
|
|
2699
|
+
const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2700
|
+
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$45) {
|
|
2678
2701
|
try {
|
|
2679
2702
|
const slugs = require_session_store.listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
|
|
2680
2703
|
const allDeals = [];
|
|
@@ -2735,8 +2758,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
|
|
|
2735
2758
|
}
|
|
2736
2759
|
//#endregion
|
|
2737
2760
|
//#region src/mcp/tools/summarize-meeting.ts
|
|
2738
|
-
const DATA_DIR$
|
|
2739
|
-
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$
|
|
2761
|
+
const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2762
|
+
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$44) {
|
|
2740
2763
|
try {
|
|
2741
2764
|
let summary = input.transcript.slice(0, 400);
|
|
2742
2765
|
let nextSteps = [];
|
|
@@ -2859,8 +2882,8 @@ function getPipelineStages(dataDir) {
|
|
|
2859
2882
|
}
|
|
2860
2883
|
//#endregion
|
|
2861
2884
|
//#region src/mcp/tools/get-pipeline-stages.ts
|
|
2862
|
-
const DATA_DIR$
|
|
2863
|
-
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$
|
|
2885
|
+
const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2886
|
+
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$43) {
|
|
2864
2887
|
const stages = getPipelineStages(dataDir);
|
|
2865
2888
|
return { content: [{
|
|
2866
2889
|
type: "text",
|
|
@@ -2888,8 +2911,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
|
|
|
2888
2911
|
}
|
|
2889
2912
|
//#endregion
|
|
2890
2913
|
//#region src/mcp/tools/get-market-intelligence.ts
|
|
2891
|
-
const DATA_DIR$
|
|
2892
|
-
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$
|
|
2914
|
+
const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2915
|
+
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$42) {
|
|
2893
2916
|
const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
|
|
2894
2917
|
const all = require_session_store.listCustomerSlugs(dataDir);
|
|
2895
2918
|
const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
|
|
@@ -2920,7 +2943,7 @@ function registerGetMarketIntelligence(server) {
|
|
|
2920
2943
|
}
|
|
2921
2944
|
//#endregion
|
|
2922
2945
|
//#region src/mcp/tools/get-relationship-graph.ts
|
|
2923
|
-
const DATA_DIR$
|
|
2946
|
+
const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2924
2947
|
function summarizeNode(n) {
|
|
2925
2948
|
return {
|
|
2926
2949
|
id: n.id,
|
|
@@ -2928,7 +2951,7 @@ function summarizeNode(n) {
|
|
|
2928
2951
|
email: n.properties["email"]
|
|
2929
2952
|
};
|
|
2930
2953
|
}
|
|
2931
|
-
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$
|
|
2954
|
+
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$41) {
|
|
2932
2955
|
try {
|
|
2933
2956
|
const graph = readGraph(dataDir, input.slug);
|
|
2934
2957
|
const stakeholders = getStakeholders(graph);
|
|
@@ -2996,9 +3019,9 @@ Returns: {
|
|
|
2996
3019
|
}
|
|
2997
3020
|
//#endregion
|
|
2998
3021
|
//#region src/mcp/tools/get-relationship-health.ts
|
|
2999
|
-
const DATA_DIR$
|
|
3022
|
+
const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3000
3023
|
const MAX_HEALTH_AGE_MS = 3600 * 1e3;
|
|
3001
|
-
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$
|
|
3024
|
+
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$40) {
|
|
3002
3025
|
try {
|
|
3003
3026
|
let health = readHealth(dataDir, input.slug);
|
|
3004
3027
|
if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
|
|
@@ -3548,7 +3571,7 @@ async function executeAction(action, dataDir) {
|
|
|
3548
3571
|
if (!slug) return "skipped";
|
|
3549
3572
|
switch (action.type) {
|
|
3550
3573
|
case "log_interaction": {
|
|
3551
|
-
const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-
|
|
3574
|
+
const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
|
|
3552
3575
|
await appendInteraction(dataDir, slug, {
|
|
3553
3576
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3554
3577
|
type: action.payload["type"] ?? "Note",
|
|
@@ -3561,7 +3584,7 @@ async function executeAction(action, dataDir) {
|
|
|
3561
3584
|
return "executed";
|
|
3562
3585
|
}
|
|
3563
3586
|
case "schedule_meeting": {
|
|
3564
|
-
const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-
|
|
3587
|
+
const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
|
|
3565
3588
|
await appendInteraction(dataDir, slug, {
|
|
3566
3589
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
3567
3590
|
type: "Note",
|
|
@@ -3667,8 +3690,8 @@ async function runDealAgent(config, dataDir, llmFn = require_llm.callLlm) {
|
|
|
3667
3690
|
}
|
|
3668
3691
|
//#endregion
|
|
3669
3692
|
//#region src/mcp/tools/run-deal-agent.ts
|
|
3670
|
-
const DATA_DIR$
|
|
3671
|
-
async function handleRunDealAgent(input, dataDir = DATA_DIR$
|
|
3693
|
+
const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3694
|
+
async function handleRunDealAgent(input, dataDir = DATA_DIR$39) {
|
|
3672
3695
|
try {
|
|
3673
3696
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3674
3697
|
const result = await runDealAgent({
|
|
@@ -3735,8 +3758,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
|
|
|
3735
3758
|
}
|
|
3736
3759
|
//#endregion
|
|
3737
3760
|
//#region src/mcp/tools/approve-agent-action.ts
|
|
3738
|
-
const DATA_DIR$
|
|
3739
|
-
async function handleApproveAgentAction(input, dataDir = DATA_DIR$
|
|
3761
|
+
const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3762
|
+
async function handleApproveAgentAction(input, dataDir = DATA_DIR$38) {
|
|
3740
3763
|
try {
|
|
3741
3764
|
const queue = readAgentQueue(dataDir, input.slug);
|
|
3742
3765
|
const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
|
|
@@ -3996,8 +4019,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
|
|
|
3996
4019
|
}
|
|
3997
4020
|
//#endregion
|
|
3998
4021
|
//#region src/mcp/tools/simulate-revenue.ts
|
|
3999
|
-
const DATA_DIR$
|
|
4000
|
-
async function handleSimulateRevenue(input, dataDir = DATA_DIR$
|
|
4022
|
+
const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4023
|
+
async function handleSimulateRevenue(input, dataDir = DATA_DIR$37) {
|
|
4001
4024
|
try {
|
|
4002
4025
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4003
4026
|
const horizon = input.horizon ?? "quarter";
|
|
@@ -4055,8 +4078,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
|
|
|
4055
4078
|
}
|
|
4056
4079
|
//#endregion
|
|
4057
4080
|
//#region src/mcp/tools/get-playbook.ts
|
|
4058
|
-
const DATA_DIR$
|
|
4059
|
-
async function handleGetPlaybook(input, dataDir = DATA_DIR$
|
|
4081
|
+
const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4082
|
+
async function handleGetPlaybook(input, dataDir = DATA_DIR$36) {
|
|
4060
4083
|
try {
|
|
4061
4084
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4062
4085
|
if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
|
|
@@ -4141,12 +4164,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
|
|
|
4141
4164
|
...healthScore !== void 0 ? { healthScore } : {},
|
|
4142
4165
|
...daysSinceContact !== void 0 ? { daysSinceContact } : {},
|
|
4143
4166
|
...championPresent !== void 0 ? { championPresent } : {}
|
|
4144
|
-
}, DATA_DIR$
|
|
4167
|
+
}, DATA_DIR$36));
|
|
4145
4168
|
}
|
|
4146
4169
|
//#endregion
|
|
4147
4170
|
//#region src/mcp/tools/create-playbook.ts
|
|
4148
|
-
const DATA_DIR$
|
|
4149
|
-
async function handleCreatePlaybook(input, dataDir = DATA_DIR$
|
|
4171
|
+
const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4172
|
+
async function handleCreatePlaybook(input, dataDir = DATA_DIR$35) {
|
|
4150
4173
|
try {
|
|
4151
4174
|
const name = toKebabCase(input.name);
|
|
4152
4175
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -4219,12 +4242,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
|
|
|
4219
4242
|
trigger,
|
|
4220
4243
|
content,
|
|
4221
4244
|
...successRate !== void 0 ? { successRate } : {}
|
|
4222
|
-
}, DATA_DIR$
|
|
4245
|
+
}, DATA_DIR$35));
|
|
4223
4246
|
}
|
|
4224
4247
|
//#endregion
|
|
4225
4248
|
//#region src/mcp/tools/list-playbooks.ts
|
|
4226
|
-
const DATA_DIR$
|
|
4227
|
-
async function handleListPlaybooks(input, dataDir = DATA_DIR$
|
|
4249
|
+
const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4250
|
+
async function handleListPlaybooks(input, dataDir = DATA_DIR$34) {
|
|
4228
4251
|
try {
|
|
4229
4252
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4230
4253
|
return { content: [{
|
|
@@ -4263,12 +4286,12 @@ Args:
|
|
|
4263
4286
|
|
|
4264
4287
|
Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
|
|
4265
4288
|
inputSchema: zod.z.object({ slug: zod.z.string().describe("Customer ID") })
|
|
4266
|
-
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$
|
|
4289
|
+
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$34));
|
|
4267
4290
|
}
|
|
4268
4291
|
//#endregion
|
|
4269
4292
|
//#region src/mcp/tools/distill-playbook.ts
|
|
4270
|
-
const DATA_DIR$
|
|
4271
|
-
async function handleDistillPlaybook(input, dataDir = DATA_DIR$
|
|
4293
|
+
const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4294
|
+
async function handleDistillPlaybook(input, dataDir = DATA_DIR$33, llmFn = require_llm.callLlm) {
|
|
4272
4295
|
try {
|
|
4273
4296
|
const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
|
|
4274
4297
|
if (!result.ok) {
|
|
@@ -4327,7 +4350,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
|
|
|
4327
4350
|
slug,
|
|
4328
4351
|
dealName,
|
|
4329
4352
|
outcome
|
|
4330
|
-
}, DATA_DIR$
|
|
4353
|
+
}, DATA_DIR$33));
|
|
4331
4354
|
}
|
|
4332
4355
|
//#endregion
|
|
4333
4356
|
//#region src/core/goal-engine.ts
|
|
@@ -4545,8 +4568,8 @@ function getActiveGoals(dataDir) {
|
|
|
4545
4568
|
}
|
|
4546
4569
|
//#endregion
|
|
4547
4570
|
//#region src/mcp/tools/pursue-goal.ts
|
|
4548
|
-
const DATA_DIR$
|
|
4549
|
-
async function handlePursueGoal(input, dataDir = DATA_DIR$
|
|
4571
|
+
const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4572
|
+
async function handlePursueGoal(input, dataDir = DATA_DIR$32, options = {}) {
|
|
4550
4573
|
try {
|
|
4551
4574
|
require_session_store.enforceRbac(dataDir, "pursue_goal");
|
|
4552
4575
|
const goal = await pursueGoal(dataDir, {
|
|
@@ -4609,12 +4632,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
|
|
|
4609
4632
|
goal,
|
|
4610
4633
|
deadline,
|
|
4611
4634
|
...context !== void 0 ? { context } : {}
|
|
4612
|
-
}, DATA_DIR$
|
|
4635
|
+
}, DATA_DIR$32));
|
|
4613
4636
|
}
|
|
4614
4637
|
//#endregion
|
|
4615
4638
|
//#region src/mcp/tools/get-goal-status.ts
|
|
4616
|
-
const DATA_DIR$
|
|
4617
|
-
async function handleGetGoalStatus(input, dataDir = DATA_DIR$
|
|
4639
|
+
const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4640
|
+
async function handleGetGoalStatus(input, dataDir = DATA_DIR$31) {
|
|
4618
4641
|
try {
|
|
4619
4642
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4620
4643
|
const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
|
|
@@ -4673,17 +4696,17 @@ Args:
|
|
|
4673
4696
|
|
|
4674
4697
|
Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
|
|
4675
4698
|
inputSchema: zod.z.object({ goalId: zod.z.string().optional().describe("Specific goal ID (omit for all active goals)") })
|
|
4676
|
-
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$
|
|
4699
|
+
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$31));
|
|
4677
4700
|
}
|
|
4678
4701
|
//#endregion
|
|
4679
4702
|
//#region src/mcp/tools/register-push-subscription.ts
|
|
4680
|
-
const DATA_DIR$
|
|
4703
|
+
const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4681
4704
|
const VALID_PROVIDERS = [
|
|
4682
4705
|
"gmail",
|
|
4683
4706
|
"microsoft-graph",
|
|
4684
4707
|
"slack"
|
|
4685
4708
|
];
|
|
4686
|
-
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$
|
|
4709
|
+
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$30) {
|
|
4687
4710
|
try {
|
|
4688
4711
|
if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
|
|
4689
4712
|
type: "text",
|
|
@@ -4769,12 +4792,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
|
|
|
4769
4792
|
...microsoftResource !== void 0 ? { microsoftResource } : {},
|
|
4770
4793
|
...slackTeamId !== void 0 ? { slackTeamId } : {},
|
|
4771
4794
|
...slackChannelId !== void 0 ? { slackChannelId } : {}
|
|
4772
|
-
}, DATA_DIR$
|
|
4795
|
+
}, DATA_DIR$30));
|
|
4773
4796
|
}
|
|
4774
4797
|
//#endregion
|
|
4775
4798
|
//#region src/mcp/tools/get-push-status.ts
|
|
4776
|
-
const DATA_DIR$
|
|
4777
|
-
async function handleGetPushStatus(input, dataDir = DATA_DIR$
|
|
4799
|
+
const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4800
|
+
async function handleGetPushStatus(input, dataDir = DATA_DIR$29) {
|
|
4778
4801
|
try {
|
|
4779
4802
|
let subs = await readSubscriptions(dataDir);
|
|
4780
4803
|
if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
|
|
@@ -4846,7 +4869,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
|
|
|
4846
4869
|
}, async ({ slug, provider }) => handleGetPushStatus({
|
|
4847
4870
|
...slug !== void 0 ? { slug } : {},
|
|
4848
4871
|
...provider !== void 0 ? { provider } : {}
|
|
4849
|
-
}, DATA_DIR$
|
|
4872
|
+
}, DATA_DIR$29));
|
|
4850
4873
|
}
|
|
4851
4874
|
//#endregion
|
|
4852
4875
|
//#region src/core/org-intelligence.ts
|
|
@@ -4912,8 +4935,8 @@ function deriveRecommendation(people, missingRoles) {
|
|
|
4912
4935
|
}
|
|
4913
4936
|
//#endregion
|
|
4914
4937
|
//#region src/mcp/tools/get-org-intelligence.ts
|
|
4915
|
-
const DATA_DIR$
|
|
4916
|
-
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$
|
|
4938
|
+
const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4939
|
+
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$28) {
|
|
4917
4940
|
try {
|
|
4918
4941
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4919
4942
|
const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
|
|
@@ -5046,8 +5069,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
|
|
|
5046
5069
|
}
|
|
5047
5070
|
//#endregion
|
|
5048
5071
|
//#region src/mcp/tools/open-deal-room.ts
|
|
5049
|
-
const DATA_DIR$
|
|
5050
|
-
async function handleOpenDealRoom(input, dataDir = DATA_DIR$
|
|
5072
|
+
const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5073
|
+
async function handleOpenDealRoom(input, dataDir = DATA_DIR$27) {
|
|
5051
5074
|
try {
|
|
5052
5075
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5053
5076
|
const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
|
|
@@ -5130,8 +5153,8 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
5130
5153
|
}
|
|
5131
5154
|
//#endregion
|
|
5132
5155
|
//#region src/mcp/tools/get-proactive-briefing.ts
|
|
5133
|
-
const DATA_DIR$
|
|
5134
|
-
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$
|
|
5156
|
+
const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5157
|
+
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$26) {
|
|
5135
5158
|
try {
|
|
5136
5159
|
const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
5137
5160
|
return { content: [{
|
|
@@ -5231,15 +5254,15 @@ function getTemplate(dataDir, id) {
|
|
|
5231
5254
|
}
|
|
5232
5255
|
//#endregion
|
|
5233
5256
|
//#region src/mcp/tools/list-email-templates.ts
|
|
5234
|
-
const DATA_DIR$
|
|
5235
|
-
async function handleListEmailTemplates(input, dataDir = DATA_DIR$
|
|
5257
|
+
const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5258
|
+
async function handleListEmailTemplates(input, dataDir = DATA_DIR$25) {
|
|
5236
5259
|
const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
|
|
5237
5260
|
return { content: [{
|
|
5238
5261
|
type: "text",
|
|
5239
5262
|
text: JSON.stringify(summary, null, 2)
|
|
5240
5263
|
}] };
|
|
5241
5264
|
}
|
|
5242
|
-
function registerListEmailTemplates(server, dataDir = DATA_DIR$
|
|
5265
|
+
function registerListEmailTemplates(server, dataDir = DATA_DIR$25) {
|
|
5243
5266
|
server.registerTool("list_email_templates", {
|
|
5244
5267
|
description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
|
|
5245
5268
|
inputSchema: zod.z.object({ category: zod.z.string().optional().describe("Filter by category") })
|
|
@@ -5273,8 +5296,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
|
|
|
5273
5296
|
}
|
|
5274
5297
|
//#endregion
|
|
5275
5298
|
//#region src/mcp/tools/get-email-template.ts
|
|
5276
|
-
const DATA_DIR$
|
|
5277
|
-
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$
|
|
5299
|
+
const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5300
|
+
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$24) {
|
|
5278
5301
|
const tmpl = getTemplate(dataDir, input.id);
|
|
5279
5302
|
if (!tmpl) return { content: [{
|
|
5280
5303
|
type: "text",
|
|
@@ -5290,7 +5313,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
|
|
|
5290
5313
|
}, null, 2)
|
|
5291
5314
|
}] };
|
|
5292
5315
|
}
|
|
5293
|
-
function registerGetEmailTemplate(server, dataDir = DATA_DIR$
|
|
5316
|
+
function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
|
|
5294
5317
|
server.registerTool("get_email_template", {
|
|
5295
5318
|
description: "Get a specific email template by ID, including its body and detected variables.",
|
|
5296
5319
|
inputSchema: zod.z.object({ id: zod.z.string().describe("Template ID (e.g. 'enterprise-intro')") })
|
|
@@ -5298,8 +5321,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
|
|
|
5298
5321
|
}
|
|
5299
5322
|
//#endregion
|
|
5300
5323
|
//#region src/mcp/tools/draft-email.ts
|
|
5301
|
-
const DATA_DIR$
|
|
5302
|
-
async function handleDraftEmail(input, dataDir = DATA_DIR$
|
|
5324
|
+
const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5325
|
+
async function handleDraftEmail(input, dataDir = DATA_DIR$23) {
|
|
5303
5326
|
const tmpl = getTemplate(dataDir, input.templateId);
|
|
5304
5327
|
if (!tmpl) return { content: [{
|
|
5305
5328
|
type: "text",
|
|
@@ -5343,7 +5366,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
|
|
|
5343
5366
|
}, null, 2)
|
|
5344
5367
|
}] };
|
|
5345
5368
|
}
|
|
5346
|
-
function registerDraftEmail(server, dataDir = DATA_DIR$
|
|
5369
|
+
function registerDraftEmail(server, dataDir = DATA_DIR$23) {
|
|
5347
5370
|
server.registerTool("draft_email", {
|
|
5348
5371
|
description: `Draft a personalized email for a customer using a stored template.
|
|
5349
5372
|
Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
|
|
@@ -5451,8 +5474,8 @@ async function updateEnrollment(dataDir, id, updates) {
|
|
|
5451
5474
|
}
|
|
5452
5475
|
//#endregion
|
|
5453
5476
|
//#region src/mcp/tools/enroll-in-sequence.ts
|
|
5454
|
-
const DATA_DIR$
|
|
5455
|
-
async function handleEnrollInSequence(input, dataDir = DATA_DIR$
|
|
5477
|
+
const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5478
|
+
async function handleEnrollInSequence(input, dataDir = DATA_DIR$22) {
|
|
5456
5479
|
const sequence = getSequence(dataDir, input.sequenceId);
|
|
5457
5480
|
if (!sequence) return { content: [{
|
|
5458
5481
|
type: "text",
|
|
@@ -5484,7 +5507,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
|
|
|
5484
5507
|
})
|
|
5485
5508
|
}] };
|
|
5486
5509
|
}
|
|
5487
|
-
function registerEnrollInSequence(server, dataDir = DATA_DIR$
|
|
5510
|
+
function registerEnrollInSequence(server, dataDir = DATA_DIR$22) {
|
|
5488
5511
|
server.registerTool("enroll_in_sequence", {
|
|
5489
5512
|
description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
|
|
5490
5513
|
Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
@@ -5501,8 +5524,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
|
5501
5524
|
}
|
|
5502
5525
|
//#endregion
|
|
5503
5526
|
//#region src/mcp/tools/list-sequence-enrollments.ts
|
|
5504
|
-
const DATA_DIR$
|
|
5505
|
-
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$
|
|
5527
|
+
const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5528
|
+
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$21) {
|
|
5506
5529
|
let enrollments = readEnrollments(dataDir);
|
|
5507
5530
|
if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
|
|
5508
5531
|
if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
|
|
@@ -5511,7 +5534,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
|
|
|
5511
5534
|
text: JSON.stringify({ enrollments }, null, 2)
|
|
5512
5535
|
}] };
|
|
5513
5536
|
}
|
|
5514
|
-
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$
|
|
5537
|
+
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$21) {
|
|
5515
5538
|
server.registerTool("list_sequence_enrollments", {
|
|
5516
5539
|
description: `List email sequence enrollments. Filter by customer slug or status.
|
|
5517
5540
|
Returns: { enrollments: SequenceEnrollment[] }`,
|
|
@@ -5530,8 +5553,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
|
|
|
5530
5553
|
}
|
|
5531
5554
|
//#endregion
|
|
5532
5555
|
//#region src/mcp/tools/unenroll-from-sequence.ts
|
|
5533
|
-
const DATA_DIR$
|
|
5534
|
-
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$
|
|
5556
|
+
const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5557
|
+
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$20) {
|
|
5535
5558
|
if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
|
|
5536
5559
|
type: "text",
|
|
5537
5560
|
text: JSON.stringify({
|
|
@@ -5544,7 +5567,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
|
|
|
5544
5567
|
text: JSON.stringify({ success: true })
|
|
5545
5568
|
}] };
|
|
5546
5569
|
}
|
|
5547
|
-
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$
|
|
5570
|
+
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$20) {
|
|
5548
5571
|
server.registerTool("unenroll_from_sequence", {
|
|
5549
5572
|
description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
|
|
5550
5573
|
Returns: { success: boolean }`,
|
|
@@ -5553,8 +5576,8 @@ Returns: { success: boolean }`,
|
|
|
5553
5576
|
}
|
|
5554
5577
|
//#endregion
|
|
5555
5578
|
//#region src/mcp/tools/list-sequences.ts
|
|
5556
|
-
const DATA_DIR$
|
|
5557
|
-
async function handleListSequences(_input, dataDir = DATA_DIR$
|
|
5579
|
+
const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5580
|
+
async function handleListSequences(_input, dataDir = DATA_DIR$19) {
|
|
5558
5581
|
const sequences = listSequences(dataDir);
|
|
5559
5582
|
const enrollments = readEnrollments(dataDir);
|
|
5560
5583
|
const result = sequences.map((seq) => ({
|
|
@@ -5568,7 +5591,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
|
|
|
5568
5591
|
text: JSON.stringify({ sequences: result }, null, 2)
|
|
5569
5592
|
}] };
|
|
5570
5593
|
}
|
|
5571
|
-
function registerListSequences(server, dataDir = DATA_DIR$
|
|
5594
|
+
function registerListSequences(server, dataDir = DATA_DIR$19) {
|
|
5572
5595
|
server.registerTool("list_sequences", {
|
|
5573
5596
|
description: `List all email sequences with step count and enrollment count.
|
|
5574
5597
|
Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
|
|
@@ -5703,8 +5726,8 @@ async function generateQuote(dataDir, input) {
|
|
|
5703
5726
|
}
|
|
5704
5727
|
//#endregion
|
|
5705
5728
|
//#region src/mcp/tools/generate-quote.ts
|
|
5706
|
-
const DATA_DIR$
|
|
5707
|
-
async function handleGenerateQuote(input, dataDir = DATA_DIR$
|
|
5729
|
+
const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5730
|
+
async function handleGenerateQuote(input, dataDir = DATA_DIR$18) {
|
|
5708
5731
|
try {
|
|
5709
5732
|
const quote = await generateQuote(dataDir, input);
|
|
5710
5733
|
return { content: [{
|
|
@@ -5728,7 +5751,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
|
|
|
5728
5751
|
}] };
|
|
5729
5752
|
}
|
|
5730
5753
|
}
|
|
5731
|
-
function registerGenerateQuote(server, dataDir = DATA_DIR$
|
|
5754
|
+
function registerGenerateQuote(server, dataDir = DATA_DIR$18) {
|
|
5732
5755
|
server.registerTool("generate_quote", {
|
|
5733
5756
|
description: `Generate a professional HTML quote/offer for a customer deal.
|
|
5734
5757
|
Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
|
|
@@ -5756,8 +5779,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
|
|
|
5756
5779
|
}
|
|
5757
5780
|
//#endregion
|
|
5758
5781
|
//#region src/mcp/tools/get-quote-status.ts
|
|
5759
|
-
const DATA_DIR$
|
|
5760
|
-
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$
|
|
5782
|
+
const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5783
|
+
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$17) {
|
|
5761
5784
|
if (input.quoteNumber) {
|
|
5762
5785
|
const quote = readQuote(dataDir, input.quoteNumber);
|
|
5763
5786
|
if (!quote) return { content: [{
|
|
@@ -5775,7 +5798,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
|
|
|
5775
5798
|
text: JSON.stringify({ quotes }, null, 2)
|
|
5776
5799
|
}] };
|
|
5777
5800
|
}
|
|
5778
|
-
function registerGetQuoteStatus(server, dataDir = DATA_DIR$
|
|
5801
|
+
function registerGetQuoteStatus(server, dataDir = DATA_DIR$17) {
|
|
5779
5802
|
server.registerTool("get_quote_status", {
|
|
5780
5803
|
description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
|
|
5781
5804
|
Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
@@ -5790,7 +5813,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
|
5790
5813
|
}
|
|
5791
5814
|
//#endregion
|
|
5792
5815
|
//#region src/mcp/tools/get-booking-link.ts
|
|
5793
|
-
const DATA_DIR$
|
|
5816
|
+
const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5794
5817
|
function loadCalendlyConfig(dataDir) {
|
|
5795
5818
|
const p = path.default.join(dataDir, ".agentic", "integrations", "calendly.yaml");
|
|
5796
5819
|
if (!fs.default.existsSync(p)) return {};
|
|
@@ -5813,7 +5836,7 @@ function readCustomerFacts(dataDir, slug) {
|
|
|
5813
5836
|
...email ? { email } : {}
|
|
5814
5837
|
};
|
|
5815
5838
|
}
|
|
5816
|
-
async function handleGetBookingLink(input, dataDir = DATA_DIR$
|
|
5839
|
+
async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
|
|
5817
5840
|
const config = loadCalendlyConfig(dataDir);
|
|
5818
5841
|
const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
|
|
5819
5842
|
if (!apiKey) return { content: [{
|
|
@@ -5841,7 +5864,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
|
|
|
5841
5864
|
}] };
|
|
5842
5865
|
}
|
|
5843
5866
|
}
|
|
5844
|
-
function registerGetBookingLink(server, dataDir = DATA_DIR$
|
|
5867
|
+
function registerGetBookingLink(server, dataDir = DATA_DIR$16) {
|
|
5845
5868
|
server.registerTool("get_booking_link", {
|
|
5846
5869
|
description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
|
|
5847
5870
|
Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
|
|
@@ -6011,8 +6034,8 @@ function calcSlaDue(createdDate, priority, rules) {
|
|
|
6011
6034
|
}
|
|
6012
6035
|
//#endregion
|
|
6013
6036
|
//#region src/mcp/tools/create-ticket.ts
|
|
6014
|
-
const DATA_DIR$
|
|
6015
|
-
async function handleCreateTicket(input, dataDir = DATA_DIR$
|
|
6037
|
+
const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6038
|
+
async function handleCreateTicket(input, dataDir = DATA_DIR$15) {
|
|
6016
6039
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6017
6040
|
const rules = loadSlaRules(dataDir);
|
|
6018
6041
|
const priority = input.priority ?? "normal";
|
|
@@ -6034,7 +6057,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
|
|
|
6034
6057
|
text: JSON.stringify({ ticket }, null, 2)
|
|
6035
6058
|
}] };
|
|
6036
6059
|
}
|
|
6037
|
-
function registerCreateTicket(server, dataDir = DATA_DIR$
|
|
6060
|
+
function registerCreateTicket(server, dataDir = DATA_DIR$15) {
|
|
6038
6061
|
server.registerTool("create_ticket", {
|
|
6039
6062
|
description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
|
|
6040
6063
|
Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
@@ -6060,8 +6083,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
|
6060
6083
|
}
|
|
6061
6084
|
//#endregion
|
|
6062
6085
|
//#region src/mcp/tools/update-ticket.ts
|
|
6063
|
-
const DATA_DIR$
|
|
6064
|
-
async function handleUpdateTicket(input, dataDir = DATA_DIR$
|
|
6086
|
+
const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6087
|
+
async function handleUpdateTicket(input, dataDir = DATA_DIR$14) {
|
|
6065
6088
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6066
6089
|
if (!ticket) return { content: [{
|
|
6067
6090
|
type: "text",
|
|
@@ -6080,7 +6103,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
|
|
|
6080
6103
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6081
6104
|
}] };
|
|
6082
6105
|
}
|
|
6083
|
-
function registerUpdateTicket(server, dataDir = DATA_DIR$
|
|
6106
|
+
function registerUpdateTicket(server, dataDir = DATA_DIR$14) {
|
|
6084
6107
|
server.registerTool("update_ticket", {
|
|
6085
6108
|
description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
|
|
6086
6109
|
Returns: { ticket }`,
|
|
@@ -6105,8 +6128,8 @@ Returns: { ticket }`,
|
|
|
6105
6128
|
}
|
|
6106
6129
|
//#endregion
|
|
6107
6130
|
//#region src/mcp/tools/list-tickets.ts
|
|
6108
|
-
const DATA_DIR$
|
|
6109
|
-
async function handleListTickets(input, dataDir = DATA_DIR$
|
|
6131
|
+
const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6132
|
+
async function handleListTickets(input, dataDir = DATA_DIR$13) {
|
|
6110
6133
|
const results = await listAllTickets(dataDir, {
|
|
6111
6134
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
6112
6135
|
...input.status !== void 0 ? { status: input.status } : {},
|
|
@@ -6118,7 +6141,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$12) {
|
|
|
6118
6141
|
text: JSON.stringify({ tickets: results }, null, 2)
|
|
6119
6142
|
}] };
|
|
6120
6143
|
}
|
|
6121
|
-
function registerListTickets(server, dataDir = DATA_DIR$
|
|
6144
|
+
function registerListTickets(server, dataDir = DATA_DIR$13) {
|
|
6122
6145
|
server.registerTool("list_tickets", {
|
|
6123
6146
|
description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
|
|
6124
6147
|
Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
@@ -6148,8 +6171,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
|
6148
6171
|
}
|
|
6149
6172
|
//#endregion
|
|
6150
6173
|
//#region src/mcp/tools/close-ticket.ts
|
|
6151
|
-
const DATA_DIR$
|
|
6152
|
-
async function handleCloseTicket(input, dataDir = DATA_DIR$
|
|
6174
|
+
const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6175
|
+
async function handleCloseTicket(input, dataDir = DATA_DIR$12) {
|
|
6153
6176
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6154
6177
|
if (!ticket) return { content: [{
|
|
6155
6178
|
type: "text",
|
|
@@ -6176,7 +6199,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
|
|
|
6176
6199
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6177
6200
|
}] };
|
|
6178
6201
|
}
|
|
6179
|
-
function registerCloseTicket(server, dataDir = DATA_DIR$
|
|
6202
|
+
function registerCloseTicket(server, dataDir = DATA_DIR$12) {
|
|
6180
6203
|
server.registerTool("close_ticket", {
|
|
6181
6204
|
description: `Close a support ticket. Optionally logs the resolution as an interaction.
|
|
6182
6205
|
Returns: { ticket } with status=closed`,
|
|
@@ -6330,8 +6353,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
|
|
|
6330
6353
|
}
|
|
6331
6354
|
//#endregion
|
|
6332
6355
|
//#region src/mcp/tools/send-nps-survey.ts
|
|
6333
|
-
const DATA_DIR$
|
|
6334
|
-
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$
|
|
6356
|
+
const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6357
|
+
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$11) {
|
|
6335
6358
|
const survey = getSurvey(dataDir, input.surveyId);
|
|
6336
6359
|
if (!survey) return { content: [{
|
|
6337
6360
|
type: "text",
|
|
@@ -6352,7 +6375,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
|
|
|
6352
6375
|
}, null, 2)
|
|
6353
6376
|
}] };
|
|
6354
6377
|
}
|
|
6355
|
-
function registerSendNpsSurvey(server, dataDir = DATA_DIR$
|
|
6378
|
+
function registerSendNpsSurvey(server, dataDir = DATA_DIR$11) {
|
|
6356
6379
|
server.registerTool("send_nps_survey", {
|
|
6357
6380
|
description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
|
|
6358
6381
|
Does NOT send automatically — returns draft for review.
|
|
@@ -6372,8 +6395,8 @@ Returns: { token, subject, body, surveyUrl }`,
|
|
|
6372
6395
|
}
|
|
6373
6396
|
//#endregion
|
|
6374
6397
|
//#region src/mcp/tools/get-survey-results.ts
|
|
6375
|
-
const DATA_DIR$
|
|
6376
|
-
async function handleGetSurveyResults(input, dataDir = DATA_DIR$
|
|
6398
|
+
const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6399
|
+
async function handleGetSurveyResults(input, dataDir = DATA_DIR$10) {
|
|
6377
6400
|
const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
|
|
6378
6401
|
const nps = calcNpsScore(responses);
|
|
6379
6402
|
const promoters = responses.filter((r) => r.score >= 9).length;
|
|
@@ -6399,7 +6422,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
|
|
|
6399
6422
|
}, null, 2)
|
|
6400
6423
|
}] };
|
|
6401
6424
|
}
|
|
6402
|
-
function registerGetSurveyResults(server, dataDir = DATA_DIR$
|
|
6425
|
+
function registerGetSurveyResults(server, dataDir = DATA_DIR$10) {
|
|
6403
6426
|
server.registerTool("get_survey_results", {
|
|
6404
6427
|
description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
|
|
6405
6428
|
Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
|
|
@@ -6500,8 +6523,8 @@ function getKbMetaForExport(article) {
|
|
|
6500
6523
|
}
|
|
6501
6524
|
//#endregion
|
|
6502
6525
|
//#region src/mcp/tools/search-knowledge-base.ts
|
|
6503
|
-
const DATA_DIR$
|
|
6504
|
-
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$
|
|
6526
|
+
const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6527
|
+
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$9) {
|
|
6505
6528
|
const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
|
|
6506
6529
|
const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
|
|
6507
6530
|
return { content: [{
|
|
@@ -6516,7 +6539,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
|
|
|
6516
6539
|
}, null, 2)
|
|
6517
6540
|
}] };
|
|
6518
6541
|
}
|
|
6519
|
-
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$
|
|
6542
|
+
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$9) {
|
|
6520
6543
|
server.registerTool("search_knowledge_base", {
|
|
6521
6544
|
description: `Search the knowledge base for articles. Text search on title, body, and tags.
|
|
6522
6545
|
Returns: { count, articles[] } with excerpts`,
|
|
@@ -6535,8 +6558,8 @@ Returns: { count, articles[] } with excerpts`,
|
|
|
6535
6558
|
}
|
|
6536
6559
|
//#endregion
|
|
6537
6560
|
//#region src/mcp/tools/create-kb-article.ts
|
|
6538
|
-
const DATA_DIR$
|
|
6539
|
-
async function handleCreateKbArticle(input, dataDir = DATA_DIR$
|
|
6561
|
+
const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6562
|
+
async function handleCreateKbArticle(input, dataDir = DATA_DIR$8) {
|
|
6540
6563
|
if (getKbArticle(dataDir, input.id)) return { content: [{
|
|
6541
6564
|
type: "text",
|
|
6542
6565
|
text: JSON.stringify({ error: `Article '${input.id}' already exists` })
|
|
@@ -6564,7 +6587,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
|
|
|
6564
6587
|
}, null, 2)
|
|
6565
6588
|
}] };
|
|
6566
6589
|
}
|
|
6567
|
-
function registerCreateKbArticle(server, dataDir = DATA_DIR$
|
|
6590
|
+
function registerCreateKbArticle(server, dataDir = DATA_DIR$8) {
|
|
6568
6591
|
server.registerTool("create_kb_article", {
|
|
6569
6592
|
description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
|
|
6570
6593
|
Returns: { id, title, category, path }`,
|
|
@@ -6589,8 +6612,8 @@ Returns: { id, title, category, path }`,
|
|
|
6589
6612
|
}
|
|
6590
6613
|
//#endregion
|
|
6591
6614
|
//#region src/mcp/tools/backup-now.ts
|
|
6592
|
-
const DATA_DIR$
|
|
6593
|
-
async function handleBackupNow(input, dataDir = DATA_DIR$
|
|
6615
|
+
const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6616
|
+
async function handleBackupNow(input, dataDir = DATA_DIR$7) {
|
|
6594
6617
|
const zipPath = path.default.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
|
|
6595
6618
|
const manifest = await require_session_store.runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
|
|
6596
6619
|
if (!manifest) return { content: [{
|
|
@@ -6627,8 +6650,8 @@ function registerBackupNow(server) {
|
|
|
6627
6650
|
}
|
|
6628
6651
|
//#endregion
|
|
6629
6652
|
//#region src/mcp/tools/list-backups.ts
|
|
6630
|
-
const DATA_DIR$
|
|
6631
|
-
async function handleListBackups(input, dataDir = DATA_DIR$
|
|
6653
|
+
const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6654
|
+
async function handleListBackups(input, dataDir = DATA_DIR$6) {
|
|
6632
6655
|
const logEntries = require_session_store.readBackupLog(dataDir);
|
|
6633
6656
|
const fileEntries = require_session_store.listBackupsInDir(dataDir);
|
|
6634
6657
|
const entries = logEntries.length > 0 ? logEntries : fileEntries;
|
|
@@ -6662,8 +6685,8 @@ function registerListBackups(server) {
|
|
|
6662
6685
|
}
|
|
6663
6686
|
//#endregion
|
|
6664
6687
|
//#region src/mcp/tools/trigger-sync.ts
|
|
6665
|
-
const DATA_DIR$
|
|
6666
|
-
async function handleTriggerSync(input, dataDir = DATA_DIR$
|
|
6688
|
+
const DATA_DIR$5 = process.cwd();
|
|
6689
|
+
async function handleTriggerSync(input, dataDir = DATA_DIR$5) {
|
|
6667
6690
|
const auth = getGmailAuth();
|
|
6668
6691
|
if (!auth) return { content: [{
|
|
6669
6692
|
type: "text",
|
|
@@ -6698,7 +6721,7 @@ async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
|
|
|
6698
6721
|
try {
|
|
6699
6722
|
const sources = JSON.parse(fs.default.readFileSync(sourcesPath, "utf-8"));
|
|
6700
6723
|
if (!sources.gmail?.enabled || !sources.gmail.query) continue;
|
|
6701
|
-
const { syncGmail } = await Promise.resolve().then(() => require("./gmail-sync-
|
|
6724
|
+
const { syncGmail } = await Promise.resolve().then(() => require("./gmail-sync-BpSVESSe.cjs"));
|
|
6702
6725
|
const result = await syncGmail({
|
|
6703
6726
|
slug,
|
|
6704
6727
|
dataDir,
|
|
@@ -6757,8 +6780,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
|
|
|
6757
6780
|
}
|
|
6758
6781
|
//#endregion
|
|
6759
6782
|
//#region src/mcp/tools/get-audit-log.ts
|
|
6760
|
-
const DATA_DIR$
|
|
6761
|
-
async function handleGetAuditLog(input, dataDir = DATA_DIR$
|
|
6783
|
+
const DATA_DIR$4 = process.cwd();
|
|
6784
|
+
async function handleGetAuditLog(input, dataDir = DATA_DIR$4) {
|
|
6762
6785
|
const entries = require_session_store.readAuditLog(dataDir);
|
|
6763
6786
|
const filterOpts = { limit: input.limit ?? 50 };
|
|
6764
6787
|
if (input.slug !== void 0) filterOpts.slug = input.slug;
|
|
@@ -6800,8 +6823,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
|
|
|
6800
6823
|
}
|
|
6801
6824
|
//#endregion
|
|
6802
6825
|
//#region src/mcp/tools/get-logs.ts
|
|
6803
|
-
const DATA_DIR$
|
|
6804
|
-
async function handleGetLogs(input, dataDir = DATA_DIR$
|
|
6826
|
+
const DATA_DIR$3 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6827
|
+
async function handleGetLogs(input, dataDir = DATA_DIR$3) {
|
|
6805
6828
|
const query = {
|
|
6806
6829
|
...input.level !== void 0 ? { level: input.level } : {},
|
|
6807
6830
|
...input.component !== void 0 ? { component: input.component } : {},
|
|
@@ -6862,6 +6885,140 @@ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors
|
|
|
6862
6885
|
});
|
|
6863
6886
|
}
|
|
6864
6887
|
//#endregion
|
|
6888
|
+
//#region src/core/doctor.ts
|
|
6889
|
+
var doctor_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
6890
|
+
cleanupTempFiles: () => cleanupTempFiles,
|
|
6891
|
+
runDiagnostics: () => runDiagnostics
|
|
6892
|
+
});
|
|
6893
|
+
/** Recursively collect files whose name matches the atomic-write temp pattern. */
|
|
6894
|
+
function findOrphanedTempFiles(dir, depth = 0) {
|
|
6895
|
+
if (depth > 3 || !fs.default.existsSync(dir)) return [];
|
|
6896
|
+
const out = [];
|
|
6897
|
+
let entries;
|
|
6898
|
+
try {
|
|
6899
|
+
entries = fs.default.readdirSync(dir);
|
|
6900
|
+
} catch {
|
|
6901
|
+
return [];
|
|
6902
|
+
}
|
|
6903
|
+
for (const entry of entries) {
|
|
6904
|
+
const full = path.default.join(dir, entry);
|
|
6905
|
+
let isDir = false;
|
|
6906
|
+
try {
|
|
6907
|
+
isDir = fs.default.statSync(full).isDirectory();
|
|
6908
|
+
} catch {
|
|
6909
|
+
continue;
|
|
6910
|
+
}
|
|
6911
|
+
if (isDir) out.push(...findOrphanedTempFiles(full, depth + 1));
|
|
6912
|
+
else if (/\.\d+\.[0-9a-f]+\.tmp$/.test(entry)) out.push(full);
|
|
6913
|
+
}
|
|
6914
|
+
return out;
|
|
6915
|
+
}
|
|
6916
|
+
/** Delete orphaned atomic-write temp files; returns the paths removed. */
|
|
6917
|
+
function cleanupTempFiles(dataDir) {
|
|
6918
|
+
const temps = [...findOrphanedTempFiles(path.default.join(dataDir, ".agentic")), ...findOrphanedTempFiles(path.default.join(dataDir, "customers"))];
|
|
6919
|
+
const removed = [];
|
|
6920
|
+
for (const f of temps) try {
|
|
6921
|
+
fs.default.rmSync(f, { force: true });
|
|
6922
|
+
removed.push(f);
|
|
6923
|
+
} catch {}
|
|
6924
|
+
return removed;
|
|
6925
|
+
}
|
|
6926
|
+
async function runDiagnostics(dataDir) {
|
|
6927
|
+
const checks = [];
|
|
6928
|
+
const agenticDir = path.default.join(dataDir, ".agentic");
|
|
6929
|
+
const customersDir = path.default.join(dataDir, "customers");
|
|
6930
|
+
if (!fs.default.existsSync(agenticDir) && !fs.default.existsSync(customersDir)) checks.push({
|
|
6931
|
+
name: "data directory",
|
|
6932
|
+
status: "fail",
|
|
6933
|
+
detail: `Neither .agentic/ nor customers/ found under ${dataDir} — run 'dxcrm init'`
|
|
6934
|
+
});
|
|
6935
|
+
else checks.push({
|
|
6936
|
+
name: "data directory",
|
|
6937
|
+
status: "ok",
|
|
6938
|
+
detail: dataDir
|
|
6939
|
+
});
|
|
6940
|
+
const slugs = require_session_store.listCustomerSlugs(dataDir);
|
|
6941
|
+
const invalid = [];
|
|
6942
|
+
for (const slug of slugs) try {
|
|
6943
|
+
await require_session_store.readMainFacts(dataDir, slug);
|
|
6944
|
+
} catch {
|
|
6945
|
+
invalid.push(slug);
|
|
6946
|
+
}
|
|
6947
|
+
checks.push({
|
|
6948
|
+
name: "customer data",
|
|
6949
|
+
status: invalid.length > 0 ? "fail" : "ok",
|
|
6950
|
+
detail: invalid.length > 0 ? `${invalid.length} of ${slugs.length} invalid: ${invalid.slice(0, 5).join(", ")}` : `${slugs.length} customer(s) valid`
|
|
6951
|
+
});
|
|
6952
|
+
const temps = [...findOrphanedTempFiles(agenticDir), ...findOrphanedTempFiles(customersDir)];
|
|
6953
|
+
checks.push({
|
|
6954
|
+
name: "temp files",
|
|
6955
|
+
status: temps.length > 0 ? "warn" : "ok",
|
|
6956
|
+
detail: temps.length > 0 ? `${temps.length} orphaned temp file(s) from interrupted writes — safe to delete` : "no orphaned temp files"
|
|
6957
|
+
});
|
|
6958
|
+
const summary = require_logger.summarizeLogs(dataDir);
|
|
6959
|
+
const errorCount = summary.byLevel.error;
|
|
6960
|
+
checks.push({
|
|
6961
|
+
name: "logs",
|
|
6962
|
+
status: errorCount > 0 ? "warn" : "ok",
|
|
6963
|
+
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`
|
|
6964
|
+
});
|
|
6965
|
+
const backupLogPath = path.default.join(agenticDir, "backup-log.json");
|
|
6966
|
+
if (fs.default.existsSync(backupLogPath)) try {
|
|
6967
|
+
const entries = JSON.parse(fs.default.readFileSync(backupLogPath, "utf-8"));
|
|
6968
|
+
const last = entries[entries.length - 1]?.createdAt;
|
|
6969
|
+
const ageDays = last ? Math.floor((Date.now() - new Date(last).getTime()) / 864e5) : Infinity;
|
|
6970
|
+
checks.push({
|
|
6971
|
+
name: "backups",
|
|
6972
|
+
status: ageDays > 7 ? "warn" : "ok",
|
|
6973
|
+
detail: last ? `last backup ${ageDays}d ago` : "no backups recorded"
|
|
6974
|
+
});
|
|
6975
|
+
} catch {
|
|
6976
|
+
checks.push({
|
|
6977
|
+
name: "backups",
|
|
6978
|
+
status: "warn",
|
|
6979
|
+
detail: "backup log unreadable"
|
|
6980
|
+
});
|
|
6981
|
+
}
|
|
6982
|
+
return {
|
|
6983
|
+
ok: !checks.some((c) => c.status === "fail"),
|
|
6984
|
+
checks
|
|
6985
|
+
};
|
|
6986
|
+
}
|
|
6987
|
+
//#endregion
|
|
6988
|
+
//#region src/mcp/tools/get-diagnostics.ts
|
|
6989
|
+
const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6990
|
+
async function handleGetDiagnostics(input, dataDir = DATA_DIR$2) {
|
|
6991
|
+
let cleaned = 0;
|
|
6992
|
+
if (input.fix) {
|
|
6993
|
+
const { cleanupTempFiles } = await Promise.resolve().then(() => doctor_exports);
|
|
6994
|
+
cleaned = cleanupTempFiles(dataDir).length;
|
|
6995
|
+
}
|
|
6996
|
+
const report = await runDiagnostics(dataDir);
|
|
6997
|
+
return { content: [{
|
|
6998
|
+
type: "text",
|
|
6999
|
+
text: JSON.stringify({
|
|
7000
|
+
ok: report.ok,
|
|
7001
|
+
...input.fix ? { tempFilesRemoved: cleaned } : {},
|
|
7002
|
+
checks: report.checks
|
|
7003
|
+
}, null, 2)
|
|
7004
|
+
}] };
|
|
7005
|
+
}
|
|
7006
|
+
function registerGetDiagnostics(server) {
|
|
7007
|
+
server.registerTool("get_diagnostics", {
|
|
7008
|
+
title: "Get Diagnostics",
|
|
7009
|
+
description: `Run a self-diagnostic health check of the CRM workspace.
|
|
7010
|
+
Verifies the data directory, validates every customer's profile, detects orphaned
|
|
7011
|
+
atomic-write temp files (a crash signature), surfaces recent log errors, and checks
|
|
7012
|
+
backup freshness. Use to answer "is everything healthy?" before/after bulk operations.
|
|
7013
|
+
|
|
7014
|
+
Args:
|
|
7015
|
+
fix: When true, first remove orphaned temp files (the only safely auto-fixable issue)
|
|
7016
|
+
|
|
7017
|
+
Returns: { ok: boolean, tempFilesRemoved?: number, checks: [{ name, status: "ok"|"warn"|"fail", detail }] }`,
|
|
7018
|
+
inputSchema: zod.z.object({ fix: zod.z.boolean().optional().describe("Clean orphaned temp files before reporting") })
|
|
7019
|
+
}, async ({ fix }) => handleGetDiagnostics(fix !== void 0 ? { fix } : {}));
|
|
7020
|
+
}
|
|
7021
|
+
//#endregion
|
|
6865
7022
|
//#region src/mcp/prompts.ts
|
|
6866
7023
|
/**
|
|
6867
7024
|
* CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
|
|
@@ -6956,7 +7113,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
|
|
|
6956
7113
|
description: "Newest-first interaction history for a customer",
|
|
6957
7114
|
mimeType: "text/markdown"
|
|
6958
7115
|
}, async (uri, variables) => {
|
|
6959
|
-
const { readInteractions } = await Promise.resolve().then(() => require("./interactions-writer-
|
|
7116
|
+
const { readInteractions } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
|
|
6960
7117
|
const text = await readInteractions(dataDir, String(variables["slug"]));
|
|
6961
7118
|
return { contents: [{
|
|
6962
7119
|
uri: uri.href,
|
|
@@ -7278,6 +7435,7 @@ function createMcpServer() {
|
|
|
7278
7435
|
registerTriggerSync(server);
|
|
7279
7436
|
registerGetAuditLog(server);
|
|
7280
7437
|
registerGetLogs(server);
|
|
7438
|
+
registerGetDiagnostics(server);
|
|
7281
7439
|
registerCustomObjectTools(server);
|
|
7282
7440
|
registerPrompts(server);
|
|
7283
7441
|
registerResources(server);
|