@elitedcs/ghl-mcp 3.89.0-beta.1 → 3.89.0-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elitedcs/ghl-mcp",
3
- "version": "3.89.0-beta.1",
3
+ "version": "3.89.0-beta.2",
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",
@@ -55,7 +55,7 @@ Load the chosen preset's `skeleton`.
55
55
 
56
56
  Apply, in order:
57
57
  1. **Evaluate `conditionalOn`** on every item (and every workflow action). Drop where false. Prune refs that now dangle, and record each prune (you will note these in the summary, not silently drop).
58
- 2. **Resolve `fillFrom`** lists. The main case is pipeline stages: if `goal.salesStages` is non-empty, build `stage.<slug>` refs from it in order; else use the preset `default`. If a workflow references a `stage.*` not in the chosen set, map it to the nearest equivalent (first stage for "new lead" creation) and note it — never ship a dead ref.
58
+ 2. **Resolve `fillFrom`** lists. The main case is pipeline stages: if `goal.salesStages` is non-empty, build `stage.<slug>` refs from it in order; else use the preset `default`. If a workflow references a `stage.*` not in the chosen set, map it to the nearest equivalent through the preset stage's `aliases` (first stage for "new lead" creation; a workflow's `stagePreference` wins for that workflow) and note it — never ship a dead ref, and never add a template stage after the client's Lost.
59
59
  3. **Substitute `{{tokens}}`** (with `||` fallback). Where a token resolves empty and has no fallback, omit the field and note the default you used.
60
60
  4. **Derive interest tags + field options** from the offer/business type (e.g. `interest-injectables` for a med spa) and add them to `tags` + the `field.interest` options, mirroring each other.
61
61
 
@@ -53,32 +53,39 @@
53
53
  "default": [
54
54
  {
55
55
  "ref": "stage.new_lead",
56
+ "aliases": ["new patient lead", "new patient", "new lead", "new inquiry", "inquiry", "new", "lead", "prospect"],
56
57
  "name": "New Patient Lead"
57
58
  },
58
59
  {
59
60
  "ref": "stage.contacted",
61
+ "aliases": ["contacted", "engaged", "in conversation", "qualified", "follow up"],
60
62
  "name": "Contacted"
61
63
  },
62
64
  {
63
65
  "ref": "stage.visit_booked",
66
+ "aliases": ["visit booked", "appointment booked", "consult booked", "consultation booked", "exam booked", "booked", "scheduled"],
64
67
  "name": "Visit Booked",
65
68
  "conditionalOn": "goal.bookingNeeded == true"
66
69
  },
67
70
  {
68
71
  "ref": "stage.showed",
72
+ "aliases": ["showed", "attended", "visit completed", "exam completed"],
69
73
  "name": "Showed",
70
74
  "conditionalOn": "goal.bookingNeeded == true"
71
75
  },
72
76
  {
73
77
  "ref": "stage.plan_accepted",
78
+ "aliases": ["care plan accepted", "plan accepted", "accepted", "started care", "sold"],
74
79
  "name": "Care Plan Accepted"
75
80
  },
76
81
  {
77
82
  "ref": "stage.active",
83
+ "aliases": ["active patient", "active", "in care"],
78
84
  "name": "Active Patient"
79
85
  },
80
86
  {
81
87
  "ref": "stage.lost",
88
+ "aliases": ["lost", "closed lost", "not interested"],
82
89
  "name": "Lost"
83
90
  }
84
91
  ]
@@ -1572,6 +1579,7 @@
1572
1579
  },
