@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
@@ -0,0 +1,32 @@
1
+ //#region src/core/chunk.ts
2
+ /**
3
+ * Split long text into overlapping chunks for embedding/indexing. Each chunk is
4
+ * at most `maxChars`; chunks overlap by `overlap` characters so a query that
5
+ * straddles a boundary still matches. Splits prefer the nearest whitespace
6
+ * before the limit to avoid cutting words mid-token. Short text returns a single
7
+ * trimmed chunk; empty/whitespace-only text returns no chunks.
8
+ */
9
+ function chunkText(text, options = {}) {
10
+ const maxChars = options.maxChars ?? 1500;
11
+ const overlap = Math.min(options.overlap ?? 150, Math.floor(maxChars / 2));
12
+ const trimmed = text.trim();
13
+ if (!trimmed) return [];
14
+ if (trimmed.length <= maxChars) return [trimmed];
15
+ const chunks = [];
16
+ let start = 0;
17
+ while (start < trimmed.length) {
18
+ let end = Math.min(start + maxChars, trimmed.length);
19
+ if (end < trimmed.length) {
20
+ const lastSpace = trimmed.lastIndexOf(" ", end);
21
+ if (lastSpace > start + maxChars / 2) end = lastSpace;
22
+ }
23
+ chunks.push(trimmed.slice(start, end).trim());
24
+ if (end >= trimmed.length) break;
25
+ start = end - overlap;
26
+ }
27
+ return chunks.filter((c) => c.length > 0);
28
+ }
29
+ //#endregion
30
+ export { chunkText };
31
+
32
+ //# sourceMappingURL=chunk-e_w8qqtP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-e_w8qqtP.js","names":[],"sources":["../src/core/chunk.ts"],"sourcesContent":["// src/core/chunk.ts\n\nexport interface ChunkOptions {\n /** Target maximum characters per chunk. */\n maxChars?: number;\n /** Characters of overlap carried from the end of one chunk into the next. */\n overlap?: number;\n}\n\n/**\n * Split long text into overlapping chunks for embedding/indexing. Each chunk is\n * at most `maxChars`; chunks overlap by `overlap` characters so a query that\n * straddles a boundary still matches. Splits prefer the nearest whitespace\n * before the limit to avoid cutting words mid-token. Short text returns a single\n * trimmed chunk; empty/whitespace-only text returns no chunks.\n */\nexport function chunkText(text: string, options: ChunkOptions = {}): string[] {\n const maxChars = options.maxChars ?? 1500;\n const overlap = Math.min(options.overlap ?? 150, Math.floor(maxChars / 2));\n const trimmed = text.trim();\n if (!trimmed) return [];\n if (trimmed.length <= maxChars) return [trimmed];\n\n const chunks: string[] = [];\n let start = 0;\n while (start < trimmed.length) {\n let end = Math.min(start + maxChars, trimmed.length);\n // Prefer breaking on whitespace, but only if it doesn't shrink the chunk too much.\n if (end < trimmed.length) {\n const lastSpace = trimmed.lastIndexOf(\" \", end);\n if (lastSpace > start + maxChars / 2) end = lastSpace;\n }\n chunks.push(trimmed.slice(start, end).trim());\n if (end >= trimmed.length) break;\n start = end - overlap;\n }\n return chunks.filter((c) => c.length > 0);\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,UAAU,MAAc,UAAwB,CAAC,GAAa;CAC5E,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,UAAU,KAAK,IAAI,QAAQ,WAAW,KAAK,KAAK,MAAM,WAAW,CAAC,CAAC;CACzE,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,IAAI,QAAQ,UAAU,UAAU,OAAO,CAAC,OAAO;CAE/C,MAAM,SAAmB,CAAC;CAC1B,IAAI,QAAQ;CACZ,OAAO,QAAQ,QAAQ,QAAQ;EAC7B,IAAI,MAAM,KAAK,IAAI,QAAQ,UAAU,QAAQ,MAAM;EAEnD,IAAI,MAAM,QAAQ,QAAQ;GACxB,MAAM,YAAY,QAAQ,YAAY,KAAK,GAAG;GAC9C,IAAI,YAAY,QAAQ,WAAW,GAAG,MAAM;EAC9C;EACA,OAAO,KAAK,QAAQ,MAAM,OAAO,GAAG,EAAE,KAAK,CAAC;EAC5C,IAAI,OAAO,QAAQ,QAAQ;EAC3B,QAAQ,MAAM;CAChB;CACA,OAAO,OAAO,QAAQ,MAAM,EAAE,SAAS,CAAC;AAC1C"}
package/dist/cli.js CHANGED
@@ -5,12 +5,12 @@ import { i as writeJsonFile } from "./json-store-WWsFzXub.js";
5
5
  import { a as warning, i as success, n as error, r as info, t as bold } from "./colors-BG07TZQz.js";
