@datasynx/agentic-crm 1.7.0 → 1.9.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 (44) hide show
  1. package/dist/cli.js +101 -8
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon/worker.js +3 -3
  4. package/dist/funnel-B2mwpZE1.js +89 -0
  5. package/dist/funnel-B2mwpZE1.js.map +1 -0
  6. package/dist/funnel-CJ7fy7hG.js +2 -0
  7. package/dist/{index-DcDaz_cu.d.cts → index-BAutNcAT.d.cts} +11 -11
  8. package/dist/index-BAutNcAT.d.cts.map +1 -0
  9. package/dist/index.d.cts +11 -11
  10. package/dist/index.d.cts.map +1 -1
  11. package/dist/{knowledge-base-Cc0niBFf.js → knowledge-base-yo-BLUcB.js} +3 -1
  12. package/dist/knowledge-base-yo-BLUcB.js.map +1 -0
  13. package/dist/{login-yt9OOQQk.js → login-dc_Hqosw.js} +2 -2
  14. package/dist/{login-yt9OOQQk.js.map → login-dc_Hqosw.js.map} +1 -1
  15. package/dist/mailbox-config-BU3vib2T.js +2 -0
  16. package/dist/{mailbox-config-Dn2xTn9N.js → mailbox-config-trjLPHPG.js} +2 -2
  17. package/dist/{mailbox-config-Dn2xTn9N.js.map → mailbox-config-trjLPHPG.js.map} +1 -1
  18. package/dist/{mailbox-poll-B8dvFAXT.js → mailbox-poll-Ban7C3X0.js} +3 -3
  19. package/dist/{mailbox-poll-B8dvFAXT.js.map → mailbox-poll-Ban7C3X0.js.map} +1 -1
  20. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  21. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  22. package/dist/mcp.cjs +415 -137
  23. package/dist/mcp.cjs.map +1 -1
  24. package/dist/mcp.d.cts.map +1 -1
  25. package/dist/mcp.d.ts.map +1 -1
  26. package/dist/mcp.js +415 -137
  27. package/dist/mcp.js.map +1 -1
  28. package/dist/{server-BbInMUgp.js → server-DAcwmRPE.js} +195 -133
  29. package/dist/server-DAcwmRPE.js.map +1 -0
  30. package/dist/{token-resolver-D98qPOOf.js → token-resolver-CL8-CSgZ.js} +2 -2
  31. package/dist/{token-resolver-D98qPOOf.js.map → token-resolver-CL8-CSgZ.js.map} +1 -1
  32. package/dist/{token-store-B0h0USqe.js → token-store-BPDwePNT.js} +13 -2
  33. package/dist/token-store-BPDwePNT.js.map +1 -0
  34. package/dist/token-store-D3HCeXmE.js +2 -0
  35. package/dist/velocity-BtX1l5Gh.js +2 -0
  36. package/dist/velocity-C2l4cW0K.js +123 -0
  37. package/dist/velocity-C2l4cW0K.js.map +1 -0
  38. package/package.json +1 -1
  39. package/dist/index-DcDaz_cu.d.cts.map +0 -1
  40. package/dist/knowledge-base-Cc0niBFf.js.map +0 -1
  41. package/dist/mailbox-config-Bu-J1O4I.js +0 -2
  42. package/dist/server-BbInMUgp.js.map +0 -1
  43. package/dist/token-store-B0h0USqe.js.map +0 -1
  44. package/dist/token-store-CEmz8d-0.js +0 -2
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ 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-Cc0niBFf.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-yo-BLUcB.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";
@@ -23,7 +23,8 @@ import { n as listQuotes, r as readQuote, t as generateQuote } from "./quote-gen
23
23
  import { i as upsertTicket, n as nextTicketId, r as readTickets, t as listAllTickets } from "./ticket-writer-a9on36Wb.js";
24
24
  import { i as loadSlaRules, t as calcSlaDue } from "./sla-engine-O-A1ntu_.js";
25
25
  import { a as listSurveys, d as writeSurvey, i as getSurvey, l as savePendingSurvey, n as calcNpsScore, o as loadSurveyResponses, r as generateSurveyToken } from "./survey-engine-DngXBv47.js";
