@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.
Files changed (89) hide show
  1. package/README.md +8 -1
  2. package/dist/{ask-D8iYqDAr.js → ask-CDysGnRg.js} +2 -2
  3. package/dist/{ask-D8iYqDAr.js.map → ask-CDysGnRg.js.map} +1 -1
  4. package/dist/attachments-CX2GAtsw.cjs +517 -0
  5. package/dist/attachments-CX2GAtsw.cjs.map +1 -0
  6. package/dist/attachments-D207gXfN.js +514 -0
  7. package/dist/attachments-D207gXfN.js.map +1 -0
  8. package/dist/attachments-rLa96rOK.js +514 -0
  9. package/dist/attachments-rLa96rOK.js.map +1 -0
  10. package/dist/chunk-BfDYWZQ8.cjs +32 -0
  11. package/dist/chunk-BfDYWZQ8.cjs.map +1 -0
  12. package/dist/chunk-BhUZmQg5.js +32 -0
  13. package/dist/chunk-BhUZmQg5.js.map +1 -0
  14. package/dist/chunk-ChC83jai.js +2 -0
  15. package/dist/chunk-e_w8qqtP.js +32 -0
  16. package/dist/chunk-e_w8qqtP.js.map +1 -0
  17. package/dist/cli.js +20 -18
  18. package/dist/cli.js.map +1 -1
  19. package/dist/daemon/worker.js +3 -3
  20. package/dist/{doctor-C14-vnJ1.js → doctor-BFeelnq8.js} +2 -2
  21. package/dist/{doctor-C14-vnJ1.js.map → doctor-BFeelnq8.js.map} +1 -1
  22. package/dist/doctor-CYDaNmFn.js +2 -0
  23. package/dist/email-body-BFSRa0AW.cjs +42 -0
  24. package/dist/email-body-BFSRa0AW.cjs.map +1 -0
  25. package/dist/email-body-BOd7U-D2.js +42 -0
  26. package/dist/email-body-BOd7U-D2.js.map +1 -0
  27. package/dist/{gmail-sync-DueE6tl5.js → gmail-sync-B4Iu3AQb.js} +45 -15
  28. package/dist/gmail-sync-B4Iu3AQb.js.map +1 -0
  29. package/dist/{gmail-sync-GEy3oVvw.cjs → gmail-sync-BpSVESSe.cjs} +45 -15
  30. package/dist/gmail-sync-BpSVESSe.cjs.map +1 -0
  31. package/dist/{gmail-sync-C-NmibzS.js → gmail-sync-DIbrPnTK.js} +45 -15
  32. package/dist/gmail-sync-DIbrPnTK.js.map +1 -0
  33. package/dist/{gmail-webhook-handler-kGKpbY9h.js → gmail-webhook-handler-BzOFbvgh.js} +2 -2
  34. package/dist/{gmail-webhook-handler-kGKpbY9h.js.map → gmail-webhook-handler-BzOFbvgh.js.map} +1 -1
  35. package/dist/{gmail-webhook-handler-B26COilD.js → gmail-webhook-handler-CvSDW_Js.js} +1 -1
  36. package/dist/{google-drive-sync-D1n7WKZn.js → google-drive-sync-B_I1d54Y.js} +2 -2
  37. package/dist/{google-drive-sync-D1n7WKZn.js.map → google-drive-sync-B_I1d54Y.js.map} +1 -1
  38. package/dist/html-BaeOCZKE.js +36 -0
  39. package/dist/html-BaeOCZKE.js.map +1 -0
  40. package/dist/html-CmOku6jS.cjs +47 -0
  41. package/dist/html-CmOku6jS.cjs.map +1 -0
  42. package/dist/{import-hubspot-DB4n89jy.js → import-hubspot-CTId9IGV.js} +2 -2
  43. package/dist/{import-hubspot-DB4n89jy.js.map → import-hubspot-CTId9IGV.js.map} +1 -1
  44. package/dist/{index-pY7tYXwH.d.cts → index-CLUKKfGb.d.cts} +12 -8
  45. package/dist/index-CLUKKfGb.d.cts.map +1 -0
  46. package/dist/{index-B0IMMrp_.d.ts → index-D8jJ1VIt.d.ts} +14 -10
  47. package/dist/index-D8jJ1VIt.d.ts.map +1 -0
  48. package/dist/index.d.cts +12 -8
  49. package/dist/index.d.cts.map +1 -1
  50. package/dist/index.d.ts +14 -10
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/{interactions-writer-RJB8SWf2.js → interactions-writer-B2y-73lh.js} +1 -1
  53. package/dist/{interactions-writer-DbSyI2rt.js → interactions-writer-B8XAzdqR.js} +3 -2
  54. package/dist/interactions-writer-B8XAzdqR.js.map +1 -0
  55. package/dist/{interactions-writer-a2yzBd7T.cjs → interactions-writer-BRJNrefF.cjs} +3 -2
  56. package/dist/interactions-writer-BRJNrefF.cjs.map +1 -0
  57. package/dist/{interactions-writer-BZzUIgJd.js → interactions-writer-ZQcpFOh9.js} +3 -2
  58. package/dist/interactions-writer-ZQcpFOh9.js.map +1 -0
  59. package/dist/{knowledge-base-DHNc4hVj.js → knowledge-base-Bx2PKQR2.js} +10 -7
  60. package/dist/knowledge-base-Bx2PKQR2.js.map +1 -0
  61. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  62. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  63. package/dist/mcp.cjs +308 -150
  64. package/dist/mcp.cjs.map +1 -1
  65. package/dist/mcp.d.cts.map +1 -1
  66. package/dist/mcp.d.ts.map +1 -1
  67. package/dist/mcp.js +308 -150
  68. package/dist/mcp.js.map +1 -1
  69. package/dist/{microsoft-calendar-jIu9K5zX.js → microsoft-calendar-BgVR8GDv.js} +3 -3
  70. package/dist/{microsoft-calendar-jIu9K5zX.js.map → microsoft-calendar-BgVR8GDv.js.map} +1 -1
  71. package/dist/{microsoft-sync-R_r8HL-B.js → microsoft-sync-D30_XksI.js} +3 -3
  72. package/dist/{microsoft-sync-R_r8HL-B.js.map → microsoft-sync-D30_XksI.js.map} +1 -1
  73. package/dist/{nba-mTJ4yEqD.js → nba-DwdfM93s.js} +2 -2
  74. package/dist/{nba-mTJ4yEqD.js.map → nba-DwdfM93s.js.map} +1 -1
  75. package/dist/{server-DqSMYhSA.js → server-BhNLrnAD.js} +201 -145
  76. package/dist/server-BhNLrnAD.js.map +1 -0
  77. package/dist/{transcript-watcher-0mh2ZhmH.js → transcript-watcher-BoClrJAz.js} +2 -2
  78. package/dist/{transcript-watcher-0mh2ZhmH.js.map → transcript-watcher-BoClrJAz.js.map} +1 -1
  79. package/package.json +13 -2
  80. package/dist/gmail-sync-C-NmibzS.js.map +0 -1
  81. package/dist/gmail-sync-DueE6tl5.js.map +0 -1
  82. package/dist/gmail-sync-GEy3oVvw.cjs.map +0 -1
  83. package/dist/index-B0IMMrp_.d.ts.map +0 -1
  84. package/dist/index-pY7tYXwH.d.cts.map +0 -1
  85. package/dist/interactions-writer-BZzUIgJd.js.map +0 -1
  86. package/dist/interactions-writer-DbSyI2rt.js.map +0 -1
  87. package/dist/interactions-writer-a2yzBd7T.cjs.map +0 -1
  88. package/dist/knowledge-base-DHNc4hVj.js.map +0 -1
  89. 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-a2yzBd7T.cjs");
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 count + pipeline + attachments list).
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$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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-GEy3oVvw.cjs")).then(({ syncGmail }) => syncGmail({
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$52) {
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$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1587
- async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$51) {
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$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$50) {
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$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2156
- async function handleLogInteraction(input, dataDir = DATA_DIR$49) {
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$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2266
- async function handleUpdateDeal(input, dataDir = DATA_DIR$48) {
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$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$47) {
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()) attachments.push(f);
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 count + pipeline deals).
2427
- Useful for reporting, audits, or creating backups.
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$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2448
- async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$46) {
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$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2627
- async function handleGetDealHealth(input, dataDir = DATA_DIR$45) {
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$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2677
- async function handleGetPipelineForecast(input, dataDir = DATA_DIR$44) {
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$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2739
- async function handleSummarizeMeeting(input, dataDir = DATA_DIR$43) {
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$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2863
- async function handleGetPipelineStages(_input, dataDir = DATA_DIR$42) {
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$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2892
- async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$41) {
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$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$40) {
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$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$39) {
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-a2yzBd7T.cjs")).then((n) => n.interactions_writer_exports);
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-a2yzBd7T.cjs")).then((n) => n.interactions_writer_exports);
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$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3671
- async function handleRunDealAgent(input, dataDir = DATA_DIR$38) {
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$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3739
- async function handleApproveAgentAction(input, dataDir = DATA_DIR$37) {
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$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4000
- async function handleSimulateRevenue(input, dataDir = DATA_DIR$36) {
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$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4059
- async function handleGetPlaybook(input, dataDir = DATA_DIR$35) {
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$35));
4167
+ }, DATA_DIR$36));
4145
4168
  }
4146
4169
  //#endregion
4147
4170
  //#region src/mcp/tools/create-playbook.ts
4148
- const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4149
- async function handleCreatePlaybook(input, dataDir = DATA_DIR$34) {
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$34));
4245
+ }, DATA_DIR$35));
4223
4246
  }