6
6
  import { n as getSession } from "./session-store-CEa39Dxs.js";
7
7
  import { i as sessionCommand, r as readAllSessions } from "./session-BgGDyP2C.js";
8
- import { a as searchKbSimple, i as listKbArticles, n as getKbArticle, o as writeKbArticle, s as CAPABILITIES_TEXT, t as deleteKbArticle } from "./knowledge-base-DHNc4hVj.js";
8
+ import { a as searchKbSimple, i as listKbArticles, n as getKbArticle, o as writeKbArticle, s as CAPABILITIES_TEXT, t as deleteKbArticle } from "./knowledge-base-Bx2PKQR2.js";
9
9
  import { a as restoreCommand, t as backupCommand } from "./backup-CTlIxUdO.js";
10
10
  import { n as readSyncState } from "./sync-state-DMZgzpez.js";
11
11
  import { n as readUnmatched } from "./unmatched-transcripts-DC-VQ9YS.js";
12
12
  import { t as AgentConfigSchema } from "./agent-config-zPvcqu07.js";
13
- import { n as appendInteraction, t as InteractionDedup } from "./interactions-writer-DbSyI2rt.js";
13
+ import { n as appendInteraction, t as InteractionDedup } from "./interactions-writer-B8XAzdqR.js";
14
14
  import { i as writeAuditEntry, n as getActor, r as readAuditLog, t as filterAuditLog } from "./audit-log-DNMY9mUZ.js";
15
15
  import { d as setActorRole, i as canWrite, s as getRbacConfig } from "./rbac-msmBc_tK.js";
16
16
  import { t as withJsonFile } from "./file-lock-CcHotQkZ.js";
@@ -240,14 +240,14 @@ mcpCommand.command("start").description("Start MCP server (stdio by default)").o
240
240
  if (opts.http) {
241
241
  const port = parseInt(opts.port, 10);
242
242
  console.error(info(`Starting MCP server in HTTP mode on port ${port}...`));
243
- const { startHttp } = await import("./server-DqSMYhSA.js");
243
+ const { startHttp } = await import("./server-BhNLrnAD.js");
244
244
  await startHttp(port);
245
245
  } else {
246
- const { startStdio } = await import("./server-DqSMYhSA.js");
246
+ const { startStdio } = await import("./server-BhNLrnAD.js");
247
247
  await startStdio();
248
248
  }
249
249
  });
250
- const TOOL_COUNT = 57;
250
+ const TOOL_COUNT = 58;
251
251
  /** Claude Code: CLAUDE.md in CRM dataDir */
252
252
  function buildClaudeMd(dataDir) {
253
253
  return `# DatasynxOpenCRM v2 — Agent Instructions (${TOOL_COUNT} MCP Tools)
@@ -374,6 +374,7 @@ It combines graph, health, revenue simulation, playbook, and org intelligence in
374
374
  - \`trigger_sync({ slug?, since? })\` — force immediate Gmail sync for one or all customers (bypasses 30-min daemon cycle)
375
375
  - \`get_audit_log({ slug?, actor?, limit? })\` — read append-only audit log of all write operations
376
376
  - \`get_logs({ level?, component?, since?, contains?, limit?, summary? })\` — query/aggregate the structured application log
377
+ - \`get_diagnostics({ fix? })\` — self-diagnostic health check (data integrity, temp files, log errors, backups)
377
378
 
378
379
  ### Custom Objects (Platform / metadata)
379
380
  - \`define_custom_object({ name, label?, fields })\` — define a runtime entity type with typed fields (no migration), admin
@@ -635,7 +636,7 @@ create_ticket · update_ticket · list_tickets · close_ticket ·
635
636
  send_nps_survey · get_survey_results ·
636
637
  search_knowledge_base · create_kb_article ·
637
638
  backup_now · list_backups ·
638
- trigger_sync · get_audit_log · get_logs ·
639
+ trigger_sync · get_audit_log · get_logs · get_diagnostics ·
639
640
  define_custom_object · create_record · list_records · list_custom_objects
640
641
 
641
642
  ## Data: ${dataDir}`.trim();
@@ -1604,7 +1605,7 @@ const initCommand = new Command("init").description("Initialize CRM and configur
1604
1605
  });