26
- import { i as resolveAccountConfig, n as imapConfigFromEnv } from "./mailbox-config-Dn2xTn9N.js";
26
+ import { i as resolveAccountConfig, n as imapConfigFromEnv, r as parseAccount } from "./mailbox-config-trjLPHPG.js";
27
+ import { i as removeMailboxToken, n as listMailboxTokens, t as isTokenExpired } from "./token-store-BPDwePNT.js";
27
28
  import { Command } from "commander";
28
29
  import path from "path";
29
30
  import fs from "fs";
@@ -242,14 +243,14 @@ mcpCommand.command("start").description("Start MCP server (stdio by default)").o
242
243
  if (opts.http) {
243
244
  const port = parseInt(opts.port, 10);
244
245
  console.error(info(`Starting MCP server in HTTP mode on port ${port}...`));
245
- const { startHttp } = await import("./server-BbInMUgp.js");
246
+ const { startHttp } = await import("./server-DAcwmRPE.js");
246
247
  await startHttp(port);
247
248
  } else {
248
- const { startStdio } = await import("./server-BbInMUgp.js");
249
+ const { startStdio } = await import("./server-DAcwmRPE.js");
249
250
  await startStdio();
250
251
  }
251
252
  });
252
- const TOOL_COUNT = 59;
253
+ const TOOL_COUNT = 61;
253
254
  /** Claude Code: CLAUDE.md in CRM dataDir */
