@elitedcs/ghl-mcp 3.83.3 → 3.83.5
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 +60 -0
- package/README.md +1 -1
- package/dist/index.js +124 -132
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 3.83.5 — the brand page's buttons work, and a run tells you it is working
|
|
6
|
+
|
|
7
|
+
If you use Design Studio, every button on a brand's own page has been dead since
|
|
8
|
+
3.78.0. "Make it" did nothing but load a blank page. So did "Save changes", which
|
|
9
|
+
means any accent, font, name or logo you edited there was thrown away without
|
|
10
|
+
saying so. Nine days, five releases. One piece of broken punctuation in the page's
|
|
11
|
+
script switched all of it off at once, and because a browser discards a script like
|
|
12
|
+
that in silence, nothing on screen ever said so.
|
|
13
|
+
|
|
14
|
+
Both are fixed, and a new check now reads every page the cockpit serves and refuses
|
|
15
|
+
to ship one whose script will not run.
|
|
16
|
+
|
|
17
|
+
A design run also used to tell you nothing at all while it worked. Claude writes the
|
|
18
|
+
whole file in a single answer, so the log stayed empty for ten or twenty minutes,
|
|
19
|
+
and there was no way to tell a working run from a dead one. The sensible thing to do
|
|
20
|
+
was stop it, which was the wrong thing to do. The run now shows a clock, counts the
|
|
21
|
+
passes, and says plainly that nothing will appear until a pass finishes.
|
|
22
|
+
|
|
23
|
+
While reading what gets sent to Claude on those runs, we found the brief was asking
|
|
24
|
+
for two tools that are deliberately switched off for them, and then telling Claude
|
|
25
|
+
in the next line that it had no tools. It no longer does that.
|
|
26
|
+
|
|
27
|
+
**A correction to 3.83.4.** That release said a form field written without its id,
|
|
28
|
+
key and data type "is stored and shows as raw data instead of a rendered field."
|
|
29
|
+
That is wrong, and we tested it after we shipped it rather than before. A field
|
|
30
|
+
without those still renders normally in the form editor. What they actually do is
|
|
31
|
+
tie the answer to the contact record, which is reason enough to set them, and
|
|
32
|
+
`update_form` now says only that.
|
|
33
|
+
|
|
34
|
+
## 3.83.4 — one door for every write, so "protected" cannot quietly stop meaning protected
|
|
35
|
+
|
|
36
|
+
3.83.3 fixed the holes. This closes the shape that kept making them.
|
|
37
|
+
|
|
38
|
+
Marking a client account protected is checked in one place for the public API. But
|
|
39
|
+
this product also writes to GoHighLevel through its own builder connection, and
|
|
40
|
+
eleven tool modules had each grown their own copy of that request — their own
|
|
41
|
+
headers, their own timeout, their own fetch. Every copy was a separate door into
|
|
42
|
+
your account, and a check added to one of them told you nothing about the other
|
|
43
|
+
ten. That is why the last release had to find fourteen of them.
|
|
44
|
+
|
|
45
|
+
They now share one door. It builds the headers, applies the thirty-second timeout
|
|
46
|
+
and runs the protected-account check once, for all of them. A tool written next
|
|
47
|
+
year gets the check without its author having to remember, and a test refuses any
|
|
48
|
+
new code that tries to go around it.
|
|
49
|
+
|
|
50
|
+
Nothing about what the tools do has changed. The same requests go to the same
|
|
51
|
+
places with the same bodies and the same headers, including the two different
|
|
52
|
+
builder origins GoHighLevel requires for page saves and for everything else. If
|
|
53
|
+
you cannot tell the difference from the outside, that is the intended result.
|
|
54
|
+
|
|
55
|
+
Also in this release: `update_form` now tells you what a field needs in order to
|
|
56
|
+
RENDER rather than only how to send one. A custom question needs the real custom
|
|
57
|
+
field's id, key and data type from your account; a field written without them is
|
|
58
|
+
stored and shows as raw data instead of a rendered field.
|
|
59
|
+
|
|
60
|
+
> **Corrected 2026-09-12, in 3.83.5.** The last sentence is wrong. It was tested
|
|
61
|
+
> after this release shipped, not before: a field without those keys still renders
|
|
62
|
+
> normally in the form editor. They tie the answer to the contact record. That is
|
|
63
|
+
> what `update_form` says now.
|
|
64
|
+
|
|
5
65
|
## 3.83.3 — an account you marked protected is now actually protected
|
|
6
66
|
|
|
7
67
|
**Marking a client account protected did not stop fourteen write paths from writing to it.**
|
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1922,6 +1922,25 @@ function validateActionChain(actions, existingIds) {
|
|
|
1922
1922
|
}
|
|
1923
1923
|
}
|
|
1924
1924
|
}
|
|
1925
|
+
async function builderRequest(client, method, url, opts = {}) {
|
|
1926
|
+
assertWriteAllowed(method, url, { body: opts.body, defaultLocationId: client.locationId });
|
|
1927
|
+
const headers = { ...await client.buildHeaders(), ...opts.headers ?? {} };
|
|
1928
|
+
const init = { method, headers };
|
|
1929
|
+
if (opts.body !== void 0) init.body = JSON.stringify(opts.body);
|
|
1930
|
+
const controller = new AbortController();
|
|
1931
|
+
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
1932
|
+
init.signal = controller.signal;
|
|
1933
|
+
try {
|
|
1934
|
+
return await fetch(url, init);
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1937
|
+
throw new Error(`Request timeout (30s): ${method} ${url}`);
|
|
1938
|
+
}
|
|
1939
|
+
throw error;
|
|
1940
|
+
} finally {
|
|
1941
|
+
clearTimeout(timeout);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1925
1944
|
var fs4, path4, dotenv, import_zod4, BACKEND_BASE, FIREBASE_TOKEN_URL, MAX_RETRIES2, BASE_DELAY_MS2, FirebaseTokenSchema, WorkflowActionSchema, WorkflowFullSchema, CreateWorkflowResponseSchema, ParkedContactsError, UUID_V4, WorkflowBuilderClient;
|
|
1926
1945
|
var init_workflow_builder_client = __esm({
|
|
1927
1946
|
"src/workflow-builder-client.ts"() {
|
|
@@ -7435,14 +7454,8 @@ function registerEmailTools(server2, client) {
|
|
|
7435
7454
|
function registerEmailBuilderInternalTools(server2, builderClient, publicClient) {
|
|
7436
7455
|
if (!builderClient) return;
|
|
7437
7456
|
const client = builderClient;
|
|
7438
|
-
async function
|
|
7439
|
-
const
|
|
7440
|
-
assertWriteAllowed(method, `${EMAIL_BUILDER_BASE}${path39}`, { defaultLocationId: client.locationId });
|
|
7441
|
-
const response = await fetch(`${EMAIL_BUILDER_BASE}${path39}`, {
|
|
7442
|
-
method,
|
|
7443
|
-
headers,
|
|
7444
|
-
body: body ? JSON.stringify(body) : void 0
|
|
7445
|
-
});
|
|
7457
|
+
async function builderRequest2(method, path39, body) {
|
|
7458
|
+
const response = await builderRequest(client, method, `${EMAIL_BUILDER_BASE}${path39}`, body ? { body } : {});
|
|
7446
7459
|
if (!response.ok) {
|
|
7447
7460
|
const text2 = await response.text();
|
|
7448
7461
|
throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path39}
|
|
@@ -7464,7 +7477,7 @@ ${text2}`);
|
|
|
7464
7477
|
const loc = locationId2 ?? client.locationId;
|
|
7465
7478
|
return deleteEmailTemplateThroughDoors({
|
|
7466
7479
|
publicDelete: () => publicClient.delete(publicEmailTemplateDeletePath(loc, templateId)),
|
|
7467
|
-
internalDelete: () =>
|
|
7480
|
+
internalDelete: () => builderRequest2("DELETE", internalEmailTemplateDeletePath(templateId, loc))
|
|
7468
7481
|
});
|
|
7469
7482
|
}
|
|
7470
7483
|
);
|
|
@@ -7479,7 +7492,7 @@ ${text2}`);
|
|
|
7479
7492
|
},
|
|
7480
7493
|
async ({ templateId, name, locationId: locationId2 }) => {
|
|
7481
7494
|
const loc = locationId2 ?? client.locationId;
|
|
7482
|
-
return
|
|
7495
|
+
return builderRequest2("PATCH", `/${templateId}`, { locationId: loc, name });
|
|
7483
7496
|
}
|
|
7484
7497
|
);
|
|
7485
7498
|
safeTool(
|
|
@@ -7493,7 +7506,7 @@ ${text2}`);
|
|
|
7493
7506
|
},
|
|
7494
7507
|
async ({ templateId, archived, locationId: locationId2 }) => {
|
|
7495
7508
|
const loc = locationId2 ?? client.locationId;
|
|
7496
|
-
return
|
|
7509
|
+
return builderRequest2("PATCH", `/${templateId}`, { locationId: loc, archived: archived ?? true });
|
|
7497
7510
|
}
|
|
7498
7511
|
);
|
|
7499
7512
|
safeTool(
|
|
@@ -7508,11 +7521,8 @@ ${text2}`);
|
|
|
7508
7521
|
},
|
|
7509
7522
|
async ({ name, body, type, locationId: locationId2 }) => {
|
|
7510
7523
|
const loc = locationId2 ?? client.locationId;
|
|
7511
|
-
const
|
|
7512
|
-
|
|
7513
|
-
method: "POST",
|
|
7514
|
-
headers,
|
|
7515
|
-
body: JSON.stringify(buildSnippetPayload({ name, body, type }))
|
|
7524
|
+
const response = await builderRequest(client, "POST", `${SNIPPETS_BASE}/${loc}`, {
|
|
7525
|
+
body: buildSnippetPayload({ name, body, type })
|
|
7516
7526
|
});
|
|
7517
7527
|
if (!response.ok) {
|
|
7518
7528
|
const text2 = await response.text();
|
|
@@ -7542,8 +7552,8 @@ var init_emails = __esm({
|
|
|
7542
7552
|
init_account_read_retry();
|
|
7543
7553
|
init_account_reads();
|
|
7544
7554
|
import_zod28 = require("zod");
|
|
7555
|
+
init_workflow_builder_client();
|
|
7545
7556
|
init_tool_helpers();
|
|
7546
|
-
init_account_rules();
|
|
7547
7557
|
EMAIL_BUILDER_BASE = "https://backend.leadconnectorhq.com/emails/builder";
|
|
7548
7558
|
SNIPPETS_BASE = "https://services.leadconnectorhq.com/snippets";
|
|
7549
7559
|
TEMPLATE_TYPES = ["html", "folder", "import", "builder", "blank", "ai_template", "vibe-editor"];
|
|
@@ -11238,15 +11248,17 @@ function registerFunnelBuilderTools(server2, builderClient) {
|
|
|
11238
11248
|
return client.request("DELETE", path39);
|
|
11239
11249
|
}
|
|
11240
11250
|
async function funnelRequest(method, path39, body) {
|
|
11241
|
-
const headers = await client.buildHeaders();
|
|
11242
|
-
headers.Origin = "https://app.gohighlevel.com";
|
|
11243
|
-
headers.Referer = "https://app.gohighlevel.com/";
|
|
11244
11251
|
const url = `https://backend.leadconnectorhq.com/funnels${path39}`;
|
|
11245
|
-
const
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11252
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
11253
|
+
const response = await builderRequest(client, method, url, {
|
|
11254
|
+
...sendsBody ? { body } : {},
|
|
11255
|
+
headers: {
|
|
11256
|
+
// Internal-API calls require the app origin (autosave needs the
|
|
11257
|
+
// page-builder one instead; see the autosave call).
|
|
11258
|
+
Origin: "https://app.gohighlevel.com",
|
|
11259
|
+
Referer: "https://app.gohighlevel.com/"
|
|
11260
|
+
}
|
|
11261
|
+
});
|
|
11250
11262
|
if (!response.ok) {
|
|
11251
11263
|
const text2 = await response.text();
|
|
11252
11264
|
throw new Error(`Funnel API Error ${response.status}: ${method} ${path39}
|
|
@@ -11508,12 +11520,17 @@ ${text2}`);
|
|
|
11508
11520
|
};
|
|
11509
11521
|
}
|
|
11510
11522
|
async function autosaveRequest(pageId, body) {
|
|
11511
|
-
const headers = await client.buildHeaders();
|
|
11512
|
-
headers.Origin = "https://page-builder.leadconnectorhq.com";
|
|
11513
|
-
headers.Referer = "https://page-builder.leadconnectorhq.com/";
|
|
11514
11523
|
const url = `https://backend.leadconnectorhq.com/funnels/builder/autosave/${pageId}`;
|
|
11515
|
-
|
|
11516
|
-
|
|
11524
|
+
const response = await builderRequest(client, "POST", url, {
|
|
11525
|
+
body,
|
|
11526
|
+
headers: {
|
|
11527
|
+
// The autosave endpoint's IAM check requires the builder origin (verified
|
|
11528
|
+
// live — app.gohighlevel.com was not tested and page-builder is what the
|
|
11529
|
+
// real builder sends).
|
|
11530
|
+
Origin: "https://page-builder.leadconnectorhq.com",
|
|
11531
|
+
Referer: "https://page-builder.leadconnectorhq.com/"
|
|
11532
|
+
}
|
|
11533
|
+
});
|
|
11517
11534
|
if (!response.ok) {
|
|
11518
11535
|
throw new Error(`Funnel API Error ${response.status}: POST /builder/autosave/${pageId}
|
|
11519
11536
|
${await response.text()}`);
|
|
@@ -11619,9 +11636,9 @@ var init_funnel_builder = __esm({
|
|
|
11619
11636
|
"src/tools/funnel-builder.ts"() {
|
|
11620
11637
|
"use strict";
|
|
11621
11638
|
import_zod41 = require("zod");
|
|
11639
|
+
init_workflow_builder_client();
|
|
11622
11640
|
init_tool_helpers();
|
|
11623
11641
|
init_page_reads();
|
|
11624
|
-
init_account_rules();
|
|
11625
11642
|
}
|
|
11626
11643
|
});
|
|
11627
11644
|
|
|
@@ -16477,10 +16494,15 @@ function registerPageStudioTools(server2, builderClient) {
|
|
|
16477
16494
|
return { map: out, truncated };
|
|
16478
16495
|
}
|
|
16479
16496
|
async function funnelRequest(method, path39, body) {
|
|
16480
|
-
const
|
|
16481
|
-
|
|
16482
|
-
|
|
16483
|
-
|
|
16497
|
+
const response = await builderRequest(client, method, `https://backend.leadconnectorhq.com/funnels${path39}`, {
|
|
16498
|
+
...body ? { body } : {},
|
|
16499
|
+
headers: {
|
|
16500
|
+
// Internal-API calls require the app origin (autosave needs the
|
|
16501
|
+
// page-builder one instead; see the autosave call).
|
|
16502
|
+
Origin: "https://app.gohighlevel.com",
|
|
16503
|
+
Referer: "https://app.gohighlevel.com/"
|
|
16504
|
+
}
|
|
16505
|
+
});
|
|
16484
16506
|
if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path39}
|
|
16485
16507
|
${await response.text()}`);
|
|
16486
16508
|
const text = await response.text();
|
|
@@ -16497,15 +16519,13 @@ ${await response.text()}`);
|
|
|
16497
16519
|
}
|
|
16498
16520
|
}
|
|
16499
16521
|
async function autosaveRequest(pageId, body) {
|
|
16500
|
-
const headers = await client.buildHeaders();
|
|
16501
|
-
headers.Origin = "https://page-builder.leadconnectorhq.com";
|
|
16502
|
-
headers.Referer = "https://page-builder.leadconnectorhq.com/";
|
|
16503
16522
|
const autosaveUrl = `https://backend.leadconnectorhq.com/funnels/builder/autosave/${pageId}`;
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
|
|
16508
|
-
|
|
16523
|
+
const response = await builderRequest(client, "POST", autosaveUrl, {
|
|
16524
|
+
body,
|
|
16525
|
+
headers: {
|
|
16526
|
+
Origin: "https://page-builder.leadconnectorhq.com",
|
|
16527
|
+
Referer: "https://page-builder.leadconnectorhq.com/"
|
|
16528
|
+
}
|
|
16509
16529
|
});
|
|
16510
16530
|
if (!response.ok) throw new Error(`Funnel API Error ${response.status}: POST /builder/autosave/${pageId}
|
|
16511
16531
|
${await response.text()}`);
|
|
@@ -16991,6 +17011,7 @@ var init_page_studio = __esm({
|
|
|
16991
17011
|
"use strict";
|
|
16992
17012
|
import_zod43 = require("zod");
|
|
16993
17013
|
crypto4 = __toESM(require("node:crypto"));
|
|
17014
|
+
init_workflow_builder_client();
|
|
16994
17015
|
init_ghl_templates();
|
|
16995
17016
|
init_retheme();
|
|
16996
17017
|
init_ghl_page();
|
|
@@ -16999,7 +17020,6 @@ var init_page_studio = __esm({
|
|
|
16999
17020
|
init_tool_helpers();
|
|
17000
17021
|
init_compose();
|
|
17001
17022
|
init_website();
|
|
17002
|
-
init_account_rules();
|
|
17003
17023
|
valueCardSchema = import_zod43.z.object({
|
|
17004
17024
|
title: import_zod43.z.string().describe("Card title (short, uppercase reads best)."),
|
|
17005
17025
|
bodyHtml: import_zod43.z.string().describe("Card body as HTML (<p>\u2026</p>). May use {{location.*}} merge fields."),
|
|
@@ -17088,14 +17108,9 @@ function cleanFormDataForSave(formData) {
|
|
|
17088
17108
|
return isJsonObject(cleaned) ? cleaned : formData;
|
|
17089
17109
|
}
|
|
17090
17110
|
async function formApiRequest(client, method, path39, body) {
|
|
17091
|
-
const headers = await client.buildHeaders();
|
|
17092
17111
|
const url = `https://backend.leadconnectorhq.com/forms${path39}`;
|
|
17093
|
-
|
|
17094
|
-
const
|
|
17095
|
-
if (body && (method === "POST" || method === "PUT")) {
|
|
17096
|
-
options.body = JSON.stringify(body);
|
|
17097
|
-
}
|
|
17098
|
-
const response = await fetch(url, options);
|
|
17112
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
17113
|
+
const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
|
|
17099
17114
|
if (!response.ok) {
|
|
17100
17115
|
const text2 = await response.text();
|
|
17101
17116
|
throw new Error(`Form API Error ${response.status}: ${method} ${path39}
|
|
@@ -17162,10 +17177,10 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
|
|
|
17162
17177
|
);
|
|
17163
17178
|
server2.tool(
|
|
17164
17179
|
"update_form",
|
|
17165
|
-
"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).",
|
|
17180
|
+
"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). IMPORTANT \u2014 a custom-question field should carry the real custom field's `id`, `fieldKey` and `dataType` from THIS account (read them with get_custom_fields; do not invent them), and a standard field (first_name, last_name, email, phone) needs `standard: true` with its `tag`. That binding is what ties the answer to the contact record. A field WITHOUT it still renders in the form editor \u2014 verified live on 2026-09-12, so do not expect a missing binding to show up as a broken field. Copy an existing field from get_form_full rather than composing one from memory; these shapes were reverse-engineered from live UI-built forms.",
|
|
17166
17181
|
{
|
|
17167
17182
|
formId: import_zod44.z.string().describe("The form ID to update."),
|
|
17168
|
-
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."),
|
|
17183
|
+
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. Fields live at formData.form.fields; each one needs the binding described above or the editor cannot render it."),
|
|
17169
17184
|
name: import_zod44.z.string().optional().describe("Updated form name. If omitted, the current name is preserved.")
|
|
17170
17185
|
},
|
|
17171
17186
|
async ({ formId, formData, name }) => {
|
|
@@ -17292,8 +17307,8 @@ var init_form_builder = __esm({
|
|
|
17292
17307
|
"src/tools/form-builder.ts"() {
|
|
17293
17308
|
"use strict";
|
|
17294
17309
|
import_zod44 = require("zod");
|
|
17310
|
+
init_workflow_builder_client();
|
|
17295
17311
|
init_tool_helpers();
|
|
17296
|
-
init_account_rules();
|
|
17297
17312
|
}
|
|
17298
17313
|
});
|
|
17299
17314
|
|
|
@@ -17686,14 +17701,9 @@ function registerPipelineBuilderTools(server2, builderClient) {
|
|
|
17686
17701
|
if (!builderClient) return;
|
|
17687
17702
|
const client = builderClient;
|
|
17688
17703
|
async function pipelineRequest(method, path39, body) {
|
|
17689
|
-
const headers = await client.buildHeaders();
|
|
17690
17704
|
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path39}`;
|
|
17691
|
-
|
|
17692
|
-
const
|
|
17693
|
-
if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
|
|
17694
|
-
options.body = JSON.stringify(body);
|
|
17695
|
-
}
|
|
17696
|
-
const response = await fetch(url, options);
|
|
17705
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT" || method === "PATCH");
|
|
17706
|
+
const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
|
|
17697
17707
|
if (!response.ok) {
|
|
17698
17708
|
const text2 = await response.text();
|
|
17699
17709
|
throw new Error(`Pipeline API Error ${response.status}: ${method} ${path39}
|
|
@@ -17871,7 +17881,7 @@ var init_pipeline_builder = __esm({
|
|
|
17871
17881
|
"src/tools/pipeline-builder.ts"() {
|
|
17872
17882
|
"use strict";
|
|
17873
17883
|
import_zod46 = require("zod");
|
|
17874
|
-
|
|
17884
|
+
init_workflow_builder_client();
|
|
17875
17885
|
}
|
|
17876
17886
|
});
|
|
17877
17887
|
|
|
@@ -21358,7 +21368,7 @@ function tokensCss(d, theme) {
|
|
|
21358
21368
|
];
|
|
21359
21369
|
return [...light, "", ...dark].join("\n");
|
|
21360
21370
|
}
|
|
21361
|
-
function composeBrief(d, brief) {
|
|
21371
|
+
function composeBrief(d, brief, packOpts = {}) {
|
|
21362
21372
|
const conversionMode = brief.options.pageMode === "conversion" && brief.conversion;
|
|
21363
21373
|
const { design, antiDefault } = rulesFor(brief.medium, "html", conversionMode ? "conversion" : "standard");
|
|
21364
21374
|
const opts = brief.options;
|
|
@@ -21475,7 +21485,7 @@ ${cleanLogo.slice(0, 6e3)}` : d.logo?.dataUri ? `Logo markup: <img src="${d.logo
|
|
|
21475
21485
|
"## Before you finish",
|
|
21476
21486
|
...checklist.map((c) => `- [ ] ${c}`),
|
|
21477
21487
|
"",
|
|
21478
|
-
`Write the whole file to \`${fileName}\`. Then run lint_design_contract, then verify_design; fix what they name; stop after three passes and report.`
|
|
21488
|
+
...packOpts.tools === false ? [] : [`Write the whole file to \`${fileName}\`. Then run lint_design_contract, then verify_design; fix what they name; stop after three passes and report.`]
|
|
21479
21489
|
].join("\n");
|
|
21480
21490
|
return { fileName, markdown, tokensCss: css2, rules: design, antiDefault, contract: chosenContract, checklist, bannedTells };
|
|
21481
21491
|
}
|
|
@@ -28581,7 +28591,7 @@ var require_package = __commonJS({
|
|
|
28581
28591
|
"package.json"(exports2, module2) {
|
|
28582
28592
|
module2.exports = {
|
|
28583
28593
|
name: "@elitedcs/ghl-mcp",
|
|
28584
|
-
version: "3.83.
|
|
28594
|
+
version: "3.83.5",
|
|
28585
28595
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
28586
28596
|
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.",
|
|
28587
28597
|
main: "dist/index.js",
|
|
@@ -32387,8 +32397,18 @@ ${d.provenance.source ? `<p class="small">Source: ${esc5(d.provenance.source.url
|
|
|
32387
32397
|
${opts.dir ? `<p class="small">Stored at ${esc5(opts.dir)}</p>` : ""}
|
|
32388
32398
|
${foot(SHELL_JS(opts.seatToken ?? "") + `
|
|
32389
32399
|
(function(){
|
|
32390
|
-
var poll=null,runId=null;
|
|
32391
|
-
function stopPolling(){if(poll){clearInterval(poll);poll=null}}
|
|
32400
|
+
var poll=null,runId=null,started=0,ticker=null,passes=0;
|
|
32401
|
+
function stopPolling(){if(poll){clearInterval(poll);poll=null}if(ticker){clearInterval(ticker);ticker=null}}
|
|
32402
|
+
function elapsed(ms){var s=Math.floor(ms/1000),m=Math.floor(s/60);s=s%60;return m?(m+"m "+(s<10?"0":"")+s+"s"):(s+"s")}
|
|
32403
|
+
/* The run prints NOTHING while Claude writes - it answers in one go, so the log
|
|
32404
|
+
box sits still for ten minutes or more. Silence used to be indistinguishable
|
|
32405
|
+
from a dead run, and the rational move was to press Stop on a working one
|
|
32406
|
+
(BUG-2026-09-12-03). So the cockpit keeps its own clock: it needs nothing
|
|
32407
|
+
from the child process, and it ticks every second, not every poll. */
|
|
32408
|
+
function tick(){
|
|
32409
|
+
if(!started)return;
|
|
32410
|
+
say("mk-status","Working on your Claude: "+elapsed(Date.now()-started)+" so far"+(passes?(", on pass "+(passes+1)):"")+". Claude writes the whole file in one answer, so nothing appears below until a pass finishes. Ten to twenty minutes is normal. Closing this tab does not stop it.");
|
|
32411
|
+
}
|
|
32392
32412
|
function show(t){var el=document.getElementById("mk-log");el.hidden=false;el.textContent=t}
|
|
32393
32413
|
document.getElementById("make").addEventListener("submit",async function(e){
|
|
32394
32414
|
e.preventDefault();
|
|
@@ -32405,24 +32425,25 @@ document.getElementById("make").addEventListener("submit",async function(e){
|
|
|
32405
32425
|
var r=await post("/api/design/run",body);
|
|
32406
32426
|
runId=r.id;
|
|
32407
32427
|
document.getElementById("mk-cancel").hidden=false;
|
|
32408
|
-
|
|
32428
|
+
started=Date.now();passes=0;tick();ticker=setInterval(tick,1000);
|
|
32409
32429
|
poll=setInterval(async function(){
|
|
32410
32430
|
var s=await (await fetch("/api/design/run?id="+encodeURIComponent(runId))).json();
|
|
32411
|
-
|
|
32412
|
-
"));
|
|
32431
|
+
var lines=s.tail||[];
|
|
32432
|
+
show(lines.join("\\n"));
|
|
32433
|
+
passes=lines.filter(function(l){return l.trim().slice(0,5)==="pass "}).length;
|
|
32413
32434
|
if(s.status!=="running"){
|
|
32414
32435
|
stopPolling();go.disabled=false;document.getElementById("mk-cancel").hidden=true;
|
|
32415
32436
|
var run=s.run||{};
|
|
32416
32437
|
var design=run.ok?"design PASS on pass "+run.greenAt:"design NOT GREEN";
|
|
32417
|
-
var copy=run.copy?(run.copy.error?" \xB7 copy not graded":" \xB7 copy "+run.copy.verdict+(run.copy.firstBreakdown?" (first breakdown: "+run.copy.firstBreakdown+")"
|
|
32438
|
+
var copy=run.copy?(run.copy.error?" \xB7 copy not graded":" \xB7 copy "+run.copy.verdict+(run.copy.firstBreakdown?" (first breakdown: "+run.copy.firstBreakdown+")":"")):"";
|
|
32418
32439
|
say("mk-status",s.status==="done"?design+copy+" \xB7 "+(run.file||s.outDir):"The run stopped: "+design+copy,s.status==="done"&&run.ok?"ok":"err");
|
|
32419
32440
|
}
|
|
32420
32441
|
},4000);
|
|
32421
|
-
}catch(err){say("mk-status",err.message,"err");go.disabled=false}
|
|
32442
|
+
}catch(err){stopPolling();started=0;say("mk-status",err.message,"err");go.disabled=false}
|
|
32422
32443
|
});
|
|
32423
32444
|
document.getElementById("mk-cancel").addEventListener("click",async function(){
|
|
32424
32445
|
if(!runId)return;
|
|
32425
|
-
try{await post("/api/design/cancel",{id:runId});stopPolling();say("mk-status","Stopped.");document.getElementById("mk-go").disabled=false;this.hidden=true}catch(e){say("mk-status",e.message,"err")}
|
|
32446
|
+
try{await post("/api/design/cancel",{id:runId});stopPolling();started=0;say("mk-status","Stopped.");document.getElementById("mk-go").disabled=false;this.hidden=true}catch(e){say("mk-status",e.message,"err")}
|
|
32426
32447
|
});
|
|
32427
32448
|
})();
|
|
32428
32449
|
document.getElementById("override").addEventListener("submit",async(e)=>{e.preventDefault();const g=(id)=>document.getElementById(id).value.trim();const body={slug:${scriptJson(d.slug)}};if(g("accent"))body.accent=g("accent");if(g("displayFont"))body.displayFont=g("displayFont");if(g("bodyFont"))body.bodyFont=g("bodyFont");if(g("brandName"))body.name=g("brandName");if(g("logoSvg"))body.logoSvg=g("logoSvg");if(Object.keys(body).length===1){say("save-status","Nothing to change.");return}const b=document.getElementById("save");b.disabled=true;try{await post("/api/brand/set",body);say("save-status","Saved.","ok");location.reload()}catch(err){say("save-status",err.message,"err");b.disabled=false}});
|
|
@@ -39216,14 +39237,9 @@ function registerSmartListTools(server2, builderClient) {
|
|
|
39216
39237
|
if (!builderClient) return;
|
|
39217
39238
|
const client = builderClient;
|
|
39218
39239
|
async function smartListRequest(method, path39, body) {
|
|
39219
|
-
const headers = await client.buildHeaders();
|
|
39220
39240
|
const url = `${SMARTLIST_BASE}${path39}`;
|
|
39221
|
-
|
|
39222
|
-
const
|
|
39223
|
-
if (body && (method === "POST" || method === "PUT")) {
|
|
39224
|
-
options.body = JSON.stringify(body);
|
|
39225
|
-
}
|
|
39226
|
-
const response = await fetch(url, options);
|
|
39241
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
39242
|
+
const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
|
|
39227
39243
|
if (!response.ok) {
|
|
39228
39244
|
const text2 = await response.text();
|
|
39229
39245
|
throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path39}
|
|
@@ -39288,8 +39304,7 @@ ${await res.text()}`);
|
|
|
39288
39304
|
];
|
|
39289
39305
|
const body = buildContactSmartListBody({ listName: name, locationId: loc, filters });
|
|
39290
39306
|
const headers = await client.buildHeaders();
|
|
39291
|
-
|
|
39292
|
-
const res = await fetch(CONTACT_SMARTLIST_BASE, { method: "POST", headers, body: JSON.stringify(body) });
|
|
39307
|
+
const res = await builderRequest(client, "POST", CONTACT_SMARTLIST_BASE, { body });
|
|
39293
39308
|
if (!res.ok) throw new Error(`Smart Lists API Error ${res.status}: POST /contacts/smartlist
|
|
39294
39309
|
${await res.text()}`);
|
|
39295
39310
|
return jsonResponse(JSON.parse(await res.text() || "{}"));
|
|
@@ -39326,12 +39341,7 @@ ${await res.text()}`);
|
|
|
39326
39341
|
async ({ listId }) => {
|
|
39327
39342
|
try {
|
|
39328
39343
|
const headers = await client.buildHeaders();
|
|
39329
|
-
|
|
39330
|
-
const res = await fetch(CONTACT_SMARTLIST_DELETE, {
|
|
39331
|
-
method: "POST",
|
|
39332
|
-
headers,
|
|
39333
|
-
body: JSON.stringify({ smartlist_id: listId })
|
|
39334
|
-
});
|
|
39344
|
+
const res = await builderRequest(client, "POST", CONTACT_SMARTLIST_DELETE, { body: { smartlist_id: listId } });
|
|
39335
39345
|
if (!res.ok) throw new Error(`Smart Lists API Error ${res.status}: POST /smartlist/delete
|
|
39336
39346
|
${await res.text()}`);
|
|
39337
39347
|
return jsonResponse(JSON.parse(await res.text() || "{}"));
|
|
@@ -39439,8 +39449,8 @@ var init_smart_lists = __esm({
|
|
|
39439
39449
|
"src/tools/smart-lists.ts"() {
|
|
39440
39450
|
"use strict";
|
|
39441
39451
|
import_zod57 = require("zod");
|
|
39452
|
+
init_workflow_builder_client();
|
|
39442
39453
|
init_tool_helpers();
|
|
39443
|
-
init_account_rules();
|
|
39444
39454
|
SMARTLIST_BASE = "https://backend.leadconnectorhq.com/lists/dynamic";
|
|
39445
39455
|
OBJECT_KEYS = ["contacts", "opportunity"];
|
|
39446
39456
|
CONTACT_SMARTLIST_BASE = "https://services.leadconnectorhq.com/contacts/smartlist";
|
|
@@ -39462,9 +39472,7 @@ function registerReputationTools(server2, builderClient) {
|
|
|
39462
39472
|
if (!builderClient) return;
|
|
39463
39473
|
const client = builderClient;
|
|
39464
39474
|
async function reputationRequest(method, path39) {
|
|
39465
|
-
|
|
39466
|
-
const headers = await client.buildHeaders();
|
|
39467
|
-
const response = await fetch(`${REPUTATION_BASE}${path39}`, { method, headers });
|
|
39475
|
+
const response = await builderRequest(client, method, `${REPUTATION_BASE}${path39}`);
|
|
39468
39476
|
if (!response.ok) {
|
|
39469
39477
|
const text2 = await response.text();
|
|
39470
39478
|
throw new Error(`Reputation API Error ${response.status}: ${method} ${path39}
|
|
@@ -39540,8 +39548,8 @@ var init_reputation = __esm({
|
|
|
39540
39548
|
"src/tools/reputation.ts"() {
|
|
39541
39549
|
"use strict";
|
|
39542
39550
|
import_zod58 = require("zod");
|
|
39551
|
+
init_workflow_builder_client();
|
|
39543
39552
|
init_tool_helpers();
|
|
39544
|
-
init_account_rules();
|
|
39545
39553
|
REPUTATION_BASE = "https://backend.leadconnectorhq.com/reputation";
|
|
39546
39554
|
}
|
|
39547
39555
|
});
|
|
@@ -39575,13 +39583,7 @@ function registerEmailCampaignTools(server2, builderClient) {
|
|
|
39575
39583
|
if (isPlainText !== void 0) body.isPlainText = isPlainText;
|
|
39576
39584
|
if (enableResendToUnopened !== void 0) body.enableResendToUnopened = enableResendToUnopened;
|
|
39577
39585
|
if (hasUtmTracking !== void 0) body.hasUtmTracking = hasUtmTracking;
|
|
39578
|
-
const
|
|
39579
|
-
assertWriteAllowed("POST", `${SVC_BASE}/emails/schedule`, { defaultLocationId: client.locationId });
|
|
39580
|
-
const response = await fetch(`${SVC_BASE}/emails/schedule`, {
|
|
39581
|
-
method: "POST",
|
|
39582
|
-
headers,
|
|
39583
|
-
body: JSON.stringify(body)
|
|
39584
|
-
});
|
|
39586
|
+
const response = await builderRequest(client, "POST", `${SVC_BASE}/emails/schedule`, { body });
|
|
39585
39587
|
if (!response.ok) {
|
|
39586
39588
|
const text2 = await response.text();
|
|
39587
39589
|
throw new Error(`Email Campaign API Error ${response.status}: POST /emails/schedule
|
|
@@ -39601,8 +39603,8 @@ var init_email_campaigns = __esm({
|
|
|
39601
39603
|
"src/tools/email-campaigns.ts"() {
|
|
39602
39604
|
"use strict";
|
|
39603
39605
|
import_zod59 = require("zod");
|
|
39606
|
+
init_workflow_builder_client();
|
|
39604
39607
|
init_tool_helpers();
|
|
39605
|
-
init_account_rules();
|
|
39606
39608
|
SVC_BASE = "https://services.leadconnectorhq.com";
|
|
39607
39609
|
}
|
|
39608
39610
|
});
|
|
@@ -39612,13 +39614,7 @@ function registerMembershipTools(server2, builderClient) {
|
|
|
39612
39614
|
if (!builderClient) return;
|
|
39613
39615
|
const client = builderClient;
|
|
39614
39616
|
async function membershipRequest(path39, method = "GET", body) {
|
|
39615
|
-
|
|
39616
|
-
const headers = await client.buildHeaders();
|
|
39617
|
-
const response = await fetch(`${MEMBERSHIP_BASE2}${path39}`, {
|
|
39618
|
-
method,
|
|
39619
|
-
headers,
|
|
39620
|
-
body: body ? JSON.stringify(body) : void 0
|
|
39621
|
-
});
|
|
39617
|
+
const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${path39}`, body ? { body } : {});
|
|
39622
39618
|
if (!response.ok) {
|
|
39623
39619
|
const text2 = await response.text();
|
|
39624
39620
|
throw new Error(`Membership API Error ${response.status}: ${method} ${path39}
|
|
@@ -39799,8 +39795,8 @@ var init_memberships = __esm({
|
|
|
39799
39795
|
"src/tools/memberships.ts"() {
|
|
39800
39796
|
"use strict";
|
|
39801
39797
|
import_zod60 = require("zod");
|
|
39798
|
+
init_workflow_builder_client();
|
|
39802
39799
|
init_tool_helpers();
|
|
39803
|
-
init_account_rules();
|
|
39804
39800
|
MEMBERSHIP_BASE2 = "https://backend.leadconnectorhq.com/membership";
|
|
39805
39801
|
}
|
|
39806
39802
|
});
|
|
@@ -40148,12 +40144,8 @@ Pipelines: ${template.pipelines.length} to create`);
|
|
|
40148
40144
|
}
|
|
40149
40145
|
} else {
|
|
40150
40146
|
try {
|
|
40151
|
-
const
|
|
40152
|
-
|
|
40153
|
-
const res = await fetch("https://backend.leadconnectorhq.com/opportunities/pipelines", {
|
|
40154
|
-
method: "POST",
|
|
40155
|
-
headers,
|
|
40156
|
-
body: JSON.stringify({
|
|
40147
|
+
const res = await builderRequest(builderClient, "POST", "https://backend.leadconnectorhq.com/opportunities/pipelines", {
|
|
40148
|
+
body: {
|
|
40157
40149
|
name: resolved2.name,
|
|
40158
40150
|
stages: (resolved2.stages || []).map((s) => ({
|
|
40159
40151
|
...s,
|
|
@@ -40163,7 +40155,7 @@ Pipelines: ${template.pipelines.length} to create`);
|
|
|
40163
40155
|
locationId: locId,
|
|
40164
40156
|
showInFunnel: true,
|
|
40165
40157
|
showInPieChart: true
|
|
40166
|
-
}
|
|
40158
|
+
}
|
|
40167
40159
|
});
|
|
40168
40160
|
if (res.ok) {
|
|
40169
40161
|
counts.pipelines.created++;
|
|
@@ -40324,7 +40316,7 @@ var init_template_deployer = __esm({
|
|
|
40324
40316
|
init_tool_helpers();
|
|
40325
40317
|
fs28 = __toESM(require("fs"));
|
|
40326
40318
|
path27 = __toESM(require("path"));
|
|
40327
|
-
|
|
40319
|
+
init_workflow_builder_client();
|
|
40328
40320
|
TemplateSchema = import_zod61.z.object({
|
|
40329
40321
|
templateName: import_zod61.z.string(),
|
|
40330
40322
|
templateVersion: import_zod61.z.string().optional(),
|
|
@@ -43708,7 +43700,7 @@ async function runDesign(opts) {
|
|
|
43708
43700
|
const medium = brief.medium;
|
|
43709
43701
|
const outDir = (0, import_node_path7.resolve)(opts.outDir);
|
|
43710
43702
|
(0, import_node_fs7.mkdirSync)(outDir, { recursive: true });
|
|
43711
|
-
const pack = composeBrief(dna, brief);
|
|
43703
|
+
const pack = composeBrief(dna, brief, { tools: false });
|
|
43712
43704
|
const maxPasses = Math.max(1, Math.min(3, opts.maxPasses ?? 3));
|
|
43713
43705
|
const generate = opts.generate ?? claudeGenerate(opts.model ?? DEFAULT_MODEL);
|
|
43714
43706
|
const conversionRun = brief.options.pageMode === "conversion" && brief.conversion ? { brief: brief.conversion, gate: opts.gate ?? "ship" } : void 0;
|
|
@@ -50986,9 +50978,7 @@ function pickCalendarPins(workflow) {
|
|
|
50986
50978
|
}
|
|
50987
50979
|
function makeFirebaseRequest(builderClient) {
|
|
50988
50980
|
return async (url, method, body) => {
|
|
50989
|
-
|
|
50990
|
-
const headers = await builderClient.buildHeaders();
|
|
50991
|
-
const response = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : void 0 });
|
|
50981
|
+
const response = await builderRequest(builderClient, method, url, body ? { body } : {});
|
|
50992
50982
|
if (!response.ok) {
|
|
50993
50983
|
const text2 = await response.text();
|
|
50994
50984
|
throw new Error(`API ${response.status}: ${method} ${url.replace(/^https:\/\/[^/]+/, "")}
|
|
@@ -51000,11 +50990,9 @@ ${text2}`);
|
|
|
51000
50990
|
}
|
|
51001
50991
|
function makePipelineApi(builderClient) {
|
|
51002
50992
|
return async (method, path39, body) => {
|
|
51003
|
-
const headers = await builderClient.buildHeaders();
|
|
51004
50993
|
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path39}`;
|
|
51005
|
-
const
|
|
51006
|
-
|
|
51007
|
-
const response = await fetch(url, options);
|
|
50994
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
50995
|
+
const response = await builderRequest(builderClient, method, url, sendsBody ? { body } : {});
|
|
51008
50996
|
if (!response.ok) {
|
|
51009
50997
|
const text2 = await response.text();
|
|
51010
50998
|
throw new Error(`Pipeline API ${response.status}: ${method} ${path39}
|
|
@@ -51021,13 +51009,17 @@ ${text2}`);
|
|
|
51021
51009
|
}
|
|
51022
51010
|
function makeFunnelApi(builderClient) {
|
|
51023
51011
|
return async (method, path39, body) => {
|
|
51024
|
-
const headers = await builderClient.buildHeaders();
|
|
51025
|
-
headers.Origin = "https://app.gohighlevel.com";
|
|
51026
|
-
headers.Referer = "https://app.gohighlevel.com/";
|
|
51027
51012
|
const url = `https://backend.leadconnectorhq.com/funnels${path39}`;
|
|
51028
|
-
const
|
|
51029
|
-
|
|
51030
|
-
|
|
51013
|
+
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
51014
|
+
const response = await builderRequest(builderClient, method, url, {
|
|
51015
|
+
...sendsBody ? { body } : {},
|
|
51016
|
+
headers: {
|
|
51017
|
+
// Origin/Referer REQUIRED on internal-API funnel writes (else 401
|
|
51018
|
+
// "Error calling IAM service") — verified in funnel-builder.ts.
|
|
51019
|
+
Origin: "https://app.gohighlevel.com",
|
|
51020
|
+
Referer: "https://app.gohighlevel.com/"
|
|
51021
|
+
}
|
|
51022
|
+
});
|
|
51031
51023
|
if (!response.ok) {
|
|
51032
51024
|
const text2 = await response.text();
|
|
51033
51025
|
throw new Error(`Funnel API ${response.status}: ${method} ${path39}
|
|
@@ -52138,6 +52130,7 @@ var init_intake_to_build = __esm({
|
|
|
52138
52130
|
init_build_contract();
|
|
52139
52131
|
init_build_obligations();
|
|
52140
52132
|
import_zod80 = require("zod");
|
|
52133
|
+
init_workflow_builder_client();
|
|
52141
52134
|
init_tool_helpers();
|
|
52142
52135
|
init_form_builder();
|
|
52143
52136
|
init_calendars();
|
|
@@ -52160,7 +52153,6 @@ var init_intake_to_build = __esm({
|
|
|
52160
52153
|
init_plan_from_preset();
|
|
52161
52154
|
init_executor();
|
|
52162
52155
|
init_execute();
|
|
52163
|
-
init_account_rules();
|
|
52164
52156
|
customFieldItemSchema = import_zod80.z.object({
|
|
52165
52157
|
id: import_zod80.z.string(),
|
|
52166
52158
|
name: import_zod80.z.string(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.83.
|
|
3
|
+
"version": "3.83.5",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
5
|
"description": "GoHighLevel MCP Server for Claude. 250 tools — 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.",
|
|
6
6
|
"main": "dist/index.js",
|