@datasynx/agentic-crm 1.5.0 → 1.7.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 +70 -76
- package/dist/cli.js.map +1 -1
- package/dist/daemon/worker.js +40 -1
- package/dist/daemon/worker.js.map +1 -1
- package/dist/{imap-o6PRuBvm.js → imap-BRgNh3T3.js} +2 -2
- package/dist/{imap-o6PRuBvm.js.map → imap-BRgNh3T3.js.map} +1 -1
- package/dist/imap-DzeqMdZ3.js +2 -0
- 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-DcDaz_cu.d.cts} +16 -16
- package/dist/index-DcDaz_cu.d.cts.map +1 -0
- package/dist/index.d.cts +16 -16
- 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/{login-CYgla6-A.js → login-yt9OOQQk.js} +3 -2
- package/dist/{login-CYgla6-A.js.map → login-yt9OOQQk.js.map} +1 -1
- package/dist/mailbox-config-Bu-J1O4I.js +2 -0
- package/dist/mailbox-config-Dn2xTn9N.js +67 -0
- package/dist/mailbox-config-Dn2xTn9N.js.map +1 -0
- package/dist/mailbox-poll-B8dvFAXT.js +80 -0
- package/dist/mailbox-poll-B8dvFAXT.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/{microsoft-DgbVlHdT.js → microsoft-dsC1fQQG.js} +2 -38
- package/dist/microsoft-dsC1fQQG.js.map +1 -0
- 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/dist/{token-resolver-BRLOmRvF.js → token-resolver-D98qPOOf.js} +3 -2
- package/dist/{token-resolver-BRLOmRvF.js.map → token-resolver-D98qPOOf.js.map} +1 -1
- package/dist/token-store-B0h0USqe.js +43 -0
- package/dist/token-store-B0h0USqe.js.map +1 -0
- package/dist/token-store-CEmz8d-0.js +2 -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/microsoft-DgbVlHdT.js.map +0 -1
- package/dist/server-uqXUhF4H.js.map +0 -1
package/dist/mcp.cjs
CHANGED
|
@@ -451,6 +451,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
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
453
|
| get_diagnostics | Self-diagnostic health check (data integrity, temp files, log errors, backups) | admin |
|
|
454
|
+
| get_pipeline_changes | Pipeline time-travel: what changed (won/lost/moved/value) since a date | any |
|
|
454
455
|
| define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
|
|
455
456
|
| create_record | Create a record of a custom object (validated against its schema) | rep+ |
|
|
456
457
|
| list_records | List records of a custom object | any |
|
|
@@ -1429,7 +1430,7 @@ async function buildContext(dataDir, slug) {
|
|
|
1429
1430
|
}
|
|
1430
1431
|
//#endregion
|
|
1431
1432
|
//#region src/mcp/tools/get-customer-context.ts
|
|
1432
|
-
const DATA_DIR$
|
|
1433
|
+
const DATA_DIR$54 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1433
1434
|
function triggerOnQuerySync(dataDir, slug) {
|
|
1434
1435
|
const auth = getGmailAuth();
|
|
1435
1436
|
if (!auth) return;
|
|
@@ -1450,7 +1451,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1450
1451
|
}).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
|
|
1451
1452
|
} catch {}
|
|
1452
1453
|
}
|
|
1453
|
-
async function handleGetCustomerContext(input, dataDir = DATA_DIR$
|
|
1454
|
+
async function handleGetCustomerContext(input, dataDir = DATA_DIR$54) {
|
|
1454
1455
|
const targetSlug = input.slug ?? require_session_store.getSession()?.customerSlug;
|
|
1455
1456
|
if (!targetSlug) return {
|
|
1456
1457
|
content: [{
|
|
@@ -1586,8 +1587,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
|
|
|
1586
1587
|
}
|
|
1587
1588
|
//#endregion
|
|
1588
1589
|
//#region src/mcp/tools/search-customer-knowledge.ts
|
|
1589
|
-
const DATA_DIR$
|
|
1590
|
-
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$
|
|
1590
|
+
const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1591
|
+
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$53) {
|
|
1591
1592
|
const limit = input.limit ?? 5;
|
|
1592
1593
|
try {
|
|
1593
1594
|
const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
|
|
@@ -1635,14 +1636,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
|
|
|
1635
1636
|
}
|
|
1636
1637
|
//#endregion
|
|
1637
1638
|
//#region src/mcp/tools/list-customers.ts
|
|
1638
|
-
const DATA_DIR$
|
|
1639
|
+
const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1639
1640
|
function extractLastInteractionDate(interactionsPath) {
|
|
1640
1641
|
if (!fs.default.existsSync(interactionsPath)) return void 0;
|
|
1641
1642
|
const content = fs.default.readFileSync(interactionsPath, "utf-8");
|
|
1642
1643
|
const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
|
|
1643
1644
|
return match ? match[1] : void 0;
|
|
1644
1645
|
}
|
|
1645
|
-
async function handleListCustomers(input, dataDir = DATA_DIR$
|
|
1646
|
+
async function handleListCustomers(input, dataDir = DATA_DIR$52) {
|
|
1646
1647
|
const customersDir = path.default.join(dataDir, "customers");
|
|
1647
1648
|
const customers = [];
|
|
1648
1649
|
if (!fs.default.existsSync(customersDir)) return { content: [{
|
|
@@ -2155,8 +2156,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
|
|
|
2155
2156
|
}
|
|
2156
2157
|
//#endregion
|
|
2157
2158
|
//#region src/mcp/tools/log-interaction.ts
|
|
2158
|
-
const DATA_DIR$
|
|
2159
|
-
async function handleLogInteraction(input, dataDir = DATA_DIR$
|
|
2159
|
+
const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2160
|
+
async function handleLogInteraction(input, dataDir = DATA_DIR$51) {
|
|
2160
2161
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2161
2162
|
const interactionDate = input.date ?? today;
|
|
2162
2163
|
const sourceRef = input.source ?? `agent://log/${Date.now()}`;
|
|
@@ -2265,8 +2266,8 @@ var update_deal_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
|
2265
2266
|
handleUpdateDeal: () => handleUpdateDeal,
|
|
2266
2267
|
registerUpdateDeal: () => registerUpdateDeal
|
|
2267
2268
|
});
|
|
2268
|
-
const DATA_DIR$
|
|
2269
|
-
async function handleUpdateDeal(input, dataDir = DATA_DIR$
|
|
2269
|
+
const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2270
|
+
async function handleUpdateDeal(input, dataDir = DATA_DIR$50) {
|
|
2270
2271
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2271
2272
|
const deal = {
|
|
2272
2273
|
name: input.dealName,
|
|
@@ -2349,12 +2350,12 @@ Returns: { success: boolean, deal: object }`,
|
|
|
2349
2350
|
}
|
|
2350
2351
|
//#endregion
|
|
2351
2352
|
//#region src/mcp/tools/export-customer.ts
|
|
2352
|
-
const DATA_DIR$
|
|
2353
|
+
const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2353
2354
|
function countInteractions(content) {
|
|
2354
2355
|
const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
2355
2356
|
return matches ? matches.length : 0;
|
|
2356
2357
|
}
|
|
2357
|
-
async function handleExportCustomer(input, dataDir = DATA_DIR$
|
|
2358
|
+
async function handleExportCustomer(input, dataDir = DATA_DIR$49) {
|
|
2358
2359
|
require_session_store.enforceRbac(dataDir, "export_customer");
|
|
2359
2360
|
const customerDir = path.default.join(dataDir, "customers", input.slug);
|
|
2360
2361
|
if (!fs.default.existsSync(customerDir)) return {
|
|
@@ -2467,8 +2468,8 @@ Returns:
|
|
|
2467
2468
|
}
|
|
2468
2469
|
//#endregion
|
|
2469
2470
|
//#region src/mcp/tools/update-customer-facts.ts
|
|
2470
|
-
const DATA_DIR$
|
|
2471
|
-
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$
|
|
2471
|
+
const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2472
|
+
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$48) {
|
|
2472
2473
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2473
2474
|
try {
|
|
2474
2475
|
require_session_store.enforceRbac(dataDir, "update_customer_facts");
|
|
@@ -2646,8 +2647,8 @@ function scoreDealForToday(deal, todayDate) {
|
|
|
2646
2647
|
}
|
|
2647
2648
|
//#endregion
|
|
2648
2649
|
//#region src/mcp/tools/get-deal-health.ts
|
|
2649
|
-
const DATA_DIR$
|
|
2650
|
-
async function handleGetDealHealth(input, dataDir = DATA_DIR$
|
|
2650
|
+
const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2651
|
+
async function handleGetDealHealth(input, dataDir = DATA_DIR$47) {
|
|
2651
2652
|
try {
|
|
2652
2653
|
const deals = await require_pipeline_writer.readPipeline(dataDir, input.slug);
|
|
2653
2654
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2696,8 +2697,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
|
|
|
2696
2697
|
}
|
|
2697
2698
|
//#endregion
|
|
2698
2699
|
//#region src/mcp/tools/get-pipeline-forecast.ts
|
|
2699
|
-
const DATA_DIR$
|
|
2700
|
-
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$
|
|
2700
|
+
const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2701
|
+
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$46) {
|
|
2701
2702
|
try {
|
|
2702
2703
|
const slugs = require_session_store.listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
|
|
2703
2704
|
const allDeals = [];
|
|
@@ -2758,8 +2759,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
|
|
|
2758
2759
|
}
|
|
2759
2760
|
//#endregion
|
|
2760
2761
|
//#region src/mcp/tools/summarize-meeting.ts
|
|
2761
|
-
const DATA_DIR$
|
|
2762
|
-
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$
|
|
2762
|
+
const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2763
|
+
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$45) {
|
|
2763
2764
|
try {
|
|
2764
2765
|
let summary = input.transcript.slice(0, 400);
|
|
2765
2766
|
let nextSteps = [];
|
|
@@ -2882,8 +2883,8 @@ function getPipelineStages(dataDir) {
|
|
|
2882
2883
|
}
|
|
2883
2884
|
//#endregion
|
|
2884
2885
|
//#region src/mcp/tools/get-pipeline-stages.ts
|
|
2885
|
-
const DATA_DIR$
|
|
2886
|
-
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$
|
|
2886
|
+
const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2887
|
+
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$44) {
|
|
2887
2888
|
const stages = getPipelineStages(dataDir);
|
|
2888
2889
|
return { content: [{
|
|
2889
2890
|
type: "text",
|
|
@@ -2911,8 +2912,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
|
|
|
2911
2912
|
}
|
|
2912
2913
|
//#endregion
|
|
2913
2914
|
//#region src/mcp/tools/get-market-intelligence.ts
|
|
2914
|
-
const DATA_DIR$
|
|
2915
|
-
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$
|
|
2915
|
+
const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2916
|
+
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$43) {
|
|
2916
2917
|
const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
|
|
2917
2918
|
const all = require_session_store.listCustomerSlugs(dataDir);
|
|
2918
2919
|
const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
|
|
@@ -2943,7 +2944,7 @@ function registerGetMarketIntelligence(server) {
|
|
|
2943
2944
|
}
|
|
2944
2945
|
//#endregion
|
|
2945
2946
|
//#region src/mcp/tools/get-relationship-graph.ts
|
|
2946
|
-
const DATA_DIR$
|
|
2947
|
+
const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2947
2948
|
function summarizeNode(n) {
|
|
2948
2949
|
return {
|
|
2949
2950
|
id: n.id,
|
|
@@ -2951,7 +2952,7 @@ function summarizeNode(n) {
|
|
|
2951
2952
|
email: n.properties["email"]
|
|
2952
2953
|
};
|
|
2953
2954
|
}
|
|
2954
|
-
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$
|
|
2955
|
+
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$42) {
|
|
2955
2956
|
try {
|
|
2956
2957
|
const graph = readGraph(dataDir, input.slug);
|
|
2957
2958
|
const stakeholders = getStakeholders(graph);
|
|
@@ -3019,9 +3020,9 @@ Returns: {
|
|
|
3019
3020
|
}
|
|
3020
3021
|
//#endregion
|
|
3021
3022
|
//#region src/mcp/tools/get-relationship-health.ts
|
|
3022
|
-
const DATA_DIR$
|
|
3023
|
+
const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3023
3024
|
const MAX_HEALTH_AGE_MS = 3600 * 1e3;
|
|
3024
|
-
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$
|
|
3025
|
+
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$41) {
|
|
3025
3026
|
try {
|
|
3026
3027
|
let health = readHealth(dataDir, input.slug);
|
|
3027
3028
|
if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
|
|
@@ -3690,8 +3691,8 @@ async function runDealAgent(config, dataDir, llmFn = require_llm.callLlm) {
|
|
|
3690
3691
|
}
|
|
3691
3692
|
//#endregion
|
|
3692
3693
|
//#region src/mcp/tools/run-deal-agent.ts
|
|
3693
|
-
const DATA_DIR$
|
|
3694
|
-
async function handleRunDealAgent(input, dataDir = DATA_DIR$
|
|
3694
|
+
const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3695
|
+
async function handleRunDealAgent(input, dataDir = DATA_DIR$40) {
|
|
3695
3696
|
try {
|
|
3696
3697
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3697
3698
|
const result = await runDealAgent({
|
|
@@ -3758,8 +3759,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
|
|
|
3758
3759
|
}
|
|
3759
3760
|
//#endregion
|
|
3760
3761
|
//#region src/mcp/tools/approve-agent-action.ts
|
|
3761
|
-
const DATA_DIR$
|
|
3762
|
-
async function handleApproveAgentAction(input, dataDir = DATA_DIR$
|
|
3762
|
+
const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3763
|
+
async function handleApproveAgentAction(input, dataDir = DATA_DIR$39) {
|
|
3763
3764
|
try {
|
|
3764
3765
|
const queue = readAgentQueue(dataDir, input.slug);
|
|
3765
3766
|
const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
|
|
@@ -4019,8 +4020,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
|
|
|
4019
4020
|
}
|
|
4020
4021
|
//#endregion
|
|
4021
4022
|
//#region src/mcp/tools/simulate-revenue.ts
|
|
4022
|
-
const DATA_DIR$
|
|
4023
|
-
async function handleSimulateRevenue(input, dataDir = DATA_DIR$
|
|
4023
|
+
const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4024
|
+
async function handleSimulateRevenue(input, dataDir = DATA_DIR$38) {
|
|
4024
4025
|
try {
|
|
4025
4026
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4026
4027
|
const horizon = input.horizon ?? "quarter";
|
|
@@ -4078,8 +4079,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
|
|
|
4078
4079
|
}
|
|
4079
4080
|
//#endregion
|
|
4080
4081
|
//#region src/mcp/tools/get-playbook.ts
|
|
4081
|
-
const DATA_DIR$
|
|
4082
|
-
async function handleGetPlaybook(input, dataDir = DATA_DIR$
|
|
4082
|
+
const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4083
|
+
async function handleGetPlaybook(input, dataDir = DATA_DIR$37) {
|
|
4083
4084
|
try {
|
|
4084
4085
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4085
4086
|
if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
|
|
@@ -4164,12 +4165,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
|
|
|
4164
4165
|
...healthScore !== void 0 ? { healthScore } : {},
|
|
4165
4166
|
...daysSinceContact !== void 0 ? { daysSinceContact } : {},
|
|
4166
4167
|
...championPresent !== void 0 ? { championPresent } : {}
|
|
4167
|
-
}, DATA_DIR$
|
|
4168
|
+
}, DATA_DIR$37));
|
|
4168
4169
|
}
|
|
4169
4170
|
//#endregion
|
|
4170
4171
|
//#region src/mcp/tools/create-playbook.ts
|
|
4171
|
-
const DATA_DIR$
|
|
4172
|
-
async function handleCreatePlaybook(input, dataDir = DATA_DIR$
|
|
4172
|
+
const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4173
|
+
async function handleCreatePlaybook(input, dataDir = DATA_DIR$36) {
|
|
4173
4174
|
try {
|
|
4174
4175
|
const name = toKebabCase(input.name);
|
|
4175
4176
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -4242,12 +4243,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
|
|
|
4242
4243
|
trigger,
|
|
4243
4244
|
content,
|
|
4244
4245
|
...successRate !== void 0 ? { successRate } : {}
|
|
4245
|
-
}, DATA_DIR$
|
|
4246
|
+
}, DATA_DIR$36));
|
|
4246
4247
|
}
|
|
4247
4248
|
//#endregion
|
|
4248
4249
|
//#region src/mcp/tools/list-playbooks.ts
|
|
4249
|
-
const DATA_DIR$
|
|
4250
|
-
async function handleListPlaybooks(input, dataDir = DATA_DIR$
|
|
4250
|
+
const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4251
|
+
async function handleListPlaybooks(input, dataDir = DATA_DIR$35) {
|
|
4251
4252
|
try {
|
|
4252
4253
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4253
4254
|
return { content: [{
|
|
@@ -4286,12 +4287,12 @@ Args:
|
|
|
4286
4287
|
|
|
4287
4288
|
Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
|
|
4288
4289
|
inputSchema: zod.z.object({ slug: zod.z.string().describe("Customer ID") })
|
|
4289
|
-
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$
|
|
4290
|
+
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$35));
|
|
4290
4291
|
}
|
|
4291
4292
|
//#endregion
|
|
4292
4293
|
//#region src/mcp/tools/distill-playbook.ts
|
|
4293
|
-
const DATA_DIR$
|
|
4294
|
-
async function handleDistillPlaybook(input, dataDir = DATA_DIR$
|
|
4294
|
+
const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4295
|
+
async function handleDistillPlaybook(input, dataDir = DATA_DIR$34, llmFn = require_llm.callLlm) {
|
|
4295
4296
|
try {
|
|
4296
4297
|
const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
|
|
4297
4298
|
if (!result.ok) {
|
|
@@ -4350,7 +4351,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
|
|
|
4350
4351
|
slug,
|
|
4351
4352
|
dealName,
|
|
4352
4353
|
outcome
|
|
4353
|
-
}, DATA_DIR$
|
|
4354
|
+
}, DATA_DIR$34));
|
|
4354
4355
|
}
|
|
4355
4356
|
//#endregion
|
|
4356
4357
|
//#region src/core/goal-engine.ts
|
|
@@ -4568,8 +4569,8 @@ function getActiveGoals(dataDir) {
|
|
|
4568
4569
|
}
|
|
4569
4570
|
//#endregion
|
|
4570
4571
|
//#region src/mcp/tools/pursue-goal.ts
|
|
4571
|
-
const DATA_DIR$
|
|
4572
|
-
async function handlePursueGoal(input, dataDir = DATA_DIR$
|
|
4572
|
+
const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4573
|
+
async function handlePursueGoal(input, dataDir = DATA_DIR$33, options = {}) {
|
|
4573
4574
|
try {
|
|
4574
4575
|
require_session_store.enforceRbac(dataDir, "pursue_goal");
|
|
4575
4576
|
const goal = await pursueGoal(dataDir, {
|
|
@@ -4632,12 +4633,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
|
|
|
4632
4633
|
goal,
|
|
4633
4634
|
deadline,
|
|
4634
4635
|
...context !== void 0 ? { context } : {}
|
|
4635
|
-
}, DATA_DIR$
|
|
4636
|
+
}, DATA_DIR$33));
|
|
4636
4637
|
}
|
|
4637
4638
|
//#endregion
|
|
4638
4639
|
//#region src/mcp/tools/get-goal-status.ts
|
|
4639
|
-
const DATA_DIR$
|
|
4640
|
-
async function handleGetGoalStatus(input, dataDir = DATA_DIR$
|
|
4640
|
+
const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4641
|
+
async function handleGetGoalStatus(input, dataDir = DATA_DIR$32) {
|
|
4641
4642
|
try {
|
|
4642
4643
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4643
4644
|
const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
|
|
@@ -4696,17 +4697,17 @@ Args:
|
|
|
4696
4697
|
|
|
4697
4698
|
Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
|
|
4698
4699
|
inputSchema: zod.z.object({ goalId: zod.z.string().optional().describe("Specific goal ID (omit for all active goals)") })
|
|
4699
|
-
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$
|
|
4700
|
+
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$32));
|
|
4700
4701
|
}
|
|
4701
4702
|
//#endregion
|
|
4702
4703
|
//#region src/mcp/tools/register-push-subscription.ts
|
|
4703
|
-
const DATA_DIR$
|
|
4704
|
+
const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4704
4705
|
const VALID_PROVIDERS = [
|
|
4705
4706
|
"gmail",
|
|
4706
4707
|
"microsoft-graph",
|
|
4707
4708
|
"slack"
|
|
4708
4709
|
];
|
|
4709
|
-
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$
|
|
4710
|
+
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$31) {
|
|
4710
4711
|
try {
|
|
4711
4712
|
if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
|
|
4712
4713
|
type: "text",
|
|
@@ -4792,12 +4793,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
|
|
|
4792
4793
|
...microsoftResource !== void 0 ? { microsoftResource } : {},
|
|
4793
4794
|
...slackTeamId !== void 0 ? { slackTeamId } : {},
|
|
4794
4795
|
...slackChannelId !== void 0 ? { slackChannelId } : {}
|
|
4795
|
-
}, DATA_DIR$
|
|
4796
|
+
}, DATA_DIR$31));
|
|
4796
4797
|
}
|
|
4797
4798
|
//#endregion
|
|
4798
4799
|
//#region src/mcp/tools/get-push-status.ts
|
|
4799
|
-
const DATA_DIR$
|
|
4800
|
-
async function handleGetPushStatus(input, dataDir = DATA_DIR$
|
|
4800
|
+
const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4801
|
+
async function handleGetPushStatus(input, dataDir = DATA_DIR$30) {
|
|
4801
4802
|
try {
|
|
4802
4803
|
let subs = await readSubscriptions(dataDir);
|
|
4803
4804
|
if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
|
|
@@ -4869,7 +4870,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
|
|
|
4869
4870
|
}, async ({ slug, provider }) => handleGetPushStatus({
|
|
4870
4871
|
...slug !== void 0 ? { slug } : {},
|
|
4871
4872
|
...provider !== void 0 ? { provider } : {}
|
|
4872
|
-
}, DATA_DIR$
|
|
4873
|
+
}, DATA_DIR$30));
|
|
4873
4874
|
}
|
|
4874
4875
|
//#endregion
|
|
4875
4876
|
//#region src/core/org-intelligence.ts
|
|
@@ -4935,8 +4936,8 @@ function deriveRecommendation(people, missingRoles) {
|
|
|
4935
4936
|
}
|
|
4936
4937
|
//#endregion
|
|
4937
4938
|
//#region src/mcp/tools/get-org-intelligence.ts
|
|
4938
|
-
const DATA_DIR$
|
|
4939
|
-
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$
|
|
4939
|
+
const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4940
|
+
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$29) {
|
|
4940
4941
|
try {
|
|
4941
4942
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4942
4943
|
const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
|
|
@@ -5069,8 +5070,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
|
|
|
5069
5070
|
}
|
|
5070
5071
|
//#endregion
|
|
5071
5072
|
//#region src/mcp/tools/open-deal-room.ts
|
|
5072
|
-
const DATA_DIR$
|
|
5073
|
-
async function handleOpenDealRoom(input, dataDir = DATA_DIR$
|
|
5073
|
+
const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5074
|
+
async function handleOpenDealRoom(input, dataDir = DATA_DIR$28) {
|
|
5074
5075
|
try {
|
|
5075
5076
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5076
5077
|
const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
|
|
@@ -5153,8 +5154,8 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
5153
5154
|
}
|
|
5154
5155
|
//#endregion
|
|
5155
5156
|
//#region src/mcp/tools/get-proactive-briefing.ts
|
|
5156
|
-
const DATA_DIR$
|
|
5157
|
-
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$
|
|
5157
|
+
const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5158
|
+
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$27) {
|
|
5158
5159
|
try {
|
|
5159
5160
|
const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
5160
5161
|
return { content: [{
|
|
@@ -5254,15 +5255,15 @@ function getTemplate(dataDir, id) {
|
|
|
5254
5255
|
}
|
|
5255
5256
|
//#endregion
|
|
5256
5257
|
//#region src/mcp/tools/list-email-templates.ts
|
|
5257
|
-
const DATA_DIR$
|
|
5258
|
-
async function handleListEmailTemplates(input, dataDir = DATA_DIR$
|
|
5258
|
+
const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5259
|
+
async function handleListEmailTemplates(input, dataDir = DATA_DIR$26) {
|
|
5259
5260
|
const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
|
|
5260
5261
|
return { content: [{
|
|
5261
5262
|
type: "text",
|
|
5262
5263
|
text: JSON.stringify(summary, null, 2)
|
|
5263
5264
|
}] };
|
|
5264
5265
|
}
|
|
5265
|
-
function registerListEmailTemplates(server, dataDir = DATA_DIR$
|
|
5266
|
+
function registerListEmailTemplates(server, dataDir = DATA_DIR$26) {
|
|
5266
5267
|
server.registerTool("list_email_templates", {
|
|
5267
5268
|
description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
|
|
5268
5269
|
inputSchema: zod.z.object({ category: zod.z.string().optional().describe("Filter by category") })
|
|
@@ -5296,8 +5297,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
|
|
|
5296
5297
|
}
|
|
5297
5298
|
//#endregion
|
|
5298
5299
|
//#region src/mcp/tools/get-email-template.ts
|
|
5299
|
-
const DATA_DIR$
|
|
5300
|
-
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$
|
|
5300
|
+
const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5301
|
+
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$25) {
|
|
5301
5302
|
const tmpl = getTemplate(dataDir, input.id);
|
|
5302
5303
|
if (!tmpl) return { content: [{
|
|
5303
5304
|
type: "text",
|
|
@@ -5313,7 +5314,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$24) {
|
|
|
5313
5314
|
}, null, 2)
|
|
5314
5315
|
}] };
|
|
5315
5316
|
}
|
|
5316
|
-
function registerGetEmailTemplate(server, dataDir = DATA_DIR$
|
|
5317
|
+
function registerGetEmailTemplate(server, dataDir = DATA_DIR$25) {
|
|
5317
5318
|
server.registerTool("get_email_template", {
|
|
5318
5319
|
description: "Get a specific email template by ID, including its body and detected variables.",
|
|
5319
5320
|
inputSchema: zod.z.object({ id: zod.z.string().describe("Template ID (e.g. 'enterprise-intro')") })
|
|
@@ -5321,8 +5322,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
|
|
|
5321
5322
|
}
|
|
5322
5323
|
//#endregion
|
|
5323
5324
|
//#region src/mcp/tools/draft-email.ts
|
|
5324
|
-
const DATA_DIR$
|
|
5325
|
-
async function handleDraftEmail(input, dataDir = DATA_DIR$
|
|
5325
|
+
const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5326
|
+
async function handleDraftEmail(input, dataDir = DATA_DIR$24) {
|
|
5326
5327
|
const tmpl = getTemplate(dataDir, input.templateId);
|
|
5327
5328
|
if (!tmpl) return { content: [{
|
|
5328
5329
|
type: "text",
|
|
@@ -5366,7 +5367,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$23) {
|
|
|
5366
5367
|
}, null, 2)
|
|
5367
5368
|
}] };
|
|
5368
5369
|
}
|
|
5369
|
-
function registerDraftEmail(server, dataDir = DATA_DIR$
|
|
5370
|
+
function registerDraftEmail(server, dataDir = DATA_DIR$24) {
|
|
5370
5371
|
server.registerTool("draft_email", {
|
|
5371
5372
|
description: `Draft a personalized email for a customer using a stored template.
|
|
5372
5373
|
Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
|
|
@@ -5474,8 +5475,8 @@ async function updateEnrollment(dataDir, id, updates) {
|
|
|
5474
5475
|
}
|
|
5475
5476
|
//#endregion
|
|
5476
5477
|
//#region src/mcp/tools/enroll-in-sequence.ts
|
|
5477
|
-
const DATA_DIR$
|
|
5478
|
-
async function handleEnrollInSequence(input, dataDir = DATA_DIR$
|
|
5478
|
+
const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5479
|
+
async function handleEnrollInSequence(input, dataDir = DATA_DIR$23) {
|
|
5479
5480
|
const sequence = getSequence(dataDir, input.sequenceId);
|
|
5480
5481
|
if (!sequence) return { content: [{
|
|
5481
5482
|
type: "text",
|
|
@@ -5507,7 +5508,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$22) {
|
|
|
5507
5508
|
})
|
|
5508
5509
|
}] };
|
|
5509
5510
|
}
|
|
5510
|
-
function registerEnrollInSequence(server, dataDir = DATA_DIR$
|
|
5511
|
+
function registerEnrollInSequence(server, dataDir = DATA_DIR$23) {
|
|
5511
5512
|
server.registerTool("enroll_in_sequence", {
|
|
5512
5513
|
description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
|
|
5513
5514
|
Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
@@ -5524,8 +5525,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
|
5524
5525
|
}
|
|
5525
5526
|
//#endregion
|
|
5526
5527
|
//#region src/mcp/tools/list-sequence-enrollments.ts
|
|
5527
|
-
const DATA_DIR$
|
|
5528
|
-
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$
|
|
5528
|
+
const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5529
|
+
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$22) {
|
|
5529
5530
|
let enrollments = readEnrollments(dataDir);
|
|
5530
5531
|
if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
|
|
5531
5532
|
if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
|
|
@@ -5534,7 +5535,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$21) {
|
|
|
5534
5535
|
text: JSON.stringify({ enrollments }, null, 2)
|
|
5535
5536
|
}] };
|
|
5536
5537
|
}
|
|
5537
|
-
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$
|
|
5538
|
+
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$22) {
|
|
5538
5539
|
server.registerTool("list_sequence_enrollments", {
|
|
5539
5540
|
description: `List email sequence enrollments. Filter by customer slug or status.
|
|
5540
5541
|
Returns: { enrollments: SequenceEnrollment[] }`,
|
|
@@ -5553,8 +5554,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
|
|
|
5553
5554
|
}
|
|
5554
5555
|
//#endregion
|
|
5555
5556
|
//#region src/mcp/tools/unenroll-from-sequence.ts
|
|
5556
|
-
const DATA_DIR$
|
|
5557
|
-
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$
|
|
5557
|
+
const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5558
|
+
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$21) {
|
|
5558
5559
|
if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
|
|
5559
5560
|
type: "text",
|
|
5560
5561
|
text: JSON.stringify({
|
|
@@ -5567,7 +5568,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$20) {
|
|
|
5567
5568
|
text: JSON.stringify({ success: true })
|
|
5568
5569
|
}] };
|
|
5569
5570
|
}
|
|
5570
|
-
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$
|
|
5571
|
+
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$21) {
|
|
5571
5572
|
server.registerTool("unenroll_from_sequence", {
|
|
5572
5573
|
description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
|
|
5573
5574
|
Returns: { success: boolean }`,
|
|
@@ -5576,8 +5577,8 @@ Returns: { success: boolean }`,
|
|
|
5576
5577
|
}
|
|
5577
5578
|
//#endregion
|
|
5578
5579
|
//#region src/mcp/tools/list-sequences.ts
|
|
5579
|
-
const DATA_DIR$
|
|
5580
|
-
async function handleListSequences(_input, dataDir = DATA_DIR$
|
|
5580
|
+
const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5581
|
+
async function handleListSequences(_input, dataDir = DATA_DIR$20) {
|
|
5581
5582
|
const sequences = listSequences(dataDir);
|
|
5582
5583
|
const enrollments = readEnrollments(dataDir);
|
|
5583
5584
|
const result = sequences.map((seq) => ({
|
|
@@ -5591,7 +5592,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$19) {
|
|
|
5591
5592
|
text: JSON.stringify({ sequences: result }, null, 2)
|
|
5592
5593
|
}] };
|
|
5593
5594
|
}
|
|
5594
|
-
function registerListSequences(server, dataDir = DATA_DIR$
|
|
5595
|
+
function registerListSequences(server, dataDir = DATA_DIR$20) {
|
|
5595
5596
|
server.registerTool("list_sequences", {
|
|
5596
5597
|
description: `List all email sequences with step count and enrollment count.
|
|
5597
5598
|
Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
|
|
@@ -5726,8 +5727,8 @@ async function generateQuote(dataDir, input) {
|
|
|
5726
5727
|
}
|
|
5727
5728
|
//#endregion
|
|
5728
5729
|
//#region src/mcp/tools/generate-quote.ts
|
|
5729
|
-
const DATA_DIR$
|
|
5730
|
-
async function handleGenerateQuote(input, dataDir = DATA_DIR$
|
|
5730
|
+
const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5731
|
+
async function handleGenerateQuote(input, dataDir = DATA_DIR$19) {
|
|
5731
5732
|
try {
|
|
5732
5733
|
const quote = await generateQuote(dataDir, input);
|
|
5733
5734
|
return { content: [{
|
|
@@ -5751,7 +5752,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$18) {
|
|
|
5751
5752
|
}] };
|
|
5752
5753
|
}
|
|
5753
5754
|
}
|
|
5754
|
-
function registerGenerateQuote(server, dataDir = DATA_DIR$
|
|
5755
|
+
function registerGenerateQuote(server, dataDir = DATA_DIR$19) {
|
|
5755
5756
|
server.registerTool("generate_quote", {
|
|
5756
5757
|
description: `Generate a professional HTML quote/offer for a customer deal.
|
|
5757
5758
|
Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
|
|
@@ -5779,8 +5780,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
|
|
|
5779
5780
|
}
|
|
5780
5781
|
//#endregion
|
|
5781
5782
|
//#region src/mcp/tools/get-quote-status.ts
|
|
5782
|
-
const DATA_DIR$
|
|
5783
|
-
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$
|
|
5783
|
+
const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5784
|
+
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$18) {
|
|
5784
5785
|
if (input.quoteNumber) {
|
|
5785
5786
|
const quote = readQuote(dataDir, input.quoteNumber);
|
|
5786
5787
|
if (!quote) return { content: [{
|
|
@@ -5798,7 +5799,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$17) {
|
|
|
5798
5799
|
text: JSON.stringify({ quotes }, null, 2)
|
|
5799
5800
|
}] };
|
|
5800
5801
|
}
|
|
5801
|
-
function registerGetQuoteStatus(server, dataDir = DATA_DIR$
|
|
5802
|
+
function registerGetQuoteStatus(server, dataDir = DATA_DIR$18) {
|
|
5802
5803
|
server.registerTool("get_quote_status", {
|
|
5803
5804
|
description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
|
|
5804
5805
|
Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
@@ -5813,7 +5814,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
|
5813
5814
|
}
|
|
5814
5815
|
//#endregion
|
|
5815
5816
|
//#region src/mcp/tools/get-booking-link.ts
|
|
5816
|
-
const DATA_DIR$
|
|
5817
|
+
const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5817
5818
|
function loadCalendlyConfig(dataDir) {
|
|
5818
5819
|
const p = path.default.join(dataDir, ".agentic", "integrations", "calendly.yaml");
|
|
5819
5820
|
if (!fs.default.existsSync(p)) return {};
|
|
@@ -5836,7 +5837,7 @@ function readCustomerFacts(dataDir, slug) {
|
|
|
5836
5837
|
...email ? { email } : {}
|
|
5837
5838
|
};
|
|
5838
5839
|
}
|
|
5839
|
-
async function handleGetBookingLink(input, dataDir = DATA_DIR$
|
|
5840
|
+
async function handleGetBookingLink(input, dataDir = DATA_DIR$17) {
|
|
5840
5841
|
const config = loadCalendlyConfig(dataDir);
|
|
5841
5842
|
const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
|
|
5842
5843
|
if (!apiKey) return { content: [{
|
|
@@ -5864,7 +5865,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
|
|
|
5864
5865
|
}] };
|
|
5865
5866
|
}
|
|
5866
5867
|
}
|
|
5867
|
-
function registerGetBookingLink(server, dataDir = DATA_DIR$
|
|
5868
|
+
function registerGetBookingLink(server, dataDir = DATA_DIR$17) {
|
|
5868
5869
|
server.registerTool("get_booking_link", {
|
|
5869
5870
|
description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
|
|
5870
5871
|
Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
|
|
@@ -6034,8 +6035,8 @@ function calcSlaDue(createdDate, priority, rules) {
|
|
|
6034
6035
|
}
|
|
6035
6036
|
//#endregion
|
|
6036
6037
|
//#region src/mcp/tools/create-ticket.ts
|
|
6037
|
-
const DATA_DIR$
|
|
6038
|
-
async function handleCreateTicket(input, dataDir = DATA_DIR$
|
|
6038
|
+
const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6039
|
+
async function handleCreateTicket(input, dataDir = DATA_DIR$16) {
|
|
6039
6040
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6040
6041
|
const rules = loadSlaRules(dataDir);
|
|
6041
6042
|
const priority = input.priority ?? "normal";
|
|
@@ -6057,7 +6058,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$15) {
|
|
|
6057
6058
|
text: JSON.stringify({ ticket }, null, 2)
|
|
6058
6059
|
}] };
|
|
6059
6060
|
}
|
|
6060
|
-
function registerCreateTicket(server, dataDir = DATA_DIR$
|
|
6061
|
+
function registerCreateTicket(server, dataDir = DATA_DIR$16) {
|
|
6061
6062
|
server.registerTool("create_ticket", {
|
|
6062
6063
|
description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
|
|
6063
6064
|
Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
@@ -6083,8 +6084,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
|
6083
6084
|
}
|
|
6084
6085
|
//#endregion
|
|
6085
6086
|
//#region src/mcp/tools/update-ticket.ts
|
|
6086
|
-
const DATA_DIR$
|
|
6087
|
-
async function handleUpdateTicket(input, dataDir = DATA_DIR$
|
|
6087
|
+
const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6088
|
+
async function handleUpdateTicket(input, dataDir = DATA_DIR$15) {
|
|
6088
6089
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6089
6090
|
if (!ticket) return { content: [{
|
|
6090
6091
|
type: "text",
|
|
@@ -6103,7 +6104,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$14) {
|
|
|
6103
6104
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6104
6105
|
}] };
|
|
6105
6106
|
}
|
|
6106
|
-
function registerUpdateTicket(server, dataDir = DATA_DIR$
|
|
6107
|
+
function registerUpdateTicket(server, dataDir = DATA_DIR$15) {
|
|
6107
6108
|
server.registerTool("update_ticket", {
|
|
6108
6109
|
description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
|
|
6109
6110
|
Returns: { ticket }`,
|
|
@@ -6128,8 +6129,8 @@ Returns: { ticket }`,
|
|
|
6128
6129
|
}
|
|
6129
6130
|
//#endregion
|
|
6130
6131
|
//#region src/mcp/tools/list-tickets.ts
|
|
6131
|
-
const DATA_DIR$
|
|
6132
|
-
async function handleListTickets(input, dataDir = DATA_DIR$
|
|
6132
|
+
const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6133
|
+
async function handleListTickets(input, dataDir = DATA_DIR$14) {
|
|
6133
6134
|
const results = await listAllTickets(dataDir, {
|
|
6134
6135
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
6135
6136
|
...input.status !== void 0 ? { status: input.status } : {},
|
|
@@ -6141,7 +6142,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$13) {
|
|
|
6141
6142
|
text: JSON.stringify({ tickets: results }, null, 2)
|
|
6142
6143
|
}] };
|
|
6143
6144
|
}
|
|
6144
|
-
function registerListTickets(server, dataDir = DATA_DIR$
|
|
6145
|
+
function registerListTickets(server, dataDir = DATA_DIR$14) {
|
|
6145
6146
|
server.registerTool("list_tickets", {
|
|
6146
6147
|
description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
|
|
6147
6148
|
Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
@@ -6171,8 +6172,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
|
6171
6172
|
}
|
|
6172
6173
|
//#endregion
|
|
6173
6174
|
//#region src/mcp/tools/close-ticket.ts
|
|
6174
|
-
const DATA_DIR$
|
|
6175
|
-
async function handleCloseTicket(input, dataDir = DATA_DIR$
|
|
6175
|
+
const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6176
|
+
async function handleCloseTicket(input, dataDir = DATA_DIR$13) {
|
|
6176
6177
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6177
6178
|
if (!ticket) return { content: [{
|
|
6178
6179
|
type: "text",
|
|
@@ -6199,7 +6200,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$12) {
|
|
|
6199
6200
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6200
6201
|
}] };
|
|
6201
6202
|
}
|
|
6202
|
-
function registerCloseTicket(server, dataDir = DATA_DIR$
|
|
6203
|
+
function registerCloseTicket(server, dataDir = DATA_DIR$13) {
|
|
6203
6204
|
server.registerTool("close_ticket", {
|
|
6204
6205
|
description: `Close a support ticket. Optionally logs the resolution as an interaction.
|
|
6205
6206
|
Returns: { ticket } with status=closed`,
|
|
@@ -6353,8 +6354,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
|
|
|
6353
6354
|
}
|
|
6354
6355
|
//#endregion
|
|
6355
6356
|
//#region src/mcp/tools/send-nps-survey.ts
|
|
6356
|
-
const DATA_DIR$
|
|
6357
|
-
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$
|
|
6357
|
+
const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6358
|
+
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$12) {
|
|
6358
6359
|
const survey = getSurvey(dataDir, input.surveyId);
|
|
6359
6360
|
if (!survey) return { content: [{
|
|
6360
6361
|
type: "text",
|
|
@@ -6375,7 +6376,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$11) {
|
|
|
6375
6376
|
}, null, 2)
|
|
6376
6377
|
}] };
|
|
6377
6378
|
}
|
|
6378
|
-
function registerSendNpsSurvey(server, dataDir = DATA_DIR$
|
|
6379
|
+
function registerSendNpsSurvey(server, dataDir = DATA_DIR$12) {
|
|
6379
6380
|
server.registerTool("send_nps_survey", {
|
|
6380
6381
|
description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
|
|
6381
6382
|
Does NOT send automatically — returns draft for review.
|
|
@@ -6395,8 +6396,8 @@ Returns: { token, subject, body, surveyUrl }`,
|
|
|
6395
6396
|
}
|
|
6396
6397
|
//#endregion
|
|
6397
6398
|
//#region src/mcp/tools/get-survey-results.ts
|
|
6398
|
-
const DATA_DIR$
|
|
6399
|
-
async function handleGetSurveyResults(input, dataDir = DATA_DIR$
|
|
6399
|
+
const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6400
|
+
async function handleGetSurveyResults(input, dataDir = DATA_DIR$11) {
|
|
6400
6401
|
const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
|
|
6401
6402
|
const nps = calcNpsScore(responses);
|
|
6402
6403
|
const promoters = responses.filter((r) => r.score >= 9).length;
|
|
@@ -6422,7 +6423,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$10) {
|
|
|
6422
6423
|
}, null, 2)
|
|
6423
6424
|
}] };
|
|
6424
6425
|
}
|
|
6425
|
-
function registerGetSurveyResults(server, dataDir = DATA_DIR$
|
|
6426
|
+
function registerGetSurveyResults(server, dataDir = DATA_DIR$11) {
|
|
6426
6427
|
server.registerTool("get_survey_results", {
|
|
6427
6428
|
description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
|
|
6428
6429
|
Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
|
|
@@ -6523,8 +6524,8 @@ function getKbMetaForExport(article) {
|
|
|
6523
6524
|
}
|
|
6524
6525
|
//#endregion
|
|
6525
6526
|
//#region src/mcp/tools/search-knowledge-base.ts
|
|
6526
|
-
const DATA_DIR$
|
|
6527
|
-
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$
|
|
6527
|
+
const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6528
|
+
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$10) {
|
|
6528
6529
|
const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
|
|
6529
6530
|
const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
|
|
6530
6531
|
return { content: [{
|
|
@@ -6539,7 +6540,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$9) {
|
|
|
6539
6540
|
}, null, 2)
|
|
6540
6541
|
}] };
|
|
6541
6542
|
}
|
|
6542
|
-
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$
|
|
6543
|
+
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$10) {
|
|
6543
6544
|
server.registerTool("search_knowledge_base", {
|
|
6544
6545
|
description: `Search the knowledge base for articles. Text search on title, body, and tags.
|
|
6545
6546
|
Returns: { count, articles[] } with excerpts`,
|
|
@@ -6558,8 +6559,8 @@ Returns: { count, articles[] } with excerpts`,
|
|
|
6558
6559
|
}
|
|
6559
6560
|
//#endregion
|
|
6560
6561
|
//#region src/mcp/tools/create-kb-article.ts
|
|
6561
|
-
const DATA_DIR$
|
|
6562
|
-
async function handleCreateKbArticle(input, dataDir = DATA_DIR$
|
|
6562
|
+
const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6563
|
+
async function handleCreateKbArticle(input, dataDir = DATA_DIR$9) {
|
|
6563
6564
|
if (getKbArticle(dataDir, input.id)) return { content: [{
|
|
6564
6565
|
type: "text",
|
|
6565
6566
|
text: JSON.stringify({ error: `Article '${input.id}' already exists` })
|
|
@@ -6587,7 +6588,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$8) {
|
|
|
6587
6588
|
}, null, 2)
|
|
6588
6589
|
}] };
|
|
6589
6590
|
}
|
|
6590
|
-
function registerCreateKbArticle(server, dataDir = DATA_DIR$
|
|
6591
|
+
function registerCreateKbArticle(server, dataDir = DATA_DIR$9) {
|
|
6591
6592
|
server.registerTool("create_kb_article", {
|
|
6592
6593
|
description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
|
|
6593
6594
|
Returns: { id, title, category, path }`,
|
|
@@ -6612,8 +6613,8 @@ Returns: { id, title, category, path }`,
|
|
|
6612
6613
|
}
|
|
6613
6614
|
//#endregion
|
|
6614
6615
|
//#region src/mcp/tools/backup-now.ts
|
|
6615
|
-
const DATA_DIR$
|
|
6616
|
-
async function handleBackupNow(input, dataDir = DATA_DIR$
|
|
6616
|
+
const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6617
|
+
async function handleBackupNow(input, dataDir = DATA_DIR$8) {
|
|
6617
6618
|
const zipPath = path.default.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
|
|
6618
6619
|
const manifest = await require_session_store.runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
|
|
6619
6620
|
if (!manifest) return { content: [{
|
|
@@ -6650,8 +6651,8 @@ function registerBackupNow(server) {
|
|
|
6650
6651
|
}
|
|
6651
6652
|
//#endregion
|
|
6652
6653
|
//#region src/mcp/tools/list-backups.ts
|
|
6653
|
-
const DATA_DIR$
|
|
6654
|
-
async function handleListBackups(input, dataDir = DATA_DIR$
|
|
6654
|
+
const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6655
|
+
async function handleListBackups(input, dataDir = DATA_DIR$7) {
|
|
6655
6656
|
const logEntries = require_session_store.readBackupLog(dataDir);
|
|
6656
6657
|
const fileEntries = require_session_store.listBackupsInDir(dataDir);
|
|
6657
6658
|
const entries = logEntries.length > 0 ? logEntries : fileEntries;
|
|
@@ -6685,8 +6686,8 @@ function registerListBackups(server) {
|
|
|
6685
6686
|
}
|
|
6686
6687
|
//#endregion
|
|
6687
6688
|
//#region src/mcp/tools/trigger-sync.ts
|
|
6688
|
-
const DATA_DIR$
|
|
6689
|
-
async function handleTriggerSync(input, dataDir = DATA_DIR$
|
|
6689
|
+
const DATA_DIR$6 = process.cwd();
|
|
6690
|
+
async function handleTriggerSync(input, dataDir = DATA_DIR$6) {
|
|
6690
6691
|
const auth = getGmailAuth();
|
|
6691
6692
|
if (!auth) return { content: [{
|
|
6692
6693
|
type: "text",
|
|
@@ -6780,8 +6781,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
|
|
|
6780
6781
|
}
|
|
6781
6782
|
//#endregion
|
|
6782
6783
|
//#region src/mcp/tools/get-audit-log.ts
|
|
6783
|
-
const DATA_DIR$
|
|
6784
|
-
async function handleGetAuditLog(input, dataDir = DATA_DIR$
|
|
6784
|
+
const DATA_DIR$5 = process.cwd();
|
|
6785
|
+
async function handleGetAuditLog(input, dataDir = DATA_DIR$5) {
|
|
6785
6786
|
const entries = require_session_store.readAuditLog(dataDir);
|
|
6786
6787
|
const filterOpts = { limit: input.limit ?? 50 };
|
|
6787
6788
|
if (input.slug !== void 0) filterOpts.slug = input.slug;
|
|
@@ -6823,8 +6824,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
|
|
|
6823
6824
|
}
|
|
6824
6825
|
//#endregion
|
|
6825
6826
|
//#region src/mcp/tools/get-logs.ts
|
|
6826
|
-
const DATA_DIR$
|
|
6827
|
-
async function handleGetLogs(input, dataDir = DATA_DIR$
|
|
6827
|
+
const DATA_DIR$4 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6828
|
+
async function handleGetLogs(input, dataDir = DATA_DIR$4) {
|
|
6828
6829
|
const query = {
|
|
6829
6830
|
...input.level !== void 0 ? { level: input.level } : {},
|
|
6830
6831
|
...input.component !== void 0 ? { component: input.component } : {},
|
|
@@ -6986,8 +6987,8 @@ async function runDiagnostics(dataDir) {
|
|
|
6986
6987
|
}
|
|
6987
6988
|
//#endregion
|
|
6988
6989
|
//#region src/mcp/tools/get-diagnostics.ts
|
|
6989
|
-
const DATA_DIR$
|
|
6990
|
-
async function handleGetDiagnostics(input, dataDir = DATA_DIR$
|
|
6990
|
+
const DATA_DIR$3 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6991
|
+
async function handleGetDiagnostics(input, dataDir = DATA_DIR$3) {
|
|
6991
6992
|
let cleaned = 0;
|
|
6992
6993
|
if (input.fix) {
|
|
6993
6994
|
const { cleanupTempFiles } = await Promise.resolve().then(() => doctor_exports);
|
|
@@ -7019,6 +7020,163 @@ Returns: { ok: boolean, tempFilesRemoved?: number, checks: [{ name, status: "ok"
|
|
|
7019
7020
|
}, async ({ fix }) => handleGetDiagnostics(fix !== void 0 ? { fix } : {}));
|
|
7020
7021
|
}
|
|
7021
7022
|
//#endregion
|
|
7023
|
+
//#region src/core/snapshots.ts
|
|
7024
|
+
function snapshotsDir(dataDir) {
|
|
7025
|
+
return path.default.join(dataDir, ".agentic", "snapshots");
|
|
7026
|
+
}
|
|
7027
|
+
function snapshotPath(dataDir, id) {
|
|
7028
|
+
return path.default.join(snapshotsDir(dataDir), `${id}.json`);
|
|
7029
|
+
}
|
|
7030
|
+
function dealKey(d) {
|
|
7031
|
+
return `${d.slug}::${d.name}`;
|
|
7032
|
+
}
|
|
7033
|
+
function isOpen(stage) {
|
|
7034
|
+
return stage !== "won" && stage !== "lost";
|
|
7035
|
+
}
|
|
7036
|
+
function openValue(deals) {
|
|
7037
|
+
return deals.filter((d) => isOpen(d.stage)).reduce((sum, d) => sum + d.value, 0);
|
|
7038
|
+
}
|
|
7039
|
+
/** Build a live snapshot of the current pipeline across all customers. */
|
|
7040
|
+
function collectDeals(dataDir) {
|
|
7041
|
+
const deals = [];
|
|
7042
|
+
for (const slug of require_session_store.listCustomerSlugs(dataDir)) for (const d of require_pipeline_writer.readPipelineSync(dataDir, slug)) deals.push({
|
|
7043
|
+
slug,
|
|
7044
|
+
name: d.name,
|
|
7045
|
+
stage: d.stage,
|
|
7046
|
+
value: d.value ?? 0,
|
|
7047
|
+
probability: d.probability ?? 0
|
|
7048
|
+
});
|
|
7049
|
+
return deals;
|
|
7050
|
+
}
|
|
7051
|
+
function snapshotIds(dataDir) {
|
|
7052
|
+
const dir = snapshotsDir(dataDir);
|
|
7053
|
+
if (!fs.default.existsSync(dir)) return [];
|
|
7054
|
+
return fs.default.readdirSync(dir).filter((f) => /^\d{4}-\d{2}-\d{2}\.json$/.test(f)).map((f) => f.replace(/\.json$/, "")).sort();
|
|
7055
|
+
}
|
|
7056
|
+
function loadSnapshot(dataDir, id) {
|
|
7057
|
+
return require_session_store.readJsonFile(snapshotPath(dataDir, id), null);
|
|
7058
|
+
}
|
|
7059
|
+
/** The most recent snapshot whose id is at or before `iso` (YYYY-MM-DD). */
|
|
7060
|
+
function latestSnapshotAtOrBefore(dataDir, iso) {
|
|
7061
|
+
const id = snapshotIds(dataDir).filter((s) => s <= iso).pop();
|
|
7062
|
+
return id ? loadSnapshot(dataDir, id) : null;
|
|
7063
|
+
}
|
|
7064
|
+
/** Compute what changed between two snapshots (before → after). */
|
|
7065
|
+
function diffSnapshots(before, after) {
|
|
7066
|
+
const beforeByKey = new Map(before.deals.map((d) => [dealKey(d), d]));
|
|
7067
|
+
const afterByKey = new Map(after.deals.map((d) => [dealKey(d), d]));
|
|
7068
|
+
const added = [];
|
|
7069
|
+
const removed = [];
|
|
7070
|
+
const advanced = [];
|
|
7071
|
+
const won = [];
|
|
7072
|
+
const lost = [];
|
|
7073
|
+
const valueChanged = [];
|
|
7074
|
+
for (const [key, a] of afterByKey) {
|
|
7075
|
+
const b = beforeByKey.get(key);
|
|
7076
|
+
if (!b) {
|
|
7077
|
+
added.push({
|
|
7078
|
+
slug: a.slug,
|
|
7079
|
+
name: a.name
|
|
7080
|
+
});
|
|
7081
|
+
continue;
|
|
7082
|
+
}
|
|
7083
|
+
if (b.stage !== a.stage) {
|
|
7084
|
+
advanced.push({
|
|
7085
|
+
slug: a.slug,
|
|
7086
|
+
name: a.name,
|
|
7087
|
+
from: b.stage,
|
|
7088
|
+
to: a.stage
|
|
7089
|
+
});
|
|
7090
|
+
if (a.stage === "won") won.push({
|
|
7091
|
+
slug: a.slug,
|
|
7092
|
+
name: a.name
|
|
7093
|
+
});
|
|
7094
|
+
if (a.stage === "lost") lost.push({
|
|
7095
|
+
slug: a.slug,
|
|
7096
|
+
name: a.name
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
7099
|
+
if (b.value !== a.value) valueChanged.push({
|
|
7100
|
+
slug: a.slug,
|
|
7101
|
+
name: a.name,
|
|
7102
|
+
from: b.value,
|
|
7103
|
+
to: a.value
|
|
7104
|
+
});
|
|
7105
|
+
}
|
|
7106
|
+
for (const [key, b] of beforeByKey) if (!afterByKey.has(key)) removed.push({
|
|
7107
|
+
slug: b.slug,
|
|
7108
|
+
name: b.name
|
|
7109
|
+
});
|
|
7110
|
+
const openValueBefore = openValue(before.deals);
|
|
7111
|
+
const openValueAfter = openValue(after.deals);
|
|
7112
|
+
return {
|
|
7113
|
+
fromId: before.id,
|
|
7114
|
+
toId: after.id,
|
|
7115
|
+
added,
|
|
7116
|
+
removed,
|
|
7117
|
+
advanced,
|
|
7118
|
+
won,
|
|
7119
|
+
lost,
|
|
7120
|
+
valueChanged,
|
|
7121
|
+
openValueBefore,
|
|
7122
|
+
openValueAfter,
|
|
7123
|
+
openValueDelta: openValueAfter - openValueBefore
|
|
7124
|
+
};
|
|
7125
|
+
}
|
|
7126
|
+
/**
|
|
7127
|
+
* Diff the live pipeline against the latest snapshot at/before `since`.
|
|
7128
|
+
* Returns null when no baseline snapshot exists yet.
|
|
7129
|
+
*/
|
|
7130
|
+
function diffAgainstNow(dataDir, since, today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)) {
|
|
7131
|
+
const baseline = latestSnapshotAtOrBefore(dataDir, since);
|
|
7132
|
+
if (!baseline) return null;
|
|
7133
|
+
return diffSnapshots(baseline, {
|
|
7134
|
+
id: today,
|
|
7135
|
+
takenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7136
|
+
deals: collectDeals(dataDir)
|
|
7137
|
+
});
|
|
7138
|
+
}
|
|
7139
|
+
//#endregion
|
|
7140
|
+
//#region src/mcp/tools/get-pipeline-changes.ts
|
|
7141
|
+
const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
7142
|
+
function daysAgoIso(days) {
|
|
7143
|
+
return (/* @__PURE__ */ new Date(Date.now() - days * 864e5)).toISOString().slice(0, 10);
|
|
7144
|
+
}
|
|
7145
|
+
async function handleGetPipelineChanges(input, dataDir = DATA_DIR$2) {
|
|
7146
|
+
const since = input.since ?? daysAgoIso(input.days ?? 7);
|
|
7147
|
+
const diff = diffAgainstNow(dataDir, since);
|
|
7148
|
+
const payload = diff ? diff : { error: `No pipeline snapshot at or before ${since}. Snapshots accrue daily via the daemon.` };
|
|
7149
|
+
return { content: [{
|
|
7150
|
+
type: "text",
|
|
7151
|
+
text: JSON.stringify(payload, null, 2)
|
|
7152
|
+
}] };
|
|
7153
|
+
}
|
|
7154
|
+
function registerGetPipelineChanges(server) {
|
|
7155
|
+
server.registerTool("get_pipeline_changes", {
|
|
7156
|
+
title: "Get Pipeline Changes",
|
|
7157
|
+
description: `Pipeline time-travel: what changed in the pipeline since a baseline date.
|
|
7158
|
+
Compares the live pipeline against the most recent daily snapshot at/before the
|
|
7159
|
+
baseline. Answers "what moved since last week?", "what did we win/lose?".
|
|
7160
|
+
|
|
7161
|
+
Args:
|
|
7162
|
+
since: Baseline date YYYY-MM-DD (optional)
|
|
7163
|
+
days: Look back this many days instead of a date (default 7)
|
|
7164
|
+
|
|
7165
|
+
Returns: { fromId, toId, added[], removed[], advanced[{from,to}], won[], lost[],
|
|
7166
|
+
valueChanged[{from,to}], openValueBefore, openValueAfter, openValueDelta }
|
|
7167
|
+
or { error } when no baseline snapshot exists yet.`,
|
|
7168
|
+
inputSchema: zod.z.object({
|
|
7169
|
+
since: zod.z.string().optional().describe("Baseline date YYYY-MM-DD"),
|
|
7170
|
+
days: zod.z.number().int().min(1).max(365).optional().describe("Look-back window in days (default 7)")
|
|
7171
|
+
})
|
|
7172
|
+
}, async ({ since, days }) => {
|
|
7173
|
+
const input = {};
|
|
7174
|
+
if (since !== void 0) input.since = since;
|
|
7175
|
+
if (days !== void 0) input.days = days;
|
|
7176
|
+
return handleGetPipelineChanges(input);
|
|
7177
|
+
});
|
|
7178
|
+
}
|
|
7179
|
+
//#endregion
|
|
7022
7180
|
//#region src/mcp/prompts.ts
|
|
7023
7181
|
/**
|
|
7024
7182
|
* CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
|
|
@@ -7436,6 +7594,7 @@ function createMcpServer() {
|
|
|
7436
7594
|
registerGetAuditLog(server);
|
|
7437
7595
|
registerGetLogs(server);
|
|
7438
7596
|
registerGetDiagnostics(server);
|
|
7597
|
+
registerGetPipelineChanges(server);
|
|
7439
7598
|
registerCustomObjectTools(server);
|
|
7440
7599
|
registerPrompts(server);
|
|
7441
7600
|
registerResources(server);
|