254
255
  function buildClaudeMd(dataDir) {
255
256
  return `# DatasynxOpenCRM v2 — Agent Instructions (${TOOL_COUNT} MCP Tools)
@@ -378,6 +379,8 @@ It combines graph, health, revenue simulation, playbook, and org intelligence in
378
379
  - \`get_logs({ level?, component?, since?, contains?, limit?, summary? })\` — query/aggregate the structured application log
379
380
  - \`get_diagnostics({ fix? })\` — self-diagnostic health check (data integrity, temp files, log errors, backups)
380
381
  - \`get_pipeline_changes({ since?, days? })\` — pipeline time-travel: what changed (won/lost/moved/value) since a date
382
+ - \`get_pipeline_velocity({ stalledDays? })\` — stage dwell times, sales cycle, and stalled deals from snapshot history
383
+ - \`get_pipeline_funnel()\` — conversion funnel & win rate: where deals leak out of the pipeline
381
384
 
382
385
  ### Custom Objects (Platform / metadata)
383
386
  - \`define_custom_object({ name, label?, fields })\` — define a runtime entity type with typed fields (no migration), admin
@@ -639,7 +642,8 @@ create_ticket · update_ticket · list_tickets · close_ticket ·
639
642
  send_nps_survey · get_survey_results ·
640
643
  search_knowledge_base · create_kb_article ·
641
644
  backup_now · list_backups ·
642
- trigger_sync · get_audit_log · get_logs · get_diagnostics · get_pipeline_changes ·
645
+ trigger_sync · get_audit_log · get_logs · get_diagnostics ·
646
+ get_pipeline_changes · get_pipeline_velocity · get_pipeline_funnel ·
643
647
  define_custom_object · create_record · list_records · list_custom_objects
644
648
 
645
649
  ## Data: ${dataDir}`.trim();
@@ -1844,6 +1848,12 @@ async function runStatus(opts, dataDir) {
1844
1848
  const daemonLine = daemon.running ? success(`running (PID ${daemon.pid})`) : error("not running");
1845
1849
  console.log(` Daemon: ${daemonLine}`);
1846
1850
  console.log(` Customers: ${slugs.length} active`);
1851
+ const { listMailboxTokens, isTokenExpired } = await import("./token-store-D3HCeXmE.js");
1852
+ const mailboxTokens = listMailboxTokens(dir);
1853
+ if (mailboxTokens.length > 0) {
1854
+ const valid = mailboxTokens.filter((t) => !isTokenExpired(t)).length;
1855
+ console.log(` Mailboxes: ${mailboxTokens.length} linked (${valid} valid)`);
1856
+ }
1847
1857
  const session = getSession() ?? readAllSessions(dir)[0] ?? null;
1848
1858
  if (session) {
1849
1859
  const ownerPart = session.owner ? ` [${session.owner}]` : "";
@@ -3018,6 +3028,54 @@ pipelineCommand.command("changes").description("Show what changed in the pipelin
3018
3028
  for (const d of diff.added) console.log(` ${d.slug}/${d.name}`);
3019
3029
  }
3020
3030
  });
3031
+ pipelineCommand.command("velocity").description("Stage dwell times, sales cycle, and stalled deals from snapshot history").option("--stalled-days <n>", "Days in one stage before a deal counts as stalled (default 14)").action(async (opts) => {
3032
+ const { analyzeVelocity } = await import("./velocity-BtX1l5Gh.js");
3033
+ const analyzeOpts = {};
3034
+ if (opts.stalledDays !== void 0) {
3035
+ const n = parseInt(opts.stalledDays, 10);
3036
+ if (Number.isFinite(n) && n > 0) analyzeOpts.stalledDays = n;
3037
+ }
3038
+ const report = analyzeVelocity(dataDir$17(), analyzeOpts);
3039
+ if (report.snapshotCount === 0) {
3040
+ console.log(info("No snapshots yet. Run 'dxcrm pipeline snapshot' (or let the daemon take daily ones)."));
3041
+ return;
3042
+ }
3043
+ console.log(bold(`Pipeline velocity (${report.snapshotCount} snapshots, ${report.fromId} → ${report.toId})`));
3044
+ if (report.stageDurations.length) {
3045
+ console.log(info("\nAvg time in stage:"));
3046
+ for (const s of report.stageDurations) {
3047
+ const samples = `${s.samples} sample${s.samples === 1 ? "" : "s"}`;
3048
+ console.log(` ${s.stage.padEnd(14)} ${s.avgDays}d (${samples})`);
3049
+ }
3050
+ }
3051
+ const cycle = report.avgSalesCycleDays;
3052
+ const cycleStr = cycle === null ? "n/a (no won deals yet)" : `${cycle}d avg`;
3053
+ console.log(`\n ${"Sales cycle".padEnd(14)} ${cycleStr} over ${report.wonCount} won`);
3054
+ if (report.stalledDeals.length) {
3055
+ console.log(error(`\nStalled deals (> ${report.stalledThresholdDays}d in stage):`));
3056
+ for (const d of report.stalledDeals) console.log(` ${d.slug}/${d.name}: ${d.stage}, ${d.daysInStage}d €${d.value.toLocaleString()}`);
3057
+ } else console.log(success(`\nNo stalled deals (threshold ${report.stalledThresholdDays}d).`));
3058
+ });
3059
+ pipelineCommand.command("funnel").description("Conversion funnel & win rate: where deals leak out of the pipeline").action(async () => {
3060
+ const { analyzeFunnel } = await import("./funnel-CJ7fy7hG.js");
3061
+ const report = analyzeFunnel(dataDir$17());
3062
+ if (report.snapshotCount === 0) {
3063
+ console.log(info("No snapshots yet. Run 'dxcrm pipeline snapshot' (or let the daemon take daily ones)."));
3064
+ return;
3065
+ }
3066
+ console.log(bold(`Pipeline funnel (${report.snapshotCount} snapshots, ${report.fromId} → ${report.toId})`));
3067
+ for (const s of report.stages) {
3068
+ const conv = s.conversionPctToNext === null ? "" : ` → ${s.conversionPctToNext}% convert`;
3069
+ console.log(` ${s.stage.padEnd(14)} ${String(s.reached).padStart(4)} reached${conv}`);
3070
+ }
3071
+ const wr = report.winRatePct;
3072
+ const wrStr = wr === null ? "n/a (nothing closed yet)" : `${wr}%`;
3073
+ console.log(`\n ${"Win rate".padEnd(14)} ${wrStr} (${report.wonCount} won / ${report.lostCount} lost)`);
3074
+ if (report.biggestLeak) {
3075
+ const l = report.biggestLeak;
3076
+ console.log(error(`\nBiggest leak: ${l.from} → ${l.to} (only ${l.conversionPct}% convert)`));
3077
+ }
3078
+ });
3021
3079
  //#endregion
3022
3080
  //#region src/commands/rbac.ts
3023
3081
  const ROLES = [
@@ -4483,6 +4541,22 @@ complianceCommand.command("status", { isDefault: true }).description("Show the a
4483
4541
  });
4484
4542
  //#endregion
4485
4543
  //#region src/commands/mailbox.ts
4544
+ /** Summarize every stored mailbox OAuth account. */
4545
+ function runMailboxList(dataDir) {
4546
+ return listMailboxTokens(dataDir).map((t) => ({
4547
+ account: `${t.provider}:${t.user}`,
4548
+ provider: t.provider,
4549
+ user: t.user,
4550
+ status: isTokenExpired(t) ? "expired" : "valid",
4551
+ expiresAt: new Date(t.expiresAt).toISOString()
4552
+ }));
4553
+ }
4554
+ /** Remove a stored mailbox account by "provider:user". */
4555
+ function runMailboxLogout(dataDir, account) {
4556
+ const parsed = parseAccount(account);
4557
+ if (!parsed) return { error: `Invalid account '${account}'. Use 'gmail:you@gmail.com' or 'microsoft:you@org.com'.` };
4558
+ return { removed: removeMailboxToken(dataDir, parsed.provider, parsed.user) };
4559
+ }
4486
4560
  /**
4487
4561
  * Sync an IMAP mailbox (any provider). With a slug, all mail goes to that one
4488
4562
  * customer; without, mail is auto-routed to customers by sender/recipient
@@ -4536,7 +4610,7 @@ async function runLogin(provider, user) {
4536
4610
  return;
4537
4611
  }
4538
4612
  const account = user ?? (await ask("Gmail address: ")).trim();
4539
- const { runGmailLogin } = await import("./login-yt9OOQQk.js");
4613
+ const { runGmailLogin } = await import("./login-dc_Hqosw.js");
4540
4614
  await runGmailLogin({
4541
4615
  dataDir,
4542
4616
  clientId,
@@ -4556,7 +4630,7 @@ async function runLogin(provider, user) {
4556
4630
  }
4557
4631
  const tenant = process.env["DXCRM_MS_TENANT"] ?? "common";
4558
4632
  const account = user ?? (await ask("Outlook/Microsoft address: ")).trim();
4559
- const { runMicrosoftLogin } = await import("./login-yt9OOQQk.js");
4633
+ const { runMicrosoftLogin } = await import("./login-dc_Hqosw.js");
4560
4634
  await runMicrosoftLogin({
4561
4635
  dataDir,
4562
4636
  clientId,
@@ -4582,6 +4656,25 @@ mailboxCommand.command("sync").description("Sync an IMAP mailbox; auto-routes to
4582
4656
  includeAttachments: options.attachments !== false
4583
4657
  });
4584
4658
  });
4659
+ mailboxCommand.command("list").description("List logged-in mailbox accounts and their token status").action(() => {
4660
+ const accounts = runMailboxList(process.env["DXCRM_DATA_DIR"] ?? process.cwd());
4661
+ if (accounts.length === 0) {
4662
+ console.log(info("No mailbox accounts. Run 'dxcrm mailbox login gmail|microsoft'."));
4663
+ return;
4664
+ }
4665
+ for (const a of accounts) {
4666
+ const tag = a.status === "valid" ? success("valid") : error("expired");
4667
+ console.log(`${bold(a.account)} — token ${tag} (expires ${a.expiresAt})`);
4668
+ }
4669
+ });
4670
+ mailboxCommand.command("logout").description("Remove a stored mailbox account").argument("<account>", "provider:user (e.g. gmail:you@gmail.com)").action((account) => {
4671
+ const result = runMailboxLogout(process.env["DXCRM_DATA_DIR"] ?? process.cwd(), account);
4672
+ if ("error" in result) {
4673
+ console.error(error(result.error));
4674
+ return;
4675
+ }
4676
+ console.log(result.removed ? success(`✓ Removed ${bold(account)}.`) : info(`No stored account '${account}'.`));
4677
+ });
4585
4678
  //#endregion
4586
4679
  //#region src/commands/registry.ts
4587
4680
  /** Every top-level `dxcrm` command, in display order. */