@elitedcs/ghl-mcp 3.83.0 → 3.83.2
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/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/dist/index.js +136 -88
- package/package.json +2 -6
- package/skills/blueprint/README.md +5 -3
- package/skills/blueprint/SKILL.md +6 -6
- package/src/command-os/design/rules/check-static.mjs +0 -238
- package/src/command-os/design/rules/fixtures/claude-default.html +0 -55
- package/src/command-os/design/rules/fixtures/external-css.html +0 -7
- package/src/command-os/design/rules/fixtures/generator-run-1.html +0 -31
- package/src/command-os/design/rules/fixtures/house-clean.html +0 -59
package/dist/index.js
CHANGED
|
@@ -241,7 +241,7 @@ function foldCredentialsIntoEnv(creds, env = process.env) {
|
|
|
241
241
|
];
|
|
242
242
|
for (const [credKey, envKey] of mappings) {
|
|
243
243
|
const value = creds[credKey];
|
|
244
|
-
if (value && !env[envKey]) {
|
|
244
|
+
if (typeof value === "string" && value && !env[envKey]) {
|
|
245
245
|
env[envKey] = value;
|
|
246
246
|
}
|
|
247
247
|
}
|
|
@@ -740,13 +740,13 @@ var init_token_registry = __esm({
|
|
|
740
740
|
name: import_zod2.z.string().optional()
|
|
741
741
|
});
|
|
742
742
|
TokenRegistryDataSchema = import_zod2.z.object({
|
|
743
|
-
tokens: import_zod2.z.record(LocationTokenSchema),
|
|
743
|
+
tokens: import_zod2.z.record(import_zod2.z.string(), LocationTokenSchema),
|
|
744
744
|
agencyKey: import_zod2.z.string().optional(),
|
|
745
745
|
// "Home" Firebase — the company the install was set up for (credentials.json).
|
|
746
746
|
firebase: FirebaseConfigSchema.optional(),
|
|
747
747
|
// Additional companies' Firebase auth, keyed by GHL companyId. Lets ONE
|
|
748
748
|
// process operate the workflow builder across multiple clients' GHL accounts.
|
|
749
|
-
firebaseByCompany: import_zod2.z.record(CompanyFirebaseSchema).optional()
|
|
749
|
+
firebaseByCompany: import_zod2.z.record(import_zod2.z.string(), CompanyFirebaseSchema).optional()
|
|
750
750
|
});
|
|
751
751
|
TokenRegistry = class _TokenRegistry {
|
|
752
752
|
data;
|
|
@@ -1256,7 +1256,7 @@ var init_trigger_schemas = __esm({
|
|
|
1256
1256
|
masterType: import_zod3.z.string().optional(),
|
|
1257
1257
|
name: import_zod3.z.string().optional(),
|
|
1258
1258
|
actions: import_zod3.z.array(TriggerActionSchema).optional(),
|
|
1259
|
-
schedule_config: import_zod3.z.record(import_zod3.z.unknown()).optional(),
|
|
1259
|
+
schedule_config: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
|
|
1260
1260
|
date_updated: import_zod3.z.string().optional()
|
|
1261
1261
|
}).passthrough();
|
|
1262
1262
|
ContactTagTriggerSchema = TriggerCommonSchema.extend({
|
|
@@ -1547,7 +1547,7 @@ var init_trigger_schemas = __esm({
|
|
|
1547
1547
|
});
|
|
1548
1548
|
UnknownTriggerSchema = TriggerCommonSchema.extend({
|
|
1549
1549
|
type: import_zod3.z.string(),
|
|
1550
|
-
conditions: import_zod3.z.array(import_zod3.z.record(import_zod3.z.unknown())).optional()
|
|
1550
|
+
conditions: import_zod3.z.array(import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown())).optional()
|
|
1551
1551
|
});
|
|
1552
1552
|
WorkflowTriggerSchema = import_zod3.z.union([
|
|
1553
1553
|
ContactTagTriggerSchema,
|
|
@@ -3883,7 +3883,8 @@ function annotateListResponse(raw, listKey, limit, nextHint) {
|
|
|
3883
3883
|
};
|
|
3884
3884
|
}
|
|
3885
3885
|
function safeTool(server2, name, description, schema, handler) {
|
|
3886
|
-
|
|
3886
|
+
const toolServer = server2;
|
|
3887
|
+
toolServer.tool(name, description, schema, async (args) => {
|
|
3887
3888
|
try {
|
|
3888
3889
|
return jsonResponse(await handler(args));
|
|
3889
3890
|
} catch (error) {
|
|
@@ -5090,7 +5091,7 @@ function registerCalendarTools(server2, client) {
|
|
|
5090
5091
|
slug: import_zod12.z.string().optional().describe("Calendar slug"),
|
|
5091
5092
|
widgetSlug: import_zod12.z.string().optional().describe("Widget slug for embedding"),
|
|
5092
5093
|
calendarType: import_zod12.z.string().optional().describe("Calendar type"),
|
|
5093
|
-
teamMembers: import_zod12.z.array(import_zod12.z.record(import_zod12.z.unknown())).optional().describe("Array of team member objects"),
|
|
5094
|
+
teamMembers: import_zod12.z.array(import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown())).optional().describe("Array of team member objects"),
|
|
5094
5095
|
eventTitle: import_zod12.z.string().optional().describe("Default event title"),
|
|
5095
5096
|
eventColor: import_zod12.z.string().optional().describe("Event color hex code"),
|
|
5096
5097
|
slotDuration: import_zod12.z.number().optional().describe("Slot duration in minutes"),
|
|
@@ -5386,7 +5387,7 @@ function registerLocationTools(server2, client) {
|
|
|
5386
5387
|
timezone: import_zod13.z.string().optional().describe("IANA timezone (e.g., 'America/New_York')."),
|
|
5387
5388
|
phone: import_zod13.z.string().optional().describe("Phone number."),
|
|
5388
5389
|
email: import_zod13.z.string().optional().describe("Email address."),
|
|
5389
|
-
settings: import_zod13.z.record(import_zod13.z.unknown()).optional().describe("Location settings object with key-value pairs."),
|
|
5390
|
+
settings: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown()).optional().describe("Location settings object with key-value pairs."),
|
|
5390
5391
|
overwriteBusinessInfo: import_zod13.z.boolean().optional().describe(
|
|
5391
5392
|
"Allow a CHANGE to business details on a sub-account that already has a registered A2P brand. Off by default. Only needed when the account has a brandId AND you are changing (not filling) one of name/address/city/state/postalCode/country/phone/website/email."
|
|
5392
5393
|
)
|
|
@@ -6726,7 +6727,7 @@ function registerUserTools(server2, client, registry2) {
|
|
|
6726
6727
|
role: import_zod22.z.enum(["admin", "user"]).describe("GHL role on this sub-account. 'admin' = full settings access; 'user' = day-to-day staff (contacts, conversations, calendar, opportunities)."),
|
|
6727
6728
|
phone: import_zod22.z.string().optional().describe("Phone number (E.164 preferred)."),
|
|
6728
6729
|
password: import_zod22.z.string().min(8).optional().describe("Only if you must set one. Omit it (recommended) so GHL sends the invite instead."),
|
|
6729
|
-
permissions: import_zod22.z.record(import_zod22.z.boolean()).optional().describe("Override the default per-role permissions object entirely (GHL UserPermissions booleans)."),
|
|
6730
|
+
permissions: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.boolean()).optional().describe("Override the default per-role permissions object entirely (GHL UserPermissions booleans)."),
|
|
6730
6731
|
companyId: import_zod22.z.string().optional().describe("Agency/company id. Resolved from the registered location by default; pass it only when that lookup fails."),
|
|
6731
6732
|
locationId: import_zod22.z.string().optional().describe("Sub-account to add the user to (defaults to the active location). The user is granted access to this ONE location.")
|
|
6732
6733
|
},
|
|
@@ -7432,8 +7433,8 @@ function registerEmailTools(server2, client) {
|
|
|
7432
7433
|
);
|
|
7433
7434
|
}
|
|
7434
7435
|
function registerEmailBuilderInternalTools(server2, builderClient, publicClient) {
|
|
7436
|
+
if (!builderClient) return;
|
|
7435
7437
|
const client = builderClient;
|
|
7436
|
-
if (!client) return;
|
|
7437
7438
|
async function builderRequest(method, path39, body) {
|
|
7438
7439
|
const headers = await client.buildHeaders();
|
|
7439
7440
|
const response = await fetch(`${EMAIL_BUILDER_BASE}${path39}`, {
|
|
@@ -7712,7 +7713,7 @@ function registerCustomObjectTools(server2, client) {
|
|
|
7712
7713
|
{
|
|
7713
7714
|
schemaKey: import_zod30.z.string().describe("The custom object schema key."),
|
|
7714
7715
|
locationId: import_zod30.z.string().optional().describe("GHL Location ID. Optional if GHL_LOCATION_ID is set in env."),
|
|
7715
|
-
properties: import_zod30.z.record(import_zod30.z.unknown()).describe("Key-value pairs of field values for the new record.")
|
|
7716
|
+
properties: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown()).describe("Key-value pairs of field values for the new record.")
|
|
7716
7717
|
},
|
|
7717
7718
|
async ({ schemaKey, locationId: locationId2, properties }) => {
|
|
7718
7719
|
const resolvedLocationId = client.resolveLocationId(locationId2);
|
|
@@ -7729,7 +7730,7 @@ function registerCustomObjectTools(server2, client) {
|
|
|
7729
7730
|
schemaKey: import_zod30.z.string().describe("The custom object schema key."),
|
|
7730
7731
|
recordId: import_zod30.z.string().describe("The record ID to update."),
|
|
7731
7732
|
locationId: import_zod30.z.string().optional().describe("GHL Location ID. Optional if GHL_LOCATION_ID is set in env."),
|
|
7732
|
-
properties: import_zod30.z.record(import_zod30.z.unknown()).describe("Key-value pairs of field values to update.")
|
|
7733
|
+
properties: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown()).describe("Key-value pairs of field values to update.")
|
|
7733
7734
|
},
|
|
7734
7735
|
async ({ schemaKey, recordId, locationId: locationId2, properties }) => {
|
|
7735
7736
|
const resolvedLocationId = client.resolveLocationId(locationId2);
|
|
@@ -7990,7 +7991,7 @@ function registerEstimateTools(server2, client) {
|
|
|
7990
7991
|
price: import_zod32.z.number().describe("Unit price, in the estimate currency."),
|
|
7991
7992
|
currency: import_zod32.z.string().optional().describe("Currency code (e.g. USD).")
|
|
7992
7993
|
})).optional().describe("Updated line items. Give quantity and price; they are translated to the qty/amount/type GHL requires."),
|
|
7993
|
-
discount: import_zod32.z.record(import_zod32.z.unknown()).optional().describe("Updated discount object.")
|
|
7994
|
+
discount: import_zod32.z.record(import_zod32.z.string(), import_zod32.z.unknown()).optional().describe("Updated discount object.")
|
|
7994
7995
|
},
|
|
7995
7996
|
async ({ estimateId, locationId: locationId2, name, title: title2, items, discount }) => {
|
|
7996
7997
|
const resolvedLocationId = client.resolveLocationId(locationId2);
|
|
@@ -8769,7 +8770,7 @@ function registerConversationAiTools(server2, client) {
|
|
|
8769
8770
|
agentId: import_zod35.z.string().describe("Agent id."),
|
|
8770
8771
|
type: import_zod35.z.enum(ACTION_TYPES),
|
|
8771
8772
|
name: import_zod35.z.string().min(1).describe("Name the operator sees."),
|
|
8772
|
-
details: import_zod35.z.record(import_zod35.z.unknown()).describe("Type-specific details. humanHandOver: enabled, triggerCondition, handoverType (contactRequest|lackOfInformation|failedToResolveIssue|custom), examples[], assignToUserId, finalMessage, reactivateEnabled(+sleepTime/Unit). appointmentBooking: calendarId, onlySendLink, triggerWorkflow(+workflowIds), sleepAfterBooking(+sleepTime/Unit), transferBot(+transferAgent), rescheduleEnabled, cancelEnabled. triggerWorkflow: workflowIds[], triggerCondition, triggerMessage. stopBot: stopBotDetectionType (Goodbye|Custom), stopBotTriggerCondition, stopBotExamples[] (2+), finalMessage, enabled, reactivateEnabled, tags[]. updateContactField: contactFieldId, description, contactUpdateExamples[]. transferBot: transferBotType, transferToBot, enabled. advancedFollowup: enabled, scenarioId, followupSequence[].")
|
|
8773
|
+
details: import_zod35.z.record(import_zod35.z.string(), import_zod35.z.unknown()).describe("Type-specific details. humanHandOver: enabled, triggerCondition, handoverType (contactRequest|lackOfInformation|failedToResolveIssue|custom), examples[], assignToUserId, finalMessage, reactivateEnabled(+sleepTime/Unit). appointmentBooking: calendarId, onlySendLink, triggerWorkflow(+workflowIds), sleepAfterBooking(+sleepTime/Unit), transferBot(+transferAgent), rescheduleEnabled, cancelEnabled. triggerWorkflow: workflowIds[], triggerCondition, triggerMessage. stopBot: stopBotDetectionType (Goodbye|Custom), stopBotTriggerCondition, stopBotExamples[] (2+), finalMessage, enabled, reactivateEnabled, tags[]. updateContactField: contactFieldId, description, contactUpdateExamples[]. transferBot: transferBotType, transferToBot, enabled. advancedFollowup: enabled, scenarioId, followupSequence[].")
|
|
8773
8774
|
},
|
|
8774
8775
|
async ({ agentId, type, name, details }) => {
|
|
8775
8776
|
const problem = actionBodyProblem(type, details);
|
|
@@ -8787,7 +8788,7 @@ function registerConversationAiTools(server2, client) {
|
|
|
8787
8788
|
actionId: import_zod35.z.string().describe("Action id."),
|
|
8788
8789
|
type: import_zod35.z.enum(ACTION_TYPES),
|
|
8789
8790
|
name: import_zod35.z.string().min(1),
|
|
8790
|
-
details: import_zod35.z.record(import_zod35.z.unknown()).describe("The complete details for this type.")
|
|
8791
|
+
details: import_zod35.z.record(import_zod35.z.string(), import_zod35.z.unknown()).describe("The complete details for this type.")
|
|
8791
8792
|
},
|
|
8792
8793
|
async ({ agentId, actionId, type, name, details }) => {
|
|
8793
8794
|
const problem = actionBodyProblem(type, details);
|
|
@@ -10024,7 +10025,7 @@ function registerVoiceAiTools(server2, shared) {
|
|
|
10024
10025
|
locationId: LOCATION,
|
|
10025
10026
|
actionType: import_zod37.z.enum(VOICE_ACTION_TYPES),
|
|
10026
10027
|
name: import_zod37.z.string().min(1).describe("Name the operator sees. Letters, numbers, spaces, _ and - only."),
|
|
10027
|
-
actionParameters: import_zod37.z.record(import_zod37.z.unknown()).describe(ACTION_PARAMS_DOC)
|
|
10028
|
+
actionParameters: import_zod37.z.record(import_zod37.z.string(), import_zod37.z.unknown()).describe(ACTION_PARAMS_DOC)
|
|
10028
10029
|
},
|
|
10029
10030
|
async ({ agentId, locationId: locationId2, actionType, name, actionParameters }) => {
|
|
10030
10031
|
const client = shared.pinned();
|
|
@@ -10060,7 +10061,7 @@ function registerVoiceAiTools(server2, shared) {
|
|
|
10060
10061
|
locationId: LOCATION,
|
|
10061
10062
|
actionType: import_zod37.z.enum(VOICE_ACTION_TYPES),
|
|
10062
10063
|
name: import_zod37.z.string().min(1),
|
|
10063
|
-
actionParameters: import_zod37.z.record(import_zod37.z.unknown()).describe("The complete parameters for this type.")
|
|
10064
|
+
actionParameters: import_zod37.z.record(import_zod37.z.string(), import_zod37.z.unknown()).describe("The complete parameters for this type.")
|
|
10064
10065
|
},
|
|
10065
10066
|
async ({ agentId, actionId, locationId: locationId2, actionType, name, actionParameters }) => {
|
|
10066
10067
|
const client = shared.pinned();
|
|
@@ -10522,7 +10523,7 @@ var init_webhooks = __esm({
|
|
|
10522
10523
|
import_zod38.z.string().describe("A GHL trigger type, e.g. 'contact_created'. Fires with no filter."),
|
|
10523
10524
|
import_zod38.z.object({
|
|
10524
10525
|
type: import_zod38.z.string().describe("A GHL trigger type, e.g. 'contact_tag' or 'pipeline_stage_updated'."),
|
|
10525
|
-
conditions: import_zod38.z.array(import_zod38.z.record(import_zod38.z.unknown())).optional().describe(
|
|
10526
|
+
conditions: import_zod38.z.array(import_zod38.z.record(import_zod38.z.string(), import_zod38.z.unknown())).optional().describe(
|
|
10526
10527
|
"Filter conditions, exactly as update_workflow_actions takes them. Use get_trigger_registry to find the valid fields for a trigger type. Omit to fire on every event of that type."
|
|
10527
10528
|
)
|
|
10528
10529
|
})
|
|
@@ -10607,8 +10608,8 @@ function registerDocumentTools(server2, client) {
|
|
|
10607
10608
|
sentBy: import_zod39.z.string().optional().describe("GHL user ID of the sender (required by the API; falls back to GHL_USER_ID env)."),
|
|
10608
10609
|
documentName: import_zod39.z.string().optional().describe("Override the document name shown to recipients."),
|
|
10609
10610
|
medium: import_zod39.z.string().optional().describe("Delivery medium, e.g. 'email'. Defaults to email."),
|
|
10610
|
-
ccRecipients: import_zod39.z.array(import_zod39.z.record(import_zod39.z.unknown())).optional().describe("Optional CC recipients: [{id, email, contactName, firstName, lastName, imageUrl}]."),
|
|
10611
|
-
notificationSettings: import_zod39.z.record(import_zod39.z.unknown()).optional().describe("Optional sender/receiver notification settings: {sender:{fromName,fromEmail}, receive:{subject,templateId}}."),
|
|
10611
|
+
ccRecipients: import_zod39.z.array(import_zod39.z.record(import_zod39.z.string(), import_zod39.z.unknown())).optional().describe("Optional CC recipients: [{id, email, contactName, firstName, lastName, imageUrl}]."),
|
|
10612
|
+
notificationSettings: import_zod39.z.record(import_zod39.z.string(), import_zod39.z.unknown()).optional().describe("Optional sender/receiver notification settings: {sender:{fromName,fromEmail}, receive:{subject,templateId}}."),
|
|
10612
10613
|
locationId: import_zod39.z.string().optional().describe("GHL Location ID. Optional if GHL_LOCATION_ID is set in env.")
|
|
10613
10614
|
},
|
|
10614
10615
|
async ({ documentId, sentBy, documentName, medium, ccRecipients, notificationSettings, locationId: locationId2 }) => {
|
|
@@ -11055,7 +11056,7 @@ function registerWorkflowBuilderTools(server2, client) {
|
|
|
11055
11056
|
"invoice_paid",
|
|
11056
11057
|
"review_request_clicked"
|
|
11057
11058
|
]).describe("The goal-condition identifier. Extras shape per condition: email_event \u2192 {stepIds:[]}; link_click \u2192 {linkIds:[]}; appointment_status \u2192 {calendarId}; payment_received \u2192 {globalProductIds:[]}; form_submission \u2192 {formIds:[]}; document_status \u2192 {templateId}; invoice_paid \u2192 {invoiceStepId}; review_request_clicked \u2192 {reviewTypes:['sms'|'email'], reviewLinkId}; add_contact_tag/remove_contact_tag \u2192 {tags:[]} (uncaptured but inferred)."),
|
|
11058
|
-
extras: import_zod40.z.record(import_zod40.z.unknown()).optional().describe("Goal-condition-specific config. See goal_condition description for the expected shape per value. Pass {} or omit for goal_conditions without extras."),
|
|
11059
|
+
extras: import_zod40.z.record(import_zod40.z.string(), import_zod40.z.unknown()).optional().describe("Goal-condition-specific config. See goal_condition description for the expected shape per value. Pass {} or omit for goal_conditions without extras."),
|
|
11059
11060
|
action: import_zod40.z.enum(["exit", "continue", "wait"]).default("exit").describe("What happens when the goal fires (per GHL's GoalAction enum). 'exit' terminates the workflow path (verified). 'continue' lets it proceed to a downstream node. 'wait' pauses on the goal."),
|
|
11060
11061
|
name: import_zod40.z.string().default("Goal").describe("Display name in the GHL UI."),
|
|
11061
11062
|
op: import_zod40.z.enum(["or", "and"]).default("or").describe("Top-level boolean operator across segments. Default 'or'."),
|
|
@@ -11134,7 +11135,7 @@ var init_workflow_builder = __esm({
|
|
|
11134
11135
|
id: import_zod40.z.string().optional().describe("Action ID (auto-generated if omitted)."),
|
|
11135
11136
|
name: import_zod40.z.string().describe("Display name for this action step."),
|
|
11136
11137
|
type: import_zod40.z.string().describe("Action type."),
|
|
11137
|
-
attributes: import_zod40.z.record(import_zod40.z.unknown()).optional().describe("Action-specific configuration."),
|
|
11138
|
+
attributes: import_zod40.z.record(import_zod40.z.string(), import_zod40.z.unknown()).optional().describe("Action-specific configuration."),
|
|
11138
11139
|
next: import_zod40.z.union([import_zod40.z.string(), import_zod40.z.array(import_zod40.z.string())]).optional().describe("Next action id, or branch id array for condition nodes."),
|
|
11139
11140
|
parent: import_zod40.z.string().optional().describe("Branch parent node id."),
|
|
11140
11141
|
parentKey: import_zod40.z.string().optional().describe("Previous action id or branch parent id."),
|
|
@@ -11190,8 +11191,7 @@ var init_page_reads = __esm({
|
|
|
11190
11191
|
|
|
11191
11192
|
// src/tools/funnel-builder.ts
|
|
11192
11193
|
function registerFunnelBuilderTools(server2, builderClient) {
|
|
11193
|
-
|
|
11194
|
-
if (!client) {
|
|
11194
|
+
if (!builderClient) {
|
|
11195
11195
|
server2.tool(
|
|
11196
11196
|
"funnel_builder_status",
|
|
11197
11197
|
"Check whether the funnel / page builder is configured. It needs Firebase credentials, added via enable_workflow_builder.",
|
|
@@ -11219,6 +11219,7 @@ function registerFunnelBuilderTools(server2, builderClient) {
|
|
|
11219
11219
|
);
|
|
11220
11220
|
return;
|
|
11221
11221
|
}
|
|
11222
|
+
const client = builderClient;
|
|
11222
11223
|
async function internalGet(path39) {
|
|
11223
11224
|
return client.request("GET", path39);
|
|
11224
11225
|
}
|
|
@@ -11524,7 +11525,7 @@ ${await response.text()}`);
|
|
|
11524
11525
|
"Update a funnel/website page's builder content \u2014 sections, elements, settings, pageStyles, trackingCode, popups, popupsList, fontsForPreview. Use get_page_content first to see the current structure, modify it, then pass the full envelope here. Writes via GHL's builder autosave and returns the new pageDataUrl. \u26A0\uFE0F GHL accepts a save onto a page that already has content but may never make it the visible version (live-tested 2026-07-28 and again 2026-08-31). The tool now VERIFIES this for you: every response carries `save_check`, and `save_check.visible: false` means the content was stored but visitors still see the previous page \u2014 rebuild on a fresh step (create_funnel_page) and save onto that. Never report a page as updated without reading save_check. Saves as a draft unless isPublished is true.",
|
|
11525
11526
|
{
|
|
11526
11527
|
pageId: import_zod41.z.string().describe("The page ID to update."),
|
|
11527
|
-
content: import_zod41.z.record(import_zod41.z.unknown()).describe("The full page content JSON \u2014 the 8-field envelope: sections, settings, general, pageStyles, trackingCode, fontsForPreview, popups, popupsList. Start from get_page_content and modify it."),
|
|
11528
|
+
content: import_zod41.z.record(import_zod41.z.string(), import_zod41.z.unknown()).describe("The full page content JSON \u2014 the 8-field envelope: sections, settings, general, pageStyles, trackingCode, fontsForPreview, popups, popupsList. Start from get_page_content and modify it."),
|
|
11528
11529
|
funnelId: import_zod41.z.string().optional().describe("Funnel ID that owns the page. Optional \u2014 auto-resolved from the page metadata if omitted."),
|
|
11529
11530
|
isPublished: import_zod41.z.boolean().optional().describe("Mark the page published after the save. Defaults to false (draft).")
|
|
11530
11531
|
},
|
|
@@ -16437,8 +16438,8 @@ function removalHoldBack(opts) {
|
|
|
16437
16438
|
return null;
|
|
16438
16439
|
}
|
|
16439
16440
|
function registerPageStudioTools(server2, builderClient) {
|
|
16441
|
+
if (!builderClient) return;
|
|
16440
16442
|
const client = builderClient;
|
|
16441
|
-
if (!client) return;
|
|
16442
16443
|
const templateApi = () => ({
|
|
16443
16444
|
headers: () => client.buildHeaders(),
|
|
16444
16445
|
companyId: () => client.getIntendedCompanyId() ?? client.getCurrentCompanyId(),
|
|
@@ -17148,7 +17149,7 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
|
|
|
17148
17149
|
"Update a form's structure \u2014 fields, labels, conditional logic, auto-responder, email notifications, styling. Use get_form_full first to read the current form, modify the formData object, then pass it here. If name is omitted, the current name is preserved (one extra GET).",
|
|
17149
17150
|
{
|
|
17150
17151
|
formId: import_zod44.z.string().describe("The form ID to update."),
|
|
17151
|
-
formData: import_zod44.z.record(import_zod44.z.unknown()).describe("The updated formData object containing form fields, settings, autoResponder config, etc."),
|
|
17152
|
+
formData: import_zod44.z.record(import_zod44.z.string(), import_zod44.z.unknown()).describe("The updated formData object containing form fields, settings, autoResponder config, etc."),
|
|
17152
17153
|
name: import_zod44.z.string().optional().describe("Updated form name. If omitted, the current name is preserved.")
|
|
17153
17154
|
},
|
|
17154
17155
|
async ({ formId, formData, name }) => {
|
|
@@ -17407,7 +17408,7 @@ function registerFunnelQaTools(server2, client, builderClient) {
|
|
|
17407
17408
|
funnelUrl: import_zod45.z.string().describe("The live URL the test submission POSTs to (your external lead-bridge Worker URL, or any endpoint that creates the GHL contact). POSTed as JSON."),
|
|
17408
17409
|
sentinelEmail: import_zod45.z.string().optional().describe("Override the minted sentinel email. Default: a unique blueprint-qa.<id>@example.com (won't deliver; used only to find the contact)."),
|
|
17409
17410
|
testPhone: import_zod45.z.string().optional().describe("Include a phone on the submission (enables SMS-path checks). Must be a test-safe number you control \u2014 real SMS may send + bill."),
|
|
17410
|
-
submitBody: import_zod45.z.record(import_zod45.z.unknown()).optional().describe("Full JSON body to POST (advanced; for non-bridge endpoints). The sentinel email is injected if absent. Default body is the lead-bridge contract {first_name,last_name,email,phone,custom,_hp}."),
|
|
17411
|
+
submitBody: import_zod45.z.record(import_zod45.z.string(), import_zod45.z.unknown()).optional().describe("Full JSON body to POST (advanced; for non-bridge endpoints). The sentinel email is injected if absent. Default body is the lead-bridge contract {first_name,last_name,email,phone,custom,_hp}."),
|
|
17411
17412
|
expectCustom: import_zod45.z.array(customFieldInput).optional().describe("Custom fields the form sends \u2014 each is asserted to PERSIST with the sent value (field-value fidelity, Carlos #3)."),
|
|
17412
17413
|
expectStandard: import_zod45.z.array(import_zod45.z.string()).optional().describe("Standard contact keys to assert saved (e.g. ['phone','first_name']). email is always asserted."),
|
|
17413
17414
|
triggerTag: import_zod45.z.string().optional().describe("The tag the form/bridge should add (the speed-to-lead trigger). Asserted to land on the contact."),
|
|
@@ -17665,8 +17666,8 @@ var init_funnel_qa = __esm({
|
|
|
17665
17666
|
|
|
17666
17667
|
// src/tools/pipeline-builder.ts
|
|
17667
17668
|
function registerPipelineBuilderTools(server2, builderClient) {
|
|
17669
|
+
if (!builderClient) return;
|
|
17668
17670
|
const client = builderClient;
|
|
17669
|
-
if (!client) return;
|
|
17670
17671
|
async function pipelineRequest(method, path39, body) {
|
|
17671
17672
|
const headers = await client.buildHeaders();
|
|
17672
17673
|
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path39}`;
|
|
@@ -18580,19 +18581,20 @@ function deviceFingerprint(opts) {
|
|
|
18580
18581
|
function base64urlDecode(s) {
|
|
18581
18582
|
const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
18582
18583
|
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
18583
|
-
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
18584
|
+
return new Uint8Array(new Uint8Array(Buffer.from(padded, "base64")).buffer);
|
|
18584
18585
|
}
|
|
18585
18586
|
async function getPublicKey() {
|
|
18586
18587
|
if (cachedPublicKey) return cachedPublicKey;
|
|
18587
18588
|
const raw = Buffer.from(ATTESTATION_PUBLIC_KEY_B64, "base64");
|
|
18588
|
-
|
|
18589
|
+
const key = await import_node_crypto3.webcrypto.subtle.importKey(
|
|
18589
18590
|
"raw",
|
|
18590
18591
|
raw,
|
|
18591
18592
|
{ name: "Ed25519" },
|
|
18592
18593
|
false,
|
|
18593
18594
|
["verify"]
|
|
18594
18595
|
);
|
|
18595
|
-
|
|
18596
|
+
cachedPublicKey = key;
|
|
18597
|
+
return key;
|
|
18596
18598
|
}
|
|
18597
18599
|
function parseAttestationPayload(token2) {
|
|
18598
18600
|
try {
|
|
@@ -20007,7 +20009,8 @@ function registerValidatorTools(server2, client, builderClient) {
|
|
|
20007
20009
|
const workflow = await builderClient.getWorkflow(workflowId);
|
|
20008
20010
|
if (!workflow) return errorResponse(new Error(`Workflow ${workflowId} not found`));
|
|
20009
20011
|
const refs = [];
|
|
20010
|
-
const
|
|
20012
|
+
const locationId2 = client.resolveLocationId();
|
|
20013
|
+
const socialPlatforms = await connectedSocialPlatforms(client, locationId2);
|
|
20011
20014
|
const shape = [
|
|
20012
20015
|
...checkActionShapes(workflow),
|
|
20013
20016
|
...checkSaveBlockers(workflow),
|
|
@@ -20020,7 +20023,7 @@ function registerValidatorTools(server2, client, builderClient) {
|
|
|
20020
20023
|
return jsonResponse({ workflowId, workflowName: workflow.name, ...summarizeFindings(shape), references_scanned: 0, actions_checked: actionsChecked, findings: shape });
|
|
20021
20024
|
const needWorkflows = refs.some((r) => r.kind === "workflow");
|
|
20022
20025
|
const catalog2 = needWorkflows ? await fullWorkflowCatalog(builderClient) : { ids: /* @__PURE__ */ new Set(), complete: true };
|
|
20023
|
-
const lookups = await fetchAndBuildLookups(client, builderClient,
|
|
20026
|
+
const lookups = await fetchAndBuildLookups(client, builderClient, locationId2, { ids: catalog2.ids, complete: catalog2.complete });
|
|
20024
20027
|
const findings = [...shape, ...checkRefs(refs, workflowId, lookups)];
|
|
20025
20028
|
const report2 = {
|
|
20026
20029
|
workflowId,
|
|
@@ -20042,7 +20045,7 @@ function registerValidatorTools(server2, client, builderClient) {
|
|
|
20042
20045
|
{},
|
|
20043
20046
|
async () => {
|
|
20044
20047
|
try {
|
|
20045
|
-
const locationId2 = client.
|
|
20048
|
+
const locationId2 = client.resolveLocationId();
|
|
20046
20049
|
const catalog2 = await fullWorkflowCatalog(builderClient);
|
|
20047
20050
|
if (catalog2.rows.length === 0)
|
|
20048
20051
|
return jsonResponse({
|
|
@@ -24836,7 +24839,7 @@ var init_plan = __esm({
|
|
|
24836
24839
|
workflows: import_zod51.z.array(workflowSchema).optional(),
|
|
24837
24840
|
handoffs: import_zod51.z.array(handoffSchema).optional(),
|
|
24838
24841
|
buildOrder: import_zod51.z.array(import_zod51.z.string()).optional(),
|
|
24839
|
-
idMap: import_zod51.z.record(import_zod51.z.string()).optional()
|
|
24842
|
+
idMap: import_zod51.z.record(import_zod51.z.string(), import_zod51.z.string()).optional()
|
|
24840
24843
|
}).strict();
|
|
24841
24844
|
PLAN_ERROR_CODES = {
|
|
24842
24845
|
/** A workflow named like /nurture/i whose waits add up to < 30 days. */
|
|
@@ -26374,15 +26377,29 @@ function newRunId(now = /* @__PURE__ */ new Date(), rand = defaultRand) {
|
|
|
26374
26377
|
function defaultRand() {
|
|
26375
26378
|
return Math.floor(Math.random() * 65536).toString(16).padStart(4, "0");
|
|
26376
26379
|
}
|
|
26380
|
+
function legacyFunnelParentage(plan) {
|
|
26381
|
+
const funnels = plan.funnels;
|
|
26382
|
+
if (!Array.isArray(funnels)) return [];
|
|
26383
|
+
const pairs = [];
|
|
26384
|
+
for (const funnel of funnels) {
|
|
26385
|
+
if (typeof funnel !== "object" || funnel === null) continue;
|
|
26386
|
+
const { ref, pages } = funnel;
|
|
26387
|
+
if (typeof ref !== "string" || !Array.isArray(pages)) continue;
|
|
26388
|
+
for (const page of pages) {
|
|
26389
|
+
if (typeof page !== "object" || page === null) continue;
|
|
26390
|
+
const pageRef = page.ref;
|
|
26391
|
+
if (typeof pageRef === "string") pairs.push([pageRef, ref]);
|
|
26392
|
+
}
|
|
26393
|
+
}
|
|
26394
|
+
return pairs;
|
|
26395
|
+
}
|
|
26377
26396
|
function parentRefIndex(plan) {
|
|
26378
26397
|
const parents = /* @__PURE__ */ new Map();
|
|
26379
26398
|
if (!plan) return parents;
|
|
26380
26399
|
for (const p of plan.pipelines ?? []) {
|
|
26381
26400
|
for (const st of p.stages ?? []) parents.set(st.ref, p.ref);
|
|
26382
26401
|
}
|
|
26383
|
-
for (const
|
|
26384
|
-
for (const pg of fn.pages ?? []) parents.set(pg.ref, fn.ref);
|
|
26385
|
-
}
|
|
26402
|
+
for (const [pageRef, funnelRef] of legacyFunnelParentage(plan)) parents.set(pageRef, funnelRef);
|
|
26386
26403
|
return parents;
|
|
26387
26404
|
}
|
|
26388
26405
|
function buildRunRecord(input) {
|
|
@@ -28540,7 +28557,7 @@ var require_package = __commonJS({
|
|
|
28540
28557
|
"package.json"(exports2, module2) {
|
|
28541
28558
|
module2.exports = {
|
|
28542
28559
|
name: "@elitedcs/ghl-mcp",
|
|
28543
|
-
version: "3.83.
|
|
28560
|
+
version: "3.83.2",
|
|
28544
28561
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
28545
28562
|
description: "GoHighLevel MCP Server for Claude. 250 tools \u2014 full CRM, automation, marketing control, account-wide workflow audit, live funnel-capture verification, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
28546
28563
|
main: "dist/index.js",
|
|
@@ -28555,11 +28572,6 @@ var require_package = __commonJS({
|
|
|
28555
28572
|
"src/command-os/design/rules/anti-default.json",
|
|
28556
28573
|
"src/command-os/design/rules/web.json",
|
|
28557
28574
|
"src/command-os/design/rules/anti-default-contract.mjs",
|
|
28558
|
-
"src/command-os/design/rules/check-static.mjs",
|
|
28559
|
-
"src/command-os/design/rules/fixtures/claude-default.html",
|
|
28560
|
-
"src/command-os/design/rules/fixtures/house-clean.html",
|
|
28561
|
-
"src/command-os/design/rules/fixtures/generator-run-1.html",
|
|
28562
|
-
"src/command-os/design/rules/fixtures/external-css.html",
|
|
28563
28575
|
"dist/index.js",
|
|
28564
28576
|
"dist/capture-helper.js",
|
|
28565
28577
|
"templates/action-schemas.json",
|
|
@@ -28577,6 +28589,7 @@ var require_package = __commonJS({
|
|
|
28577
28589
|
],
|
|
28578
28590
|
scripts: {
|
|
28579
28591
|
build: "node src/command-os/assessment/build-app.mjs && esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.js --packages=external && esbuild src/capture-helper.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/capture-helper.js --packages=external",
|
|
28592
|
+
typecheck: "tsc --noEmit",
|
|
28580
28593
|
setup: "node setup-wizard.mjs",
|
|
28581
28594
|
catalogue: "node scripts/export-command-os-catalogue.mjs",
|
|
28582
28595
|
"manifest:write": "node scripts/write-package-manifest.mjs",
|
|
@@ -29001,7 +29014,8 @@ function writeClientEngagement(locationId2, patch, file2 = clientEngagementsPath
|
|
|
29001
29014
|
throw new Error("Something else saved this record while you were editing. Nothing was changed \u2014 reload and enter it again.");
|
|
29002
29015
|
}
|
|
29003
29016
|
function floorFor(e, profile) {
|
|
29004
|
-
const
|
|
29017
|
+
const wanted = e.offer?.trim().toLowerCase();
|
|
29018
|
+
const offer = wanted ? profile.offers?.find((o) => o.name.trim().toLowerCase() === wanted) : void 0;
|
|
29005
29019
|
if (offer?.priceFloor !== void 0) return offer.priceFloor;
|
|
29006
29020
|
if (e.cadence === "monthly") return profile.pricing?.minMonthly;
|
|
29007
29021
|
if (e.cadence === "one-time") return profile.pricing?.minSetup;
|
|
@@ -30024,13 +30038,14 @@ function pickLatest(notes) {
|
|
|
30024
30038
|
}
|
|
30025
30039
|
return null;
|
|
30026
30040
|
}
|
|
30027
|
-
var PIPELINE_NAME, NOTE_TITLE, MACHINE_MARKER, MARKER_LINE, NOTE_LIMIT;
|
|
30041
|
+
var PIPELINE_NAME, NOTE_TITLE, MACHINE_MARKER, STAGES, MARKER_LINE, NOTE_LIMIT;
|
|
30028
30042
|
var init_store2 = __esm({
|
|
30029
30043
|
"src/command-os/assessment/store.ts"() {
|
|
30030
30044
|
"use strict";
|
|
30031
30045
|
PIPELINE_NAME = "Assessments";
|
|
30032
30046
|
NOTE_TITLE = "GHL COMMAND ASSESSMENT";
|
|
30033
30047
|
MACHINE_MARKER = "--- machine block, do not edit below this line ---";
|
|
30048
|
+
STAGES = ["Gathering", "Findings", "Proposal sent", "Won", "Lost"];
|
|
30034
30049
|
MARKER_LINE = /^--- machine block, do not edit below this line ---(?: \((\d+)\/(\d+)(?: s=([a-z0-9]{6}))?\))?[ \t]*$/gm;
|
|
30035
30050
|
NOTE_LIMIT = 2e4;
|
|
30036
30051
|
}
|
|
@@ -30044,7 +30059,8 @@ async function loadAssessmentRecord(reader, contactId) {
|
|
|
30044
30059
|
}
|
|
30045
30060
|
async function findAssessmentPipeline(reader, locationId2) {
|
|
30046
30061
|
const raw = await reader.get("/opportunities/pipelines", { params: { locationId: locationId2 } });
|
|
30047
|
-
|
|
30062
|
+
const pipelines = Array.isArray(raw?.pipelines) ? raw.pipelines : [];
|
|
30063
|
+
return pipelines.find((p) => String(p.name).trim().toLowerCase() === PIPELINE_NAME.toLowerCase());
|
|
30048
30064
|
}
|
|
30049
30065
|
async function listAssessmentRecords(reader, locationId2) {
|
|
30050
30066
|
const pipeline = await findAssessmentPipeline(reader, locationId2);
|
|
@@ -33394,7 +33410,7 @@ function registerAssessmentTools(server2, client) {
|
|
|
33394
33410
|
quote: import_zod52.z.string().describe("The owner's own words, VERBATIM from the transcript. Do not tidy it up \u2014 if it is not in the transcript the answer is thrown out."),
|
|
33395
33411
|
reasoning: import_zod52.z.string().optional().describe("How you got from the quote to the value, when they are not the same.")
|
|
33396
33412
|
})).describe("One entry per question you could answer. Leave out anything the conversation did not cover."),
|
|
33397
|
-
existing: import_zod52.z.record(import_zod52.z.union([import_zod52.z.string(), import_zod52.z.number()])).optional().describe("Answers already captured, so this adds to them rather than replacing them.")
|
|
33413
|
+
existing: import_zod52.z.record(import_zod52.z.string(), import_zod52.z.union([import_zod52.z.string(), import_zod52.z.number()])).optional().describe("Answers already captured, so this adds to them rather than replacing them.")
|
|
33398
33414
|
},
|
|
33399
33415
|
async ({ transcript, proposed, existing }) => {
|
|
33400
33416
|
const gated = gateExtraction(transcript, proposed, QUESTION_UNITS);
|
|
@@ -33517,9 +33533,9 @@ var init_assessment = __esm({
|
|
|
33517
33533
|
StateSchema = import_zod52.z.object({
|
|
33518
33534
|
biz: import_zod52.z.string().min(1).describe("The prospect's business name."),
|
|
33519
33535
|
trade: import_zod52.z.string().optional().describe("Their trade. Decides which benchmarks may be applied."),
|
|
33520
|
-
ans: import_zod52.z.record(import_zod52.z.union([import_zod52.z.string(), import_zod52.z.number()])).describe("questionId -> answer, exactly as typed."),
|
|
33521
|
-
skip: import_zod52.z.record(import_zod52.z.boolean()).optional().describe("questionId -> true where they did not know."),
|
|
33522
|
-
asm: import_zod52.z.record(import_zod52.z.number()).optional().describe("assumption id -> rate as a decimal."),
|
|
33536
|
+
ans: import_zod52.z.record(import_zod52.z.string(), import_zod52.z.union([import_zod52.z.string(), import_zod52.z.number()])).describe("questionId -> answer, exactly as typed."),
|
|
33537
|
+
skip: import_zod52.z.record(import_zod52.z.string(), import_zod52.z.boolean()).optional().describe("questionId -> true where they did not know."),
|
|
33538
|
+
asm: import_zod52.z.record(import_zod52.z.string(), import_zod52.z.number()).optional().describe("assumption id -> rate as a decimal."),
|
|
33523
33539
|
client: import_zod52.z.object({ name: import_zod52.z.string().max(120), role: import_zod52.z.string().max(80), email: import_zod52.z.string().max(200), phone: import_zod52.z.string().max(40), website: import_zod52.z.string().max(300), city: import_zod52.z.string().max(120) }).partial().optional().describe("The person and place this is for, as typed on The client step. Rides with the answers so a load brings it back.")
|
|
33524
33540
|
});
|
|
33525
33541
|
}
|
|
@@ -34096,7 +34112,7 @@ function startRun(locationId2, stage, onDone, meta = {}) {
|
|
|
34096
34112
|
const obligations = (context.manualObligations ?? []).filter((o) => !deps.some((d) => d.ref === o.ref) && !(outcome.manualChecks ?? []).some((c) => c.ref === o.ref && c.type === o.type && c.ok && c.evidence.trim()));
|
|
34097
34113
|
for (const h of plan?.plan?.handoffs ?? []) if (!obligations.some((o) => o.ref === h.ref) && !(outcome.manualChecks ?? []).some((c) => c.ref === h.ref && c.ok && c.evidence.trim())) obligations.push({ ref: h.ref, type: "handoff", name: h.title || h.name || h.ref, reason: h.instruction || "Finish this manual action." });
|
|
34098
34114
|
outcome.ok = verifyBuildPassed(outcome, readback, plan?.plan);
|
|
34099
|
-
verifyRaw = { summary: outcome.summary, issues: outcome.issues, verification: { deps, checks, readback, obligations, buildOk: outcome.ok, liveProofApplicable: Boolean(plan?.plan
|
|
34115
|
+
verifyRaw = { summary: outcome.summary, issues: outcome.issues, verification: { deps, checks, readback, obligations, buildOk: outcome.ok, liveProofApplicable: Boolean(plan?.plan && typeof plan.plan === "object" && "funnels" in plan.plan && Array.isArray(plan.plan.funnels) && plan.plan.funnels.length), liveProof: outcome.liveProof ?? { ok: false, evidence: outcome.error || "No test-lead result was returned." } } };
|
|
34100
34116
|
if (!plan?.plan) {
|
|
34101
34117
|
outcome.ok = false;
|
|
34102
34118
|
verifyRaw.issues = [...verifyRaw.issues ?? [], "Run Build before verifying."];
|
|
@@ -36987,8 +37003,9 @@ async function runDashboard(argv) {
|
|
|
36987
37003
|
state = setAccountType(state, outcome.locationId, "client");
|
|
36988
37004
|
if (args.industry) state = setAccountIndustry(state, outcome.locationId, args.industry);
|
|
36989
37005
|
if (!outcome.registered) {
|
|
36990
|
-
|
|
36991
|
-
if (outcome.saveFailed)
|
|
37006
|
+
const pending = setPending(state, outcome.locationId, args.name, args.industry || void 0);
|
|
37007
|
+
if (outcome.saveFailed) pending.pending[outcome.locationId].saveFailed = true;
|
|
37008
|
+
state = pending;
|
|
36992
37009
|
}
|
|
36993
37010
|
writeCockpitState(state);
|
|
36994
37011
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -37996,7 +38013,7 @@ function registerBulkOperationTools(server2, client) {
|
|
|
37996
38013
|
"Update the same field(s) on multiple contacts at once. Rate-limited. Example: set a custom field value, change source, update address for a batch of contacts.",
|
|
37997
38014
|
{
|
|
37998
38015
|
contactIds: import_zod54.z.array(import_zod54.z.string()).min(1, "At least one contact ID required.").describe("Array of contact IDs to update."),
|
|
37999
|
-
fields: import_zod54.z.record(import_zod54.z.unknown()).describe("Fields to set on each contact (e.g. {customField: {id: 'xxx', value: 'yyy'}}, {source: 'Import'}).")
|
|
38016
|
+
fields: import_zod54.z.record(import_zod54.z.string(), import_zod54.z.unknown()).describe("Fields to set on each contact (e.g. {customField: {id: 'xxx', value: 'yyy'}}, {source: 'Import'}).")
|
|
38000
38017
|
},
|
|
38001
38018
|
async ({ contactIds, fields }) => {
|
|
38002
38019
|
if (Object.keys(fields).length === 0) {
|
|
@@ -39054,10 +39071,12 @@ function registerWorkflowClonerTools(server2, builderClient) {
|
|
|
39054
39071
|
workflowId: void 0
|
|
39055
39072
|
// Will be set by the new workflow
|
|
39056
39073
|
};
|
|
39057
|
-
|
|
39074
|
+
const clonedData = cloned.data;
|
|
39075
|
+
if (clonedData && typeof clonedData === "object" && "targetActionId" in clonedData) {
|
|
39076
|
+
const targetActionId = clonedData.targetActionId;
|
|
39058
39077
|
cloned.data = {
|
|
39059
|
-
...
|
|
39060
|
-
targetActionId: remap(
|
|
39078
|
+
...clonedData,
|
|
39079
|
+
targetActionId: typeof targetActionId === "string" ? remap(targetActionId) : targetActionId
|
|
39061
39080
|
};
|
|
39062
39081
|
}
|
|
39063
39082
|
return cloned;
|
|
@@ -39170,8 +39189,8 @@ function buildContactSmartListBody(args) {
|
|
|
39170
39189
|
};
|
|
39171
39190
|
}
|
|
39172
39191
|
function registerSmartListTools(server2, builderClient) {
|
|
39192
|
+
if (!builderClient) return;
|
|
39173
39193
|
const client = builderClient;
|
|
39174
|
-
if (!client) return;
|
|
39175
39194
|
async function smartListRequest(method, path39, body) {
|
|
39176
39195
|
const headers = await client.buildHeaders();
|
|
39177
39196
|
const url = `${SMARTLIST_BASE}${path39}`;
|
|
@@ -39232,7 +39251,7 @@ ${await res.text()}`);
|
|
|
39232
39251
|
{
|
|
39233
39252
|
name: import_zod57.z.string().describe("Display name for the smart list."),
|
|
39234
39253
|
tagFilters: import_zod57.z.array(import_zod57.z.array(import_zod57.z.string())).optional().describe('Tag conditions. Each inner array is one filter requiring ALL those tags, e.g. [["escalated"]] for "has the escalated tag".'),
|
|
39235
|
-
rawFilters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.unknown())).optional().describe("Advanced: raw filter leaves {field, operator, value, options}. Combined with tagFilters into one AND group."),
|
|
39254
|
+
rawFilters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.string(), import_zod57.z.unknown())).optional().describe("Advanced: raw filter leaves {field, operator, value, options}. Combined with tagFilters into one AND group."),
|
|
39236
39255
|
locationId: import_zod57.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
39237
39256
|
},
|
|
39238
39257
|
async ({ name, tagFilters, rawFilters, locationId: locationId2 }) => {
|
|
@@ -39317,8 +39336,8 @@ ${await res.text()}`);
|
|
|
39317
39336
|
{
|
|
39318
39337
|
name: import_zod57.z.string().describe("Display name for the smart list."),
|
|
39319
39338
|
objectKey: import_zod57.z.enum(OBJECT_KEYS).describe("Object type the list segments over. 'contacts' or 'opportunity'."),
|
|
39320
|
-
filters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.unknown())).optional().describe("Array of filter objects. Each object has fields like {field, operator, value} \u2014 exact shape varies by filter type. See get_smart_list on an existing list to learn the format."),
|
|
39321
|
-
columns: import_zod57.z.array(import_zod57.z.record(import_zod57.z.unknown())).optional().describe("Array of column definitions for the smart list view in GHL UI. Each defines which contact/opportunity field shows as a column. Defaults to GHL's standard columns if omitted."),
|
|
39339
|
+
filters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.string(), import_zod57.z.unknown())).optional().describe("Array of filter objects. Each object has fields like {field, operator, value} \u2014 exact shape varies by filter type. See get_smart_list on an existing list to learn the format."),
|
|
39340
|
+
columns: import_zod57.z.array(import_zod57.z.record(import_zod57.z.string(), import_zod57.z.unknown())).optional().describe("Array of column definitions for the smart list view in GHL UI. Each defines which contact/opportunity field shows as a column. Defaults to GHL's standard columns if omitted."),
|
|
39322
39341
|
pipelineIds: import_zod57.z.array(import_zod57.z.string()).optional().describe("(opportunity objectKey only) Pipeline IDs to restrict this smart list to. Empty array = all pipelines."),
|
|
39323
39342
|
defaultInPipelines: import_zod57.z.array(import_zod57.z.string()).optional().describe("(opportunity objectKey only) Pipeline IDs where this list is the default view."),
|
|
39324
39343
|
locationId: import_zod57.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
@@ -39344,8 +39363,8 @@ ${await res.text()}`);
|
|
|
39344
39363
|
{
|
|
39345
39364
|
listId: import_zod57.z.string().describe("The smart list ID to update."),
|
|
39346
39365
|
name: import_zod57.z.string().optional().describe("New display name."),
|
|
39347
|
-
filters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.unknown())).optional().describe("Replace the filter array entirely. To add a filter, fetch the current list, append, and pass the new array."),
|
|
39348
|
-
columns: import_zod57.z.array(import_zod57.z.record(import_zod57.z.unknown())).optional().describe("Replace the column array entirely."),
|
|
39366
|
+
filters: import_zod57.z.array(import_zod57.z.record(import_zod57.z.string(), import_zod57.z.unknown())).optional().describe("Replace the filter array entirely. To add a filter, fetch the current list, append, and pass the new array."),
|
|
39367
|
+
columns: import_zod57.z.array(import_zod57.z.record(import_zod57.z.string(), import_zod57.z.unknown())).optional().describe("Replace the column array entirely."),
|
|
39349
39368
|
pipelineIds: import_zod57.z.array(import_zod57.z.string()).optional().describe("(opportunity only) Update the pipeline scope."),
|
|
39350
39369
|
defaultInPipelines: import_zod57.z.array(import_zod57.z.string()).optional().describe("(opportunity only) Update the default-in-pipelines list."),
|
|
39351
39370
|
locationId: import_zod57.z.string().optional().describe("Location ID. Falls back to the active builder client's location.")
|
|
@@ -39412,8 +39431,8 @@ var init_smart_lists = __esm({
|
|
|
39412
39431
|
|
|
39413
39432
|
// src/tools/reputation.ts
|
|
39414
39433
|
function registerReputationTools(server2, builderClient) {
|
|
39434
|
+
if (!builderClient) return;
|
|
39415
39435
|
const client = builderClient;
|
|
39416
|
-
if (!client) return;
|
|
39417
39436
|
async function reputationRequest(method, path39) {
|
|
39418
39437
|
const headers = await client.buildHeaders();
|
|
39419
39438
|
const response = await fetch(`${REPUTATION_BASE}${path39}`, { method, headers });
|
|
@@ -39558,8 +39577,8 @@ var init_email_campaigns = __esm({
|
|
|
39558
39577
|
|
|
39559
39578
|
// src/tools/memberships.ts
|
|
39560
39579
|
function registerMembershipTools(server2, builderClient) {
|
|
39580
|
+
if (!builderClient) return;
|
|
39561
39581
|
const client = builderClient;
|
|
39562
|
-
if (!client) return;
|
|
39563
39582
|
async function membershipRequest(path39, method = "GET", body) {
|
|
39564
39583
|
const headers = await client.buildHeaders();
|
|
39565
39584
|
const response = await fetch(`${MEMBERSHIP_BASE2}${path39}`, {
|
|
@@ -39875,7 +39894,7 @@ function registerTemplateDeployerTools(server2, client) {
|
|
|
39875
39894
|
"Deploy a template to set up a GHL sub-account. Creates tags, custom fields, pipelines with stages, calendars, workflows, and forms based on the template and the user's questionnaire answers. This is the main setup automation tool.",
|
|
39876
39895
|
{
|
|
39877
39896
|
templateFile: import_zod61.z.string().describe("Path to the template JSON file."),
|
|
39878
|
-
answers: import_zod61.z.record(import_zod61.z.unknown()).describe("Questionnaire answers keyed by question ID (e.g. {business_name: 'My Clinic', business_phone: '+15551234567', ...})."),
|
|
39897
|
+
answers: import_zod61.z.record(import_zod61.z.string(), import_zod61.z.unknown()).describe("Questionnaire answers keyed by question ID (e.g. {business_name: 'My Clinic', business_phone: '+15551234567', ...})."),
|
|
39879
39898
|
locationId: import_zod61.z.string().optional().describe("Location ID to deploy to. Uses default if not specified."),
|
|
39880
39899
|
dryRun: import_zod61.z.boolean().optional().describe("If true, shows what would be created without actually creating anything. Defaults to false."),
|
|
39881
39900
|
overwriteBusinessInfo: import_zod61.z.boolean().optional().describe(
|
|
@@ -40281,7 +40300,7 @@ var init_template_deployer = __esm({
|
|
|
40281
40300
|
required: import_zod61.z.boolean().optional(),
|
|
40282
40301
|
placeholder: import_zod61.z.string().optional()
|
|
40283
40302
|
})).optional().default([]),
|
|
40284
|
-
location: import_zod61.z.record(import_zod61.z.unknown()).optional(),
|
|
40303
|
+
location: import_zod61.z.record(import_zod61.z.string(), import_zod61.z.unknown()).optional(),
|
|
40285
40304
|
tags: import_zod61.z.array(import_zod61.z.string()).optional(),
|
|
40286
40305
|
customFields: import_zod61.z.array(import_zod61.z.object({
|
|
40287
40306
|
name: import_zod61.z.string(),
|
|
@@ -40294,7 +40313,7 @@ var init_template_deployer = __esm({
|
|
|
40294
40313
|
workflows: import_zod61.z.array(import_zod61.z.object({
|
|
40295
40314
|
name: import_zod61.z.string(),
|
|
40296
40315
|
condition: import_zod61.z.string().optional(),
|
|
40297
|
-
actions: import_zod61.z.array(import_zod61.z.record(import_zod61.z.unknown())).optional().default([])
|
|
40316
|
+
actions: import_zod61.z.array(import_zod61.z.record(import_zod61.z.string(), import_zod61.z.unknown())).optional().default([])
|
|
40298
40317
|
})).optional(),
|
|
40299
40318
|
calendars: import_zod61.z.array(import_zod61.z.object({
|
|
40300
40319
|
name: import_zod61.z.string(),
|
|
@@ -40334,13 +40353,17 @@ var init_version_check = __esm({
|
|
|
40334
40353
|
});
|
|
40335
40354
|
|
|
40336
40355
|
// src/tools/diagnostics.ts
|
|
40356
|
+
function anthropicKeyCheckStatus(verdict) {
|
|
40357
|
+
const severity = ANTHROPIC_KEY_STATUS[verdict];
|
|
40358
|
+
return severity === "ok" ? "pass" : severity;
|
|
40359
|
+
}
|
|
40337
40360
|
async function collectInstallChecks(installedVersion, client, builderClient, registry2, getGatingReport, plan = "mcp", probeAnthropic = probeAnthropicKey) {
|
|
40338
40361
|
const checks = [];
|
|
40339
40362
|
const anthropicPromise = plan === "command-os" ? (async () => {
|
|
40340
40363
|
const r = await probeAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
40341
40364
|
return {
|
|
40342
40365
|
name: "Anthropic key (Command OS demo builder)",
|
|
40343
|
-
status:
|
|
40366
|
+
status: anthropicKeyCheckStatus(r.verdict),
|
|
40344
40367
|
detail: r.raw ? `${r.detail} Anthropic said: "${r.raw}"` : r.detail
|
|
40345
40368
|
};
|
|
40346
40369
|
})() : null;
|
|
@@ -46256,7 +46279,7 @@ function registerAgencyBuildTools(server2, knownTools) {
|
|
|
46256
46279
|
why: import_zod72.z.string().min(3).describe("Plain English. This is what the operator reads before approving."),
|
|
46257
46280
|
targets: import_zod72.z.array(targetSchema).default([]),
|
|
46258
46281
|
creates: import_zod72.z.array(import_zod72.z.object({ ref: import_zod72.z.string(), kind: import_zod72.z.string() })).optional().describe("What this step brings into existence, for later steps to point at."),
|
|
46259
|
-
args: import_zod72.z.record(import_zod72.z.unknown()).optional().describe("The arguments, kept verbatim \u2014 the approval covers these, so changing one voids it.")
|
|
46282
|
+
args: import_zod72.z.record(import_zod72.z.string(), import_zod72.z.unknown()).optional().describe("The arguments, kept verbatim \u2014 the approval covers these, so changing one voids it.")
|
|
46260
46283
|
})).min(1)
|
|
46261
46284
|
},
|
|
46262
46285
|
async ({ goal, findings, steps }) => {
|
|
@@ -46326,7 +46349,7 @@ function registerAgencyBuildTools(server2, knownTools) {
|
|
|
46326
46349
|
undo: import_zod72.z.string().optional().describe("Required on 'applied'. How to reverse this exact write, specifically enough to act on months later."),
|
|
46327
46350
|
because: import_zod72.z.string().optional().describe("Required on 'failed'. What the account actually said."),
|
|
46328
46351
|
result: import_zod72.z.unknown().optional().describe("What came back, kept so a stall can be diagnosed without re-running anything."),
|
|
46329
|
-
resolved: import_zod72.z.record(import_zod72.z.string()).optional().describe("The real ids this step created, keyed by the ref later steps use."),
|
|
46352
|
+
resolved: import_zod72.z.record(import_zod72.z.string(), import_zod72.z.string()).optional().describe("The real ids this step created, keyed by the ref later steps use."),
|
|
46330
46353
|
retry: import_zod72.z.boolean().optional().describe("This is a second run of a step that failed. Both attempts are kept, and the earlier failure stops blocking what came after it.")
|
|
46331
46354
|
},
|
|
46332
46355
|
async ({ buildId, stepId, state, undo, because, result, resolved: resolved2, retry }) => {
|
|
@@ -47191,7 +47214,7 @@ function registerAuditReportTools(server2) {
|
|
|
47191
47214
|
"build_audit_report",
|
|
47192
47215
|
"Turn the output of `audit_workflows` into a client-ready assessment: plain-English findings with money attached where it can honestly be attached, ranked worst-first, plus an explicit list of what could NOT be checked. Call `audit_workflows` first and pass its result here \u2014 this does not re-read the account. Give `leadsPerMonth`, `closeRate` and `monthlyValuePerClient` if you know them and the findings get costed in dollars; leave them out and it says which input is missing instead of guessing. `monthlyValuePerClient` defaults to your saved minimum monthly fee from your agency profile. Use this to produce the document you send or present, not to diagnose \u2014 the diagnosing already happened.",
|
|
47193
47216
|
{
|
|
47194
|
-
audit: import_zod74.z.record(import_zod74.z.unknown()).describe("The full JSON result returned by audit_workflows."),
|
|
47217
|
+
audit: import_zod74.z.record(import_zod74.z.string(), import_zod74.z.unknown()).describe("The full JSON result returned by audit_workflows."),
|
|
47195
47218
|
audience: import_zod74.z.enum(["internal", "prospect"]).optional().describe("Who reads it. 'internal' (default) is a report about an account you already run, and may use your own minimum monthly as what a client is worth. 'prospect' is a document about somebody else's business: your numbers are NEVER used, so findings stay uncosted unless you supply THEIR lead volume, close rate and client value."),
|
|
47196
47219
|
accountName: import_zod74.z.string().describe("The client's name as they should see it on the document."),
|
|
47197
47220
|
locationId: import_zod74.z.string().optional().describe("Sub-account id. Recorded on the document, never shown in the body."),
|
|
@@ -47256,7 +47279,7 @@ function registerAuditReportTools(server2) {
|
|
|
47256
47279
|
"build_site_audit_report",
|
|
47257
47280
|
"Turn a website read-through into the assessment document you put in front of a PROSPECT \u2014 someone whose GoHighLevel account you do not have. Pass the verified observations from a site crawl and it returns plain-English findings, ranked, each one carrying the quote and the page it came from. Use it before a sales call, or alongside a receptionist demo, so the same read of their site fills both. It never invents money: a website cannot tell you what a lead is worth to that business, so findings come back uncosted unless you supply THEIR figures, and the document says why. It also never repeats a claim the crawl could not stand up \u2014 anything refused is returned separately, so you can see what was thrown out rather than wonder what was missed.",
|
|
47258
47281
|
{
|
|
47259
|
-
observations: import_zod74.z.record(import_zod74.z.unknown()).describe("The verified observations payload from the site read: site, pagesRead, observations, limits. Passed through as-is."),
|
|
47282
|
+
observations: import_zod74.z.record(import_zod74.z.string(), import_zod74.z.unknown()).describe("The verified observations payload from the site read: site, pagesRead, observations, limits. Passed through as-is."),
|
|
47260
47283
|
businessName: import_zod74.z.string().describe("The business's name as it should appear on the document."),
|
|
47261
47284
|
leadsPerMonth: import_zod74.z.number().min(0).optional().describe("THEIR leads per month, if they told you. Never your own figure."),
|
|
47262
47285
|
closeRate: import_zod74.z.number().min(0).max(1).optional().describe("THEIR close rate, 0-1, if they told you. Never guessed."),
|
|
@@ -48138,7 +48161,7 @@ var init_brief2 = __esm({
|
|
|
48138
48161
|
preset: presetSchema,
|
|
48139
48162
|
briefSource: briefSourceSchema,
|
|
48140
48163
|
/** Partner-OS deep structures (ICA / offer / brand-DNA), carried verbatim. */
|
|
48141
|
-
extended: import_zod79.z.record(import_zod79.z.unknown()).optional(),
|
|
48164
|
+
extended: import_zod79.z.record(import_zod79.z.string(), import_zod79.z.unknown()).optional(),
|
|
48142
48165
|
business: import_zod79.z.object({
|
|
48143
48166
|
name: import_zod79.z.string(),
|
|
48144
48167
|
type: import_zod79.z.string().optional(),
|
|
@@ -49913,7 +49936,7 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
49913
49936
|
pendStaff(u, `Staff member "${name}" (${u.email}) was not created: no agency key is registered (creating users is an agency-level write). Run register_agency_key with an agency-level Private Integration key that has users.write, then re-run \u2014 or add them in Settings \u2192 Team and re-run to bind them by email.`);
|
|
49914
49937
|
continue;
|
|
49915
49938
|
}
|
|
49916
|
-
let outcome;
|
|
49939
|
+
let outcome = void 0;
|
|
49917
49940
|
let recoveredUser;
|
|
49918
49941
|
try {
|
|
49919
49942
|
outcome = await deps.createUser({ firstName: u.firstName, lastName: u.lastName, email: u.email, role: u.role, phone: u.phone });
|
|
@@ -51353,14 +51376,14 @@ function registerIntakeToBuildTools(server2, client, builderClient, registry2) {
|
|
|
51353
51376
|
"validate_brief",
|
|
51354
51377
|
"Validate an Intake-to-Build Brief object against the \xA74 schema. Returns {valid, errors}. Use to check a normalized brief before handing it to the plan-generation skill.",
|
|
51355
51378
|
{
|
|
51356
|
-
brief: import_zod80.z.record(import_zod80.z.unknown()).describe("The Brief object to validate.")
|
|
51379
|
+
brief: import_zod80.z.record(import_zod80.z.string(), import_zod80.z.unknown()).describe("The Brief object to validate.")
|
|
51357
51380
|
},
|
|
51358
51381
|
async ({ brief }) => validateBrief(brief)
|
|
51359
51382
|
);
|
|
51360
51383
|
const buildPlanSchema2 = {
|
|
51361
|
-
plan: import_zod80.z.record(import_zod80.z.unknown()).optional().describe("The approved \xA75 Build Plan object. Omit it and pass useSavedPlan:true to build from the plan already saved for this account."),
|
|
51384
|
+
plan: import_zod80.z.record(import_zod80.z.string(), import_zod80.z.unknown()).optional().describe("The approved \xA75 Build Plan object. Omit it and pass useSavedPlan:true to build from the plan already saved for this account."),
|
|
51362
51385
|
fromPreset: import_zod80.z.boolean().optional().describe("PLAN-FROM-PRESET (PRD row 4d): compose the \xA75 plan SERVER-SIDE from the industry preset + the \xA74 brief, deterministically, in milliseconds \u2014 never author workflow actions by hand when a preset covers the brief. Pass `brief` (required) and optionally `preset` and `copy`; omit `plan`. The composed plan carries the preset's full structure (workflows, templates with complete send-ready copy token-filled from the brief, staff users, calendars with the brief's appointment lengths, pipeline stages, notification targets) and then flows through the exact same validate \u2192 dry_run/execute path as a passed plan, including being saved on execute. The dry_run response lists copySlots \u2014 the template refs whose subject/body the model MAY refine via `copy` on the execute call. If the preset cannot cover the brief the tool answers phase:\"compose\" with the reasons; only then author a plan by hand."),
|
|
51363
|
-
brief: import_zod80.z.record(import_zod80.z.unknown()).optional().describe("fromPreset only: the \xA74 Brief (from normalize_submission_to_brief, or assembled from the cockpit intake answers)."),
|
|
51386
|
+
brief: import_zod80.z.record(import_zod80.z.string(), import_zod80.z.unknown()).optional().describe("fromPreset only: the \xA74 Brief (from normalize_submission_to_brief, or assembled from the cockpit intake answers)."),
|
|
51364
51387
|
preset: import_zod80.z.string().optional().describe("fromPreset only: which preset to compose from \u2014 a preset id (med_spa, clinic, coach, local_service, ecom, generic), an alias (dental, medspa, home_services\u2026), or an industry slug (med-spa, local-service, ecommerce\u2026). Defaults to the brief's own preset field; an unknown value falls back to the generic preset (noted in the response)."),
|
|
51365
51388
|
copy: import_zod80.z.array(
|
|
51366
51389
|
import_zod80.z.object({
|
|
@@ -52013,7 +52036,7 @@ function registerIntakeToBuildTools(server2, client, builderClient, registry2) {
|
|
|
52013
52036
|
{
|
|
52014
52037
|
formId: import_zod80.z.string().describe("The intake form ID (from install_intake_form)."),
|
|
52015
52038
|
submissionId: import_zod80.z.string().optional().describe("Specific submission to normalize. Defaults to the most recent."),
|
|
52016
|
-
fieldMap: import_zod80.z.record(import_zod80.z.string()).optional().describe("intakeKey -> customFieldId map from install_intake_form. Reconstructed from the form if omitted."),
|
|
52039
|
+
fieldMap: import_zod80.z.record(import_zod80.z.string(), import_zod80.z.string()).optional().describe("intakeKey -> customFieldId map from install_intake_form. Reconstructed from the form if omitted."),
|
|
52017
52040
|
preset: import_zod80.z.string().optional().describe("Override the preset. Defaults to one derived from business_type.")
|
|
52018
52041
|
},
|
|
52019
52042
|
async ({ formId, submissionId, fieldMap, preset }) => {
|
|
@@ -52145,7 +52168,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
|
|
|
52145
52168
|
registerConnectorTools(wrap(CONNECTORS_MODULE));
|
|
52146
52169
|
registerGoogleCalendarTools(wrap(GOOGLE_CALENDAR_MODULE));
|
|
52147
52170
|
registerDeliveryAuditTools(wrap(DELIVERY_AUDIT_MODULE));
|
|
52148
|
-
registerDesignStudioTools(wrap(DESIGN_STUDIO_MODULE)
|
|
52171
|
+
registerDesignStudioTools(wrap(DESIGN_STUDIO_MODULE));
|
|
52149
52172
|
registerAgencyBuildTools(wrap(AGENCY_BUILD_MODULE), () => registeredTools);
|
|
52150
52173
|
registerClientEngagementTools(wrap(CLIENT_ENGAGEMENTS_MODULE), registry2);
|
|
52151
52174
|
registerAuditReportTools(wrap(AUDIT_REPORT_MODULE));
|
|
@@ -52291,9 +52314,16 @@ var init_tools = __esm({
|
|
|
52291
52314
|
[registerAssociationTools, "associations"],
|
|
52292
52315
|
[registerEstimateTools, "estimates"],
|
|
52293
52316
|
[registerCouponTools, "coupons"],
|
|
52294
|
-
[registerKnowledgeBaseTools, "knowledge-base"],
|
|
52295
|
-
|
|
52296
|
-
|
|
52317
|
+
[(server2, client) => registerKnowledgeBaseTools(server2, client), "knowledge-base"],
|
|
52318
|
+
// Wrapped, not listed bare: this registrar's third parameter is a `deps`
|
|
52319
|
+
// object, not the TokenRegistry the loop below passes to everything in this
|
|
52320
|
+
// list. Today that is harmless — every key of `deps` is optional and a
|
|
52321
|
+
// TokenRegistry has none of them, so every read falls back to its default —
|
|
52322
|
+
// but it is harmless by luck, and stops being harmless the day TokenRegistry
|
|
52323
|
+
// grows a `sleep`, `now` or `journalDir`. The wrapper passes nothing, which
|
|
52324
|
+
// is what the registrar effectively receives now.
|
|
52325
|
+
[(server2, client) => registerConversationAiTools(server2, client), "conversation-ai"],
|
|
52326
|
+
[(server2, client) => registerAiEmployeeDemoTools(server2, client), "ai-employee-demo"],
|
|
52297
52327
|
[registerVoiceAiTools, "voice-ai"],
|
|
52298
52328
|
[registerDocumentTools, "documents"],
|
|
52299
52329
|
[registerBulkOperationTools, "bulk-operations"],
|
|
@@ -52542,6 +52572,12 @@ var init_cli2 = __esm({
|
|
|
52542
52572
|
});
|
|
52543
52573
|
|
|
52544
52574
|
// src/index.ts
|
|
52575
|
+
var index_exports = {};
|
|
52576
|
+
__export(index_exports, {
|
|
52577
|
+
TRANSITIONAL_ATTESTATION_DEADLINE: () => TRANSITIONAL_ATTESTATION_DEADLINE,
|
|
52578
|
+
licenseGateFailureMessage: () => licenseGateFailureMessage
|
|
52579
|
+
});
|
|
52580
|
+
module.exports = __toCommonJS(index_exports);
|
|
52545
52581
|
var dotenv2 = __toESM(require("dotenv"));
|
|
52546
52582
|
var path38 = __toESM(require("path"));
|
|
52547
52583
|
var fs39 = __toESM(require("fs"));
|
|
@@ -52909,6 +52945,12 @@ registerMetaTools(server, pkg.version);
|
|
|
52909
52945
|
var inBootstrapMode = true;
|
|
52910
52946
|
var telemetryTier = "none";
|
|
52911
52947
|
var TRANSITIONAL_ATTESTATION_DEADLINE = Date.parse("2026-06-15T00:00:00.000Z");
|
|
52948
|
+
function licenseGateFailureMessage(lic, deadline = TRANSITIONAL_ATTESTATION_DEADLINE) {
|
|
52949
|
+
if (!lic.ok) return `[ghl-mcp] License check failed: ${lic.error}
|
|
52950
|
+
`;
|
|
52951
|
+
return `[ghl-mcp] Your license is valid, but our license server did not return a signed attestation, which has been required since ${new Date(deadline).toISOString().slice(0, 10)}. This is on our side, not your install. Please write support@ghlcommand.com.
|
|
52952
|
+
`;
|
|
52953
|
+
}
|
|
52912
52954
|
async function renewAttestation(creds) {
|
|
52913
52955
|
if (!creds.email || !creds.license_key) return "unauthorized";
|
|
52914
52956
|
let lic;
|
|
@@ -52991,7 +53033,9 @@ async function resolveAccessAndRegister() {
|
|
|
52991
53033
|
attestationStatus = "renewed-from-legacy";
|
|
52992
53034
|
} else {
|
|
52993
53035
|
attestationStatus = "needs-reset";
|
|
52994
|
-
if (renewed === "
|
|
53036
|
+
if (renewed === "install_limit") {
|
|
53037
|
+
process.stderr.write("[ghl-mcp] Bootstrap mode. Free a device on your license, or write support@ghlcommand.com.\n");
|
|
53038
|
+
} else if (renewed === "cancelled" || renewed === "unauthorized") {
|
|
52995
53039
|
process.stderr.write(`[ghl-mcp] Server says license is ${renewed}. Bootstrap mode.
|
|
52996
53040
|
`);
|
|
52997
53041
|
} else if (renewed === "renewed-unsigned") {
|
|
@@ -53028,8 +53072,7 @@ async function resolveAccessAndRegister() {
|
|
|
53028
53072
|
} catch {
|
|
53029
53073
|
}
|
|
53030
53074
|
} else {
|
|
53031
|
-
process.stderr.write(
|
|
53032
|
-
`);
|
|
53075
|
+
process.stderr.write(licenseGateFailureMessage(lic));
|
|
53033
53076
|
}
|
|
53034
53077
|
} else {
|
|
53035
53078
|
process.stderr.write(
|
|
@@ -53231,3 +53274,8 @@ main().catch((error) => {
|
|
|
53231
53274
|
process.stderr.write(`[ghl-mcp] Failed to start: ${error}
|
|
53232
53275
|
`);
|
|
53233
53276
|
});
|
|
53277
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
53278
|
+
0 && (module.exports = {
|
|
53279
|
+
TRANSITIONAL_ATTESTATION_DEADLINE,
|
|
53280
|
+
licenseGateFailureMessage
|
|
53281
|
+
});
|