@datasynx/agentic-crm 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +7 -6
- package/dist/cli.js.map +1 -1
- package/dist/{doctor-C14-vnJ1.js → doctor-BFeelnq8.js} +2 -2
- package/dist/{doctor-C14-vnJ1.js.map → doctor-BFeelnq8.js.map} +1 -1
- package/dist/doctor-CYDaNmFn.js +2 -0
- package/dist/{index-BAutNcAT.d.cts → index-CLUKKfGb.d.cts} +2 -2
- package/dist/{index-BAutNcAT.d.cts.map → index-CLUKKfGb.d.cts.map} +1 -1
- package/dist/{index-FzDsNSSb.d.ts → index-D8jJ1VIt.d.ts} +10 -10
- package/dist/{index-FzDsNSSb.d.ts.map → index-D8jJ1VIt.d.ts.map} +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/{knowledge-base--063Kpa3.js → knowledge-base-Bx2PKQR2.js} +2 -1
- package/dist/knowledge-base-Bx2PKQR2.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 +264 -128
- 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 +264 -128
- package/dist/mcp.js.map +1 -1
- package/dist/{server-DoRPPOeR.js → server-BhNLrnAD.js} +164 -128
- package/dist/server-BhNLrnAD.js.map +1 -0
- package/package.json +2 -2
- package/dist/knowledge-base--063Kpa3.js.map +0 -1
- package/dist/server-DoRPPOeR.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -443,6 +443,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
|
|
|
443
443
|
| trigger_sync | Force immediate Gmail sync for one or all customers | rep+ |
|
|
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
|
+
| get_diagnostics | Self-diagnostic health check (data integrity, temp files, log errors, backups) | admin |
|
|
446
447
|
| define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
|
|
447
448
|
| create_record | Create a record of a custom object (validated against its schema) | rep+ |
|
|
448
449
|
| list_records | List records of a custom object | any |
|
|
@@ -1421,7 +1422,7 @@ async function buildContext(dataDir, slug) {
|
|
|
1421
1422
|
}
|
|
1422
1423
|
//#endregion
|
|
1423
1424
|
//#region src/mcp/tools/get-customer-context.ts
|
|
1424
|
-
const DATA_DIR$
|
|
1425
|
+
const DATA_DIR$53 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1425
1426
|
function triggerOnQuerySync(dataDir, slug) {
|
|
1426
1427
|
const auth = getGmailAuth();
|
|
1427
1428
|
if (!auth) return;
|
|
@@ -1442,7 +1443,7 @@ function triggerOnQuerySync(dataDir, slug) {
|
|
|
1442
1443
|
}).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
|
|
1443
1444
|
} catch {}
|
|
1444
1445
|
}
|
|
1445
|
-
async function handleGetCustomerContext(input, dataDir = DATA_DIR$
|
|
1446
|
+
async function handleGetCustomerContext(input, dataDir = DATA_DIR$53) {
|
|
1446
1447
|
const targetSlug = input.slug ?? getSession()?.customerSlug;
|
|
1447
1448
|
if (!targetSlug) return {
|
|
1448
1449
|
content: [{
|
|
@@ -1578,8 +1579,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
|
|
|
1578
1579
|
}
|
|
1579
1580
|
//#endregion
|
|
1580
1581
|
//#region src/mcp/tools/search-customer-knowledge.ts
|
|
1581
|
-
const DATA_DIR$
|
|
1582
|
-
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$
|
|
1582
|
+
const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1583
|
+
async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$52) {
|
|
1583
1584
|
const limit = input.limit ?? 5;
|
|
1584
1585
|
try {
|
|
1585
1586
|
const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
|
|
@@ -1627,14 +1628,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
|
|
|
1627
1628
|
}
|
|
1628
1629
|
//#endregion
|
|
1629
1630
|
//#region src/mcp/tools/list-customers.ts
|
|
1630
|
-
const DATA_DIR$
|
|
1631
|
+
const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
1631
1632
|
function extractLastInteractionDate(interactionsPath) {
|
|
1632
1633
|
if (!fs.existsSync(interactionsPath)) return void 0;
|
|
1633
1634
|
const content = fs.readFileSync(interactionsPath, "utf-8");
|
|
1634
1635
|
const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
|
|
1635
1636
|
return match ? match[1] : void 0;
|
|
1636
1637
|
}
|
|
1637
|
-
async function handleListCustomers(input, dataDir = DATA_DIR$
|
|
1638
|
+
async function handleListCustomers(input, dataDir = DATA_DIR$51) {
|
|
1638
1639
|
const customersDir = path.join(dataDir, "customers");
|
|
1639
1640
|
const customers = [];
|
|
1640
1641
|
if (!fs.existsSync(customersDir)) return { content: [{
|
|
@@ -2147,8 +2148,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
|
|
|
2147
2148
|
}
|
|
2148
2149
|
//#endregion
|
|
2149
2150
|
//#region src/mcp/tools/log-interaction.ts
|
|
2150
|
-
const DATA_DIR$
|
|
2151
|
-
async function handleLogInteraction(input, dataDir = DATA_DIR$
|
|
2151
|
+
const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2152
|
+
async function handleLogInteraction(input, dataDir = DATA_DIR$50) {
|
|
2152
2153
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2153
2154
|
const interactionDate = input.date ?? today;
|
|
2154
2155
|
const sourceRef = input.source ?? `agent://log/${Date.now()}`;
|
|
@@ -2257,8 +2258,8 @@ var update_deal_exports = /* @__PURE__ */ __exportAll({
|
|
|
2257
2258
|
handleUpdateDeal: () => handleUpdateDeal,
|
|
2258
2259
|
registerUpdateDeal: () => registerUpdateDeal
|
|
2259
2260
|
});
|
|
2260
|
-
const DATA_DIR$
|
|
2261
|
-
async function handleUpdateDeal(input, dataDir = DATA_DIR$
|
|
2261
|
+
const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2262
|
+
async function handleUpdateDeal(input, dataDir = DATA_DIR$49) {
|
|
2262
2263
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2263
2264
|
const deal = {
|
|
2264
2265
|
name: input.dealName,
|
|
@@ -2341,12 +2342,12 @@ Returns: { success: boolean, deal: object }`,
|
|
|
2341
2342
|
}
|
|
2342
2343
|
//#endregion
|
|
2343
2344
|
//#region src/mcp/tools/export-customer.ts
|
|
2344
|
-
const DATA_DIR$
|
|
2345
|
+
const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2345
2346
|
function countInteractions(content) {
|
|
2346
2347
|
const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
|
|
2347
2348
|
return matches ? matches.length : 0;
|
|
2348
2349
|
}
|
|
2349
|
-
async function handleExportCustomer(input, dataDir = DATA_DIR$
|
|
2350
|
+
async function handleExportCustomer(input, dataDir = DATA_DIR$48) {
|
|
2350
2351
|
enforceRbac(dataDir, "export_customer");
|
|
2351
2352
|
const customerDir = path.join(dataDir, "customers", input.slug);
|
|
2352
2353
|
if (!fs.existsSync(customerDir)) return {
|
|
@@ -2459,8 +2460,8 @@ Returns:
|
|
|
2459
2460
|
}
|
|
2460
2461
|
//#endregion
|
|
2461
2462
|
//#region src/mcp/tools/update-customer-facts.ts
|
|
2462
|
-
const DATA_DIR$
|
|
2463
|
-
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$
|
|
2463
|
+
const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2464
|
+
async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$47) {
|
|
2464
2465
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2465
2466
|
try {
|
|
2466
2467
|
enforceRbac(dataDir, "update_customer_facts");
|
|
@@ -2638,8 +2639,8 @@ function scoreDealForToday(deal, todayDate) {
|
|
|
2638
2639
|
}
|
|
2639
2640
|
//#endregion
|
|
2640
2641
|
//#region src/mcp/tools/get-deal-health.ts
|
|
2641
|
-
const DATA_DIR$
|
|
2642
|
-
async function handleGetDealHealth(input, dataDir = DATA_DIR$
|
|
2642
|
+
const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2643
|
+
async function handleGetDealHealth(input, dataDir = DATA_DIR$46) {
|
|
2643
2644
|
try {
|
|
2644
2645
|
const deals = await readPipeline(dataDir, input.slug);
|
|
2645
2646
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2688,8 +2689,8 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
|
|
|
2688
2689
|
}
|
|
2689
2690
|
//#endregion
|
|
2690
2691
|
//#region src/mcp/tools/get-pipeline-forecast.ts
|
|
2691
|
-
const DATA_DIR$
|
|
2692
|
-
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$
|
|
2692
|
+
const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2693
|
+
async function handleGetPipelineForecast(input, dataDir = DATA_DIR$45) {
|
|
2693
2694
|
try {
|
|
2694
2695
|
const slugs = listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
|
|
2695
2696
|
const allDeals = [];
|
|
@@ -2750,8 +2751,8 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
|
|
|
2750
2751
|
}
|
|
2751
2752
|
//#endregion
|
|
2752
2753
|
//#region src/mcp/tools/summarize-meeting.ts
|
|
2753
|
-
const DATA_DIR$
|
|
2754
|
-
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$
|
|
2754
|
+
const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2755
|
+
async function handleSummarizeMeeting(input, dataDir = DATA_DIR$44) {
|
|
2755
2756
|
try {
|
|
2756
2757
|
let summary = input.transcript.slice(0, 400);
|
|
2757
2758
|
let nextSteps = [];
|
|
@@ -2874,8 +2875,8 @@ function getPipelineStages(dataDir) {
|
|
|
2874
2875
|
}
|
|
2875
2876
|
//#endregion
|
|
2876
2877
|
//#region src/mcp/tools/get-pipeline-stages.ts
|
|
2877
|
-
const DATA_DIR$
|
|
2878
|
-
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$
|
|
2878
|
+
const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2879
|
+
async function handleGetPipelineStages(_input, dataDir = DATA_DIR$43) {
|
|
2879
2880
|
const stages = getPipelineStages(dataDir);
|
|
2880
2881
|
return { content: [{
|
|
2881
2882
|
type: "text",
|
|
@@ -2903,8 +2904,8 @@ async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
|
|
|
2903
2904
|
}
|
|
2904
2905
|
//#endregion
|
|
2905
2906
|
//#region src/mcp/tools/get-market-intelligence.ts
|
|
2906
|
-
const DATA_DIR$
|
|
2907
|
-
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$
|
|
2907
|
+
const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2908
|
+
async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$42) {
|
|
2908
2909
|
const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
|
|
2909
2910
|
const all = listCustomerSlugs(dataDir);
|
|
2910
2911
|
const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
|
|
@@ -2935,7 +2936,7 @@ function registerGetMarketIntelligence(server) {
|
|
|
2935
2936
|
}
|
|
2936
2937
|
//#endregion
|
|
2937
2938
|
//#region src/mcp/tools/get-relationship-graph.ts
|
|
2938
|
-
const DATA_DIR$
|
|
2939
|
+
const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
2939
2940
|
function summarizeNode(n) {
|
|
2940
2941
|
return {
|
|
2941
2942
|
id: n.id,
|
|
@@ -2943,7 +2944,7 @@ function summarizeNode(n) {
|
|
|
2943
2944
|
email: n.properties["email"]
|
|
2944
2945
|
};
|
|
2945
2946
|
}
|
|
2946
|
-
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$
|
|
2947
|
+
async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$41) {
|
|
2947
2948
|
try {
|
|
2948
2949
|
const graph = readGraph(dataDir, input.slug);
|
|
2949
2950
|
const stakeholders = getStakeholders(graph);
|
|
@@ -3011,9 +3012,9 @@ Returns: {
|
|
|
3011
3012
|
}
|
|
3012
3013
|
//#endregion
|
|
3013
3014
|
//#region src/mcp/tools/get-relationship-health.ts
|
|
3014
|
-
const DATA_DIR$
|
|
3015
|
+
const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3015
3016
|
const MAX_HEALTH_AGE_MS = 3600 * 1e3;
|
|
3016
|
-
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$
|
|
3017
|
+
async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$40) {
|
|
3017
3018
|
try {
|
|
3018
3019
|
let health = readHealth(dataDir, input.slug);
|
|
3019
3020
|
if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
|
|
@@ -3682,8 +3683,8 @@ async function runDealAgent(config, dataDir, llmFn = callLlm) {
|
|
|
3682
3683
|
}
|
|
3683
3684
|
//#endregion
|
|
3684
3685
|
//#region src/mcp/tools/run-deal-agent.ts
|
|
3685
|
-
const DATA_DIR$
|
|
3686
|
-
async function handleRunDealAgent(input, dataDir = DATA_DIR$
|
|
3686
|
+
const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3687
|
+
async function handleRunDealAgent(input, dataDir = DATA_DIR$39) {
|
|
3687
3688
|
try {
|
|
3688
3689
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3689
3690
|
const result = await runDealAgent({
|
|
@@ -3750,8 +3751,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
|
|
|
3750
3751
|
}
|
|
3751
3752
|
//#endregion
|
|
3752
3753
|
//#region src/mcp/tools/approve-agent-action.ts
|
|
3753
|
-
const DATA_DIR$
|
|
3754
|
-
async function handleApproveAgentAction(input, dataDir = DATA_DIR$
|
|
3754
|
+
const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
3755
|
+
async function handleApproveAgentAction(input, dataDir = DATA_DIR$38) {
|
|
3755
3756
|
try {
|
|
3756
3757
|
const queue = readAgentQueue(dataDir, input.slug);
|
|
3757
3758
|
const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
|
|
@@ -4011,8 +4012,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
|
|
|
4011
4012
|
}
|
|
4012
4013
|
//#endregion
|
|
4013
4014
|
//#region src/mcp/tools/simulate-revenue.ts
|
|
4014
|
-
const DATA_DIR$
|
|
4015
|
-
async function handleSimulateRevenue(input, dataDir = DATA_DIR$
|
|
4015
|
+
const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4016
|
+
async function handleSimulateRevenue(input, dataDir = DATA_DIR$37) {
|
|
4016
4017
|
try {
|
|
4017
4018
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4018
4019
|
const horizon = input.horizon ?? "quarter";
|
|
@@ -4070,8 +4071,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
|
|
|
4070
4071
|
}
|
|
4071
4072
|
//#endregion
|
|
4072
4073
|
//#region src/mcp/tools/get-playbook.ts
|
|
4073
|
-
const DATA_DIR$
|
|
4074
|
-
async function handleGetPlaybook(input, dataDir = DATA_DIR$
|
|
4074
|
+
const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4075
|
+
async function handleGetPlaybook(input, dataDir = DATA_DIR$36) {
|
|
4075
4076
|
try {
|
|
4076
4077
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4077
4078
|
if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
|
|
@@ -4156,12 +4157,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
|
|
|
4156
4157
|
...healthScore !== void 0 ? { healthScore } : {},
|
|
4157
4158
|
...daysSinceContact !== void 0 ? { daysSinceContact } : {},
|
|
4158
4159
|
...championPresent !== void 0 ? { championPresent } : {}
|
|
4159
|
-
}, DATA_DIR$
|
|
4160
|
+
}, DATA_DIR$36));
|
|
4160
4161
|
}
|
|
4161
4162
|
//#endregion
|
|
4162
4163
|
//#region src/mcp/tools/create-playbook.ts
|
|
4163
|
-
const DATA_DIR$
|
|
4164
|
-
async function handleCreatePlaybook(input, dataDir = DATA_DIR$
|
|
4164
|
+
const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4165
|
+
async function handleCreatePlaybook(input, dataDir = DATA_DIR$35) {
|
|
4165
4166
|
try {
|
|
4166
4167
|
const name = toKebabCase(input.name);
|
|
4167
4168
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -4234,12 +4235,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
|
|
|
4234
4235
|
trigger,
|
|
4235
4236
|
content,
|
|
4236
4237
|
...successRate !== void 0 ? { successRate } : {}
|
|
4237
|
-
}, DATA_DIR$
|
|
4238
|
+
}, DATA_DIR$35));
|
|
4238
4239
|
}
|
|
4239
4240
|
//#endregion
|
|
4240
4241
|
//#region src/mcp/tools/list-playbooks.ts
|
|
4241
|
-
const DATA_DIR$
|
|
4242
|
-
async function handleListPlaybooks(input, dataDir = DATA_DIR$
|
|
4242
|
+
const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4243
|
+
async function handleListPlaybooks(input, dataDir = DATA_DIR$34) {
|
|
4243
4244
|
try {
|
|
4244
4245
|
const playbooks = listPlaybooks(dataDir, input.slug);
|
|
4245
4246
|
return { content: [{
|
|
@@ -4278,12 +4279,12 @@ Args:
|
|
|
4278
4279
|
|
|
4279
4280
|
Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
|
|
4280
4281
|
inputSchema: z.object({ slug: z.string().describe("Customer ID") })
|
|
4281
|
-
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$
|
|
4282
|
+
}, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$34));
|
|
4282
4283
|
}
|
|
4283
4284
|
//#endregion
|
|
4284
4285
|
//#region src/mcp/tools/distill-playbook.ts
|
|
4285
|
-
const DATA_DIR$
|
|
4286
|
-
async function handleDistillPlaybook(input, dataDir = DATA_DIR$
|
|
4286
|
+
const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4287
|
+
async function handleDistillPlaybook(input, dataDir = DATA_DIR$33, llmFn = callLlm) {
|
|
4287
4288
|
try {
|
|
4288
4289
|
const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
|
|
4289
4290
|
if (!result.ok) {
|
|
@@ -4342,7 +4343,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
|
|
|
4342
4343
|
slug,
|
|
4343
4344
|
dealName,
|
|
4344
4345
|
outcome
|
|
4345
|
-
}, DATA_DIR$
|
|
4346
|
+
}, DATA_DIR$33));
|
|
4346
4347
|
}
|
|
4347
4348
|
//#endregion
|
|
4348
4349
|
//#region src/core/goal-engine.ts
|
|
@@ -4560,8 +4561,8 @@ function getActiveGoals(dataDir) {
|
|
|
4560
4561
|
}
|
|
4561
4562
|
//#endregion
|
|
4562
4563
|
//#region src/mcp/tools/pursue-goal.ts
|
|
4563
|
-
const DATA_DIR$
|
|
4564
|
-
async function handlePursueGoal(input, dataDir = DATA_DIR$
|
|
4564
|
+
const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4565
|
+
async function handlePursueGoal(input, dataDir = DATA_DIR$32, options = {}) {
|
|
4565
4566
|
try {
|
|
4566
4567
|
enforceRbac(dataDir, "pursue_goal");
|
|
4567
4568
|
const goal = await pursueGoal(dataDir, {
|
|
@@ -4624,12 +4625,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
|
|
|
4624
4625
|
goal,
|
|
4625
4626
|
deadline,
|
|
4626
4627
|
...context !== void 0 ? { context } : {}
|
|
4627
|
-
}, DATA_DIR$
|
|
4628
|
+
}, DATA_DIR$32));
|
|
4628
4629
|
}
|
|
4629
4630
|
//#endregion
|
|
4630
4631
|
//#region src/mcp/tools/get-goal-status.ts
|
|
4631
|
-
const DATA_DIR$
|
|
4632
|
-
async function handleGetGoalStatus(input, dataDir = DATA_DIR$
|
|
4632
|
+
const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4633
|
+
async function handleGetGoalStatus(input, dataDir = DATA_DIR$31) {
|
|
4633
4634
|
try {
|
|
4634
4635
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4635
4636
|
const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
|
|
@@ -4688,17 +4689,17 @@ Args:
|
|
|
4688
4689
|
|
|
4689
4690
|
Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
|
|
4690
4691
|
inputSchema: z.object({ goalId: z.string().optional().describe("Specific goal ID (omit for all active goals)") })
|
|
4691
|
-
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$
|
|
4692
|
+
}, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$31));
|
|
4692
4693
|
}
|
|
4693
4694
|
//#endregion
|
|
4694
4695
|
//#region src/mcp/tools/register-push-subscription.ts
|
|
4695
|
-
const DATA_DIR$
|
|
4696
|
+
const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4696
4697
|
const VALID_PROVIDERS = [
|
|
4697
4698
|
"gmail",
|
|
4698
4699
|
"microsoft-graph",
|
|
4699
4700
|
"slack"
|
|
4700
4701
|
];
|
|
4701
|
-
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$
|
|
4702
|
+
async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$30) {
|
|
4702
4703
|
try {
|
|
4703
4704
|
if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
|
|
4704
4705
|
type: "text",
|
|
@@ -4784,12 +4785,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
|
|
|
4784
4785
|
...microsoftResource !== void 0 ? { microsoftResource } : {},
|
|
4785
4786
|
...slackTeamId !== void 0 ? { slackTeamId } : {},
|
|
4786
4787
|
...slackChannelId !== void 0 ? { slackChannelId } : {}
|
|
4787
|
-
}, DATA_DIR$
|
|
4788
|
+
}, DATA_DIR$30));
|
|
4788
4789
|
}
|
|
4789
4790
|
//#endregion
|
|
4790
4791
|
//#region src/mcp/tools/get-push-status.ts
|
|
4791
|
-
const DATA_DIR$
|
|
4792
|
-
async function handleGetPushStatus(input, dataDir = DATA_DIR$
|
|
4792
|
+
const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4793
|
+
async function handleGetPushStatus(input, dataDir = DATA_DIR$29) {
|
|
4793
4794
|
try {
|
|
4794
4795
|
let subs = await readSubscriptions(dataDir);
|
|
4795
4796
|
if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
|
|
@@ -4861,7 +4862,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
|
|
|
4861
4862
|
}, async ({ slug, provider }) => handleGetPushStatus({
|
|
4862
4863
|
...slug !== void 0 ? { slug } : {},
|
|
4863
4864
|
...provider !== void 0 ? { provider } : {}
|
|
4864
|
-
}, DATA_DIR$
|
|
4865
|
+
}, DATA_DIR$29));
|
|
4865
4866
|
}
|
|
4866
4867
|
//#endregion
|
|
4867
4868
|
//#region src/core/org-intelligence.ts
|
|
@@ -4927,8 +4928,8 @@ function deriveRecommendation(people, missingRoles) {
|
|
|
4927
4928
|
}
|
|
4928
4929
|
//#endregion
|
|
4929
4930
|
//#region src/mcp/tools/get-org-intelligence.ts
|
|
4930
|
-
const DATA_DIR$
|
|
4931
|
-
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$
|
|
4931
|
+
const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
4932
|
+
async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$28) {
|
|
4932
4933
|
try {
|
|
4933
4934
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4934
4935
|
const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
|
|
@@ -5061,8 +5062,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
|
|
|
5061
5062
|
}
|
|
5062
5063
|
//#endregion
|
|
5063
5064
|
//#region src/mcp/tools/open-deal-room.ts
|
|
5064
|
-
const DATA_DIR$
|
|
5065
|
-
async function handleOpenDealRoom(input, dataDir = DATA_DIR$
|
|
5065
|
+
const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5066
|
+
async function handleOpenDealRoom(input, dataDir = DATA_DIR$27) {
|
|
5066
5067
|
try {
|
|
5067
5068
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5068
5069
|
const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
|
|
@@ -5145,8 +5146,8 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
5145
5146
|
}
|
|
5146
5147
|
//#endregion
|
|
5147
5148
|
//#region src/mcp/tools/get-proactive-briefing.ts
|
|
5148
|
-
const DATA_DIR$
|
|
5149
|
-
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$
|
|
5149
|
+
const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5150
|
+
async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$26) {
|
|
5150
5151
|
try {
|
|
5151
5152
|
const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
5152
5153
|
return { content: [{
|
|
@@ -5246,15 +5247,15 @@ function getTemplate(dataDir, id) {
|
|
|
5246
5247
|
}
|
|
5247
5248
|
//#endregion
|
|
5248
5249
|
//#region src/mcp/tools/list-email-templates.ts
|
|
5249
|
-
const DATA_DIR$
|
|
5250
|
-
async function handleListEmailTemplates(input, dataDir = DATA_DIR$
|
|
5250
|
+
const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5251
|
+
async function handleListEmailTemplates(input, dataDir = DATA_DIR$25) {
|
|
5251
5252
|
const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
|
|
5252
5253
|
return { content: [{
|
|
5253
5254
|
type: "text",
|
|
5254
5255
|
text: JSON.stringify(summary, null, 2)
|
|
5255
5256
|
}] };
|
|
5256
5257
|
}
|
|
5257
|
-
function registerListEmailTemplates(server, dataDir = DATA_DIR$
|
|
5258
|
+
function registerListEmailTemplates(server, dataDir = DATA_DIR$25) {
|
|
5258
5259
|
server.registerTool("list_email_templates", {
|
|
5259
5260
|
description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
|
|
5260
5261
|
inputSchema: z.object({ category: z.string().optional().describe("Filter by category") })
|
|
@@ -5288,8 +5289,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
|
|
|
5288
5289
|
}
|
|
5289
5290
|
//#endregion
|
|
5290
5291
|
//#region src/mcp/tools/get-email-template.ts
|
|
5291
|
-
const DATA_DIR$
|
|
5292
|
-
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$
|
|
5292
|
+
const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5293
|
+
async function handleGetEmailTemplate(input, dataDir = DATA_DIR$24) {
|
|
5293
5294
|
const tmpl = getTemplate(dataDir, input.id);
|
|
5294
5295
|
if (!tmpl) return { content: [{
|
|
5295
5296
|
type: "text",
|
|
@@ -5305,7 +5306,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
|
|
|
5305
5306
|
}, null, 2)
|
|
5306
5307
|
}] };
|
|
5307
5308
|
}
|
|
5308
|
-
function registerGetEmailTemplate(server, dataDir = DATA_DIR$
|
|
5309
|
+
function registerGetEmailTemplate(server, dataDir = DATA_DIR$24) {
|
|
5309
5310
|
server.registerTool("get_email_template", {
|
|
5310
5311
|
description: "Get a specific email template by ID, including its body and detected variables.",
|
|
5311
5312
|
inputSchema: z.object({ id: z.string().describe("Template ID (e.g. 'enterprise-intro')") })
|
|
@@ -5313,8 +5314,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
|
|
|
5313
5314
|
}
|
|
5314
5315
|
//#endregion
|
|
5315
5316
|
//#region src/mcp/tools/draft-email.ts
|
|
5316
|
-
const DATA_DIR$
|
|
5317
|
-
async function handleDraftEmail(input, dataDir = DATA_DIR$
|
|
5317
|
+
const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5318
|
+
async function handleDraftEmail(input, dataDir = DATA_DIR$23) {
|
|
5318
5319
|
const tmpl = getTemplate(dataDir, input.templateId);
|
|
5319
5320
|
if (!tmpl) return { content: [{
|
|
5320
5321
|
type: "text",
|
|
@@ -5358,7 +5359,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
|
|
|
5358
5359
|
}, null, 2)
|
|
5359
5360
|
}] };
|
|
5360
5361
|
}
|
|
5361
|
-
function registerDraftEmail(server, dataDir = DATA_DIR$
|
|
5362
|
+
function registerDraftEmail(server, dataDir = DATA_DIR$23) {
|
|
5362
5363
|
server.registerTool("draft_email", {
|
|
5363
5364
|
description: `Draft a personalized email for a customer using a stored template.
|
|
5364
5365
|
Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
|
|
@@ -5466,8 +5467,8 @@ async function updateEnrollment(dataDir, id, updates) {
|
|
|
5466
5467
|
}
|
|
5467
5468
|
//#endregion
|
|
5468
5469
|
//#region src/mcp/tools/enroll-in-sequence.ts
|
|
5469
|
-
const DATA_DIR$
|
|
5470
|
-
async function handleEnrollInSequence(input, dataDir = DATA_DIR$
|
|
5470
|
+
const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5471
|
+
async function handleEnrollInSequence(input, dataDir = DATA_DIR$22) {
|
|
5471
5472
|
const sequence = getSequence(dataDir, input.sequenceId);
|
|
5472
5473
|
if (!sequence) return { content: [{
|
|
5473
5474
|
type: "text",
|
|
@@ -5499,7 +5500,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
|
|
|
5499
5500
|
})
|
|
5500
5501
|
}] };
|
|
5501
5502
|
}
|
|
5502
|
-
function registerEnrollInSequence(server, dataDir = DATA_DIR$
|
|
5503
|
+
function registerEnrollInSequence(server, dataDir = DATA_DIR$22) {
|
|
5503
5504
|
server.registerTool("enroll_in_sequence", {
|
|
5504
5505
|
description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
|
|
5505
5506
|
Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
@@ -5516,8 +5517,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
|
|
|
5516
5517
|
}
|
|
5517
5518
|
//#endregion
|
|
5518
5519
|
//#region src/mcp/tools/list-sequence-enrollments.ts
|
|
5519
|
-
const DATA_DIR$
|
|
5520
|
-
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$
|
|
5520
|
+
const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5521
|
+
async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$21) {
|
|
5521
5522
|
let enrollments = readEnrollments(dataDir);
|
|
5522
5523
|
if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
|
|
5523
5524
|
if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
|
|
@@ -5526,7 +5527,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
|
|
|
5526
5527
|
text: JSON.stringify({ enrollments }, null, 2)
|
|
5527
5528
|
}] };
|
|
5528
5529
|
}
|
|
5529
|
-
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$
|
|
5530
|
+
function registerListSequenceEnrollments(server, dataDir = DATA_DIR$21) {
|
|
5530
5531
|
server.registerTool("list_sequence_enrollments", {
|
|
5531
5532
|
description: `List email sequence enrollments. Filter by customer slug or status.
|
|
5532
5533
|
Returns: { enrollments: SequenceEnrollment[] }`,
|
|
@@ -5545,8 +5546,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
|
|
|
5545
5546
|
}
|
|
5546
5547
|
//#endregion
|
|
5547
5548
|
//#region src/mcp/tools/unenroll-from-sequence.ts
|
|
5548
|
-
const DATA_DIR$
|
|
5549
|
-
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$
|
|
5549
|
+
const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5550
|
+
async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$20) {
|
|
5550
5551
|
if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
|
|
5551
5552
|
type: "text",
|
|
5552
5553
|
text: JSON.stringify({
|
|
@@ -5559,7 +5560,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
|
|
|
5559
5560
|
text: JSON.stringify({ success: true })
|
|
5560
5561
|
}] };
|
|
5561
5562
|
}
|
|
5562
|
-
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$
|
|
5563
|
+
function registerUnenrollFromSequence(server, dataDir = DATA_DIR$20) {
|
|
5563
5564
|
server.registerTool("unenroll_from_sequence", {
|
|
5564
5565
|
description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
|
|
5565
5566
|
Returns: { success: boolean }`,
|
|
@@ -5568,8 +5569,8 @@ Returns: { success: boolean }`,
|
|
|
5568
5569
|
}
|
|
5569
5570
|
//#endregion
|
|
5570
5571
|
//#region src/mcp/tools/list-sequences.ts
|
|
5571
|
-
const DATA_DIR$
|
|
5572
|
-
async function handleListSequences(_input, dataDir = DATA_DIR$
|
|
5572
|
+
const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5573
|
+
async function handleListSequences(_input, dataDir = DATA_DIR$19) {
|
|
5573
5574
|
const sequences = listSequences(dataDir);
|
|
5574
5575
|
const enrollments = readEnrollments(dataDir);
|
|
5575
5576
|
const result = sequences.map((seq) => ({
|
|
@@ -5583,7 +5584,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
|
|
|
5583
5584
|
text: JSON.stringify({ sequences: result }, null, 2)
|
|
5584
5585
|
}] };
|
|
5585
5586
|
}
|
|
5586
|
-
function registerListSequences(server, dataDir = DATA_DIR$
|
|
5587
|
+
function registerListSequences(server, dataDir = DATA_DIR$19) {
|
|
5587
5588
|
server.registerTool("list_sequences", {
|
|
5588
5589
|
description: `List all email sequences with step count and enrollment count.
|
|
5589
5590
|
Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
|
|
@@ -5718,8 +5719,8 @@ async function generateQuote(dataDir, input) {
|
|
|
5718
5719
|
}
|
|
5719
5720
|
//#endregion
|
|
5720
5721
|
//#region src/mcp/tools/generate-quote.ts
|
|
5721
|
-
const DATA_DIR$
|
|
5722
|
-
async function handleGenerateQuote(input, dataDir = DATA_DIR$
|
|
5722
|
+
const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5723
|
+
async function handleGenerateQuote(input, dataDir = DATA_DIR$18) {
|
|
5723
5724
|
try {
|
|
5724
5725
|
const quote = await generateQuote(dataDir, input);
|
|
5725
5726
|
return { content: [{
|
|
@@ -5743,7 +5744,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
|
|
|
5743
5744
|
}] };
|
|
5744
5745
|
}
|
|
5745
5746
|
}
|
|
5746
|
-
function registerGenerateQuote(server, dataDir = DATA_DIR$
|
|
5747
|
+
function registerGenerateQuote(server, dataDir = DATA_DIR$18) {
|
|
5747
5748
|
server.registerTool("generate_quote", {
|
|
5748
5749
|
description: `Generate a professional HTML quote/offer for a customer deal.
|
|
5749
5750
|
Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
|
|
@@ -5771,8 +5772,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
|
|
|
5771
5772
|
}
|
|
5772
5773
|
//#endregion
|
|
5773
5774
|
//#region src/mcp/tools/get-quote-status.ts
|
|
5774
|
-
const DATA_DIR$
|
|
5775
|
-
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$
|
|
5775
|
+
const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5776
|
+
async function handleGetQuoteStatus(input, dataDir = DATA_DIR$17) {
|
|
5776
5777
|
if (input.quoteNumber) {
|
|
5777
5778
|
const quote = readQuote(dataDir, input.quoteNumber);
|
|
5778
5779
|
if (!quote) return { content: [{
|
|
@@ -5790,7 +5791,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
|
|
|
5790
5791
|
text: JSON.stringify({ quotes }, null, 2)
|
|
5791
5792
|
}] };
|
|
5792
5793
|
}
|
|
5793
|
-
function registerGetQuoteStatus(server, dataDir = DATA_DIR$
|
|
5794
|
+
function registerGetQuoteStatus(server, dataDir = DATA_DIR$17) {
|
|
5794
5795
|
server.registerTool("get_quote_status", {
|
|
5795
5796
|
description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
|
|
5796
5797
|
Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
@@ -5805,7 +5806,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
|
|
|
5805
5806
|
}
|
|
5806
5807
|
//#endregion
|
|
5807
5808
|
//#region src/mcp/tools/get-booking-link.ts
|
|
5808
|
-
const DATA_DIR$
|
|
5809
|
+
const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
5809
5810
|
function loadCalendlyConfig(dataDir) {
|
|
5810
5811
|
const p = path.join(dataDir, ".agentic", "integrations", "calendly.yaml");
|
|
5811
5812
|
if (!fs.existsSync(p)) return {};
|
|
@@ -5828,7 +5829,7 @@ function readCustomerFacts(dataDir, slug) {
|
|
|
5828
5829
|
...email ? { email } : {}
|
|
5829
5830
|
};
|
|
5830
5831
|
}
|
|
5831
|
-
async function handleGetBookingLink(input, dataDir = DATA_DIR$
|
|
5832
|
+
async function handleGetBookingLink(input, dataDir = DATA_DIR$16) {
|
|
5832
5833
|
const config = loadCalendlyConfig(dataDir);
|
|
5833
5834
|
const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
|
|
5834
5835
|
if (!apiKey) return { content: [{
|
|
@@ -5856,7 +5857,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
|
|
|
5856
5857
|
}] };
|
|
5857
5858
|
}
|
|
5858
5859
|
}
|
|
5859
|
-
function registerGetBookingLink(server, dataDir = DATA_DIR$
|
|
5860
|
+
function registerGetBookingLink(server, dataDir = DATA_DIR$16) {
|
|
5860
5861
|
server.registerTool("get_booking_link", {
|
|
5861
5862
|
description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
|
|
5862
5863
|
Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
|
|
@@ -6026,8 +6027,8 @@ function calcSlaDue(createdDate, priority, rules) {
|
|
|
6026
6027
|
}
|
|
6027
6028
|
//#endregion
|
|
6028
6029
|
//#region src/mcp/tools/create-ticket.ts
|
|
6029
|
-
const DATA_DIR$
|
|
6030
|
-
async function handleCreateTicket(input, dataDir = DATA_DIR$
|
|
6030
|
+
const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6031
|
+
async function handleCreateTicket(input, dataDir = DATA_DIR$15) {
|
|
6031
6032
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6032
6033
|
const rules = loadSlaRules(dataDir);
|
|
6033
6034
|
const priority = input.priority ?? "normal";
|
|
@@ -6049,7 +6050,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
|
|
|
6049
6050
|
text: JSON.stringify({ ticket }, null, 2)
|
|
6050
6051
|
}] };
|
|
6051
6052
|
}
|
|
6052
|
-
function registerCreateTicket(server, dataDir = DATA_DIR$
|
|
6053
|
+
function registerCreateTicket(server, dataDir = DATA_DIR$15) {
|
|
6053
6054
|
server.registerTool("create_ticket", {
|
|
6054
6055
|
description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
|
|
6055
6056
|
Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
@@ -6075,8 +6076,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
|
|
|
6075
6076
|
}
|
|
6076
6077
|
//#endregion
|
|
6077
6078
|
//#region src/mcp/tools/update-ticket.ts
|
|
6078
|
-
const DATA_DIR$
|
|
6079
|
-
async function handleUpdateTicket(input, dataDir = DATA_DIR$
|
|
6079
|
+
const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6080
|
+
async function handleUpdateTicket(input, dataDir = DATA_DIR$14) {
|
|
6080
6081
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6081
6082
|
if (!ticket) return { content: [{
|
|
6082
6083
|
type: "text",
|
|
@@ -6095,7 +6096,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
|
|
|
6095
6096
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6096
6097
|
}] };
|
|
6097
6098
|
}
|
|
6098
|
-
function registerUpdateTicket(server, dataDir = DATA_DIR$
|
|
6099
|
+
function registerUpdateTicket(server, dataDir = DATA_DIR$14) {
|
|
6099
6100
|
server.registerTool("update_ticket", {
|
|
6100
6101
|
description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
|
|
6101
6102
|
Returns: { ticket }`,
|
|
@@ -6120,8 +6121,8 @@ Returns: { ticket }`,
|
|
|
6120
6121
|
}
|
|
6121
6122
|
//#endregion
|
|
6122
6123
|
//#region src/mcp/tools/list-tickets.ts
|
|
6123
|
-
const DATA_DIR$
|
|
6124
|
-
async function handleListTickets(input, dataDir = DATA_DIR$
|
|
6124
|
+
const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6125
|
+
async function handleListTickets(input, dataDir = DATA_DIR$13) {
|
|
6125
6126
|
const results = await listAllTickets(dataDir, {
|
|
6126
6127
|
...input.slug !== void 0 ? { slug: input.slug } : {},
|
|
6127
6128
|
...input.status !== void 0 ? { status: input.status } : {},
|
|
@@ -6133,7 +6134,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$12) {
|
|
|
6133
6134
|
text: JSON.stringify({ tickets: results }, null, 2)
|
|
6134
6135
|
}] };
|
|
6135
6136
|
}
|
|
6136
|
-
function registerListTickets(server, dataDir = DATA_DIR$
|
|
6137
|
+
function registerListTickets(server, dataDir = DATA_DIR$13) {
|
|
6137
6138
|
server.registerTool("list_tickets", {
|
|
6138
6139
|
description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
|
|
6139
6140
|
Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
@@ -6163,8 +6164,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
|
|
|
6163
6164
|
}
|
|
6164
6165
|
//#endregion
|
|
6165
6166
|
//#region src/mcp/tools/close-ticket.ts
|
|
6166
|
-
const DATA_DIR$
|
|
6167
|
-
async function handleCloseTicket(input, dataDir = DATA_DIR$
|
|
6167
|
+
const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6168
|
+
async function handleCloseTicket(input, dataDir = DATA_DIR$12) {
|
|
6168
6169
|
const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
|
|
6169
6170
|
if (!ticket) return { content: [{
|
|
6170
6171
|
type: "text",
|
|
@@ -6191,7 +6192,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
|
|
|
6191
6192
|
text: JSON.stringify({ ticket: updated }, null, 2)
|
|
6192
6193
|
}] };
|
|
6193
6194
|
}
|
|
6194
|
-
function registerCloseTicket(server, dataDir = DATA_DIR$
|
|
6195
|
+
function registerCloseTicket(server, dataDir = DATA_DIR$12) {
|
|
6195
6196
|
server.registerTool("close_ticket", {
|
|
6196
6197
|
description: `Close a support ticket. Optionally logs the resolution as an interaction.
|
|
6197
6198
|
Returns: { ticket } with status=closed`,
|
|
@@ -6345,8 +6346,8 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
|
|
|
6345
6346
|
}
|
|
6346
6347
|
//#endregion
|
|
6347
6348
|
//#region src/mcp/tools/send-nps-survey.ts
|
|
6348
|
-
const DATA_DIR$
|
|
6349
|
-
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$
|
|
6349
|
+
const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6350
|
+
async function handleSendNpsSurvey(input, dataDir = DATA_DIR$11) {
|
|
6350
6351
|
const survey = getSurvey(dataDir, input.surveyId);
|
|
6351
6352
|
if (!survey) return { content: [{
|
|
6352
6353
|
type: "text",
|
|
@@ -6367,7 +6368,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
|
|
|
6367
6368
|
}, null, 2)
|
|
6368
6369
|
}] };
|
|
6369
6370
|
}
|
|
6370
|
-
function registerSendNpsSurvey(server, dataDir = DATA_DIR$
|
|
6371
|
+
function registerSendNpsSurvey(server, dataDir = DATA_DIR$11) {
|
|
6371
6372
|
server.registerTool("send_nps_survey", {
|
|
6372
6373
|
description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
|
|
6373
6374
|
Does NOT send automatically — returns draft for review.
|
|
@@ -6387,8 +6388,8 @@ Returns: { token, subject, body, surveyUrl }`,
|
|
|
6387
6388
|
}
|
|
6388
6389
|
//#endregion
|
|
6389
6390
|
//#region src/mcp/tools/get-survey-results.ts
|
|
6390
|
-
const DATA_DIR$
|
|
6391
|
-
async function handleGetSurveyResults(input, dataDir = DATA_DIR$
|
|
6391
|
+
const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6392
|
+
async function handleGetSurveyResults(input, dataDir = DATA_DIR$10) {
|
|
6392
6393
|
const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
|
|
6393
6394
|
const nps = calcNpsScore(responses);
|
|
6394
6395
|
const promoters = responses.filter((r) => r.score >= 9).length;
|
|
@@ -6414,7 +6415,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
|
|
|
6414
6415
|
}, null, 2)
|
|
6415
6416
|
}] };
|
|
6416
6417
|
}
|
|
6417
|
-
function registerGetSurveyResults(server, dataDir = DATA_DIR$
|
|
6418
|
+
function registerGetSurveyResults(server, dataDir = DATA_DIR$10) {
|
|
6418
6419
|
server.registerTool("get_survey_results", {
|
|
6419
6420
|
description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
|
|
6420
6421
|
Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
|
|
@@ -6515,8 +6516,8 @@ function getKbMetaForExport(article) {
|
|
|
6515
6516
|
}
|
|
6516
6517
|
//#endregion
|
|
6517
6518
|
//#region src/mcp/tools/search-knowledge-base.ts
|
|
6518
|
-
const DATA_DIR$
|
|
6519
|
-
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$
|
|
6519
|
+
const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6520
|
+
async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$9) {
|
|
6520
6521
|
const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
|
|
6521
6522
|
const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
|
|
6522
6523
|
return { content: [{
|
|
@@ -6531,7 +6532,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
|
|
|
6531
6532
|
}, null, 2)
|
|
6532
6533
|
}] };
|
|
6533
6534
|
}
|
|
6534
|
-
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$
|
|
6535
|
+
function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$9) {
|
|
6535
6536
|
server.registerTool("search_knowledge_base", {
|
|
6536
6537
|
description: `Search the knowledge base for articles. Text search on title, body, and tags.
|
|
6537
6538
|
Returns: { count, articles[] } with excerpts`,
|
|
@@ -6550,8 +6551,8 @@ Returns: { count, articles[] } with excerpts`,
|
|
|
6550
6551
|
}
|
|
6551
6552
|
//#endregion
|
|
6552
6553
|
//#region src/mcp/tools/create-kb-article.ts
|
|
6553
|
-
const DATA_DIR$
|
|
6554
|
-
async function handleCreateKbArticle(input, dataDir = DATA_DIR$
|
|
6554
|
+
const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6555
|
+
async function handleCreateKbArticle(input, dataDir = DATA_DIR$8) {
|
|
6555
6556
|
if (getKbArticle(dataDir, input.id)) return { content: [{
|
|
6556
6557
|
type: "text",
|
|
6557
6558
|
text: JSON.stringify({ error: `Article '${input.id}' already exists` })
|
|
@@ -6579,7 +6580,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
|
|
|
6579
6580
|
}, null, 2)
|
|
6580
6581
|
}] };
|
|
6581
6582
|
}
|
|
6582
|
-
function registerCreateKbArticle(server, dataDir = DATA_DIR$
|
|
6583
|
+
function registerCreateKbArticle(server, dataDir = DATA_DIR$8) {
|
|
6583
6584
|
server.registerTool("create_kb_article", {
|
|
6584
6585
|
description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
|
|
6585
6586
|
Returns: { id, title, category, path }`,
|
|
@@ -6604,8 +6605,8 @@ Returns: { id, title, category, path }`,
|
|
|
6604
6605
|
}
|
|
6605
6606
|
//#endregion
|
|
6606
6607
|
//#region src/mcp/tools/backup-now.ts
|
|
6607
|
-
const DATA_DIR$
|
|
6608
|
-
async function handleBackupNow(input, dataDir = DATA_DIR$
|
|
6608
|
+
const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6609
|
+
async function handleBackupNow(input, dataDir = DATA_DIR$7) {
|
|
6609
6610
|
const zipPath = path.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
|
|
6610
6611
|
const manifest = await runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
|
|
6611
6612
|
if (!manifest) return { content: [{
|
|
@@ -6642,8 +6643,8 @@ function registerBackupNow(server) {
|
|
|
6642
6643
|
}
|
|
6643
6644
|
//#endregion
|
|
6644
6645
|
//#region src/mcp/tools/list-backups.ts
|
|
6645
|
-
const DATA_DIR$
|
|
6646
|
-
async function handleListBackups(input, dataDir = DATA_DIR$
|
|
6646
|
+
const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6647
|
+
async function handleListBackups(input, dataDir = DATA_DIR$6) {
|
|
6647
6648
|
const logEntries = readBackupLog(dataDir);
|
|
6648
6649
|
const fileEntries = listBackupsInDir(dataDir);
|
|
6649
6650
|
const entries = logEntries.length > 0 ? logEntries : fileEntries;
|
|
@@ -6677,8 +6678,8 @@ function registerListBackups(server) {
|
|
|
6677
6678
|
}
|
|
6678
6679
|
//#endregion
|
|
6679
6680
|
//#region src/mcp/tools/trigger-sync.ts
|
|
6680
|
-
const DATA_DIR$
|
|
6681
|
-
async function handleTriggerSync(input, dataDir = DATA_DIR$
|
|
6681
|
+
const DATA_DIR$5 = process.cwd();
|
|
6682
|
+
async function handleTriggerSync(input, dataDir = DATA_DIR$5) {
|
|
6682
6683
|
const auth = getGmailAuth();
|
|
6683
6684
|
if (!auth) return { content: [{
|
|
6684
6685
|
type: "text",
|
|
@@ -6772,8 +6773,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
|
|
|
6772
6773
|
}
|
|
6773
6774
|
//#endregion
|
|
6774
6775
|
//#region src/mcp/tools/get-audit-log.ts
|
|
6775
|
-
const DATA_DIR$
|
|
6776
|
-
async function handleGetAuditLog(input, dataDir = DATA_DIR$
|
|
6776
|
+
const DATA_DIR$4 = process.cwd();
|
|
6777
|
+
async function handleGetAuditLog(input, dataDir = DATA_DIR$4) {
|
|
6777
6778
|
const entries = readAuditLog(dataDir);
|
|
6778
6779
|
const filterOpts = { limit: input.limit ?? 50 };
|
|
6779
6780
|
if (input.slug !== void 0) filterOpts.slug = input.slug;
|
|
@@ -6815,8 +6816,8 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
|
|
|
6815
6816
|
}
|
|
6816
6817
|
//#endregion
|
|
6817
6818
|
//#region src/mcp/tools/get-logs.ts
|
|
6818
|
-
const DATA_DIR$
|
|
6819
|
-
async function handleGetLogs(input, dataDir = DATA_DIR$
|
|
6819
|
+
const DATA_DIR$3 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6820
|
+
async function handleGetLogs(input, dataDir = DATA_DIR$3) {
|
|
6820
6821
|
const query = {
|
|
6821
6822
|
...input.level !== void 0 ? { level: input.level } : {},
|
|
6822
6823
|
...input.component !== void 0 ? { component: input.component } : {},
|
|
@@ -6877,6 +6878,140 @@ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors
|
|
|
6877
6878
|
});
|
|
6878
6879
|
}
|
|
6879
6880
|
//#endregion
|
|
6881
|
+
//#region src/core/doctor.ts
|
|
6882
|
+
var doctor_exports = /* @__PURE__ */ __exportAll({
|
|
6883
|
+
cleanupTempFiles: () => cleanupTempFiles,
|
|
6884
|
+
runDiagnostics: () => runDiagnostics
|
|
6885
|
+
});
|
|
6886
|
+
/** Recursively collect files whose name matches the atomic-write temp pattern. */
|
|
6887
|
+
function findOrphanedTempFiles(dir, depth = 0) {
|
|
6888
|
+
if (depth > 3 || !fs.existsSync(dir)) return [];
|
|
6889
|
+
const out = [];
|
|
6890
|
+
let entries;
|
|
6891
|
+
try {
|
|
6892
|
+
entries = fs.readdirSync(dir);
|
|
6893
|
+
} catch {
|
|
6894
|
+
return [];
|
|
6895
|
+
}
|
|
6896
|
+
for (const entry of entries) {
|
|
6897
|
+
const full = path.join(dir, entry);
|
|
6898
|
+
let isDir = false;
|
|
6899
|
+
try {
|
|
6900
|
+
isDir = fs.statSync(full).isDirectory();
|
|
6901
|
+
} catch {
|
|
6902
|
+
continue;
|
|
6903
|
+
}
|
|
6904
|
+
if (isDir) out.push(...findOrphanedTempFiles(full, depth + 1));
|
|
6905
|
+
else if (/\.\d+\.[0-9a-f]+\.tmp$/.test(entry)) out.push(full);
|
|
6906
|
+
}
|
|
6907
|
+
return out;
|
|
6908
|
+
}
|
|
6909
|
+
/** Delete orphaned atomic-write temp files; returns the paths removed. */
|
|
6910
|
+
function cleanupTempFiles(dataDir) {
|
|
6911
|
+
const temps = [...findOrphanedTempFiles(path.join(dataDir, ".agentic")), ...findOrphanedTempFiles(path.join(dataDir, "customers"))];
|
|
6912
|
+
const removed = [];
|
|
6913
|
+
for (const f of temps) try {
|
|
6914
|
+
fs.rmSync(f, { force: true });
|
|
6915
|
+
removed.push(f);
|
|
6916
|
+
} catch {}
|
|
6917
|
+
return removed;
|
|
6918
|
+
}
|
|
6919
|
+
async function runDiagnostics(dataDir) {
|
|
6920
|
+
const checks = [];
|
|
6921
|
+
const agenticDir = path.join(dataDir, ".agentic");
|
|
6922
|
+
const customersDir = path.join(dataDir, "customers");
|
|
6923
|
+
if (!fs.existsSync(agenticDir) && !fs.existsSync(customersDir)) checks.push({
|
|
6924
|
+
name: "data directory",
|
|
6925
|
+
status: "fail",
|
|
6926
|
+
detail: `Neither .agentic/ nor customers/ found under ${dataDir} — run 'dxcrm init'`
|
|
6927
|
+
});
|
|
6928
|
+
else checks.push({
|
|
6929
|
+
name: "data directory",
|
|
6930
|
+
status: "ok",
|
|
6931
|
+
detail: dataDir
|
|
6932
|
+
});
|
|
6933
|
+
const slugs = listCustomerSlugs(dataDir);
|
|
6934
|
+
const invalid = [];
|
|
6935
|
+
for (const slug of slugs) try {
|
|
6936
|
+
await readMainFacts(dataDir, slug);
|
|
6937
|
+
} catch {
|
|
6938
|
+
invalid.push(slug);
|
|
6939
|
+
}
|
|
6940
|
+
checks.push({
|
|
6941
|
+
name: "customer data",
|
|
6942
|
+
status: invalid.length > 0 ? "fail" : "ok",
|
|
6943
|
+
detail: invalid.length > 0 ? `${invalid.length} of ${slugs.length} invalid: ${invalid.slice(0, 5).join(", ")}` : `${slugs.length} customer(s) valid`
|
|
6944
|
+
});
|
|
6945
|
+
const temps = [...findOrphanedTempFiles(agenticDir), ...findOrphanedTempFiles(customersDir)];
|
|
6946
|
+
checks.push({
|
|
6947
|
+
name: "temp files",
|
|
6948
|
+
status: temps.length > 0 ? "warn" : "ok",
|
|
6949
|
+
detail: temps.length > 0 ? `${temps.length} orphaned temp file(s) from interrupted writes — safe to delete` : "no orphaned temp files"
|
|
6950
|
+
});
|
|
6951
|
+
const summary = summarizeLogs(dataDir);
|
|
6952
|
+
const errorCount = summary.byLevel.error;
|
|
6953
|
+
checks.push({
|
|
6954
|
+
name: "logs",
|
|
6955
|
+
status: errorCount > 0 ? "warn" : "ok",
|
|
6956
|
+
detail: errorCount > 0 ? `${errorCount} error entr${errorCount === 1 ? "y" : "ies"} in the log (dxcrm logs --level error)` : `${summary.total} log entr${summary.total === 1 ? "y" : "ies"}, no errors`
|
|
6957
|
+
});
|
|
6958
|
+
const backupLogPath = path.join(agenticDir, "backup-log.json");
|
|
6959
|
+
if (fs.existsSync(backupLogPath)) try {
|
|
6960
|
+
const entries = JSON.parse(fs.readFileSync(backupLogPath, "utf-8"));
|
|
6961
|
+
const last = entries[entries.length - 1]?.createdAt;
|
|
6962
|
+
const ageDays = last ? Math.floor((Date.now() - new Date(last).getTime()) / 864e5) : Infinity;
|
|
6963
|
+
checks.push({
|
|
6964
|
+
name: "backups",
|
|
6965
|
+
status: ageDays > 7 ? "warn" : "ok",
|
|
6966
|
+
detail: last ? `last backup ${ageDays}d ago` : "no backups recorded"
|
|
6967
|
+
});
|
|
6968
|
+
} catch {
|
|
6969
|
+
checks.push({
|
|
6970
|
+
name: "backups",
|
|
6971
|
+
status: "warn",
|
|
6972
|
+
detail: "backup log unreadable"
|
|
6973
|
+
});
|
|
6974
|
+
}
|
|
6975
|
+
return {
|
|
6976
|
+
ok: !checks.some((c) => c.status === "fail"),
|
|
6977
|
+
checks
|
|
6978
|
+
};
|
|
6979
|
+
}
|
|
6980
|
+
//#endregion
|
|
6981
|
+
//#region src/mcp/tools/get-diagnostics.ts
|
|
6982
|
+
const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
|
|
6983
|
+
async function handleGetDiagnostics(input, dataDir = DATA_DIR$2) {
|
|
6984
|
+
let cleaned = 0;
|
|
6985
|
+
if (input.fix) {
|
|
6986
|
+
const { cleanupTempFiles } = await Promise.resolve().then(() => doctor_exports);
|
|
6987
|
+
cleaned = cleanupTempFiles(dataDir).length;
|
|
6988
|
+
}
|
|
6989
|
+
const report = await runDiagnostics(dataDir);
|
|
6990
|
+
return { content: [{
|
|
6991
|
+
type: "text",
|
|
6992
|
+
text: JSON.stringify({
|
|
6993
|
+
ok: report.ok,
|
|
6994
|
+
...input.fix ? { tempFilesRemoved: cleaned } : {},
|
|
6995
|
+
checks: report.checks
|
|
6996
|
+
}, null, 2)
|
|
6997
|
+
}] };
|
|
6998
|
+
}
|
|
6999
|
+
function registerGetDiagnostics(server) {
|
|
7000
|
+
server.registerTool("get_diagnostics", {
|
|
7001
|
+
title: "Get Diagnostics",
|
|
7002
|
+
description: `Run a self-diagnostic health check of the CRM workspace.
|
|
7003
|
+
Verifies the data directory, validates every customer's profile, detects orphaned
|
|
7004
|
+
atomic-write temp files (a crash signature), surfaces recent log errors, and checks
|
|
7005
|
+
backup freshness. Use to answer "is everything healthy?" before/after bulk operations.
|
|
7006
|
+
|
|
7007
|
+
Args:
|
|
7008
|
+
fix: When true, first remove orphaned temp files (the only safely auto-fixable issue)
|
|
7009
|
+
|
|
7010
|
+
Returns: { ok: boolean, tempFilesRemoved?: number, checks: [{ name, status: "ok"|"warn"|"fail", detail }] }`,
|
|
7011
|
+
inputSchema: z.object({ fix: z.boolean().optional().describe("Clean orphaned temp files before reporting") })
|
|
7012
|
+
}, async ({ fix }) => handleGetDiagnostics(fix !== void 0 ? { fix } : {}));
|
|
7013
|
+
}
|
|
7014
|
+
//#endregion
|
|
6880
7015
|
//#region src/mcp/prompts.ts
|
|
6881
7016
|
/**
|
|
6882
7017
|
* CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
|
|
@@ -7293,6 +7428,7 @@ function createMcpServer() {
|
|
|
7293
7428
|
registerTriggerSync(server);
|
|
7294
7429
|
registerGetAuditLog(server);
|
|
7295
7430
|
registerGetLogs(server);
|
|
7431
|
+
registerGetDiagnostics(server);
|
|
7296
7432
|
registerCustomObjectTools(server);
|
|
7297
7433
|
registerPrompts(server);
|
|
7298
7434
|
registerResources(server);
|