@datasynx/agentic-crm 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.cjs CHANGED
@@ -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 |
@@ -1428,7 +1429,7 @@ async function buildContext(dataDir, slug) {
1428
1429
  }
1429
1430
  //#endregion
1430
1431
  //#region src/mcp/tools/get-customer-context.ts
1431
- const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1432
+ const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1432
1433
  function triggerOnQuerySync(dataDir, slug) {
1433
1434
  const auth = getGmailAuth();
1434
1435
  if (!auth) return;
@@ -1449,7 +1450,7 @@ function triggerOnQuerySync(dataDir, slug) {
1449
1450
  }).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
1450
1451
  } catch {}
1451
1452
  }
1452
- async function handleGetCustomerContext(input, dataDir = DATA_DIR$52) {
1453
+ async function handleGetCustomerContext(input, dataDir = DATA_DIR$53) {
1453
1454
  const targetSlug = input.slug ?? require_session_store.getSession()?.customerSlug;
1454
1455
  if (!targetSlug) return {
1455
1456
  content: [{
@@ -1585,8 +1586,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
1585
1586
  }
1586
1587
  //#endregion
1587
1588
  //#region src/mcp/tools/search-customer-knowledge.ts
1588
- const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1589
- 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) {
1590
1591
  const limit = input.limit ?? 5;
1591
1592
  try {
1592
1593
  const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
@@ -1634,14 +1635,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
1634
1635
  }
1635
1636
  //#endregion
1636
1637
  //#region src/mcp/tools/list-customers.ts
1637
- const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1638
+ const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1638
1639
  function extractLastInteractionDate(interactionsPath) {
1639
1640
  if (!fs.default.existsSync(interactionsPath)) return void 0;
1640
1641
  const content = fs.default.readFileSync(interactionsPath, "utf-8");
1641
1642
  const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
1642
1643
  return match ? match[1] : void 0;
1643
1644
  }
1644
- async function handleListCustomers(input, dataDir = DATA_DIR$50) {
1645
+ async function handleListCustomers(input, dataDir = DATA_DIR$51) {
1645
1646
  const customersDir = path.default.join(dataDir, "customers");
1646
1647
  const customers = [];
1647
1648
  if (!fs.default.existsSync(customersDir)) return { content: [{
@@ -2154,8 +2155,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
2154
2155
  }
2155
2156
  //#endregion
2156
2157
  //#region src/mcp/tools/log-interaction.ts
2157
- const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2158
- 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) {
2159
2160
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2160
2161
  const interactionDate = input.date ?? today;
2161
2162
  const sourceRef = input.source ?? `agent://log/${Date.now()}`;
@@ -2264,8 +2265,8 @@ var update_deal_exports = /* @__PURE__ */ require_chunk.__exportAll({
2264
2265
  handleUpdateDeal: () => handleUpdateDeal,
2265
2266
  registerUpdateDeal: () => registerUpdateDeal
2266
2267
  });
2267
- const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2268
- 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) {
2269
2270
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2270
2271
  const deal = {
2271
2272
  name: input.dealName,
@@ -2348,12 +2349,12 @@ Returns: { success: boolean, deal: object }`,
2348
2349
  }
2349
2350
  //#endregion
2350
2351
  //#region src/mcp/tools/export-customer.ts
2351
- const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2352
+ const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2352
2353
  function countInteractions(content) {
2353
2354
  const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
2354
2355
  return matches ? matches.length : 0;
2355
2356
  }
2356
- async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
2357
+ async function handleExportCustomer(input, dataDir = DATA_DIR$48) {
2357
2358
  require_session_store.enforceRbac(dataDir, "export_customer");
2358
2359
  const customerDir = path.default.join(dataDir, "customers", input.slug);
2359
2360
  if (!fs.default.existsSync(customerDir)) return {
@@ -2466,8 +2467,8 @@ Returns:
2466
2467
  }
2467
2468
  //#endregion
2468
2469
  //#region src/mcp/tools/update-customer-facts.ts
2469
- const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2470
- 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) {
2471
2472
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2472
2473
  try {
2473
2474
  require_session_store.enforceRbac(dataDir, "update_customer_facts");
@@ -2645,8 +2646,8 @@ function scoreDealForToday(deal, todayDate) {
2645
2646
  }
2646
2647
  //#endregion
2647
2648
  //#region src/mcp/tools/get-deal-health.ts
2648
- const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2649
- 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) {
2650
2651
  try {
2651
2652
  const deals = await require_pipeline_writer.readPipeline(dataDir, input.slug);
2652
2653
  const today = /* @__PURE__ */ new Date();
@@ -2695,8 +2696,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
2695
2696
  }
2696
2697
  //#endregion
2697
2698
  //#region src/mcp/tools/get-pipeline-forecast.ts
2698
- const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2699
- 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) {
2700
2701
  try {
2701
2702
  const slugs = require_session_store.listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
2702
2703
  const allDeals = [];
@@ -2757,8 +2758,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
2757
2758
  }
2758
2759
  //#endregion
2759
2760
  //#region src/mcp/tools/summarize-meeting.ts
2760
- const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2761
- 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) {
2762
2763
  try {
2763
2764
  let summary = input.transcript.slice(0, 400);
2764
2765
  let nextSteps = [];
@@ -2881,8 +2882,8 @@ function getPipelineStages(dataDir) {
2881
2882
  }
2882
2883
  //#endregion
2883
2884
  //#region src/mcp/tools/get-pipeline-stages.ts
2884
- const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2885
- 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) {
2886
2887
  const stages = getPipelineStages(dataDir);
2887
2888
  return { content: [{
2888
2889
  type: "text",
@@ -2910,8 +2911,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
2910
2911
  }
2911
2912
  //#endregion
2912
2913
  //#region src/mcp/tools/get-market-intelligence.ts
2913
- const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2914
- 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) {
2915
2916
  const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
2916
2917
  const all = require_session_store.listCustomerSlugs(dataDir);
2917
2918
  const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
@@ -2942,7 +2943,7 @@ function registerGetMarketIntelligence(server) {
2942
2943
  }
2943
2944
  //#endregion
2944
2945
  //#region src/mcp/tools/get-relationship-graph.ts
2945
- const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2946
+ const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2946
2947
  function summarizeNode(n) {
2947
2948
  return {
2948
2949
  id: n.id,
@@ -2950,7 +2951,7 @@ function summarizeNode(n) {
2950
2951
  email: n.properties["email"]
2951
2952
  };
2952
2953
  }
2953
- async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$40) {
2954
+ async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$41) {
2954
2955
  try {
2955
2956
  const graph = readGraph(dataDir, input.slug);
2956
2957
  const stakeholders = getStakeholders(graph);
@@ -3018,9 +3019,9 @@ Returns: {
3018
3019
  }
3019
3020
  //#endregion
3020
3021
  //#region src/mcp/tools/get-relationship-health.ts
3021
- const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3022
+ const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3022
3023
  const MAX_HEALTH_AGE_MS = 3600 * 1e3;
3023
- async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$39) {
3024
+ async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$40) {
3024
3025
  try {
3025
3026
  let health = readHealth(dataDir, input.slug);
3026
3027
  if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
@@ -3689,8 +3690,8 @@ async function runDealAgent(config, dataDir, llmFn = require_llm.callLlm) {
3689
3690
  }
3690
3691
  //#endregion
3691
3692
  //#region src/mcp/tools/run-deal-agent.ts
3692
- const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3693
- 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) {
3694
3695
  try {
3695
3696
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3696
3697
  const result = await runDealAgent({
@@ -3757,8 +3758,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
3757
3758
  }
3758
3759
  //#endregion
3759
3760
  //#region src/mcp/tools/approve-agent-action.ts
3760
- const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3761
- 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) {
3762
3763
  try {
3763
3764
  const queue = readAgentQueue(dataDir, input.slug);
3764
3765
  const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
@@ -4018,8 +4019,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
4018
4019
  }
4019
4020
  //#endregion
4020
4021
  //#region src/mcp/tools/simulate-revenue.ts
4021
- const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4022
- 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) {
4023
4024
  try {
4024
4025
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4025
4026
  const horizon = input.horizon ?? "quarter";
@@ -4077,8 +4078,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
4077
4078
  }
4078
4079
  //#endregion
4079
4080
  //#region src/mcp/tools/get-playbook.ts
4080
- const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4081
- 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) {
4082
4083
  try {
4083
4084
  const playbooks = listPlaybooks(dataDir, input.slug);
4084
4085
  if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
@@ -4163,12 +4164,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
4163
4164
  ...healthScore !== void 0 ? { healthScore } : {},
4164
4165
  ...daysSinceContact !== void 0 ? { daysSinceContact } : {},
4165
4166
  ...championPresent !== void 0 ? { championPresent } : {}
4166
- }, DATA_DIR$35));
4167
+ }, DATA_DIR$36));
4167
4168
  }
4168
4169
  //#endregion
4169
4170
  //#region src/mcp/tools/create-playbook.ts
4170
- const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4171
- 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) {
4172
4173
  try {
4173
4174
  const name = toKebabCase(input.name);
4174
4175
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4241,12 +4242,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
4241
4242
  trigger,
4242
4243
  content,
4243
4244
  ...successRate !== void 0 ? { successRate } : {}
4244
- }, DATA_DIR$34));
4245
+ }, DATA_DIR$35));
4245
4246
  }
4246
4247
  //#endregion
4247
4248
  //#region src/mcp/tools/list-playbooks.ts
4248
- const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4249
- 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) {
4250
4251
  try {
4251
4252
  const playbooks = listPlaybooks(dataDir, input.slug);
4252
4253
  return { content: [{
@@ -4285,12 +4286,12 @@ Args:
4285
4286
 
4286
4287
  Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
4287
4288
  inputSchema: zod.z.object({ slug: zod.z.string().describe("Customer ID") })
4288
- }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$33));
4289
+ }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$34));
4289
4290
  }
4290
4291
  //#endregion
4291
4292
  //#region src/mcp/tools/distill-playbook.ts
4292
- const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4293
- 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) {
4294
4295
  try {
4295
4296
  const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
4296
4297
  if (!result.ok) {
@@ -4349,7 +4350,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
4349
4350
  slug,
4350
4351
  dealName,
4351
4352
  outcome
4352
- }, DATA_DIR$32));
4353
+ }, DATA_DIR$33));
4353
4354
  }
4354
4355
  //#endregion
4355
4356
  //#region src/core/goal-engine.ts
@@ -4567,8 +4568,8 @@ function getActiveGoals(dataDir) {
4567
4568
  }
4568
4569
  //#endregion
4569
4570
  //#region src/mcp/tools/pursue-goal.ts
4570
- const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4571
- 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 = {}) {
4572
4573
  try {
4573
4574
  require_session_store.enforceRbac(dataDir, "pursue_goal");
4574
4575
  const goal = await pursueGoal(dataDir, {
@@ -4631,12 +4632,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
4631
4632
  goal,
4632
4633
  deadline,
4633
4634
  ...context !== void 0 ? { context } : {}
4634
- }, DATA_DIR$31));
4635
+ }, DATA_DIR$32));
4635
4636
  }
4636
4637
  //#endregion
4637
4638
  //#region src/mcp/tools/get-goal-status.ts
4638
- const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4639
- 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) {
4640
4641
  try {
4641
4642
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4642
4643
  const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
@@ -4695,17 +4696,17 @@ Args:
4695
4696
 
4696
4697
  Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
4697
4698
  inputSchema: zod.z.object({ goalId: zod.z.string().optional().describe("Specific goal ID (omit for all active goals)") })
4698
- }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$30));
4699
+ }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$31));
4699
4700
  }
4700
4701
  //#endregion
4701
4702
  //#region src/mcp/tools/register-push-subscription.ts
4702
- const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4703
+ const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4703
4704
  const VALID_PROVIDERS = [
4704
4705
  "gmail",
4705
4706
  "microsoft-graph",
4706
4707
  "slack"
4707
4708
  ];
4708
- async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$29) {
4709
+ async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$30) {
4709
4710
  try {
4710
4711
  if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
4711
4712
  type: "text",
@@ -4791,12 +4792,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
4791
4792
  ...microsoftResource !== void 0 ? { microsoftResource } : {},
4792
4793
  ...slackTeamId !== void 0 ? { slackTeamId } : {},
4793
4794
  ...slackChannelId !== void 0 ? { slackChannelId } : {}
4794
- }, DATA_DIR$29));
4795
+ }, DATA_DIR$30));
4795
4796
  }
4796
4797
  //#endregion
4797
4798
  //#region src/mcp/tools/get-push-status.ts
4798
- const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4799
- 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) {
4800
4801
  try {
4801
4802
  let subs = await readSubscriptions(dataDir);
4802
4803
  if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
@@ -4868,7 +4869,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
4868
4869
  }, async ({ slug, provider }) => handleGetPushStatus({
4869
4870
  ...slug !== void 0 ? { slug } : {},
4870
4871
  ...provider !== void 0 ? { provider } : {}
4871
- }, DATA_DIR$28));
4872
+ }, DATA_DIR$29));
4872
4873
  }
4873
4874
  //#endregion
4874
4875
  //#region src/core/org-intelligence.ts
@@ -4934,8 +4935,8 @@ function deriveRecommendation(people, missingRoles) {
4934
4935
  }
4935
4936
  //#endregion
4936
4937
  //#region src/mcp/tools/get-org-intelligence.ts
4937
- const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4938
- 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) {
4939
4940
  try {
4940
4941
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4941
4942
  const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
@@ -5068,8 +5069,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
5068
5069
  }
5069
5070
  //#endregion
5070
5071
  //#region src/mcp/tools/open-deal-room.ts
5071
- const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5072
- 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) {
5073
5074
  try {
5074
5075
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5075
5076
  const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
@@ -5152,8 +5153,8 @@ async function buildDailyBriefing(dataDir, today) {
5152
5153
  }
5153
5154
  //#endregion
5154
5155
  //#region src/mcp/tools/get-proactive-briefing.ts
5155
- const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5156
- 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) {
5157
5158
  try {
5158
5159
  const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
5159
5160
  return { content: [{
@@ -5253,15 +5254,15 @@ function getTemplate(dataDir, id) {
5253
5254
  }
5254
5255
  //#endregion
5255
5256
  //#region src/mcp/tools/list-email-templates.ts
5256
- const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5257
- 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) {
5258
5259
  const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
5259
5260
  return { content: [{
5260
5261
  type: "text",
5261
5262
  text: JSON.stringify(summary, null, 2)
5262
5263
  }] };
5263
5264
  }
5264
- function registerListEmailTemplates(server, dataDir = DATA_DIR$24) {
5265
+ function registerListEmailTemplates(server, dataDir = DATA_DIR$25) {
5265
5266
  server.registerTool("list_email_templates", {
5266
5267
  description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
5267
5268
  inputSchema: zod.z.object({ category: zod.z.string().optional().describe("Filter by category") })
@@ -5295,8 +5296,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
5295
5296
  }
5296
5297
  //#endregion
5297
5298
  //#region src/mcp/tools/get-email-template.ts
5298
- const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5299
- 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) {
5300
5301
  const tmpl = getTemplate(dataDir, input.id);
5301
5302
  if (!tmpl) return { content: [{
5302
5303
  type: "text",
@@ -5312,7 +5313,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
5312
5313
  }, null, 2)
5313
5314
  }] };
5314
5315
  }
5315
- function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
5316
+ function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
5316
5317
  server.registerTool("get_email_template", {
5317
5318
  description: "Get a specific email template by ID, including its body and detected variables.",
5318
5319
  inputSchema: zod.z.object({ id: zod.z.string().describe("Template ID (e.g. 'enterprise-intro')") })
@@ -5320,8 +5321,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
5320
5321
  }
5321
5322
  //#endregion
5322
5323
  //#region src/mcp/tools/draft-email.ts
5323
- const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5324
- 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) {
5325
5326
  const tmpl = getTemplate(dataDir, input.templateId);
5326
5327
  if (!tmpl) return { content: [{
5327
5328
  type: "text",
@@ -5365,7 +5366,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
5365
5366
  }, null, 2)
5366
5367
  }] };
5367
5368
  }
5368
- function registerDraftEmail(server, dataDir = DATA_DIR$22) {
5369
+ function registerDraftEmail(server, dataDir = DATA_DIR$23) {
5369
5370
  server.registerTool("draft_email", {
5370
5371
  description: `Draft a personalized email for a customer using a stored template.
5371
5372
  Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
@@ -5473,8 +5474,8 @@ async function updateEnrollment(dataDir, id, updates) {
5473
5474
  }
5474
5475
  //#endregion
5475
5476
  //#region src/mcp/tools/enroll-in-sequence.ts
5476
- const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5477
- 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) {
5478
5479
  const sequence = getSequence(dataDir, input.sequenceId);
5479
5480
  if (!sequence) return { content: [{
5480
5481
  type: "text",
@@ -5506,7 +5507,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
5506
5507
  })
5507
5508
  }] };
5508
5509
  }
5509
- function registerEnrollInSequence(server, dataDir = DATA_DIR$21) {
5510
+ function registerEnrollInSequence(server, dataDir = DATA_DIR$22) {
5510
5511
  server.registerTool("enroll_in_sequence", {
5511
5512
  description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
5512
5513
  Returns: { enrollmentId, sequenceName, totalSteps }`,
@@ -5523,8 +5524,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
5523
5524
  }
5524
5525
  //#endregion
5525
5526
  //#region src/mcp/tools/list-sequence-enrollments.ts
5526
- const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5527
- 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) {
5528
5529
  let enrollments = readEnrollments(dataDir);
5529
5530
  if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
5530
5531
  if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
@@ -5533,7 +5534,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
5533
5534
  text: JSON.stringify({ enrollments }, null, 2)
5534
5535
  }] };
5535
5536
  }
5536
- function registerListSequenceEnrollments(server, dataDir = DATA_DIR$20) {
5537
+ function registerListSequenceEnrollments(server, dataDir = DATA_DIR$21) {
5537
5538
  server.registerTool("list_sequence_enrollments", {
5538
5539
  description: `List email sequence enrollments. Filter by customer slug or status.
5539
5540
  Returns: { enrollments: SequenceEnrollment[] }`,
@@ -5552,8 +5553,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
5552
5553
  }
5553
5554
  //#endregion
5554
5555
  //#region src/mcp/tools/unenroll-from-sequence.ts
5555
- const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5556
- 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) {
5557
5558
  if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
5558
5559
  type: "text",
5559
5560
  text: JSON.stringify({
@@ -5566,7 +5567,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
5566
5567
  text: JSON.stringify({ success: true })
5567
5568
  }] };
5568
5569
  }
5569
- function registerUnenrollFromSequence(server, dataDir = DATA_DIR$19) {
5570
+ function registerUnenrollFromSequence(server, dataDir = DATA_DIR$20) {
5570
5571
  server.registerTool("unenroll_from_sequence", {
5571
5572
  description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
5572
5573
  Returns: { success: boolean }`,
@@ -5575,8 +5576,8 @@ Returns: { success: boolean }`,
5575
5576
  }
5576
5577
  //#endregion
5577
5578
  //#region src/mcp/tools/list-sequences.ts
5578
- const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5579
- 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) {
5580
5581
  const sequences = listSequences(dataDir);
5581
5582
  const enrollments = readEnrollments(dataDir);
5582
5583
  const result = sequences.map((seq) => ({
@@ -5590,7 +5591,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
5590
5591
  text: JSON.stringify({ sequences: result }, null, 2)
5591
5592
  }] };
5592
5593
  }
5593
- function registerListSequences(server, dataDir = DATA_DIR$18) {
5594
+ function registerListSequences(server, dataDir = DATA_DIR$19) {
5594
5595
  server.registerTool("list_sequences", {
5595
5596
  description: `List all email sequences with step count and enrollment count.
5596
5597
  Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
@@ -5725,8 +5726,8 @@ async function generateQuote(dataDir, input) {
5725
5726
  }
5726
5727
  //#endregion
5727
5728
  //#region src/mcp/tools/generate-quote.ts
5728
- const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5729
- 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) {
5730
5731
  try {
5731
5732
  const quote = await generateQuote(dataDir, input);
5732
5733
  return { content: [{
@@ -5750,7 +5751,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
5750
5751
  }] };
5751
5752
  }
5752
5753
  }
5753
- function registerGenerateQuote(server, dataDir = DATA_DIR$17) {
5754
+ function registerGenerateQuote(server, dataDir = DATA_DIR$18) {
5754
5755
  server.registerTool("generate_quote", {
5755
5756
  description: `Generate a professional HTML quote/offer for a customer deal.
5756
5757
  Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
@@ -5778,8 +5779,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
5778
5779
  }
5779
5780
  //#endregion
5780
5781
  //#region src/mcp/tools/get-quote-status.ts
5781
- const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5782
- 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) {
5783
5784
  if (input.quoteNumber) {
5784
5785
  const quote = readQuote(dataDir, input.quoteNumber);
5785
5786
  if (!quote) return { content: [{
@@ -5797,7 +5798,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
5797
5798
  text: JSON.stringify({ quotes }, null, 2)
5798
5799
  }] };
5799
5800
  }
5800
- function registerGetQuoteStatus(server, dataDir = DATA_DIR$16) {
5801
+ function registerGetQuoteStatus(server, dataDir = DATA_DIR$17) {
5801
5802
  server.registerTool("get_quote_status", {
5802
5803
  description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
5803
5804
  Returns quote with status: draft | sent | viewed | accepted | declined`,
@@ -5812,7 +5813,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
5812
5813
  }
5813
5814
  //#endregion
5814
5815
  //#region src/mcp/tools/get-booking-link.ts
5815
- const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5816
+ const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5816
5817
  function loadCalendlyConfig(dataDir) {
5817
5818
  const p = path.default.join(dataDir, ".agentic", "integrations", "calendly.yaml");
5818
5819
  if (!fs.default.existsSync(p)) return {};
@@ -5835,7 +5836,7 @@ function readCustomerFacts(dataDir, slug) {
5835
5836
  ...email ? { email } : {}
5836
5837
  };
5837
5838
  }
5838
- async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
5839
+ async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
5839
5840
  const config = loadCalendlyConfig(dataDir);
5840
5841
  const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
5841
5842
  if (!apiKey) return { content: [{
@@ -5863,7 +5864,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
5863
5864
  }] };
5864
5865
  }
5865
5866
  }
5866
- function registerGetBookingLink(server, dataDir = DATA_DIR$15) {
5867
+ function registerGetBookingLink(server, dataDir = DATA_DIR$16) {
5867
5868
  server.registerTool("get_booking_link", {
5868
5869
  description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
5869
5870
  Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
@@ -6033,8 +6034,8 @@ function calcSlaDue(createdDate, priority, rules) {
6033
6034
  }
6034
6035
  //#endregion
6035
6036
  //#region src/mcp/tools/create-ticket.ts
6036
- const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6037
- 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) {
6038
6039
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6039
6040
  const rules = loadSlaRules(dataDir);
6040
6041
  const priority = input.priority ?? "normal";
@@ -6056,7 +6057,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
6056
6057
  text: JSON.stringify({ ticket }, null, 2)
6057
6058
  }] };
6058
6059
  }
6059
- function registerCreateTicket(server, dataDir = DATA_DIR$14) {
6060
+ function registerCreateTicket(server, dataDir = DATA_DIR$15) {
6060
6061
  server.registerTool("create_ticket", {
6061
6062
  description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
6062
6063
  Returns: { ticket } with id T-NNN, status=open, slaDue`,
@@ -6082,8 +6083,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
6082
6083
  }
6083
6084
  //#endregion
6084
6085
  //#region src/mcp/tools/update-ticket.ts
6085
- const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6086
- 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) {
6087
6088
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6088
6089
  if (!ticket) return { content: [{
6089
6090
  type: "text",
@@ -6102,7 +6103,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
6102
6103
  text: JSON.stringify({ ticket: updated }, null, 2)
6103
6104
  }] };
6104
6105
  }
6105
- function registerUpdateTicket(server, dataDir = DATA_DIR$13) {
6106
+ function registerUpdateTicket(server, dataDir = DATA_DIR$14) {
6106
6107
  server.registerTool("update_ticket", {
6107
6108
  description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
6108
6109
  Returns: { ticket }`,
@@ -6127,8 +6128,8 @@ Returns: { ticket }`,
6127
6128
  }
6128
6129
  //#endregion
6129
6130
  //#region src/mcp/tools/list-tickets.ts
6130
- const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6131
- 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) {
6132
6133
  const results = await listAllTickets(dataDir, {
6133
6134
  ...input.slug !== void 0 ? { slug: input.slug } : {},
6134
6135
  ...input.status !== void 0 ? { status: input.status } : {},
@@ -6140,7 +6141,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$12) {
6140
6141
  text: JSON.stringify({ tickets: results }, null, 2)
6141
6142
  }] };
6142
6143
  }
6143
- function registerListTickets(server, dataDir = DATA_DIR$12) {
6144
+ function registerListTickets(server, dataDir = DATA_DIR$13) {
6144
6145
  server.registerTool("list_tickets", {
6145
6146
  description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
6146
6147
  Returns: { tickets: Array<{ slug, ticket }> }`,
@@ -6170,8 +6171,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
6170
6171
  }
6171
6172
  //#endregion
6172
6173
  //#region src/mcp/tools/close-ticket.ts
6173
- const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6174
- 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) {
6175
6176
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6176
6177
  if (!ticket) return { content: [{
6177
6178
  type: "text",
@@ -6198,7 +6199,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
6198
6199
  text: JSON.stringify({ ticket: updated }, null, 2)
6199
6200
  }] };
6200
6201
  }
6201
- function registerCloseTicket(server, dataDir = DATA_DIR$11) {
6202
+ function registerCloseTicket(server, dataDir = DATA_DIR$12) {
6202
6203
  server.registerTool("close_ticket", {
6203
6204
  description: `Close a support ticket. Optionally logs the resolution as an interaction.
6204
6205
  Returns: { ticket } with status=closed`,
@@ -6352,8 +6353,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
6352
6353
  }
6353
6354
  //#endregion
6354
6355
  //#region src/mcp/tools/send-nps-survey.ts
6355
- const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6356
- 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) {
6357
6358
  const survey = getSurvey(dataDir, input.surveyId);
6358
6359
  if (!survey) return { content: [{
6359
6360
  type: "text",
@@ -6374,7 +6375,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
6374
6375
  }, null, 2)
6375
6376
  }] };
6376
6377
  }
6377
- function registerSendNpsSurvey(server, dataDir = DATA_DIR$10) {
6378
+ function registerSendNpsSurvey(server, dataDir = DATA_DIR$11) {
6378
6379
  server.registerTool("send_nps_survey", {
6379
6380
  description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
6380
6381
  Does NOT send automatically — returns draft for review.
@@ -6394,8 +6395,8 @@ Returns: { token, subject, body, surveyUrl }`,
6394
6395
  }
6395
6396
  //#endregion
6396
6397
  //#region src/mcp/tools/get-survey-results.ts
6397
- const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6398
- 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) {
6399
6400
  const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
6400
6401
  const nps = calcNpsScore(responses);
6401
6402
  const promoters = responses.filter((r) => r.score >= 9).length;
@@ -6421,7 +6422,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
6421
6422
  }, null, 2)
6422
6423
  }] };
6423
6424
  }
6424
- function registerGetSurveyResults(server, dataDir = DATA_DIR$9) {
6425
+ function registerGetSurveyResults(server, dataDir = DATA_DIR$10) {
6425
6426
  server.registerTool("get_survey_results", {
6426
6427
  description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
6427
6428
  Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
@@ -6522,8 +6523,8 @@ function getKbMetaForExport(article) {
6522
6523
  }
6523
6524
  //#endregion
6524
6525
  //#region src/mcp/tools/search-knowledge-base.ts
6525
- const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6526
- 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) {
6527
6528
  const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
6528
6529
  const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
6529
6530
  return { content: [{
@@ -6538,7 +6539,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
6538
6539
  }, null, 2)
6539
6540
  }] };
6540
6541
  }
6541
- function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$8) {
6542
+ function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$9) {
6542
6543
  server.registerTool("search_knowledge_base", {
6543
6544
  description: `Search the knowledge base for articles. Text search on title, body, and tags.
6544
6545
  Returns: { count, articles[] } with excerpts`,
@@ -6557,8 +6558,8 @@ Returns: { count, articles[] } with excerpts`,
6557
6558
  }
6558
6559
  //#endregion
6559
6560
  //#region src/mcp/tools/create-kb-article.ts
6560
- const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6561
- 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) {
6562
6563
  if (getKbArticle(dataDir, input.id)) return { content: [{
6563
6564
  type: "text",
6564
6565
  text: JSON.stringify({ error: `Article '${input.id}' already exists` })
@@ -6586,7 +6587,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
6586
6587
  }, null, 2)
6587
6588
  }] };
6588
6589
  }
6589
- function registerCreateKbArticle(server, dataDir = DATA_DIR$7) {
6590
+ function registerCreateKbArticle(server, dataDir = DATA_DIR$8) {
6590
6591
  server.registerTool("create_kb_article", {
6591
6592
  description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
6592
6593
  Returns: { id, title, category, path }`,
@@ -6611,8 +6612,8 @@ Returns: { id, title, category, path }`,
6611
6612
  }
6612
6613
  //#endregion
6613
6614
  //#region src/mcp/tools/backup-now.ts
6614
- const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6615
- 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) {
6616
6617
  const zipPath = path.default.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
6617
6618
  const manifest = await require_session_store.runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
6618
6619
  if (!manifest) return { content: [{
@@ -6649,8 +6650,8 @@ function registerBackupNow(server) {
6649
6650
  }
6650
6651
  //#endregion
6651
6652
  //#region src/mcp/tools/list-backups.ts
6652
- const DATA_DIR$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6653
- 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) {
6654
6655
  const logEntries = require_session_store.readBackupLog(dataDir);
6655
6656
  const fileEntries = require_session_store.listBackupsInDir(dataDir);
6656
6657
  const entries = logEntries.length > 0 ? logEntries : fileEntries;
@@ -6684,8 +6685,8 @@ function registerListBackups(server) {
6684
6685
  }
6685
6686
  //#endregion
6686
6687
  //#region src/mcp/tools/trigger-sync.ts
6687
- const DATA_DIR$4 = process.cwd();
6688
- async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
6688
+ const DATA_DIR$5 = process.cwd();
6689
+ async function handleTriggerSync(input, dataDir = DATA_DIR$5) {
6689
6690
  const auth = getGmailAuth();
6690
6691
  if (!auth) return { content: [{
6691
6692
  type: "text",
@@ -6779,8 +6780,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
6779
6780
  }
6780
6781
  //#endregion
6781
6782
  //#region src/mcp/tools/get-audit-log.ts
6782
- const DATA_DIR$3 = process.cwd();
6783
- async function handleGetAuditLog(input, dataDir = DATA_DIR$3) {
6783
+ const DATA_DIR$4 = process.cwd();
6784
+ async function handleGetAuditLog(input, dataDir = DATA_DIR$4) {
6784
6785
  const entries = require_session_store.readAuditLog(dataDir);
6785
6786
  const filterOpts = { limit: input.limit ?? 50 };
6786
6787
  if (input.slug !== void 0) filterOpts.slug = input.slug;
@@ -6822,8 +6823,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
6822
6823
  }
6823
6824
  //#endregion
6824
6825
  //#region src/mcp/tools/get-logs.ts
6825
- const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6826
- 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) {
6827
6828
  const query = {
6828
6829
  ...input.level !== void 0 ? { level: input.level } : {},
6829
6830
  ...input.component !== void 0 ? { component: input.component } : {},
@@ -6884,6 +6885,140 @@ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors
6884
6885
  });
6885
6886
  }
6886
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
6887
7022
  //#region src/mcp/prompts.ts
6888
7023
  /**
6889
7024
  * CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
@@ -7300,6 +7435,7 @@ function createMcpServer() {
7300
7435
  registerTriggerSync(server);
7301
7436
  registerGetAuditLog(server);
7302
7437
  registerGetLogs(server);
7438
+ registerGetDiagnostics(server);
7303
7439
  registerCustomObjectTools(server);
7304
7440
  registerPrompts(server);
7305
7441
  registerResources(server);