@elitedcs/ghl-mcp 3.89.0-beta.2 → 3.89.0-beta.4

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.
@@ -51,7 +51,7 @@ The Build Plan is the reviewable, editable output of the skill. **Refs only, no
51
51
  - **handoffs:** `{ref, owner, title, trigger?, instruction, produces?, successCheck, blocks?}` — `owner` ∈ **OPERATOR-UI/OPERATOR-EXT/TEAM** (legacy JERRY-UI/JERRY-EXT/SASHA accepted + normalized, never emitted). To gate a workflow DRAFT, `blocks` must list its `workflow.*` ref (a bare `sms.*` wildcard gates only the asset surface).
52
52
 
53
53
  ## Logical workflow actions (executor expands to native)
54
- `add_contact_tag {tagRef}`, `remove_contact_tag {tagRef}`, `send_email {emailRef | templateRef}`, `send_sms {smsRef | templateRef}` (one of the two is required — `templateRef` points at `templates.*`, v2), `wait {value, unit}`, `wait_appointment {value, unit}` (integer; appointment-triggered workflows only), `internal_notification {userRef, title, body}` (`userRef` = a `user.*` ref or `user.__pending__`; the 0.1 `to` literal is still accepted with a warning), `task_notification {title, body?, dueDate?, userRef?}` (`assignedTo` literal still accepted with a warning; no assignee = warning), `assign_user {userRef}` *(v2 — GHL "Assign to user"; the contact's owner becomes that person)*, `update_contact_field {fieldRef, value}`, `add_notes {body}`, `create_opportunity {pipelineRef, stageRef, name?, value?}`, `update_opportunity {pipelineRef, stageRef, value?}` (forces allowBackward), `add_to_workflow {workflowRef}`, `remove_from_workflow {workflowRef}`, `goal_event {goalCondition, action?}`, and `find_opportunity {pipelineRef, found:[...], notFound:[...]}` — the only branching action; it MUST be the LAST action (branches do not rejoin). All pointers are refs. The executor owns the failure-prone native shapes; the plan never contains them.
54
+ `add_contact_tag {tagRef}`, `remove_contact_tag {tagRef}`, `send_email {emailRef | templateRef}`, `send_sms {smsRef | templateRef}` (one of the two is required — `templateRef` points at `templates.*`, v2), `wait {value, unit}`, `wait_appointment {value, unit}` (integer; appointment-triggered workflows only), `internal_notification {userRef, title, body}` (`userRef` = a `user.*` ref or `user.__pending__`; the 0.1 `to` literal is still accepted with a warning), `task_notification {title, body?, dueDate?, userRef?}` (`assignedTo` literal still accepted with a warning; no assignee = warning), `assign_user {userRef}` *(v2 — GHL "Assign to user"; the contact's owner becomes that person)*, `update_contact_field {fieldRef, value}`, `add_notes {body}`, `enable_dnd {}` *(turns on Do Not Disturb for outbound messages, e.g. after a STOP reply; emitted as GHL's `dnd_contact` step)*, `create_opportunity {pipelineRef, stageRef, name?, value?}`, `update_opportunity {pipelineRef, stageRef, value?}` (forces allowBackward), `add_to_workflow {workflowRef}`, `remove_from_workflow {workflowRef}`, `goal_event {goalCondition, action?}`, and `find_opportunity {pipelineRef, found:[...], notFound:[...]}` — the only branching action; it MUST be the LAST action (branches do not rejoin). All pointers are refs. The executor owns the failure-prone native shapes; the plan never contains them.
55
55
 
56
56
  ## v2 rules the validator enforces (2026-08-26) — read before writing workflows
57
57
  Two are **hard errors on purpose** even for plans that use no new field. Both come from a real build the owner inspected: the nurture went quiet after a week and the speed-to-lead ended with a text and dropped the lead. Error strings start with the code.
@@ -56,6 +56,8 @@ Library (v2.0.0): `med-spa` (default), `generic-client` (agency / other fallback
56
56
 
57
57
  `selectors.businessTypes` are the `business_type` answers that route to this preset. `selectors.aliases` are the `brief.preset` enum values that resolve to this preset (e.g. `preset: "med_spa"` resolves to the med-spa preset, which claims that alias). Exactly one preset across the library has `"default": true` — **`med_spa`**. `generic` is `default:false`, the neutral fallback for agency / other / unmatched types.
58
58
 
59
+ `conventions` values are strings the model reads, with one switch the composer itself reads: `"quotesNeverAutomatic": true` means a client quote never goes into a message automatically, even with written consent. The claims guard then treats a consented testimonial as not allowed and looks for the words of every intake quote, so a copy override that quotes one (even a size result with "results vary") falls back to the preset's own wording. The wellness clinic preset sets it.
60
+
59
61
  ## The `skeleton` object
60
62
 
61
63
  `skeleton` mirrors the §5 build-plan top level — `users`, `pipelines`, `customFields`, `tags`, `customValues`, `calendars`, `forms`, `funnels`, `templates`, `emails`, `sms`, `workflows`, `handoffs`. Keys starting with `_` are author notes and are dropped at fill time. Every item is a §5 object, optionally annotated with:
@@ -158,6 +160,8 @@ Presets must use GHL-correct enum values so the emitted plan passes ghl-command-
158
160
  - handoff `owner` ∈ **`OPERATOR-UI`**, **`OPERATOR-EXT`**, **`TEAM`** (customer-facing, generic). The MCP still accepts + normalizes the legacy `JERRY-UI`/`JERRY-EXT`/`SASHA`, but presets EMIT the canonical labels.
159
161
  - `handoff.a2p.blocks` MUST list every SMS-bearing **workflow** ref (the validator checks it) — only an explicit `workflow.*` ref keeps a workflow DRAFT.
160
162
  - Max 40 actions per workflow (a `find_opportunity` counts head + 2 transitions + children); `find_opportunity` must be the last action.
163
+ - **Texting rules (2026-09-29, proven on live clinic accounts; enforced for every preset by `src/intake-to-build/preset-message-rules.test.ts`).** SMS bodies use plain GSM-7 characters only: no long or short dashes, curly quotes, one-character ellipsis or emoji (one long dash took a live account from 22 billed parts per contact to 47). The first text of every nurture, win-back or reactivation workflow ends with `Reply STOP to opt out.` (or `Reply N to opt out.` where a reply of N is handled) on a line of its own. A keyword trigger carries `"keyword"` plus `"keywordMatch": "exact"`; never `"contains"` (a contains-STOP opted out a patient who asked "when should I stop eating").
164
+ - **No claims in preset copy.** No message may make an outcome or health claim (pain, sleep, inflammation relief, cures, weight or inch loss, guaranteed results, numeric results) or quote a named result ("Sarah lost 3 inches"). The composer fails a preset whose own words do (`src/intake-to-build/claims-guard.ts` holds the word list). Client proof comes only from the brief, with consent: `proof.testimonials[]` with `consent: true`, or `offer.claims[]` that say "results vary". Consent covers using the quote and name, not a claim inside it: a size or weight result goes out only with "results vary" in the same message, and a health claim never does.
161
165
 
162
166
  > The schema §5 contract and the live Zod schema (`src/intake-to-build/plan.ts`) are the sources of truth. If the doc and the Zod schema ever disagree, the Zod schema wins.
163
167