@elitedcs/ghl-mcp 3.84.8 → 3.84.9
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 +6 -0
- package/README.md +1 -1
- package/dist/index.js +122 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.84.9 — build steps you can read
|
|
4
|
+
|
|
5
|
+
Each client's build now shows a progress bar, the next step across the full width with one clear button, and one readable row per step, instead of seven narrow columns. Nothing about how building works changed: the same steps, checks and typed confirmations. Step descriptions now say what each step really does. Verify checks the links between workflows, pipelines and fields and tests the form, and reports anything it cannot check.
|
|
6
|
+
|
|
7
|
+
Call recordings: Plaud is proven and Zoom should work the same way but has not been checked yet. For any other recorder, export the transcript and attach it.
|
|
8
|
+
|
|
3
9
|
## 3.84.8 — client calls into assessments, and locks you can always reach
|
|
4
10
|
|
|
5
11
|
Bring a recorded client call into their assessment in one step. Your Claude fetches the transcript from its own Plaud or Zoom connection (or you attach the file), proposes answers with the client's exact words, and read_assessment_transcript now saves them to the client's contact and reads them back. Answers in the client's own words save straight away. Every number waits for your OK in one short list: reply "confirm all" or "confirm all except …", and those save marked as confirmed by you. A needs analysis comes with it: what they said they want, what they actually need, problems they didn't name, and solutions they didn't know to ask for, each tied to their own words and written for you, never sent to the client. The reply also lays out a client file for your Google Drive (Clients / the client / Calls, plus a running "Client understanding" document), and can keep a copy in a local folder you choose.
|
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -29058,7 +29058,7 @@ var require_package = __commonJS({
|
|
|
29058
29058
|
"package.json"(exports2, module2) {
|
|
29059
29059
|
module2.exports = {
|
|
29060
29060
|
name: "@elitedcs/ghl-mcp",
|
|
29061
|
-
version: "3.84.
|
|
29061
|
+
version: "3.84.9",
|
|
29062
29062
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
29063
29063
|
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.",
|
|
29064
29064
|
main: "dist/index.js",
|
|
@@ -39943,7 +39943,7 @@ var init_client_calls = __esm({
|
|
|
39943
39943
|
init_words();
|
|
39944
39944
|
init_store3();
|
|
39945
39945
|
init_assessment();
|
|
39946
|
-
RECORDERS = ["Plaud", "Zoom", "
|
|
39946
|
+
RECORDERS = ["Plaud", "Zoom", "Other"];
|
|
39947
39947
|
SOLUTION_KINDS = ["GoHighLevel build", "AI tool", "custom build", "process"];
|
|
39948
39948
|
clean = (s) => String(s ?? "").replace(/\s+/g, " ").trim();
|
|
39949
39949
|
ANALYSIS_MIN_WORDS = 3;
|
|
@@ -40245,7 +40245,7 @@ function registerAssessmentTools(server2, client) {
|
|
|
40245
40245
|
safeTool(
|
|
40246
40246
|
server2,
|
|
40247
40247
|
"read_assessment_transcript",
|
|
40248
|
-
`Bring a recorded client call (Plaud
|
|
40248
|
+
`Bring a recorded client call (Plaud or Zoom through your own connection, or a transcript file the owner exports from any other recorder and attaches) into the client's assessment, their needs analysis and their client file. The flow: 1) get the transcript yourself, with your own Plaud or Zoom connection or from the attached file; 2) propose assessment answers, each with the client's words copied VERBATIM from the transcript as the quote; for a text question the value is the client's own words taken from that quote, and for a number it is the number they said, written in digits (Plaud writes "a hundred percent"; send "100%"); 3) write the needs analysis, every need, unnamed problem and recommended solution tied to a verbatim quote of at least three words; 4) call this with the client's contactId and the source; 5) write the returned clientFile to the owner's Google Drive with your Drive connection, following clientFile.howToWrite; 6) show the owner the reply as given, including the "To confirm" list. EVERY NUMBER waits for the owner's OK and never saves on its own, because no word check can tell a figure that answers the question from one said in passing. Text answers in the client's own words save straight away. When the owner answers the list ("confirm all", or "confirm all except ..."), call again with the same transcript, proposed and contactId, and confirmed holding exactly the approved items (questionId and value from toConfirm); for an item marked replacesSaved, also set replace: true on that proposed answer. Never put an item in confirmed that the owner has not approved in this conversation. Drive allows two folders with the same name, so SEARCH for each folder in the path (and for the client's folder above all) before creating it, and never create a second tree. To append to "Client understanding": read it, add the new dated section at the end, write it back, then read it again and confirm every earlier section is still there. Answers and analysis points whose quote is not in the transcript are thrown out. With a contactId the saved answers are read back: the reply starts SAVED, NOT SAVED, NOT CONFIRMED or NOTHING TO SAVE, and only SAVED means they are on the contact. The needs analysis is advice for the owner and is never sent to the client. Without a contactId nothing is saved.`,
|
|
40249
40249
|
{
|
|
40250
40250
|
transcript: import_zod61.z.string().min(20).describe("The recording, as text. Paste the whole thing."),
|
|
40251
40251
|
proposed: import_zod61.z.array(import_zod61.z.object({
|
|
@@ -40265,7 +40265,7 @@ function registerAssessmentTools(server2, client) {
|
|
|
40265
40265
|
businessName: import_zod61.z.string().optional().describe("The client's business name, used when the contact and its saved assessment carry none."),
|
|
40266
40266
|
createPipeline: import_zod61.z.boolean().optional().describe('Create the "Assessments" pipeline if it is missing. Only when the owner has said yes.'),
|
|
40267
40267
|
source: import_zod61.z.object({
|
|
40268
|
-
recorder: import_zod61.z.enum(["Plaud", "Zoom", "
|
|
40268
|
+
recorder: import_zod61.z.enum(["Plaud", "Zoom", "Other"]).describe("What recorded the call. Use Other for any recorder whose transcript was exported and attached."),
|
|
40269
40269
|
recordedAt: import_zod61.z.string().describe("When the call happened, as an ISO date (2026-09-24) or timestamp, from the recording itself."),
|
|
40270
40270
|
title: import_zod61.z.string().optional().describe("The recording's title, as the recorder shows it."),
|
|
40271
40271
|
fetchedBy: import_zod61.z.enum(["claude", "upload"]).optional().describe("claude when you fetched it with your own connector, upload when the owner attached a file.")
|
|
@@ -41202,17 +41202,46 @@ function html(roster, seatToken, screen = "board", cap) {
|
|
|
41202
41202
|
.sandbox-badge{background:var(--ok-soft);color:var(--ok);border-radius:999px;padding:.14rem .55rem;font-size:var(--fs-label);font-weight:700;letter-spacing:.04em;vertical-align:middle;white-space:nowrap}
|
|
41203
41203
|
|
|
41204
41204
|
/* Stage tiles . same shapes as the hub's 7-stage track, clickable */
|
|
41205
|
-
|
|
41206
|
-
.
|
|
41207
|
-
.
|
|
41208
|
-
.
|
|
41209
|
-
.
|
|
41210
|
-
.
|
|
41211
|
-
.
|
|
41212
|
-
.
|
|
41213
|
-
.
|
|
41214
|
-
.
|
|
41215
|
-
.
|
|
41205
|
+
/* The steps (owner-approved layout, 2026-09-25): progress bar, next-step panel, one row per step. */
|
|
41206
|
+
.sprog{margin:1rem 0 .9rem}
|
|
41207
|
+
.strack{display:grid;grid-template-columns:repeat(7,1fr);gap:.35rem}
|
|
41208
|
+
.sseg{height:.45rem;border-radius:999px;background:var(--wait-soft)}
|
|
41209
|
+
.sseg.done{background:var(--ok)}.sseg.now{background:var(--gold)}.sseg.stale{background:var(--warn)}
|
|
41210
|
+
.splabel{display:flex;justify-content:space-between;flex-wrap:wrap;gap:.3rem 1rem;margin-top:.55rem;font-size:var(--fs-sm)}
|
|
41211
|
+
.splabel b{color:var(--heading);font-weight:600}.splabel span{color:var(--ink-3)}
|
|
41212
|
+
.snext{border:1px solid var(--gold);background:var(--gold-soft);border-radius:var(--radius);padding:1rem 1.1rem;display:grid;grid-template-columns:1fr auto;gap:.6rem 1.2rem;align-items:center}
|
|
41213
|
+
.snext .sk{font-size:var(--fs-label);letter-spacing:.14em;text-transform:uppercase;color:var(--gold-ink);font-weight:700;margin:0 0 .2rem}
|
|
41214
|
+
.snext h3{margin:0 0 .35rem;font-size:var(--fs-lg);color:var(--heading)}
|
|
41215
|
+
.snext p{margin:0;color:var(--ink-2);font-size:var(--fs-sm);max-width:60ch}
|
|
41216
|
+
.snext .swarn{margin-top:.5rem;color:var(--warn);font-weight:500}
|
|
41217
|
+
.snext .snoteline{margin-top:.4rem}
|
|
41218
|
+
.snext .slive{margin-top:.5rem}
|
|
41219
|
+
.sbtns{display:flex;flex-direction:column;align-items:flex-end;gap:.5rem}
|
|
41220
|
+
.sbtns .sbig{padding:.6rem 1.1rem;font-size:var(--fs-body)}
|
|
41221
|
+
.stage button,.snext button{box-sizing:border-box;max-width:100%;white-space:normal;overflow-wrap:anywhere;height:auto}
|
|
41222
|
+
.sbtns .runbtn.sbig{color:var(--on-accent)}
|
|
41223
|
+
.sbtns .swhy{margin:0;font-size:var(--fs-sm);max-width:22rem;text-align:right}
|
|
41224
|
+
.stages{margin-top:1rem;border-top:1px solid var(--line)}
|
|
41225
|
+
.stage{display:grid;grid-template-columns:2rem 9.5rem 7.5rem 1fr auto;gap:.4rem 1rem;align-items:center;padding:.7rem .3rem;border-bottom:1px solid var(--line)}
|
|
41226
|
+
.stage.here{background:var(--gold-soft)}
|
|
41227
|
+
.snum{width:1.7rem;height:1.7rem;border-radius:50%;display:grid;place-items:center;font-size:var(--fs-label);font-weight:700;background:var(--wait-soft);color:var(--wait)}
|
|
41228
|
+
.snum.done{background:var(--ok-soft);color:var(--ok)}.snum.stale{background:var(--warn-soft);color:var(--warn)}.snum.now{background:var(--gold);color:var(--on-accent)}
|
|
41229
|
+
.sname{font-weight:600;color:var(--heading)}
|
|
41230
|
+
.schip{justify-self:start;font-size:var(--fs-label);letter-spacing:.06em;text-transform:uppercase;font-weight:700;padding:.15rem .55rem;border-radius:999px;white-space:nowrap}
|
|
41231
|
+
.schip.done{background:var(--ok-soft);color:var(--ok)}.schip.stale{background:var(--warn-soft);color:var(--warn)}.schip.wait{background:var(--wait-soft);color:var(--wait)}.schip.you,.schip.now{background:var(--gold-soft);color:var(--gold-ink)}
|
|
41232
|
+
.swhat{color:var(--ink-2);font-size:var(--fs-sm);min-width:0;overflow-wrap:anywhere}
|
|
41233
|
+
.swhat .sreason{color:var(--warn)}
|
|
41234
|
+
.snote{display:block;font-size:var(--fs-sm);line-height:1.35}
|
|
41235
|
+
.slive{font-size:var(--fs-sm);line-height:1.35;margin-top:.25rem}
|
|
41236
|
+
.sact{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.2rem .8rem}
|
|
41237
|
+
.sactbtn{font-size:var(--fs-sm);color:var(--gold-ink);font-weight:600;background:none;border:0;padding:.2rem 0;cursor:pointer;text-align:right}
|
|
41238
|
+
.sactbtn:hover{text-decoration:underline}
|
|
41239
|
+
.sactbtn:disabled{color:var(--ink-3);cursor:default;text-decoration:none}
|
|
41240
|
+
@media (max-width: 52rem){
|
|
41241
|
+
.stage{grid-template-columns:2rem 1fr auto;grid-template-areas:"n name act" ". chip chip" ". what what"}
|
|
41242
|
+
.stage .snum{grid-area:n}.stage .sname{grid-area:name}.stage .schip{grid-area:chip}.stage .swhat{grid-area:what}.stage .sact{grid-area:act}
|
|
41243
|
+
.snext{grid-template-columns:1fr}.sbtns{align-items:flex-start}.sbtns .swhy{text-align:left}
|
|
41244
|
+
}
|
|
41216
41245
|
|
|
41217
41246
|
/* \u2500\u2500 Other accounts: one-line rows. One account at a time is the rule. \u2500\u2500 */
|
|
41218
41247
|
.acct-list{padding:.2rem .9rem}
|
|
@@ -41322,8 +41351,6 @@ function html(roster, seatToken, screen = "board", cap) {
|
|
|
41322
41351
|
|
|
41323
41352
|
@media (max-width: 46rem){
|
|
41324
41353
|
.brand-sub,.localpill{display:none}
|
|
41325
|
-
.stages{gap:.3rem}
|
|
41326
|
-
.stage{min-width:4.2rem}
|
|
41327
41354
|
}
|
|
41328
41355
|
@media (prefers-reduced-motion: reduce){*{transition:none !important}}
|
|
41329
41356
|
` })}<body data-screen="${screen}"${cap ? ` data-capability="${cap.key}"` : ""}>
|
|
@@ -41358,6 +41385,14 @@ const GATES=${scriptJson(HUMAN_GATE_STAGES)};let PROTECTED=${scriptJson(PROTECTE
|
|
|
41358
41385
|
const TYPES=["client","sandbox","template","hidden"];
|
|
41359
41386
|
const TYPE_LABELS={client:"Client",sandbox:"Practice sandbox",template:"Template",hidden:"Hidden"};
|
|
41360
41387
|
const LABELS=["Intake","Brief","Approve","Build","Verify","Manual tasks","Go-live"];
|
|
41388
|
+
// What each step does: [the one line on its row, the fuller sentence in the next-step panel].
|
|
41389
|
+
const STEP_ABOUT=[["Creates the intake form, its fields and one notification workflow.","Creates or repairs this client's intake form, its custom fields and one published notification workflow."],
|
|
41390
|
+
["Reads the intake into a brief.","Reads this client's intake, from the submitted form or the one completed here, and turns it into the brief the plan is made from."],
|
|
41391
|
+
["You approve the proposed build.","Review the intake and the brief, then approve the proposed build for this client."],
|
|
41392
|
+
["Builds the approved plan into this account.","Builds the approved plan into this client's account. Anything it cannot build is listed as an issue."],
|
|
41393
|
+
["Checks the build for broken links.","Checks the account for broken links between workflows, pipelines and fields, and tests the form. It may submit and delete one test lead. Anything it cannot check is reported as unchecked."],
|
|
41394
|
+
["Jobs only a person can do. You confirm them.","The jobs only a person can do, such as A2P, Google sign-in, staff and phone. Confirm them when they are finished."],
|
|
41395
|
+
["You sign this client live.","Sign this client live once Verify is clean and the manual tasks are finished."]];
|
|
41361
41396
|
const STATUS_TEXT={pending:"not started",in_progress:"in progress",done:"done"};
|
|
41362
41397
|
const NEXT={pending:"in_progress",in_progress:"done",done:"pending"};
|
|
41363
41398
|
let polling=false,query="",showParked=false,showNew=false,snapshots=null,snapshotError="";
|
|
@@ -41902,8 +41937,22 @@ function card(c,state,run){const st=(state.clients[c.locationId]||{stages:STAGES
|
|
|
41902
41937
|
if(!response.ok||r.ok!==true){r.ok=false;r.error=r.error||"Command OS could not confirm the result. Refresh this client to read its saved state before retrying."}
|
|
41903
41938
|
if(!r.ok)alert(r.error);else load()
|
|
41904
41939
|
}catch(e){alert("Command OS could not confirm the result. Refresh this client to read its saved state before retrying.")}};
|
|
41905
|
-
|
|
41906
|
-
|
|
41940
|
+
// The steps, laid out as the owner approved on 2026-09-25: a progress bar, the next step in
|
|
41941
|
+
// full, then one row per step. Only the layout changed. Every button below keeps the condition
|
|
41942
|
+
// and the handler it had in the seven-column layout; the next-step panel draws the SAME
|
|
41943
|
+
// buttons again for the current step, so nothing appears there that its row would not offer.
|
|
41944
|
+
const staleOf=i=>state.buildViews?.[c.locationId]?.stale?.find(x=>x.stage===i);
|
|
41945
|
+
const isDone=i=>(st[i]||"pending")==="done"&&!staleOf(i);
|
|
41946
|
+
let curI=-1;for(let i=0;i<STAGES.length;i++){if(!isDone(i)){curI=i;break}}
|
|
41947
|
+
const nDone=STAGES.filter((_,i)=>isDone(i)).length;
|
|
41948
|
+
const prog=document.createElement("div");prog.className="sprog";prog.setAttribute("aria-label","Progress: "+nDone+" of "+STAGES.length+" steps done");
|
|
41949
|
+
const track=document.createElement("div");track.className="strack";prog.appendChild(track);
|
|
41950
|
+
const plabel=document.createElement("div");plabel.className="splabel";prog.appendChild(plabel);
|
|
41951
|
+
div.appendChild(prog);
|
|
41952
|
+
const nextBox=document.createElement("div");nextBox.className="snext";div.appendChild(nextBox);
|
|
41953
|
+
const row=document.createElement("div");row.className="stages";row.setAttribute("role","list");
|
|
41954
|
+
let curLive=false;
|
|
41955
|
+
STAGES.forEach((name,i)=>{const stale=staleOf(i);const el=document.createElement("div");el.className="stage "+(stale?"pending":(st[i]||"pending"))+(i===curI?" here":"");el.setAttribute("role","listitem");
|
|
41907
41956
|
const gate=GATES[String(i)];
|
|
41908
41957
|
const oc0=(state.outcomes||{})[c.locationId+":"+i];const notPassed=(st[i]||"pending")==="pending"&&oc0&&(oc0.issues||[]).length>0;
|
|
41909
41958
|
if(notPassed)el.className+=" notpassed";
|
|
@@ -41913,8 +41962,16 @@ function card(c,state,run){const st=(state.clients[c.locationId]||{stages:STAGES
|
|
|
41913
41962
|
// from before the run (a "stale" warning and an old issue count are both wrong then).
|
|
41914
41963
|
const live=Boolean(run&&run.running&&run.locationId===c.locationId&&run.stage===i);
|
|
41915
41964
|
const anyBusy=Boolean(run&&run.running&&run.locationId===c.locationId);
|
|
41916
|
-
|
|
41917
|
-
|
|
41965
|
+
if(i===curI&&live)curLive=true;
|
|
41966
|
+
const tone=i===curI?"now":isDone(i)?"done":(stale||notPassed)?"stale":"";
|
|
41967
|
+
const seg=document.createElement("span");seg.className="sseg "+tone;track.appendChild(seg);
|
|
41968
|
+
const num=document.createElement("span");num.className="snum "+tone;num.textContent=String(i+1);el.appendChild(num);
|
|
41969
|
+
const nm=document.createElement("b");nm.className="sname";nm.textContent=LABELS[i];el.appendChild(nm);
|
|
41970
|
+
const chipOf=live?["Running\u2026","now"]:stale?["Run again","stale"]:notPassed?["Not passed","stale"]:isDone(i)?["Done","done"]:gate?["Your call","you"]:(st[i]||"pending")==="in_progress"?["In progress","now"]:i===curI?["Up next","now"]:["Waiting","wait"];
|
|
41971
|
+
const chip=document.createElement("span");chip.className="schip "+chipOf[1];chip.textContent=chipOf[0];el.appendChild(chip);
|
|
41972
|
+
const what=document.createElement("div");what.className="swhat";el.appendChild(what);
|
|
41973
|
+
const act=document.createElement("div");act.className="sact";el.appendChild(act);
|
|
41974
|
+
const mkLive=()=>{const box=document.createElement("div");box.className="slive";
|
|
41918
41975
|
const clock=document.createElement("div");clock.style.cssText="font-variant-numeric:tabular-nums;color:var(--ok)";
|
|
41919
41976
|
const began=run.startedAt?new Date(run.startedAt).getTime():0;
|
|
41920
41977
|
const tick=()=>{if(!began)return;const sec=Math.max(0,Math.round((Date.now()-began)/1000));
|
|
@@ -41927,29 +41984,60 @@ function card(c,state,run){const st=(state.clients[c.locationId]||{stages:STAGES
|
|
|
41927
41984
|
line.textContent=(doneAll?"\u2713 ":g.state==="in_progress"?"\u203A ":" ")+g.label+" "+g.done+"/"+g.total;box.appendChild(line)}}
|
|
41928
41985
|
if(pr&&pr.current){const now=document.createElement("div");now.style.cssText="margin-top:.25rem;color:var(--muted)";
|
|
41929
41986
|
now.textContent=String(pr.current).replace(/^"|"$/g,"").slice(0,110);box.appendChild(now)}
|
|
41930
|
-
|
|
41987
|
+
return box};
|
|
41931
41988
|
// One short line here; the button's confirmation carries the full wording. At 135
|
|
41932
41989
|
// characters this sentence made every stage box 677 px tall (auditor, 2026-09-07).
|
|
41933
|
-
|
|
41990
|
+
let about=document.createElement("span");about.textContent=STEP_ABOUT[i][0];
|
|
41991
|
+
if(i===4){const disclosure=document.createElement("span");disclosure.textContent="Checks links and the form. May submit and delete one test lead.";about=disclosure}
|
|
41934
41992
|
if(gate)el.title=gate;
|
|
41935
|
-
if(stale&&!live){const reason=document.createElement("small");reason.textContent=stale.reason;el.appendChild(reason)}
|
|
41936
41993
|
const oc=(state.outcomes||{})[c.locationId+":"+i];
|
|
41937
|
-
|
|
41938
|
-
|
|
41939
|
-
|
|
41994
|
+
const nIss=oc?(oc.issues||[]).length:0;
|
|
41995
|
+
const toggleIssues=(ev)=>{ev.stopPropagation();oOpen[c.locationId+":"+i]=!oOpen[c.locationId+":"+i];render(lastState,lastRun)};
|
|
41996
|
+
const mkNote=()=>{let note=null;
|
|
41997
|
+
if(!live&&oc&&(oc.summary||(oc.issues||[]).length)){note=document.createElement("small");note.className="snote";
|
|
41998
|
+
note.style.cssText="color:"+(nIss?"var(--warn)":"var(--ok)")+";text-decoration:"+(nIss?"underline":"none")+";cursor:"+(nIss?"pointer":"default");
|
|
41940
41999
|
note.textContent=i===4&&oc.ok===true?(${verifyPassedLine.toString()})((state.manualTasks?.[c.locationId]||[]).length):nIss?("\u26A0 "+nIss+" issue"+(nIss>1?"s":"")+". See details"):((oc.plain&&oc.plain.summary)||oc.summary||"").slice(0,90);
|
|
41941
|
-
if(nIss)note.onclick=
|
|
41942
|
-
|
|
42000
|
+
if(nIss)note.onclick=toggleIssues}
|
|
42001
|
+
return note};
|
|
42002
|
+
// What the row says, in one place: the live run, else why it went stale, else what the last
|
|
42003
|
+
// run found, else what the step does.
|
|
42004
|
+
if(live){const rn=document.createElement("span");rn.textContent="Running now.";what.appendChild(rn);what.appendChild(mkLive())}
|
|
42005
|
+
if(stale&&!live){const reason=document.createElement("span");reason.className="sreason";reason.textContent=stale.reason;what.appendChild(reason)}
|
|
42006
|
+
else if(!live){const note=mkNote();what.appendChild(note||about)}
|
|
41943
42007
|
if(POWERED.includes(i)&&(st[i]||"pending")!=="done"){el.style.cursor="default";
|
|
41944
42008
|
el.title="Command OS runs and checks this step. Its result comes from a run, never from a click."}
|
|
41945
|
-
|
|
42009
|
+
const gateLabel=({2:"Approve this plan",5:"Confirm these tasks are finished",6:"Sign this client live"})[i];
|
|
42010
|
+
const mkGate=cls=>{const action=document.createElement("button");action.className=cls;action.textContent=gateLabel;action.onclick=()=>{if(i===2)return approveBuilding();return markStage(c.locationId,i,"done")};return action};
|
|
41946
42011
|
const canBuild=!parkedType&&(i<=1||sandbox||Boolean((state.buildApproved||{})[c.locationId]));
|
|
41947
|
-
if(
|
|
41948
|
-
|
|
42012
|
+
const runIt=async(ev)=>{ev.stopPropagation();if(i===0&&!confirm("In "+c.name+", Intake writes custom fields, one form, and one published notification workflow."+String.fromCharCode(10,10)+INTAKE_NOTIFICATION_REVIEW.join(String.fromCharCode(10))+String.fromCharCode(10,10)+"Create or repair these intake items?"))return;if(i===4&&!confirm("Verify submits one test lead to "+c.name+"\u2019s funnel, watches it arrive, and deletes the test contact afterwards. It may fire this client\u2019s own automations once. Run the check?"))return;const res=await fetch("/api/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({locationId:c.locationId,stage:i,intakeConfirmed:i===0})});const j=await res.json();if(!j.ok)alert(j.error);load()};
|
|
42013
|
+
const mkRun=(cls,label)=>{const b=document.createElement("button");b.className=cls;
|
|
42014
|
+
const busy=run&&run.running;b.textContent=busy&&run.locationId===c.locationId&&run.stage===i?"Running\u2026":label;
|
|
41949
42015
|
b.disabled=Boolean(busy)||(!st.some(s=>s==="done")&&!preflights[c.locationId]?.ok);
|
|
41950
|
-
b.onclick=
|
|
41951
|
-
|
|
42016
|
+
b.onclick=runIt;return b};
|
|
42017
|
+
if(!live&&nIss){const si=document.createElement("button");si.className="sactbtn";si.textContent=nIss>1?"See issues":"See issue";si.onclick=toggleIssues;act.appendChild(si)}
|
|
42018
|
+
if(gate&&!anyBusy&&!parkedType)act.appendChild(mkGate("sactbtn"));
|
|
42019
|
+
if(canBuild&&POWERED.includes(i))act.appendChild(mkRun("sactbtn srun",i===curI?"Run "+LABELS[i]:(st[i]||"pending")==="done"?"Run again":"Run this step"));
|
|
42020
|
+
if(i===curI){const main=document.createElement("div");
|
|
42021
|
+
const k=document.createElement("p");k.className="sk";k.textContent=parkedType?"Building is off":"Next step";main.appendChild(k);
|
|
42022
|
+
const h3=document.createElement("h3");h3.textContent=parkedType?"Nothing is built into this account":(i+1)+". "+LABELS[i];main.appendChild(h3);
|
|
42023
|
+
const pa=document.createElement("p");pa.textContent=parkedType?"It opens here so you can lock or unlock it, or change its type to Client to build it.":STEP_ABOUT[i][1];main.appendChild(pa);
|
|
42024
|
+
if(live)main.appendChild(mkLive());
|
|
42025
|
+
if(stale&&!live){const w=document.createElement("p");w.className="swarn";w.textContent=stale.reason;main.appendChild(w)}
|
|
42026
|
+
const pn=mkNote();if(pn){const w=document.createElement("p");w.className="snoteline";w.appendChild(pn);main.appendChild(w)}
|
|
42027
|
+
const btns=document.createElement("div");btns.className="sbtns";
|
|
42028
|
+
if(gate&&!anyBusy&&!parkedType)btns.appendChild(mkGate("intakebtn sbig"));
|
|
42029
|
+
if(canBuild&&POWERED.includes(i))btns.appendChild(mkRun("runbtn sbig","Run "+LABELS[i]));
|
|
42030
|
+
if(!parkedType&&canBuild&&POWERED.includes(i)&&run&&run.running&&run.locationId!==c.locationId){const why=document.createElement("p");why.className="muted swhy";why.textContent="A step is running for another client. This one can start when it finishes.";btns.appendChild(why)}
|
|
42031
|
+
if(!btns.children.length&&!live&&!parkedType){const why=document.createElement("p");why.className="muted swhy";
|
|
42032
|
+
why.textContent=anyBusy?"Another step is running for this client. This one opens when it finishes.":POWERED.includes(i)?"Approve building for this client below, and this step can run.":"";
|
|
42033
|
+
if(why.textContent)btns.appendChild(why)}
|
|
42034
|
+
nextBox.title=el.title||"";nextBox.appendChild(main);nextBox.appendChild(btns)}
|
|
41952
42035
|
row.appendChild(el)});
|
|
42036
|
+
if(curI<0){const main=document.createElement("div");const k=document.createElement("p");k.className="sk";k.textContent="All done";main.appendChild(k);
|
|
42037
|
+
const h3=document.createElement("h3");h3.textContent="All "+STAGES.length+" steps are done.";main.appendChild(h3);nextBox.appendChild(main)}
|
|
42038
|
+
{const b=document.createElement("b");b.textContent=curI<0?"All "+STAGES.length+" steps done":"Step "+(curI+1)+" of "+STAGES.length+": "+LABELS[curI];plabel.appendChild(b);
|
|
42039
|
+
const after=STAGES.length-nDone-(curI<0?0:1);const s=document.createElement("span");
|
|
42040
|
+
s.textContent=nDone+" done"+(curI<0?"":" \xB7 "+(curLive?"1 running now":"1 needs you")+" \xB7 "+after+" after that");plabel.appendChild(s)}
|
|
41953
42041
|
div.appendChild(row);
|
|
41954
42042
|
for(let i=0;i<STAGES.length;i++){if(oOpen[c.locationId+":"+i]){const op=outcomePanel(c.locationId,i,state);if(op)div.appendChild(op)}}
|
|
41955
42043
|
const view=(state.buildViews||{})[c.locationId];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.84.
|
|
3
|
+
"version": "3.84.9",
|
|
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",
|