@datasynx/agentic-crm 1.5.0 → 1.6.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/cli.js +66 -11
- package/dist/cli.js.map +1 -1
- package/dist/daemon/worker.js +16 -0
- package/dist/daemon/worker.js.map +1 -1
- package/dist/{index-FzDsNSSb.d.ts → index-BBAlKZg6.d.ts} +3 -3
- package/dist/{index-FzDsNSSb.d.ts.map → index-BBAlKZg6.d.ts.map} +1 -1
- package/dist/{index-B5_QnkG8.d.cts → index-DNHsURo5.d.cts} +14 -14
- package/dist/index-DNHsURo5.d.cts.map +1 -0
- package/dist/index.d.cts +14 -14
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/{knowledge-base-Bx2PKQR2.js → knowledge-base-Cc0niBFf.js} +2 -1
- package/dist/knowledge-base-Cc0niBFf.js.map +1 -0
- package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
- package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
- package/dist/mcp.cjs +289 -130
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.d.cts.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +289 -130
- package/dist/mcp.js.map +1 -1
- package/dist/{server-uqXUhF4H.js → server-BbInMUgp.js} +172 -130
- package/dist/server-BbInMUgp.js.map +1 -0
- package/dist/snapshots-B6aOhoXs.js +2 -0
- package/dist/snapshots-CQSOaIMs.js +161 -0
- package/dist/snapshots-CQSOaIMs.js.map +1 -0
- package/package.json +2 -2
- package/dist/index-B5_QnkG8.d.cts.map +0 -1
- package/dist/knowledge-base-Bx2PKQR2.js.map +0 -1
- package/dist/server-uqXUhF4H.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -444,6 +444,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
444
444
|
| get_audit_log | Read audit log — all write operations with actor, tool, customer | admin |
|
|
445
445
|
| get_logs | Query/aggregate the structured application log (level, component, errors) | admin |
|
|
446
446
|
| get_diagnostics | Self-diagnostic health check (data integrity, temp files, log errors, backups) | admin |
|
|
447
|
+
| get_pipeline_changes | Pipeline time-travel: what changed (won/lost/moved/value) since a date | any |
|
|
447
448
|
| define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
|
|
448
449
|
| create_record | Create a record of a custom object (validated against its schema) | rep+ |
|
|
449
450
|
| list_records | List records of a custom object | any |
|
|
@@ -1422,7 +1423,7 @@ async function buildContext(dataDir, slug) {
|
|
|
1422
1423
|
}
|
|
1423
1424
|
//#endregion
|
|
1424
1425
|
//#region src/mcp/tools/get-customer-context.ts
|
|
1425
|
-
const DATA_DIR$
|
|
1426
|
+
const DATA_DIR$54 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1426
1427
|
function triggerOnQuerySync(dataDir, slug) {
|
|
1427
1428
|
const auth = getGmailAuth();
|
|
1428
1429
|
if (!auth) return;
|
|
@@ -1443,7 +1444,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1443
1444
|
}).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
|
|
1444
1445
|
} catch {}
|
|
1445
1446
|
}
|
|
1446
|
-
async function handleGetCustomerContext(input, dataDir = DATA_DIR$
|
|
1447
|
+
async function handleGetCustomerContext(input, dataDir = DATA_DIR$54) {
|
|
1447
1448
|
const targetSlug = input.slug ?? getSession()?.customerSlug;
|
|
1448
1449
|
if (!targetSlug) return {
|
|
1449
1450
|
content: [{
|
|
@@ -1579,8 +1580,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
|
|
|
1579
1580
|
}
|
|
1580
1581
|
//#endregion
|
|
1581
1582
|
//#region src/mcp/tools/search-customer-knowledge.ts
|
|
1582
|
-
const DATA_DIR$
|
|
1583
|
-
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$
|
|
1583
|
+
const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1584
|
+
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$53) {
|
|
1584
1585
|
const limit = input.limit ?? 5;
|
|
1585
1586
|
try {
|
|
1586
1587
|
const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
|
|
@@ -1628,14 +1629,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
|
|
|
1628
1629
|
}
|
|
1629
1630
|
//#endregion
|
|
1630
1631
|
//#region src/mcp/tools/list-customers.ts
|
|
1631
|
-
const DATA_DIR$
|
|
1632
|
+
const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1632
1633
|
function extractLastInteractionDate(interactionsPath) {
|
|
1633
1634
|
if (!fs.existsSync(interactionsPath)) return void 0;
|
|
1634
1635
|
const content = fs.readFileSync(interactionsPath, "utf-8");
|
|
1635
1636
|
const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
|
|
1636
1637
|
return match ? match[1] : void 0;
|
|
1637
1638
|
}
|
|
1638
|
-
async function handleListCustomers(input, dataDir = DATA_DIR$
|
|
1639
|
+
async function handleListCustomers(input, dataDir = DATA_DIR$52) {
|
|
1639
1640
|
const customersDir = path.join(dataDir, "customers");
|
|
1640
1641
|
const customers = [];
|
|
1641
1642
|
if (!fs.existsSync(customersDir)) return { content: [{
|
|
@@ -2148,8 +2149,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
|
|
|
2148
2149
|
}
|
|
2149
2150
|
//#endregion
|
|
2150
2151
|
//#region src/mcp/tools/log-interaction.ts
|
|
2151
|
-
const DATA_DIR$
|
|
2152
|
-
async function handleLogInteraction(input, dataDir = DATA_DIR$
|
|
2152
|
+
const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2153
|
+
async function handleLogInteraction(input, dataDir = DATA_DIR$51) {
|
|
2153
2154
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2154
2155
|
const interactionDate = input.date ?? today;
|
|
2155
2156
|
const sourceRef = input.source ?? `agent://log/${Date.now()}`;
|
|
@@ -2258,8 +2259,8 @@ var update_deal_exports = /* @__PURE__ */ __exportAll({
|
|
|
2258
2259
|
handleUpdateDeal: () => handleUpdateDeal,
|
|
2259
2260
|
registerUpdateDeal: () => registerUpdateDeal
|
|
2260
2261
|
});
|
|
2261
|
-
const DATA_DIR$
|
|
2262
|
-
async function handleUpdateDeal(input, dataDir = DATA_DIR$
|
|
2262
|
+
const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2263
|
+
async function handleUpdateDeal(input, dataDir = DATA_DIR$50) {
|
|
2263
2264
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2264
2265
|
const deal = {
|
|
2265
2266
|
name: input.dealName,
|
|
@@ -2342,12 +2343,12 @@ Returns: { success: boolean, deal: object }`,
|
|
|
2342
2343
|
}
|
|
2343
2344
|
//#endregion
|
|
2344
2345
|
//#region src/mcp/tools/export-customer.ts
|
|
2345
|
-
const DATA_DIR$
|
|
2346
|
+
const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2346
2347
|
function countInteractions(content) {
|
|
2347
2348
|
const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
2348
2349
|
return matches ? matches.length : 0;
|
|
2349
2350
|
}
|
|
2350
|
-
async function handleExportCustomer(input, dataDir = DATA_DIR$
|
|
2351
|
+
async function handleExportCustomer(input, dataDir = DATA_DIR$49) {
|
|
2351
2352
|
enforceRbac(dataDir, "export_customer");
|
|
2352
2353
|
const customerDir = path.join(dataDir, "customers", input.slug);
|
|
2353
2354
|
if (!fs.existsSync(customerDir)) return {
|
|
@@ -2460,8 +2461,8 @@ Returns:
|
|
|
2460
2461
|
}
|
|
2461
2462
|
//#endregion
|
|
2462
2463
|
//#region src/mcp/tools/update-customer-facts.ts
|
|
2463
|
-
const DATA_DIR$
|
|
2464
|
-
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$
|
|
2464
|
+
const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2465
|
+
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$48) {
|
|
2465
2466
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2466
2467
|
try {
|
|
2467
2468
|
enforceRbac(dataDir, "update_customer_facts");
|
|
@@ -2639,8 +2640,8 @@ function scoreDealForToday(deal, todayDate) {
|
|
|
2639
2640
|
}
|
|
2640
2641
|
//#endregion
|
|
2641
2642
|
//#region src/mcp/tools/get-deal-health.ts
|
|
2642
|
-
const DATA_DIR$
|
|
2643
|
-
async function handleGetDealHealth(input, dataDir = DATA_DIR$
|
|
2643
|
+
const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2644
|
+
async function handleGetDealHealth(input, dataDir = DATA_DIR$47) {
|
|
2644
2645
|
try {
|
|
2645
2646
|
const deals = await readPipeline(dataDir, input.slug);
|
|
2646
2647
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2689,8 +2690,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
|
|
|
2689
2690
|
}
|
|
2690
2691
|
//#endregion
|
|
2691
2692
|
//#region src/mcp/tools/get-pipeline-forecast.ts
|
|
2692
|
-
const DATA_DIR$
|
|
2693
|
-
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$
|
|
2693
|
+
const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2694
|
+
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$46) {
|
|
2694
2695
|
try {
|
|
2695
2696
|
const slugs = listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
|
|
2696
2697
|
const allDeals = [];
|
|
@@ -2751,8 +2752,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
|
|
|
2751
2752
|
}
|
|
2752
2753
|
//#endregion
|
|
2753
2754
|
//#region src/mcp/tools/summarize-meeting.ts
|
|
2754
|
-
const DATA_DIR$
|
|
2755
|
-
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$
|
|
2755
|
+
const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2756
|
+
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$45) {
|
|
2756
2757
|
try {
|
|
2757
2758
|
let summary = input.transcript.slice(0, 400);
|
|
2758
2759
|
let nextSteps = [];
|
|
@@ -2875,8 +2876,8 @@ function getPipelineStages(dataDir) {
|
|
|
2875
2876
|
}
|
|
2876
2877
|
//#endregion
|
|
2877
2878
|
//#region src/mcp/tools/get-pipeline-stages.ts
|
|
2878
|
-
const DATA_DIR$
|
|
2879
|
-
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$
|
|
2879
|
+
const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2880
|
+
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$44) {
|
|
2880
2881
|
const stages = getPipelineStages(dataDir);
|
|
2881
2882
|
return { content: [{
|
|
2882
2883
|
type: "text",
|
|
@@ -2904,8 +2905,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
|
|
|
2904
2905
|
}
|
|
2905
2906
|
//#endregion
|
|
2906
2907
|
//#region src/mcp/tools/get-market-intelligence.ts
|
|
2907
|
-
const DATA_DIR$
|
|
2908
|
-
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$
|
|
2908
|
+
const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2909
|
+
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$43) {
|
|
2909
2910
|
const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
|
|
2910
2911
|
const all = listCustomerSlugs(dataDir);
|
|
2911
2912
|
const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
|
|
@@ -2936,7 +2937,7 @@ function registerGetMarketIntelligence(server) {
|
|
|
2936
2937
|
}
|
|
2937
2938
|
//#endregion
|
|
2938
2939
|
//#region src/mcp/tools/get-relationship-graph.ts
|
|
2939
|
-
const DATA_DIR$
|
|
2940
|
+
const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2940
2941
|
function summarizeNode(n) {
|
|
2941
2942
|
return {
|
|
2942
2943
|
id: n.id,
|
|
@@ -2944,7 +2945,7 @@ function summarizeNode(n) {
|
|
|
2944
2945
|
email: n.properties["email"]
|
|
2945
2946
|
};
|
|
2946
2947
|
}
|
|
2947
|
-
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$
|
|
2948
|
+
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$42) {
|
|
2948
2949
|
try {
|
|
2949
2950
|
const graph = readGraph(dataDir, input.slug);
|
|
2950
2951
|
const stakeholders = getStakeholders(graph);
|
|
@@ -3012,9 +3013,9 @@ Returns: {
|
|
|
3012
3013
|
}
|
|
3013
3014
|
//#endregion
|
|
3014
3015
|
//#region src/mcp/tools/get-relationship-health.ts
|
|
3015
|
-
const DATA_DIR$
|
|
3016
|
+
const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3016
3017
|
const MAX_HEALTH_AGE_MS = 3600 * 1e3;
|
|
3017
|
-
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$
|
|
3018
|
+
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$41) {
|
|
3018
3019
|
try {
|
|
3019
3020
|
let health = readHealth(dataDir, input.slug);
|
|
3020
3021
|
if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
|
|
@@ -3683,8 +3684,8 @@ async function runDealAgent(config, dataDir, llmFn = callLlm) {
|
|
|
3683
3684
|
}
|
|
3684
3685
|
//#endregion
|
|
3685
3686
|
//#region src/mcp/tools/run-deal-agent.ts
|
|
3686
|
-
const DATA_DIR$
|
|
3687
|
-
async function handleRunDealAgent(input, dataDir = DATA_DIR$
|
|
3687
|
+
const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3688
|
+
async function handleRunDealAgent(input, dataDir = DATA_DIR$40) {
|
|
3688
3689
|
try {
|
|
3689
3690
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3690
3691
|
const result = await runDealAgent({
|
|
@@ -3751,8 +3752,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
|
|
|
3751
3752
|
}
|
|
3752
3753
|
//#endregion
|
|
3753
3754
|
//#region src/mcp/tools/approve-agent-action.ts
|
|
3754
|
-
const DATA_DIR$
|
|
3755
|
-
async function handleApproveAgentAction(input, dataDir = DATA_DIR$
|
|
3755
|
+
const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3756
|
+
async function handleApproveAgentAction(input, dataDir = DATA_DIR$39) {
|
|
3756
3757
|
try {
|
|
3757
3758
|
const queue = readAgentQueue(dataDir, input.slug);
|
|
3758
3759
|
const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
|
|
@@ -4012,8 +4013,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
|
|
|
4012
4013
|
}
|
|
4013
4014
|
//#endregion
|
|
4014
4015
|
//#region src/mcp/tools/simulate-revenue.ts
|
|
4015
|
-
const DATA_DIR$
|
|
4016
|
-
async function handleSimulateRevenue(input, dataDir = DATA_DIR$
|
|
4016
|
+
const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4017
|
+
async function handleSimulateRevenue(input, dataDir = DATA_DIR$38) {
|
|
4017
4018
|
try {
|
|
4018
4019
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4019
4020
|
const horizon = input.horizon ?? "quarter";
|
|
@@ -4071,8 +4072,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
|
|
|
4071
4072
|
}
|
|
4072
4073
|
//#endregion
|
|
4073
4074
|
//#region src/mcp/tools/get-playbook.ts
|
|
4074
|
-
const DATA_DIR$
|
|
4075
|
-
async function handleGetPlaybook(input, dataDir = DATA_DIR$
|
|
4075
|
+
const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4076
|
+
async function handleGetPlaybook(input, dataDir = DATA_DIR$37) {
|
|
4076
4077
|
try {
|
|
4077
4078
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4078
4079
|
if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
|
|
@@ -4157,12 +4158,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
|
|
|
4157
4158
|
...healthScore !== void 0 ? { healthScore } : {},
|
|
4158
4159
|
...daysSinceContact !== void 0 ? { daysSinceContact } : {},
|
|
4159
4160
|
...championPresent !== void 0 ? { championPresent } : {}
|
|
4160
|
-
}, DATA_DIR$
|
|
4161
|
+
}, DATA_DIR$37));
|
|
4161
4162
|
}
|
|
4162
4163
|
//#endregion
|
|
4163
4164
|
//#region src/mcp/tools/create-playbook.ts
|
|
4164
|
-
const DATA_DIR$
|
|
4165
|
-
async function handleCreatePlaybook(input, dataDir = DATA_DIR$
|
|
4165
|
+
const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4166
|
+
async function handleCreatePlaybook(input, dataDir = DATA_DIR$36) {
|
|
4166
4167
|
try {
|
|
4167
4168
|
const name = toKebabCase(input.name);
|
|
4168
4169
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -4235,12 +4236,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
|
|
|
4235
4236
|
trigger,
|
|
4236
4237
|
content,
|
|
4237
4238
|
...successRate !== void 0 ? { successRate } : {}
|
|
4238
|
-
}, DATA_DIR$
|
|
4239
|
+
}, DATA_DIR$36));
|
|
4239
4240
|
}
|
|
4240
4241
|
//#endregion
|
|
4241
4242
|
//#region src/mcp/tools/list-playbooks.ts
|
|
4242
|
-
const DATA_DIR$
|
|
4243
|
-
async function handleListPlaybooks(input, dataDir = DATA_DIR$
|
|
4243
|
+
const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4244
|
+
async function handleListPlaybooks(input, dataDir = DATA_DIR$35) {
|
|
4244
4245
|
try {
|
|
4245
4246
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4246
4247
|
return { content: [{
|
|
@@ -4279,12 +4280,12 @@ Args:
|
|
|
4279
4280
|
|
|
4280
4281
|
Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
|
|
4281
4282
|
inputSchema: z.object({ slug: z.string().describe("Customer ID") })
|
|
4282
|
-
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$
|
|
4283
|
+
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$35));
|
|
4283
4284
|
}
|
|
4284
4285
|
//#endregion
|
|
4285
4286
|
//#region src/mcp/tools/distill-playbook.ts
|
|
4286
|
-
const DATA_DIR$
|
|
4287
|
-
async function handleDistillPlaybook(input, dataDir = DATA_DIR$
|
|
4287
|
+
const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4288
|
+
async function handleDistillPlaybook(input, dataDir = DATA_DIR$34, llmFn = callLlm) {
|
|
4288
4289
|
try {
|
|
4289
4290
|
const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
|
|
4290
4291
|
if (!result.ok) {
|
|
@@ -4343,7 +4344,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
|
|
|
4343
4344
|
slug,
|
|
4344
4345
|
dealName,
|
|
4345
4346
|
outcome
|
|
4346
|
-
}, DATA_DIR$
|
|
4347
|
+
}, DATA_DIR$34));
|
|
4347
4348
|
}
|
|
4348
4349
|
//#endregion
|
|
4349
4350
|
//#region src/core/goal-engine.ts
|
|
@@ -4561,8 +4562,8 @@ function getActiveGoals(dataDir) {
|
|
|
4561
4562
|
}
|
|
4562
4563
|
//#endregion
|
|
4563
4564
|
//#region src/mcp/tools/pursue-goal.ts
|
|
4564
|
-
const DATA_DIR$
|
|
4565
|
-
async function handlePursueGoal(input, dataDir = DATA_DIR$
|
|
4565
|
+
const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4566
|
+
async function handlePursueGoal(input, dataDir = DATA_DIR$33, options = {}) {
|
|
4566
4567
|
try {
|
|
4567
4568
|
enforceRbac(dataDir, "pursue_goal");
|
|
4568
4569
|
const goal = await pursueGoal(dataDir, {
|
|
@@ -4625,12 +4626,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
|
|
|
4625
4626
|
goal,
|
|
4626
4627
|
deadline,
|
|
4627
4628
|
...context !== void 0 ? { context } : {}
|
|
4628
|
-
}, DATA_DIR$
|
|
4629
|
+
}, DATA_DIR$33));
|
|
4629
4630
|
}
|
|
4630
4631
|
//#endregion
|
|
4631
4632
|
//#region src/mcp/tools/get-goal-status.ts
|
|
4632
|
-
const DATA_DIR$
|
|
4633
|
-
async function handleGetGoalStatus(input, dataDir = DATA_DIR$
|
|
4633
|
+
const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4634
|
+
async function handleGetGoalStatus(input, dataDir = DATA_DIR$32) {
|
|
4634
4635
|
try {
|
|
4635
4636
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4636
4637
|
const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
|
|
@@ -4689,17 +4690,17 @@ Args:
|
|
|
4689
4690
|
|
|
4690
4691
|
Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
|
|
4691
4692
|
inputSchema: z.object({ goalId: z.string().optional().describe("Specific goal ID (omit for all active goals)") })
|
|
4692
|
-
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$
|
|
4693
|
+
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$32));
|
|
4693
4694
|
}
|
|
4694
4695
|
//#endregion
|
|
4695
4696
|
//#region src/mcp/tools/register-push-subscription.ts
|
|
4696
|
-
const DATA_DIR$
|
|
4697
|
+
const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4697
4698
|
const VALID_PROVIDERS = [
|
|
4698
4699
|
"gmail",
|
|
4699
4700
|
"microsoft-graph",
|
|
4700
4701
|
"slack"
|
|
4701
4702
|
];
|
|
4702
|
-
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$
|
|
4703
|
+
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$31) {
|
|
4703
4704
|
try {
|
|
4704
4705
|
if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
|
|
4705
4706
|
type: "text",
|
|
@@ -4785,12 +4786,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
|
|
|
4785
4786
|
...microsoftResource !== void 0 ? { microsoftResource } : {},
|
|
4786
4787
|
...slackTeamId !== void 0 ? { slackTeamId } : {},
|
|
4787
4788
|
...slackChannelId !== void 0 ? { slackChannelId } : {}
|
|
4788
|
-
}, DATA_DIR$
|
|
4789
|
+
}, DATA_DIR$31));
|
|
4789
4790
|
}
|
|
4790
4791
|
//#endregion
|
|
4791
4792
|
//#region src/mcp/tools/get-push-status.ts
|
|
4792
|
-
const DATA_DIR$
|
|
4793
|
-
async function handleGetPushStatus(input, dataDir = DATA_DIR$
|
|
4793
|
+
const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4794
|
+
async function handleGetPushStatus(input, dataDir = DATA_DIR$30) {
|
|
4794
4795
|
try {
|
|
4795
4796
|
let subs = await readSubscriptions(dataDir);
|
|
4796
4797
|
if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
|
|
@@ -4862,7 +4863,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
|
|
|
4862
4863
|
}, async ({ slug, provider }) => handleGetPushStatus({
|
|
4863
4864
|
...slug !== void 0 ? { slug } : {},
|
|
4864
4865
|
...provider !== void 0 ? { provider } : {}
|
|
4865
|
-
}, DATA_DIR$
|
|
4866
|
+
}, DATA_DIR$30));
|
|
4866
4867
|
}
|
|
4867
4868
|
//#endregion
|
|
4868
4869
|
//#region src/core/org-intelligence.ts
|
|
@@ -4928,8 +4929,8 @@ function deriveRecommendation(people, missingRoles) {
|
|
|
4928
4929
|
}
|
|
4929
4930
|
//#endregion
|
|
4930
4931
|
//#region src/mcp/tools/get-org-intelligence.ts
|
|
4931
|
-
const DATA_DIR$
|
|
4932
|
-
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$
|
|
4932
|
+
const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4933
|
+
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$29) {
|
|
4933
4934
|
try {
|
|
4934
4935
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4935
4936
|
const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
|
|
@@ -5062,8 +5063,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
|
|
|
5062
5063
|
}
|
|
5063
5064
|
//#endregion
|
|
5064
5065
|
//#region src/mcp/tools/open-deal-room.ts
|
|
5065
|
-
const DATA_DIR$
|
|
5066
|
-
async function handleOpenDealRoom(input, dataDir = DATA_DIR$
|
|
5066
|
+
const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5067
|
+
async function handleOpenDealRoom(input, dataDir = DATA_DIR$28) {
|
|
5067
5068
|
try {
|
|
5068
5069
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5069
5070
|
const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
|
|
@@ -5146,8 +5147,8 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
5146
5147
|
}
|
|
5147
5148
|
//#endregion
|
|
5148
5149
|
//#region src/mcp/tools/get-proactive-briefing.ts
|
|
5149
|
-
const DATA_DIR$
|
|
5150
|
-
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$
|
|
5150
|
+
const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5151
|
+
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$27) {
|
|
5151
5152
|
try {
|
|
5152
5153
|
const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
5153
5154
|
return { content: [{
|
|
@@ -5247,15 +5248,15 @@ function getTemplate(dataDir, id) {
|
|
|
5247
5248
|
}
|
|
5248
5249
|
//#endregion
|
|
5249
5250
|
//#region src/mcp/tools/list-email-templates.ts
|
|
5250
|
-
const DATA_DIR$
|
|
5251
|
-
async function handleListEmailTemplates(input, dataDir = DATA_DIR$
|
|
5251
|
+
const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5252
|
+
async function handleListEmailTemplates(input, dataDir = DATA_DIR$26) {
|
|
5252
5253
|
const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
|
|
5253
5254
|
return { content: [{
|
|
5254
5255
|
type: "text",
|
|
5255
5256
|
text: JSON.stringify(summary, null, 2)
|
|
5256
5257
|
}] };
|
|
5257
5258
|
}
|
|
5258
|
-
function registerListEmailTemplates(server, dataDir = DATA_DIR$
|
|
5259
|
+
function registerListEmailTemplates(server, dataDir = DATA_DIR$26) {
|
|
5259
5260
|
server.registerTool("list_email_templates", {
|
|
5260
5261
|
description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
|
|
5261
5262
|
inputSchema: z.object({ category: z.string().optional().describe("Filter by category") })
|
|
@@ -5289,8 +5290,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
|
|
|
5289
5290
|
}
|
|
5290
5291
|
//#endregion
|
|
5291
5292
|
//#region src/mcp/tools/get-email-template.ts
|
|
5292
|
-
const DATA_DIR$
|
|
5293
|
-
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$
|
|
5293
|
+
const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5294
|
+
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$25) {
|
|
5294
5295
|
const tmpl = getTemplate(dataDir, input.id);
|
|
5295
5296
|
if (!tmpl) return { content: [{
|
|
5296
5297
|
type: "text",
|
|
@@ -5306,7 +5307,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$24) {
|
|
|
5306
5307
|
}, null, 2)
|
|
5307
5308
|
}] };
|
|
5308
5309
|
}
|
|
5309
|
-
function registerGetEmailTemplate(server, dataDir = DATA_DIR$
|
|
5310
|
+
function registerGetEmailTemplate(server, dataDir = DATA_DIR$25) {
|
|
5310
5311
|
server.registerTool("get_email_template", {
|
|
5311
5312
|
description: "Get a specific email template by ID, including its body and detected variables.",
|
|
5312
5313
|
inputSchema: z.object({ id: z.string().describe("Template ID (e.g. 'enterprise-intro')") })
|
|
@@ -5314,8 +5315,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
|
|
|
5314
5315
|
}
|
|
5315
5316
|
//#endregion
|
|
5316
5317
|
//#region src/mcp/tools/draft-email.ts
|
|
5317
|
-
const DATA_DIR$
|
|
5318
|
-
async function handleDraftEmail(input, dataDir = DATA_DIR$
|
|
5318
|
+
const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5319
|
+
async function handleDraftEmail(input, dataDir = DATA_DIR$24) {
|
|
5319
5320
|
const tmpl = getTemplate(dataDir, input.templateId);
|
|
5320
5321
|
if (!tmpl) return { content: [{
|
|
5321
5322
|
type: "text",
|
|
@@ -5359,7 +5360,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$23) {
|
|
|
5359
5360
|
}, null, 2)
|
|
5360
5361
|
}] };
|
|
5361
5362
|
}
|
|
5362
|
-
function registerDraftEmail(server, dataDir = DATA_DIR$
|
|
5363
|
+
function registerDraftEmail(server, dataDir = DATA_DIR$24) {
|
|
5363
5364
|
server.registerTool("draft_email", {
|
|
5364
5365
|
description: `Draft a personalized email for a customer using a stored template.
|
|
5365
5366
|
Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
|
|
@@ -5467,8 +5468,8 @@ async function updateEnrollment(dataDir, id, updates) {
|
|
|
5467
5468
|
}
|
|
5468
5469
|
//#endregion
|
|
5469
5470
|
//#region src/mcp/tools/enroll-in-sequence.ts
|
|
5470
|
-
const DATA_DIR$
|
|
5471
|
-
async function handleEnrollInSequence(input, dataDir = DATA_DIR$
|
|
5471
|
+
const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5472
|
+
async function handleEnrollInSequence(input, dataDir = DATA_DIR$23) {
|
|
5472
5473
|
const sequence = getSequence(dataDir, input.sequenceId);
|
|
5473
5474
|
if (!sequence) return { content: [{
|
|
5474
5475
|
type: "text",
|
|
@@ -5500,7 +5501,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$22) {
|
|
|
5500
5501
|
})
|
|
5501
5502
|
}] };
|
|
5502
5503
|
}
|
|
5503
|
-
function registerEnrollInSequence(server, dataDir = DATA_DIR$
|
|
5504
|
+
function registerEnrollInSequence(server, dataDir = DATA_DIR$23) {
|
|
5504
5505
|
server.registerTool("enroll_in_sequence", {
|
|
5505
5506
|
description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
|
|
5506
5507
|
Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
@@ -5517,8 +5518,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
|
5517
5518
|
}
|
|
5518
5519
|
//#endregion
|
|
5519
5520
|
//#region src/mcp/tools/list-sequence-enrollments.ts
|
|
5520
|
-
const DATA_DIR$
|
|
5521
|
-
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$
|
|
5521
|
+
const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5522
|
+
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$22) {
|
|
5522
5523
|
let enrollments = readEnrollments(dataDir);
|
|
5523
5524
|
if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
|
|
5524
5525
|
if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
|
|
@@ -5527,7 +5528,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$21) {
|
|
|
5527
5528
|
text: JSON.stringify({ enrollments }, null, 2)
|
|
5528
5529
|
}] };
|
|
5529
5530
|
}
|
|
5530
|
-
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$
|
|
5531
|
+
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$22) {
|
|
5531
5532
|
server.registerTool("list_sequence_enrollments", {
|
|
5532
5533
|
description: `List email sequence enrollments. Filter by customer slug or status.
|
|
5533
5534
|
Returns: { enrollments: SequenceEnrollment[] }`,
|
|
@@ -5546,8 +5547,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
|
|
|
5546
5547
|
}
|
|
5547
5548
|
//#endregion
|
|
5548
5549
|
//#region src/mcp/tools/unenroll-from-sequence.ts
|
|
5549
|
-
const DATA_DIR$
|
|
5550
|
-
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$
|
|
5550
|
+
const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5551
|
+
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$21) {
|
|
5551
5552
|
if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
|
|
5552
5553
|
type: "text",
|
|
5553
5554
|
text: JSON.stringify({
|
|
@@ -5560,7 +5561,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$20) {
|
|
|
5560
5561
|
text: JSON.stringify({ success: true })
|
|
5561
5562
|
}] };
|
|
5562
5563
|
}
|
|
5563
|
-
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$
|
|
5564
|
+
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$21) {
|
|
5564
5565
|
server.registerTool("unenroll_from_sequence", {
|
|
5565
5566
|
description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
|
|
5566
5567
|
Returns: { success: boolean }`,
|
|
@@ -5569,8 +5570,8 @@ Returns: { success: boolean }`,
|
|
|
5569
5570
|
}
|
|
5570
5571
|
//#endregion
|
|
5571
5572
|
//#region src/mcp/tools/list-sequences.ts
|
|
5572
|
-
const DATA_DIR$
|
|
5573
|
-
async function handleListSequences(_input, dataDir = DATA_DIR$
|
|
5573
|
+
const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5574
|
+
async function handleListSequences(_input, dataDir = DATA_DIR$20) {
|
|
5574
5575
|
const sequences = listSequences(dataDir);
|
|
5575
5576
|
const enrollments = readEnrollments(dataDir);
|
|
5576
5577
|
const result = sequences.map((seq) => ({
|
|
@@ -5584,7 +5585,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$19) {
|
|
|
5584
5585
|
text: JSON.stringify({ sequences: result }, null, 2)
|
|
5585
5586
|
}] };
|
|
5586
5587
|
}
|
|
5587
|
-
function registerListSequences(server, dataDir = DATA_DIR$
|
|
5588
|
+
function registerListSequences(server, dataDir = DATA_DIR$20) {
|
|
5588
5589
|
server.registerTool("list_sequences", {
|
|
5589
5590
|
description: `List all email sequences with step count and enrollment count.
|
|
5590
5591
|
Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
|
|
@@ -5719,8 +5720,8 @@ async function generateQuote(dataDir, input) {
|
|
|
5719
5720
|
}
|
|
5720
5721
|
//#endregion
|
|
5721
5722
|
//#region src/mcp/tools/generate-quote.ts
|
|
5722
|
-
const DATA_DIR$
|
|
5723
|
-
async function handleGenerateQuote(input, dataDir = DATA_DIR$
|
|
5723
|
+
const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5724
|
+
async function handleGenerateQuote(input, dataDir = DATA_DIR$19) {
|
|
5724
5725
|
try {
|
|
5725
5726
|
const quote = await generateQuote(dataDir, input);
|
|
5726
5727
|
return { content: [{
|
|
@@ -5744,7 +5745,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$18) {
|
|
|
5744
5745
|
}] };
|
|
5745
5746
|
}
|
|
5746
5747
|
}
|
|
5747
|
-
function registerGenerateQuote(server, dataDir = DATA_DIR$
|
|
5748
|
+
function registerGenerateQuote(server, dataDir = DATA_DIR$19) {
|
|
5748
5749
|
server.registerTool("generate_quote", {
|
|
5749
5750
|
description: `Generate a professional HTML quote/offer for a customer deal.
|
|
5750
5751
|
Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
|
|
@@ -5772,8 +5773,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
|
|
|
5772
5773
|
}
|
|
5773
5774
|
//#endregion
|
|
5774
5775
|
//#region src/mcp/tools/get-quote-status.ts
|
|
5775
|
-
const DATA_DIR$
|
|
5776
|
-
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$
|
|
5776
|
+
const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5777
|
+
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$18) {
|
|
5777
5778
|
if (input.quoteNumber) {
|
|
5778
5779
|
const quote = readQuote(dataDir, input.quoteNumber);
|
|
5779
5780
|
if (!quote) return { content: [{
|
|
@@ -5791,7 +5792,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$17) {
|
|
|
5791
5792
|
text: JSON.stringify({ quotes }, null, 2)
|
|
5792
5793
|
}] };
|
|
5793
5794
|
}
|
|
5794
|
-
function registerGetQuoteStatus(server, dataDir = DATA_DIR$
|
|
5795
|
+
function registerGetQuoteStatus(server, dataDir = DATA_DIR$18) {
|
|
5795
5796
|
server.registerTool("get_quote_status", {
|
|
5796
5797
|
description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
|
|
5797
5798
|
Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
@@ -5806,7 +5807,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
|
5806
5807
|
}
|
|
5807
5808
|
//#endregion
|
|
5808
5809
|
//#region src/mcp/tools/get-booking-link.ts
|
|
5809
|
-
const DATA_DIR$
|
|
5810
|
+
const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5810
5811
|
function loadCalendlyConfig(dataDir) {
|
|
5811
5812
|
const p = path.join(dataDir, ".agentic", "integrations", "calendly.yaml");
|
|
5812
5813
|
if (!fs.existsSync(p)) return {};
|
|
@@ -5829,7 +5830,7 @@ function readCustomerFacts(dataDir, slug) {
|
|
|
5829
5830
|
...email ? { email } : {}
|
|
5830
5831
|
};
|
|
5831
5832
|
}
|
|
5832
|
-
async function handleGetBookingLink(input, dataDir = DATA_DIR$
|
|
5833
|
+
async function handleGetBookingLink(input, dataDir = DATA_DIR$17) {
|
|
5833
5834
|
const config = loadCalendlyConfig(dataDir);
|
|
5834
5835
|
const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
|
|
5835
5836
|
if (!apiKey) return { content: [{
|
|
@@ -5857,7 +5858,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
|
|
|
5857
5858
|
}] };
|
|
5858
5859
|
}
|
|
5859
5860
|
}
|
|
5860
|
-
function registerGetBookingLink(server, dataDir = DATA_DIR$
|
|
5861
|
+
function registerGetBookingLink(server, dataDir = DATA_DIR$17) {
|
|
5861
5862
|
server.registerTool("get_booking_link", {
|
|
5862
5863
|
description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
|
|
5863
5864
|
Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
|
|
@@ -6027,8 +6028,8 @@ function calcSlaDue(createdDate, priority, rules) {
|
|
|
6027
6028
|
}
|
|
6028
6029
|
//#endregion
|
|
6029
6030
|
//#region src/mcp/tools/create-ticket.ts
|
|
6030
|
-
const DATA_DIR$
|
|
6031
|
-
async function handleCreateTicket(input, dataDir = DATA_DIR$
|
|
6031
|
+
const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6032
|
+
async function handleCreateTicket(input, dataDir = DATA_DIR$16) {
|
|
6032
6033
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6033
6034
|
const rules = loadSlaRules(dataDir);
|
|
6034
6035
|
const priority = input.priority ?? "normal";
|
|
@@ -6050,7 +6051,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$15) {
|
|
|
6050
6051
|
text: JSON.stringify({ ticket }, null, 2)
|
|
6051
6052
|
}] };
|
|
6052
6053
|
}
|
|
6053
|
-
function registerCreateTicket(server, dataDir = DATA_DIR$
|
|
6054
|
+
function registerCreateTicket(server, dataDir = DATA_DIR$16) {
|
|
6054
6055
|
server.registerTool("create_ticket", {
|
|
6055
6056
|
description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
|
|
6056
6057
|
Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
@@ -6076,8 +6077,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
|
6076
6077
|
}
|
|
6077
6078
|
//#endregion
|
|
6078
6079
|
//#region src/mcp/tools/update-ticket.ts
|
|
6079
|
-
const DATA_DIR$
|
|
6080
|
-
async function handleUpdateTicket(input, dataDir = DATA_DIR$
|
|
6080
|
+
const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6081
|
+
async function handleUpdateTicket(input, dataDir = DATA_DIR$15) {
|
|
6081
6082
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6082
6083
|
if (!ticket) return { content: [{
|
|
6083
6084
|
type: "text",
|
|
@@ -6096,7 +6097,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$14) {
|
|
|
6096
6097
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6097
6098
|
}] };
|
|
6098
6099
|
}
|
|
6099
|
-
function registerUpdateTicket(server, dataDir = DATA_DIR$
|
|
6100
|
+
function registerUpdateTicket(server, dataDir = DATA_DIR$15) {
|
|
6100
6101
|
server.registerTool("update_ticket", {
|
|
6101
6102
|
description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
|
|
6102
6103
|
Returns: { ticket }`,
|
|
@@ -6121,8 +6122,8 @@ Returns: { ticket }`,
|
|
|
6121
6122
|
}
|
|
6122
6123
|
//#endregion
|
|
6123
6124
|
//#region src/mcp/tools/list-tickets.ts
|
|
6124
|
-
const DATA_DIR$
|
|
6125
|
-
async function handleListTickets(input, dataDir = DATA_DIR$
|
|
6125
|
+
const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6126
|
+
async function handleListTickets(input, dataDir = DATA_DIR$14) {
|
|
6126
6127
|
const results = await listAllTickets(dataDir, {
|
|
6127
6128
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
6128
6129
|
...input.status !== void 0 ? { status: input.status } : {},
|
|
@@ -6134,7 +6135,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$13) {
|
|
|
6134
6135
|
text: JSON.stringify({ tickets: results }, null, 2)
|
|
6135
6136
|
}] };
|
|
6136
6137
|
}
|
|
6137
|
-
function registerListTickets(server, dataDir = DATA_DIR$
|
|
6138
|
+
function registerListTickets(server, dataDir = DATA_DIR$14) {
|
|
6138
6139
|
server.registerTool("list_tickets", {
|
|
6139
6140
|
description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
|
|
6140
6141
|
Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
@@ -6164,8 +6165,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
|
6164
6165
|
}
|
|
6165
6166
|
//#endregion
|
|
6166
6167
|
//#region src/mcp/tools/close-ticket.ts
|
|
6167
|
-
const DATA_DIR$
|
|
6168
|
-
async function handleCloseTicket(input, dataDir = DATA_DIR$
|
|
6168
|
+
const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6169
|
+
async function handleCloseTicket(input, dataDir = DATA_DIR$13) {
|
|
6169
6170
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6170
6171
|
if (!ticket) return { content: [{
|
|
6171
6172
|
type: "text",
|
|
@@ -6192,7 +6193,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$12) {
|
|
|
6192
6193
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6193
6194
|
}] };
|
|
6194
6195
|
}
|
|
6195
|
-
function registerCloseTicket(server, dataDir = DATA_DIR$
|
|
6196
|
+
function registerCloseTicket(server, dataDir = DATA_DIR$13) {
|
|
6196
6197
|
server.registerTool("close_ticket", {
|
|
6197
6198
|
description: `Close a support ticket. Optionally logs the resolution as an interaction.
|
|
6198
6199
|
Returns: { ticket } with status=closed`,
|
|
@@ -6346,8 +6347,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
|
|
|
6346
6347
|
}
|
|
6347
6348
|
//#endregion
|
|
6348
6349
|
//#region src/mcp/tools/send-nps-survey.ts
|
|
6349
|
-
const DATA_DIR$
|
|
6350
|
-
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$
|
|
6350
|
+
const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6351
|
+
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$12) {
|
|
6351
6352
|
const survey = getSurvey(dataDir, input.surveyId);
|
|
6352
6353
|
if (!survey) return { content: [{
|
|
6353
6354
|
type: "text",
|
|
@@ -6368,7 +6369,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$11) {
|
|
|
6368
6369
|
}, null, 2)
|
|
6369
6370
|
}] };
|
|
6370
6371
|
}
|
|
6371
|
-
function registerSendNpsSurvey(server, dataDir = DATA_DIR$
|
|
6372
|
+
function registerSendNpsSurvey(server, dataDir = DATA_DIR$12) {
|
|
6372
6373
|
server.registerTool("send_nps_survey", {
|
|
6373
6374
|
description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
|
|
6374
6375
|
Does NOT send automatically — returns draft for review.
|
|
@@ -6388,8 +6389,8 @@ Returns: { token, subject, body, surveyUrl }`,
|
|
|
6388
6389
|
}
|
|
6389
6390
|
//#endregion
|
|
6390
6391
|
//#region src/mcp/tools/get-survey-results.ts
|
|
6391
|
-
const DATA_DIR$
|
|
6392
|
-
async function handleGetSurveyResults(input, dataDir = DATA_DIR$
|
|
6392
|
+
const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6393
|
+
async function handleGetSurveyResults(input, dataDir = DATA_DIR$11) {
|
|
6393
6394
|
const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
|
|
6394
6395
|
const nps = calcNpsScore(responses);
|
|
6395
6396
|
const promoters = responses.filter((r) => r.score >= 9).length;
|
|
@@ -6415,7 +6416,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$10) {
|
|
|
6415
6416
|
}, null, 2)
|
|
6416
6417
|
}] };
|
|
6417
6418
|
}
|
|
6418
|
-
function registerGetSurveyResults(server, dataDir = DATA_DIR$
|
|
6419
|
+
function registerGetSurveyResults(server, dataDir = DATA_DIR$11) {
|
|
6419
6420
|
server.registerTool("get_survey_results", {
|
|
6420
6421
|
description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
|
|
6421
6422
|
Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
|
|
@@ -6516,8 +6517,8 @@ function getKbMetaForExport(article) {
|
|
|
6516
6517
|
}
|
|
6517
6518
|
//#endregion
|
|
6518
6519
|
//#region src/mcp/tools/search-knowledge-base.ts
|
|
6519
|
-
const DATA_DIR$
|
|
6520
|
-
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$
|
|
6520
|
+
const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6521
|
+
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$10) {
|
|
6521
6522
|
const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
|
|
6522
6523
|
const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
|
|
6523
6524
|
return { content: [{
|
|
@@ -6532,7 +6533,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$9) {
|
|
|
6532
6533
|
}, null, 2)
|
|
6533
6534
|
}] };
|
|
6534
6535
|
}
|
|
6535
|
-
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$
|
|
6536
|
+
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$10) {
|
|
6536
6537
|
server.registerTool("search_knowledge_base", {
|
|
6537
6538
|
description: `Search the knowledge base for articles. Text search on title, body, and tags.
|
|
6538
6539
|
Returns: { count, articles[] } with excerpts`,
|
|
@@ -6551,8 +6552,8 @@ Returns: { count, articles[] } with excerpts`,
|
|
|
6551
6552
|
}
|
|
6552
6553
|
//#endregion
|
|
6553
6554
|
//#region src/mcp/tools/create-kb-article.ts
|
|
6554
|
-
const DATA_DIR$
|
|
6555
|
-
async function handleCreateKbArticle(input, dataDir = DATA_DIR$
|
|
6555
|
+
const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6556
|
+
async function handleCreateKbArticle(input, dataDir = DATA_DIR$9) {
|
|
6556
6557
|
if (getKbArticle(dataDir, input.id)) return { content: [{
|
|
6557
6558
|
type: "text",
|
|
6558
6559
|
text: JSON.stringify({ error: `Article '${input.id}' already exists` })
|
|
@@ -6580,7 +6581,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$8) {
|
|
|
6580
6581
|
}, null, 2)
|
|
6581
6582
|
}] };
|
|
6582
6583
|
}
|
|
6583
|
-
function registerCreateKbArticle(server, dataDir = DATA_DIR$
|
|
6584
|
+
function registerCreateKbArticle(server, dataDir = DATA_DIR$9) {
|
|
6584
6585
|
server.registerTool("create_kb_article", {
|
|
6585
6586
|
description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
|
|
6586
6587
|
Returns: { id, title, category, path }`,
|
|
@@ -6605,8 +6606,8 @@ Returns: { id, title, category, path }`,
|
|
|
6605
6606
|
}
|
|
6606
6607
|
//#endregion
|
|
6607
6608
|
//#region src/mcp/tools/backup-now.ts
|
|
6608
|
-
const DATA_DIR$
|
|
6609
|
-
async function handleBackupNow(input, dataDir = DATA_DIR$
|
|
6609
|
+
const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6610
|
+
async function handleBackupNow(input, dataDir = DATA_DIR$8) {
|
|
6610
6611
|
const zipPath = path.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
|
|
6611
6612
|
const manifest = await runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
|
|
6612
6613
|
if (!manifest) return { content: [{
|
|
@@ -6643,8 +6644,8 @@ function registerBackupNow(server) {
|
|
|
6643
6644
|
}
|
|
6644
6645
|
//#endregion
|
|
6645
6646
|
//#region src/mcp/tools/list-backups.ts
|
|
6646
|
-
const DATA_DIR$
|
|
6647
|
-
async function handleListBackups(input, dataDir = DATA_DIR$
|
|
6647
|
+
const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6648
|
+
async function handleListBackups(input, dataDir = DATA_DIR$7) {
|
|
6648
6649
|
const logEntries = readBackupLog(dataDir);
|
|
6649
6650
|
const fileEntries = listBackupsInDir(dataDir);
|
|
6650
6651
|
const entries = logEntries.length > 0 ? logEntries : fileEntries;
|
|
@@ -6678,8 +6679,8 @@ function registerListBackups(server) {
|
|
|
6678
6679
|
}
|
|
6679
6680
|
//#endregion
|
|
6680
6681
|
//#region src/mcp/tools/trigger-sync.ts
|
|
6681
|
-
const DATA_DIR$
|
|
6682
|
-
async function handleTriggerSync(input, dataDir = DATA_DIR$
|
|
6682
|
+
const DATA_DIR$6 = process.cwd();
|
|
6683
|
+
async function handleTriggerSync(input, dataDir = DATA_DIR$6) {
|
|
6683
6684
|
const auth = getGmailAuth();
|
|
6684
6685
|
if (!auth) return { content: [{
|
|
6685
6686
|
type: "text",
|
|
@@ -6773,8 +6774,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
|
|
|
6773
6774
|
}
|
|
6774
6775
|
//#endregion
|
|
6775
6776
|
//#region src/mcp/tools/get-audit-log.ts
|
|
6776
|
-
const DATA_DIR$
|
|
6777
|
-
async function handleGetAuditLog(input, dataDir = DATA_DIR$
|
|
6777
|
+
const DATA_DIR$5 = process.cwd();
|
|
6778
|
+
async function handleGetAuditLog(input, dataDir = DATA_DIR$5) {
|
|
6778
6779
|
const entries = readAuditLog(dataDir);
|
|
6779
6780
|
const filterOpts = { limit: input.limit ?? 50 };
|
|
6780
6781
|
if (input.slug !== void 0) filterOpts.slug = input.slug;
|
|
@@ -6816,8 +6817,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
|
|
|
6816
6817
|
}
|
|
6817
6818
|
//#endregion
|
|
6818
6819
|
//#region src/mcp/tools/get-logs.ts
|
|
6819
|
-
const DATA_DIR$
|
|
6820
|
-
async function handleGetLogs(input, dataDir = DATA_DIR$
|
|
6820
|
+
const DATA_DIR$4 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6821
|
+
async function handleGetLogs(input, dataDir = DATA_DIR$4) {
|
|
6821
6822
|
const query = {
|
|
6822
6823
|
...input.level !== void 0 ? { level: input.level } : {},
|
|
6823
6824
|
...input.component !== void 0 ? { component: input.component } : {},
|
|
@@ -6979,8 +6980,8 @@ async function runDiagnostics(dataDir) {
|
|
|
6979
6980
|
}
|
|
6980
6981
|
//#endregion
|
|
6981
6982
|
//#region src/mcp/tools/get-diagnostics.ts
|
|
6982
|
-
const DATA_DIR$
|
|
6983
|
-
async function handleGetDiagnostics(input, dataDir = DATA_DIR$
|
|
6983
|
+
const DATA_DIR$3 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6984
|
+
async function handleGetDiagnostics(input, dataDir = DATA_DIR$3) {
|
|
6984
6985
|
let cleaned = 0;
|
|
6985
6986
|
if (input.fix) {
|
|
6986
6987
|
const { cleanupTempFiles } = await Promise.resolve().then(() => doctor_exports);
|
|
@@ -7012,6 +7013,163 @@ Returns: { ok: boolean, tempFilesRemoved?: number, checks: [{ name, status: "ok"
|
|
|
7012
7013
|
}, async ({ fix }) => handleGetDiagnostics(fix !== void 0 ? { fix } : {}));
|
|
7013
7014
|
}
|
|
7014
7015
|
//#endregion
|
|
7016
|
+
//#region src/core/snapshots.ts
|
|
7017
|
+
function snapshotsDir(dataDir) {
|
|
7018
|
+
return path.join(dataDir, ".agentic", "snapshots");
|
|
7019
|
+
}
|
|
7020
|
+
function snapshotPath(dataDir, id) {
|
|
7021
|
+
return path.join(snapshotsDir(dataDir), `${id}.json`);
|
|
7022
|
+
}
|
|
7023
|
+
function dealKey(d) {
|
|
7024
|
+
return `${d.slug}::${d.name}`;
|
|
7025
|
+
}
|
|
7026
|
+
function isOpen(stage) {
|
|
7027
|
+
return stage !== "won" && stage !== "lost";
|
|
7028
|
+
}
|
|
7029
|
+
function openValue(deals) {
|
|
7030
|
+
return deals.filter((d) => isOpen(d.stage)).reduce((sum, d) => sum + d.value, 0);
|
|
7031
|
+
}
|
|
7032
|
+
/** Build a live snapshot of the current pipeline across all customers. */
|
|
7033
|
+
function collectDeals(dataDir) {
|
|
7034
|
+
const deals = [];
|
|
7035
|
+
for (const slug of listCustomerSlugs(dataDir)) for (const d of readPipelineSync(dataDir, slug)) deals.push({
|
|
7036
|
+
slug,
|
|
7037
|
+
name: d.name,
|
|
7038
|
+
stage: d.stage,
|
|
7039
|
+
value: d.value ?? 0,
|
|
7040
|
+
probability: d.probability ?? 0
|
|
7041
|
+
});
|
|
7042
|
+
return deals;
|
|
7043
|
+
}
|
|
7044
|
+
function snapshotIds(dataDir) {
|
|
7045
|
+
const dir = snapshotsDir(dataDir);
|
|
7046
|
+
if (!fs.existsSync(dir)) return [];
|
|
7047
|
+
return fs.readdirSync(dir).filter((f) => /^\d{4}-\d{2}-\d{2}\.json$/.test(f)).map((f) => f.replace(/\.json$/, "")).sort();
|
|
7048
|
+
}
|
|
7049
|
+
function loadSnapshot(dataDir, id) {
|
|
7050
|
+
return readJsonFile(snapshotPath(dataDir, id), null);
|
|
7051
|
+
}
|
|
7052
|
+
/** The most recent snapshot whose id is at or before `iso` (YYYY-MM-DD). */
|
|
7053
|
+
function latestSnapshotAtOrBefore(dataDir, iso) {
|
|
7054
|
+
const id = snapshotIds(dataDir).filter((s) => s <= iso).pop();
|
|
7055
|
+
return id ? loadSnapshot(dataDir, id) : null;
|
|
7056
|
+
}
|
|
7057
|
+
/** Compute what changed between two snapshots (before → after). */
|
|
7058
|
+
function diffSnapshots(before, after) {
|
|
7059
|
+
const beforeByKey = new Map(before.deals.map((d) => [dealKey(d), d]));
|
|
7060
|
+
const afterByKey = new Map(after.deals.map((d) => [dealKey(d), d]));
|
|
7061
|
+
const added = [];
|
|
7062
|
+
const removed = [];
|
|
7063
|
+
const advanced = [];
|
|
7064
|
+
const won = [];
|
|
7065
|
+
const lost = [];
|
|
7066
|
+
const valueChanged = [];
|
|
7067
|
+
for (const [key, a] of afterByKey) {
|
|
7068
|
+
const b = beforeByKey.get(key);
|
|
7069
|
+
if (!b) {
|
|
7070
|
+
added.push({
|
|
7071
|
+
slug: a.slug,
|
|
7072
|
+
name: a.name
|
|
7073
|
+
});
|
|
7074
|
+
continue;
|
|
7075
|
+
}
|
|
7076
|
+
if (b.stage !== a.stage) {
|
|
7077
|
+
advanced.push({
|
|
7078
|
+
slug: a.slug,
|
|
7079
|
+
name: a.name,
|
|
7080
|
+
from: b.stage,
|
|
7081
|
+
to: a.stage
|
|
7082
|
+
});
|
|
7083
|
+
if (a.stage === "won") won.push({
|
|
7084
|
+
slug: a.slug,
|
|
7085
|
+
name: a.name
|
|
7086
|
+
});
|
|
7087
|
+
if (a.stage === "lost") lost.push({
|
|
7088
|
+
slug: a.slug,
|
|
7089
|
+
name: a.name
|
|
7090
|
+
});
|
|
7091
|
+
}
|
|
7092
|
+
if (b.value !== a.value) valueChanged.push({
|
|
7093
|
+
slug: a.slug,
|
|
7094
|
+
name: a.name,
|
|
7095
|
+
from: b.value,
|
|
7096
|
+
to: a.value
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
7099
|
+
for (const [key, b] of beforeByKey) if (!afterByKey.has(key)) removed.push({
|
|
7100
|
+
slug: b.slug,
|
|
7101
|
+
name: b.name
|
|
7102
|
+
});
|
|
7103
|
+
const openValueBefore = openValue(before.deals);
|
|
7104
|
+
const openValueAfter = openValue(after.deals);
|
|
7105
|
+
return {
|
|
7106
|
+
fromId: before.id,
|
|
7107
|
+
toId: after.id,
|
|
7108
|
+
added,
|
|
7109
|
+
removed,
|
|
7110
|
+
advanced,
|
|
7111
|
+
won,
|
|
7112
|
+
lost,
|
|
7113
|
+
valueChanged,
|
|
7114
|
+
openValueBefore,
|
|
7115
|
+
openValueAfter,
|
|
7116
|
+
openValueDelta: openValueAfter - openValueBefore
|
|
7117
|
+
};
|
|
7118
|
+
}
|
|
7119
|
+
/**
|
|
7120
|
+
* Diff the live pipeline against the latest snapshot at/before `since`.
|
|
7121
|
+
* Returns null when no baseline snapshot exists yet.
|
|
7122
|
+
*/
|
|
7123
|
+
function diffAgainstNow(dataDir, since, today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)) {
|
|
7124
|
+
const baseline = latestSnapshotAtOrBefore(dataDir, since);
|
|
7125
|
+
if (!baseline) return null;
|
|
7126
|
+
return diffSnapshots(baseline, {
|
|
7127
|
+
id: today,
|
|
7128
|
+
takenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7129
|
+
deals: collectDeals(dataDir)
|
|
7130
|
+
});
|
|
7131
|
+
}
|
|
7132
|
+
//#endregion
|
|
7133
|
+
//#region src/mcp/tools/get-pipeline-changes.ts
|
|
7134
|
+
const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
7135
|
+
function daysAgoIso(days) {
|
|
7136
|
+
return (/* @__PURE__ */ new Date(Date.now() - days * 864e5)).toISOString().slice(0, 10);
|
|
7137
|
+
}
|
|
7138
|
+
async function handleGetPipelineChanges(input, dataDir = DATA_DIR$2) {
|
|
7139
|
+
const since = input.since ?? daysAgoIso(input.days ?? 7);
|
|
7140
|
+
const diff = diffAgainstNow(dataDir, since);
|
|
7141
|
+
const payload = diff ? diff : { error: `No pipeline snapshot at or before ${since}. Snapshots accrue daily via the daemon.` };
|
|
7142
|
+
return { content: [{
|
|
7143
|
+
type: "text",
|
|
7144
|
+
text: JSON.stringify(payload, null, 2)
|
|
7145
|
+
}] };
|
|
7146
|
+
}
|
|
7147
|
+
function registerGetPipelineChanges(server) {
|
|
7148
|
+
server.registerTool("get_pipeline_changes", {
|
|
7149
|
+
title: "Get Pipeline Changes",
|
|
7150
|
+
description: `Pipeline time-travel: what changed in the pipeline since a baseline date.
|
|
7151
|
+
Compares the live pipeline against the most recent daily snapshot at/before the
|
|
7152
|
+
baseline. Answers "what moved since last week?", "what did we win/lose?".
|
|
7153
|
+
|
|
7154
|
+
Args:
|
|
7155
|
+
since: Baseline date YYYY-MM-DD (optional)
|
|
7156
|
+
days: Look back this many days instead of a date (default 7)
|
|
7157
|
+
|
|
7158
|
+
Returns: { fromId, toId, added[], removed[], advanced[{from,to}], won[], lost[],
|
|
7159
|
+
valueChanged[{from,to}], openValueBefore, openValueAfter, openValueDelta }
|
|
7160
|
+
or { error } when no baseline snapshot exists yet.`,
|
|
7161
|
+
inputSchema: z.object({
|
|
7162
|
+
since: z.string().optional().describe("Baseline date YYYY-MM-DD"),
|
|
7163
|
+
days: z.number().int().min(1).max(365).optional().describe("Look-back window in days (default 7)")
|
|
7164
|
+
})
|
|
7165
|
+
}, async ({ since, days }) => {
|
|
7166
|
+
const input = {};
|
|
7167
|
+
if (since !== void 0) input.since = since;
|
|
7168
|
+
if (days !== void 0) input.days = days;
|
|
7169
|
+
return handleGetPipelineChanges(input);
|
|
7170
|
+
});
|
|
7171
|
+
}
|
|
7172
|
+
//#endregion
|
|
7015
7173
|
//#region src/mcp/prompts.ts
|
|
7016
7174
|
/**
|
|
7017
7175
|
* CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
|
|
@@ -7429,6 +7587,7 @@ function createMcpServer() {
|
|
|
7429
7587
|
registerGetAuditLog(server);
|
|
7430
7588
|
registerGetLogs(server);
|
|
7431
7589
|
registerGetDiagnostics(server);
|
|
7590
|
+
registerGetPipelineChanges(server);
|
|
7432
7591
|
registerCustomObjectTools(server);
|
|
7433
7592
|
registerPrompts(server);
|
|
7434
7593
|
registerResources(server);
|