1605
1606
  //#endregion
1606
1607
  //#region src/commands/sync.ts
1607
- const syncCommand = new Command("sync").argument("<slug>", "Customer slug to sync").description("Sync Gmail and transcripts for a customer").option("--since <date>", "Only sync emails/files after this date (YYYY-MM-DD)").option("--gmail", "Sync Gmail only").option("--transcripts", "Sync transcripts only").option("--provider <provider>", "Sync provider: gmail | microsoft | transcripts").action(async (slug, opts) => {
1608
+ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to sync").description("Sync Gmail and transcripts for a customer").option("--since <date>", "Only sync emails/files after this date (YYYY-MM-DD)").option("--gmail", "Sync Gmail only").option("--transcripts", "Sync transcripts only").option("--provider <provider>", "Sync provider: gmail | microsoft | transcripts").option("--no-attachments", "Skip downloading/converting/indexing email attachments").action(async (slug, opts) => {
1608
1609
  const dataDir = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1609
1610
  const customerDir = path.join(dataDir, "customers", slug);
1610
1611
  if (!fs.existsSync(customerDir)) {
@@ -1631,13 +1632,14 @@ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to syn
1631
1632
  else try {
1632
1633
  console.log(info(` Syncing Gmail for ${bold(slug)}...`));
1633
1634
  const { getGmailAuth } = await import("./gmail-auth-OComS92L.js");
1634
- const { syncGmail: doGmailSync } = await import("./gmail-sync-DueE6tl5.js");
1635
+ const { syncGmail: doGmailSync } = await import("./gmail-sync-B4Iu3AQb.js");
1635
1636
  const result = await doGmailSync({
1636
1637
  slug,
1637
1638
  dataDir,
1638
1639
  auth: await getGmailAuth(credPath, tokenPath),
1639
1640
  query: sources.gmail.query,
1640
- since
1641
+ since,
1642
+ includeAttachments: opts.attachments !== false
1641
1643
  });
1642
1644
  totalSynced += result.synced;
1643
1645
  console.log(success(` ✓ Gmail: +${result.synced} synced, ${result.skipped} skipped`));
@@ -1651,7 +1653,7 @@ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to syn
1651
1653
  const token = await getMicrosoftToken(dataDir);
1652
1654
  if (!token) console.log(info(" Microsoft: no token found (.agentic/microsoft-token.json)"));
1653
1655
  else {
1654
- const { syncMicrosoft: doMsSync } = await import("./microsoft-sync-R_r8HL-B.js");
1656
+ const { syncMicrosoft: doMsSync } = await import("./microsoft-sync-D30_XksI.js");
1655
1657
  const emailResult = await doMsSync({
1656
1658
  slug,
1657
1659
  dataDir,
@@ -1660,7 +1662,7 @@ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to syn
1660
1662
  });
1661
1663
  totalSynced += emailResult.synced;
1662
1664
  console.log(success(` ✓ Microsoft Email: +${emailResult.synced} synced, ${emailResult.skipped} skipped`));
1663
- const { syncMicrosoftCalendar } = await import("./microsoft-calendar-jIu9K5zX.js");
1665
+ const { syncMicrosoftCalendar } = await import("./microsoft-calendar-BgVR8GDv.js");
1664
1666
  const calResult = await syncMicrosoftCalendar({
1665
1667
  slug,
1666
1668
  dataDir,
@@ -1678,7 +1680,7 @@ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to syn
1678
1680
  if (fs.existsSync(agenticSourcesPath)) try {
1679
1681
  const agenticSources = JSON.parse(fs.readFileSync(agenticSourcesPath, "utf-8"));
1680
1682
  if (agenticSources.transcripts?.enabled && agenticSources.transcripts.paths?.length) {
1681
- const { processTranscriptFile } = await import("./transcript-watcher-0mh2ZhmH.js");
1683
+ const { processTranscriptFile } = await import("./transcript-watcher-BoClrJAz.js");
1682
1684
  const exts = agenticSources.transcripts.extensions ?? [".txt", ".vtt"];
1683
1685
  let transcriptSynced = 0;
1684
1686
  for (const watchPath of agenticSources.transcripts.paths) {
@@ -1707,7 +1709,7 @@ const syncCommand = new Command("sync").argument("<slug>", "Customer slug to syn
1707
1709
  if (!accessToken) console.log(info(" Google Drive: accessToken not found in token file"));
1708
1710
  else {
1709
1711
  console.log(info(` Syncing Google Drive for ${bold(slug)}...`));
1710
- const { syncGoogleDriveFiles } = await import("./google-drive-sync-D1n7WKZn.js");
1712
+ const { syncGoogleDriveFiles } = await import("./google-drive-sync-B_I1d54Y.js");
1711
1713
  const result = await syncGoogleDriveFiles({
1712
1714
  slug,
1713
1715
  dataDir,
@@ -2229,7 +2231,7 @@ async function runImport(sourcePath, opts, dataDir) {
2229
2231
  if (opts.from === "salesforce" && opts.mode === "api") return runSalesforceApiImport(opts, dir);
2230
2232
  if (opts.from === "pipedrive" && opts.mode === "api") return runPipedriveApiImport(opts, dir);
2231
2233
  if (opts.from === "hubspot" && sourcePath && fs.existsSync(sourcePath) && fs.statSync(sourcePath).isDirectory()) {
2232
- const { runHubSpotCsvImport } = await import("./import-hubspot-DB4n89jy.js");
2234
+ const { runHubSpotCsvImport } = await import("./import-hubspot-CTId9IGV.js");
2233
2235
  const r = await runHubSpotCsvImport(sourcePath, dir, {
2234
2236
  ...opts.dryRun ? { dryRun: true } : {},
2235
2237
  ...opts.resume ? { resume: true } : {},
@@ -2745,7 +2747,7 @@ const importCommand = new Command("import").description("Import customers and in
2745
2747
  if (hs && rep) ownerMap[hs.trim()] = rep.trim();
2746
2748
  }
2747
2749
  if (opts.analyze && opts.from === "hubspot" && sourcePath) {
2748
- const { analyzeHubSpotExport } = await import("./import-hubspot-DB4n89jy.js");
2750
+ const { analyzeHubSpotExport } = await import("./import-hubspot-CTId9IGV.js");
2749
2751
  const analysis = await analyzeHubSpotExport(sourcePath);
2750
2752
  console.log(bold("\nDatasynxOpenCRM — HubSpot Import Analysis"));
2751
2753
  console.log("==========================================");
@@ -2944,7 +2946,7 @@ function icon(status) {
2944
2946
  return error("✗");
2945
2947
  }
2946
2948
  const doctorCommand = new Command("doctor").description("Run self-diagnostics: data integrity, temp files, log errors, backup freshness").option("--fix", "Clean up safely-fixable issues (orphaned temp files)").action(async (opts) => {
2947
- const { runDiagnostics, cleanupTempFiles } = await import("./doctor-C14-vnJ1.js");
2949
+ const { runDiagnostics, cleanupTempFiles } = await import("./doctor-CYDaNmFn.js");
2948
2950
  if (opts.fix) {
2949
2951
  const removed = cleanupTempFiles(dataDir$17());
2950
2952
  console.log(removed.length > 0 ? success(`Removed ${removed.length} orphaned temp file(s).`) : warning("Nothing to fix."));
@@ -4229,7 +4231,7 @@ function dataDir$5() {
4229
4231
  return process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4230
4232
  }
4231
4233
  const askCommand = new Command("ask").description("Ask your CRM a natural-language question").argument("<question>", "The question").option("--slug <slug>", "Scope to a customer").action(async (question, opts) => {
4232
- const { askCrm } = await import("./ask-D8iYqDAr.js");
4234
+ const { askCrm } = await import("./ask-CDysGnRg.js");
4233
4235
  const res = await askCrm(dataDir$5(), question, opts.slug);
4234
4236
  if (res.answer) {
4235
4237
  console.log(bold("Answer:"));
@@ -4248,7 +4250,7 @@ function dataDir$4() {
4248
4250
  return process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4249
4251
  }
4250
4252
  const nbaCommand = new Command("nba").description("Next-best-action recommendations for a customer").argument("<slug>", "Customer slug").action(async (slug) => {
4251
- const { nextBestAction } = await import("./nba-mTJ4yEqD.js");
4253
+ const { nextBestAction } = await import("./nba-DwdfM93s.js");
4252
4254
  const actions = await nextBestAction(dataDir$4(), slug);
4253
4255
  if (actions.length === 0) {
4254
4256
  console.log(info("No recommendations."));