4224
4247
  //#endregion
4225
4248
  //#region src/mcp/tools/list-playbooks.ts
4226
- const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4227
- async function handleListPlaybooks(input, dataDir = DATA_DIR$33) {
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$33));
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$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4271
- async function handleDistillPlaybook(input, dataDir = DATA_DIR$32, llmFn = require_llm.callLlm) {
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$32));
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$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4549
- async function handlePursueGoal(input, dataDir = DATA_DIR$31, options = {}) {
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$31));
4635
+ }, DATA_DIR$32));
4613
4636
  }
4614
4637
  //#endregion
4615
4638
  //#region src/mcp/tools/get-goal-status.ts
4616
- const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4617
- async function handleGetGoalStatus(input, dataDir = DATA_DIR$30) {
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$30));
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$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$29) {
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$29));
4795
+ }, DATA_DIR$30));
4773
4796
  }
4774
4797
  //#endregion
4775
4798
  //#region src/mcp/tools/get-push-status.ts
4776
- const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4777
- async function handleGetPushStatus(input, dataDir = DATA_DIR$28) {
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$28));
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$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4916
- async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$27) {
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$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5050
- async function handleOpenDealRoom(input, dataDir = DATA_DIR$26) {
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$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5134
- async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$25) {
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$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5235
- async function handleListEmailTemplates(input, dataDir = DATA_DIR$24) {
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$24) {
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$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5277
- async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
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$23) {
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$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5302
- async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
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$22) {
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$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5455
- async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
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$21) {
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$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5505
- async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
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$20) {
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$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5534
- async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
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$19) {
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$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5557
- async function handleListSequences(_input, dataDir = DATA_DIR$18) {
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$18) {
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$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5707
- async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
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$17) {
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$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5760
- async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
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$16) {
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$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
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$15) {
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$15) {
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$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6015
- async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
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$14) {
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$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6064
- async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
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$13) {
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$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6109
- async function handleListTickets(input, dataDir = DATA_DIR$12) {
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$12) {
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$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6152
- async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
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$11) {
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$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6334
- async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
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$10) {
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$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6376
- async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
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$9) {
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$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6504
- async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
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$8) {
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$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6539
- async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
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$7) {
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$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6593
- async function handleBackupNow(input, dataDir = DATA_DIR$6) {
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$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6631
- async function handleListBackups(input, dataDir = DATA_DIR$5) {
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$4 = process.cwd();
6666
- async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
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-GEy3oVvw.cjs"));
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$3 = process.cwd();
6761
- async function handleGetAuditLog(input, dataDir = DATA_DIR$3) {
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$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6804
- async function handleGetLogs(input, dataDir = DATA_DIR$2) {
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-a2yzBd7T.cjs")).then((n) => n.interactions_writer_exports);
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);