conduyt-mcp 4.96.0 → 4.97.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/README.md +4 -0
- package/dist/index.js +2 -108
- package/dist/register-all.d.ts +4 -0
- package/dist/register-all.js +113 -0
- package/dist/tool-annotations.d.ts +33 -0
- package/dist/tool-annotations.js +386 -0
- package/dist/tools/automations.d.ts +1 -1
- package/dist/tools/automations.js +1 -1
- package/dist/tools/booking-pages.js +5 -5
- package/package.json +1 -1
- package/scripts/coverage-matrix.json +1 -1
package/README.md
CHANGED
|
@@ -465,3 +465,7 @@ Scopes can be restricted to specific modules (contacts, deals, tasks, etc.).
|
|
|
465
465
|
|----------|----------|-------------|
|
|
466
466
|
| `CONDUYT_API_URL` | Yes | Base URL (e.g. `https://conduyt.app`) |
|
|
467
467
|
| `CONDUYT_API_KEY` | Yes | API key starting with `cdy_` |
|
|
468
|
+
|
|
469
|
+
## Release: the contract gate's catalog pin
|
|
470
|
+
|
|
471
|
+
CI (`.github/workflows/contract-gate.yml`) runs `ENFORCE=1 node scripts/verify-contracts.mjs` against the app's `generated-api-catalog.json` at the commit pinned in `contracts/catalog-source.json` (`repo`, full 40-character `commit`, `catalogPath`). The workflow checks that commit out with the read-only deploy key on the app repository, stored as the repository secret `CONDUYT_APP_DEPLOY_KEY` (the private half; the checkout uses `ssh-key`) and fails closed if the secret or the file is missing. When you publish, set `commit` to the app commit the refreshed `scripts/contracts-snapshot.json` was generated from (the same one named in the CHANGELOG entry), in the same commit as the version bump. CI never uses a live API key. Under `ENFORCE=1` with a catalog source the gate also fails if `scripts/contracts-snapshot.json` differs from that catalog's endpoints in any field, so a pin and snapshot that disagree cannot pass.
|
package/dist/index.js
CHANGED
|
@@ -3,60 +3,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { ConduytClient } from "./client.js";
|
|
6
|
-
import {
|
|
7
|
-
import { registerContactTools } from "./tools/contacts.js";
|
|
8
|
-
import { registerDealTools } from "./tools/deals.js";
|
|
9
|
-
import { registerTaskTools } from "./tools/tasks.js";
|
|
10
|
-
import { registerPipelineTools } from "./tools/pipelines.js";
|
|
11
|
-
import { registerActivityTools } from "./tools/activities.js";
|
|
12
|
-
import { registerAiTools } from "./tools/ai.js";
|
|
13
|
-
import { registerAutomationTools } from "./tools/automations.js";
|
|
14
|
-
import { registerSequenceTools } from "./tools/sequences.js";
|
|
15
|
-
import { registerMessagingTools } from "./tools/messaging.js";
|
|
16
|
-
import { registerMessageCheckSettingsTools } from "./tools/message-check-settings.js";
|
|
17
|
-
import { registerCallTools } from "./tools/calls.js";
|
|
18
|
-
import { registerDialerSettingsTools } from "./tools/dialer-settings.js";
|
|
19
|
-
import { registerCompanyTools } from "./tools/companies.js";
|
|
20
|
-
import { registerTagTools } from "./tools/tags.js";
|
|
21
|
-
import { registerCalendarTools } from "./tools/calendar.js";
|
|
22
|
-
import { registerFormTools } from "./tools/forms.js";
|
|
23
|
-
import { registerInvoiceTools } from "./tools/invoices.js";
|
|
24
|
-
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
25
|
-
import { registerFormIntakeTools } from "./tools/form-intakes.js";
|
|
26
|
-
import { registerCalendlyTools } from "./tools/calendly.js";
|
|
27
|
-
import { registerBoardSettingsTools } from "./tools/board-settings.js";
|
|
28
|
-
import { registerMailchimpTools } from "./tools/mailchimp.js";
|
|
29
|
-
import { registerStatusMetadataTools } from "./tools/status-metadata.js";
|
|
30
|
-
import { registerNotificationTools } from "./tools/notifications.js";
|
|
31
|
-
import { registerChatTools } from "./tools/chat.js";
|
|
32
|
-
import { registerCustomFieldTools } from "./tools/custom-fields.js";
|
|
33
|
-
import { registerSmartListTools } from "./tools/smart-lists.js";
|
|
34
|
-
import { registerUserTools } from "./tools/users.js";
|
|
35
|
-
import { registerBulkTools } from "./tools/bulk.js";
|
|
36
|
-
import { registerBatchOperationTools } from "./tools/batch-operations.js";
|
|
37
|
-
import { registerDncTools } from "./tools/dnc.js";
|
|
38
|
-
import { registerSavedFilterTools } from "./tools/saved-filters.js";
|
|
39
|
-
import { registerDripCampaignTools } from "./tools/drip-campaigns.js";
|
|
40
|
-
import { registerScoringTools } from "./tools/scoring.js";
|
|
41
|
-
import { registerProductTools } from "./tools/products.js";
|
|
42
|
-
import { registerTemplateTools } from "./tools/templates.js";
|
|
43
|
-
import { registerDashboardTools } from "./tools/dashboard.js";
|
|
44
|
-
import { registerAiExtendedTools } from "./tools/ai-extended.js";
|
|
45
|
-
import { registerWorkflowSandboxTools } from "./tools/workflow-sandbox.js";
|
|
46
|
-
import { registerPrivacyTools } from "./tools/privacy.js";
|
|
47
|
-
import { registerSmartViewTools } from "./tools/smart-views.js";
|
|
48
|
-
import { registerAccountExportTools } from "./tools/account-exports.js";
|
|
49
|
-
import { registerLifecycleTools } from "./tools/lifecycle.js";
|
|
50
|
-
import { registerLeadPoolTools } from "./tools/lead-pool.js";
|
|
51
|
-
import { registerReplyCaptureTools } from "./tools/reply-capture.js";
|
|
52
|
-
import { registerCallFlowTools } from "./tools/call-flows.js";
|
|
53
|
-
import { registerProjectBlueTools } from "./tools/project-blue.js";
|
|
54
|
-
import { registerWhatsappTools } from "./tools/whatsapp.js";
|
|
55
|
-
import { registerFromkTools } from "./tools/fromk.js";
|
|
56
|
-
import { registerZoomTools } from "./tools/zoom.js";
|
|
57
|
-
import { registerBookingPageTools } from "./tools/booking-pages.js";
|
|
58
|
-
import { registerReportTools } from "./tools/reports.js";
|
|
59
|
-
import { registerReportDashboardTools } from "./tools/dashboards.js";
|
|
6
|
+
import { registerAllTools } from "./register-all.js";
|
|
60
7
|
const apiUrl = process.env.CONDUYT_API_URL;
|
|
61
8
|
const apiKey = process.env.CONDUYT_API_KEY;
|
|
62
9
|
if (!apiUrl || !apiKey) {
|
|
@@ -82,59 +29,6 @@ const server = new McpServer({
|
|
|
82
29
|
name: "conduyt",
|
|
83
30
|
version: pkg.version,
|
|
84
31
|
});
|
|
85
|
-
|
|
86
|
-
registerContactTools(server, client);
|
|
87
|
-
registerDealTools(server, client);
|
|
88
|
-
registerTaskTools(server, client);
|
|
89
|
-
registerPipelineTools(server, client);
|
|
90
|
-
registerActivityTools(server, client);
|
|
91
|
-
registerAiTools(server, client);
|
|
92
|
-
registerAutomationTools(server, client);
|
|
93
|
-
registerSequenceTools(server, client);
|
|
94
|
-
registerMessagingTools(server, client);
|
|
95
|
-
registerMessageCheckSettingsTools(server, client);
|
|
96
|
-
registerCallTools(server, client);
|
|
97
|
-
registerDialerSettingsTools(server, client);
|
|
98
|
-
registerCompanyTools(server, client);
|
|
99
|
-
registerTagTools(server, client);
|
|
100
|
-
registerCalendarTools(server, client);
|
|
101
|
-
registerFormTools(server, client);
|
|
102
|
-
registerInvoiceTools(server, client);
|
|
103
|
-
registerWebhookTools(server, client);
|
|
104
|
-
registerFormIntakeTools(server, client);
|
|
105
|
-
registerCalendlyTools(server, client);
|
|
106
|
-
registerBoardSettingsTools(server, client);
|
|
107
|
-
registerMailchimpTools(server, client);
|
|
108
|
-
registerStatusMetadataTools(server, client);
|
|
109
|
-
registerNotificationTools(server, client);
|
|
110
|
-
registerChatTools(server, client);
|
|
111
|
-
registerCustomFieldTools(server, client);
|
|
112
|
-
registerSmartListTools(server, client);
|
|
113
|
-
registerUserTools(server, client);
|
|
114
|
-
registerBulkTools(server, client);
|
|
115
|
-
registerBatchOperationTools(server, client);
|
|
116
|
-
registerDncTools(server, client);
|
|
117
|
-
registerSavedFilterTools(server, client);
|
|
118
|
-
registerDripCampaignTools(server, client);
|
|
119
|
-
registerScoringTools(server, client);
|
|
120
|
-
registerProductTools(server, client);
|
|
121
|
-
registerTemplateTools(server, client);
|
|
122
|
-
registerDashboardTools(server, client);
|
|
123
|
-
registerAiExtendedTools(server, client);
|
|
124
|
-
registerWorkflowSandboxTools(server, client);
|
|
125
|
-
registerPrivacyTools(server, client);
|
|
126
|
-
registerSmartViewTools(server, client);
|
|
127
|
-
registerAccountExportTools(server, client);
|
|
128
|
-
registerLifecycleTools(server, client);
|
|
129
|
-
registerLeadPoolTools(server, client);
|
|
130
|
-
registerReplyCaptureTools(server, client);
|
|
131
|
-
registerCallFlowTools(server, client);
|
|
132
|
-
registerProjectBlueTools(server, client);
|
|
133
|
-
registerWhatsappTools(server, client);
|
|
134
|
-
registerFromkTools(server, client);
|
|
135
|
-
registerZoomTools(server, client);
|
|
136
|
-
registerBookingPageTools(server, client);
|
|
137
|
-
registerReportTools(server, client);
|
|
138
|
-
registerReportDashboardTools(server, client);
|
|
32
|
+
registerAllTools(server, client);
|
|
139
33
|
const transport = new StdioServerTransport();
|
|
140
34
|
await server.connect(transport);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { ConduytClient } from "./client.js";
|
|
3
|
+
/** Registers every Conduyt tool on the server; each tool gets its title + MCP annotations from src/tool-annotations.ts. */
|
|
4
|
+
export declare function registerAllTools(server: McpServer, client: ConduytClient): void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { annotateRegistrations } from "./tool-annotations.js";
|
|
2
|
+
import { registerDiscoveryTools } from "./tools/discovery.js";
|
|
3
|
+
import { registerContactTools } from "./tools/contacts.js";
|
|
4
|
+
import { registerDealTools } from "./tools/deals.js";
|
|
5
|
+
import { registerTaskTools } from "./tools/tasks.js";
|
|
6
|
+
import { registerPipelineTools } from "./tools/pipelines.js";
|
|
7
|
+
import { registerActivityTools } from "./tools/activities.js";
|
|
8
|
+
import { registerAiTools } from "./tools/ai.js";
|
|
9
|
+
import { registerAutomationTools } from "./tools/automations.js";
|
|
10
|
+
import { registerSequenceTools } from "./tools/sequences.js";
|
|
11
|
+
import { registerMessagingTools } from "./tools/messaging.js";
|
|
12
|
+
import { registerMessageCheckSettingsTools } from "./tools/message-check-settings.js";
|
|
13
|
+
import { registerCallTools } from "./tools/calls.js";
|
|
14
|
+
import { registerDialerSettingsTools } from "./tools/dialer-settings.js";
|
|
15
|
+
import { registerCompanyTools } from "./tools/companies.js";
|
|
16
|
+
import { registerTagTools } from "./tools/tags.js";
|
|
17
|
+
import { registerCalendarTools } from "./tools/calendar.js";
|
|
18
|
+
import { registerFormTools } from "./tools/forms.js";
|
|
19
|
+
import { registerInvoiceTools } from "./tools/invoices.js";
|
|
20
|
+
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
21
|
+
import { registerFormIntakeTools } from "./tools/form-intakes.js";
|
|
22
|
+
import { registerCalendlyTools } from "./tools/calendly.js";
|
|
23
|
+
import { registerBoardSettingsTools } from "./tools/board-settings.js";
|
|
24
|
+
import { registerMailchimpTools } from "./tools/mailchimp.js";
|
|
25
|
+
import { registerStatusMetadataTools } from "./tools/status-metadata.js";
|
|
26
|
+
import { registerNotificationTools } from "./tools/notifications.js";
|
|
27
|
+
import { registerChatTools } from "./tools/chat.js";
|
|
28
|
+
import { registerCustomFieldTools } from "./tools/custom-fields.js";
|
|
29
|
+
import { registerSmartListTools } from "./tools/smart-lists.js";
|
|
30
|
+
import { registerUserTools } from "./tools/users.js";
|
|
31
|
+
import { registerBulkTools } from "./tools/bulk.js";
|
|
32
|
+
import { registerBatchOperationTools } from "./tools/batch-operations.js";
|
|
33
|
+
import { registerDncTools } from "./tools/dnc.js";
|
|
34
|
+
import { registerSavedFilterTools } from "./tools/saved-filters.js";
|
|
35
|
+
import { registerDripCampaignTools } from "./tools/drip-campaigns.js";
|
|
36
|
+
import { registerScoringTools } from "./tools/scoring.js";
|
|
37
|
+
import { registerProductTools } from "./tools/products.js";
|
|
38
|
+
import { registerTemplateTools } from "./tools/templates.js";
|
|
39
|
+
import { registerDashboardTools } from "./tools/dashboard.js";
|
|
40
|
+
import { registerAiExtendedTools } from "./tools/ai-extended.js";
|
|
41
|
+
import { registerWorkflowSandboxTools } from "./tools/workflow-sandbox.js";
|
|
42
|
+
import { registerPrivacyTools } from "./tools/privacy.js";
|
|
43
|
+
import { registerSmartViewTools } from "./tools/smart-views.js";
|
|
44
|
+
import { registerAccountExportTools } from "./tools/account-exports.js";
|
|
45
|
+
import { registerLifecycleTools } from "./tools/lifecycle.js";
|
|
46
|
+
import { registerLeadPoolTools } from "./tools/lead-pool.js";
|
|
47
|
+
import { registerReplyCaptureTools } from "./tools/reply-capture.js";
|
|
48
|
+
import { registerCallFlowTools } from "./tools/call-flows.js";
|
|
49
|
+
import { registerProjectBlueTools } from "./tools/project-blue.js";
|
|
50
|
+
import { registerWhatsappTools } from "./tools/whatsapp.js";
|
|
51
|
+
import { registerFromkTools } from "./tools/fromk.js";
|
|
52
|
+
import { registerZoomTools } from "./tools/zoom.js";
|
|
53
|
+
import { registerBookingPageTools } from "./tools/booking-pages.js";
|
|
54
|
+
import { registerReportTools } from "./tools/reports.js";
|
|
55
|
+
import { registerReportDashboardTools } from "./tools/dashboards.js";
|
|
56
|
+
/** Registers every Conduyt tool on the server; each tool gets its title + MCP annotations from src/tool-annotations.ts. */
|
|
57
|
+
export function registerAllTools(server, client) {
|
|
58
|
+
annotateRegistrations(server);
|
|
59
|
+
registerDiscoveryTools(server, client);
|
|
60
|
+
registerContactTools(server, client);
|
|
61
|
+
registerDealTools(server, client);
|
|
62
|
+
registerTaskTools(server, client);
|
|
63
|
+
registerPipelineTools(server, client);
|
|
64
|
+
registerActivityTools(server, client);
|
|
65
|
+
registerAiTools(server, client);
|
|
66
|
+
registerAutomationTools(server, client);
|
|
67
|
+
registerSequenceTools(server, client);
|
|
68
|
+
registerMessagingTools(server, client);
|
|
69
|
+
registerMessageCheckSettingsTools(server, client);
|
|
70
|
+
registerCallTools(server, client);
|
|
71
|
+
registerDialerSettingsTools(server, client);
|
|
72
|
+
registerCompanyTools(server, client);
|
|
73
|
+
registerTagTools(server, client);
|
|
74
|
+
registerCalendarTools(server, client);
|
|
75
|
+
registerFormTools(server, client);
|
|
76
|
+
registerInvoiceTools(server, client);
|
|
77
|
+
registerWebhookTools(server, client);
|
|
78
|
+
registerFormIntakeTools(server, client);
|
|
79
|
+
registerCalendlyTools(server, client);
|
|
80
|
+
registerBoardSettingsTools(server, client);
|
|
81
|
+
registerMailchimpTools(server, client);
|
|
82
|
+
registerStatusMetadataTools(server, client);
|
|
83
|
+
registerNotificationTools(server, client);
|
|
84
|
+
registerChatTools(server, client);
|
|
85
|
+
registerCustomFieldTools(server, client);
|
|
86
|
+
registerSmartListTools(server, client);
|
|
87
|
+
registerUserTools(server, client);
|
|
88
|
+
registerBulkTools(server, client);
|
|
89
|
+
registerBatchOperationTools(server, client);
|
|
90
|
+
registerDncTools(server, client);
|
|
91
|
+
registerSavedFilterTools(server, client);
|
|
92
|
+
registerDripCampaignTools(server, client);
|
|
93
|
+
registerScoringTools(server, client);
|
|
94
|
+
registerProductTools(server, client);
|
|
95
|
+
registerTemplateTools(server, client);
|
|
96
|
+
registerDashboardTools(server, client);
|
|
97
|
+
registerAiExtendedTools(server, client);
|
|
98
|
+
registerWorkflowSandboxTools(server, client);
|
|
99
|
+
registerPrivacyTools(server, client);
|
|
100
|
+
registerSmartViewTools(server, client);
|
|
101
|
+
registerAccountExportTools(server, client);
|
|
102
|
+
registerLifecycleTools(server, client);
|
|
103
|
+
registerLeadPoolTools(server, client);
|
|
104
|
+
registerReplyCaptureTools(server, client);
|
|
105
|
+
registerCallFlowTools(server, client);
|
|
106
|
+
registerProjectBlueTools(server, client);
|
|
107
|
+
registerWhatsappTools(server, client);
|
|
108
|
+
registerFromkTools(server, client);
|
|
109
|
+
registerZoomTools(server, client);
|
|
110
|
+
registerBookingPageTools(server, client);
|
|
111
|
+
registerReportTools(server, client);
|
|
112
|
+
registerReportDashboardTools(server, client);
|
|
113
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* MCP tool title + annotations for EVERY registered tool (#359). Hosts and connector directories read these hints to decide
|
|
4
|
+
* which tools may run without asking, and ChatGPT's directory requires all four hints to be explicit booleans.
|
|
5
|
+
*
|
|
6
|
+
* Every tool talks to the Conduyt API only, so openWorldHint is false on every row. The four kinds:
|
|
7
|
+
* ro reads only (readOnly true, destructive false, idempotent true)
|
|
8
|
+
* create adds records / sends / enqueues (readOnly false, destructive false, idempotent false)
|
|
9
|
+
* update changes existing state, same call repeated (readOnly false, destructive false, idempotent true)
|
|
10
|
+
* lands on the same state (PATCH / PUT / settings / reversible archive, disable, unassign)
|
|
11
|
+
* destroy deletes, erases, merges or tears down data (readOnly false, destructive true, idempotent true)
|
|
12
|
+
* Policy (Codex mcp359-r1): readOnlyHint means no Conduyt domain state is written by the call, including side-effect GETs
|
|
13
|
+
* (membership bootstrap, snapshot refresh, run ledger, Activity rows). Operational bookkeeping that is not CRM data (AI-guard audit
|
|
14
|
+
* rows, expiring dry-run confirmation tokens, rate limits) is deliberately outside that policy, so conduyt_ai_compose_email,
|
|
15
|
+
* conduyt_ai_enrich_contact and the conduyt_ai_task_* dry runs stay read-only. destructiveHint is true when ANY branch can delete
|
|
16
|
+
* or irreversibly change data (final decisions, terminal cancels, consent changes, token revocation, replace-mode deletes).
|
|
17
|
+
* A tool whose callback uses more than one HTTP method takes the most conservative combination. A new tool without a row
|
|
18
|
+
* here fails registration (annotateRegistrations) and the build-time test.
|
|
19
|
+
*/
|
|
20
|
+
export interface ToolAnnotation {
|
|
21
|
+
title: string;
|
|
22
|
+
readOnlyHint: boolean;
|
|
23
|
+
destructiveHint: boolean;
|
|
24
|
+
idempotentHint: boolean;
|
|
25
|
+
openWorldHint: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const TOOL_ANNOTATIONS: Record<string, ToolAnnotation>;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps server.tool so each tool registered afterwards gets its title and annotations from TOOL_ANNOTATIONS. The registered
|
|
30
|
+
* tool object is mutated in place (the same object strictInput() already swaps the input schema on), so the rest of each
|
|
31
|
+
* tool's registration is untouched. A tool with no row throws at registration.
|
|
32
|
+
*/
|
|
33
|
+
export declare function annotateRegistrations(server: McpServer): void;
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
const row = (title, readOnlyHint, destructiveHint, idempotentHint) => ({
|
|
2
|
+
title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint: false,
|
|
3
|
+
});
|
|
4
|
+
const ro = (title) => row(title, true, false, true);
|
|
5
|
+
const create = (title) => row(title, false, false, false);
|
|
6
|
+
const update = (title) => row(title, false, false, true);
|
|
7
|
+
const destroy = (title) => row(title, false, true, true);
|
|
8
|
+
export const TOOL_ANNOTATIONS = {
|
|
9
|
+
conduyt_api_catalog: ro("Get API Catalog"),
|
|
10
|
+
conduyt_check_permissions: ro("Check Permissions"),
|
|
11
|
+
conduyt_search: ro("Search CRM Records"),
|
|
12
|
+
conduyt_mcp_coverage: ro("Get MCP Coverage Matrix"),
|
|
13
|
+
conduyt_list_contacts: ro("List Contacts"),
|
|
14
|
+
conduyt_get_contact: ro("Get Contact"),
|
|
15
|
+
conduyt_create_contact: create("Create Contact"),
|
|
16
|
+
conduyt_update_contact: update("Update Contact"),
|
|
17
|
+
conduyt_add_contact_collaborator: update("Add Contact Collaborator"),
|
|
18
|
+
conduyt_remove_contact_collaborator: update("Remove Contact Collaborator"),
|
|
19
|
+
conduyt_delete_contact: destroy("Delete Contact"),
|
|
20
|
+
conduyt_add_tags: update("Add Tags"),
|
|
21
|
+
conduyt_link_contact_to_deal: update("Link Contact to Deal"),
|
|
22
|
+
conduyt_verify_line_type: create("Verify Phone Line Type"),
|
|
23
|
+
conduyt_merge_contacts: destroy("Merge Contacts"),
|
|
24
|
+
conduyt_list_duplicate_proposals: ro("List Duplicate Proposals"),
|
|
25
|
+
conduyt_decide_duplicate_proposal: destroy("Decide Duplicate Proposal"),
|
|
26
|
+
conduyt_list_import_duplicate_proposals: ro("List Import Duplicate Proposals"),
|
|
27
|
+
conduyt_list_deals: ro("List Deals"),
|
|
28
|
+
conduyt_pipeline_health: ro("Get Pipeline Health"),
|
|
29
|
+
conduyt_pipeline_health_fix_deal: update("Fix Deal From Pipeline Health"),
|
|
30
|
+
conduyt_pipeline_health_fix_next_action: create("Set Next Action From Pipeline Health"),
|
|
31
|
+
conduyt_get_deal: ro("Get Deal"),
|
|
32
|
+
conduyt_create_deal: create("Create Deal"),
|
|
33
|
+
conduyt_update_deal: row("Update Deal", false, false, false), // only a repeated close is silent; any other identical PATCH re-dispatches deal.updated and writes a deal.updated audit row (deals/[id]/route.ts:1330,1346)
|
|
34
|
+
conduyt_delete_deal: destroy("Delete Deal"),
|
|
35
|
+
conduyt_import_deals: create("Import Deals"),
|
|
36
|
+
conduyt_add_deal_tags: update("Add Deal Tags"),
|
|
37
|
+
conduyt_list_deal_views: ro("List Deal Views"),
|
|
38
|
+
conduyt_list_tasks: ro("List Tasks"),
|
|
39
|
+
conduyt_create_task: create("Create Task"),
|
|
40
|
+
conduyt_get_task: ro("Get Task"),
|
|
41
|
+
conduyt_update_task: update("Update Task"),
|
|
42
|
+
conduyt_complete_task: update("Complete Task"),
|
|
43
|
+
conduyt_delete_task: destroy("Delete Task"),
|
|
44
|
+
conduyt_list_pipelines: ro("List Pipelines"),
|
|
45
|
+
conduyt_list_archived_pipelines: ro("List Archived Pipelines"),
|
|
46
|
+
conduyt_create_pipeline: create("Create Pipeline"),
|
|
47
|
+
conduyt_update_pipeline: update("Update Pipeline"),
|
|
48
|
+
conduyt_delete_pipeline: destroy("Delete Pipeline"),
|
|
49
|
+
conduyt_archive_pipeline: update("Archive Pipeline"),
|
|
50
|
+
conduyt_restore_pipeline: update("Restore Pipeline"),
|
|
51
|
+
conduyt_reorder_pipelines: update("Reorder Pipelines"),
|
|
52
|
+
conduyt_create_stage: create("Create Stage"),
|
|
53
|
+
conduyt_update_stage: update("Update Stage"),
|
|
54
|
+
conduyt_reorder_stages: update("Reorder Stages"),
|
|
55
|
+
conduyt_delete_stage: destroy("Delete Stage"),
|
|
56
|
+
conduyt_list_activities: ro("List Activities"),
|
|
57
|
+
conduyt_create_activity: create("Create Activity"),
|
|
58
|
+
conduyt_ai_insights: create("Query AI Insights"),
|
|
59
|
+
conduyt_list_automations: ro("List Automations"),
|
|
60
|
+
conduyt_get_automation: ro("Get Automation"),
|
|
61
|
+
conduyt_create_automation: create("Create Automation"),
|
|
62
|
+
conduyt_update_automation: row("Update Automation", false, true, false), // webhook secret rotate/clear revokes the old credential; every config write bumps configRevision (automations/[id]/route.ts:248-275,726-739,1576-1579)
|
|
63
|
+
conduyt_publish_automation: row("Publish Automation", false, false, false), // each repeat can publish another numbered version (automations/[id]/publish/route.ts:218,291)
|
|
64
|
+
conduyt_resolve_names: ro("Resolve Names to IDs"),
|
|
65
|
+
conduyt_list_sequences: ro("List Sequences"),
|
|
66
|
+
conduyt_get_sequence: ro("Get Sequence"),
|
|
67
|
+
conduyt_create_sequence: create("Create Sequence"),
|
|
68
|
+
conduyt_update_sequence: row("Update Sequence", false, false, false), // archived:true assigns a fresh archivedAt on every call (emails/sequences/[id]/route.ts:124-128,235-238)
|
|
69
|
+
conduyt_list_sequence_senders: ro("List Sequence Senders"),
|
|
70
|
+
conduyt_preflight_sequence_enrollment: ro("Preflight Sequence Enrollment"),
|
|
71
|
+
conduyt_pick_sequence_list: ro("Pick Sequence List"),
|
|
72
|
+
conduyt_enroll_in_sequence: create("Enroll in Sequence"),
|
|
73
|
+
conduyt_unenroll_from_sequence: destroy("Unenroll from Sequence"),
|
|
74
|
+
conduyt_list_sequence_enrollments: ro("List Sequence Enrollments"),
|
|
75
|
+
conduyt_get_sequence_stats: ro("Get Sequence Stats"),
|
|
76
|
+
conduyt_check_message: ro("Check Message Grade"),
|
|
77
|
+
conduyt_list_sms_provider_options: ro("List SMS Provider Options"),
|
|
78
|
+
conduyt_sms_transports: ro("List SMS Transports"),
|
|
79
|
+
conduyt_whatsapp_templates: ro("List WhatsApp Templates"),
|
|
80
|
+
conduyt_voice_drop: create("Send Voice Drop"),
|
|
81
|
+
conduyt_send_sms: create("Send SMS"),
|
|
82
|
+
conduyt_send_email: create("Send Email"),
|
|
83
|
+
conduyt_get_conversation: ro("Get Conversation"),
|
|
84
|
+
conduyt_list_messages: ro("List Messages"),
|
|
85
|
+
conduyt_log_message: row("Log Message", false, true, false),
|
|
86
|
+
conduyt_sms_delivery_report: ro("Get SMS Delivery Report"),
|
|
87
|
+
conduyt_sms_drip_conversion_report: ro("Get SMS Drip Conversion Report"),
|
|
88
|
+
conduyt_speed_to_lead_report: ro("Get Speed to Lead Report"),
|
|
89
|
+
conduyt_attribution_report: ro("Get Attribution Report"),
|
|
90
|
+
conduyt_agent_performance_report: ro("Get Agent Performance Report"),
|
|
91
|
+
conduyt_list_targets: ro("List Targets"),
|
|
92
|
+
conduyt_set_targets: update("Set Targets"),
|
|
93
|
+
conduyt_call_performance_report: ro("Get Call Performance Report"),
|
|
94
|
+
conduyt_appointment_report: ro("Get Appointment Report"),
|
|
95
|
+
conduyt_funnel_report: ro("Get Funnel Report"),
|
|
96
|
+
conduyt_get_message_check_minimum_grade: ro("Get Message Check Minimum Grade"),
|
|
97
|
+
conduyt_update_message_check_minimum_grade: update("Update Message Check Minimum Grade"),
|
|
98
|
+
conduyt_list_calls: ro("List Calls"),
|
|
99
|
+
conduyt_search_dialer_history: ro("Search Dialer History"),
|
|
100
|
+
conduyt_search_dialer_calls: ro("Search Dialer Calls"),
|
|
101
|
+
conduyt_count_unknown_callers: ro("Count Unknown Callers"),
|
|
102
|
+
conduyt_link_call: update("Link Call"),
|
|
103
|
+
conduyt_get_call: ro("Get Call"),
|
|
104
|
+
conduyt_get_post_call_insight: ro("Get Post Call Insight"),
|
|
105
|
+
conduyt_sync_local_presence: row("Sync Local Presence", false, false, false), // every call writes lastSyncedAt (local-presence-sync.ts:225)
|
|
106
|
+
conduyt_get_dialer_settings: ro("Get Dialer Settings"),
|
|
107
|
+
conduyt_update_dialer_settings: update("Update Dialer Settings"),
|
|
108
|
+
conduyt_get_call_recording_settings: ro("Get Call Recording Settings"),
|
|
109
|
+
conduyt_update_call_recording_settings: update("Update Call Recording Settings"),
|
|
110
|
+
conduyt_list_companies: ro("List Companies"),
|
|
111
|
+
conduyt_get_company: ro("Get Company"),
|
|
112
|
+
conduyt_create_company: create("Create Company"),
|
|
113
|
+
conduyt_update_company: row("Update Company", false, false, false), // every identical PATCH creates a new company_updated Activity and re-dispatches the update fan-out (companies/[id]/route.ts:362-375)
|
|
114
|
+
conduyt_list_tags: ro("List Tags"),
|
|
115
|
+
conduyt_create_tag: create("Create Tag"),
|
|
116
|
+
conduyt_update_tag: update("Update Tag"),
|
|
117
|
+
conduyt_delete_tag: destroy("Delete Tag"),
|
|
118
|
+
conduyt_merge_tags: destroy("Merge Tags"),
|
|
119
|
+
conduyt_list_calendars: ro("List Calendars"),
|
|
120
|
+
conduyt_list_appointments: ro("List Appointments"),
|
|
121
|
+
conduyt_get_appointment: ro("Get Appointment"),
|
|
122
|
+
conduyt_create_appointment: create("Create Appointment"),
|
|
123
|
+
conduyt_update_appointment: row("Update Appointment", false, true, true), // cancellation permanently removes operational artifacts and cannot be reopened (appointments/[id]/route.ts:331); a repeat lands the same state
|
|
124
|
+
conduyt_appointment_outcome: row("Record Appointment Outcome", false, true, true), // cancelled outcomes cannot be undone; an identical outcome takes the explicit replay path (appointment-outcome-service.ts:515,633)
|
|
125
|
+
conduyt_appointment_outcome_undo: update("Undo Appointment Outcome"),
|
|
126
|
+
conduyt_list_forms: ro("List Forms"),
|
|
127
|
+
conduyt_get_form: ro("Get Form"),
|
|
128
|
+
conduyt_create_form: create("Create Form"),
|
|
129
|
+
conduyt_list_form_submissions: ro("List Form Submissions"),
|
|
130
|
+
conduyt_list_invoices: ro("List Invoices"),
|
|
131
|
+
conduyt_get_invoice: ro("Get Invoice"),
|
|
132
|
+
conduyt_create_invoice: create("Create Invoice"),
|
|
133
|
+
conduyt_update_invoice: row("Update Invoice", false, true, false), // line-item replacement deletes and recreates items with new ids every call (invoices/[id]/route.ts:413)
|
|
134
|
+
conduyt_send_invoice: create("Send Invoice"),
|
|
135
|
+
conduyt_list_webhooks: ro("List Webhooks"),
|
|
136
|
+
conduyt_create_webhook: create("Create Webhook"),
|
|
137
|
+
conduyt_update_webhook: update("Update Webhook"),
|
|
138
|
+
conduyt_delete_webhook: destroy("Delete Webhook"),
|
|
139
|
+
conduyt_cancel_webhook_log: destroy("Cancel Webhook Log"),
|
|
140
|
+
conduyt_get_form_intake_status: ro("Get Form Intake Status"),
|
|
141
|
+
conduyt_list_form_intakes: ro("List Form Intakes"),
|
|
142
|
+
conduyt_create_form_intake: create("Create Form Intake"),
|
|
143
|
+
conduyt_revoke_form_intake: destroy("Revoke Form Intake"),
|
|
144
|
+
conduyt_get_calendly_status: ro("Get Calendly Status"),
|
|
145
|
+
conduyt_get_calendly_import_progress: ro("Get Calendly Import Progress"),
|
|
146
|
+
conduyt_list_calendly_event_types: row("List Calendly Event Types", false, false, false), // refreshes and persists the live provider snapshot (calendly-sync.ts:430); not read-only per the round-2 policy
|
|
147
|
+
conduyt_set_calendly_event_types: row("Set Calendly Event Types", false, false, false), // always advances selectionSavedAt and can retry webhook/import setup (calendly-sync.ts:475)
|
|
148
|
+
conduyt_disconnect_calendly: destroy("Disconnect Calendly"),
|
|
149
|
+
conduyt_get_stage_rules: ro("Get Stage Rules"),
|
|
150
|
+
conduyt_set_stage_rules: update("Set Stage Rules"),
|
|
151
|
+
conduyt_get_deal_card_fields: ro("Get Deal Card Fields"),
|
|
152
|
+
conduyt_set_deal_card_fields: update("Set Deal Card Fields"),
|
|
153
|
+
conduyt_get_settings_revision: ro("Get Settings Revision"),
|
|
154
|
+
conduyt_get_pipeline_rot_days: ro("Get Pipeline Rot Days"),
|
|
155
|
+
conduyt_set_pipeline_rot_days: update("Set Pipeline Rot Days"),
|
|
156
|
+
conduyt_get_mailchimp_settings: ro("Get Mailchimp Settings"),
|
|
157
|
+
conduyt_update_mailchimp_settings: row("Update Mailchimp Settings", false, true, false), // audience change retires the old webhook/member generation; every save advances configGeneration (mailchimp-sync.ts:3684,3725)
|
|
158
|
+
conduyt_list_mailchimp_audiences: ro("List Mailchimp Audiences"),
|
|
159
|
+
conduyt_mailchimp_push_now: create("Push Contacts to Mailchimp Now"),
|
|
160
|
+
conduyt_mailchimp_retry_unsubscribes: row("Retry Mailchimp Unsubscribes", false, false, false), // one pass per call; a repeat can deliver more pending unsubscribes
|
|
161
|
+
conduyt_mailchimp_reconcile_statuses: row("Reconcile Mailchimp Statuses", false, false, false), // each call advances one pass (up to three); restart: true replaces a completed report
|
|
162
|
+
conduyt_mailchimp_confirm_reconciliation: row("Confirm Mailchimp Reconciliation", false, true, true), // final operator decision: deletes recovery ids, clears the report/block, advances the cursor; a repeat fails the precondition with no further effect (mailchimp-sync.ts:4606)
|
|
163
|
+
conduyt_list_status_metadata: ro("List Status Metadata"),
|
|
164
|
+
conduyt_get_status_metadata: ro("Get Status Metadata"),
|
|
165
|
+
conduyt_create_status_metadata: create("Create Status Metadata"),
|
|
166
|
+
conduyt_update_status_metadata: row("Update Status Metadata", false, false, false), // every successful write advances the concurrency version (status-metadata/[id]/route.ts:201)
|
|
167
|
+
conduyt_delete_status_metadata: destroy("Delete Status Metadata"),
|
|
168
|
+
conduyt_import_status_metadata: row("Import Status Metadata", false, true, false), // replace mode deletes and recreates rows with new ids; merge mode advances updatedAt (the concurrency version) on every call
|
|
169
|
+
conduyt_list_notifications: ro("List Notifications"),
|
|
170
|
+
conduyt_create_notification: create("Create Notification"),
|
|
171
|
+
conduyt_list_chat_channels: update("List Chat Channels"),
|
|
172
|
+
conduyt_get_chat_unread: ro("Get Chat Unread Counts"),
|
|
173
|
+
conduyt_list_chat_messages: update("List Chat Messages"),
|
|
174
|
+
conduyt_mark_chat_read: row("Mark Chat Read", false, false, false), // every call re-announces the read receipt to the reader's other tabs and devices, even when the marker did not move (chat/channels/[id]/messages/route.ts:126)
|
|
175
|
+
conduyt_get_chat_realtime_token: ro("Get Chat Realtime Token"),
|
|
176
|
+
conduyt_get_chat_notifications: update("Get Chat Notifications"),
|
|
177
|
+
conduyt_set_chat_notifications: update("Set Chat Notifications"),
|
|
178
|
+
conduyt_update_team_chat_settings: update("Update Team Chat Settings"),
|
|
179
|
+
conduyt_list_custom_fields: ro("List Custom Fields"),
|
|
180
|
+
conduyt_create_custom_field: create("Create Custom Field"),
|
|
181
|
+
conduyt_update_custom_field: update("Update Custom Field"),
|
|
182
|
+
conduyt_delete_custom_field: destroy("Delete Custom Field"),
|
|
183
|
+
conduyt_get_contact_table_defaults: ro("Get Contact Table Defaults"),
|
|
184
|
+
conduyt_set_contact_table_defaults: update("Set Contact Table Defaults"),
|
|
185
|
+
conduyt_list_smart_lists: ro("List Smart Lists"),
|
|
186
|
+
conduyt_get_smart_list: ro("Get Smart List"),
|
|
187
|
+
conduyt_create_smart_list: create("Create Smart List"),
|
|
188
|
+
conduyt_update_smart_list: update("Update Smart List"),
|
|
189
|
+
conduyt_add_contacts_to_smart_list: update("Add Contacts to Smart List"),
|
|
190
|
+
conduyt_get_smart_list_contacts: ro("Get Smart List Contacts"),
|
|
191
|
+
conduyt_list_users: ro("List Users"),
|
|
192
|
+
conduyt_get_user: ro("Get User"),
|
|
193
|
+
conduyt_create_user: create("Create User"),
|
|
194
|
+
conduyt_update_user: row("Update User", false, false, false), // phone supplied deletes and recreates the auto QuickConnect row, a fresh UUID each call (users/[id]/route.ts:579-594)
|
|
195
|
+
conduyt_get_user_stats: ro("Get User Stats"),
|
|
196
|
+
conduyt_invite_user: create("Invite User"),
|
|
197
|
+
conduyt_deactivate_user: update("Deactivate User"),
|
|
198
|
+
conduyt_reactivate_user: update("Reactivate User"),
|
|
199
|
+
conduyt_ai_import_contacts: create("Import Contacts With AI"),
|
|
200
|
+
conduyt_export_contacts: create("Export Contacts"),
|
|
201
|
+
conduyt_export_deals: create("Export Deals"),
|
|
202
|
+
conduyt_bulk_tag_contacts: update("Bulk Tag Contacts"),
|
|
203
|
+
conduyt_bulk_untag_contacts: update("Bulk Untag Contacts"),
|
|
204
|
+
conduyt_bulk_edit_contacts: row("Bulk Edit Contacts", false, true, true), // optedOutSms / optedOutEmail / doNotContact can clear consent and re-enable outreach; switches are state-predicated absolute writes, so a repeat of the same body lands the same state
|
|
205
|
+
conduyt_bulk_update_contacts: row("Bulk Update Contacts", false, true, true), // same consent fields per row as bulk edit; state-predicated switches, a repeat lands the same state
|
|
206
|
+
conduyt_bulk_delete_contacts: destroy("Bulk Delete Contacts"),
|
|
207
|
+
conduyt_bulk_delete_contacts_matching: destroy("Bulk Delete Contacts Matching"),
|
|
208
|
+
conduyt_bulk_dnc_contacts: row("Bulk Set Do Not Contact", false, true, true), // action "remove" tombstones suppression rows (re-enables outreach); add skips rows already suppressed and remove matches only removedAt null, so a repeat changes nothing
|
|
209
|
+
conduyt_bulk_edit_deals: row("Bulk Edit Deals", false, false, false), // a stage-only update to the existing won/lost stage assigns a fresh wonAt/lostAt on every call (app/api/v1/bulk/deals/edit/route.ts:216-233)
|
|
210
|
+
conduyt_bulk_update_deals: row("Bulk Update Deals", false, false, false), // a stage-only update to the existing won/lost stage assigns a fresh wonAt/lostAt on every call (app/api/v1/bulk/deals/update/route.ts:195-212)
|
|
211
|
+
conduyt_import_preflight: ro("Check Contact Import Before Running"),
|
|
212
|
+
conduyt_create_batch_operation: row("Create Batch Operation", false, true, false),
|
|
213
|
+
conduyt_list_batch_operations: ro("List Batch Operations"),
|
|
214
|
+
conduyt_get_batch_operation: ro("Get Batch Operation"),
|
|
215
|
+
conduyt_cancel_batch_operation: destroy("Cancel Batch Operation"),
|
|
216
|
+
conduyt_list_dnc: ro("List DNC"),
|
|
217
|
+
conduyt_add_dnc: update("Add DNC"),
|
|
218
|
+
conduyt_remove_dnc: destroy("Remove DNC"),
|
|
219
|
+
conduyt_list_saved_filters: ro("List Saved Filters"),
|
|
220
|
+
conduyt_create_saved_filter: create("Create Saved Filter"),
|
|
221
|
+
conduyt_update_saved_filter: update("Update Saved Filter"),
|
|
222
|
+
conduyt_delete_saved_filter: destroy("Delete Saved Filter"),
|
|
223
|
+
conduyt_list_drip_campaigns: ro("List Drip Campaigns"),
|
|
224
|
+
conduyt_get_drip_campaign: ro("Get Drip Campaign"),
|
|
225
|
+
conduyt_create_drip_campaign: create("Create Drip Campaign"),
|
|
226
|
+
conduyt_update_drip_campaign: update("Update Drip Campaign"),
|
|
227
|
+
conduyt_list_drip_enrollments: ro("List Drip Enrollments"),
|
|
228
|
+
conduyt_batch_pause_enrollments: update("Pause Drip Enrollments in Bulk"),
|
|
229
|
+
conduyt_batch_resume_enrollments: update("Resume Drip Enrollments in Bulk"),
|
|
230
|
+
conduyt_batch_stop_enrollments: destroy("Stop Drip Enrollments in Bulk"),
|
|
231
|
+
conduyt_cancel_drip_enrollment_barrier: row("Cancel Drip Enrollment Send Barrier", false, true, false),
|
|
232
|
+
conduyt_list_scoring_rules: ro("List Scoring Rules"),
|
|
233
|
+
conduyt_create_scoring_rule: create("Create Scoring Rule"),
|
|
234
|
+
conduyt_update_scoring_rule: row("Update Scoring Rule", false, false, false), // queues a recalculation on every update (scoring-rules/[id]/route.ts:78-87; data-model-jobs.ts:133-165)
|
|
235
|
+
conduyt_delete_scoring_rule: destroy("Delete Scoring Rule"),
|
|
236
|
+
conduyt_recalculate_scores: row("Recalculate Scores", false, false, false), // after a prior job completes the same call creates another job (data-model-jobs.ts:133)
|
|
237
|
+
conduyt_list_products: ro("List Products"),
|
|
238
|
+
conduyt_get_product: ro("Get Product"),
|
|
239
|
+
conduyt_create_product: create("Create Product"),
|
|
240
|
+
conduyt_update_product: update("Update Product"),
|
|
241
|
+
conduyt_list_templates: ro("List Templates"),
|
|
242
|
+
conduyt_get_template: ro("Get Template"),
|
|
243
|
+
conduyt_create_template: create("Create Template"),
|
|
244
|
+
conduyt_update_template: update("Update Template"),
|
|
245
|
+
conduyt_dashboard: ro("Get CRM Dashboard Summary"),
|
|
246
|
+
conduyt_ai_compose_email: ro("Compose Email With AI"),
|
|
247
|
+
conduyt_ai_enrich_contact: ro("Enrich Contact With AI"),
|
|
248
|
+
conduyt_ai_summarize_contact: ro("Summarize Contact With AI"),
|
|
249
|
+
conduyt_ai_chat: ro("Chat With AI Assistant"),
|
|
250
|
+
conduyt_ai_improve_email: ro("Improve Email With AI"),
|
|
251
|
+
conduyt_ai_deal_insights: ro("Get AI Deal Insights"),
|
|
252
|
+
conduyt_ai_conversation_intelligence: create("Analyze Conversation With AI"),
|
|
253
|
+
conduyt_ai_call_disposition: ro("Suggest Call Disposition"),
|
|
254
|
+
conduyt_ai_agenda: ro("Get AI Agenda"),
|
|
255
|
+
conduyt_ai_plan_actions: ro("Plan Copilot Actions"),
|
|
256
|
+
conduyt_ai_execute_actions: create("Execute Copilot Actions"),
|
|
257
|
+
conduyt_reply_suggestion: ro("Get Suggested Reply"),
|
|
258
|
+
conduyt_reply_suggestion_decide: row("Record Suggested Reply Decision", false, true, true), // final decision: dismissed and sent cannot be reversed; a repeat is refused before any further write (message-insights.ts:480), so idempotent
|
|
259
|
+
conduyt_ai_daily_brief: ro("Get AI Daily Brief"),
|
|
260
|
+
conduyt_ai_next_actions: ro("Get AI Next Actions"),
|
|
261
|
+
conduyt_ai_feed: ro("Get AI Feed"),
|
|
262
|
+
conduyt_ai_usage: ro("Get AI Usage"),
|
|
263
|
+
conduyt_ai_task_import_and_enroll: ro("Preview AI Import and Enroll"),
|
|
264
|
+
conduyt_ai_task_segment_and_act: ro("Preview AI Segment and Act"),
|
|
265
|
+
conduyt_ai_task_pipeline_cleanup: ro("Preview AI Pipeline Cleanup"),
|
|
266
|
+
conduyt_workflow_validate: ro("Validate Workflow"),
|
|
267
|
+
conduyt_workflow_simulate: ro("Simulate Workflow"),
|
|
268
|
+
conduyt_workflow_promote: row("Validate and Publish Workflow", false, false, false), // each repeat can publish another numbered version (automations/[id]/publish/route.ts:218,291)
|
|
269
|
+
conduyt_export_contact_data: create("Export Contact Data"),
|
|
270
|
+
conduyt_forget_contact: destroy("Erase Contact (GDPR)"),
|
|
271
|
+
conduyt_list_smart_views: ro("List Smart Views"),
|
|
272
|
+
conduyt_update_smart_view_dialing: update("Update Smart View Dialing"),
|
|
273
|
+
conduyt_get_smart_dialing_order: ro("Get Smart Dialing Order"),
|
|
274
|
+
conduyt_set_smart_dialing_order: update("Set Smart Dialing Order"),
|
|
275
|
+
conduyt_set_smart_view_audience: row("Set Smart View Audience", false, false, false), // the tool always sends members (src/tools/smart-views.ts:135); app/api/v1/smart-views/[id]/route.ts:254-279 rewrites the audience on every call
|
|
276
|
+
conduyt_reorder_smart_views: update("Reorder Smart Views"),
|
|
277
|
+
conduyt_move_smart_view: update("Move Smart View"),
|
|
278
|
+
conduyt_scheduled_export_get_settings: ro("Get Scheduled Export Settings"),
|
|
279
|
+
conduyt_scheduled_export_update_settings: update("Update Scheduled Export Settings"),
|
|
280
|
+
conduyt_account_exports_list: ro("List Account Exports"),
|
|
281
|
+
conduyt_get_lifecycle_settings: ro("Get Lifecycle Settings"),
|
|
282
|
+
conduyt_update_intake_deals: update("Update Intake Deals Setting"),
|
|
283
|
+
conduyt_update_deal_working_mode: update("Update Deal Working Mode"),
|
|
284
|
+
conduyt_update_lost_propagation: update("Update Lost Propagation Setting"),
|
|
285
|
+
conduyt_update_booking_creates_own_card: update("Update Booking Creates Own Card Setting"),
|
|
286
|
+
conduyt_update_disposition_status_map: update("Update Disposition Status Map"),
|
|
287
|
+
conduyt_get_agent_statuses: ro("Get Agent Statuses"),
|
|
288
|
+
conduyt_update_agent_statuses: update("Update Agent Statuses"),
|
|
289
|
+
conduyt_update_master_statuses: update("Update Master Statuses"),
|
|
290
|
+
conduyt_list_pool_filter_sets: ro("List Pool Filter Sets"),
|
|
291
|
+
conduyt_create_pool_filter_set: create("Create Pool Filter Set"),
|
|
292
|
+
conduyt_update_pool_filter_set: update("Update Pool Filter Set"),
|
|
293
|
+
conduyt_delete_pool_filter_set: destroy("Delete Pool Filter Set"),
|
|
294
|
+
conduyt_get_lead_pool_settings: ro("Get Lead Pool Settings"),
|
|
295
|
+
conduyt_update_lead_pool_settings: update("Update Lead Pool Settings"),
|
|
296
|
+
conduyt_list_up_for_grabs: ro("List Up for Grabs Leads"),
|
|
297
|
+
conduyt_reply_capture_get: row("Get Reply Capture", false, true, false), // reconciliation can move a live domain to degraded, which retires it permanently; the outcome depends on provider state at call time
|
|
298
|
+
conduyt_reply_capture_setup: update("Set Up Reply Capture"),
|
|
299
|
+
conduyt_reply_capture_verify: row("Verify Reply Capture", false, false, false), // kicks provider verification; a later identical poll can promote the domain (email-domains/reply-capture/verify/route.ts:96)
|
|
300
|
+
conduyt_reply_capture_remove: destroy("Remove Reply Capture"),
|
|
301
|
+
conduyt_list_call_flows: ro("List Call Flows"),
|
|
302
|
+
conduyt_get_call_flow: ro("Get Call Flow"),
|
|
303
|
+
conduyt_create_call_flow: create("Create Call Flow"),
|
|
304
|
+
conduyt_update_call_flow: update("Update Call Flow"),
|
|
305
|
+
conduyt_delete_call_flow: destroy("Delete Call Flow"),
|
|
306
|
+
conduyt_validate_call_flow: ro("Validate Call Flow"),
|
|
307
|
+
conduyt_publish_call_flow: update("Publish Call Flow"),
|
|
308
|
+
conduyt_unpublish_call_flow: update("Unpublish Call Flow"),
|
|
309
|
+
conduyt_simulate_call_flow: ro("Simulate Call Flow"),
|
|
310
|
+
conduyt_call_flow_roster: ro("Get Call Flow Roster"),
|
|
311
|
+
conduyt_list_ring_groups: ro("List Ring Groups"),
|
|
312
|
+
conduyt_get_ring_group: ro("Get Ring Group"),
|
|
313
|
+
conduyt_create_ring_group: create("Create Ring Group"),
|
|
314
|
+
conduyt_update_ring_group: update("Update Ring Group"),
|
|
315
|
+
conduyt_delete_ring_group: destroy("Delete Ring Group"),
|
|
316
|
+
conduyt_release_ring_group_number: destroy("Release Ring Group Number"),
|
|
317
|
+
conduyt_list_call_flow_numbers: ro("List Call Flow Numbers"),
|
|
318
|
+
conduyt_get_call_flow_wiring: ro("Get Call Flow Wiring"),
|
|
319
|
+
conduyt_wire_call_flow_number: update("Wire Call Flow Number"),
|
|
320
|
+
conduyt_release_call_flow_tombstone: destroy("Release Call Flow Tombstone"),
|
|
321
|
+
conduyt_upload_call_flow_audio: create("Upload Call Flow Audio"),
|
|
322
|
+
conduyt_list_call_flow_functions: ro("List Call Flow Functions"),
|
|
323
|
+
conduyt_create_call_flow_function: create("Create Call Flow Function"),
|
|
324
|
+
conduyt_update_call_flow_function: row("Update Call Flow Function", false, true, true), // a new secret revokes the old signing credential; the secret is caller-supplied and the PATCH is a pure set, so a repeat of the same body lands the same state
|
|
325
|
+
conduyt_delete_call_flow_function: destroy("Delete Call Flow Function"),
|
|
326
|
+
conduyt_test_call_flow_function: create("Test Call Flow Function"),
|
|
327
|
+
conduyt_project_blue_status: ro("Project Blue Status"),
|
|
328
|
+
conduyt_project_blue_lines: ro("Project Blue Lines"),
|
|
329
|
+
conduyt_project_blue_assign_line: row("Assign Project Blue Line", false, false, false), // lib/project-blue-lines.ts:186-195 deletes the current same-line/same-user assignment and creates a new row (new UUID, lastInboundSyncAt cleared) on every identical call
|
|
330
|
+
conduyt_project_blue_voice_status: ro("Project Blue Voice Status"),
|
|
331
|
+
conduyt_project_blue_voice_connect: row("Connect or Disconnect Project Blue Voice", false, true, false), // rewrites health timestamps and reopens unreconcilable vendor calls (project-blue-voice.ts:146, settings/project-blue/voice/route.ts:100)
|
|
332
|
+
conduyt_whatsapp_status: ro("WhatsApp Status"),
|
|
333
|
+
conduyt_whatsapp_senders: ro("WhatsApp Senders"),
|
|
334
|
+
conduyt_whatsapp_connect: destroy("Connect or Disconnect WhatsApp"),
|
|
335
|
+
conduyt_fromk_status: ro("FromK.ai Status"),
|
|
336
|
+
conduyt_fromk_lines: row("FromK.ai Lines", false, false, false), // persists a provider-dependent line snapshot (fromk-transport.ts:110)
|
|
337
|
+
conduyt_fromk_connect: row("Connect or Disconnect FromK.ai", false, true, false), // even the same key refreshes lines and deletes all contact links (fromk-transport.ts:87)
|
|
338
|
+
conduyt_fromk_webhook_secret: destroy("Set or Clear FromK.ai Webhook Secret"),
|
|
339
|
+
conduyt_zoom_status: ro("Zoom Status"),
|
|
340
|
+
conduyt_zoom_connect: destroy("Connect or Disconnect Zoom"),
|
|
341
|
+
conduyt_zoom_test: ro("Test Zoom Connection"),
|
|
342
|
+
conduyt_list_booking_pages: ro("List Booking Pages"),
|
|
343
|
+
conduyt_get_booking_page: ro("Get Booking Page"),
|
|
344
|
+
conduyt_create_booking_page: create("Create Booking Page"),
|
|
345
|
+
conduyt_update_booking_page: row("Update Booking Page", false, true, true), // owner transfer clears the iCal feed token (booking-pages/[id]/route.ts:266); the tool no longer offers enableIcalFeed (the route refuses it for API-key calls, #401), so a repeat lands the same state
|
|
346
|
+
conduyt_report_fields: ro("Report Fields"),
|
|
347
|
+
conduyt_list_reports: ro("List Reports"),
|
|
348
|
+
conduyt_create_report: create("Create Report"),
|
|
349
|
+
conduyt_run_report: create("Run Saved Report"),
|
|
350
|
+
conduyt_preview_report: ro("Preview Report"),
|
|
351
|
+
conduyt_update_report: update("Update Report"),
|
|
352
|
+
conduyt_export_report: create("Export Report File"),
|
|
353
|
+
conduyt_list_report_schedules: ro("List Report Schedules"),
|
|
354
|
+
conduyt_create_report_schedule: create("Create Report Schedule"),
|
|
355
|
+
conduyt_update_report_schedule: row("Update Report Schedule", false, false, false), // nextRunAt recomputed from now, slotAt/retryCount reset on any schedule field (reports/subscriptions/[sid]/route.ts:64-79)
|
|
356
|
+
conduyt_delete_report_schedule: destroy("Delete Report Schedule"),
|
|
357
|
+
conduyt_send_report_schedule_now: create("Send Report Schedule Now"),
|
|
358
|
+
conduyt_report_schedule_deliveries: ro("Report Schedule Deliveries"),
|
|
359
|
+
conduyt_list_dashboards: ro("List Dashboards"),
|
|
360
|
+
conduyt_create_dashboard: create("Create Dashboard"),
|
|
361
|
+
conduyt_get_dashboard: ro("Get Dashboard"),
|
|
362
|
+
conduyt_update_dashboard: update("Update Dashboard"),
|
|
363
|
+
conduyt_delete_dashboard: destroy("Delete Dashboard"),
|
|
364
|
+
conduyt_add_dashboard_tile: create("Add Dashboard Tile"),
|
|
365
|
+
conduyt_update_dashboard_tile: update("Update Dashboard Tile"),
|
|
366
|
+
conduyt_remove_dashboard_tile: destroy("Remove Dashboard Tile"),
|
|
367
|
+
conduyt_run_dashboard: ro("Run Dashboard"),
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Wraps server.tool so each tool registered afterwards gets its title and annotations from TOOL_ANNOTATIONS. The registered
|
|
371
|
+
* tool object is mutated in place (the same object strictInput() already swaps the input schema on), so the rest of each
|
|
372
|
+
* tool's registration is untouched. A tool with no row throws at registration.
|
|
373
|
+
*/
|
|
374
|
+
export function annotateRegistrations(server) {
|
|
375
|
+
const original = server.tool.bind(server);
|
|
376
|
+
server.tool = (name, ...rest) => {
|
|
377
|
+
const a = TOOL_ANNOTATIONS[name];
|
|
378
|
+
if (!a)
|
|
379
|
+
throw new Error(`tool ${name} has no row in src/tool-annotations.ts: add a title and its four MCP hints`);
|
|
380
|
+
const registered = original(name, ...rest);
|
|
381
|
+
const { title, ...hints } = a;
|
|
382
|
+
registered.title = title;
|
|
383
|
+
registered.annotations = { title, ...hints };
|
|
384
|
+
return registered;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ConduytClient } from "../client.js";
|
|
3
3
|
/** (card ownership per lane, app 10-08/09) the action options an agent can set; the catalog does not carry action config, so this is the one place they are documented */
|
|
4
|
-
export declare const CARD_OWNERSHIP_ACTIONS_NOTE = " Card ownership per lane: assign_to_user config {userId | userIds (round robin) | groupId, target|applyTo: contact|deal|both, overwriteExisting, laneSource, lanePipelineId, laneStageId}: laneSource names a card lane (the Deal.source its Auto-Create step wrote, e.g. 'GSM', max 500 chars) and makes the deal leg assign the contact's newest OPEN card from that lane (inside lanePipelineId when set) instead of the run's deal; when the contact has none and lanePipelineId is set, the card is created there (laneStageId, else the pipeline's first stage) already owned by the user; lanePipelineId or laneStageId without laneSource, or laneStageId without lanePipelineId, is refused; a lane never applies to an 'Assign to: contact' step. create_deal config {pipelineId (required), stageId, dealName, dealValue, allowDuplicates, status, source, assignedTo, leaveUnassigned}: leaveUnassigned true leaves the card unassigned when no assignee is set (default false: the card goes to the lead's owner). close_other_open_deals config {lostReason (required)}: closes the contact's OTHER open cards as lost with that reason, keeping the run's own card (each moves to its pipeline's lost stage with the usual stage-change effects; cards already won/lost, in the DPP Post-Close pipeline or in a pipeline with no lost stage are skipped; a re-run closes nothing twice); it needs the run's own deal, so use a deal trigger or a find_opportunity step first.";
|
|
4
|
+
export declare const CARD_OWNERSHIP_ACTIONS_NOTE = " Card ownership per lane: assign_to_user config {userId | userIds (round robin) | groupId, mode (single | round_robin | trigger_host), target|applyTo: contact|deal|both, overwriteExisting, laneSource, lanePipelineId, laneStageId}: laneSource names a card lane (the Deal.source its Auto-Create step wrote, e.g. 'GSM', max 500 chars) and makes the deal leg assign the contact's newest OPEN card from that lane (inside lanePipelineId when set) instead of the run's deal; when the contact has none and lanePipelineId is set, the card is created there (laneStageId, else the pipeline's first stage) already owned by the user; lanePipelineId or laneStageId without laneSource, or laneStageId without lanePipelineId, is refused; a lane never applies to an 'Assign to: contact' step. assign_to_user mode 'trigger_host' assigns to the appointment's booked host (appointment.booked runs only; fails closed when the run has no host). create_deal config {pipelineId (required), stageId, dealName, dealValue, allowDuplicates, status, source, assignedTo, assigneeMode, leaveUnassigned}: leaveUnassigned true leaves the card unassigned when no assignee is set (default false: the card goes to the lead's owner). assigneeMode 'trigger_host' assigns the card to the appointment's booked host (appointment.booked runs only; wins over assignedTo; fails closed when the run has no host, creating nothing). The condition field 'Booked host' (trigger.hostUserId) exists on appointment.booked, whose payload now carries hostUserId. close_other_open_deals config {lostReason (required)}: closes the contact's OTHER open cards as lost with that reason, keeping the run's own card (each moves to its pipeline's lost stage with the usual stage-change effects; cards already won/lost, in the DPP Post-Close pipeline or in a pipeline with no lost stage are skipped; a re-run closes nothing twice); it needs the run's own deal, so use a deal trigger or a find_opportunity step first.";
|
|
5
5
|
/** (deal nodes, app 10-13) find_opportunity v2, link_appointment_to_deal, update_deal_field systemField source; the catalog does not carry action config */
|
|
6
6
|
export declare const DEAL_NODES_ACTIONS_NOTE = " Deal nodes: find_opportunity config {version: 2, pipelineIds (ordered; the first pipeline holding a match wins; empty = every pipeline), status (open default | won | lost | abandoned | any), excludeSources (lead sources never matched, case-insensitive), excludeCreatedByAutomationIds (automations whose create_deal cards are skipped; cards created from 2026-10-13 on), matchField {fieldKey, value} (searches the WHOLE WORKSPACE, any contact, for the card whose deal custom field equals the value, merge fields allowed e.g. {{trigger.oes}}; a card is found when its field holds the searched value (trimmed) as the same text exactly (no case folding); a value written with separators such as dashes or spaces also matches its digits as text; it matches a stored number only when the value (or those digits) is a plain number with no leading zero and at most 15 significant digits that a number holds exactly (007 is text and does not match the number 7; a 16-digit value, 1e-400 or 3e-324 is text only); booleans and differently formatted stored values never match; status, pipelines and exclusions still apply; exactly one match is found, several are ambiguous and take not found; a found card becomes the run's contact when the run has none; the field must exist; an empty rendered value finds nothing), resolution}: searches the run's contact's cards; FOUND makes the card the run's deal and follows nextIfTrue (else next), NOT FOUND is a normal outcome that follows nextIfFalse (else next) and leaves the run's existing deal unchanged (a later deal step on the false branch still acts on the deal the run already had); without version 2 the step keeps the original single-pipeline lookup (a miss fails the step). Prerequisite: a version 2 find needs step cursors on this workspace, and publishing refuses (find_needs_step_cursors) with \"Find opportunity needs step cursors on this workspace; ask support\"; every version 2 find must hold its own live step cursor or it hard-stops the run without selecting or routing. A version 2 find cannot be retried on its own: retrying a failed one alone answers 409, so re-trigger the automation for the contact. An automation definition that touches deals needs the `deals` scope on an API key: without it the write answers 403. link_appointment_to_deal config {stageId, pipelineId (needs stageId), lostReason}: in an appointment-triggered run, links the trigger's appointment to the run's deal (its appointment fields follow it; a newer booking is never displaced; the appointment must be the deal's contact's), then optionally moves the card; it needs an appointment trigger and the run's deal (find_opportunity first, or a booking made with a deal id). update_deal_field config {systemField: \"source\", value, overwriteExisting}: sets the deal's own lead source instead of a custom field (a value only, trimmed, at most 500 characters; overwriteExisting false writes only while the source is the Unknown label).";
|
|
7
7
|
/** (#124, automation unknown keys / types) the refusal codes the write paths answer; surfaced verbatim by the client (details JSON object last), never retried */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult, formatToolError } from "../client.js";
|
|
3
3
|
/** (card ownership per lane, app 10-08/09) the action options an agent can set; the catalog does not carry action config, so this is the one place they are documented */
|
|
4
|
-
export const CARD_OWNERSHIP_ACTIONS_NOTE = " Card ownership per lane: assign_to_user config {userId | userIds (round robin) | groupId, target|applyTo: contact|deal|both, overwriteExisting, laneSource, lanePipelineId, laneStageId}: laneSource names a card lane (the Deal.source its Auto-Create step wrote, e.g. 'GSM', max 500 chars) and makes the deal leg assign the contact's newest OPEN card from that lane (inside lanePipelineId when set) instead of the run's deal; when the contact has none and lanePipelineId is set, the card is created there (laneStageId, else the pipeline's first stage) already owned by the user; lanePipelineId or laneStageId without laneSource, or laneStageId without lanePipelineId, is refused; a lane never applies to an 'Assign to: contact' step. create_deal config {pipelineId (required), stageId, dealName, dealValue, allowDuplicates, status, source, assignedTo, leaveUnassigned}: leaveUnassigned true leaves the card unassigned when no assignee is set (default false: the card goes to the lead's owner). close_other_open_deals config {lostReason (required)}: closes the contact's OTHER open cards as lost with that reason, keeping the run's own card (each moves to its pipeline's lost stage with the usual stage-change effects; cards already won/lost, in the DPP Post-Close pipeline or in a pipeline with no lost stage are skipped; a re-run closes nothing twice); it needs the run's own deal, so use a deal trigger or a find_opportunity step first.";
|
|
4
|
+
export const CARD_OWNERSHIP_ACTIONS_NOTE = " Card ownership per lane: assign_to_user config {userId | userIds (round robin) | groupId, mode (single | round_robin | trigger_host), target|applyTo: contact|deal|both, overwriteExisting, laneSource, lanePipelineId, laneStageId}: laneSource names a card lane (the Deal.source its Auto-Create step wrote, e.g. 'GSM', max 500 chars) and makes the deal leg assign the contact's newest OPEN card from that lane (inside lanePipelineId when set) instead of the run's deal; when the contact has none and lanePipelineId is set, the card is created there (laneStageId, else the pipeline's first stage) already owned by the user; lanePipelineId or laneStageId without laneSource, or laneStageId without lanePipelineId, is refused; a lane never applies to an 'Assign to: contact' step. assign_to_user mode 'trigger_host' assigns to the appointment's booked host (appointment.booked runs only; fails closed when the run has no host). create_deal config {pipelineId (required), stageId, dealName, dealValue, allowDuplicates, status, source, assignedTo, assigneeMode, leaveUnassigned}: leaveUnassigned true leaves the card unassigned when no assignee is set (default false: the card goes to the lead's owner). assigneeMode 'trigger_host' assigns the card to the appointment's booked host (appointment.booked runs only; wins over assignedTo; fails closed when the run has no host, creating nothing). The condition field 'Booked host' (trigger.hostUserId) exists on appointment.booked, whose payload now carries hostUserId. close_other_open_deals config {lostReason (required)}: closes the contact's OTHER open cards as lost with that reason, keeping the run's own card (each moves to its pipeline's lost stage with the usual stage-change effects; cards already won/lost, in the DPP Post-Close pipeline or in a pipeline with no lost stage are skipped; a re-run closes nothing twice); it needs the run's own deal, so use a deal trigger or a find_opportunity step first.";
|
|
5
5
|
/** (deal nodes, app 10-13) find_opportunity v2, link_appointment_to_deal, update_deal_field systemField source; the catalog does not carry action config */
|
|
6
6
|
export const DEAL_NODES_ACTIONS_NOTE = " Deal nodes: find_opportunity config {version: 2, pipelineIds (ordered; the first pipeline holding a match wins; empty = every pipeline), status (open default | won | lost | abandoned | any), excludeSources (lead sources never matched, case-insensitive), excludeCreatedByAutomationIds (automations whose create_deal cards are skipped; cards created from 2026-10-13 on), matchField {fieldKey, value} (searches the WHOLE WORKSPACE, any contact, for the card whose deal custom field equals the value, merge fields allowed e.g. {{trigger.oes}}; a card is found when its field holds the searched value (trimmed) as the same text exactly (no case folding); a value written with separators such as dashes or spaces also matches its digits as text; it matches a stored number only when the value (or those digits) is a plain number with no leading zero and at most 15 significant digits that a number holds exactly (007 is text and does not match the number 7; a 16-digit value, 1e-400 or 3e-324 is text only); booleans and differently formatted stored values never match; status, pipelines and exclusions still apply; exactly one match is found, several are ambiguous and take not found; a found card becomes the run's contact when the run has none; the field must exist; an empty rendered value finds nothing), resolution}: searches the run's contact's cards; FOUND makes the card the run's deal and follows nextIfTrue (else next), NOT FOUND is a normal outcome that follows nextIfFalse (else next) and leaves the run's existing deal unchanged (a later deal step on the false branch still acts on the deal the run already had); without version 2 the step keeps the original single-pipeline lookup (a miss fails the step). Prerequisite: a version 2 find needs step cursors on this workspace, and publishing refuses (find_needs_step_cursors) with \"Find opportunity needs step cursors on this workspace; ask support\"; every version 2 find must hold its own live step cursor or it hard-stops the run without selecting or routing. A version 2 find cannot be retried on its own: retrying a failed one alone answers 409, so re-trigger the automation for the contact. An automation definition that touches deals needs the `deals` scope on an API key: without it the write answers 403. link_appointment_to_deal config {stageId, pipelineId (needs stageId), lostReason}: in an appointment-triggered run, links the trigger's appointment to the run's deal (its appointment fields follow it; a newer booking is never displaced; the appointment must be the deal's contact's), then optionally moves the card; it needs an appointment trigger and the run's deal (find_opportunity first, or a booking made with a deal id). update_deal_field config {systemField: \"source\", value, overwriteExisting}: sets the deal's own lead source instead of a custom field (a value only, trimmed, at most 500 characters; overwriteExisting false writes only while the source is the Unknown label).";
|
|
7
7
|
/** (#124, automation unknown keys / types) the refusal codes the write paths answer; surfaced verbatim by the client (details JSON object last), never retried */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult } from "../client.js";
|
|
3
|
+
import { strictInput } from "./strict.js";
|
|
3
4
|
/**
|
|
4
5
|
* Booking pages (Conduyt #72, 2026-09-15): the public scheduling pages. Until now an AI operator could read appointments
|
|
5
6
|
* but not the pages that create them; these tools cover the page itself and its video option (videoProvider "zoom" =
|
|
@@ -67,7 +68,6 @@ const updateOnlyFields = {
|
|
|
67
68
|
gdprText: z.string().max(2000).nullable().optional(),
|
|
68
69
|
gdprLinkUrl: z.string().url().nullable().optional(),
|
|
69
70
|
waitlistEnabled: z.boolean().optional(),
|
|
70
|
-
enableIcalFeed: z.boolean().optional().describe("true issues a new iCal feed token, false revokes it"),
|
|
71
71
|
};
|
|
72
72
|
export function registerBookingPageTools(server, client) {
|
|
73
73
|
server.tool("conduyt_list_booking_pages", "List the account's booking pages (GET /api/v1/booking-pages): slug, title, host, duration, active, video option. Requires calendar:view.", { activeOnly: z.boolean().optional().describe("only pages accepting bookings") }, async ({ activeOnly }) => {
|
|
@@ -78,12 +78,12 @@ export function registerBookingPageTools(server, client) {
|
|
|
78
78
|
const result = await client.get(`/api/v1/booking-pages/${id}`);
|
|
79
79
|
return formatResult(result);
|
|
80
80
|
});
|
|
81
|
-
server.tool("conduyt_create_booking_page", "Create a booking page (POST /api/v1/booking-pages): title, slug, userId (host) and durationMinutes at least; optional written location, videoProvider 'zoom' + videoHostEmail for one Zoom meeting per booking, availabilityRules override, embedAllowedOrigins, leadSource, brandName. Requires calendar:edit (admin/owner).", { ...pageFields, title: z.string().min(1).max(200), slug: z.string().min(1).max(100), userId: z.string().uuid(), durationMinutes: z.number().int().min(5).max(480) }, async (params) => {
|
|
81
|
+
strictInput(server.tool("conduyt_create_booking_page", "Create a booking page (POST /api/v1/booking-pages): title, slug, userId (host) and durationMinutes at least; optional written location, videoProvider 'zoom' + videoHostEmail for one Zoom meeting per booking, availabilityRules override, embedAllowedOrigins, leadSource, brandName. Requires calendar:edit (admin/owner).", { ...pageFields, title: z.string().min(1).max(200), slug: z.string().min(1).max(100), userId: z.string().uuid(), durationMinutes: z.number().int().min(5).max(480) }, async (params) => {
|
|
82
82
|
const result = await client.post("/api/v1/booking-pages", params);
|
|
83
83
|
return formatResult(result);
|
|
84
|
-
});
|
|
85
|
-
server.tool("conduyt_update_booking_page", "Update a booking page (PATCH /api/v1/booking-pages/{id}): only the fields given change. videoProvider 'zoom' turns on one Zoom meeting per booking (null turns it off and clears the host); videoHostEmail must be a user of the connected Zoom account (null = the app's own user). Requires calendar:edit (admin/owner).", { id: z.string().uuid().describe("booking page UUID"), ...pageFields, ...updateOnlyFields }, async ({ id, ...updates }) => {
|
|
84
|
+
}));
|
|
85
|
+
strictInput(server.tool("conduyt_update_booking_page", "Update a booking page (PATCH /api/v1/booking-pages/{id}): only the fields given change. videoProvider 'zoom' turns on one Zoom meeting per booking (null turns it off and clears the host); videoHostEmail must be a user of the connected Zoom account (null = the app's own user). The iCal feed token cannot be issued or revoked through the API; the page owner does that in the app. Requires calendar:edit (admin/owner).", { id: z.string().uuid().describe("booking page UUID"), ...pageFields, ...updateOnlyFields }, async ({ id, ...updates }) => {
|
|
86
86
|
const result = await client.patch(`/api/v1/booking-pages/${id}`, updates);
|
|
87
87
|
return formatResult(result);
|
|
88
|
-
});
|
|
88
|
+
}));
|
|
89
89
|
}
|
package/package.json
CHANGED