@elitedcs/ghl-mcp 3.61.0 → 3.62.0

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/dist/index.js CHANGED
@@ -114,8 +114,8 @@ var init_ghl_client = __esm({
114
114
  Version: version || GHL_API_VERSION
115
115
  };
116
116
  }
117
- buildUrl(path14, params) {
118
- const url = new URL(path14, GHL_BASE_URL);
117
+ buildUrl(path15, params) {
118
+ const url = new URL(path15, GHL_BASE_URL);
119
119
  if (params) {
120
120
  for (const [key, value] of Object.entries(params)) {
121
121
  if (value !== void 0 && value !== null) {
@@ -125,8 +125,8 @@ var init_ghl_client = __esm({
125
125
  }
126
126
  return url.toString();
127
127
  }
128
- async request(method, path14, options = {}, attempt = 0) {
129
- const url = this.buildUrl(path14, options.params);
128
+ async request(method, path15, options = {}, attempt = 0) {
129
+ const url = this.buildUrl(path15, options.params);
130
130
  const headers = this.buildHeaders(options.version);
131
131
  const fetchOptions = {
132
132
  method,
@@ -144,14 +144,14 @@ var init_ghl_client = __esm({
144
144
  } catch (error) {
145
145
  clearTimeout(timeout);
146
146
  if (error instanceof Error && error.name === "AbortError") {
147
- throw new Error(`Request timeout (30s): ${method} ${path14}`);
147
+ throw new Error(`Request timeout (30s): ${method} ${path15}`);
148
148
  }
149
149
  if (!options.noRetry && attempt < MAX_RETRIES) {
150
150
  const delay4 = computeRetryDelay(null, attempt, BASE_DELAY_MS);
151
- process.stderr.write(`[ghl-mcp] Network error on ${method} ${path14}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay4}ms
151
+ process.stderr.write(`[ghl-mcp] Network error on ${method} ${path15}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay4}ms
152
152
  `);
153
153
  await new Promise((r) => setTimeout(r, delay4));
154
- return this.request(method, path14, options, attempt + 1);
154
+ return this.request(method, path15, options, attempt + 1);
155
155
  }
156
156
  throw error;
157
157
  } finally {
@@ -159,10 +159,10 @@ var init_ghl_client = __esm({
159
159
  }
160
160
  if (!options.noRetry && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {
161
161
  const delay4 = computeRetryDelay(response.headers.get("Retry-After"), attempt, BASE_DELAY_MS);
162
- process.stderr.write(`[ghl-mcp] ${response.status} on ${method} ${path14}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay4}ms
162
+ process.stderr.write(`[ghl-mcp] ${response.status} on ${method} ${path15}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay4}ms
163
163
  `);
164
164
  await new Promise((r) => setTimeout(r, delay4));
165
- return this.request(method, path14, options, attempt + 1);
165
+ return this.request(method, path15, options, attempt + 1);
166
166
  }
167
167
  if (!response.ok) {
168
168
  let errorBody = "";
@@ -171,7 +171,7 @@ var init_ghl_client = __esm({
171
171
  } catch {
172
172
  }
173
173
  throw new Error(
174
- `GHL API Error ${response.status} ${response.statusText}: ${method} ${path14}
174
+ `GHL API Error ${response.status} ${response.statusText}: ${method} ${path15}
175
175
  ${errorBody}`
176
176
  );
177
177
  }
@@ -183,20 +183,20 @@ ${errorBody}`
183
183
  return { message: text };
184
184
  }
185
185
  }
186
- async get(path14, options) {
187
- return this.request("GET", path14, options);
186
+ async get(path15, options) {
187
+ return this.request("GET", path15, options);
188
188
  }
189
- async post(path14, options) {
190
- return this.request("POST", path14, options);
189
+ async post(path15, options) {
190
+ return this.request("POST", path15, options);
191
191
  }
192
- async put(path14, options) {
193
- return this.request("PUT", path14, options);
192
+ async put(path15, options) {
193
+ return this.request("PUT", path15, options);
194
194
  }
195
- async patch(path14, options) {
196
- return this.request("PATCH", path14, options);
195
+ async patch(path15, options) {
196
+ return this.request("PATCH", path15, options);
197
197
  }
198
- async delete(path14, options) {
199
- return this.request("DELETE", path14, options);
198
+ async delete(path15, options) {
199
+ return this.request("DELETE", path15, options);
200
200
  }
201
201
  /**
202
202
  * Helper: resolves locationId from args or falls back to default
@@ -1648,7 +1648,7 @@ Note: Firebase credentials rejected (${fb.error}).`;
1648
1648
  const telemetryLine = telemetryDisabled(process.env) ? "" : `
1649
1649
 
1650
1650
  ${TELEMETRY_DISCLOSURE}`;
1651
- const finishedCount = isFree ? "108" : "234";
1651
+ const finishedCount = isFree ? "109" : "235";
1652
1652
  const freeTip = isFree ? `
1653
1653
 
1654
1654
  Free tier: read-only. Write tools stay visible but answer with upgrade info instead of acting. Full version ($97/mo founding rate) upgrades in place \u2014 same install, you only swap the license key: https://ghlcommand.com` : "";
@@ -1693,7 +1693,7 @@ Free tier: read-only. Write tools stay visible but answer with upgrade info inst
1693
1693
  function registerEnableWorkflowBuilderTool(server2) {
1694
1694
  server2.tool(
1695
1695
  "enable_workflow_builder",
1696
- "Add Firebase credentials to an existing GHL Command install to unlock 52 additional tools across the internal-API modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder, form builder, pipeline builder, workflow cloner, smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator. On the FREE tier this same login unlocks the read-only auditor suite (audit_workflows, validate_workflow, full-detail workflow/funnel/pipeline reads). Requires you've already run setup_ghl_mcp. EASIEST PATH: run `capture_firebase_interactive` instead \u2014 a Chrome window opens, you log into GHL, zero pasting. Use THIS tool when you have JSON from `auto_capture_firebase_script` (console-paste path) to put in `firebase_paste`, or the three manual DevTools fields. Tool count goes from 182 to 234 after the next Claude restart.",
1696
+ "Add Firebase credentials to an existing GHL Command install to unlock 52 additional tools across the internal-API modules: workflow builder (create/edit/clone/delete/publish/validate workflows, build_if_else_branch, build_goal_event, get_trigger_registry), funnel + page builder, form builder, pipeline builder, workflow cloner, smart lists, reputation, email campaigns, email templates, and memberships, plus the pre-deploy validator. On the FREE tier this same login unlocks the read-only auditor suite (audit_workflows, validate_workflow, full-detail workflow/funnel/pipeline reads). Requires you've already run setup_ghl_mcp. EASIEST PATH: run `capture_firebase_interactive` instead \u2014 a Chrome window opens, you log into GHL, zero pasting. Use THIS tool when you have JSON from `auto_capture_firebase_script` (console-paste path) to put in `firebase_paste`, or the three manual DevTools fields. Tool count goes from 183 to 235 after the next Claude restart.",
1697
1697
  {
1698
1698
  // v3.25.0: one-paste path. Tool runs `auto_capture_firebase_script` to
1699
1699
  // get the console script; the script returns a JSON object that pastes
@@ -1774,7 +1774,7 @@ DevTools steps: https://elitedcs.com/ghl-mcp-firebase`
1774
1774
  "",
1775
1775
  "**You MUST restart Claude before using any workflow-builder tool.** Quit Claude completely (Cmd+Q on Mac, full exit on Windows) and reopen. Without a restart, the workflow builder tools will keep using the OLD Firebase auth from before this call and fail with 401 errors \u2014 even though this tool reported success.",
1776
1776
  "",
1777
- 'After restart, all 234 tools load. Try: "List my workflows in full detail" or "Validate workflow <id>".',
1777
+ 'After restart, all 235 tools load. Try: "List my workflows in full detail" or "Validate workflow <id>".',
1778
1778
  "",
1779
1779
  "Note: Firebase refresh tokens rotate every few weeks. If workflow tools stop working in a few weeks (run `health_check` to confirm Firebase auth: FAIL), run `auto_capture_firebase_script` for fresh values and re-run this tool with the new firebase_paste."
1780
1780
  ].join("\n")
@@ -1870,7 +1870,7 @@ The login in the capture window may belong to the wrong GHL account, or the sess
1870
1870
  "",
1871
1871
  "**You MUST restart Claude before using any workflow-builder tool.** Quit Claude completely (Cmd+Q on Mac, full exit on Windows) and reopen.",
1872
1872
  "",
1873
- 'After restart, all 234 tools load. Try: "List my workflows in full detail".',
1873
+ 'After restart, all 235 tools load. Try: "List my workflows in full detail".',
1874
1874
  "",
1875
1875
  "Future token rotations re-capture silently \u2014 if workflow tools ever 401, just run capture_firebase_interactive again; no window should appear."
1876
1876
  ].join("\n")
@@ -2471,7 +2471,7 @@ function defaultIO() {
2471
2471
  return {
2472
2472
  out: (l) => process.stdout.write(l + "\n"),
2473
2473
  err: (l) => process.stderr.write(l + "\n"),
2474
- rename: (from, to) => fs9.renameSync(from, to),
2474
+ rename: (from, to) => fs10.renameSync(from, to),
2475
2475
  sleep: (ms) => new Promise((r) => setTimeout(r, ms))
2476
2476
  };
2477
2477
  }
@@ -2481,32 +2481,32 @@ function candidateConfigPaths(opts) {
2481
2481
  const file = "claude_desktop_config.json";
2482
2482
  const candidates = [];
2483
2483
  if (platform2 === "darwin") {
2484
- candidates.push(path8.join(home, "Library", "Application Support", "Claude", file));
2484
+ candidates.push(path9.join(home, "Library", "Application Support", "Claude", file));
2485
2485
  } else if (platform2 === "win32") {
2486
- const appData = opts?.appData ?? process.env.APPDATA ?? path8.join(home, "AppData", "Roaming");
2487
- candidates.push(path8.join(appData, "Claude", file));
2488
- const localAppData = opts?.localAppData ?? process.env.LOCALAPPDATA ?? path8.join(home, "AppData", "Local");
2489
- const packagesDir = path8.join(localAppData, "Packages");
2486
+ const appData = opts?.appData ?? process.env.APPDATA ?? path9.join(home, "AppData", "Roaming");
2487
+ candidates.push(path9.join(appData, "Claude", file));
2488
+ const localAppData = opts?.localAppData ?? process.env.LOCALAPPDATA ?? path9.join(home, "AppData", "Local");
2489
+ const packagesDir = path9.join(localAppData, "Packages");
2490
2490
  try {
2491
- for (const entry of fs9.readdirSync(packagesDir)) {
2491
+ for (const entry of fs10.readdirSync(packagesDir)) {
2492
2492
  if (entry.startsWith("Claude_")) {
2493
- candidates.push(path8.join(packagesDir, entry, "LocalCache", "Roaming", "Claude", file));
2493
+ candidates.push(path9.join(packagesDir, entry, "LocalCache", "Roaming", "Claude", file));
2494
2494
  }
2495
2495
  }
2496
2496
  } catch {
2497
2497
  }
2498
2498
  } else {
2499
- candidates.push(path8.join(home, ".config", "Claude", file));
2499
+ candidates.push(path9.join(home, ".config", "Claude", file));
2500
2500
  }
2501
2501
  return candidates;
2502
2502
  }
2503
2503
  function resolveConfigPath(explicitPath) {
2504
2504
  if (explicitPath) {
2505
- const p = path8.resolve(explicitPath);
2506
- return { configPath: p, exists: fs9.existsSync(p) };
2505
+ const p = path9.resolve(explicitPath);
2506
+ return { configPath: p, exists: fs10.existsSync(p) };
2507
2507
  }
2508
2508
  const candidates = candidateConfigPaths();
2509
- const existing = candidates.filter((c) => fs9.existsSync(c));
2509
+ const existing = candidates.filter((c) => fs10.existsSync(c));
2510
2510
  if (existing.length > 1) {
2511
2511
  throw new InstallStop(
2512
2512
  EXIT_REFUSED,
@@ -2523,22 +2523,22 @@ function resolveConfigPath(explicitPath) {
2523
2523
  function resolveSymlinkPolicy(configPath, explicitPath, home = os4.homedir()) {
2524
2524
  let st;
2525
2525
  try {
2526
- st = fs9.lstatSync(configPath);
2526
+ st = fs10.lstatSync(configPath);
2527
2527
  } catch {
2528
2528
  return configPath;
2529
2529
  }
2530
2530
  if (!st.isSymbolicLink()) return configPath;
2531
2531
  let real;
2532
2532
  try {
2533
- real = fs9.realpathSync(configPath);
2533
+ real = fs10.realpathSync(configPath);
2534
2534
  } catch {
2535
2535
  throw new InstallStop(
2536
2536
  EXIT_REFUSED,
2537
2537
  `${configPath} is a link that points to a file that does not exist. Fix or remove the link, or run again with --path to a real file. Nothing was changed.`
2538
2538
  );
2539
2539
  }
2540
- const rel = path8.relative(path8.resolve(home), real);
2541
- const outsideHome = rel.startsWith("..") || path8.isAbsolute(rel);
2540
+ const rel = path9.relative(path9.resolve(home), real);
2541
+ const outsideHome = rel.startsWith("..") || path9.isAbsolute(rel);
2542
2542
  if (outsideHome && !explicitPath) {
2543
2543
  throw new InstallStop(
2544
2544
  EXIT_REFUSED,
@@ -2548,8 +2548,8 @@ function resolveSymlinkPolicy(configPath, explicitPath, home = os4.homedir()) {
2548
2548
  return real;
2549
2549
  }
2550
2550
  function readConfigBytes(configPath) {
2551
- const bytes = fs9.readFileSync(configPath);
2552
- const stat = fs9.statSync(configPath);
2551
+ const bytes = fs10.readFileSync(configPath);
2552
+ const stat = fs10.statSync(configPath);
2553
2553
  if (bytes.length >= 2 && (bytes[0] === 255 && bytes[1] === 254 || bytes[0] === 254 && bytes[1] === 255)) {
2554
2554
  throw new InstallStop(
2555
2555
  EXIT_REFUSED,
@@ -2623,23 +2623,23 @@ function backupStamp(now) {
2623
2623
  }
2624
2624
  function chooseBackupPath(configPath, now = /* @__PURE__ */ new Date()) {
2625
2625
  const base = `${configPath}.bak-${backupStamp(now)}`;
2626
- if (!fs9.existsSync(base)) return base;
2626
+ if (!fs10.existsSync(base)) return base;
2627
2627
  for (let i = 2; ; i++) {
2628
2628
  const candidate = `${base}-${i}`;
2629
- if (!fs9.existsSync(candidate)) return candidate;
2629
+ if (!fs10.existsSync(candidate)) return candidate;
2630
2630
  }
2631
2631
  }
2632
2632
  function writeVerifiedBackup(configPath, originalBytes) {
2633
2633
  const backupPath = chooseBackupPath(configPath);
2634
2634
  try {
2635
- fs9.writeFileSync(backupPath, originalBytes);
2636
- const readBack = fs9.readFileSync(backupPath);
2635
+ fs10.writeFileSync(backupPath, originalBytes);
2636
+ const readBack = fs10.readFileSync(backupPath);
2637
2637
  if (!readBack.equals(originalBytes)) {
2638
2638
  throw new Error("backup read-back did not match");
2639
2639
  }
2640
2640
  } catch (e) {
2641
2641
  try {
2642
- fs9.rmSync(backupPath, { force: true });
2642
+ fs10.rmSync(backupPath, { force: true });
2643
2643
  } catch {
2644
2644
  }
2645
2645
  throw new InstallStop(
@@ -2658,9 +2658,9 @@ function baselineOf(bytes, stat) {
2658
2658
  function assertNotStale(configPath, baseline) {
2659
2659
  let ok = false;
2660
2660
  try {
2661
- const st = fs9.statSync(configPath);
2661
+ const st = fs10.statSync(configPath);
2662
2662
  if (st.size === baseline.size && st.mtimeMs === baseline.mtimeMs) {
2663
- ok = sha2562(fs9.readFileSync(configPath)) === baseline.hash;
2663
+ ok = sha2562(fs10.readFileSync(configPath)) === baseline.hash;
2664
2664
  } else {
2665
2665
  ok = false;
2666
2666
  }
@@ -2675,14 +2675,14 @@ function assertNotStale(configPath, baseline) {
2675
2675
  }
2676
2676
  }
2677
2677
  async function atomicReplace(opts) {
2678
- const dir = path8.dirname(opts.configPath);
2679
- const tempPath = path8.join(dir, `.${path8.basename(opts.configPath)}.tmp-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`);
2680
- const fd = fs9.openSync(tempPath, "w");
2678
+ const dir = path9.dirname(opts.configPath);
2679
+ const tempPath = path9.join(dir, `.${path9.basename(opts.configPath)}.tmp-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`);
2680
+ const fd = fs10.openSync(tempPath, "w");
2681
2681
  try {
2682
- fs9.writeFileSync(fd, opts.newBytes);
2683
- fs9.fsyncSync(fd);
2682
+ fs10.writeFileSync(fd, opts.newBytes);
2683
+ fs10.fsyncSync(fd);
2684
2684
  } finally {
2685
- fs9.closeSync(fd);
2685
+ fs10.closeSync(fd);
2686
2686
  }
2687
2687
  try {
2688
2688
  for (let attempt = 0; ; attempt++) {
@@ -2707,17 +2707,17 @@ async function atomicReplace(opts) {
2707
2707
  }
2708
2708
  } catch (e) {
2709
2709
  try {
2710
- fs9.rmSync(tempPath, { force: true });
2710
+ fs10.rmSync(tempPath, { force: true });
2711
2711
  } catch {
2712
2712
  }
2713
2713
  throw e;
2714
2714
  }
2715
2715
  try {
2716
- const dirFd = fs9.openSync(dir, "r");
2716
+ const dirFd = fs10.openSync(dir, "r");
2717
2717
  try {
2718
- fs9.fsyncSync(dirFd);
2718
+ fs10.fsyncSync(dirFd);
2719
2719
  } finally {
2720
- fs9.closeSync(dirFd);
2720
+ fs10.closeSync(dirFd);
2721
2721
  }
2722
2722
  } catch {
2723
2723
  }
@@ -2769,7 +2769,7 @@ async function runInstall(argv, ioOverride) {
2769
2769
  try {
2770
2770
  const resolved2 = resolveConfigPath(flags.path);
2771
2771
  const configPath = resolveSymlinkPolicy(resolved2.configPath, flags.path !== void 0);
2772
- const exists = fs9.existsSync(configPath);
2772
+ const exists = fs10.existsSync(configPath);
2773
2773
  let read = null;
2774
2774
  let outcome;
2775
2775
  if (exists) {
@@ -2799,7 +2799,7 @@ async function runInstall(argv, ioOverride) {
2799
2799
  return EXIT_OK;
2800
2800
  }
2801
2801
  const backupPath = exists && read ? writeVerifiedBackup(configPath, read.bytes) : null;
2802
- if (!exists) fs9.mkdirSync(path8.dirname(configPath), { recursive: true });
2802
+ if (!exists) fs10.mkdirSync(path9.dirname(configPath), { recursive: true });
2803
2803
  await atomicReplace({
2804
2804
  configPath,
2805
2805
  newBytes,
@@ -2817,13 +2817,13 @@ async function runInstall(argv, ioOverride) {
2817
2817
  return EXIT_ABORTED;
2818
2818
  }
2819
2819
  }
2820
- var fs9, os4, path8, import_node_crypto3, import_node_util, import_json5, SERVER_KEY, DESIRED_ENTRY, EXIT_OK, EXIT_USAGE, EXIT_REFUSED, EXIT_ABORTED, RENAME_RETRY_DELAYS_MS, LOCK_ERROR_CODES, BOM_UTF8, InstallStop;
2820
+ var fs10, os4, path9, import_node_crypto3, import_node_util, import_json5, SERVER_KEY, DESIRED_ENTRY, EXIT_OK, EXIT_USAGE, EXIT_REFUSED, EXIT_ABORTED, RENAME_RETRY_DELAYS_MS, LOCK_ERROR_CODES, BOM_UTF8, InstallStop;
2821
2821
  var init_config_installer = __esm({
2822
2822
  "src/config-installer.ts"() {
2823
2823
  "use strict";
2824
- fs9 = __toESM(require("node:fs"));
2824
+ fs10 = __toESM(require("node:fs"));
2825
2825
  os4 = __toESM(require("node:os"));
2826
- path8 = __toESM(require("node:path"));
2826
+ path9 = __toESM(require("node:path"));
2827
2827
  import_node_crypto3 = require("node:crypto");
2828
2828
  import_node_util = require("node:util");
2829
2829
  import_json5 = __toESM(require("json5"));
@@ -2854,9 +2854,9 @@ var require_package = __commonJS({
2854
2854
  "package.json"(exports2, module2) {
2855
2855
  module2.exports = {
2856
2856
  name: "@elitedcs/ghl-mcp",
2857
- version: "3.61.0",
2857
+ version: "3.62.0",
2858
2858
  mcpName: "io.github.drjerryrelth/ghl-command",
2859
- description: "GoHighLevel MCP Server for Claude. 234 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.",
2859
+ description: "GoHighLevel MCP Server for Claude. 235 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.",
2860
2860
  main: "dist/index.js",
2861
2861
  bin: {
2862
2862
  "ghl-mcp": "dist/index.js"
@@ -2871,7 +2871,8 @@ var require_package = __commonJS({
2871
2871
  "templates/external-funnel/README.md",
2872
2872
  "README.md",
2873
2873
  "CHANGELOG.md",
2874
- "skills"
2874
+ "skills",
2875
+ "guide"
2875
2876
  ],
2876
2877
  scripts: {
2877
2878
  build: "esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.js --packages=external && esbuild src/capture-helper.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/capture-helper.js --packages=external",
@@ -2945,7 +2946,7 @@ function launchCommand(port = 7300) {
2945
2946
  return `npx -y @elitedcs/ghl-mcp@latest dashboard --port=${port}`;
2946
2947
  }
2947
2948
  function installingEntry() {
2948
- return path10.join(__dirname, "index.js");
2949
+ return path11.join(__dirname, "index.js");
2949
2950
  }
2950
2951
  function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
2951
2952
  const cmd = launchCommand(port);
@@ -2953,12 +2954,12 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
2953
2954
  const systemApps = "/Applications";
2954
2955
  let base = home;
2955
2956
  try {
2956
- fs11.accessSync(systemApps, fs11.constants.W_OK);
2957
+ fs12.accessSync(systemApps, fs12.constants.W_OK);
2957
2958
  base = "";
2958
2959
  } catch {
2959
2960
  }
2960
- const appDir = base ? path10.join(home, "Applications", "Command OS.app") : path10.join(systemApps, "Command OS.app");
2961
- const macOSDir = path10.join(appDir, "Contents", "MacOS");
2961
+ const appDir = base ? path11.join(home, "Applications", "Command OS.app") : path11.join(systemApps, "Command OS.app");
2962
+ const macOSDir = path11.join(appDir, "Contents", "MacOS");
2962
2963
  const script = [
2963
2964
  "#!/bin/bash",
2964
2965
  "# GHL Command \u2014 Command OS launcher (regenerate: ghl-mcp install-launcher)",
@@ -2987,13 +2988,13 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
2987
2988
  targetPath: appDir,
2988
2989
  humanLocation: base ? "your personal Applications folder at ~/Applications (Finder \u2192 Go \u2192 Home \u2192 Applications)" : "your Applications folder \u2014 open Finder \u2192 Applications and look for \u201CCommand OS\u201D",
2989
2990
  files: [
2990
- { path: path10.join(macOSDir, "command-os"), contents: script, executable: true },
2991
- { path: path10.join(appDir, "Contents", "Info.plist"), contents: plist, executable: false }
2991
+ { path: path11.join(macOSDir, "command-os"), contents: script, executable: true },
2992
+ { path: path11.join(appDir, "Contents", "Info.plist"), contents: plist, executable: false }
2992
2993
  ]
2993
2994
  };
2994
2995
  }
2995
2996
  if (platform2 === "win32") {
2996
- const target2 = path10.join(home, "Desktop", "Command OS.cmd");
2997
+ const target2 = path11.join(home, "Desktop", "Command OS.cmd");
2997
2998
  return {
2998
2999
  platform: platform2,
2999
3000
  targetPath: target2,
@@ -3006,7 +3007,7 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
3006
3007
  ].join("\r\n"), executable: false }]
3007
3008
  };
3008
3009
  }
3009
- const target = path10.join(home, ".local", "share", "applications", "command-os.desktop");
3010
+ const target = path11.join(home, ".local", "share", "applications", "command-os.desktop");
3010
3011
  return {
3011
3012
  platform: platform2,
3012
3013
  targetPath: target,
@@ -3033,8 +3034,8 @@ function installLauncher(argv = []) {
3033
3034
  const plan = planLauncher(process.platform, os5.homedir(), port, installingEntry());
3034
3035
  try {
3035
3036
  for (const f of plan.files) {
3036
- fs11.mkdirSync(path10.dirname(f.path), { recursive: true });
3037
- fs11.writeFileSync(f.path, f.contents, { mode: f.executable ? 493 : 420 });
3037
+ fs12.mkdirSync(path11.dirname(f.path), { recursive: true });
3038
+ fs12.writeFileSync(f.path, f.contents, { mode: f.executable ? 493 : 420 });
3038
3039
  }
3039
3040
  } catch (e) {
3040
3041
  process.stderr.write(`
@@ -3054,13 +3055,13 @@ function installLauncher(argv = []) {
3054
3055
  ].join("\n"));
3055
3056
  return 0;
3056
3057
  }
3057
- var fs11, os5, path10;
3058
+ var fs12, os5, path11;
3058
3059
  var init_launcher = __esm({
3059
3060
  "src/launcher.ts"() {
3060
3061
  "use strict";
3061
- fs11 = __toESM(require("fs"));
3062
+ fs12 = __toESM(require("fs"));
3062
3063
  os5 = __toESM(require("os"));
3063
- path10 = __toESM(require("path"));
3064
+ path11 = __toESM(require("path"));
3064
3065
  }
3065
3066
  });
3066
3067
 
@@ -3089,10 +3090,10 @@ function stageBlockedBy(stages, stage) {
3089
3090
  return null;
3090
3091
  }
3091
3092
  function claudeBin() {
3092
- const fallback = path11.join(os6.homedir(), ".local", "bin", "claude");
3093
- const fromPath = (process.env.PATH || "").split(path11.delimiter).map((d) => path11.join(d, "claude")).find((p) => {
3093
+ const fallback = path12.join(os6.homedir(), ".local", "bin", "claude");
3094
+ const fromPath = (process.env.PATH || "").split(path12.delimiter).map((d) => path12.join(d, "claude")).find((p) => {
3094
3095
  try {
3095
- fs12.accessSync(p, fs12.constants.X_OK);
3096
+ fs13.accessSync(p, fs13.constants.X_OK);
3096
3097
  return true;
3097
3098
  } catch {
3098
3099
  return false;
@@ -3100,7 +3101,7 @@ function claudeBin() {
3100
3101
  });
3101
3102
  if (fromPath) return fromPath;
3102
3103
  try {
3103
- fs12.accessSync(fallback, fs12.constants.X_OK);
3104
+ fs13.accessSync(fallback, fs13.constants.X_OK);
3104
3105
  return fallback;
3105
3106
  } catch {
3106
3107
  }
@@ -3149,10 +3150,10 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
3149
3150
  const locationName = SANDBOX_ALLOWLIST[locationId2] || opts.name || locationId2;
3150
3151
  const spec = STAGE_SPECS[stage];
3151
3152
  if (!spec) return Promise.reject(new Error(`Stage ${stage} is not powered yet.`));
3152
- return new Promise((resolve7) => {
3153
+ return new Promise((resolve8) => {
3153
3154
  const bin = claudeBin();
3154
3155
  onEvent({ kind: "status", line: `Starting ${spec.name} on ${locationName} (headless Claude, ${spec.allowedTools.length} tools allowed)\u2026` });
3155
- const child = (0, import_child_process2.spawn)(bin, buildClaudeArgs(spec, locationId2, locationName, opts.context), {
3156
+ const child = (0, import_child_process3.spawn)(bin, buildClaudeArgs(spec, locationId2, locationName, opts.context), {
3156
3157
  stdio: ["ignore", "pipe", "pipe"],
3157
3158
  env: { ...process.env }
3158
3159
  });
@@ -3195,31 +3196,31 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
3195
3196
  if (code !== 0 && !lastText) {
3196
3197
  const outcome2 = { ok: false, error: `claude exited ${code}: ${stderrTail.trim().slice(-200) || "no output"}` };
3197
3198
  onEvent({ kind: "error", line: outcome2.error });
3198
- resolve7(outcome2);
3199
+ resolve8(outcome2);
3199
3200
  return;
3200
3201
  }
3201
3202
  const outcome = parseResultLine(lastText);
3202
3203
  const detail = outcome.error || (outcome.issues?.length ? outcome.issues.join(" \xB7 ") : "") || outcome.summary || "no detail reported";
3203
3204
  const success = outcome.formId ? `Done: form "${outcome.formName}" (${outcome.formId})` : `Done: ${outcome.summary ?? "stage complete"}`;
3204
3205
  onEvent({ kind: "result", line: outcome.ok ? success : `Not passed: ${detail}` });
3205
- resolve7(outcome);
3206
+ resolve8(outcome);
3206
3207
  });
3207
3208
  child.on("error", (err) => {
3208
3209
  clearTimeout(timeout);
3209
3210
  const outcome = { ok: false, error: `could not start claude: ${err.message}` };
3210
3211
  onEvent({ kind: "error", line: outcome.error });
3211
- resolve7(outcome);
3212
+ resolve8(outcome);
3212
3213
  });
3213
3214
  });
3214
3215
  }
3215
- var import_child_process2, fs12, os6, path11, SANDBOX_ALLOWLIST, PROTECTED_LOCATIONS, STAGE_SPECS, HUMAN_GATE_STAGES;
3216
+ var import_child_process3, fs13, os6, path12, SANDBOX_ALLOWLIST, PROTECTED_LOCATIONS, STAGE_SPECS, HUMAN_GATE_STAGES;
3216
3217
  var init_stage_runner = __esm({
3217
3218
  "src/stage-runner.ts"() {
3218
3219
  "use strict";
3219
- import_child_process2 = require("child_process");
3220
- fs12 = __toESM(require("fs"));
3220
+ import_child_process3 = require("child_process");
3221
+ fs13 = __toESM(require("fs"));
3221
3222
  os6 = __toESM(require("os"));
3222
- path11 = __toESM(require("path"));
3223
+ path12 = __toESM(require("path"));
3223
3224
  SANDBOX_ALLOWLIST = {
3224
3225
  JrV2p35O3hY2wqhr2c0T: "MCP Testing",
3225
3226
  jHP5wkYRineXDlzAOEbW: "Blueprint Demo"
@@ -3939,11 +3940,11 @@ __export(dashboard_exports, {
3939
3940
  writeOverlay: () => writeOverlay
3940
3941
  });
3941
3942
  function overlayPath() {
3942
- return path12.join(appDataDir(), "intake-overlay.json");
3943
+ return path13.join(appDataDir(), "intake-overlay.json");
3943
3944
  }
3944
3945
  function readOverlay() {
3945
3946
  try {
3946
- const raw = JSON.parse(fs13.readFileSync(overlayPath(), "utf8"));
3947
+ const raw = JSON.parse(fs14.readFileSync(overlayPath(), "utf8"));
3947
3948
  if (raw && typeof raw === "object") return raw;
3948
3949
  } catch {
3949
3950
  }
@@ -3951,7 +3952,7 @@ function readOverlay() {
3951
3952
  }
3952
3953
  function writeOverlay(layer) {
3953
3954
  ensureAppDataDir();
3954
- fs13.writeFileSync(overlayPath(), JSON.stringify(layer, null, 2), { mode: 384 });
3955
+ fs14.writeFileSync(overlayPath(), JSON.stringify(layer, null, 2), { mode: 384 });
3955
3956
  }
3956
3957
  function recoverStuckStages(state) {
3957
3958
  let recovered = 0;
@@ -3963,11 +3964,11 @@ function recoverStuckStages(state) {
3963
3964
  return { state: { ...state, clients }, recovered };
3964
3965
  }
3965
3966
  function cockpitStatePath() {
3966
- return path12.join(appDataDir(), "cockpit-state.json");
3967
+ return path13.join(appDataDir(), "cockpit-state.json");
3967
3968
  }
3968
3969
  function readCockpitState() {
3969
3970
  try {
3970
- const raw = JSON.parse(fs13.readFileSync(cockpitStatePath(), "utf8"));
3971
+ const raw = JSON.parse(fs14.readFileSync(cockpitStatePath(), "utf8"));
3971
3972
  if (raw && raw.v === 1 && raw.clients && typeof raw.clients === "object") return raw;
3972
3973
  } catch {
3973
3974
  }
@@ -3975,7 +3976,7 @@ function readCockpitState() {
3975
3976
  }
3976
3977
  function writeCockpitState(state) {
3977
3978
  ensureAppDataDir();
3978
- fs13.writeFileSync(cockpitStatePath(), JSON.stringify(state, null, 2), { mode: 384 });
3979
+ fs14.writeFileSync(cockpitStatePath(), JSON.stringify(state, null, 2), { mode: 384 });
3979
3980
  }
3980
3981
  function setStage(state, locationId2, stageIndex, status) {
3981
3982
  if (!Number.isInteger(stageIndex) || stageIndex < 0 || stageIndex >= STAGES.length) throw new Error("bad stage index");
@@ -4067,13 +4068,13 @@ function notify(message) {
4067
4068
  `);
4068
4069
  try {
4069
4070
  ensureAppDataDir();
4070
- fs13.appendFileSync(path12.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
4071
+ fs14.appendFileSync(path13.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
4071
4072
  `);
4072
4073
  } catch {
4073
4074
  }
4074
4075
  if (!process.stdout.isTTY && process.platform === "darwin") {
4075
4076
  try {
4076
- (0, import_child_process3.spawn)(
4077
+ (0, import_child_process4.spawn)(
4077
4078
  "/usr/bin/osascript",
4078
4079
  ["-e", `display dialog ${JSON.stringify(message)} with title "Command OS" buttons {"OK"} default button "OK"`],
4079
4080
  { stdio: "ignore", detached: true }
@@ -4086,7 +4087,7 @@ function openBrowser(port) {
4086
4087
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
4087
4088
  const openArgs = process.platform === "win32" ? ["/c", "start", "", `http://localhost:${port}`] : [`http://localhost:${port}`];
4088
4089
  try {
4089
- (0, import_child_process3.spawn)(opener, openArgs, { stdio: "ignore", detached: true }).unref();
4090
+ (0, import_child_process4.spawn)(opener, openArgs, { stdio: "ignore", detached: true }).unref();
4090
4091
  } catch {
4091
4092
  }
4092
4093
  }
@@ -4768,17 +4769,17 @@ async function runDashboard(argv) {
4768
4769
  const source = args.url ? { kind: "url", url: String(args.url) } : args.instruction ? { kind: "recorder", instruction: String(args.instruction) } : { kind: "text", text: String(args.transcript ?? "") };
4769
4770
  let recorderPatterns = [];
4770
4771
  if (source.kind === "recorder") {
4771
- recorderPatterns = await new Promise((resolve7) => {
4772
- const ls = (0, import_child_process4.spawn)(claudeBin(), ["mcp", "list"], { stdio: ["ignore", "pipe", "ignore"] });
4772
+ recorderPatterns = await new Promise((resolve8) => {
4773
+ const ls = (0, import_child_process5.spawn)(claudeBin(), ["mcp", "list"], { stdio: ["ignore", "pipe", "ignore"] });
4773
4774
  let buf = "";
4774
4775
  ls.stdout.on("data", (d) => {
4775
4776
  buf += d.toString();
4776
4777
  });
4777
- ls.on("close", () => resolve7(recorderAllowPatterns(buf)));
4778
- ls.on("error", () => resolve7([]));
4778
+ ls.on("close", () => resolve8(recorderAllowPatterns(buf)));
4779
+ ls.on("error", () => resolve8([]));
4779
4780
  setTimeout(() => {
4780
4781
  ls.kill("SIGKILL");
4781
- resolve7(recorderAllowPatterns(buf));
4782
+ resolve8(recorderAllowPatterns(buf));
4782
4783
  }, 9e4).unref?.();
4783
4784
  });
4784
4785
  if (!recorderPatterns.length) {
@@ -4788,16 +4789,16 @@ async function runDashboard(argv) {
4788
4789
  }
4789
4790
  }
4790
4791
  const out = await prefillFromSource(
4791
- (prompt, tools) => new Promise((resolve7, reject) => {
4792
+ (prompt, tools) => new Promise((resolve8, reject) => {
4792
4793
  const argv2 = ["-p", prompt, "--max-turns", "25", "--disallowedTools", tools.deny];
4793
4794
  if (tools.allow) argv2.push("--allowedTools", tools.allow);
4794
4795
  else argv2.push("--allowedTools", "");
4795
- const child = (0, import_child_process4.spawn)(claudeBin(), argv2, { stdio: ["ignore", "pipe", "pipe"] });
4796
+ const child = (0, import_child_process5.spawn)(claudeBin(), argv2, { stdio: ["ignore", "pipe", "pipe"] });
4796
4797
  let out2 = "";
4797
4798
  child.stdout.on("data", (d) => {
4798
4799
  out2 += d.toString();
4799
4800
  });
4800
- child.on("close", () => resolve7(out2));
4801
+ child.on("close", () => resolve8(out2));
4801
4802
  child.on("error", reject);
4802
4803
  setTimeout(() => child.kill("SIGKILL"), 5 * 60 * 1e3).unref?.();
4803
4804
  }),
@@ -4929,13 +4930,13 @@ async function runDashboard(argv) {
4929
4930
  }
4930
4931
  }
4931
4932
  const review = await generateReview(
4932
- (prompt) => new Promise((resolve7, reject) => {
4933
- const child = (0, import_child_process4.spawn)(claudeBin(), ["-p", prompt, "--allowedTools", "", "--disallowedTools", "Bash,Write,Edit,WebFetch,WebSearch,Task,Read,Glob,Grep", "--max-turns", "6"], { stdio: ["ignore", "pipe", "pipe"] });
4933
+ (prompt) => new Promise((resolve8, reject) => {
4934
+ const child = (0, import_child_process5.spawn)(claudeBin(), ["-p", prompt, "--allowedTools", "", "--disallowedTools", "Bash,Write,Edit,WebFetch,WebSearch,Task,Read,Glob,Grep", "--max-turns", "6"], { stdio: ["ignore", "pipe", "pipe"] });
4934
4935
  let out = "";
4935
4936
  child.stdout.on("data", (d) => {
4936
4937
  out += d.toString();
4937
4938
  });
4938
- child.on("close", () => resolve7(out));
4939
+ child.on("close", () => resolve8(out));
4939
4940
  child.on("error", reject);
4940
4941
  setTimeout(() => child.kill("SIGKILL"), 6 * 60 * 1e3).unref?.();
4941
4942
  }),
@@ -5108,9 +5109,9 @@ async function runDashboard(argv) {
5108
5109
  res.end();
5109
5110
  });
5110
5111
  try {
5111
- await new Promise((resolve7, reject) => {
5112
+ await new Promise((resolve8, reject) => {
5112
5113
  server2.once("error", reject);
5113
- server2.listen(port, "127.0.0.1", resolve7);
5114
+ server2.listen(port, "127.0.0.1", resolve8);
5114
5115
  });
5115
5116
  } catch (e) {
5116
5117
  const msg2 = e?.code === "EADDRINUSE" ? `Port ${port} is busy with another program. Close it, or start Command OS on a different port.` : `Command OS could not start: ${e instanceof Error ? e.message : String(e)}`;
@@ -5136,20 +5137,20 @@ async function runDashboard(argv) {
5136
5137
  if (adopted) process.stderr.write(` Synced ${adopted} client${adopted === 1 ? "" : "s"} from your GHL (teammate updates).
5137
5138
  `);
5138
5139
  });
5139
- return await new Promise((resolve7) => {
5140
- const stop = () => server2.close(() => resolve7(0));
5140
+ return await new Promise((resolve8) => {
5141
+ const stop = () => server2.close(() => resolve8(0));
5141
5142
  process.on("SIGINT", stop);
5142
5143
  process.on("SIGTERM", stop);
5143
5144
  });
5144
5145
  }
5145
- var fs13, path12, http, import_child_process3, import_child_process4, osmod, STAGES, ACCOUNT_TYPES, activeRun, UPGRADE_MSG;
5146
+ var fs14, path13, http, import_child_process4, import_child_process5, osmod, STAGES, ACCOUNT_TYPES, activeRun, UPGRADE_MSG;
5146
5147
  var init_dashboard = __esm({
5147
5148
  "src/dashboard.ts"() {
5148
5149
  "use strict";
5149
- fs13 = __toESM(require("fs"));
5150
- path12 = __toESM(require("path"));
5150
+ fs14 = __toESM(require("fs"));
5151
+ path13 = __toESM(require("path"));
5151
5152
  http = __toESM(require("http"));
5152
- import_child_process3 = require("child_process");
5153
+ import_child_process4 = require("child_process");
5153
5154
  init_credentials_store();
5154
5155
  init_attestation();
5155
5156
  init_setup_tool();
@@ -5161,7 +5162,7 @@ var init_dashboard = __esm({
5161
5162
  init_client_intake();
5162
5163
  init_blueprint_review();
5163
5164
  init_stage_runner();
5164
- import_child_process4 = require("child_process");
5165
+ import_child_process5 = require("child_process");
5165
5166
  init_ghl_client();
5166
5167
  init_shared_brain();
5167
5168
  osmod = __toESM(require("os"));
@@ -5182,8 +5183,8 @@ var init_dashboard = __esm({
5182
5183
 
5183
5184
  // src/index.ts
5184
5185
  var dotenv2 = __toESM(require("dotenv"));
5185
- var path13 = __toESM(require("path"));
5186
- var fs14 = __toESM(require("fs"));
5186
+ var path14 = __toESM(require("path"));
5187
+ var fs15 = __toESM(require("fs"));
5187
5188
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
5188
5189
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
5189
5190
  init_ghl_client();
@@ -9340,16 +9341,16 @@ function registerEmailTools(server2, client) {
9340
9341
  function registerEmailBuilderInternalTools(server2, builderClient) {
9341
9342
  const client = builderClient;
9342
9343
  if (!client) return;
9343
- async function builderRequest(method, path14, body) {
9344
+ async function builderRequest(method, path15, body) {
9344
9345
  const headers = await client.buildHeaders();
9345
- const response = await fetch(`${EMAIL_BUILDER_BASE}${path14}`, {
9346
+ const response = await fetch(`${EMAIL_BUILDER_BASE}${path15}`, {
9346
9347
  method,
9347
9348
  headers,
9348
9349
  body: body ? JSON.stringify(body) : void 0
9349
9350
  });
9350
9351
  if (!response.ok) {
9351
9352
  const text2 = await response.text();
9352
- throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path14}
9353
+ throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path15}
9353
9354
  ${text2}`);
9354
9355
  }
9355
9356
  const text = await response.text();
@@ -10606,23 +10607,23 @@ var import_zod37 = require("zod");
10606
10607
  function registerFunnelBuilderTools(server2, builderClient) {
10607
10608
  const client = builderClient;
10608
10609
  if (!client) return;
10609
- async function internalGet(path14) {
10610
- return client.request("GET", path14);
10610
+ async function internalGet(path15) {
10611
+ return client.request("GET", path15);
10611
10612
  }
10612
- async function internalPost(path14, body) {
10613
- return client.request("POST", path14, body);
10613
+ async function internalPost(path15, body) {
10614
+ return client.request("POST", path15, body);
10614
10615
  }
10615
- async function internalPut(path14, body) {
10616
- return client.request("PUT", path14, body);
10616
+ async function internalPut(path15, body) {
10617
+ return client.request("PUT", path15, body);
10617
10618
  }
10618
- async function internalDelete(path14) {
10619
- return client.request("DELETE", path14);
10619
+ async function internalDelete(path15) {
10620
+ return client.request("DELETE", path15);
10620
10621
  }
10621
- async function funnelRequest(method, path14, body) {
10622
+ async function funnelRequest(method, path15, body) {
10622
10623
  const headers = await client.buildHeaders();
10623
10624
  headers.Origin = "https://app.gohighlevel.com";
10624
10625
  headers.Referer = "https://app.gohighlevel.com/";
10625
- const url = `https://backend.leadconnectorhq.com/funnels${path14}`;
10626
+ const url = `https://backend.leadconnectorhq.com/funnels${path15}`;
10626
10627
  const options = { method, headers };
10627
10628
  if (body && (method === "POST" || method === "PUT")) {
10628
10629
  options.body = JSON.stringify(body);
@@ -10630,7 +10631,7 @@ function registerFunnelBuilderTools(server2, builderClient) {
10630
10631
  const response = await fetch(url, options);
10631
10632
  if (!response.ok) {
10632
10633
  const text2 = await response.text();
10633
- throw new Error(`Funnel API Error ${response.status}: ${method} ${path14}
10634
+ throw new Error(`Funnel API Error ${response.status}: ${method} ${path15}
10634
10635
  ${text2}`);
10635
10636
  }
10636
10637
  const text = await response.text();
@@ -11575,12 +11576,12 @@ var valueCardSchema = import_zod38.z.object({
11575
11576
  function registerPageStudioTools(server2, builderClient) {
11576
11577
  const client = builderClient;
11577
11578
  if (!client) return;
11578
- async function funnelRequest(method, path14) {
11579
+ async function funnelRequest(method, path15) {
11579
11580
  const headers = await client.buildHeaders();
11580
11581
  headers.Origin = "https://app.gohighlevel.com";
11581
11582
  headers.Referer = "https://app.gohighlevel.com/";
11582
- const response = await fetch(`https://backend.leadconnectorhq.com/funnels${path14}`, { method, headers });
11583
- if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path14}
11583
+ const response = await fetch(`https://backend.leadconnectorhq.com/funnels${path15}`, { method, headers });
11584
+ if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path15}
11584
11585
  ${await response.text()}`);
11585
11586
  const text = await response.text();
11586
11587
  return text ? JSON.parse(text) : {};
@@ -11899,9 +11900,9 @@ function buildUpdateFormPath(formId, locationId2) {
11899
11900
  function buildUpdateFormBody(name, formData) {
11900
11901
  return { name, formData };
11901
11902
  }
11902
- async function formApiRequest(client, method, path14, body) {
11903
+ async function formApiRequest(client, method, path15, body) {
11903
11904
  const headers = await client.buildHeaders();
11904
- const url = `https://backend.leadconnectorhq.com/forms${path14}`;
11905
+ const url = `https://backend.leadconnectorhq.com/forms${path15}`;
11905
11906
  const options = { method, headers };
11906
11907
  if (body && (method === "POST" || method === "PUT")) {
11907
11908
  options.body = JSON.stringify(body);
@@ -11909,7 +11910,7 @@ async function formApiRequest(client, method, path14, body) {
11909
11910
  const response = await fetch(url, options);
11910
11911
  if (!response.ok) {
11911
11912
  const text2 = await response.text();
11912
- throw new Error(`Form API Error ${response.status}: ${method} ${path14}
11913
+ throw new Error(`Form API Error ${response.status}: ${method} ${path15}
11913
11914
  ${text2}`);
11914
11915
  }
11915
11916
  const text = await response.text();
@@ -11923,7 +11924,7 @@ ${text2}`);
11923
11924
  function registerFormBuilderTools(server2, builderClient, publicClient) {
11924
11925
  const client = builderClient;
11925
11926
  if (!client) return;
11926
- const formRequest = (method, path14, body) => formApiRequest(client, method, path14, body);
11927
+ const formRequest = (method, path15, body) => formApiRequest(client, method, path15, body);
11927
11928
  server2.tool(
11928
11929
  "get_form_full",
11929
11930
  "Get a form with full builder data: all fields (labels, types, IDs, validation), conditional logic, auto-responder config, email notification settings, styling, and version history. This is the internal API \u2014 it returns everything the form builder UI shows.",
@@ -12044,10 +12045,10 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
12044
12045
  },
12045
12046
  async ({ formId, limit, skip }) => {
12046
12047
  try {
12047
- let path14 = `/submissions?locationId=${client.locationId}&limit=${limit ?? 20}`;
12048
- if (formId) path14 += `&formId=${formId}`;
12049
- if (skip) path14 += `&skip=${skip}`;
12050
- const result = await formRequest("GET", path14);
12048
+ let path15 = `/submissions?locationId=${client.locationId}&limit=${limit ?? 20}`;
12049
+ if (formId) path15 += `&formId=${formId}`;
12050
+ if (skip) path15 += `&skip=${skip}`;
12051
+ const result = await formRequest("GET", path15);
12051
12052
  return {
12052
12053
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
12053
12054
  };
@@ -12440,9 +12441,9 @@ var import_zod41 = require("zod");
12440
12441
  function registerPipelineBuilderTools(server2, builderClient) {
12441
12442
  const client = builderClient;
12442
12443
  if (!client) return;
12443
- async function pipelineRequest(method, path14, body) {
12444
+ async function pipelineRequest(method, path15, body) {
12444
12445
  const headers = await client.buildHeaders();
12445
- const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path14}`;
12446
+ const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path15}`;
12446
12447
  const options = { method, headers };
12447
12448
  if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
12448
12449
  options.body = JSON.stringify(body);
@@ -12450,7 +12451,7 @@ function registerPipelineBuilderTools(server2, builderClient) {
12450
12451
  const response = await fetch(url, options);
12451
12452
  if (!response.ok) {
12452
12453
  const text2 = await response.text();
12453
- throw new Error(`Pipeline API Error ${response.status}: ${method} ${path14}
12454
+ throw new Error(`Pipeline API Error ${response.status}: ${method} ${path15}
12454
12455
  ${text2}`);
12455
12456
  }
12456
12457
  const text = await response.text();
@@ -13195,7 +13196,7 @@ ${lines.join("\n")}
13195
13196
  // src/tools/bulk-operations.ts
13196
13197
  var import_zod45 = require("zod");
13197
13198
  function delay(ms) {
13198
- return new Promise((resolve7) => setTimeout(resolve7, ms));
13199
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
13199
13200
  }
13200
13201
  function formatResults(op, results, total) {
13201
13202
  return `${op}: ${results.success} success, ${results.failed} failed out of ${total}.${results.errors.length ? "\nErrors:\n" + results.errors.join("\n") : ""}`;
@@ -13320,7 +13321,7 @@ function registerBulkOperationTools(server2, client) {
13320
13321
  // src/tools/account-export.ts
13321
13322
  var import_zod46 = require("zod");
13322
13323
  function delay2(ms) {
13323
- return new Promise((resolve7) => setTimeout(resolve7, ms));
13324
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
13324
13325
  }
13325
13326
  function registerAccountExportTools(server2, client) {
13326
13327
  const builderClient = WorkflowBuilderClient.fromEnv();
@@ -13641,9 +13642,9 @@ var OBJECT_KEYS = ["contacts", "opportunity"];
13641
13642
  function registerSmartListTools(server2, builderClient) {
13642
13643
  const client = builderClient;
13643
13644
  if (!client) return;
13644
- async function smartListRequest(method, path14, body) {
13645
+ async function smartListRequest(method, path15, body) {
13645
13646
  const headers = await client.buildHeaders();
13646
- const url = `${SMARTLIST_BASE}${path14}`;
13647
+ const url = `${SMARTLIST_BASE}${path15}`;
13647
13648
  const options = { method, headers };
13648
13649
  if (body && (method === "POST" || method === "PUT")) {
13649
13650
  options.body = JSON.stringify(body);
@@ -13651,7 +13652,7 @@ function registerSmartListTools(server2, builderClient) {
13651
13652
  const response = await fetch(url, options);
13652
13653
  if (!response.ok) {
13653
13654
  const text2 = await response.text();
13654
- throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path14}
13655
+ throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path15}
13655
13656
  ${text2}`);
13656
13657
  }
13657
13658
  const text = await response.text();
@@ -13783,12 +13784,12 @@ var REPUTATION_BASE = "https://backend.leadconnectorhq.com/reputation";
13783
13784
  function registerReputationTools(server2, builderClient) {
13784
13785
  const client = builderClient;
13785
13786
  if (!client) return;
13786
- async function reputationRequest(method, path14) {
13787
+ async function reputationRequest(method, path15) {
13787
13788
  const headers = await client.buildHeaders();
13788
- const response = await fetch(`${REPUTATION_BASE}${path14}`, { method, headers });
13789
+ const response = await fetch(`${REPUTATION_BASE}${path15}`, { method, headers });
13789
13790
  if (!response.ok) {
13790
13791
  const text2 = await response.text();
13791
- throw new Error(`Reputation API Error ${response.status}: ${method} ${path14}
13792
+ throw new Error(`Reputation API Error ${response.status}: ${method} ${path15}
13792
13793
  ${text2}`);
13793
13794
  }
13794
13795
  const text = await response.text();
@@ -13903,16 +13904,16 @@ var MEMBERSHIP_BASE = "https://backend.leadconnectorhq.com/membership";
13903
13904
  function registerMembershipTools(server2, builderClient) {
13904
13905
  const client = builderClient;
13905
13906
  if (!client) return;
13906
- async function membershipRequest(path14, method = "GET", body) {
13907
+ async function membershipRequest(path15, method = "GET", body) {
13907
13908
  const headers = await client.buildHeaders();
13908
- const response = await fetch(`${MEMBERSHIP_BASE}${path14}`, {
13909
+ const response = await fetch(`${MEMBERSHIP_BASE}${path15}`, {
13909
13910
  method,
13910
13911
  headers,
13911
13912
  body: body ? JSON.stringify(body) : void 0
13912
13913
  });
13913
13914
  if (!response.ok) {
13914
13915
  const text2 = await response.text();
13915
- throw new Error(`Membership API Error ${response.status}: ${method} ${path14}
13916
+ throw new Error(`Membership API Error ${response.status}: ${method} ${path15}
13916
13917
  ${text2}`);
13917
13918
  }
13918
13919
  const text = await response.text();
@@ -14081,7 +14082,7 @@ var import_zod52 = require("zod");
14081
14082
  var fs7 = __toESM(require("fs"));
14082
14083
  var path6 = __toESM(require("path"));
14083
14084
  function delay3(ms) {
14084
- return new Promise((resolve7) => setTimeout(resolve7, ms));
14085
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
14085
14086
  }
14086
14087
  var TemplateSchema = import_zod52.z.object({
14087
14088
  templateName: import_zod52.z.string(),
@@ -14225,7 +14226,7 @@ function registerTemplateDeployerTools(server2, client) {
14225
14226
  const locId = client.resolveLocationId(locationId2);
14226
14227
  const safePath = validateTemplatePath(templateFile);
14227
14228
  const template = TemplateSchema.parse(JSON.parse(fs7.readFileSync(safePath, "utf-8")));
14228
- const resolve7 = (text) => {
14229
+ const resolve8 = (text) => {
14229
14230
  if (typeof text !== "string") return text;
14230
14231
  let result = text;
14231
14232
  for (const [key, value] of Object.entries(answers)) {
@@ -14238,7 +14239,7 @@ function registerTemplateDeployerTools(server2, client) {
14238
14239
  return result;
14239
14240
  };
14240
14241
  const resolveObj = (obj) => {
14241
- if (typeof obj === "string") return resolve7(obj);
14242
+ if (typeof obj === "string") return resolve8(obj);
14242
14243
  if (Array.isArray(obj)) return obj.map(resolveObj);
14243
14244
  if (obj && typeof obj === "object") {
14244
14245
  const result = {};
@@ -15239,6 +15240,57 @@ function registerDiagnosticTools(server2, installedVersion, client, builderClien
15239
15240
  );
15240
15241
  }
15241
15242
 
15243
+ // src/tools/user-guide.ts
15244
+ var import_child_process2 = require("child_process");
15245
+ var fs8 = __toESM(require("fs"));
15246
+ var path7 = __toESM(require("path"));
15247
+ function resolveGuidePath() {
15248
+ const bundled = path7.resolve(__dirname, "..", "guide", "guide.html");
15249
+ if (fs8.existsSync(bundled)) return bundled;
15250
+ const devRoot = path7.resolve(__dirname, "..", "..");
15251
+ try {
15252
+ const pkg2 = JSON.parse(fs8.readFileSync(path7.join(devRoot, "package.json"), "utf8"));
15253
+ if (pkg2.name === "@elitedcs/ghl-mcp") {
15254
+ const dev = path7.join(devRoot, "guide", "guide.html");
15255
+ if (fs8.existsSync(dev)) return dev;
15256
+ }
15257
+ } catch {
15258
+ }
15259
+ return bundled;
15260
+ }
15261
+ function registerUserGuideTools(server2) {
15262
+ server2.tool(
15263
+ "get_user_guide",
15264
+ "Open the GHL Command user guide in your browser \u2014 the full library of plain-English guides with copy-paste prompts (count and report contacts, build a nurture sequence, audit workflows, and more). Ships with every install, free or paid, and updates with the product. Always returns the guide's file path so it can be opened manually if no browser window appears.",
15265
+ {},
15266
+ async () => {
15267
+ const guidePath = resolveGuidePath();
15268
+ if (!fs8.existsSync(guidePath)) {
15269
+ return {
15270
+ content: [{
15271
+ type: "text",
15272
+ text: `The bundled user guide is missing (expected at ${guidePath}). Installed copies always include it \u2014 a reinstall restores it: npx -y @elitedcs/ghl-mcp cli install. In a development checkout, render it with: node scripts/build-guides.mjs`
15273
+ }]
15274
+ };
15275
+ }
15276
+ let launched = false;
15277
+ try {
15278
+ const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
15279
+ const args = process.platform === "win32" ? ["/c", "start", "", guidePath] : [guidePath];
15280
+ (0, import_child_process2.spawn)(opener, args, { stdio: "ignore", detached: true }).unref();
15281
+ launched = true;
15282
+ } catch {
15283
+ }
15284
+ const text = launched ? `Opened the GHL Command user guide in your browser.
15285
+
15286
+ If a tab didn't appear, open this file directly:
15287
+ ${guidePath}` : `Could not launch a browser automatically. Open this file directly:
15288
+ ${guidePath}`;
15289
+ return { content: [{ type: "text", text }] };
15290
+ }
15291
+ );
15292
+ }
15293
+
15242
15294
  // src/tools/snapshots.ts
15243
15295
  var import_zod54 = require("zod");
15244
15296
  init_ghl_client();
@@ -15921,9 +15973,9 @@ function presetForBusinessType(type) {
15921
15973
  return "generic";
15922
15974
  }
15923
15975
  }
15924
- function setPath(target, path14, value) {
15976
+ function setPath(target, path15, value) {
15925
15977
  if (value === void 0) return;
15926
- const parts = path14.split(".");
15978
+ const parts = path15.split(".");
15927
15979
  let node = target;
15928
15980
  for (let i = 0; i < parts.length - 1; i++) {
15929
15981
  const k = parts[i];
@@ -18009,15 +18061,15 @@ function extractFunnelId(result) {
18009
18061
  return void 0;
18010
18062
  }
18011
18063
  function makeExecuteDeps(client, builderClient, locationId2) {
18012
- const pipelineApi = async (method, path14, body) => {
18064
+ const pipelineApi = async (method, path15, body) => {
18013
18065
  const headers = await builderClient.buildHeaders();
18014
- const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path14}`;
18066
+ const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path15}`;
18015
18067
  const options = { method, headers };
18016
18068
  if (body && (method === "POST" || method === "PUT")) options.body = JSON.stringify(body);
18017
18069
  const response = await fetch(url, options);
18018
18070
  if (!response.ok) {
18019
18071
  const text2 = await response.text();
18020
- throw new Error(`Pipeline API ${response.status}: ${method} ${path14}
18072
+ throw new Error(`Pipeline API ${response.status}: ${method} ${path15}
18021
18073
  ${text2.slice(0, 300)}`);
18022
18074
  }
18023
18075
  const text = await response.text();
@@ -18028,17 +18080,17 @@ ${text2.slice(0, 300)}`);
18028
18080
  return JSON.parse(text.replace(/[\x00-\x1F\x7F]/g, ""));
18029
18081
  }
18030
18082
  };
18031
- const funnelApi = async (method, path14, body) => {
18083
+ const funnelApi = async (method, path15, body) => {
18032
18084
  const headers = await builderClient.buildHeaders();
18033
18085
  headers.Origin = "https://app.gohighlevel.com";
18034
18086
  headers.Referer = "https://app.gohighlevel.com/";
18035
- const url = `https://backend.leadconnectorhq.com/funnels${path14}`;
18087
+ const url = `https://backend.leadconnectorhq.com/funnels${path15}`;
18036
18088
  const options = { method, headers };
18037
18089
  if (body && (method === "POST" || method === "PUT")) options.body = JSON.stringify(body);
18038
18090
  const response = await fetch(url, options);
18039
18091
  if (!response.ok) {
18040
18092
  const text2 = await response.text();
18041
- throw new Error(`Funnel API ${response.status}: ${method} ${path14}
18093
+ throw new Error(`Funnel API ${response.status}: ${method} ${path15}
18042
18094
  ${text2.slice(0, 300)}`);
18043
18095
  }
18044
18096
  const text = await response.text();
@@ -18689,12 +18741,14 @@ var SNAPSHOTS_MODULE = "snapshots";
18689
18741
  var FORM_BUILDER_MODULE = "form-builder";
18690
18742
  var INTAKE_TO_BUILD_MODULE = "intake-to-build";
18691
18743
  var FUNNEL_QA_MODULE = "funnel-qa";
18744
+ var USER_GUIDE_MODULE = "user-guide";
18692
18745
  var KNOWN_MODULES = /* @__PURE__ */ new Set([
18693
18746
  ...publicApiTools.map(([, label]) => label),
18694
18747
  ...internalApiTools.map(([, label]) => label),
18695
18748
  FORM_BUILDER_MODULE,
18696
18749
  INTAKE_TO_BUILD_MODULE,
18697
18750
  FUNNEL_QA_MODULE,
18751
+ USER_GUIDE_MODULE,
18698
18752
  VALIDATORS_MODULE,
18699
18753
  DIAGNOSTICS_MODULE,
18700
18754
  LOCATION_SWITCHER_MODULE,
@@ -18716,6 +18770,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env = process.
18716
18770
  registerFormBuilderTools(wrap(FORM_BUILDER_MODULE), builderClient, client);
18717
18771
  registerIntakeToBuildTools(wrap(INTAKE_TO_BUILD_MODULE), client, builderClient);
18718
18772
  registerFunnelQaTools(wrap(FUNNEL_QA_MODULE), client, builderClient);
18773
+ registerUserGuideTools(wrap(USER_GUIDE_MODULE));
18719
18774
  registerValidatorTools(wrap(VALIDATORS_MODULE), client, builderClient);
18720
18775
  registerDiagnosticTools(
18721
18776
  wrap(DIAGNOSTICS_MODULE),
@@ -18778,16 +18833,16 @@ var import_zod60 = require("zod");
18778
18833
 
18779
18834
  // src/skill-installer.ts
18780
18835
  var import_node_crypto2 = require("node:crypto");
18781
- var fs8 = __toESM(require("node:fs"));
18782
- var path7 = __toESM(require("node:path"));
18836
+ var fs9 = __toESM(require("node:fs"));
18837
+ var path8 = __toESM(require("node:path"));
18783
18838
  var os3 = __toESM(require("node:os"));
18784
18839
  function sha256(buf) {
18785
18840
  return (0, import_node_crypto2.createHash)("sha256").update(buf).digest("hex");
18786
18841
  }
18787
18842
  function bundledSkillsDir(baseDir) {
18788
- const candidate = path7.resolve(baseDir, "..", "skills");
18843
+ const candidate = path8.resolve(baseDir, "..", "skills");
18789
18844
  try {
18790
- return fs8.statSync(candidate).isDirectory() ? candidate : null;
18845
+ return fs9.statSync(candidate).isDirectory() ? candidate : null;
18791
18846
  } catch {
18792
18847
  return null;
18793
18848
  }
@@ -18795,10 +18850,10 @@ function bundledSkillsDir(baseDir) {
18795
18850
  function listFiles(root) {
18796
18851
  const out = [];
18797
18852
  const walk = (dir) => {
18798
- for (const entry of fs8.readdirSync(dir, { withFileTypes: true })) {
18799
- const full = path7.join(dir, entry.name);
18853
+ for (const entry of fs9.readdirSync(dir, { withFileTypes: true })) {
18854
+ const full = path8.join(dir, entry.name);
18800
18855
  if (entry.isDirectory()) walk(full);
18801
- else if (entry.isFile()) out.push(path7.relative(root, full));
18856
+ else if (entry.isFile()) out.push(path8.relative(root, full));
18802
18857
  }
18803
18858
  };
18804
18859
  walk(root);
@@ -18806,7 +18861,7 @@ function listFiles(root) {
18806
18861
  }
18807
18862
  function readMarker(markerPath) {
18808
18863
  try {
18809
- const parsed = JSON.parse(fs8.readFileSync(markerPath, "utf8"));
18864
+ const parsed = JSON.parse(fs9.readFileSync(markerPath, "utf8"));
18810
18865
  return parsed && typeof parsed === "object" && parsed.files ? parsed : null;
18811
18866
  } catch {
18812
18867
  return null;
@@ -18819,35 +18874,35 @@ function installBundledSkills(opts) {
18819
18874
  skippedUserModified: [],
18820
18875
  unchanged: [],
18821
18876
  errors: [],
18822
- targetDir: opts.targetDir ?? path7.join(os3.homedir(), ".claude", "skills"),
18877
+ targetDir: opts.targetDir ?? path8.join(os3.homedir(), ".claude", "skills"),
18823
18878
  bundledDir: null
18824
18879
  };
18825
18880
  const bundled = bundledSkillsDir(opts.baseDir);
18826
18881
  result.bundledDir = bundled;
18827
18882
  if (!bundled) return result;
18828
18883
  try {
18829
- fs8.mkdirSync(result.targetDir, { recursive: true });
18884
+ fs9.mkdirSync(result.targetDir, { recursive: true });
18830
18885
  } catch (e) {
18831
18886
  result.errors.push(`cannot create ${result.targetDir}: ${String(e)}`);
18832
18887
  return result;
18833
18888
  }
18834
- const markerPath = path7.join(result.targetDir, ".ghl-command-skills.json");
18889
+ const markerPath = path8.join(result.targetDir, ".ghl-command-skills.json");
18835
18890
  const marker = readMarker(markerPath) ?? { packageVersion: "", files: {} };
18836
18891
  const newMarker = { packageVersion: opts.packageVersion, files: { ...marker.files } };
18837
18892
  for (const rel of listFiles(bundled)) {
18838
18893
  try {
18839
- const src = fs8.readFileSync(path7.join(bundled, rel));
18840
- const dest = path7.join(result.targetDir, rel);
18894
+ const src = fs9.readFileSync(path8.join(bundled, rel));
18895
+ const dest = path8.join(result.targetDir, rel);
18841
18896
  const srcHash = sha256(src);
18842
18897
  let destBuf = null;
18843
18898
  try {
18844
- destBuf = fs8.readFileSync(dest);
18899
+ destBuf = fs9.readFileSync(dest);
18845
18900
  } catch {
18846
18901
  destBuf = null;
18847
18902
  }
18848
18903
  if (destBuf === null) {
18849
- fs8.mkdirSync(path7.dirname(dest), { recursive: true });
18850
- fs8.writeFileSync(dest, src);
18904
+ fs9.mkdirSync(path8.dirname(dest), { recursive: true });
18905
+ fs9.writeFileSync(dest, src);
18851
18906
  newMarker.files[rel] = srcHash;
18852
18907
  result.installed.push(rel);
18853
18908
  continue;
@@ -18860,7 +18915,7 @@ function installBundledSkills(opts) {
18860
18915
  }
18861
18916
  const lastWritten = marker.files[rel];
18862
18917
  if (lastWritten && destHash === lastWritten) {
18863
- fs8.writeFileSync(dest, src);
18918
+ fs9.writeFileSync(dest, src);
18864
18919
  newMarker.files[rel] = srcHash;
18865
18920
  result.updated.push(rel);
18866
18921
  } else {
@@ -18871,7 +18926,7 @@ function installBundledSkills(opts) {
18871
18926
  }
18872
18927
  }
18873
18928
  try {
18874
- fs8.writeFileSync(markerPath, JSON.stringify(newMarker, null, 2));
18929
+ fs9.writeFileSync(markerPath, JSON.stringify(newMarker, null, 2));
18875
18930
  } catch (e) {
18876
18931
  result.errors.push(`marker write failed: ${String(e)}`);
18877
18932
  }
@@ -18956,8 +19011,8 @@ function registerMetaTools(server2, installedVersion) {
18956
19011
 
18957
19012
  // src/cli.ts
18958
19013
  var import_node_util2 = require("node:util");
18959
- var fs10 = __toESM(require("fs"));
18960
- var path9 = __toESM(require("path"));
19014
+ var fs11 = __toESM(require("fs"));
19015
+ var path10 = __toESM(require("path"));
18961
19016
  var import_crypto2 = require("crypto");
18962
19017
  init_ghl_client();
18963
19018
  init_token_registry();
@@ -19008,9 +19063,9 @@ function errLine(msg2) {
19008
19063
  function preflightWritable() {
19009
19064
  try {
19010
19065
  const dir = ensureAppDataDir();
19011
- const probe = path9.join(dir, `.write-probe.${process.pid}.${(0, import_crypto2.randomBytes)(4).toString("hex")}`);
19012
- fs10.writeFileSync(probe, "ok");
19013
- fs10.unlinkSync(probe);
19066
+ const probe = path10.join(dir, `.write-probe.${process.pid}.${(0, import_crypto2.randomBytes)(4).toString("hex")}`);
19067
+ fs11.writeFileSync(probe, "ok");
19068
+ fs11.unlinkSync(probe);
19014
19069
  return true;
19015
19070
  } catch (error) {
19016
19071
  errLine(`Config dir is not writable: ${error instanceof Error ? error.message : String(error)}`);
@@ -19264,7 +19319,7 @@ var bundledPkg = require_package();
19264
19319
  var pkg = (() => {
19265
19320
  try {
19266
19321
  const onDisk = JSON.parse(
19267
- fs14.readFileSync(path13.resolve(__dirname, "..", "package.json"), "utf8")
19322
+ fs15.readFileSync(path14.resolve(__dirname, "..", "package.json"), "utf8")
19268
19323
  );
19269
19324
  if (typeof onDisk.version === "string" && onDisk.version.length > 0) {
19270
19325
  return { version: onDisk.version };
@@ -19277,7 +19332,7 @@ dotenv2.config();
19277
19332
  setPkgVersion(pkg.version);
19278
19333
  {
19279
19334
  const configDirOverride = process.env.GHL_MCP_CONFIG_DIR?.trim();
19280
- if (configDirOverride && !path13.isAbsolute(configDirOverride)) {
19335
+ if (configDirOverride && !path14.isAbsolute(configDirOverride)) {
19281
19336
  process.stderr.write(
19282
19337
  `[ghl-mcp] GHL_MCP_CONFIG_DIR must be an absolute path (got "${configDirOverride}"). Use e.g. /data/ghl-mcp in a container, with a volume mounted at /data.
19283
19338
  `
@@ -19290,20 +19345,20 @@ process.on("unhandledRejection", (reason) => {
19290
19345
  `);
19291
19346
  });
19292
19347
  function hardenSecretFilePerms() {
19293
- const repoDir = path13.resolve(__dirname, "..");
19348
+ const repoDir = path14.resolve(__dirname, "..");
19294
19349
  const candidates = [
19295
- { file: path13.join(repoDir, "start-mcp.sh"), mode: 448 },
19350
+ { file: path14.join(repoDir, "start-mcp.sh"), mode: 448 },
19296
19351
  // Legacy registry location (pre-migration); new location lives in app-data.
19297
- { file: path13.join(repoDir, ".ghl-tokens.json"), mode: 384 },
19352
+ { file: path14.join(repoDir, ".ghl-tokens.json"), mode: 384 },
19298
19353
  { file: tokenRegistryPath(), mode: 384 }
19299
19354
  ];
19300
19355
  for (const { file, mode } of candidates) {
19301
19356
  let current;
19302
19357
  try {
19303
- if (!fs14.existsSync(file)) continue;
19304
- current = fs14.statSync(file).mode & 511;
19358
+ if (!fs15.existsSync(file)) continue;
19359
+ current = fs15.statSync(file).mode & 511;
19305
19360
  if (current !== mode) {
19306
- fs14.chmodSync(file, mode);
19361
+ fs15.chmodSync(file, mode);
19307
19362
  }
19308
19363
  } catch (error) {
19309
19364
  const message = error instanceof Error ? error.message : String(error);