@elitedcs/ghl-mcp 3.72.2 → 3.72.3
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 +24 -0
- package/dist/index.js +44 -5
- package/package.json +1 -1
- package/templates/action-schemas.json +2 -2
- package/templates/clinic-medspa.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.72.3 — the waits in a built account can actually go live
|
|
4
|
+
|
|
5
|
+
Blueprint builds a client's account and then asks whether to publish the workflows or
|
|
6
|
+
leave them as drafts for review. Say publish, and the ones with a wait of a day or more
|
|
7
|
+
were refused by GoHighLevel and stayed as drafts. The build still reported them as
|
|
8
|
+
created, so the account looked finished when the follow-up sequences were not running.
|
|
9
|
+
|
|
10
|
+
The cause was one word. GoHighLevel takes `minutes` and `hour`, but for days it wants
|
|
11
|
+
`days`, and we were sending `day`. It is not a rule you can guess: a workflow that is
|
|
12
|
+
nothing but a wait accepts the singular quite happily, which is why this went unnoticed.
|
|
13
|
+
It only fails on the shape a real nurture has, a message followed by a wait, which is
|
|
14
|
+
every follow-up sequence the presets build. **123 of the waits in the shipped presets
|
|
15
|
+
were affected.**
|
|
16
|
+
|
|
17
|
+
Workflows already in an account are untouched and keep working; this was only ever about
|
|
18
|
+
newly built ones.
|
|
19
|
+
|
|
20
|
+
**The second half is the reporting.** A workflow that could not be published was still
|
|
21
|
+
counted as built, and the summary read the same as a run where nobody asked to publish at
|
|
22
|
+
all: it suggested turning on publishing, to someone who had just turned it on. The real
|
|
23
|
+
reason sat further down the report where nobody looks first. A build now says plainly
|
|
24
|
+
which workflows could not be published, what GoHighLevel said about each, that they are
|
|
25
|
+
sitting as drafts and not running, and that repeating the build will not help.
|
|
26
|
+
|
|
3
27
|
## 3.72.2 — a form you read back can be saved again
|
|
4
28
|
|
|
5
29
|
A subscriber tried to edit one of her forms the documented way: read it with
|
package/dist/index.js
CHANGED
|
@@ -18523,7 +18523,7 @@ var init_executor = __esm({
|
|
|
18523
18523
|
WAIT_UNIT_MAP = {
|
|
18524
18524
|
minutes: "minutes",
|
|
18525
18525
|
hours: "hour",
|
|
18526
|
-
days: "
|
|
18526
|
+
days: "days"
|
|
18527
18527
|
};
|
|
18528
18528
|
PENDING = (ref) => `__PENDING__:${ref}`;
|
|
18529
18529
|
isPending = (v) => v.startsWith("__PENDING__:");
|
|
@@ -21493,6 +21493,36 @@ var init_plan_form = __esm({
|
|
|
21493
21493
|
}
|
|
21494
21494
|
});
|
|
21495
21495
|
|
|
21496
|
+
// src/intake-to-build/publish-report.ts
|
|
21497
|
+
function publishNote(r) {
|
|
21498
|
+
if (r.publishFailed.length) {
|
|
21499
|
+
const lead = r.published.length ? `Auto-published ${r.published.length} workflow(s) live, but ` : "";
|
|
21500
|
+
const detail = r.publishFailed.map((p) => `${p.name} (${p.error})`).join("; ");
|
|
21501
|
+
return `${lead}${r.publishFailed.length} workflow(s) were BUILT BUT COULD NOT BE PUBLISHED. They exist in GHL as DRAFT and are NOT running: ${detail}. You already opted in, so re-running with publishWorkflows will not help. If GHL rejected the workflow's contents, publishing by hand will hit the SAME error until the cause is fixed. Read the error above, fix it, then publish (see nextManualSteps).${r.published.length ? " Any gated workflow stays DRAFT until its handoff is met." : ""}`;
|
|
21502
|
+
}
|
|
21503
|
+
if (r.published.length) {
|
|
21504
|
+
return `Auto-published ${r.published.length} workflow(s) live (you opted in). Any gated workflow stays DRAFT until its handoff is met.`;
|
|
21505
|
+
}
|
|
21506
|
+
if (r.anyWorkflowCreated) {
|
|
21507
|
+
return "Workflows were built as DRAFT (the safe default). Review them in GHL and publish, or re-run with publishWorkflows:true to auto-publish ungated ones.";
|
|
21508
|
+
}
|
|
21509
|
+
return "No workflows were built in this run (none in the plan, or all already existed and were left untouched).";
|
|
21510
|
+
}
|
|
21511
|
+
function publishSummaryClause(r) {
|
|
21512
|
+
if (r.publishFailed.length) {
|
|
21513
|
+
const also = r.published.length ? ` (${r.published.length} did publish)` : "";
|
|
21514
|
+
return ` ${r.publishFailed.length} workflow(s) BUILT BUT NOT PUBLISHED${also}. They are DRAFT and not running, see publishNote.`;
|
|
21515
|
+
}
|
|
21516
|
+
if (r.published.length) return ` Published ${r.published.length} workflow(s) live.`;
|
|
21517
|
+
if (r.anyWorkflowCreated) return " Workflows are DRAFT (opt in with publishWorkflows to auto-publish).";
|
|
21518
|
+
return "";
|
|
21519
|
+
}
|
|
21520
|
+
var init_publish_report = __esm({
|
|
21521
|
+
"src/intake-to-build/publish-report.ts"() {
|
|
21522
|
+
"use strict";
|
|
21523
|
+
}
|
|
21524
|
+
});
|
|
21525
|
+
|
|
21496
21526
|
// src/intake-to-build/customization.ts
|
|
21497
21527
|
function industryPack(slug3) {
|
|
21498
21528
|
if (!slug3) return void 0;
|
|
@@ -23424,6 +23454,7 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
23424
23454
|
const built = [];
|
|
23425
23455
|
const manual = [];
|
|
23426
23456
|
const published = [];
|
|
23457
|
+
const publishFailed = [];
|
|
23427
23458
|
const staff = [];
|
|
23428
23459
|
const templates = { emails: [], sms: [] };
|
|
23429
23460
|
let templatesUnverified = 0;
|
|
@@ -23447,6 +23478,7 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
23447
23478
|
built,
|
|
23448
23479
|
manual,
|
|
23449
23480
|
published,
|
|
23481
|
+
publishFailed,
|
|
23450
23482
|
halted: { atRef, type, reason },
|
|
23451
23483
|
deferred,
|
|
23452
23484
|
staff,
|
|
@@ -24124,6 +24156,7 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
24124
24156
|
await deps.publishWorkflow(wfId);
|
|
24125
24157
|
published.push(wf.ref);
|
|
24126
24158
|
} catch (e) {
|
|
24159
|
+
publishFailed.push({ ref: wf.ref, name: wf.name, error: msg2(e) });
|
|
24127
24160
|
manual.push({ ref: wf.ref, type: "workflow-publish", name: wf.name, reason: `[${wf.name}] built successfully but auto-publish failed (${msg2(e)}) \u2014 publish it manually in GHL.` });
|
|
24128
24161
|
}
|
|
24129
24162
|
}
|
|
@@ -24178,7 +24211,7 @@ async function executeBackbone(plan, deps, opts = {}) {
|
|
|
24178
24211
|
}
|
|
24179
24212
|
}
|
|
24180
24213
|
}
|
|
24181
|
-
return { ok: true, idMap, built, manual, published, deferred, staff, templates, templatesUnverified, templatesFormatNote, calendarPending, refreshed, missingSteps, recipients };
|
|
24214
|
+
return { ok: true, idMap, built, manual, published, publishFailed, deferred, staff, templates, templatesUnverified, templatesFormatNote, calendarPending, refreshed, missingSteps, recipients };
|
|
24182
24215
|
}
|
|
24183
24216
|
async function buildSimple(objects, type, list2, create, nameOf, pollForNew, idMap, built) {
|
|
24184
24217
|
if (objects.length === 0) return null;
|
|
@@ -25190,13 +25223,18 @@ function registerIntakeToBuildTools(server2, client, builderClient, registry2) {
|
|
|
25190
25223
|
templatesFormatNote: exec.templatesFormatNote,
|
|
25191
25224
|
templatesNote: exec.templates.emails.length + exec.templates.sms.length ? `The plan's email and SMS copy was also saved as account-level templates (Marketing \u2192 Emails \u2192 Templates; Conversations \u2192 Templates) \u2014 the reusable version your team edits. Templates are created in the editor's own format (vibe-editor) so they open and edit in Marketing \u2192 Emails \u2192 Templates. Workflow steps carry the same copy inline; editing a template does not change a step already built.${exec.templatesUnverified ? ` ${exec.templatesUnverified} email template(s) were saved but their body was NOT seen in GHL's preview \u2014 see templates.emails[].warning; do not report them as written.` : exec.templates.emails.some((t) => t.status === "created") ? ` Every email template created this run had its body verified in GHL's preview.` : ""}` : void 0,
|
|
25192
25225
|
published: exec.published,
|
|
25193
|
-
|
|
25226
|
+
publishFailed: exec.publishFailed,
|
|
25227
|
+
publishNote: publishNote({
|
|
25228
|
+
published: exec.published,
|
|
25229
|
+
publishFailed: exec.publishFailed,
|
|
25230
|
+
anyWorkflowCreated: exec.built.some((b) => b.type === "workflow" && b.status === "created")
|
|
25231
|
+
}),
|
|
25194
25232
|
externalWiring,
|
|
25195
25233
|
externalWiringNote: externalWiring ? "For each target:\"external\" funnel: plug these into your self-hosted site form + lead bridge (templates/external-funnel/). custom formFields carry the VERIFIED GHL field id your form's `custom` object must send (never name-guess keys); add a triggerTag to start the speed-to-lead workflow; bookingUrl is the GHL calendar widget for the CTA. Anything in `unresolved` wasn't built yet \u2014 re-run after it is." : void 0,
|
|
25196
25234
|
deferred: exec.deferred,
|
|
25197
25235
|
deferredNote: `execute builds the WHOLE plan live: staff users (plan.users, via the agency key \u2014 bound by email when they already exist), CRM backbone (pipelines, custom fields, tags, custom values), calendars (with the plan's named team members), forms, funnels (GHL-built = funnel + named steps), account-level email/SMS templates (the plan's reusable copy), and workflows (DRAFT, with all steps incl. opportunity create/move; notification / task steps are NEVER dropped \u2014 with no staff member yet they ship as placeholders flagged staff_pending). Remaining manual steps are surfaced per item: pending staff (no agency key), staff-requiring calendars whose team members are pending (workflows that point at such a calendar are STILL built \u2014 trigger unpinned, flagged calendar_pending \u2014 never a halt), GHL funnel page content/design, EXTERNAL funnels (target:"external" \u2014 the user builds + hosts the site themselves and wires it back; not built here), workflow triggers other than contact_tag, and publishing the DRAFT workflows.`,
|
|
25198
25236
|
nextManualSteps: [...execManualLines, ...manualLines, ...handoffLines],
|
|
25199
|
-
summary: exec.ok ? `Built ${exec.built.filter((b) => b.status === "created").length} new object(s), bound ${exec.built.filter((b) => b.status === "existing" || b.status === "refreshed").length} existing${exec.refreshed.length ? ` (${exec.refreshed.length} workflow(s) refreshed in place \u2014 see refreshed[])` : ""}.${exec.staff.length ? ` Staff: ${exec.staff.filter((s) => s.status === "created").length} created, ${exec.staff.filter((s) => s.status === "existing").length} already in the account, ${exec.staff.filter((s) => s.status === "pending").length} pending.` : ""}${exec.templates.emails.length + exec.templates.sms.length ? ` Templates: ${exec.templates.emails.length} email (${exec.templates.emails.filter((t) => t.status === "created" && !t.warning).length} created with the body verified in the preview${exec.templatesUnverified ? `, ${exec.templatesUnverified} created but NOT verified \u2014 see templates.emails[].warning` : ""}${exec.templates.emails.filter((t) => t.status === "existing").length ? `, ${exec.templates.emails.filter((t) => t.status === "existing").length} already existed` : ""}${exec.templates.emails.filter((t) => t.status === "failed").length ? `, ${exec.templates.emails.filter((t) => t.status === "failed").length} failed` : ""}), ${exec.templates.sms.length} SMS.` : ""}${exec.published
|
|
25237
|
+
summary: exec.ok ? `Built ${exec.built.filter((b) => b.status === "created").length} new object(s), bound ${exec.built.filter((b) => b.status === "existing" || b.status === "refreshed").length} existing${exec.refreshed.length ? ` (${exec.refreshed.length} workflow(s) refreshed in place \u2014 see refreshed[])` : ""}.${exec.staff.length ? ` Staff: ${exec.staff.filter((s) => s.status === "created").length} created, ${exec.staff.filter((s) => s.status === "existing").length} already in the account, ${exec.staff.filter((s) => s.status === "pending").length} pending.` : ""}${exec.templates.emails.length + exec.templates.sms.length ? ` Templates: ${exec.templates.emails.length} email (${exec.templates.emails.filter((t) => t.status === "created" && !t.warning).length} created with the body verified in the preview${exec.templatesUnverified ? `, ${exec.templatesUnverified} created but NOT verified \u2014 see templates.emails[].warning` : ""}${exec.templates.emails.filter((t) => t.status === "existing").length ? `, ${exec.templates.emails.filter((t) => t.status === "existing").length} already existed` : ""}${exec.templates.emails.filter((t) => t.status === "failed").length ? `, ${exec.templates.emails.filter((t) => t.status === "failed").length} failed` : ""}), ${exec.templates.sms.length} SMS.` : ""}${publishSummaryClause({ published: exec.published, publishFailed: exec.publishFailed, anyWorkflowCreated: exec.built.some((b) => b.type === "workflow" && b.status === "created") })}${exec.manual.some((m) => m.type === "calendar") || exec.calendarPending.length ? ` Calendars: ${exec.manual.filter((m) => m.type === "calendar").length} deferred to manual; ${new Set(exec.calendarPending.filter((c) => c.status === "pending").map((c) => c.workflowRef)).size} workflow(s) built with the calendar unpinned${exec.calendarPending.some((c) => c.status === "calendar_ready") ? `, ${new Set(exec.calendarPending.filter((c) => c.status === "calendar_ready").map((c) => c.workflowRef)).size} ready to pin` : ""}.` : ""}${exec.manual.some((m) => m.type === "calendar_team") ? ` ${exec.manual.filter((m) => m.type === "calendar_team").length} calendar(s) were built WITHOUT the people the plan named \u2014 see nextManualSteps; do not report those calendars as staffed.` : ""}${exec.missingSteps.length ? ` NOT COMPLETE: ${exec.missingSteps.reduce((n, w) => n + w.steps.length, 0)} step(s) the plan asks for are still missing from ${exec.missingSteps.length} workflow(s) that already existed \u2014 add them by hand (see missingSteps).` : ""}${exec.manual.length ? ` ${exec.manual.length} item(s) need a manual step (see nextManualSteps).` : ""}${exec.deferred.length ? " Deferred: " + exec.deferred.map((d) => `${d.count} ${d.section}`).join(", ") + " (manual)." : ""}` : `HALTED at ${exec.halted?.atRef} (${exec.halted?.reason}). ${exec.built.length} object(s) were created before the halt \u2014 see idMap to resume or clean up. NEVER-CLOBBER means a re-run will bind those, not duplicate them.`
|
|
25200
25238
|
});
|
|
25201
25239
|
}
|
|
25202
25240
|
const collisions = result.items.filter((i) => i.status === "existing");
|
|
@@ -25616,6 +25654,7 @@ var init_intake_to_build = __esm({
|
|
|
25616
25654
|
init_emails();
|
|
25617
25655
|
init_user_provisioning();
|
|
25618
25656
|
init_plan_form();
|
|
25657
|
+
init_publish_report();
|
|
25619
25658
|
init_question_set();
|
|
25620
25659
|
init_customization();
|
|
25621
25660
|
init_intake_overlay();
|
|
@@ -26294,7 +26333,7 @@ var require_package = __commonJS({
|
|
|
26294
26333
|
"package.json"(exports2, module2) {
|
|
26295
26334
|
module2.exports = {
|
|
26296
26335
|
name: "@elitedcs/ghl-mcp",
|
|
26297
|
-
version: "3.72.
|
|
26336
|
+
version: "3.72.3",
|
|
26298
26337
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
26299
26338
|
description: "GoHighLevel MCP Server for Claude. 247 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.",
|
|
26300
26339
|
main: "dist/index.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.72.
|
|
3
|
+
"version": "3.72.3",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
5
|
"description": "GoHighLevel MCP Server for Claude. 247 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",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"example_3days": {
|
|
83
83
|
"type": "time",
|
|
84
84
|
"startAfter": {
|
|
85
|
-
"type": "
|
|
85
|
+
"type": "days",
|
|
86
86
|
"value": 3,
|
|
87
87
|
"when": "after"
|
|
88
88
|
},
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"convertToMultipath": false,
|
|
93
93
|
"transitions": []
|
|
94
94
|
},
|
|
95
|
-
"notes": "startAfter.type: 'minutes', 'hour', or 'day'. ALL 5 fields required (type, startAfter, isHybridAction, hybridActionType, transitions). Derived from working GHL UI-built workflows."
|
|
95
|
+
"notes": "startAfter.type: 'minutes', 'hour', or 'days' — NOT consistently singular, and 'day' is rejected with 400 INVALID_FIELD_VALUE on a workflow that has a real action before the wait (live-verified 2026-08-29). ALL 5 fields required (type, startAfter, isHybridAction, hybridActionType, transitions). Derived from working GHL UI-built workflows."
|
|
96
96
|
},
|
|
97
97
|
"internal_notification": {
|
|
98
98
|
"example": {
|
|
@@ -243,7 +243,7 @@
|
|
|
243
243
|
"actions": [
|
|
244
244
|
{ "name": "Add Reactivation Tag", "type": "add_contact_tag", "attributes": { "tags": ["reactivation-candidate"] } },
|
|
245
245
|
{ "name": "Send Reactivation SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, it's been a while since your last visit to {{business_name}}. We miss you! Book your next session and get 10% off.", "attachments": [] } },
|
|
246
|
-
{ "name": "Wait 3 Days", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "
|
|
246
|
+
{ "name": "Wait 3 Days", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "days", "value": 3, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
247
247
|
{ "name": "Send Reactivation Email", "type": "email", "attributes": { "subject": "We miss you, {{contact.first_name}}!", "html": "<p style=\"margin:0px;\">Hi {{contact.first_name}},</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">It's been over 90 days since your last visit to {{business_name}}, and we wanted to check in.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">As a valued patient, we'd like to offer you 10% off your next treatment. Just mention this email when you book.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">See you soon!</p><p style=\"margin:0px;\">{{owner_name}}</p>", "trackingOptions": { "hasTrackingLinks": false, "hasUtmTracking": false, "hasTags": false } } }
|
|
248
248
|
]
|
|
249
249
|
}
|