@elitedcs/ghl-mcp 3.83.4 → 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 +34 -0
- package/README.md +1 -1
- package/dist/index.js +24 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
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
|
+
|
|
5
34
|
## 3.83.4 — one door for every write, so "protected" cannot quietly stop meaning protected
|
|
6
35
|
|
|
7
36
|
3.83.3 fixed the holes. This closes the shape that kept making them.
|
|
@@ -28,6 +57,11 @@ RENDER rather than only how to send one. A custom question needs the real custom
|
|
|
28
57
|
field's id, key and data type from your account; a field written without them is
|
|
29
58
|
stored and shows as raw data instead of a rendered field.
|
|
30
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
|
+
|
|
31
65
|
## 3.83.3 — an account you marked protected is now actually protected
|
|
32
66
|
|
|
33
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
|
@@ -17177,7 +17177,7 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
|
|
|
17177
17177
|
);
|
|
17178
17178
|
server2.tool(
|
|
17179
17179
|
"update_form",
|
|
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
|
|
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.",
|
|
17181
17181
|
{
|
|
17182
17182
|
formId: import_zod44.z.string().describe("The form ID to update."),
|
|
17183
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."),
|
|
@@ -21368,7 +21368,7 @@ function tokensCss(d, theme) {
|
|
|
21368
21368
|
];
|
|
21369
21369
|
return [...light, "", ...dark].join("\n");
|
|
21370
21370
|
}
|
|
21371
|
-
function composeBrief(d, brief) {
|
|
21371
|
+
function composeBrief(d, brief, packOpts = {}) {
|
|
21372
21372
|
const conversionMode = brief.options.pageMode === "conversion" && brief.conversion;
|
|
21373
21373
|
const { design, antiDefault } = rulesFor(brief.medium, "html", conversionMode ? "conversion" : "standard");
|
|
21374
21374
|
const opts = brief.options;
|
|
@@ -21485,7 +21485,7 @@ ${cleanLogo.slice(0, 6e3)}` : d.logo?.dataUri ? `Logo markup: <img src="${d.logo
|
|
|
21485
21485
|
"## Before you finish",
|
|
21486
21486
|
...checklist.map((c) => `- [ ] ${c}`),
|
|
21487
21487
|
"",
|
|
21488
|
-
`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.`]
|
|
21489
21489
|
].join("\n");
|
|
21490
21490
|
return { fileName, markdown, tokensCss: css2, rules: design, antiDefault, contract: chosenContract, checklist, bannedTells };
|
|
21491
21491
|
}
|
|
@@ -28591,7 +28591,7 @@ var require_package = __commonJS({
|
|
|
28591
28591
|
"package.json"(exports2, module2) {
|
|
28592
28592
|
module2.exports = {
|
|
28593
28593
|
name: "@elitedcs/ghl-mcp",
|
|
28594
|
-
version: "3.83.
|
|
28594
|
+
version: "3.83.5",
|
|
28595
28595
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
28596
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.",
|
|
28597
28597
|
main: "dist/index.js",
|
|
@@ -32397,8 +32397,18 @@ ${d.provenance.source ? `<p class="small">Source: ${esc5(d.provenance.source.url
|
|
|
32397
32397
|
${opts.dir ? `<p class="small">Stored at ${esc5(opts.dir)}</p>` : ""}
|
|
32398
32398
|
${foot(SHELL_JS(opts.seatToken ?? "") + `
|
|
32399
32399
|
(function(){
|
|
32400
|
-
var poll=null,runId=null;
|
|
32401
|
-
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
|
+
}
|
|
32402
32412
|
function show(t){var el=document.getElementById("mk-log");el.hidden=false;el.textContent=t}
|
|
32403
32413
|
document.getElementById("make").addEventListener("submit",async function(e){
|
|
32404
32414
|
e.preventDefault();
|
|
@@ -32415,24 +32425,25 @@ document.getElementById("make").addEventListener("submit",async function(e){
|
|
|
32415
32425
|
var r=await post("/api/design/run",body);
|
|
32416
32426
|
runId=r.id;
|
|
32417
32427
|
document.getElementById("mk-cancel").hidden=false;
|
|
32418
|
-
|
|
32428
|
+
started=Date.now();passes=0;tick();ticker=setInterval(tick,1000);
|
|
32419
32429
|
poll=setInterval(async function(){
|
|
32420
32430
|
var s=await (await fetch("/api/design/run?id="+encodeURIComponent(runId))).json();
|
|
32421
|
-
|
|
32422
|
-
"));
|
|
32431
|
+
var lines=s.tail||[];
|
|
32432
|
+
show(lines.join("\\n"));
|
|
32433
|
+
passes=lines.filter(function(l){return l.trim().slice(0,5)==="pass "}).length;
|
|
32423
32434
|
if(s.status!=="running"){
|
|
32424
32435
|
stopPolling();go.disabled=false;document.getElementById("mk-cancel").hidden=true;
|
|
32425
32436
|
var run=s.run||{};
|
|
32426
32437
|
var design=run.ok?"design PASS on pass "+run.greenAt:"design NOT GREEN";
|
|
32427
|
-
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+")":"")):"";
|
|
32428
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");
|
|
32429
32440
|
}
|
|
32430
32441
|
},4000);
|
|
32431
|
-
}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}
|
|
32432
32443
|
});
|
|
32433
32444
|
document.getElementById("mk-cancel").addEventListener("click",async function(){
|
|
32434
32445
|
if(!runId)return;
|
|
32435
|
-
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")}
|
|
32436
32447
|
});
|
|
32437
32448
|
})();
|
|
32438
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}});
|
|
@@ -43689,7 +43700,7 @@ async function runDesign(opts) {
|
|
|
43689
43700
|
const medium = brief.medium;
|
|
43690
43701
|
const outDir = (0, import_node_path7.resolve)(opts.outDir);
|
|
43691
43702
|
(0, import_node_fs7.mkdirSync)(outDir, { recursive: true });
|
|
43692
|
-
const pack = composeBrief(dna, brief);
|
|
43703
|
+
const pack = composeBrief(dna, brief, { tools: false });
|
|
43693
43704
|
const maxPasses = Math.max(1, Math.min(3, opts.maxPasses ?? 3));
|
|
43694
43705
|
const generate = opts.generate ?? claudeGenerate(opts.model ?? DEFAULT_MODEL);
|
|
43695
43706
|
const conversionRun = brief.options.pageMode === "conversion" && brief.conversion ? { brief: brief.conversion, gate: opts.gate ?? "ship" } : void 0;
|
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",
|