1573
1580
  {
1574
1581
  "ref": "workflow.no_show",
1582
+ "stagePreference": { "stage.contacted": ["no show", "noshow", "missed appointment", "did not show"] },
1575
1583
  "name": "No-Show Rescue",
1576
1584
  "trigger": {
1577
1585
  "type": "appointment",
@@ -50,36 +50,44 @@
50
50
  "default": [
51
51
  {
52
52
  "ref": "stage.new_lead",
53
+ "aliases": ["new lead", "new inquiry", "inquiry", "new", "lead", "prospect"],
53
54
  "name": "New Lead"
54
55
  },
55
56
  {
56
57
  "ref": "stage.contacted",
58
+ "aliases": ["contacted", "engaged", "in conversation", "qualified", "follow up"],
57
59
  "name": "Contacted"
58
60
  },
59
61
  {
60
62
  "ref": "stage.call_booked",
63
+ "aliases": ["call booked", "discovery call booked", "strategy call booked", "consult booked", "appointment booked", "booked", "scheduled"],
61
64
  "name": "Call Booked",
62
65
  "conditionalOn": "goal.bookingNeeded == true"
63
66
  },
64
67
  {
65
68
  "ref": "stage.call_held",
69
+ "aliases": ["call held", "call completed", "showed", "attended"],
66
70
  "name": "Call Held",
67
71
  "conditionalOn": "goal.bookingNeeded == true"
68
72
  },
69
73
  {
70
74
  "ref": "stage.offer_made",
75
+ "aliases": ["offer made", "offer sent", "proposal sent", "pitched"],
71
76
  "name": "Offer Made"
72
77
  },
73
78
  {
74
79
  "ref": "stage.enrolled",
80
+ "aliases": ["enrolled", "signed", "sold", "purchased"],
75
81
  "name": "Enrolled"
76
82
  },
77
83
  {
78
84
  "ref": "stage.alumni",
85
+ "aliases": ["alumni", "referral", "graduated"],
79
86
  "name": "Alumni / Referral"
80
87
  },
81
88
  {
82
89
  "ref": "stage.lost",
90
+ "aliases": ["lost", "closed lost", "not interested"],
83
91
  "name": "Lost"
84
92
  }
85
93
  ]
@@ -1572,6 +1580,7 @@
1572
1580
  },
1573
1581
  {
1574
1582
  "ref": "workflow.no_show",
1583
+ "stagePreference": { "stage.contacted": ["no show", "noshow", "missed appointment", "did not show"] },
1575
1584
  "name": "No-Show Rescue",
1576
1585
  "trigger": {
1577
1586
  "type": "appointment",
@@ -50,26 +50,32 @@
50
50
  "default": [
51
51
  {
52
52
  "ref": "stage.new_subscriber",
53
+ "aliases": ["new subscriber", "subscriber", "new lead", "signup", "lead", "new"],
53
54
  "name": "New Subscriber"
54
55
  },
55
56
  {
56
57
  "ref": "stage.engaged",
58
+ "aliases": ["engaged", "clicked", "contacted"],
57
59
  "name": "Engaged"
58
60
  },
59
61
  {
60
62
  "ref": "stage.first_order",
63
+ "aliases": ["first order", "first purchase", "purchased", "customer"],
61
64
  "name": "First Order"
62
65
  },
63
66
  {
64
67
  "ref": "stage.repeat",
68
+ "aliases": ["repeat customer", "repeat", "returning"],
65
69
  "name": "Repeat Customer"
66
70
  },
67
71
  {
68
72
  "ref": "stage.vip",
73
+ "aliases": ["vip"],
69
74
  "name": "VIP"
70
75
  },
71
76
  {
72
77
  "ref": "stage.lapsed",
78
+ "aliases": ["lapsed", "inactive", "churned", "lost"],
73
79
  "name": "Lapsed"
74
80
  }
75
81
  ]
@@ -44,35 +44,43 @@
44
44
  "default": [
45
45
  {
46
46
  "ref": "stage.new_lead",
47
+ "aliases": ["new lead", "new inquiry", "inquiry", "new", "lead", "prospect"],
47
48
  "name": "New Lead"
48
49
  },
49
50
  {
50
51
  "ref": "stage.contacted",
52
+ "aliases": ["contacted", "engaged", "in conversation", "follow up"],
51
53
  "name": "Contacted"
52
54
  },
53
55
  {
54
56
  "ref": "stage.qualified",
57
+ "aliases": ["qualified"],
55
58
  "name": "Qualified"
56
59
  },
57
60
  {
58
61
  "ref": "stage.appointment_booked",
62
+ "aliases": ["appointment booked", "consult booked", "consultation booked", "call booked", "booked", "scheduled"],
59
63
  "name": "Appointment Booked",
60
64
  "conditionalOn": "goal.bookingNeeded == true"
61
65
  },
62
66
  {
63
67
  "ref": "stage.proposal_sent",
68
+ "aliases": ["proposal sent", "quote sent", "estimate sent", "proposal", "quote"],
64
69
  "name": "Proposal / Quote Sent"
65
70
  },
66
71
  {
67
72
  "ref": "stage.won",
73
+ "aliases": ["won", "closed won", "sold", "signed"],
68
74
  "name": "Won"
69
75
  },
70
76
  {
71
77
  "ref": "stage.repeat",
78
+ "aliases": ["repeat", "retention"],
72
79
  "name": "Repeat / Retention"
73
80
  },
74
81
  {
75
82
  "ref": "stage.lost",
83
+ "aliases": ["lost", "closed lost", "not interested"],
76
84
  "name": "Lost"
77
85
  }
78
86
  ]
@@ -1569,6 +1577,7 @@
1569
1577
  },
1570
1578
  {
1571
1579
  "ref": "workflow.no_show",
1580
+ "stagePreference": { "stage.contacted": ["no show", "noshow", "missed appointment", "did not show"] },
1572
1581
  "name": "No-Show Rescue",
1573
1582
  "trigger": {
1574
1583
  "type": "appointment",
@@ -53,35 +53,43 @@
53
53
  "default": [
54
54
  {
55
55
  "ref": "stage.new_lead",
56
+ "aliases": ["new lead", "new inquiry", "inquiry", "new", "lead", "prospect"],
56
57
  "name": "New Lead"
57
58
  },
58
59
  {
59
60
  "ref": "stage.contacted",
61
+ "aliases": ["contacted", "engaged", "in conversation", "qualified", "follow up"],
60
62
  "name": "Contacted"
61
63
  },
62
64
  {
63
65
  "ref": "stage.estimate_scheduled",
66
+ "aliases": ["estimate scheduled", "estimate booked", "appointment booked", "visit booked", "booked", "scheduled"],
64
67
  "name": "Estimate Scheduled",
65
68
  "conditionalOn": "goal.bookingNeeded == true"
66
69
  },
67
70
  {
68
71
  "ref": "stage.quote_sent",
72
+ "aliases": ["quote sent", "estimate sent", "proposal sent", "quote"],
69
73
  "name": "Quote Sent"
70
74
  },
71
75
  {
72
76
  "ref": "stage.job_won",
77
+ "aliases": ["job won", "closed won", "won", "sold", "hired"],
73
78
  "name": "Job Won"
74
79
  },
75
80
  {
76
81
  "ref": "stage.job_complete",
82
+ "aliases": ["job complete", "job completed", "completed", "finished"],
77
83
  "name": "Job Complete"
78
84
  },
79
85
  {
80
86
  "ref": "stage.maintenance",
87
+ "aliases": ["maintenance", "repeat", "recurring"],
81
88
  "name": "Repeat / Maintenance"
82
89
  },
83
90
  {
84
91
  "ref": "stage.lost",
92
+ "aliases": ["lost", "closed lost", "not interested"],
85
93
  "name": "Lost"
86
94
  }
87
95
  ]
@@ -1582,6 +1590,7 @@
1582
1590
  },
1583
1591
  {
1584
1592
  "ref": "workflow.no_show",
1593
+ "stagePreference": { "stage.contacted": ["no show", "noshow", "missed appointment", "did not show"] },
1585
1594
  "name": "No-Show Rescue",
1586
1595
  "trigger": {
1587
1596
  "type": "appointment",
@@ -49,32 +49,39 @@
49
49
  "default": [
50
50
  {
51
51
  "ref": "stage.new_lead",
52
+ "aliases": ["new lead", "new inquiry", "inquiry", "new", "lead", "prospect"],
52
53
  "name": "New Lead"
53
54
  },
54
55
  {
55
56
  "ref": "stage.contacted",
57
+ "aliases": ["contacted", "engaged", "in conversation", "qualified", "follow up"],
56
58
  "name": "Contacted"
57
59
  },
58
60
  {
59
61
  "ref": "stage.consult_booked",
62
+ "aliases": ["consult booked", "consultation booked", "trial booked", "appointment booked", "booked", "scheduled"],
60
63
  "name": "Consult Booked",
61
64
  "conditionalOn": "goal.bookingNeeded == true"
62
65
  },
63
66
  {
64
67
  "ref": "stage.showed",
68
+ "aliases": ["showed", "trial showed", "consult completed", "attended"],
65
69
  "name": "Showed",
66
70
  "conditionalOn": "goal.bookingNeeded == true"
67
71
  },
68
72
  {
69
73
  "ref": "stage.treated",
74
+ "aliases": ["treated", "package sold", "sold", "purchased"],
70
75
  "name": "Treated"
71
76
  },
72
77
  {
73
78
  "ref": "stage.member",
79
+ "aliases": ["member", "membership", "rebooked"],
74
80
  "name": "Member / Rebooked"
75
81
  },
76
82
  {
77
83
  "ref": "stage.lost",
84
+ "aliases": ["lost", "closed lost", "not interested"],
78
85
  "name": "Lost"
79
86
  }
80
87
  ]
@@ -1559,6 +1566,7 @@
1559
1566
  },
1560
1567
  {
1561
1568
  "ref": "workflow.no_show",
1569
+ "stagePreference": { "stage.contacted": ["no show", "noshow", "missed appointment", "did not show"] },
1562
1570
  "name": "No-Show Rescue",
1563
1571
  "trigger": {
1564
1572
  "type": "appointment",
@@ -96,7 +96,7 @@ For list-valued structure the brief can override:
96
96
  "users": { "fillFrom": "team.staff", "transform": "userList", "default": [] }
97
97
  ```
98
98
 
99
- - `stageList`: `["new lead","contacted",...]` → `[{ref: "stage.<slug>", name, position}]`. Workflows that point at `stage.*` refs resolve against whichever set won; a referenced stage not in the chosen set is mapped to the nearest equivalent (new-lead → the first stage; booked → any stage whose name contains "book" / "consult" / "visit" / "estimate" / "call") and the mapping is noted. Never ship a dead ref.
99
+ - `stageList`: `["new lead","contacted",...]` → `[{ref: "stage.<slug>", name, position}]`. Workflows that point at `stage.*` refs resolve against whichever set won. The client's list is the whole pipeline: a referenced default stage the client did not name is mapped onto one of theirs through the default stage's `aliases` array (whole-word match on the slug; each client stage goes to at most one default stage, the one whose alias matches it most specifically, and the loser tries its next alias; a stage still working the lead is never mapped onto a terminal one such as lost, no show, no sale, closed, won, not a fit, disqualified, dead, cancelled, declined, DND, churned, lapsed or archived; the first default stage falls back to the client's first stage), and the mapping is noted. A workflow may carry `stagePreference: { "stage.contacted": ["no show", ...] }` to prefer a client stage for one ref in that workflow only (No-Show Rescue → the client's "No show" stage); it is stripped from the plan. Only when nothing maps is the default stage kept, placed in preset order right after the client stage the previous preset stage landed on (else before the one the next preset stage landed on, else before the first terminal stage), never after Lost. Never ship a dead ref.
100
100
  - `userList` (v2): each `brief.team.staff[]` entry → `{ref: "user.<slug of name>", firstName, lastName, email, role, phone?}`. `role` is `admin` for the first person / anyone whose title says owner, admin or director; `user` otherwise. Emails must be unique.
101
101
 
102
102
  ### 4. `templates` and `templateRef` (v2) — every message lives once, complete