@elitedcs/ghl-mcp 3.84.5 → 3.84.7

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
@@ -446,18 +446,18 @@ function setProtectedAccount(locationId2, name, file2 = accountRulesPath()) {
446
446
  function isWriteMethod(method) {
447
447
  return WRITE_METHODS.has(method.toUpperCase());
448
448
  }
449
- function locationIdsInRequest(path42, opts = {}) {
449
+ function locationIdsInRequest(path41, opts = {}) {
450
450
  const found = /* @__PURE__ */ new Set();
451
- const add = (v) => {
451
+ const add2 = (v) => {
452
452
  if (typeof v === "string" && v.trim()) found.add(v.trim());
453
- else if (Array.isArray(v)) v.forEach(add);
453
+ else if (Array.isArray(v)) v.forEach(add2);
454
454
  };
455
- const seg = /\/locations\/([^/?#]+)/i.exec(path42);
456
- if (seg) add(decodeURIComponent(seg[1]));
455
+ const seg = /\/locations\/([^/?#]+)/i.exec(path41);
456
+ if (seg) add2(decodeURIComponent(seg[1]));
457
457
  for (const src of [opts.params, opts.body]) {
458
458
  if (!src || typeof src !== "object") continue;
459
459
  for (const key of ["locationId", "location_id", "locationIds", "location_ids", "targetLocationId"]) {
460
- add(src[key]);
460
+ add2(src[key]);
461
461
  }
462
462
  }
463
463
  return [...found];
@@ -479,7 +479,7 @@ function protectedRefusalFor(locationId2, rulesFile) {
479
479
  const name = rules.protected[id];
480
480
  return name ? protectedRefusalMessage(name, false) : null;
481
481
  }
482
- function assertWriteAllowed(method, path42, opts = {}) {
482
+ function assertWriteAllowed(method, path41, opts = {}) {
483
483
  if (!isWriteMethod(method)) return;
484
484
  let rules;
485
485
  try {
@@ -488,7 +488,7 @@ function assertWriteAllowed(method, path42, opts = {}) {
488
488
  throw new Error(UNREADABLE_RULES_MSG);
489
489
  }
490
490
  if (Object.keys(rules.protected).length === 0) return;
491
- for (const id of locationIdsInRequest(path42, opts)) {
491
+ for (const id of locationIdsInRequest(path41, opts)) {
492
492
  const name = rules.protected[id];
493
493
  if (name) throw new Error(protectedRefusalMessage(name, false));
494
494
  }
@@ -646,8 +646,8 @@ var init_ghl_client = __esm({
646
646
  Version: version || GHL_API_VERSION
647
647
  };
648
648
  }
649
- buildUrl(path42, params) {
650
- const url = new URL(path42, GHL_BASE_URL);
649
+ buildUrl(path41, params) {
650
+ const url = new URL(path41, GHL_BASE_URL);
651
651
  if (params) {
652
652
  for (const [key, value] of Object.entries(params)) {
653
653
  if (value !== void 0 && value !== null) {
@@ -657,19 +657,19 @@ var init_ghl_client = __esm({
657
657
  }
658
658
  return url.toString();
659
659
  }
660
- async request(method, path42, options = {}, attempt = 0) {
660
+ async request(method, path41, options = {}, attempt = 0) {
661
661
  this.signal?.throwIfAborted();
662
662
  if (inBuildRequestScope() && method === "GET" && !inAccountReadAttempt()) {
663
- return retryAccountRead(() => this.request(method, path42, options, attempt), `${method} ${path42}`);
663
+ return retryAccountRead(() => this.request(method, path41, options, attempt), `${method} ${path41}`);
664
664
  }
665
665
  if (attempt === 0) {
666
- assertWriteAllowed(method, path42, {
666
+ assertWriteAllowed(method, path41, {
667
667
  params: options.params,
668
668
  body: options.body,
669
669
  defaultLocationId: this.defaultLocationId
670
670
  });
671
671
  }
672
- const url = this.buildUrl(path42, options.params);
672
+ const url = this.buildUrl(path41, options.params);
673
673
  const headers = this.buildHeaders(options.version);
674
674
  const fetchOptions = {
675
675
  method,
@@ -690,14 +690,14 @@ var init_ghl_client = __esm({
690
690
  clearTimeout(timeout);
691
691
  this.signal?.throwIfAborted();
692
692
  if (error instanceof Error && error.name === "AbortError") {
693
- throw requestError(new Error(`Request timeout (30s): ${method} ${path42}`));
693
+ throw requestError(new Error(`Request timeout (30s): ${method} ${path41}`));
694
694
  }
695
695
  if (!inBuildRequestScope() && !options.noRetry && attempt < MAX_RETRIES) {
696
696
  const delay5 = computeRetryDelay(null, attempt, BASE_DELAY_MS);
697
- process.stderr.write(`[ghl-mcp] Network error on ${method} ${path42}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay5}ms
697
+ process.stderr.write(`[ghl-mcp] Network error on ${method} ${path41}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay5}ms
698
698
  `);
699
699
  await new Promise((r) => setTimeout(r, delay5));
700
- return this.request(method, path42, options, attempt + 1);
700
+ return this.request(method, path41, options, attempt + 1);
701
701
  }
702
702
  throw requestError(error);
703
703
  } finally {
@@ -705,10 +705,10 @@ var init_ghl_client = __esm({
705
705
  }
706
706
  if (!inBuildRequestScope() && !options.noRetry && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {
707
707
  const delay5 = computeRetryDelay(response.headers.get("Retry-After"), attempt, BASE_DELAY_MS);
708
- process.stderr.write(`[ghl-mcp] ${response.status} on ${method} ${path42}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay5}ms
708
+ process.stderr.write(`[ghl-mcp] ${response.status} on ${method} ${path41}, retry ${attempt + 1}/${MAX_RETRIES} in ${delay5}ms
709
709
  `);
710
710
  await new Promise((r) => setTimeout(r, delay5));
711
- return this.request(method, path42, options, attempt + 1);
711
+ return this.request(method, path41, options, attempt + 1);
712
712
  }
713
713
  if (!response.ok) {
714
714
  let errorBody = "";
@@ -717,7 +717,7 @@ var init_ghl_client = __esm({
717
717
  } catch {
718
718
  }
719
719
  throw requestError(new Error(
720
- `GHL API Error ${response.status} ${response.statusText}: ${method} ${path42}
720
+ `GHL API Error ${response.status} ${response.statusText}: ${method} ${path41}
721
721
  ${errorBody}`
722
722
  ));
723
723
  }
@@ -738,20 +738,20 @@ ${errorBody}`
738
738
  combined?.dispose();
739
739
  }
740
740
  }
741
- async get(path42, options) {
742
- return this.request("GET", path42, options);
741
+ async get(path41, options) {
742
+ return this.request("GET", path41, options);
743
743
  }
744
- async post(path42, options) {
745
- return this.request("POST", path42, options);
744
+ async post(path41, options) {
745
+ return this.request("POST", path41, options);
746
746
  }
747
- async put(path42, options) {
748
- return this.request("PUT", path42, options);
747
+ async put(path41, options) {
748
+ return this.request("PUT", path41, options);
749
749
  }
750
- async patch(path42, options) {
751
- return this.request("PATCH", path42, options);
750
+ async patch(path41, options) {
751
+ return this.request("PATCH", path41, options);
752
752
  }
753
- async delete(path42, options) {
754
- return this.request("DELETE", path42, options);
753
+ async delete(path41, options) {
754
+ return this.request("DELETE", path41, options);
755
755
  }
756
756
  /**
757
757
  * Helper: resolves locationId from args or falls back to default
@@ -3436,8 +3436,6 @@ var init_tool_filter = __esm({
3436
3436
  "attach_assessment",
3437
3437
  // source GETs plus local card and intake drafts only
3438
3438
  "set_income_source",
3439
- "record_brief_answers",
3440
- // local chat rows only; no account/provider writes
3441
3439
  "connect_system",
3442
3440
  "disconnect_system"
3443
3441
  ]);
@@ -7107,11 +7105,11 @@ function registerEmailTools(server2, client) {
7107
7105
  function registerEmailBuilderInternalTools(server2, builderClient, publicClient) {
7108
7106
  if (!builderClient) return;
7109
7107
  const client = builderClient;
7110
- async function builderRequest2(method, path42, body) {
7111
- const response = await builderRequest(client, method, `${EMAIL_BUILDER_BASE}${path42}`, body ? { body } : {});
7108
+ async function builderRequest2(method, path41, body) {
7109
+ const response = await builderRequest(client, method, `${EMAIL_BUILDER_BASE}${path41}`, body ? { body } : {});
7112
7110
  if (!response.ok) {
7113
7111
  const text3 = await response.text();
7114
- throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path42}
7112
+ throw new Error(`Email Builder API Error ${response.status}: ${method} /emails/builder${path41}
7115
7113
  ${text3}`);
7116
7114
  }
7117
7115
  const text2 = await response.text();
@@ -10921,11 +10919,11 @@ async function readPageFull(client, pageId, fetcher = fetch) {
10921
10919
  const headers = await client.buildHeaders();
10922
10920
  headers.Origin = "https://app.gohighlevel.com";
10923
10921
  headers.Referer = "https://app.gohighlevel.com/";
10924
- const path42 = `/page/${pageId}?locationId=${client.locationId}`;
10925
- const response = await fetcher(`https://backend.leadconnectorhq.com/funnels${path42}`, { method: "GET", headers });
10922
+ const path41 = `/page/${pageId}?locationId=${client.locationId}`;
10923
+ const response = await fetcher(`https://backend.leadconnectorhq.com/funnels${path41}`, { method: "GET", headers });
10926
10924
  if (!response.ok) {
10927
10925
  const text3 = await response.text();
10928
- throw new Error(`Funnel API Error ${response.status}: GET ${path42}
10926
+ throw new Error(`Funnel API Error ${response.status}: GET ${path41}
10929
10927
  ${text3}`);
10930
10928
  }
10931
10929
  const text2 = await response.text();
@@ -10984,20 +10982,20 @@ function registerFunnelBuilderTools(server2, builderClient) {
10984
10982
  return;
10985
10983
  }
10986
10984
  const client = builderClient;
10987
- async function internalGet(path42) {
10988
- return client.request("GET", path42);
10985
+ async function internalGet(path41) {
10986
+ return client.request("GET", path41);
10989
10987
  }
10990
- async function internalPost(path42, body) {
10991
- return client.request("POST", path42, body);
10988
+ async function internalPost(path41, body) {
10989
+ return client.request("POST", path41, body);
10992
10990
  }
10993
- async function internalPut(path42, body) {
10994
- return client.request("PUT", path42, body);
10991
+ async function internalPut(path41, body) {
10992
+ return client.request("PUT", path41, body);
10995
10993
  }
10996
- async function internalDelete(path42) {
10997
- return client.request("DELETE", path42);
10994
+ async function internalDelete(path41) {
10995
+ return client.request("DELETE", path41);
10998
10996
  }
10999
- async function funnelRequest(method, path42, body) {
11000
- const url = `https://backend.leadconnectorhq.com/funnels${path42}`;
10997
+ async function funnelRequest(method, path41, body) {
10998
+ const url = `https://backend.leadconnectorhq.com/funnels${path41}`;
11001
10999
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
11002
11000
  const response = await builderRequest(client, method, url, {
11003
11001
  ...sendsBody ? { body } : {},
@@ -11010,7 +11008,7 @@ function registerFunnelBuilderTools(server2, builderClient) {
11010
11008
  });
11011
11009
  if (!response.ok) {
11012
11010
  const text3 = await response.text();
11013
- throw new Error(`Funnel API Error ${response.status}: ${method} ${path42}
11011
+ throw new Error(`Funnel API Error ${response.status}: ${method} ${path41}
11014
11012
  ${text3}`);
11015
11013
  }
11016
11014
  const text2 = await response.text();
@@ -11601,17 +11599,17 @@ function requireCompany(api) {
11601
11599
  }
11602
11600
  return company;
11603
11601
  }
11604
- async function call(api, path42, init) {
11602
+ async function call(api, path41, init) {
11605
11603
  const headers = { ...await api.headers(), Origin: "https://app.gohighlevel.com", Referer: "https://app.gohighlevel.com/" };
11606
- if (MUTATING_PATHS.some((mutating) => path42.startsWith(mutating))) {
11607
- assertWriteAllowed("POST", SVC + path42, { defaultLocationId: api.locationId() });
11604
+ if (MUTATING_PATHS.some((mutating) => path41.startsWith(mutating))) {
11605
+ assertWriteAllowed("POST", SVC + path41, { defaultLocationId: api.locationId() });
11608
11606
  }
11609
11607
  const doFetch = api.fetch ?? fetch;
11610
- const response = await doFetch(SVC + path42, { ...init, headers });
11608
+ const response = await doFetch(SVC + path41, { ...init, headers });
11611
11609
  const text2 = await response.text();
11612
11610
  if (!response.ok) {
11613
11611
  const hint = response.status === 401 && /not authorized to access this company/i.test(text2) ? " \u2014 the Firebase session is authenticated as a DIFFERENT company than the one that owns this sub-account. Run switch_location for this sub-account and try again." : response.status === 401 ? " \u2014 the template library needs the workflow-builder Firebase session, not the API key alone. Run enable_workflow_builder for this sub-account." : "";
11614
- throw new Error(`GoHighLevel template library ${response.status} on ${path42}${hint}
11612
+ throw new Error(`GoHighLevel template library ${response.status} on ${path41}${hint}
11615
11613
  ${text2.slice(0, 300)}`);
11616
11614
  }
11617
11615
  return text2 ? JSON.parse(text2) : {};
@@ -11968,12 +11966,12 @@ function normaliseColour(value) {
11968
11966
  function renderedPalette(envelope) {
11969
11967
  const defs = pageVariables(envelope);
11970
11968
  const paints = [];
11971
- const walk = (node, path42, prop) => {
11972
- if (Array.isArray(node)) return void node.forEach((x, i) => walk(x, `${path42}[${i}]`, prop));
11969
+ const walk = (node, path41, prop) => {
11970
+ if (Array.isArray(node)) return void node.forEach((x, i) => walk(x, `${path41}[${i}]`, prop));
11973
11971
  if (isRecord8(node)) {
11974
11972
  for (const [k, x] of Object.entries(node)) {
11975
11973
  if (DEFINITION_KEYS.has(k) || k.startsWith("--")) continue;
11976
- walk(x, `${path42}.${k}`, WRAPPER_KEYS.has(k) ? prop : k);
11974
+ walk(x, `${path41}.${k}`, WRAPPER_KEYS.has(k) ? prop : k);
11977
11975
  }
11978
11976
  return;
11979
11977
  }
@@ -11983,7 +11981,7 @@ function renderedPalette(envelope) {
11983
11981
  const resolved2 = resolveValue(raw, defs);
11984
11982
  const colour = normaliseColour(resolved2);
11985
11983
  if (colour === null && resolved2 !== null) return;
11986
- paints.push({ path: path42, prop, kind: kindOf(prop), colour });
11984
+ paints.push({ path: path41, prop, kind: kindOf(prop), colour });
11987
11985
  };
11988
11986
  walk(envelope, "", "");
11989
11987
  const face = (name, settingsKey) => {
@@ -12078,7 +12076,7 @@ var init_rendered_palette = __esm({
12078
12076
  VISIBLE_CHANGE = 0.05;
12079
12077
  BARELY_SHARE = 0.5;
12080
12078
  CARRIES_COLOUR = 0.02;
12081
- paintGroup = (path42) => /^\.(sections|popups)\[\d+\]/.exec(path42)?.[0]?.slice(1) ?? "page";
12079
+ paintGroup = (path41) => /^\.(sections|popups)\[\d+\]/.exec(path41)?.[0]?.slice(1) ?? "page";
12082
12080
  looksDifferent = (a, b) => {
12083
12081
  if (a === b) return false;
12084
12082
  if (a === "transparent" || b === "transparent" || a.startsWith("rgba") || b.startsWith("rgba")) return a !== b;
@@ -16653,9 +16651,9 @@ function removalHoldBack(opts) {
16653
16651
  if (opts.multiPageStepNames.length > 0) return `${opts.multiPageStepNames.length} step(s) carry more than one page (${opts.multiPageStepNames.join(", ")}) and only the first of each was rebuilt`;
16654
16652
  return null;
16655
16653
  }
16656
- function brandedPath(path42, name, taken) {
16654
+ function brandedPath(path41, name, taken) {
16657
16655
  const normalize = (s) => s.replace(/^\/+|\/+$/g, "").toLowerCase();
16658
- const base = normalize(path42 ?? "") || name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "page";
16656
+ const base = normalize(path41 ?? "") || name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "page";
16659
16657
  const used = new Set([...taken].map(normalize));
16660
16658
  let candidate = `${base}-branded`;
16661
16659
  for (let n = 2; used.has(candidate); n++) candidate = `${base}-branded-${n}`;
@@ -16683,9 +16681,9 @@ function rewriteTemplateLinks(envelope, destinations) {
16683
16681
  representation = "page";
16684
16682
  matches = destinations.filter((d2) => d2.pageId === preview[2]);
16685
16683
  } else if (!/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(from) && !from.startsWith("#")) {
16686
- const [path42] = from.split(/[?#]/);
16687
- suffix = from.slice(path42.length);
16688
- matches = destinations.filter((d2) => d2.path && normalize(d2.path) === normalize(path42));
16684
+ const [path41] = from.split(/[?#]/);
16685
+ suffix = from.slice(path41.length);
16686
+ matches = destinations.filter((d2) => d2.path && normalize(d2.path) === normalize(path41));
16689
16687
  }
16690
16688
  }
16691
16689
  if (matches.length !== 1) {
@@ -16768,8 +16766,8 @@ function registerPageStudioTools(server2, builderClient) {
16768
16766
  }
16769
16767
  return { map: out, truncated };
16770
16768
  }
16771
- async function funnelRequest(method, path42, body) {
16772
- const response = await builderRequest(client, method, `https://backend.leadconnectorhq.com/funnels${path42}`, {
16769
+ async function funnelRequest(method, path41, body) {
16770
+ const response = await builderRequest(client, method, `https://backend.leadconnectorhq.com/funnels${path41}`, {
16773
16771
  ...body ? { body } : {},
16774
16772
  headers: {
16775
16773
  // Internal-API calls require the app origin (autosave needs the
@@ -16778,7 +16776,7 @@ function registerPageStudioTools(server2, builderClient) {
16778
16776
  Referer: "https://app.gohighlevel.com/"
16779
16777
  }
16780
16778
  });
16781
- if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path42}
16779
+ if (!response.ok) throw new Error(`Funnel API Error ${response.status}: ${method} ${path41}
16782
16780
  ${await response.text()}`);
16783
16781
  const text2 = await response.text();
16784
16782
  return text2 ? JSON.parse(text2) : {};
@@ -17647,13 +17645,13 @@ function cleanFormDataForSave(formData) {
17647
17645
  const cleaned = dropRedundantCaseCollidingKeys(formData);
17648
17646
  return isJsonObject(cleaned) ? cleaned : formData;
17649
17647
  }
17650
- async function formApiRequest(client, method, path42, body) {
17651
- const url = `https://backend.leadconnectorhq.com/forms${path42}`;
17648
+ async function formApiRequest(client, method, path41, body) {
17649
+ const url = `https://backend.leadconnectorhq.com/forms${path41}`;
17652
17650
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
17653
17651
  const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
17654
17652
  if (!response.ok) {
17655
17653
  const text3 = await response.text();
17656
- throw new Error(`Form API Error ${response.status}: ${method} ${path42}
17654
+ throw new Error(`Form API Error ${response.status}: ${method} ${path41}
17657
17655
  ${text3}`);
17658
17656
  }
17659
17657
  const text2 = await response.text();
@@ -17695,7 +17693,7 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
17695
17693
  );
17696
17694
  return;
17697
17695
  }
17698
- const formRequest = (method, path42, body) => formApiRequest(client, method, path42, body);
17696
+ const formRequest = (method, path41, body) => formApiRequest(client, method, path41, body);
17699
17697
  server2.tool(
17700
17698
  "get_form_full",
17701
17699
  "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 what the form builder UI shows, with one exception: where GoHighLevel stores the same value under two spellings of one key that differ only in case (it writes custom fields with both `Id` and `id`), only the lowercase one is returned. No value is lost, and the result can be edited and passed straight back to update_form.",
@@ -17829,10 +17827,10 @@ function registerFormBuilderTools(server2, builderClient, publicClient) {
17829
17827
  },
17830
17828
  async ({ formId, limit, skip }) => {
17831
17829
  try {
17832
- let path42 = `/submissions?locationId=${client.locationId}&limit=${limit ?? 20}`;
17833
- if (formId) path42 += `&formId=${formId}`;
17834
- if (skip) path42 += `&skip=${skip}`;
17835
- const result = await formRequest("GET", path42);
17830
+ let path41 = `/submissions?locationId=${client.locationId}&limit=${limit ?? 20}`;
17831
+ if (formId) path41 += `&formId=${formId}`;
17832
+ if (skip) path41 += `&skip=${skip}`;
17833
+ const result = await formRequest("GET", path41);
17836
17834
  return {
17837
17835
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
17838
17836
  };
@@ -18240,13 +18238,13 @@ var init_funnel_qa = __esm({
18240
18238
  function registerPipelineBuilderTools(server2, builderClient) {
18241
18239
  if (!builderClient) return;
18242
18240
  const client = builderClient;
18243
- async function pipelineRequest(method, path42, body) {
18244
- const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path42}`;
18241
+ async function pipelineRequest(method, path41, body) {
18242
+ const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path41}`;
18245
18243
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT" || method === "PATCH");
18246
18244
  const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
18247
18245
  if (!response.ok) {
18248
18246
  const text3 = await response.text();
18249
- throw new Error(`Pipeline API Error ${response.status}: ${method} ${path42}
18247
+ throw new Error(`Pipeline API Error ${response.status}: ${method} ${path41}
18250
18248
  ${text3}`);
18251
18249
  }
18252
18250
  const text2 = await response.text();
@@ -20006,56 +20004,17 @@ var init_brief_deadline = __esm({
20006
20004
  }
20007
20005
  });
20008
20006
 
20009
- // src/command-os/connectors/brief-answers.ts
20010
- function readBriefAnswers() {
20011
- try {
20012
- return FileSchema.parse(JSON.parse(fs11.readFileSync(briefAnswersPath(), "utf8")));
20013
- } catch (error) {
20014
- if (error instanceof Error && "code" in error && error.code === "ENOENT") return {};
20015
- throw new Error("The saved chat brief could not be read; nothing was replaced.");
20016
- }
20017
- }
20018
- function recordBriefAnswers(input) {
20019
- const { source, readAt, rows: rows2 } = BriefAnswersInput.parse(input);
20020
- const records = readBriefAnswers();
20021
- records[source] = { readAt, rows: rows2 };
20022
- ensureAppDataDir();
20023
- const tmp = `${briefAnswersPath()}.${(0, import_node_crypto4.randomUUID)()}.tmp`;
20024
- try {
20025
- fs11.writeFileSync(tmp, JSON.stringify(records) + "\n", { mode: 384, flag: "wx" });
20026
- fs11.renameSync(tmp, briefAnswersPath());
20027
- } catch {
20028
- throw new Error("The chat brief could not be saved privately on this machine.");
20029
- } finally {
20030
- try {
20031
- fs11.unlinkSync(tmp);
20032
- } catch {
20033
- }
20034
- }
20035
- return { source, rows: rows2.length, readAt };
20036
- }
20037
- var fs11, path10, import_node_crypto4, import_zod49, BriefRowSchema, BriefAnswersInput, RecordSchema, FileSchema, briefAnswersPath;
20038
- var init_brief_answers = __esm({
20039
- "src/command-os/connectors/brief-answers.ts"() {
20007
+ // src/command-os/connectors/brief-row.ts
20008
+ var import_zod49, BriefRowSchema;
20009
+ var init_brief_row = __esm({
20010
+ "src/command-os/connectors/brief-row.ts"() {
20040
20011
  "use strict";
20041
- fs11 = __toESM(require("node:fs"));
20042
- path10 = __toESM(require("node:path"));
20043
- import_node_crypto4 = require("node:crypto");
20044
20012
  import_zod49 = require("zod");
20045
- init_credentials_store();
20046
20013
  BriefRowSchema = import_zod49.z.object({
20047
20014
  text: import_zod49.z.string().min(1).max(12e3),
20048
20015
  when: import_zod49.z.string().max(300).optional(),
20049
20016
  link: import_zod49.z.url().refine((value) => ["https:", "http:"].includes(new URL(value).protocol), "Use an HTTP or HTTPS link.").optional()
20050
20017
  }).strict();
20051
- BriefAnswersInput = import_zod49.z.object({
20052
- source: import_zod49.z.enum(["gmail", "google-drive"]),
20053
- readAt: import_zod49.z.iso.datetime({ offset: true }),
20054
- rows: import_zod49.z.array(BriefRowSchema).max(50, "Record at most 50 rows per source.")
20055
- }).strict();
20056
- RecordSchema = BriefAnswersInput.omit({ source: true });
20057
- FileSchema = import_zod49.z.object({ gmail: RecordSchema.optional(), "google-drive": RecordSchema.optional() }).strict();
20058
- briefAnswersPath = () => path10.join(appDataDir(), "brief-answers.json");
20059
20018
  }
20060
20019
  });
20061
20020
 
@@ -20079,13 +20038,13 @@ var init_registry = __esm({
20079
20038
  builtState: "built",
20080
20039
  whatItIs: "A restricted key is a password Stripe issues that lets this machine read only the parts of your account you allow.",
20081
20040
  checkedOn: null,
20082
- gives: "Adds who owes you money, what each client pays and when they renew to your brief.",
20083
- needs: ["Access to your Stripe account's API keys.", "A restricted key with Read access to Customers, Invoices and Subscriptions."],
20041
+ gives: "Adds your monthly recurring revenue, money received, failed payments, who owes you and when clients renew to your brief.",
20042
+ needs: ["Access to your Stripe account's API keys.", "A restricted key with Read access to Customers, Invoices and Subscriptions, plus Charges and Products for money received and revenue by product."],
20084
20043
  steps: [
20085
20044
  "[UNVERIFIED] Sign in to your Stripe Dashboard and choose the account you want to read.",
20086
20045
  "[UNVERIFIED] Open Developers, then API keys. If your dashboard shows Workbench, open its API keys page.",
20087
20046
  "[UNVERIFIED] Under Restricted keys, choose Create restricted key and give it a name you recognise.",
20088
- "[UNVERIFIED] Set Customers, Invoices and Subscriptions to Read. Leave other permissions at None, then create the key.",
20047
+ "[UNVERIFIED] Set Customers, Invoices, Subscriptions, Charges and Products to Read. Leave other permissions at None, then create the key.",
20089
20048
  "[UNVERIFIED] Copy the key into the password field on the Stripe card on the Connections screen, add an account label if useful, and choose Connect. Use a live-mode key for real income."
20090
20049
  ],
20091
20050
  say: ["Connect my Stripe.", "Sync my Stripe.", "Run my morning brief."],
@@ -20129,22 +20088,20 @@ var init_registry = __esm({
20129
20088
  tools: { connect: "connect_google_calendar", disconnect: "connect_google_calendar", read: "read_my_calendar" }
20130
20089
  },
20131
20090
  {
20132
- panel: (deps) => deps.chat("gmail", "Gmail"),
20133
20091
  id: "gmail",
20134
20092
  name: "Gmail",
20135
20093
  builtState: "via-claude",
20136
20094
  whatItIs: "Your Claude's Gmail connection lets Claude read the mail you permit in your conversation.",
20137
20095
  checkedOn: null,
20138
20096
  viaClaude: "Answered by your Claude's Gmail connector; nothing to connect here",
20139
- gives: "Adds client email waiting on you through your Claude's Gmail connector.",
20097
+ gives: "Your Claude reads client email waiting on you in its own morning brief. The cockpit does not show mail.",
20140
20098
  needs: ["Gmail connected in your Claude."],
20141
20099
  steps: [],
20142
- say: ["Run my morning brief and check client email waiting on me through Gmail.", "After checking Gmail, call record_brief_answers to put the results on my brief dashboard."],
20100
+ say: ["Run my morning brief.", "What client email is waiting on me?"],
20143
20101
  revoke: "Disconnect Gmail in your Claude's connector settings.",
20144
20102
  tools: {}
20145
20103
  },
20146
20104
  {
20147
- panel: (deps) => deps.chat("google-drive", "Google Drive"),
20148
20105
  id: "google-drive",
20149
20106
  name: "Google Drive",
20150
20107
  builtState: "via-claude",
@@ -20154,11 +20111,10 @@ var init_registry = __esm({
20154
20111
  gives: "Finds a client's agreement, onboarding form and brand files on request through your Claude's Drive connector.",
20155
20112
  needs: ["Google Drive connected in your Claude."],
20156
20113
  steps: [],
20157
- say: ["Find this client's agreement, onboarding form and brand files in Google Drive, using their name and domain.", "After checking Drive on request, call record_brief_answers to put the results on my brief dashboard."],
20114
+ say: ["Find this client's agreement, onboarding form and brand files in Google Drive, using their name and domain."],
20158
20115
  revoke: "Disconnect Google Drive in your Claude's connector settings.",
20159
20116
  tools: {}
20160
20117
  },
20161
- { id: "meta-ads", name: "Meta Ads", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} },
20162
20118
  { id: "zoom", name: "Zoom", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} },
20163
20119
  { id: "plaud", name: "Plaud", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} }
20164
20120
  ];
@@ -20167,11 +20123,11 @@ var init_registry = __esm({
20167
20123
 
20168
20124
  // src/command-os/connectors/store.ts
20169
20125
  function connectorsPath() {
20170
- return path11.join(appDataDir(), "connectors.json");
20126
+ return path10.join(appDataDir(), "connectors.json");
20171
20127
  }
20172
20128
  function readFile() {
20173
20129
  try {
20174
- const raw = fs12.readFileSync(connectorsPath(), "utf-8");
20130
+ const raw = fs11.readFileSync(connectorsPath(), "utf-8");
20175
20131
  const parsed2 = JSON.parse(raw);
20176
20132
  if (!parsed2 || typeof parsed2 !== "object" || !parsed2.connectors) return { v: 1, connectors: {} };
20177
20133
  return parsed2;
@@ -20183,7 +20139,7 @@ function readForWrite() {
20183
20139
  const target = connectorsPath();
20184
20140
  let raw;
20185
20141
  try {
20186
- raw = fs12.readFileSync(target, "utf-8");
20142
+ raw = fs11.readFileSync(target, "utf-8");
20187
20143
  } catch (e) {
20188
20144
  if (e?.code === "ENOENT") return { v: 1, connectors: {} };
20189
20145
  throw new Error("Your connector file could not be read, so nothing was changed. Nothing was lost.");
@@ -20195,8 +20151,8 @@ function readForWrite() {
20195
20151
  } catch {
20196
20152
  const kept = `${target}.unreadable-${Date.now()}`;
20197
20153
  try {
20198
- fs12.copyFileSync(target, kept);
20199
- fs12.chmodSync(kept, 384);
20154
+ fs11.copyFileSync(target, kept);
20155
+ fs11.chmodSync(kept, 384);
20200
20156
  } catch {
20201
20157
  }
20202
20158
  throw new Error(
@@ -20210,31 +20166,36 @@ function writeFile(f) {
20210
20166
  const tmp = `${target}.${process.pid}.tmp`;
20211
20167
  let renamed = false;
20212
20168
  try {
20213
- fs12.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
20169
+ fs11.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
20214
20170
  try {
20215
- fs12.chmodSync(tmp, 384);
20171
+ fs11.chmodSync(tmp, 384);
20216
20172
  } catch {
20217
20173
  }
20218
- fs12.renameSync(tmp, target);
20174
+ fs11.renameSync(tmp, target);
20219
20175
  renamed = true;
20220
20176
  } finally {
20221
20177
  if (!renamed) {
20222
20178
  try {
20223
- fs12.unlinkSync(tmp);
20179
+ fs11.unlinkSync(tmp);
20224
20180
  } catch {
20225
20181
  }
20226
20182
  }
20227
20183
  }
20228
20184
  try {
20229
- fs12.chmodSync(target, 384);
20185
+ fs11.chmodSync(target, 384);
20230
20186
  } catch {
20231
20187
  }
20232
20188
  }
20233
20189
  function safeLabel(label, key) {
20234
- const variants = [.../* @__PURE__ */ new Set([key, key.trim()])].filter(Boolean);
20235
- if (label === void 0 || !variants.length) return label;
20236
- const pattern = variants.map((value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
20237
- return label.replace(new RegExp(pattern, "g"), "[key removed from label]");
20190
+ if (label === void 0) return label;
20191
+ let out = label;
20192
+ for (const value of [.../* @__PURE__ */ new Set([key, key.trim()])].filter(Boolean).sort((a, b) => b.length - a.length)) {
20193
+ for (let length = value.length; length >= 8; length--) {
20194
+ const part = value.slice(0, length);
20195
+ if (out.includes(part)) out = out.split(part).join("[key removed from label]");
20196
+ }
20197
+ }
20198
+ return out;
20238
20199
  }
20239
20200
  function connect(system, key, label, now = () => /* @__PURE__ */ new Date(), verified = true) {
20240
20201
  const trimmed = String(key ?? "").trim();
@@ -20257,7 +20218,7 @@ function summaryOf(s) {
20257
20218
  }
20258
20219
  function listConnectors(options = {}) {
20259
20220
  try {
20260
- const file2 = import_zod50.z.object({ v: import_zod50.z.literal(1), connectors: import_zod50.z.record(import_zod50.z.string(), import_zod50.z.unknown()) }).parse(JSON.parse(fs12.readFileSync(connectorsPath(), "utf8")));
20221
+ const file2 = import_zod50.z.object({ v: import_zod50.z.literal(1), connectors: import_zod50.z.record(import_zod50.z.string(), import_zod50.z.unknown()) }).parse(JSON.parse(fs11.readFileSync(connectorsPath(), "utf8")));
20261
20222
  const summaries = [];
20262
20223
  for (const [system, value] of Object.entries(file2.connectors)) {
20263
20224
  if (!SystemSchema.safeParse(system).success) continue;
@@ -20283,16 +20244,16 @@ async function withKey(system, fn) {
20283
20244
  if (!s) throw new Error(`${system} is not connected on this machine.`);
20284
20245
  return fn(s.key);
20285
20246
  }
20286
- var fs12, import_zod50, path11, hintOf, SystemSchema, SummarySourceSchema;
20247
+ var fs11, import_zod50, path10, hintOf, SystemSchema, SummarySourceSchema;
20287
20248
  var init_store2 = __esm({
20288
20249
  "src/command-os/connectors/store.ts"() {
20289
20250
  "use strict";
20290
- fs12 = __toESM(require("node:fs"));
20251
+ fs11 = __toESM(require("node:fs"));
20291
20252
  import_zod50 = require("zod");
20292
- path11 = __toESM(require("node:path"));
20253
+ path10 = __toESM(require("node:path"));
20293
20254
  init_credentials_store();
20294
20255
  hintOf = (key) => `\u2026${String(key).slice(-4)}`;
20295
- SystemSchema = import_zod50.z.enum(["ghl", "stripe", "google-workspace", "meeting-capture", "slack", "meta-ads", "byo"]);
20256
+ SystemSchema = import_zod50.z.enum(["ghl", "stripe", "google-workspace", "meeting-capture", "slack", "byo"]);
20296
20257
  SummarySourceSchema = import_zod50.z.object({
20297
20258
  system: SystemSchema,
20298
20259
  key: import_zod50.z.string().min(1),
@@ -20661,7 +20622,83 @@ async function health(fetcher, now = () => /* @__PURE__ */ new Date()) {
20661
20622
  return { system: SYSTEM, state: "BROKEN", detail: `Stripe read failed: ${msg3.slice(0, 120)}`, checkedAt };
20662
20623
  }
20663
20624
  }
20664
- var SYSTEM, iso, ZERO_DECIMAL, THREE_DECIMAL, fromMinor, upper, stillOwed;
20625
+ function productGroup(name, all) {
20626
+ const parents = all.filter((p) => p !== name && name.startsWith(p) && /^\s*[\-—–:(+]/.test(name.slice(p.length)));
20627
+ return parents.sort((a, b) => b.length - a.length)[0] ?? name;
20628
+ }
20629
+ function moneySummary(subs, invoices, charges, products, now = /* @__PURE__ */ new Date()) {
20630
+ const names = new Map(products.map((p) => [p.id, p.name]));
20631
+ const allNames = [...new Set(products.map((p) => p.name))];
20632
+ const mrr = /* @__PURE__ */ new Map();
20633
+ const groups = /* @__PURE__ */ new Map();
20634
+ let mrrUnpriced = 0;
20635
+ for (const sub of subs) {
20636
+ if (sub.status !== "active" && sub.status !== "past_due") continue;
20637
+ for (const item of sub.items?.data ?? []) {
20638
+ const price = item.price;
20639
+ const currency = upper(price?.currency) ?? upper(sub.currency);
20640
+ const per = PER_MONTH[price?.recurring?.interval ?? ""];
20641
+ const count2 = price?.recurring?.interval_count ?? 1;
20642
+ const unit = fromMinor(price?.unit_amount, currency);
20643
+ if (!currency || per === void 0 || unit === null || !(count2 > 0)) {
20644
+ mrrUnpriced++;
20645
+ continue;
20646
+ }
20647
+ const monthly = unit * (item.quantity ?? 1) * per / count2;
20648
+ add(mrr, currency, monthly);
20649
+ const product = price?.product ? names.get(price.product) ?? "A product no longer in Stripe" : "Unnamed product";
20650
+ const group = productGroup(product, allNames);
20651
+ const key = `${group}\0${currency}`;
20652
+ const g = groups.get(key) ?? { subs: /* @__PURE__ */ new Set(), currency, monthly: 0 };
20653
+ g.subs.add(sub.id);
20654
+ g.monthly += monthly;
20655
+ groups.set(key, g);
20656
+ }
20657
+ }
20658
+ const nowS = now.getTime() / 1e3;
20659
+ const within = (t, days) => t <= nowS && nowS - t <= days * 86400;
20660
+ const r7 = /* @__PURE__ */ new Map(), r30 = /* @__PURE__ */ new Map();
20661
+ let c7 = 0, c30 = 0, failed30 = 0;
20662
+ for (const c of charges) {
20663
+ if (!within(c.created, 30)) continue;
20664
+ if (c.status === "failed") {
20665
+ failed30++;
20666
+ continue;
20667
+ }
20668
+ if (c.status !== "succeeded") continue;
20669
+ const currency = upper(c.currency);
20670
+ const net = fromMinor(c.amount - (c.amount_refunded ?? 0), currency) ?? 0;
20671
+ if (net <= 0) continue;
20672
+ add(r30, currency, net);
20673
+ c30++;
20674
+ if (within(c.created, 7)) {
20675
+ add(r7, currency, net);
20676
+ c7++;
20677
+ }
20678
+ }
20679
+ const recurring = /* @__PURE__ */ new Map();
20680
+ for (const i of invoices) {
20681
+ const paidAt = i.status_transitions?.paid_at;
20682
+ const subId = i.parent?.subscription_details?.subscription ?? i.subscription;
20683
+ if (i.status !== "paid" || !paidAt || !within(paidAt, 30) || !subId) continue;
20684
+ const currency = upper(i.currency);
20685
+ const paid = fromMinor(i.amount_paid, currency);
20686
+ if (currency && paid) add(recurring, currency, paid);
20687
+ }
20688
+ const oneOff = /* @__PURE__ */ new Map();
20689
+ for (const [currency, amount] of r30) oneOff.set(currency, Math.max(0, amount - (recurring.get(currency) ?? 0)));
20690
+ return {
20691
+ mrr: totals(mrr),
20692
+ mrrUnpriced,
20693
+ byProduct: [...groups].map(([key, g]) => ({ name: key.split("\0")[0], subscribers: g.subs.size, currency: g.currency, monthly: Math.round(g.monthly * 100) / 100 })).sort((a, b) => b.monthly - a.monthly),
20694
+ received7: { count: c7, totals: totals(r7) },
20695
+ received30: { count: c30, totals: totals(r30) },
20696
+ recurring30: totals(recurring),
20697
+ oneOff30: totals(oneOff),
20698
+ failed30
20699
+ };
20700
+ }
20701
+ var SYSTEM, iso, ZERO_DECIMAL, THREE_DECIMAL, fromMinor, upper, stillOwed, PER_MONTH, add, totals;
20665
20702
  var init_stripe = __esm({
20666
20703
  "src/command-os/connectors/stripe.ts"() {
20667
20704
  "use strict";
@@ -20681,13 +20718,16 @@ var init_stripe = __esm({
20681
20718
  return t ? t : null;
20682
20719
  };
20683
20720
  stillOwed = (i) => (fromMinor(i.amount_remaining ?? i.amount_due ?? null, upper(i.currency)) ?? 0) > 0;
20721
+ PER_MONTH = { day: 365 / 12, week: 52 / 12, month: 1, year: 1 / 12 };
20722
+ add = (m, currency, amount) => m.set(currency, (m.get(currency) ?? 0) + amount);
20723
+ totals = (m) => [...m].map(([currency, amount]) => ({ currency, amount: Math.round(amount * 100) / 100 }));
20684
20724
  }
20685
20725
  });
20686
20726
 
20687
20727
  // src/command-os/connectors/google-calendar-store.ts
20688
20728
  function read() {
20689
20729
  try {
20690
- return SecretSchema.parse(JSON.parse(fs13.readFileSync(googleCalendarPath(), "utf8")));
20730
+ return SecretSchema.parse(JSON.parse(fs12.readFileSync(googleCalendarPath(), "utf8")));
20691
20731
  } catch (error) {
20692
20732
  if (error.code === "ENOENT") return null;
20693
20733
  throw new Error("The Google Calendar sign-in on this machine could not be read. Connect your Google Calendar again.");
@@ -20710,16 +20750,16 @@ function saveCalendarSecret(secret) {
20710
20750
  try {
20711
20751
  const validated = SecretSchema.parse(secret);
20712
20752
  const dir = ensureAppDataDir();
20713
- if (process.platform !== "win32") fs13.chmodSync(dir, 448);
20714
- tmp = `${googleCalendarPath()}.${(0, import_node_crypto5.randomUUID)()}.tmp`;
20715
- fs13.writeFileSync(tmp, JSON.stringify(validated) + "\n", { mode: 384, flag: "wx" });
20716
- fs13.renameSync(tmp, googleCalendarPath());
20753
+ if (process.platform !== "win32") fs12.chmodSync(dir, 448);
20754
+ tmp = `${googleCalendarPath()}.${(0, import_node_crypto4.randomUUID)()}.tmp`;
20755
+ fs12.writeFileSync(tmp, JSON.stringify(validated) + "\n", { mode: 384, flag: "wx" });
20756
+ fs12.renameSync(tmp, googleCalendarPath());
20717
20757
  } catch {
20718
20758
  throw new Error("The Google Calendar sign-in could not be saved privately on this machine. Nothing new was saved.");
20719
20759
  } finally {
20720
20760
  if (tmp) {
20721
20761
  try {
20722
- fs13.unlinkSync(tmp);
20762
+ fs12.unlinkSync(tmp);
20723
20763
  } catch {
20724
20764
  }
20725
20765
  }
@@ -20727,20 +20767,20 @@ function saveCalendarSecret(secret) {
20727
20767
  }
20728
20768
  function removeCalendarSecret() {
20729
20769
  try {
20730
- fs13.unlinkSync(googleCalendarPath());
20770
+ fs12.unlinkSync(googleCalendarPath());
20731
20771
  return true;
20732
20772
  } catch (error) {
20733
20773
  if (error.code === "ENOENT") return false;
20734
20774
  throw new Error("The Google Calendar sign-in could not be removed from this machine.");
20735
20775
  }
20736
20776
  }
20737
- var fs13, path12, import_node_crypto5, import_zod51, CALENDAR_SCOPE, SecretSchema, googleCalendarPath;
20777
+ var fs12, path11, import_node_crypto4, import_zod51, CALENDAR_SCOPE, SecretSchema, googleCalendarPath;
20738
20778
  var init_google_calendar_store = __esm({
20739
20779
  "src/command-os/connectors/google-calendar-store.ts"() {
20740
20780
  "use strict";
20741
- fs13 = __toESM(require("node:fs"));
20742
- path12 = __toESM(require("node:path"));
20743
- import_node_crypto5 = require("node:crypto");
20781
+ fs12 = __toESM(require("node:fs"));
20782
+ path11 = __toESM(require("node:path"));
20783
+ import_node_crypto4 = require("node:crypto");
20744
20784
  import_zod51 = require("zod");
20745
20785
  init_credentials_store();
20746
20786
  CALENDAR_SCOPE = "https://www.googleapis.com/auth/calendar.readonly";
@@ -20751,7 +20791,7 @@ var init_google_calendar_store = __esm({
20751
20791
  scope: import_zod51.z.literal(CALENDAR_SCOPE),
20752
20792
  connectedAt: import_zod51.z.string()
20753
20793
  });
20754
- googleCalendarPath = () => path12.join(appDataDir(), "google-calendar.json");
20794
+ googleCalendarPath = () => path11.join(appDataDir(), "google-calendar.json");
20755
20795
  }
20756
20796
  });
20757
20797
 
@@ -20873,16 +20913,16 @@ function createGoogleCalendar(deps = {}) {
20873
20913
  requireOnlyCalendar(result.scope);
20874
20914
  return result.access_token;
20875
20915
  }
20876
- async function pages(path42, access, item, query = {}) {
20916
+ async function pages(path41, access, item, query = {}) {
20877
20917
  const result = [];
20878
20918
  const seen = /* @__PURE__ */ new Set();
20879
20919
  let pageToken;
20880
20920
  for (let page = 0; page < 100; page++) {
20881
- const url = new URL(`${API}${path42}`);
20921
+ const url = new URL(`${API}${path41}`);
20882
20922
  for (const [k, v] of Object.entries(query)) url.searchParams.set(k, v);
20883
20923
  if (pageToken) url.searchParams.set("pageToken", pageToken);
20884
20924
  const data = parsed(
20885
- import_zod52.z.object({ items: import_zod52.z.array(item).optional(), nextPageToken: import_zod52.z.string().optional(), kind: import_zod52.z.string().optional() }).refine((p) => p.items !== void 0 || p.kind === (path42.endsWith("/events") ? "calendar#events" : "calendar#calendarList")),
20925
+ import_zod52.z.object({ items: import_zod52.z.array(item).optional(), nextPageToken: import_zod52.z.string().optional(), kind: import_zod52.z.string().optional() }).refine((p) => p.items !== void 0 || p.kind === (path41.endsWith("/events") ? "calendar#events" : "calendar#calendarList")),
20886
20926
  await request(url.href, { headers: { Authorization: `Bearer ${access}` } })
20887
20927
  );
20888
20928
  result.push(...data.items ?? []);
@@ -20900,8 +20940,8 @@ function createGoogleCalendar(deps = {}) {
20900
20940
  async function start() {
20901
20941
  const app = appConfig();
20902
20942
  clearPending2();
20903
- const state = (0, import_node_crypto6.randomBytes)(32).toString("base64url");
20904
- const verifier = (0, import_node_crypto6.randomBytes)(32).toString("base64url");
20943
+ const state = (0, import_node_crypto5.randomBytes)(32).toString("base64url");
20944
+ const verifier = (0, import_node_crypto5.randomBytes)(32).toString("base64url");
20905
20945
  const server2 = (deps.createServer ?? import_node_http.createServer)((req, res) => {
20906
20946
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
20907
20947
  res.setHeader("Cache-Control", "no-store");
@@ -20955,7 +20995,7 @@ function createGoogleCalendar(deps = {}) {
20955
20995
  response_type: "code",
20956
20996
  scope: CALENDAR_SCOPE,
20957
20997
  state,
20958
- code_challenge: (0, import_node_crypto6.createHash)("sha256").update(verifier).digest("base64url"),
20998
+ code_challenge: (0, import_node_crypto5.createHash)("sha256").update(verifier).digest("base64url"),
20959
20999
  code_challenge_method: "S256",
20960
21000
  access_type: "offline",
20961
21001
  prompt: "consent"
@@ -21085,13 +21125,13 @@ function createGoogleCalendar(deps = {}) {
21085
21125
  close: clearPending2
21086
21126
  };
21087
21127
  }
21088
- var import_node_http, import_node_crypto6, import_node_child_process, import_zod52, TOKEN_URL, REVOKE_URL, API, tokenSchema, calendarSchema, eventSchema;
21128
+ var import_node_http, import_node_crypto5, import_node_child_process, import_zod52, TOKEN_URL, REVOKE_URL, API, tokenSchema, calendarSchema, eventSchema;
21089
21129
  var init_google_calendar = __esm({
21090
21130
  "src/command-os/connectors/google-calendar.ts"() {
21091
21131
  "use strict";
21092
21132
  init_any_signal();
21093
21133
  import_node_http = require("node:http");
21094
- import_node_crypto6 = require("node:crypto");
21134
+ import_node_crypto5 = require("node:crypto");
21095
21135
  import_node_child_process = require("node:child_process");
21096
21136
  import_zod52 = require("zod");
21097
21137
  init_credentials_store();
@@ -21133,8 +21173,8 @@ function redactConnectionKey(value, key) {
21133
21173
  return value;
21134
21174
  }
21135
21175
  function stripeFetcher(key, signal) {
21136
- return async (path42, query) => {
21137
- const url = new URL(`https://api.stripe.com${path42}`);
21176
+ return async (path41, query) => {
21177
+ const url = new URL(`https://api.stripe.com${path41}`);
21138
21178
  for (const [k, v] of Object.entries(query ?? {})) url.searchParams.set(k, v);
21139
21179
  const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` }, signal });
21140
21180
  if (!res.ok) {
@@ -21179,7 +21219,7 @@ async function connectSystem({ system, key, label }) {
21179
21219
  system,
21180
21220
  because: h.detail,
21181
21221
  storedAt: null,
21182
- note: "Nothing was saved, so nothing now claims to be connected. Fix the key and run this again \u2014 a Stripe RESTRICTED key needs read access to subscriptions, invoices and customers."
21222
+ note: "Nothing was saved, so nothing now claims to be connected. Fix the key and run this again \u2014 a Stripe RESTRICTED key needs read access to subscriptions, invoices and customers (and charges and products for the money figures)."
21183
21223
  };
21184
21224
  }
21185
21225
  const s = connect(system, key, label, void 0, h.state === "WORKING");
@@ -21223,11 +21263,11 @@ var init_handlers = __esm({
21223
21263
  });
21224
21264
 
21225
21265
  // src/command-os/connectors/stripe-read.ts
21226
- async function listAll(f, path42, schema, extra = {}) {
21266
+ async function listAll(f, path41, schema, extra = {}) {
21227
21267
  const out = [];
21228
21268
  let after;
21229
21269
  for (let page = 0; page < 20; page++) {
21230
- const result = import_zod53.z.object({ data: import_zod53.z.array(schema), has_more: import_zod53.z.boolean().optional() }).parse(await f(path42, { limit: "100", ...extra, ...after ? { starting_after: after } : {} }));
21270
+ const result = import_zod53.z.object({ data: import_zod53.z.array(schema), has_more: import_zod53.z.boolean().optional() }).parse(await f(path41, { limit: "100", ...extra, ...after ? { starting_after: after } : {} }));
21231
21271
  out.push(...result.data);
21232
21272
  if (!result.has_more) return out;
21233
21273
  const last = import_zod53.z.object({ id: import_zod53.z.string().min(1) }).parse(result.data.at(-1));
@@ -21244,7 +21284,15 @@ async function readStripe(f) {
21244
21284
  ]);
21245
21285
  return { subs, invoices, customers };
21246
21286
  }
21247
- var import_zod53, Customer, Subscription, Invoice;
21287
+ async function readStripeMoney(f, now) {
21288
+ const since = String(Math.floor(now.getTime() / 1e3) - 30 * 86400);
21289
+ const [charges, products] = await Promise.all([
21290
+ listAll(f, "/v1/charges", Charge, { "created[gte]": since }),
21291
+ listAll(f, "/v1/products", Product)
21292
+ ]);
21293
+ return { charges, products };
21294
+ }
21295
+ var import_zod53, Customer, Subscription, Invoice, Charge, Product;
21248
21296
  var init_stripe_read = __esm({
21249
21297
  "src/command-os/connectors/stripe-read.ts"() {
21250
21298
  "use strict";
@@ -21261,9 +21309,10 @@ var init_stripe_read = __esm({
21261
21309
  quantity: import_zod53.z.number().nullable().optional(),
21262
21310
  current_period_end: import_zod53.z.number().optional(),
21263
21311
  price: import_zod53.z.object({
21312
+ product: import_zod53.z.string().nullable().optional(),
21264
21313
  unit_amount: import_zod53.z.number().nullable().optional(),
21265
21314
  currency: import_zod53.z.string().nullable().optional(),
21266
- recurring: import_zod53.z.object({ interval: import_zod53.z.string().optional() }).nullable().optional()
21315
+ recurring: import_zod53.z.object({ interval: import_zod53.z.string().optional(), interval_count: import_zod53.z.number().optional() }).nullable().optional()
21267
21316
  }).nullable().optional()
21268
21317
  })).optional() }).optional()
21269
21318
  });
@@ -21276,15 +21325,28 @@ var init_stripe_read = __esm({
21276
21325
  amount_remaining: import_zod53.z.number().optional(),
21277
21326
  due_date: import_zod53.z.number().nullable().optional(),
21278
21327
  number: import_zod53.z.string().nullable().optional(),
21279
- hosted_invoice_url: import_zod53.z.string().nullable().optional()
21328
+ hosted_invoice_url: import_zod53.z.string().nullable().optional(),
21329
+ amount_paid: import_zod53.z.number().optional(),
21330
+ subscription: import_zod53.z.string().nullable().optional(),
21331
+ parent: import_zod53.z.object({ subscription_details: import_zod53.z.object({ subscription: import_zod53.z.string().nullable().optional() }).nullable().optional() }).nullable().optional(),
21332
+ status_transitions: import_zod53.z.object({ paid_at: import_zod53.z.number().nullable().optional() }).nullable().optional()
21333
+ });
21334
+ Charge = import_zod53.z.object({
21335
+ id: import_zod53.z.string(),
21336
+ amount: import_zod53.z.number(),
21337
+ amount_refunded: import_zod53.z.number().optional(),
21338
+ currency: import_zod53.z.string(),
21339
+ status: import_zod53.z.string(),
21340
+ created: import_zod53.z.number()
21280
21341
  });
21342
+ Product = import_zod53.z.object({ id: import_zod53.z.string(), name: import_zod53.z.string() });
21281
21343
  }
21282
21344
  });
21283
21345
 
21284
21346
  // src/client-engagements.ts
21285
21347
  function clientEngagementsPath() {
21286
21348
  const override = process.env[CLIENT_ENGAGEMENTS_ENV];
21287
- return override && override.trim() ? override : path13.join(appDataDir(), "client-engagements.json");
21349
+ return override && override.trim() ? override : path12.join(appDataDir(), "client-engagements.json");
21288
21350
  }
21289
21351
  function isAgencyClient(e) {
21290
21352
  return (e.kind ?? DEFAULT_ENGAGEMENT_KIND) === "client";
@@ -21343,7 +21405,7 @@ function sanitizeEngagements(raw) {
21343
21405
  }
21344
21406
  function readClientEngagements(file2 = clientEngagementsPath()) {
21345
21407
  try {
21346
- const raw = JSON.parse(fs14.readFileSync(file2, "utf8"));
21408
+ const raw = JSON.parse(fs13.readFileSync(file2, "utf8"));
21347
21409
  if (raw && typeof raw === "object") return sanitizeEngagements(raw);
21348
21410
  } catch {
21349
21411
  }
@@ -21370,7 +21432,7 @@ function writeClientEngagement(locationId2, patch, file2 = clientEngagementsPath
21370
21432
  if (!id || FORBIDDEN_KEY.has(id)) throw new Error("An id is required.");
21371
21433
  const stamp = () => {
21372
21434
  try {
21373
- return fs14.readFileSync(file2, "utf8");
21435
+ return fs13.readFileSync(file2, "utf8");
21374
21436
  } catch {
21375
21437
  return "";
21376
21438
  }
@@ -21390,20 +21452,20 @@ function writeClientEngagement(locationId2, patch, file2 = clientEngagementsPath
21390
21452
  };
21391
21453
  const persist = (next) => {
21392
21454
  if (file2 === clientEngagementsPath() && !process.env[CLIENT_ENGAGEMENTS_ENV]) ensureAppDataDir();
21393
- fs14.mkdirSync(path13.dirname(file2), { recursive: true });
21455
+ fs13.mkdirSync(path12.dirname(file2), { recursive: true });
21394
21456
  const tmp = `${file2}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
21395
21457
  try {
21396
- fs14.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", "utf-8");
21458
+ fs13.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", "utf-8");
21397
21459
  if (process.platform !== "win32") {
21398
21460
  try {
21399
- fs14.chmodSync(tmp, 384);
21461
+ fs13.chmodSync(tmp, 384);
21400
21462
  } catch {
21401
21463
  }
21402
21464
  }
21403
- fs14.renameSync(tmp, file2);
21465
+ fs13.renameSync(tmp, file2);
21404
21466
  } catch (e) {
21405
21467
  try {
21406
- fs14.unlinkSync(tmp);
21468
+ fs13.unlinkSync(tmp);
21407
21469
  } catch {
21408
21470
  }
21409
21471
  throw e;
@@ -21475,12 +21537,12 @@ function monthlyFloor(roster, profile) {
21475
21537
  byKind
21476
21538
  };
21477
21539
  }
21478
- var fs14, path13, CLIENT_ENGAGEMENTS_ENV, ENGAGEMENT_STATUSES, ENGAGEMENT_KINDS, DEFAULT_ENGAGEMENT_KIND, EMPTY2, MAX_NOTES, MAX_SOP2, MAX_CLIENTS, FORBIDDEN_KEY;
21540
+ var fs13, path12, CLIENT_ENGAGEMENTS_ENV, ENGAGEMENT_STATUSES, ENGAGEMENT_KINDS, DEFAULT_ENGAGEMENT_KIND, EMPTY2, MAX_NOTES, MAX_SOP2, MAX_CLIENTS, FORBIDDEN_KEY;
21479
21541
  var init_client_engagements = __esm({
21480
21542
  "src/client-engagements.ts"() {
21481
21543
  "use strict";
21482
- fs14 = __toESM(require("fs"));
21483
- path13 = __toESM(require("path"));
21544
+ fs13 = __toESM(require("fs"));
21545
+ path12 = __toESM(require("path"));
21484
21546
  init_credentials_store();
21485
21547
  init_field_sanitize();
21486
21548
  CLIENT_ENGAGEMENTS_ENV = "GHL_MCP_CLIENT_ENGAGEMENTS";
@@ -21498,7 +21560,7 @@ var init_client_engagements = __esm({
21498
21560
  // src/board-roster.ts
21499
21561
  function readBoardState() {
21500
21562
  try {
21501
- const raw = JSON.parse(fs15.readFileSync(path14.join(appDataDir(), "cockpit-state.json"), "utf8"));
21563
+ const raw = JSON.parse(fs14.readFileSync(path13.join(appDataDir(), "cockpit-state.json"), "utf8"));
21502
21564
  if (raw && typeof raw === "object" && raw.clients && typeof raw.clients === "object") return raw;
21503
21565
  } catch {
21504
21566
  }
@@ -21516,12 +21578,12 @@ function knownClients(registry2, state) {
21516
21578
  }
21517
21579
  return [...out.values()];
21518
21580
  }
21519
- var fs15, path14;
21581
+ var fs14, path13;
21520
21582
  var init_board_roster = __esm({
21521
21583
  "src/board-roster.ts"() {
21522
21584
  "use strict";
21523
- fs15 = __toESM(require("fs"));
21524
- path14 = __toESM(require("path"));
21585
+ fs14 = __toESM(require("fs"));
21586
+ path13 = __toESM(require("path"));
21525
21587
  init_credentials_store();
21526
21588
  init_client_engagements();
21527
21589
  }
@@ -21736,17 +21798,17 @@ var init_stage_boundary = __esm({
21736
21798
  // src/plan-guide.ts
21737
21799
  function skillRoot() {
21738
21800
  const candidates = [
21739
- path15.join(__dirname, "..", "skills", "blueprint"),
21801
+ path14.join(__dirname, "..", "skills", "blueprint"),
21740
21802
  // dist/ → package root
21741
- path15.join(__dirname, "..", "..", "skills", "blueprint"),
21803
+ path14.join(__dirname, "..", "..", "skills", "blueprint"),
21742
21804
  // src/ in dev
21743
- path15.join(process.cwd(), "skills", "blueprint")
21805
+ path14.join(process.cwd(), "skills", "blueprint")
21744
21806
  ];
21745
- return candidates.find((c) => fs16.existsSync(path15.join(c, "references", "build-plan-schema.md"))) ?? null;
21807
+ return candidates.find((c) => fs15.existsSync(path14.join(c, "references", "build-plan-schema.md"))) ?? null;
21746
21808
  }
21747
21809
  function readIf(p, max) {
21748
21810
  try {
21749
- const t = fs16.readFileSync(p, "utf8");
21811
+ const t = fs15.readFileSync(p, "utf8");
21750
21812
  return t.length > max ? t.slice(0, max) : t;
21751
21813
  } catch {
21752
21814
  return null;
@@ -21759,12 +21821,12 @@ function presetForIndustry(industry) {
21759
21821
  function loadPlanGuide(industry) {
21760
21822
  const root = skillRoot();
21761
21823
  if (!root) return "";
21762
- const schema = readIf(path15.join(root, "references", "build-plan-schema.md"), CAP_SCHEMA);
21824
+ const schema = readIf(path14.join(root, "references", "build-plan-schema.md"), CAP_SCHEMA);
21763
21825
  const presetName = presetForIndustry(industry);
21764
- const preset = readIf(path15.join(root, "presets", `${presetName}.preset.json`), CAP_PRESET);
21826
+ const preset = readIf(path14.join(root, "presets", `${presetName}.preset.json`), CAP_PRESET);
21765
21827
  const exampleFile = EXAMPLE_FOR_PRESET[presetName] ?? "sample-build-plan.json";
21766
- const example = readIf(path15.join(root, "examples", exampleFile), CAP_EXAMPLE);
21767
- const copyGuide = readIf(path15.join(root, "references", "copy-guide.md"), CAP_COPY_GUIDE);
21828
+ const example = readIf(path14.join(root, "examples", exampleFile), CAP_EXAMPLE);
21829
+ const copyGuide = readIf(path14.join(root, "references", "copy-guide.md"), CAP_COPY_GUIDE);
21768
21830
  if (!schema) return "";
21769
21831
  return `
21770
21832
  PLAN GUIDE \u2014 everything you need to write the build plan is below. Do NOT try to read files; you cannot.
@@ -21782,12 +21844,12 @@ ${example}
21782
21844
  ` : "") + `=== End of plan guide ===
21783
21845
  `;
21784
21846
  }
21785
- var fs16, path15, PRESET_FOR_INDUSTRY, EXAMPLE_FOR_PRESET, COPY_INSTRUCTION, CALENDAR_INSTRUCTION, CAP_SCHEMA, CAP_PRESET, CAP_EXAMPLE, CAP_COPY_GUIDE;
21847
+ var fs15, path14, PRESET_FOR_INDUSTRY, EXAMPLE_FOR_PRESET, COPY_INSTRUCTION, CALENDAR_INSTRUCTION, CAP_SCHEMA, CAP_PRESET, CAP_EXAMPLE, CAP_COPY_GUIDE;
21786
21848
  var init_plan_guide = __esm({
21787
21849
  "src/plan-guide.ts"() {
21788
21850
  "use strict";
21789
- fs16 = __toESM(require("fs"));
21790
- path15 = __toESM(require("path"));
21851
+ fs15 = __toESM(require("fs"));
21852
+ path14 = __toESM(require("path"));
21791
21853
  PRESET_FOR_INDUSTRY = {
21792
21854
  "med-spa": "med-spa",
21793
21855
  clinic: "clinic",
@@ -22373,26 +22435,26 @@ function isHandoffAction(a, nurtureTriggerTags) {
22373
22435
  function collectDefinedRefs(plan) {
22374
22436
  const refs = /* @__PURE__ */ new Map();
22375
22437
  const duplicates = [];
22376
- const add = (ref) => {
22438
+ const add2 = (ref) => {
22377
22439
  if (refs.has(ref)) duplicates.push(ref);
22378
22440
  else refs.set(ref, refNamespace(ref));
22379
22441
  };
22380
- for (const u of plan.users ?? []) add(u.ref);
22442
+ for (const u of plan.users ?? []) add2(u.ref);
22381
22443
  for (const p of plan.pipelines ?? []) {
22382
- add(p.ref);
22383
- for (const s of p.stages) add(s.ref);
22384
- }
22385
- for (const f of plan.customFields ?? []) add(f.ref);
22386
- for (const t of plan.tags ?? []) add(t.ref);
22387
- for (const cv of plan.customValues ?? []) add(cv.ref);
22388
- for (const c of plan.calendars ?? []) add(c.ref);
22389
- for (const fm of plan.forms ?? []) add(fm.ref);
22390
- for (const e of plan.emails ?? []) add(e.ref);
22391
- for (const s of plan.sms ?? []) add(s.ref);
22392
- for (const t of plan.templates?.emails ?? []) add(t.ref);
22393
- for (const t of plan.templates?.sms ?? []) add(t.ref);
22394
- for (const w of plan.workflows ?? []) add(w.ref);
22395
- for (const h of plan.handoffs ?? []) add(h.ref);
22444
+ add2(p.ref);
22445
+ for (const s of p.stages) add2(s.ref);
22446
+ }
22447
+ for (const f of plan.customFields ?? []) add2(f.ref);
22448
+ for (const t of plan.tags ?? []) add2(t.ref);
22449
+ for (const cv of plan.customValues ?? []) add2(cv.ref);
22450
+ for (const c of plan.calendars ?? []) add2(c.ref);
22451
+ for (const fm of plan.forms ?? []) add2(fm.ref);
22452
+ for (const e of plan.emails ?? []) add2(e.ref);
22453
+ for (const s of plan.sms ?? []) add2(s.ref);
22454
+ for (const t of plan.templates?.emails ?? []) add2(t.ref);
22455
+ for (const t of plan.templates?.sms ?? []) add2(t.ref);
22456
+ for (const w of plan.workflows ?? []) add2(w.ref);
22457
+ for (const h of plan.handoffs ?? []) add2(h.ref);
22396
22458
  return { refs, duplicates };
22397
22459
  }
22398
22460
  function checkRefIntegrity(plan, defined) {
@@ -24407,10 +24469,10 @@ function progressLine(e) {
24407
24469
  }
24408
24470
  }
24409
24471
  function defaultProgressDir(base = appDataDir()) {
24410
- return path16.join(base, "progress");
24472
+ return path15.join(base, "progress");
24411
24473
  }
24412
24474
  function progressFilePath(dir, locationId2) {
24413
- return path16.join(dir, `${locationId2.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
24475
+ return path15.join(dir, `${locationId2.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
24414
24476
  }
24415
24477
  function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DIR_ENV]) {
24416
24478
  if (!dir) return null;
@@ -24418,10 +24480,10 @@ function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DI
24418
24480
  const file2 = progressFilePath(dir, locationId2);
24419
24481
  const write = () => {
24420
24482
  try {
24421
- fs17.mkdirSync(dir, { recursive: true, mode: 448 });
24483
+ fs16.mkdirSync(dir, { recursive: true, mode: 448 });
24422
24484
  const tmp = `${file2}.tmp`;
24423
- fs17.writeFileSync(tmp, JSON.stringify({ locationId: locationId2, progress: tracker.snapshot() }), { mode: 384 });
24424
- fs17.renameSync(tmp, file2);
24485
+ fs16.writeFileSync(tmp, JSON.stringify({ locationId: locationId2, progress: tracker.snapshot() }), { mode: 384 });
24486
+ fs16.renameSync(tmp, file2);
24425
24487
  } catch {
24426
24488
  }
24427
24489
  };
@@ -24439,7 +24501,7 @@ function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DI
24439
24501
  }
24440
24502
  function readProgressSnapshot(dir, locationId2) {
24441
24503
  try {
24442
- const raw = JSON.parse(fs17.readFileSync(progressFilePath(dir, locationId2), "utf8"));
24504
+ const raw = JSON.parse(fs16.readFileSync(progressFilePath(dir, locationId2), "utf8"));
24443
24505
  const p = raw?.progress;
24444
24506
  if (!p || !Array.isArray(p.groups) || typeof p.updatedAt !== "string") return null;
24445
24507
  return p;
@@ -24468,12 +24530,12 @@ function tapPush(arr, onItem) {
24468
24530
  };
24469
24531
  Object.defineProperty(arr, "push", { value: tapped, writable: true, configurable: true, enumerable: false });
24470
24532
  }
24471
- var fs17, path16, PROGRESS_GROUPS, GROUP_INDEX, TYPE_TO_GROUP, HALT_TYPE_TO_GROUP, CREATING_LINE, BuildProgressTracker, PROGRESS_DIR_ENV;
24533
+ var fs16, path15, PROGRESS_GROUPS, GROUP_INDEX, TYPE_TO_GROUP, HALT_TYPE_TO_GROUP, CREATING_LINE, BuildProgressTracker, PROGRESS_DIR_ENV;
24472
24534
  var init_build_progress = __esm({
24473
24535
  "src/build-progress.ts"() {
24474
24536
  "use strict";
24475
- fs17 = __toESM(require("fs"));
24476
- path16 = __toESM(require("path"));
24537
+ fs16 = __toESM(require("fs"));
24538
+ path15 = __toESM(require("path"));
24477
24539
  init_executor();
24478
24540
  init_credentials_store();
24479
24541
  PROGRESS_GROUPS = [
@@ -24528,11 +24590,11 @@ var init_build_progress = __esm({
24528
24590
  current;
24529
24591
  updatedAt;
24530
24592
  constructor(plan) {
24531
- const totals = planProgressTotals(plan);
24593
+ const totals2 = planProgressTotals(plan);
24532
24594
  this.tallies = PROGRESS_GROUPS.map(({ key, label }) => ({
24533
24595
  key,
24534
24596
  label,
24535
- total: totals[key],
24597
+ total: totals2[key],
24536
24598
  done: 0,
24537
24599
  deferred: 0,
24538
24600
  failed: 0,
@@ -24611,10 +24673,10 @@ var init_build_progress = __esm({
24611
24673
 
24612
24674
  // src/build-journal.ts
24613
24675
  function journalDir(base = appDataDir()) {
24614
- return path17.join(base, "build-journal");
24676
+ return path16.join(base, "build-journal");
24615
24677
  }
24616
24678
  function journalPath(locationId2, base) {
24617
- return path17.join(journalDir(base), `${locationId2}.jsonl`);
24679
+ return path16.join(journalDir(base), `${locationId2}.jsonl`);
24618
24680
  }
24619
24681
  function newRunId(now = /* @__PURE__ */ new Date(), rand = defaultRand) {
24620
24682
  const iso2 = now.toISOString();
@@ -24688,40 +24750,40 @@ function directoryFlushUnsupported(e) {
24688
24750
  }
24689
24751
  function appendJournal(record, base) {
24690
24752
  const dir = journalDir(base);
24691
- fs18.mkdirSync(dir, { recursive: true, mode: 448 });
24753
+ fs17.mkdirSync(dir, { recursive: true, mode: 448 });
24692
24754
  const file2 = journalPath(record.locationId, base);
24693
24755
  let needsBoundary = false;
24694
24756
  try {
24695
- const st = fs18.statSync(file2);
24757
+ const st = fs17.statSync(file2);
24696
24758
  if (st.size > 0) {
24697
- const fd2 = fs18.openSync(file2, "r");
24759
+ const fd2 = fs17.openSync(file2, "r");
24698
24760
  try {
24699
24761
  const buf = Buffer.alloc(1);
24700
- fs18.readSync(fd2, buf, 0, 1, st.size - 1);
24762
+ fs17.readSync(fd2, buf, 0, 1, st.size - 1);
24701
24763
  needsBoundary = buf[0] !== 10;
24702
24764
  } finally {
24703
- fs18.closeSync(fd2);
24765
+ fs17.closeSync(fd2);
24704
24766
  }
24705
24767
  }
24706
24768
  } catch {
24707
24769
  }
24708
- const fd = fs18.openSync(file2, "a", 384);
24770
+ const fd = fs17.openSync(file2, "a", 384);
24709
24771
  try {
24710
- fs18.appendFileSync(fd, `${needsBoundary ? "\n" : ""}${JSON.stringify(record)}
24772
+ fs17.appendFileSync(fd, `${needsBoundary ? "\n" : ""}${JSON.stringify(record)}
24711
24773
  `);
24712
- fs18.fsyncSync(fd);
24774
+ fs17.fsyncSync(fd);
24713
24775
  } finally {
24714
- fs18.closeSync(fd);
24776
+ fs17.closeSync(fd);
24715
24777
  }
24716
- for (const directory of [dir, path17.dirname(dir)]) {
24778
+ for (const directory of [dir, path16.dirname(dir)]) {
24717
24779
  let dirFd;
24718
24780
  try {
24719
- dirFd = fs18.openSync(directory, "r");
24720
- fs18.fsyncSync(dirFd);
24781
+ dirFd = fs17.openSync(directory, "r");
24782
+ fs17.fsyncSync(dirFd);
24721
24783
  } catch (e) {
24722
24784
  if (!directoryFlushUnsupported(e)) throw e;
24723
24785
  } finally {
24724
- if (dirFd !== void 0) fs18.closeSync(dirFd);
24786
+ if (dirFd !== void 0) fs17.closeSync(dirFd);
24725
24787
  }
24726
24788
  }
24727
24789
  return file2;
@@ -24729,7 +24791,7 @@ function appendJournal(record, base) {
24729
24791
  function readJournal(locationId2, base) {
24730
24792
  let raw;
24731
24793
  try {
24732
- raw = fs18.readFileSync(journalPath(locationId2, base), "utf8");
24794
+ raw = fs17.readFileSync(journalPath(locationId2, base), "utf8");
24733
24795
  } catch {
24734
24796
  return [];
24735
24797
  }
@@ -24800,12 +24862,12 @@ function describeRuns(locationId2, base) {
24800
24862
  reverted: reverted.has(r.runId)
24801
24863
  })).reverse();
24802
24864
  }
24803
- var fs18, path17, DIRECTORY_FLUSH_UNSUPPORTED;
24865
+ var fs17, path16, DIRECTORY_FLUSH_UNSUPPORTED;
24804
24866
  var init_build_journal = __esm({
24805
24867
  "src/build-journal.ts"() {
24806
24868
  "use strict";
24807
- fs18 = __toESM(require("fs"));
24808
- path17 = __toESM(require("path"));
24869
+ fs17 = __toESM(require("fs"));
24870
+ path16 = __toESM(require("path"));
24809
24871
  init_credentials_store();
24810
24872
  DIRECTORY_FLUSH_UNSUPPORTED = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "ENOSYS", "EISDIR", "EBADF"]);
24811
24873
  }
@@ -24817,7 +24879,7 @@ function unusableShimMessage(shim) {
24817
24879
  }
24818
24880
  function runnable(p) {
24819
24881
  try {
24820
- fs19.accessSync(p, fs19.constants.X_OK);
24882
+ fs18.accessSync(p, fs18.constants.X_OK);
24821
24883
  return true;
24822
24884
  } catch {
24823
24885
  return false;
@@ -24829,27 +24891,27 @@ function claudeFileNames(platform2, env2) {
24829
24891
  return [...exts.map((ext) => `claude${ext}`), "claude"];
24830
24892
  }
24831
24893
  function isShim(file2) {
24832
- const ext = path18.extname(file2).toLowerCase();
24894
+ const ext = path17.extname(file2).toLowerCase();
24833
24895
  return ext === ".cmd" || ext === ".bat";
24834
24896
  }
24835
24897
  function shimTarget(shim) {
24836
24898
  let text2;
24837
24899
  try {
24838
- text2 = fs19.readFileSync(shim, "utf8");
24900
+ text2 = fs18.readFileSync(shim, "utf8");
24839
24901
  } catch {
24840
24902
  return null;
24841
24903
  }
24842
24904
  const refs = [...text2.matchAll(/"%~?dp0%?\\([^"\r\n]+)"/g)].map((m) => m[1]);
24843
- const resolve12 = (rel) => path18.join(path18.dirname(shim), ...rel.split(/[\\/]/));
24905
+ const resolve12 = (rel) => path17.join(path17.dirname(shim), ...rel.split(/[\\/]/));
24844
24906
  const script = refs.find((r) => /\.(?:js|cjs|mjs)$/i.test(r));
24845
24907
  if (script) {
24846
24908
  const p = resolve12(script);
24847
- return fs19.existsSync(p) ? { kind: "script", path: p } : null;
24909
+ return fs18.existsSync(p) ? { kind: "script", path: p } : null;
24848
24910
  }
24849
24911
  const program = refs.find((r) => /\.exe$/i.test(r) && !/(^|[\\/])node\.exe$/i.test(r));
24850
24912
  if (program) {
24851
24913
  const p = resolve12(program);
24852
- return fs19.existsSync(p) ? { kind: "program", path: p } : null;
24914
+ return fs18.existsSync(p) ? { kind: "program", path: p } : null;
24853
24915
  }
24854
24916
  return null;
24855
24917
  }
@@ -24862,7 +24924,7 @@ function claudeBin(lookup = {}) {
24862
24924
  let unusableShim = null;
24863
24925
  for (const dir of dirs) {
24864
24926
  for (const name of names) {
24865
- const candidate = path18.join(dir, name);
24927
+ const candidate = path17.join(dir, name);
24866
24928
  if (!runnable(candidate)) continue;
24867
24929
  if (platform2 === "win32" && isShim(candidate) && !shimTarget(candidate)) {
24868
24930
  unusableShim ??= candidate;
@@ -24871,7 +24933,7 @@ function claudeBin(lookup = {}) {
24871
24933
  return candidate;
24872
24934
  }
24873
24935
  }
24874
- const fallback = path18.join(home, ".local", "bin", platform2 === "win32" ? "claude.exe" : "claude");
24936
+ const fallback = path17.join(home, ".local", "bin", platform2 === "win32" ? "claude.exe" : "claude");
24875
24937
  if (runnable(fallback)) return fallback;
24876
24938
  throw new Error(unusableShim ? unusableShimMessage(unusableShim) : NOT_FOUND_MESSAGE);
24877
24939
  }
@@ -24891,13 +24953,13 @@ function claudeCommand(bin, args, lookup = {}) {
24891
24953
  if (!target) return { command: resolved2, args };
24892
24954
  return target.kind === "script" ? { command: lookup.execPath ?? process.execPath, args: [target.path, ...args] } : { command: target.path, args };
24893
24955
  }
24894
- var fs19, os3, path18, NOT_FOUND_MESSAGE;
24956
+ var fs18, os3, path17, NOT_FOUND_MESSAGE;
24895
24957
  var init_claude_locate = __esm({
24896
24958
  "src/claude-locate.ts"() {
24897
24959
  "use strict";
24898
- fs19 = __toESM(require("node:fs"));
24960
+ fs18 = __toESM(require("node:fs"));
24899
24961
  os3 = __toESM(require("node:os"));
24900
- path18 = __toESM(require("node:path"));
24962
+ path17 = __toESM(require("node:path"));
24901
24963
  NOT_FOUND_MESSAGE = "Claude Code CLI not found. Install it, then reopen the cockpit.";
24902
24964
  }
24903
24965
  });
@@ -24933,21 +24995,21 @@ function tooOldMessage(found) {
24933
24995
  return `Command OS needs Claude Code ${MIN_CLAUDE_VERSION} or newer to run a stage. ${seen} Update Claude Code, then reopen Command OS. Nothing was started and nothing was spent.`;
24934
24996
  }
24935
24997
  function enginePath() {
24936
- return path19.join(appDataDir(), "command-os-engine.json");
24998
+ return path18.join(appDataDir(), "command-os-engine.json");
24937
24999
  }
24938
25000
  function readEngineRecord(file2 = enginePath()) {
24939
25001
  try {
24940
- const r = JSON.parse(fs20.readFileSync(file2, "utf8"));
25002
+ const r = JSON.parse(fs19.readFileSync(file2, "utf8"));
24941
25003
  return typeof r?.version === "string" ? r : null;
24942
25004
  } catch {
24943
25005
  return null;
24944
25006
  }
24945
25007
  }
24946
25008
  function writeEngineRecord(rec, file2 = enginePath()) {
24947
- fs20.mkdirSync(path19.dirname(file2), { recursive: true });
24948
- fs20.writeFileSync(file2, JSON.stringify(rec, null, 2), { mode: 384 });
25009
+ fs19.mkdirSync(path18.dirname(file2), { recursive: true });
25010
+ fs19.writeFileSync(file2, JSON.stringify(rec, null, 2), { mode: 384 });
24949
25011
  try {
24950
- fs20.chmodSync(file2, 384);
25012
+ fs19.chmodSync(file2, 384);
24951
25013
  } catch {
24952
25014
  }
24953
25015
  }
@@ -25086,13 +25148,13 @@ async function ensureEngineReady(bin, onNote = () => {
25086
25148
  onNote(`Claude Code ${version} checked out${smoke.model ? ` (${smoke.model})` : ""}. Starting the step.`);
25087
25149
  return { ok: true, version, smoked: true, smokeCostUsd: smoke.costUsd, smokeModel: smoke.model };
25088
25150
  }
25089
- var import_child_process2, fs20, path19, MIN_CLAUDE_VERSION, SMOKE_PROMPT;
25151
+ var import_child_process2, fs19, path18, MIN_CLAUDE_VERSION, SMOKE_PROMPT;
25090
25152
  var init_claude_cli = __esm({
25091
25153
  "src/claude-cli.ts"() {
25092
25154
  "use strict";
25093
25155
  import_child_process2 = require("child_process");
25094
- fs20 = __toESM(require("fs"));
25095
- path19 = __toESM(require("path"));
25156
+ fs19 = __toESM(require("fs"));
25157
+ path18 = __toESM(require("path"));
25096
25158
  init_credentials_store();
25097
25159
  init_claude_locate();
25098
25160
  MIN_CLAUDE_VERSION = "2.1.0";
@@ -25213,7 +25275,7 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
25213
25275
  const progressDir = opts.onProgress ? defaultProgressDir() : void 0;
25214
25276
  if (progressDir) {
25215
25277
  try {
25216
- fs21.rmSync(progressFilePath(progressDir, locationId2), { force: true });
25278
+ fs20.rmSync(progressFilePath(progressDir, locationId2), { force: true });
25217
25279
  } catch {
25218
25280
  }
25219
25281
  }
@@ -25327,13 +25389,13 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
25327
25389
  });
25328
25390
  });
25329
25391
  }
25330
- var import_child_process3, fs21, STAFF_NOTIFICATION_RULE, MISSING_STEP_RULE, NO_INVENTED_CAUSE_RULE, STAGE_SPECS, HUMAN_GATE_STAGES;
25392
+ var import_child_process3, fs20, STAFF_NOTIFICATION_RULE, MISSING_STEP_RULE, NO_INVENTED_CAUSE_RULE, STAGE_SPECS, HUMAN_GATE_STAGES;
25331
25393
  var init_stage_runner = __esm({
25332
25394
  "src/stage-runner.ts"() {
25333
25395
  "use strict";
25334
25396
  init_intake_notification();
25335
25397
  import_child_process3 = require("child_process");
25336
- fs21 = __toESM(require("fs"));
25398
+ fs20 = __toESM(require("fs"));
25337
25399
  init_stage_boundary();
25338
25400
  init_plan_guide();
25339
25401
  init_question_set();
@@ -28410,19 +28472,6 @@ async function readDailyBrief(registry2, options = {}) {
28410
28472
  return { brief, ownDay, accounts: { total: roster.filter((r) => !r.pending).length, unread: liveRead?.unreachable?.length ?? 0 } };
28411
28473
  }
28412
28474
  function registerDailyBriefTools(server2, registry2) {
28413
- const recordTool = server2.tool(
28414
- "record_brief_answers",
28415
- "Save up to 50 rows from your Gmail or Google Drive chat brief on this machine, one source per call. Replaces that source's previous rows; makes no provider calls. Record at most 50 rows per source.",
28416
- BriefAnswersInput.shape,
28417
- async (input) => {
28418
- try {
28419
- return jsonResponse(recordBriefAnswers(input));
28420
- } catch (error) {
28421
- return errorResponse(error);
28422
- }
28423
- }
28424
- );
28425
- if (recordTool) recordTool.inputSchema = BriefAnswersInput;
28426
28475
  safeTool(
28427
28476
  server2,
28428
28477
  "daily_brief",
@@ -28434,7 +28483,7 @@ function registerDailyBriefTools(server2, registry2) {
28434
28483
  },
28435
28484
  async ({ live, hoursBack, quietAfterDays }) => {
28436
28485
  const { brief } = await readDailyBrief(registry2, { live, hoursBack, quietAfterDays });
28437
- return { ...brief, afterBeyondGoHighLevel: "then call record_brief_answers with what you found, one call per source" };
28486
+ return brief;
28438
28487
  }
28439
28488
  );
28440
28489
  }
@@ -28443,7 +28492,6 @@ var init_daily_brief2 = __esm({
28443
28492
  "src/tools/daily-brief.ts"() {
28444
28493
  "use strict";
28445
28494
  import_zod56 = require("zod");
28446
- init_brief_answers();
28447
28495
  init_tool_helpers();
28448
28496
  init_ghl_client();
28449
28497
  init_agency_profile();
@@ -28463,16 +28511,11 @@ var init_daily_brief2 = __esm({
28463
28511
 
28464
28512
  // src/command-os/connectors/brief-panels.ts
28465
28513
  function briefPanelDeps(input) {
28466
- return {
28467
- stripe: () => stripePanel(input),
28468
- slack: () => slackPanel(input),
28469
- calendar: () => calendarPanel(input),
28470
- chat: (id, name) => chatPanel(id, name)(input)
28471
- };
28514
+ return { stripe: () => stripePanel(input), slack: () => slackPanel(input), calendar: () => calendarPanel(input) };
28472
28515
  }
28473
28516
  function readTimes() {
28474
28517
  try {
28475
- return TimesSchema.parse(JSON.parse(fs22.readFileSync(timesPath(), "utf8")));
28518
+ return TimesSchema.parse(JSON.parse(fs21.readFileSync(timesPath(), "utf8")));
28476
28519
  } catch {
28477
28520
  return {};
28478
28521
  }
@@ -28481,13 +28524,13 @@ function remember(id, readAt) {
28481
28524
  const times = readTimes();
28482
28525
  times[id] = readAt;
28483
28526
  ensureAppDataDir();
28484
- const tmp = `${timesPath()}.${(0, import_node_crypto7.randomUUID)()}.tmp`;
28527
+ const tmp = `${timesPath()}.${(0, import_node_crypto6.randomUUID)()}.tmp`;
28485
28528
  try {
28486
- fs22.writeFileSync(tmp, JSON.stringify(times) + "\n", { mode: 384, flag: "wx" });
28487
- fs22.renameSync(tmp, timesPath());
28529
+ fs21.writeFileSync(tmp, JSON.stringify(times) + "\n", { mode: 384, flag: "wx" });
28530
+ fs21.renameSync(tmp, timesPath());
28488
28531
  } finally {
28489
28532
  try {
28490
- fs22.unlinkSync(tmp);
28533
+ fs21.unlinkSync(tmp);
28491
28534
  } catch {
28492
28535
  }
28493
28536
  }
@@ -28520,50 +28563,31 @@ function livePanel(id, name, read2) {
28520
28563
  };
28521
28564
  }
28522
28565
  function money2(rows2) {
28523
- const totals = /* @__PURE__ */ new Map();
28566
+ const totals2 = /* @__PURE__ */ new Map();
28524
28567
  let unpriced = 0;
28525
28568
  for (const row of rows2) {
28526
28569
  if (row.amount === null || !row.currency) {
28527
28570
  unpriced++;
28528
28571
  continue;
28529
28572
  }
28530
- totals.set(row.currency, (totals.get(row.currency) ?? 0) + row.amount);
28573
+ totals2.set(row.currency, (totals2.get(row.currency) ?? 0) + row.amount);
28531
28574
  }
28532
- return { count: rows2.length, totals: [...totals].map(([currency, amount]) => ({ currency, amount })), unpriced };
28533
- }
28534
- function chatPanel(id, name) {
28535
- return async (_deps) => {
28536
- try {
28537
- const record = readBriefAnswers()[id];
28538
- return {
28539
- id,
28540
- name,
28541
- ok: Boolean(record),
28542
- state: record ? "read" : "not-recorded",
28543
- readAt: record?.readAt ?? null,
28544
- why: record ? "Filled by your last chat brief" : "Nothing recorded yet. Ask Claude: run my morning brief",
28545
- rows: record?.rows ?? [],
28546
- needsYou: []
28547
- };
28548
- } catch {
28549
- return failure(id, name, "The saved chat brief could not be read; ask Claude to record it again.");
28550
- }
28551
- };
28575
+ return { count: rows2.length, totals: [...totals2].map(([currency, amount]) => ({ currency, amount })), unpriced };
28552
28576
  }
28553
28577
  async function readBriefPanels(deps) {
28554
28578
  return Promise.all(CONNECTOR_REGISTRY.flatMap((entry) => entry.panel ? [entry.panel(briefPanelDeps(deps))] : []));
28555
28579
  }
28556
- var fs22, path20, import_node_crypto7, import_zod57, MoneySchema, BriefPanelSchema, TimesSchema, timesPath, NotConnected, safeLink, amountText, stripePanel, slackPanel, calendarPanel;
28580
+ var fs21, path19, import_node_crypto6, import_zod57, MoneySchema, TotalsSchema, SummarySchema, BriefPanelSchema, TimesSchema, timesPath, NotConnected, safeLink, amountText, stripePanel, slackPanel, calendarPanel;
28557
28581
  var init_brief_panels = __esm({
28558
28582
  "src/command-os/connectors/brief-panels.ts"() {
28559
28583
  "use strict";
28560
28584
  init_brief_deadline();
28561
- fs22 = __toESM(require("node:fs"));
28562
- path20 = __toESM(require("node:path"));
28563
- import_node_crypto7 = require("node:crypto");
28585
+ fs21 = __toESM(require("node:fs"));
28586
+ path19 = __toESM(require("node:path"));
28587
+ import_node_crypto6 = require("node:crypto");
28564
28588
  import_zod57 = require("zod");
28565
28589
  init_credentials_store();
28566
- init_brief_answers();
28590
+ init_brief_row();
28567
28591
  init_registry();
28568
28592
  init_store2();
28569
28593
  init_handlers();
@@ -28573,6 +28597,17 @@ var init_brief_panels = __esm({
28573
28597
  init_daily_brief2();
28574
28598
  init_agency_profile();
28575
28599
  MoneySchema = import_zod57.z.object({ count: import_zod57.z.number().int().nonnegative(), totals: import_zod57.z.array(import_zod57.z.object({ currency: import_zod57.z.string(), amount: import_zod57.z.number() })), unpriced: import_zod57.z.number().int().nonnegative() });
28600
+ TotalsSchema = import_zod57.z.array(import_zod57.z.object({ currency: import_zod57.z.string(), amount: import_zod57.z.number() }));
28601
+ SummarySchema = import_zod57.z.object({
28602
+ mrr: TotalsSchema,
28603
+ mrrUnpriced: import_zod57.z.number().int().nonnegative(),
28604
+ byProduct: import_zod57.z.array(import_zod57.z.object({ name: import_zod57.z.string(), subscribers: import_zod57.z.number().int().nonnegative(), currency: import_zod57.z.string(), monthly: import_zod57.z.number() })),
28605
+ received7: import_zod57.z.object({ count: import_zod57.z.number().int().nonnegative(), totals: TotalsSchema }),
28606
+ received30: import_zod57.z.object({ count: import_zod57.z.number().int().nonnegative(), totals: TotalsSchema }),
28607
+ recurring30: TotalsSchema,
28608
+ oneOff30: TotalsSchema,
28609
+ failed30: import_zod57.z.number().int().nonnegative()
28610
+ });
28576
28611
  BriefPanelSchema = import_zod57.z.object({
28577
28612
  id: import_zod57.z.string(),
28578
28613
  name: import_zod57.z.string(),
@@ -28584,10 +28619,10 @@ var init_brief_panels = __esm({
28584
28619
  why: import_zod57.z.string().optional(),
28585
28620
  rows: import_zod57.z.array(BriefRowSchema),
28586
28621
  needsYou: import_zod57.z.array(BriefRowSchema),
28587
- money: import_zod57.z.object({ owed: MoneySchema, renewals: MoneySchema }).optional()
28622
+ money: import_zod57.z.object({ owed: MoneySchema, renewals: MoneySchema, summary: SummarySchema.optional() }).optional()
28588
28623
  });
28589
28624
  TimesSchema = import_zod57.z.record(import_zod57.z.string(), import_zod57.z.iso.datetime({ offset: true }));
28590
- timesPath = () => path20.join(appDataDir(), "brief-read-times.json");
28625
+ timesPath = () => path19.join(appDataDir(), "brief-read-times.json");
28591
28626
  NotConnected = class extends Error {
28592
28627
  constructor() {
28593
28628
  super("not connected");
@@ -28602,7 +28637,15 @@ var init_brief_panels = __esm({
28602
28637
  stripePanel = livePanel("stripe", "Stripe", async ({ now, signal }) => {
28603
28638
  if (!listConnectors({ strict: true }).some((c) => c.system === "stripe")) throw new NotConnected();
28604
28639
  return withKey("stripe", async (key) => {
28605
- const result = await readStripe(stripeFetcher(key, signal));
28640
+ const fetcher = stripeFetcher(key, signal);
28641
+ const [result, paid] = await Promise.all([readStripe(fetcher), readStripeMoney(fetcher, now).then(
28642
+ (value) => ({ value, why: "" }),
28643
+ (error) => {
28644
+ if (error instanceof Error && error.name === "TimeoutError" || signal?.aborted) throw error;
28645
+ const text2 = error instanceof Error ? error.message : "";
28646
+ return { value: null, why: /401|403|permission/i.test(text2) ? "Money figures need Read access to Charges and Products on your Stripe key; add them in Stripe and the figures appear on the next refresh." : /more records than this read can cover/.test(text2) ? "Money figures are not shown: this account has more payments or products than one read covers." : "Money figures could not be read this time; try Refresh." };
28647
+ }
28648
+ )]);
28606
28649
  const names = new Map(result.customers.map((c) => [c.id, c.name || c.email || c.id]));
28607
28650
  const owed = outstanding(result.invoices, now);
28608
28651
  const renewals = renewalsWithStale(result.subs, 30, now);
@@ -28614,8 +28657,12 @@ var init_brief_panels = __esm({
28614
28657
  return {
28615
28658
  rows: [...owed.map(invoiceRow), ...renewals.due.map((r) => ({ text: `${names.get(r.customerId) ?? r.customerId}: ${r.cancelling ? "cancels" : "renews"} at ${amountText(r.amount, r.currency)}`, when: r.renewsAt }))],
28616
28659
  needsYou: owed.filter((i) => i.daysOverdue !== null).map(invoiceRow),
28617
- money: { owed: money2(owed), renewals: money2(renewals.due) },
28618
- ...renewals.stale.length ? { why: `${renewals.stale.length} subscriptions have a past period end; they are excluded from renewals due.` } : {}
28660
+ money: {
28661
+ owed: money2(owed),
28662
+ renewals: money2(renewals.due),
28663
+ ...paid.value ? { summary: moneySummary(result.subs, result.invoices, paid.value.charges, paid.value.products, now) } : {}
28664
+ },
28665
+ ...renewals.stale.length || paid.why ? { why: [paid.why, renewals.stale.length ? `${renewals.stale.length} subscriptions have a past period end; they are excluded from renewals due.` : ""].filter(Boolean).join(" ") } : {}
28619
28666
  };
28620
28667
  });
28621
28668
  });
@@ -28716,7 +28763,7 @@ var init_client_capabilities = __esm({
28716
28763
  { key: "reputation", label: "Reputation and content", blurb: "Reviews, social posts and the blog." },
28717
28764
  { key: "health", label: "Health and handoff", blurb: "Proving it works, keeping it clean, and handing it over." }
28718
28765
  ];
28719
- N = (label, path42, params, key, nameField, version) => ({ label, path: path42, params, key, nameField, version });
28766
+ N = (label, path41, params, key, nameField, version) => ({ label, path: path41, params, key, nameField, version });
28720
28767
  AI2 = "2021-04-15";
28721
28768
  CAPABILITIES = [
28722
28769
  // ── Set up ──────────────────────────────────────────────────────────────
@@ -28977,7 +29024,7 @@ var require_package = __commonJS({
28977
29024
  "package.json"(exports2, module2) {
28978
29025
  module2.exports = {
28979
29026
  name: "@elitedcs/ghl-mcp",
28980
- version: "3.84.5",
29027
+ version: "3.84.7",
28981
29028
  mcpName: "io.github.drjerryrelth/ghl-command",
28982
29029
  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.",
28983
29030
  main: "dist/index.js",
@@ -29076,17 +29123,17 @@ var require_package = __commonJS({
29076
29123
  });
29077
29124
 
29078
29125
  // src/package-version.ts
29079
- var fs23, path21, bundledPkg, pkg;
29126
+ var fs22, path20, bundledPkg, pkg;
29080
29127
  var init_package_version = __esm({
29081
29128
  "src/package-version.ts"() {
29082
29129
  "use strict";
29083
- fs23 = __toESM(require("fs"));
29084
- path21 = __toESM(require("path"));
29130
+ fs22 = __toESM(require("fs"));
29131
+ path20 = __toESM(require("path"));
29085
29132
  bundledPkg = require_package();
29086
29133
  pkg = (() => {
29087
29134
  try {
29088
29135
  const onDisk = JSON.parse(
29089
- fs23.readFileSync(path21.resolve(__dirname, "..", "package.json"), "utf8")
29136
+ fs22.readFileSync(path20.resolve(__dirname, "..", "package.json"), "utf8")
29090
29137
  );
29091
29138
  if (typeof onDisk.version === "string" && onDisk.version.length > 0) {
29092
29139
  return { version: onDisk.version };
@@ -29356,6 +29403,7 @@ main.brief{max-width:64rem;margin:auto;padding:0 1.2rem 4rem;color:var(--ink);li
29356
29403
  .brief .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));gap:.7rem;margin-top:1.4rem}
29357
29404
  .brief .stat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:.9rem 1rem}
29358
29405
  .brief .stat .big{display:block;font-family:var(--font-display);font-weight:600;font-size:1.5rem;line-height:1.15;color:var(--heading);font-variant-numeric:tabular-nums}
29406
+ .brief .stat.warn .big{color:var(--warn)}.brief .money-stats{margin:0 0 1rem}
29359
29407
  .brief .stat .lbl{display:block;font-size:var(--fs-label);letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);margin-top:.3rem}
29360
29408
  .brief .stats-meta{margin:.8rem 0 0;font-size:var(--fs-sm);color:var(--ink-3)}
29361
29409
  .brief blockquote{margin:1.2rem 0 0;padding:.2rem 0 .2rem 1rem;border-left:3px solid var(--gold);font-family:var(--font-display);font-size:1.25rem;line-height:1.4;color:var(--heading)}
@@ -29450,6 +29498,8 @@ const panelDate=p=>{
29450
29498
  return line;
29451
29499
  };
29452
29500
  const panelTone=p=>p.state==="read"?"ok":p.state==="not-connected"?"wait":p.state==="not-recorded"?"draft":"warn";
29501
+ const cash=(t)=>{try{return new Intl.NumberFormat(undefined,{style:"currency",currency:t.currency,maximumFractionDigits:Number.isInteger(t.amount)?0:2}).format(t.amount)}catch{return t.currency+" "+t.amount.toFixed(2)}};
29502
+ const cashAll=ts=>ts.length?ts.map(cash).join(" + "):cash({currency:"USD",amount:0});
29453
29503
  const amount=m=>m.totals.length?m.totals.map(t=>t.currency+" "+t.amount.toFixed(2)).join(" + "):m.count?"Total not stated":"No amount due";
29454
29504
  const plural=(n,one,many)=>n+" "+(n===1?one:many);
29455
29505
  /* The work queue's titles carry the client's name ("Fix 2 things the verify
@@ -29523,8 +29573,10 @@ function draw(){
29523
29573
  tile((b.readFrom?.accounts||0)+" of "+data.accounts.total,"accounts read");
29524
29574
  tile(needs.length,"needs you today");
29525
29575
  const stripe=data.panels.find(p=>p.id==="stripe");const money=stripe?.ok?stripe.money:null;
29526
- if(money){tile(amount(money.owed),"owed on "+plural(money.owed.count,"open invoice","open invoices"));tile(money.renewals.count,"renewals within 30 days")}
29527
- else{tile("Not read","open invoices owed");tile("Not read","renewals within 30 days")}
29576
+ const sum=money?.summary;
29577
+ if(sum){tile(cashAll(sum.mrr),"monthly recurring revenue");tile(cashAll(sum.received30.totals),"received before Stripe fees, last 30 days")}
29578
+ else if(money){tile(amount(money.owed),"owed on "+plural(money.owed.count,"open invoice","open invoices"));tile(money.renewals.count,"renewals within 30 days")}
29579
+ else{tile("Not read","monthly recurring revenue");tile("Not read","received before Stripe fees, last 30 days")}
29528
29580
  tile(data.accounts.unread,"accounts could not be read");
29529
29581
  tiles.appendChild(el("p",readLine(),"stats-meta"));
29530
29582
  const tb=el("div","","tiles-bar");const total=data.accounts.total||0,got=b.readFrom?.accounts||0;tb.appendChild(el("span",got+" of "+total+" accounts read","lbl"));const bar=el("div","","bar");const fill=el("i");fill.style.width=(total?Math.round(100*got/total):0)+"%";bar.appendChild(fill);tb.appendChild(bar);tiles.appendChild(tb);
@@ -29565,10 +29617,20 @@ function draw(){
29565
29617
  list(card(lc,"By source"),(b.leadsBySource||[]).map(r=>({text:r.client+": "+r.line})),"No source breakdown available.");
29566
29618
  /* One panel per connected system */
29567
29619
  data.panels.forEach(p=>{
29568
- const s=section(root,"panel-"+p.id,"Connected system",p.name,"",panelDate(p));
29620
+ const isMoney=p.id==="stripe";
29621
+ const s=section(root,"panel-"+p.id,isMoney?"From Stripe":"Connected system",isMoney?"Money":p.name,"",panelDate(p));
29569
29622
  const head=el("div","","panel-head");head.appendChild(el("p","Results from "+p.name+" for this brief.","intro"));
29570
29623
  const button=el("button","Refresh "+p.name,"refresh");button.type="button";button.dataset.refresh=p.id;button.onclick=()=>refreshPanel(p.id,button);head.appendChild(button);s.appendChild(head);
29571
29624
  const c=card(s,"");
29625
+ const sm=p.id==="stripe"&&p.ok?p.money?.summary:null;
29626
+ if(sm){const g=el("div","","stats money-stats");const st=(v,l,w)=>{const b=el("div","","stat"+(w?" warn":""));b.appendChild(el("strong",String(v),"big"));b.appendChild(el("span",l,"lbl"));g.appendChild(b)};
29627
+ st(cashAll(sm.mrr),"monthly recurring revenue");st(cashAll(sm.received7.totals),"received before Stripe fees, last 7 days \xB7 "+plural(sm.received7.count,"payment","payments"));
29628
+ st(cashAll(sm.received30.totals),"received before Stripe fees, last 30 days \xB7 "+plural(sm.received30.count,"payment","payments"));st(sm.failed30,"failed payment attempts, last 30 days (Stripe retries count each time)",sm.failed30>0);c.appendChild(g);
29629
+ if(sm.byProduct.length){const t=el("table","","rows");const hr=el("tr");["Product","Subscribers","Monthly"].forEach(h=>hr.appendChild(el("th",h)));t.appendChild(hr);
29630
+ sm.byProduct.forEach(r=>{const tr=el("tr");tr.appendChild(el("td",r.name));tr.appendChild(el("td",String(r.subscribers),"num"));tr.appendChild(el("td",cash({currency:r.currency,amount:r.monthly}),"num"));t.appendChild(tr)});c.appendChild(t)}
29631
+ const split=el("table");const srow=(k,v)=>{const tr=el("tr");tr.appendChild(el("th",k));tr.appendChild(el("td",v,"num"));split.appendChild(tr)};
29632
+ srow("Subscription invoices paid, last 30 days",cashAll(sm.recurring30));srow("Everything else received, last 30 days",cashAll(sm.oneOff30));c.appendChild(split);
29633
+ c.appendChild(el("p","MRR is list price per month for active and past-due subscriptions. Everything else received is money in minus subscription invoices paid, never below zero."+(sm.mrrUnpriced?" "+plural(sm.mrrUnpriced,"line has no fixed price and is","lines have no fixed price and are")+" not counted.":""),"intro"))}
29572
29634
  if(p.id==="stripe"&&p.ok&&p.money){const t=el("table");const row=(k,v)=>{const tr=el("tr");tr.appendChild(el("th",k));tr.appendChild(el("td",v,"num"));t.appendChild(tr)};
29573
29635
  row(plural(p.money.owed.count,"open invoice","open invoices"),amount(p.money.owed));row(plural(p.money.renewals.count,"renewal within 30 days","renewals within 30 days"),amount(p.money.renewals));
29574
29636
  if(p.money.owed.unpriced||p.money.renewals.unpriced)row("Amounts not stated",String(p.money.owed.unpriced+p.money.renewals.unpriced));c.appendChild(t)}
@@ -29576,6 +29638,7 @@ function draw(){
29576
29638
  if(p.id==="stripe")rowsTable(c,marked.map(splitRow),["Customer","What","When"],p.ok?"No items returned by this source.":"");
29577
29639
  else list(c,marked,p.ok?"No items returned by this source.":"");
29578
29640
  });
29641
+ const mail=section(root,"mail","Mail, files and calendar","In your Claude brief","");mail.appendChild(el("p","Your Claude reads your mail, files and calendar in its own morning brief. Ask it: \u201CRun my morning brief.\u201D","intro"));
29579
29642
  highlight();
29580
29643
  }
29581
29644
  /* The active pill follows the section in view. */
@@ -29679,15 +29742,15 @@ async function loadBriefDashboard(registry2, now = /* @__PURE__ */ new Date(), s
29679
29742
  }
29680
29743
  async function secretsKnownToThisProcess(registry2, extras = []) {
29681
29744
  const secrets = /* @__PURE__ */ new Set();
29682
- const add = (key) => {
29745
+ const add2 = (key) => {
29683
29746
  if (typeof key !== "string" || !key.trim()) throw new Error("A saved credential could not be read.");
29684
29747
  secrets.add(key);
29685
29748
  };
29686
29749
  const addOptional = (key) => {
29687
29750
  if (typeof key === "string" && !key.trim()) return;
29688
- add(key);
29751
+ add2(key);
29689
29752
  };
29690
- extras.forEach(add);
29753
+ extras.forEach(add2);
29691
29754
  const credentialFields = [
29692
29755
  ["license_key", "GHL_LICENSE_KEY"],
29693
29756
  ["ghl_api_key", "GHL_API_KEY"],
@@ -29708,14 +29771,14 @@ async function secretsKnownToThisProcess(registry2, extras = []) {
29708
29771
  }
29709
29772
  for (const { system } of listConnectors({ strict: true })) {
29710
29773
  await withKey(system, async (key) => {
29711
- add(key);
29774
+ add2(key);
29712
29775
  });
29713
29776
  }
29714
29777
  if (calendarConnectionStatus().connected) {
29715
29778
  await withCalendarSecret(async (secret) => {
29716
- add(secret.clientId);
29717
- add(secret.clientSecret);
29718
- add(secret.refreshToken);
29779
+ add2(secret.clientId);
29780
+ add2(secret.clientSecret);
29781
+ add2(secret.refreshToken);
29719
29782
  });
29720
29783
  }
29721
29784
  if (registry2) {
@@ -29727,7 +29790,7 @@ async function secretsKnownToThisProcess(registry2, extras = []) {
29727
29790
  for (const { locationId: locationId2 } of locations) {
29728
29791
  const token2 = registry2.getToken(locationId2);
29729
29792
  if (!token2) throw new Error("Account credentials could not be read.");
29730
- add(token2.apiKey);
29793
+ add2(token2.apiKey);
29731
29794
  }
29732
29795
  const agency = registry2.getAgencyKey();
29733
29796
  if (agency !== void 0) addOptional(agency);
@@ -31311,7 +31374,7 @@ function scrubForClient(text2) {
31311
31374
  }
31312
31375
  function clientNextSteps(items) {
31313
31376
  const steps = [];
31314
- const add = (s) => {
31377
+ const add2 = (s) => {
31315
31378
  if (s && !steps.includes(s)) steps.push(s);
31316
31379
  };
31317
31380
  for (const it of items) {
@@ -31319,12 +31382,12 @@ function clientNextSteps(items) {
31319
31382
  if (it.state === "waiting") {
31320
31383
  const who = scrubForClient(it.resolvedBy ?? "");
31321
31384
  if (who) {
31322
- add(`${it.title}: ${who}${it.roughly ? ` \u2014 roughly ${scrubForClient(it.roughly)}` : ""}`);
31385
+ add2(`${it.title}: ${who}${it.roughly ? ` \u2014 roughly ${scrubForClient(it.roughly)}` : ""}`);
31323
31386
  continue;
31324
31387
  }
31325
31388
  }
31326
31389
  const rule5 = NEXT_STEP_RULES.find((r) => r.re.test(it.sentence));
31327
- add(rule5 ? rule5.step : `Confirm "${it.title}" with your team once the item above has been sorted.`);
31390
+ add2(rule5 ? rule5.step : `Confirm "${it.title}" with your team once the item above has been sorted.`);
31328
31391
  }
31329
31392
  return steps;
31330
31393
  }
@@ -31659,11 +31722,11 @@ var init_client_status = __esm({
31659
31722
 
31660
31723
  // src/command-os/client-status-placement.ts
31661
31724
  function statusStorePath(base = appDataDir()) {
31662
- return path22.join(base, "client-status.json");
31725
+ return path21.join(base, "client-status.json");
31663
31726
  }
31664
31727
  function readStatusStore(base) {
31665
31728
  try {
31666
- const raw = JSON.parse(fs24.readFileSync(statusStorePath(base), "utf8"));
31729
+ const raw = JSON.parse(fs23.readFileSync(statusStorePath(base), "utf8"));
31667
31730
  if (raw && raw.v === 1 && raw.clients) return raw;
31668
31731
  } catch {
31669
31732
  }
@@ -31671,8 +31734,8 @@ function readStatusStore(base) {
31671
31734
  }
31672
31735
  function writeStatusStore(store, base) {
31673
31736
  const file2 = statusStorePath(base);
31674
- fs24.mkdirSync(path22.dirname(file2), { recursive: true, mode: 448 });
31675
- fs24.writeFileSync(file2, JSON.stringify(store, null, 2), { mode: 384 });
31737
+ fs23.mkdirSync(path21.dirname(file2), { recursive: true, mode: 448 });
31738
+ fs23.writeFileSync(file2, JSON.stringify(store, null, 2), { mode: 384 });
31676
31739
  }
31677
31740
  function readStatusRecord(locationId2, base) {
31678
31741
  return readStatusStore(base).clients[locationId2] ?? { locationId: locationId2 };
@@ -31704,9 +31767,9 @@ function describePlacement(placement) {
31704
31767
  return `A real page inside the client's own GoHighLevel account, at /${placement.slug ?? STATUS_SLUG}${placement.publicUrl ? ` \u2014 ${placement.publicUrl}` : ""}. Every re-check replaces that one page; it never adds a second copy.`;
31705
31768
  }
31706
31769
  if (placement.kind === "agency-site") {
31707
- return `A file on your own site: ${path22.join(placement.directory, placement.fileName ?? "status.html")}${placement.publicUrl ? `, which you publish at ${placement.publicUrl}` : ""}. The same file is rewritten every time, so the address never changes.`;
31770
+ return `A file on your own site: ${path21.join(placement.directory, placement.fileName ?? "status.html")}${placement.publicUrl ? `, which you publish at ${placement.publicUrl}` : ""}. The same file is rewritten every time, so the address never changes.`;
31708
31771
  }
31709
- return `A page written to ${path22.join(placement.directory, placement.fileName ?? "status.html")} for you to publish as an Artifact from your own Claude${placement.publicUrl ? `, currently at ${placement.publicUrl}` : ""}.`;
31772
+ return `A page written to ${path21.join(placement.directory, placement.fileName ?? "status.html")} for you to publish as an Artifact from your own Claude${placement.publicUrl ? `, currently at ${placement.publicUrl}` : ""}.`;
31710
31773
  }
31711
31774
  function placementReadiness(placement) {
31712
31775
  if (!placement) return ["Choose where this client's page should live: their own GoHighLevel account, your own site, or an Artifact from your own Claude."];
@@ -31765,12 +31828,12 @@ function artifactPublishSteps(filePath, existingUrl) {
31765
31828
  "Send the client the link once. From then on they just revisit it."
31766
31829
  ];
31767
31830
  }
31768
- var fs24, path22, STATUS_SLUG, OUR_HOSTS;
31831
+ var fs23, path21, STATUS_SLUG, OUR_HOSTS;
31769
31832
  var init_client_status_placement = __esm({
31770
31833
  "src/command-os/client-status-placement.ts"() {
31771
31834
  "use strict";
31772
- fs24 = __toESM(require("node:fs"));
31773
- path22 = __toESM(require("node:path"));
31835
+ fs23 = __toESM(require("node:fs"));
31836
+ path21 = __toESM(require("node:path"));
31774
31837
  init_credentials_store();
31775
31838
  init_client_status();
31776
31839
  STATUS_SLUG = "status";
@@ -31790,7 +31853,7 @@ var init_client_status_placement = __esm({
31790
31853
  // src/build-contract.ts
31791
31854
  function contentHash(value) {
31792
31855
  const canonical2 = (v) => Array.isArray(v) ? v.map(canonical2) : v && typeof v === "object" ? Object.fromEntries(Object.keys(v).sort().filter((k) => v[k] !== void 0).map((k) => [k, canonical2(v[k])])) : v;
31793
- return (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(canonical2(value)) ?? "null").digest("hex");
31856
+ return (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(canonical2(value)) ?? "null").digest("hex");
31794
31857
  }
31795
31858
  function assertBuildApproval(approval, inputHash) {
31796
31859
  if (!approval?.at) throw new Error("Approve building before running Build.");
@@ -31965,11 +32028,11 @@ function executablePlanLines(saved) {
31965
32028
  for (const w of preview?.workflows ?? []) for (const m of [...w.manual ?? [], ...w.needsContent ?? []]) lines.push(`Unresolved: ${w.name || names.get(w.ref) || "Unnamed workflow"}. ${m.reason}`);
31966
32029
  return lines.map(sentence);
31967
32030
  }
31968
- var import_node_crypto8, import_node_fs3, import_node_path3, INTAKE_CHANGED;
32031
+ var import_node_crypto7, import_node_fs3, import_node_path3, INTAKE_CHANGED;
31969
32032
  var init_build_contract = __esm({
31970
32033
  "src/build-contract.ts"() {
31971
32034
  "use strict";
31972
- import_node_crypto8 = require("node:crypto");
32035
+ import_node_crypto7 = require("node:crypto");
31973
32036
  import_node_fs3 = require("node:fs");
31974
32037
  import_node_path3 = require("node:path");
31975
32038
  init_credentials_store();
@@ -32229,30 +32292,30 @@ var init_client_status_page = __esm({
32229
32292
 
32230
32293
  // src/command-os/client-status-publish.ts
32231
32294
  function handoffSnapshotDir(base = appDataDir()) {
32232
- return path23.join(base, "handoffs");
32295
+ return path22.join(base, "handoffs");
32233
32296
  }
32234
32297
  function handoffSnapshotPath(locationId2, base) {
32235
- return path23.join(handoffSnapshotDir(base), `${locationId2}-handoff.json`);
32298
+ return path22.join(handoffSnapshotDir(base), `${locationId2}-handoff.json`);
32236
32299
  }
32237
32300
  function saveHandoffSnapshot(saved, base) {
32238
32301
  const file2 = handoffSnapshotPath(saved.locationId, base);
32239
- fs25.mkdirSync(path23.dirname(file2), { recursive: true, mode: 448 });
32240
- fs25.writeFileSync(file2, JSON.stringify(saved, null, 2), { mode: 384 });
32302
+ fs24.mkdirSync(path22.dirname(file2), { recursive: true, mode: 448 });
32303
+ fs24.writeFileSync(file2, JSON.stringify(saved, null, 2), { mode: 384 });
32241
32304
  return file2;
32242
32305
  }
32243
32306
  function readHandoffSnapshot(locationId2, base) {
32244
32307
  try {
32245
- return JSON.parse(fs25.readFileSync(handoffSnapshotPath(locationId2, base), "utf8"));
32308
+ return JSON.parse(fs24.readFileSync(handoffSnapshotPath(locationId2, base), "utf8"));
32246
32309
  } catch {
32247
32310
  return null;
32248
32311
  }
32249
32312
  }
32250
32313
  function localCopyPath(locationId2, base = appDataDir()) {
32251
- return path23.join(base, "client-status", `${locationId2}-status.html`);
32314
+ return path22.join(base, "client-status", `${locationId2}-status.html`);
32252
32315
  }
32253
32316
  function readVerifyOutcome(locationId2, base = appDataDir()) {
32254
32317
  try {
32255
- const st = JSON.parse(fs25.readFileSync(path23.join(base, "cockpit-state.json"), "utf8"));
32318
+ const st = JSON.parse(fs24.readFileSync(path22.join(base, "cockpit-state.json"), "utf8"));
32256
32319
  const o = st.outcomes?.[`${locationId2}:4`];
32257
32320
  if (!o) return null;
32258
32321
  const src = o.plain ?? { summary: o.summary, issues: o.issues };
@@ -32262,9 +32325,9 @@ function readVerifyOutcome(locationId2, base = appDataDir()) {
32262
32325
  }
32263
32326
  }
32264
32327
  function writeFileFor(dir, fileName, html2) {
32265
- fs25.mkdirSync(dir, { recursive: true });
32266
- const file2 = path23.join(dir, fileName);
32267
- fs25.writeFileSync(file2, html2);
32328
+ fs24.mkdirSync(dir, { recursive: true });
32329
+ const file2 = path22.join(dir, fileName);
32330
+ fs24.writeFileSync(file2, html2);
32268
32331
  return file2;
32269
32332
  }
32270
32333
  async function refreshClientStatus(opts) {
@@ -32300,7 +32363,7 @@ async function refreshClientStatus(opts) {
32300
32363
  record.preparedSentences = input.items.map((i) => i.sentence);
32301
32364
  if (!opts.dryRun) saveStatusRecord({ ...record, locationId: opts.locationId }, opts.base);
32302
32365
  const localPath = localCopyPath(opts.locationId, opts.base);
32303
- if (!opts.dryRun) writeFileFor(path23.dirname(localPath), path23.basename(localPath), html2);
32366
+ if (!opts.dryRun) writeFileFor(path22.dirname(localPath), path22.basename(localPath), html2);
32304
32367
  const placement = record.placement;
32305
32368
  const missing = placementReadiness(placement);
32306
32369
  if (!placement || missing.length) {
@@ -32347,7 +32410,7 @@ async function publishTo(placement, input, html2, opts) {
32347
32410
  if (placement.kind === "agency-site") {
32348
32411
  assertNotOurHost(placement.publicUrl, "The address you chose for this page");
32349
32412
  const fileName = placement.fileName ?? "status.html";
32350
- const destinationPath = opts.dryRun ? path23.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
32413
+ const destinationPath = opts.dryRun ? path22.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
32351
32414
  return {
32352
32415
  ...placement.publicUrl && { url: placement.publicUrl },
32353
32416
  destinationPath,
@@ -32361,7 +32424,7 @@ async function publishTo(placement, input, html2, opts) {
32361
32424
  const safety = artifactSafety(html2);
32362
32425
  if (!safety.ok) throw new Error(safety.problems.join(" "));
32363
32426
  const fileName = placement.fileName ?? "status.html";
32364
- const destinationPath = opts.dryRun ? path23.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
32427
+ const destinationPath = opts.dryRun ? path22.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
32365
32428
  assertNotOurHost(placement.publicUrl, "The Artifact link saved for this client");
32366
32429
  return {
32367
32430
  ...placement.publicUrl && { url: placement.publicUrl },
@@ -32402,13 +32465,13 @@ async function refreshAfterVerify(locationId2, accountName, emit2, base, approve
32402
32465
  emit2(`The client's status page was not updated: ${e instanceof Error ? e.message : String(e)}`);
32403
32466
  }
32404
32467
  }
32405
- var fs25, path23;
32468
+ var fs24, path22;
32406
32469
  var init_client_status_publish = __esm({
32407
32470
  "src/command-os/client-status-publish.ts"() {
32408
32471
  "use strict";
32409
32472
  init_publication_proof();
32410
- fs25 = __toESM(require("node:fs"));
32411
- path23 = __toESM(require("node:path"));
32473
+ fs24 = __toESM(require("node:fs"));
32474
+ path22 = __toESM(require("node:path"));
32412
32475
  init_credentials_store();
32413
32476
  init_branding();
32414
32477
  init_client_status();
@@ -32487,11 +32550,11 @@ var init_handoff_snapshot = __esm({
32487
32550
  // src/build-obligations.ts
32488
32551
  function fileFor(id) {
32489
32552
  if (!/^[a-zA-Z0-9_-]+$/.test(id)) throw new Error("Choose a registered client.");
32490
- return path24.join(appDataDir(), "build-obligations", id + ".json");
32553
+ return path23.join(appDataDir(), "build-obligations", id + ".json");
32491
32554
  }
32492
32555
  function readBuildObligations(id) {
32493
32556
  try {
32494
- const data = JSON.parse(fs26.readFileSync(fileFor(id), "utf8"));
32557
+ const data = JSON.parse(fs25.readFileSync(fileFor(id), "utf8"));
32495
32558
  return Array.isArray(data) ? data : [];
32496
32559
  } catch (e) {
32497
32560
  if (e.code === "ENOENT") return [];
@@ -32502,9 +32565,9 @@ function saveBuildObligations(id, items) {
32502
32565
  const merged = new Map(readBuildObligations(id).map((m) => [`${m.type}:${m.ref}`, m]));
32503
32566
  for (const item of items) merged.set(`${item.type}:${item.ref}`, item);
32504
32567
  const file2 = fileFor(id);
32505
- fs26.mkdirSync(path24.dirname(file2), { recursive: true });
32506
- fs26.writeFileSync(file2 + ".tmp", JSON.stringify([...merged.values()], null, 2), { mode: 384 });
32507
- fs26.renameSync(file2 + ".tmp", file2);
32568
+ fs25.mkdirSync(path23.dirname(file2), { recursive: true });
32569
+ fs25.writeFileSync(file2 + ".tmp", JSON.stringify([...merged.values()], null, 2), { mode: 384 });
32570
+ fs25.renameSync(file2 + ".tmp", file2);
32508
32571
  }
32509
32572
  function planObjectRefs(plan) {
32510
32573
  const refs = /* @__PURE__ */ new Set();
@@ -32529,16 +32592,16 @@ function reconcileBuildObligations(id, checks, currentPlan) {
32529
32592
  item.type === "workflow-manual" && Array.isArray(workflows) && workflows.some((workflow) => item.ref.startsWith(`${workflow.name}:`) && /^\d+$/.test(item.ref.slice(workflow.name.length + 1)));
32530
32593
  const remaining = readBuildObligations(id).filter((item) => stillPlanned(item) && !checks.some((c) => c.ref === item.ref && c.type === item.type && c.ok === true && typeof c.evidence === "string" && c.evidence.trim()));
32531
32594
  const file2 = fileFor(id);
32532
- fs26.mkdirSync(path24.dirname(file2), { recursive: true });
32533
- fs26.writeFileSync(file2 + ".tmp", JSON.stringify(remaining, null, 2), { mode: 384 });
32534
- fs26.renameSync(file2 + ".tmp", file2);
32595
+ fs25.mkdirSync(path23.dirname(file2), { recursive: true });
32596
+ fs25.writeFileSync(file2 + ".tmp", JSON.stringify(remaining, null, 2), { mode: 384 });
32597
+ fs25.renameSync(file2 + ".tmp", file2);
32535
32598
  }
32536
- var fs26, path24;
32599
+ var fs25, path23;
32537
32600
  var init_build_obligations = __esm({
32538
32601
  "src/build-obligations.ts"() {
32539
32602
  "use strict";
32540
- fs26 = __toESM(require("node:fs"));
32541
- path24 = __toESM(require("node:path"));
32603
+ fs25 = __toESM(require("node:fs"));
32604
+ path23 = __toESM(require("node:path"));
32542
32605
  init_credentials_store();
32543
32606
  }
32544
32607
  });
@@ -32548,7 +32611,7 @@ function engineRepair(version) {
32548
32611
  return !version ? CLAUDE_REPAIR_MESSAGES[0] : !meetsFloor(version) ? CLAUDE_REPAIR_MESSAGES[1] : CLAUDE_REPAIR_MESSAGES[2];
32549
32612
  }
32550
32613
  function keyFingerprint(key) {
32551
- return (0, import_node_crypto9.createHash)("sha256").update(key).digest("hex");
32614
+ return (0, import_node_crypto8.createHash)("sha256").update(key).digest("hex");
32552
32615
  }
32553
32616
  async function clientPreflight(registry2, locationId2) {
32554
32617
  const lines = [];
@@ -32615,7 +32678,7 @@ async function agencyConnectionReady(registry2, companyId) {
32615
32678
  return false;
32616
32679
  }
32617
32680
  }
32618
- var import_node_crypto9, CLAUDE_REPAIR_MESSAGES;
32681
+ var import_node_crypto8, CLAUDE_REPAIR_MESSAGES;
32619
32682
  var init_client_preflight = __esm({
32620
32683
  "src/client-preflight.ts"() {
32621
32684
  "use strict";
@@ -32625,7 +32688,7 @@ var init_client_preflight = __esm({
32625
32688
  init_stage_runner();
32626
32689
  init_tool_filter();
32627
32690
  init_credentials_store();
32628
- import_node_crypto9 = require("node:crypto");
32691
+ import_node_crypto8 = require("node:crypto");
32629
32692
  CLAUDE_REPAIR_MESSAGES = [
32630
32693
  "Install Claude Code from Your agency before reading this source.",
32631
32694
  "Update Claude Code to version 2.1.0 or newer from Your agency.",
@@ -32732,7 +32795,7 @@ function startDesignRun(request, opts = {}) {
32732
32795
  const checked = validateRunRequest(request);
32733
32796
  if (!checked.ok) throw new Error(checked.error);
32734
32797
  request = checked.value;
32735
- const id = (0, import_node_crypto10.randomUUID)();
32798
+ const id = (0, import_node_crypto9.randomUUID)();
32736
32799
  const outDir = (0, import_node_path5.join)(designRunsDir(), id);
32737
32800
  (0, import_node_fs5.mkdirSync)(outDir, { recursive: true });
32738
32801
  const job = { id, status: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString(), outDir, request, tail: [] };
@@ -32799,14 +32862,14 @@ function cancelDesignRun(id) {
32799
32862
  }
32800
32863
  return true;
32801
32864
  }
32802
- var import_node_child_process3, import_node_fs5, import_node_path5, import_node_crypto10, SLUG2, MODEL, JOINED_FLAG, jobs, children;
32865
+ var import_node_child_process3, import_node_fs5, import_node_path5, import_node_crypto9, SLUG2, MODEL, JOINED_FLAG, jobs, children;
32803
32866
  var init_run_jobs = __esm({
32804
32867
  "src/command-os/design/run-jobs.ts"() {
32805
32868
  "use strict";
32806
32869
  import_node_child_process3 = require("node:child_process");
32807
32870
  import_node_fs5 = require("node:fs");
32808
32871
  import_node_path5 = require("node:path");
32809
- import_node_crypto10 = require("node:crypto");
32872
+ import_node_crypto9 = require("node:crypto");
32810
32873
  init_credentials_store();
32811
32874
  init_schema();
32812
32875
  init_brief_validation();
@@ -32834,20 +32897,20 @@ var init_run_expectations = __esm({
32834
32897
 
32835
32898
  // src/run-cost.ts
32836
32899
  function runCostPath() {
32837
- return path25.join(appDataDir(), "command-os-run-cost.jsonl");
32900
+ return path24.join(appDataDir(), "command-os-run-cost.jsonl");
32838
32901
  }
32839
32902
  function recordRunCost(rec, file2 = runCostPath()) {
32840
- fs27.mkdirSync(path25.dirname(file2), { recursive: true });
32841
- fs27.appendFileSync(file2, `${JSON.stringify(rec)}
32903
+ fs26.mkdirSync(path24.dirname(file2), { recursive: true });
32904
+ fs26.appendFileSync(file2, `${JSON.stringify(rec)}
32842
32905
  `, { mode: 384 });
32843
32906
  try {
32844
- fs27.chmodSync(file2, 384);
32907
+ fs26.chmodSync(file2, 384);
32845
32908
  } catch {
32846
32909
  }
32847
32910
  }
32848
32911
  function readRunCosts(file2 = runCostPath()) {
32849
32912
  try {
32850
- return fs27.readFileSync(file2, "utf8").split("\n").filter((l) => l.trim()).map((l) => {
32913
+ return fs26.readFileSync(file2, "utf8").split("\n").filter((l) => l.trim()).map((l) => {
32851
32914
  try {
32852
32915
  return JSON.parse(l);
32853
32916
  } catch {
@@ -32878,12 +32941,12 @@ function costLines(o) {
32878
32941
  if (o.engineCheckRan && o.engineCheckCostUsd === void 0) out.push("Claude readiness check: cost not reported.");
32879
32942
  return out;
32880
32943
  }
32881
- var fs27, path25;
32944
+ var fs26, path24;
32882
32945
  var init_run_cost = __esm({
32883
32946
  "src/run-cost.ts"() {
32884
32947
  "use strict";
32885
- fs27 = __toESM(require("fs"));
32886
- path25 = __toESM(require("path"));
32948
+ fs26 = __toESM(require("fs"));
32949
+ path24 = __toESM(require("path"));
32887
32950
  init_credentials_store();
32888
32951
  }
32889
32952
  });
@@ -33685,9 +33748,9 @@ function presetForBusinessType(type) {
33685
33748
  return "generic";
33686
33749
  }
33687
33750
  }
33688
- function setPath(target, path42, value) {
33751
+ function setPath(target, path41, value) {
33689
33752
  if (value === void 0) return;
33690
- const parts = path42.split(".");
33753
+ const parts = path41.split(".");
33691
33754
  let node = target;
33692
33755
  for (let i = 0; i < parts.length - 1; i++) {
33693
33756
  const k = parts[i];
@@ -34486,17 +34549,17 @@ function planFromPreset(input) {
34486
34549
  }
34487
34550
  function presetsRoot() {
34488
34551
  const candidates = [
34489
- path26.join(__dirname, "..", "skills", "blueprint", "presets"),
34552
+ path25.join(__dirname, "..", "skills", "blueprint", "presets"),
34490
34553
  // dist/ → package root
34491
- path26.join(__dirname, "..", "..", "skills", "blueprint", "presets"),
34554
+ path25.join(__dirname, "..", "..", "skills", "blueprint", "presets"),
34492
34555
  // src/intake-to-build in dev
34493
- path26.join(process.cwd(), "skills", "blueprint", "presets")
34556
+ path25.join(process.cwd(), "skills", "blueprint", "presets")
34494
34557
  ];
34495
- return candidates.find((c) => fs28.existsSync(c)) ?? null;
34558
+ return candidates.find((c) => fs27.existsSync(c)) ?? null;
34496
34559
  }
34497
34560
  function readPresetFile(dir, base) {
34498
34561
  try {
34499
- const raw = JSON.parse(fs28.readFileSync(path26.join(dir, `${base}.preset.json`), "utf8"));
34562
+ const raw = JSON.parse(fs27.readFileSync(path25.join(dir, `${base}.preset.json`), "utf8"));
34500
34563
  if (raw && typeof raw === "object" && typeof raw.presetId === "string" && raw.skeleton) return raw;
34501
34564
  return null;
34502
34565
  } catch {
@@ -34508,7 +34571,7 @@ function loadPresetChoice(requested, briefPreset) {
34508
34571
  if (!dir) {
34509
34572
  return { ok: false, error: "The preset library is not installed with this copy of the tool (skills/blueprint/presets is missing) \u2014 reinstall, or author the plan by hand." };
34510
34573
  }
34511
- const bases = fs28.readdirSync(dir).filter((f) => f.endsWith(".preset.json")).map((f) => f.replace(/\.preset\.json$/, ""));
34574
+ const bases = fs27.readdirSync(dir).filter((f) => f.endsWith(".preset.json")).map((f) => f.replace(/\.preset\.json$/, ""));
34512
34575
  const tryMatch = (want) => {
34513
34576
  const norm6 = slugify2(want);
34514
34577
  for (const base of bases) {
@@ -34539,12 +34602,12 @@ function loadPresetChoice(requested, briefPreset) {
34539
34602
  if (generic) return { ok: true, preset: generic, file: "generic-client.preset.json", note: "Using the generic preset." };
34540
34603
  return { ok: false, error: "No usable preset file was found in the library." };
34541
34604
  }
34542
- var fs28, path26, PRESET_TOKEN_ROOTS, FLAG_ALIASES, INLINE_TOKEN_RE, ADMIN_ROLE_RE, BRIEF_CALENDAR_TYPE_MAP;
34605
+ var fs27, path25, PRESET_TOKEN_ROOTS, FLAG_ALIASES, INLINE_TOKEN_RE, ADMIN_ROLE_RE, BRIEF_CALENDAR_TYPE_MAP;
34543
34606
  var init_plan_from_preset = __esm({
34544
34607
  "src/intake-to-build/plan-from-preset.ts"() {
34545
34608
  "use strict";
34546
- fs28 = __toESM(require("fs"));
34547
- path26 = __toESM(require("path"));
34609
+ fs27 = __toESM(require("fs"));
34610
+ path25 = __toESM(require("path"));
34548
34611
  init_plan();
34549
34612
  init_brief2();
34550
34613
  init_normalizer();
@@ -34644,7 +34707,7 @@ function compute(ans, skip, asm) {
34644
34707
  O.push(o);
34645
34708
  return o;
34646
34709
  }
34647
- function add(id, title2, needs, assumption, fn, fix) {
34710
+ function add2(id, title2, needs, assumption, fn, fix) {
34648
34711
  var missing = needs.filter(function(n) {
34649
34712
  return (n.share ? share(n.id) : raw(n.id)) === null;
34650
34713
  }).map(function(n) {
@@ -34675,7 +34738,7 @@ function compute(ans, skip, asm) {
34675
34738
  }
34676
34739
  F.push({ id, title: title2, monthly: m, assumption: assumption || null, fix });
34677
34740
  }
34678
- add(
34741
+ add2(
34679
34742
  "missed",
34680
34743
  "Calls you never get back to",
34681
34744
  [{ id: "calls_missed" }, { id: "missed_never_return", share: true }],
@@ -34685,7 +34748,7 @@ function compute(ans, skip, asm) {
34685
34748
  },
34686
34749
  "Call answering, day and night"
34687
34750
  );
34688
- add(
34751
+ add2(
34689
34752
  "waited",
34690
34753
  "Enquiries that waited",
34691
34754
  [{ id: "waited_month" }],
@@ -34703,7 +34766,7 @@ function compute(ans, skip, asm) {
34703
34766
  reason: "you told us more quotes were won than were sent \u2014 worth checking before this is priced"
34704
34767
  });
34705
34768
  } else {
34706
- add(
34769
+ add2(
34707
34770
  "quotes",
34708
34771
  "Quotes nobody chases",
34709
34772
  [{ id: "quotes_month" }, { id: "quotes_won" }],
@@ -34714,7 +34777,7 @@ function compute(ans, skip, asm) {
34714
34777
  "Follow-up that runs itself"
34715
34778
  );
34716
34779
  }
34717
- add(
34780
+ add2(
34718
34781
  "noshow",
34719
34782
  "No-shows nobody rebooks",
34720
34783
  [{ id: "booked_month" }, { id: "show_rate", share: true }],
@@ -35867,13 +35930,13 @@ var init_client_intake = __esm({
35867
35930
 
35868
35931
  // src/plan-store.ts
35869
35932
  function plansDir(base = appDataDir()) {
35870
- return path27.join(base, "plans");
35933
+ return path26.join(base, "plans");
35871
35934
  }
35872
35935
  function savePlanRecord(rec, base) {
35873
35936
  const dir = plansDir(base);
35874
- fs29.mkdirSync(dir, { recursive: true, mode: 448 });
35875
- const file2 = path27.join(dir, `${rec.locationId}.json`);
35876
- fs29.writeFileSync(file2, JSON.stringify({ ...rec, contentHash: contentHash(rec.plan), inputHash: rec.inputHash ?? process.env.GHL_COMMAND_INTAKE_HASH, dependencies: rec.dependencies ?? planDependencies(rec.plan) }, null, 2), { mode: 384 });
35937
+ fs28.mkdirSync(dir, { recursive: true, mode: 448 });
35938
+ const file2 = path26.join(dir, `${rec.locationId}.json`);
35939
+ fs28.writeFileSync(file2, JSON.stringify({ ...rec, contentHash: contentHash(rec.plan), inputHash: rec.inputHash ?? process.env.GHL_COMMAND_INTAKE_HASH, dependencies: rec.dependencies ?? planDependencies(rec.plan) }, null, 2), { mode: 384 });
35877
35940
  return file2;
35878
35941
  }
35879
35942
  function savedPlanMatchesScope(saved, current) {
@@ -35888,7 +35951,7 @@ function savedPlanMatchesScope(saved, current) {
35888
35951
  }
35889
35952
  function readSavedPlan(locationId2, base) {
35890
35953
  try {
35891
- return JSON.parse(fs29.readFileSync(path27.join(plansDir(base), `${locationId2}.json`), "utf8"));
35954
+ return JSON.parse(fs28.readFileSync(path26.join(plansDir(base), `${locationId2}.json`), "utf8"));
35892
35955
  } catch {
35893
35956
  return null;
35894
35957
  }
@@ -35911,12 +35974,12 @@ function planSummary(rec) {
35911
35974
  if (wfs.length) parts.push(`workflows: ${wfs.map((w) => `${w.name} (${Array.isArray(w.actions) ? w.actions.length : "?"} actions)`).join("; ")}`);
35912
35975
  return parts.join("\n") || "(plan has no recognisable sections)";
35913
35976
  }
35914
- var fs29, path27;
35977
+ var fs28, path26;
35915
35978
  var init_plan_store = __esm({
35916
35979
  "src/plan-store.ts"() {
35917
35980
  "use strict";
35918
- fs29 = __toESM(require("fs"));
35919
- path27 = __toESM(require("path"));
35981
+ fs28 = __toESM(require("fs"));
35982
+ path26 = __toESM(require("path"));
35920
35983
  init_credentials_store();
35921
35984
  init_build_contract();
35922
35985
  }
@@ -37579,7 +37642,7 @@ function launchCommand(port = 7300) {
37579
37642
  return `npx -y @elitedcs/ghl-mcp@latest dashboard --port=${port}`;
37580
37643
  }
37581
37644
  function installingEntry() {
37582
- return path28.join(__dirname, "index.js");
37645
+ return path27.join(__dirname, "index.js");
37583
37646
  }
37584
37647
  function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
37585
37648
  const cmd = launchCommand(port);
@@ -37587,12 +37650,12 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
37587
37650
  const systemApps = "/Applications";
37588
37651
  let base = home;
37589
37652
  try {
37590
- fs30.accessSync(systemApps, fs30.constants.W_OK);
37653
+ fs29.accessSync(systemApps, fs29.constants.W_OK);
37591
37654
  base = "";
37592
37655
  } catch {
37593
37656
  }
37594
- const appDir = base ? path28.join(home, "Applications", "Command OS.app") : path28.join(systemApps, "Command OS.app");
37595
- const macOSDir = path28.join(appDir, "Contents", "MacOS");
37657
+ const appDir = base ? path27.join(home, "Applications", "Command OS.app") : path27.join(systemApps, "Command OS.app");
37658
+ const macOSDir = path27.join(appDir, "Contents", "MacOS");
37596
37659
  const script = [
37597
37660
  "#!/bin/bash",
37598
37661
  "# GHL Command \u2014 Command OS launcher (regenerate: ghl-mcp install-launcher)",
@@ -37621,13 +37684,13 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
37621
37684
  targetPath: appDir,
37622
37685
  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",
37623
37686
  files: [
37624
- { path: path28.join(macOSDir, "command-os"), contents: script, executable: true },
37625
- { path: path28.join(appDir, "Contents", "Info.plist"), contents: plist, executable: false }
37687
+ { path: path27.join(macOSDir, "command-os"), contents: script, executable: true },
37688
+ { path: path27.join(appDir, "Contents", "Info.plist"), contents: plist, executable: false }
37626
37689
  ]
37627
37690
  };
37628
37691
  }
37629
37692
  if (platform2 === "win32") {
37630
- const target2 = path28.join(home, "Desktop", "Command OS.cmd");
37693
+ const target2 = path27.join(home, "Desktop", "Command OS.cmd");
37631
37694
  return {
37632
37695
  platform: platform2,
37633
37696
  targetPath: target2,
@@ -37640,7 +37703,7 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
37640
37703
  ].join("\r\n"), executable: false }]
37641
37704
  };
37642
37705
  }
37643
- const target = path28.join(home, ".local", "share", "applications", "command-os.desktop");
37706
+ const target = path27.join(home, ".local", "share", "applications", "command-os.desktop");
37644
37707
  return {
37645
37708
  platform: platform2,
37646
37709
  targetPath: target,
@@ -37664,7 +37727,7 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
37664
37727
  function launcherInstalled(port = 7300, platform2 = process.platform, home = os4.homedir()) {
37665
37728
  try {
37666
37729
  const plan = planLauncher(platform2, home, port, installingEntry());
37667
- return plan.files.every((f) => fs30.existsSync(f.path));
37730
+ return plan.files.every((f) => fs29.existsSync(f.path));
37668
37731
  } catch {
37669
37732
  return false;
37670
37733
  }
@@ -37675,8 +37738,8 @@ function installLauncher(argv = []) {
37675
37738
  const plan = planLauncher(process.platform, os4.homedir(), port, installingEntry());
37676
37739
  try {
37677
37740
  for (const f of plan.files) {
37678
- fs30.mkdirSync(path28.dirname(f.path), { recursive: true });
37679
- fs30.writeFileSync(f.path, f.contents, { mode: f.executable ? 493 : 420 });
37741
+ fs29.mkdirSync(path27.dirname(f.path), { recursive: true });
37742
+ fs29.writeFileSync(f.path, f.contents, { mode: f.executable ? 493 : 420 });
37680
37743
  }
37681
37744
  } catch (e) {
37682
37745
  process.stderr.write(`
@@ -37696,47 +37759,47 @@ function installLauncher(argv = []) {
37696
37759
  ].join("\n"));
37697
37760
  return 0;
37698
37761
  }
37699
- var fs30, os4, path28;
37762
+ var fs29, os4, path27;
37700
37763
  var init_launcher = __esm({
37701
37764
  "src/launcher.ts"() {
37702
37765
  "use strict";
37703
- fs30 = __toESM(require("fs"));
37766
+ fs29 = __toESM(require("fs"));
37704
37767
  os4 = __toESM(require("os"));
37705
- path28 = __toESM(require("path"));
37768
+ path27 = __toESM(require("path"));
37706
37769
  }
37707
37770
  });
37708
37771
 
37709
37772
  // src/npx-cache-check.ts
37710
37773
  function defaultNpxCacheDir(env2 = process.env, platform2 = process.platform, home = os5.homedir()) {
37711
37774
  const configured = env2.npm_config_cache?.trim();
37712
- const cache = configured ? configured : platform2 === "win32" ? path29.join(env2.LOCALAPPDATA?.trim() || path29.join(home, "AppData", "Local"), "npm-cache") : path29.join(home, ".npm");
37713
- return path29.join(cache, "_npx");
37775
+ const cache = configured ? configured : platform2 === "win32" ? path28.join(env2.LOCALAPPDATA?.trim() || path28.join(home, "AppData", "Local"), "npm-cache") : path28.join(home, ".npm");
37776
+ return path28.join(cache, "_npx");
37714
37777
  }
37715
37778
  function damagedNpxDownloads(npxDir) {
37716
37779
  let entries;
37717
37780
  try {
37718
- entries = fs31.readdirSync(npxDir, { withFileTypes: true });
37781
+ entries = fs30.readdirSync(npxDir, { withFileTypes: true });
37719
37782
  } catch {
37720
37783
  return [];
37721
37784
  }
37722
37785
  const damaged = [];
37723
37786
  const gone = (p) => {
37724
37787
  try {
37725
- fs31.statSync(p);
37788
+ fs30.statSync(p);
37726
37789
  return false;
37727
37790
  } catch (e) {
37728
37791
  return e.code === "ENOENT";
37729
37792
  }
37730
37793
  };
37731
37794
  for (const entry of entries) {
37732
- const dir = path29.join(npxDir, entry.name);
37733
- const pkg2 = path29.join(dir, PACKAGE_SUBDIR);
37795
+ const dir = path28.join(npxDir, entry.name);
37796
+ const pkg2 = path28.join(dir, PACKAGE_SUBDIR);
37734
37797
  try {
37735
- if (!fs31.statSync(dir).isDirectory() || !fs31.statSync(pkg2).isDirectory()) continue;
37798
+ if (!fs30.statSync(dir).isDirectory() || !fs30.statSync(pkg2).isDirectory()) continue;
37736
37799
  } catch {
37737
37800
  continue;
37738
37801
  }
37739
- if (gone(path29.join(dir, "package.json")) || gone(path29.join(pkg2, "package.json"))) damaged.push(dir);
37802
+ if (gone(path28.join(dir, "package.json")) || gone(path28.join(pkg2, "package.json"))) damaged.push(dir);
37740
37803
  }
37741
37804
  return damaged.sort();
37742
37805
  }
@@ -37745,14 +37808,14 @@ function damagedDownloadLine(dirs) {
37745
37808
  const one = dirs.length === 1;
37746
37809
  return `${one ? "One earlier download" : "Earlier downloads"} of GHL Command on this computer ${one ? "is" : "are"} damaged, which makes Claude say "Connection closed" instead of starting it. Delete ${one ? "this folder" : "these folders"}, then start Claude again: ${dirs.join(" and ")}`;
37747
37810
  }
37748
- var fs31, os5, path29, PACKAGE_SUBDIR;
37811
+ var fs30, os5, path28, PACKAGE_SUBDIR;
37749
37812
  var init_npx_cache_check = __esm({
37750
37813
  "src/npx-cache-check.ts"() {
37751
37814
  "use strict";
37752
- fs31 = __toESM(require("node:fs"));
37815
+ fs30 = __toESM(require("node:fs"));
37753
37816
  os5 = __toESM(require("node:os"));
37754
- path29 = __toESM(require("node:path"));
37755
- PACKAGE_SUBDIR = path29.join("node_modules", "@elitedcs", "ghl-mcp");
37817
+ path28 = __toESM(require("node:path"));
37818
+ PACKAGE_SUBDIR = path28.join("node_modules", "@elitedcs", "ghl-mcp");
37756
37819
  }
37757
37820
  });
37758
37821
 
@@ -37776,7 +37839,7 @@ function defaultIO() {
37776
37839
  npxCacheDir: defaultNpxCacheDir(),
37777
37840
  out: (l) => process.stdout.write(l + "\n"),
37778
37841
  err: (l) => process.stderr.write(l + "\n"),
37779
- rename: (from, to) => fs32.renameSync(from, to),
37842
+ rename: (from, to) => fs31.renameSync(from, to),
37780
37843
  sleep: (ms) => new Promise((r) => setTimeout(r, ms))
37781
37844
  };
37782
37845
  }
@@ -37786,32 +37849,32 @@ function candidateConfigPaths(opts) {
37786
37849
  const file2 = "claude_desktop_config.json";
37787
37850
  const candidates = [];
37788
37851
  if (platform2 === "darwin") {
37789
- candidates.push(path30.join(home, "Library", "Application Support", "Claude", file2));
37852
+ candidates.push(path29.join(home, "Library", "Application Support", "Claude", file2));
37790
37853
  } else if (platform2 === "win32") {
37791
- const appData = opts?.appData ?? process.env.APPDATA ?? path30.join(home, "AppData", "Roaming");
37792
- candidates.push(path30.join(appData, "Claude", file2));
37793
- const localAppData = opts?.localAppData ?? process.env.LOCALAPPDATA ?? path30.join(home, "AppData", "Local");
37794
- const packagesDir = path30.join(localAppData, "Packages");
37854
+ const appData = opts?.appData ?? process.env.APPDATA ?? path29.join(home, "AppData", "Roaming");
37855
+ candidates.push(path29.join(appData, "Claude", file2));
37856
+ const localAppData = opts?.localAppData ?? process.env.LOCALAPPDATA ?? path29.join(home, "AppData", "Local");
37857
+ const packagesDir = path29.join(localAppData, "Packages");
37795
37858
  try {
37796
- for (const entry of fs32.readdirSync(packagesDir)) {
37859
+ for (const entry of fs31.readdirSync(packagesDir)) {
37797
37860
  if (entry.startsWith("Claude_")) {
37798
- candidates.push(path30.join(packagesDir, entry, "LocalCache", "Roaming", "Claude", file2));
37861
+ candidates.push(path29.join(packagesDir, entry, "LocalCache", "Roaming", "Claude", file2));
37799
37862
  }
37800
37863
  }
37801
37864
  } catch {
37802
37865
  }
37803
37866
  } else {
37804
- candidates.push(path30.join(home, ".config", "Claude", file2));
37867
+ candidates.push(path29.join(home, ".config", "Claude", file2));
37805
37868
  }
37806
37869
  return candidates;
37807
37870
  }
37808
37871
  function resolveConfigPath(explicitPath) {
37809
37872
  if (explicitPath) {
37810
- const p = path30.resolve(explicitPath);
37811
- return { configPath: p, exists: fs32.existsSync(p) };
37873
+ const p = path29.resolve(explicitPath);
37874
+ return { configPath: p, exists: fs31.existsSync(p) };
37812
37875
  }
37813
37876
  const candidates = candidateConfigPaths();
37814
- const existing = candidates.filter((c) => fs32.existsSync(c));
37877
+ const existing = candidates.filter((c) => fs31.existsSync(c));
37815
37878
  if (existing.length > 1) {
37816
37879
  throw new InstallStop(
37817
37880
  EXIT_REFUSED,
@@ -37828,22 +37891,22 @@ function resolveConfigPath(explicitPath) {
37828
37891
  function resolveSymlinkPolicy(configPath, explicitPath, home = os6.homedir()) {
37829
37892
  let st;
37830
37893
  try {
37831
- st = fs32.lstatSync(configPath);
37894
+ st = fs31.lstatSync(configPath);
37832
37895
  } catch {
37833
37896
  return configPath;
37834
37897
  }
37835
37898
  if (!st.isSymbolicLink()) return configPath;
37836
37899
  let real;
37837
37900
  try {
37838
- real = fs32.realpathSync(configPath);
37901
+ real = fs31.realpathSync(configPath);
37839
37902
  } catch {
37840
37903
  throw new InstallStop(
37841
37904
  EXIT_REFUSED,
37842
37905
  `${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.`
37843
37906
  );
37844
37907
  }
37845
- const rel = path30.relative(path30.resolve(home), real);
37846
- const outsideHome = rel.startsWith("..") || path30.isAbsolute(rel);
37908
+ const rel = path29.relative(path29.resolve(home), real);
37909
+ const outsideHome = rel.startsWith("..") || path29.isAbsolute(rel);
37847
37910
  if (outsideHome && !explicitPath) {
37848
37911
  throw new InstallStop(
37849
37912
  EXIT_REFUSED,
@@ -37853,8 +37916,8 @@ function resolveSymlinkPolicy(configPath, explicitPath, home = os6.homedir()) {
37853
37916
  return real;
37854
37917
  }
37855
37918
  function readConfigBytes(configPath) {
37856
- const bytes = fs32.readFileSync(configPath);
37857
- const stat = fs32.statSync(configPath);
37919
+ const bytes = fs31.readFileSync(configPath);
37920
+ const stat = fs31.statSync(configPath);
37858
37921
  if (bytes.length >= 2 && (bytes[0] === 255 && bytes[1] === 254 || bytes[0] === 254 && bytes[1] === 255)) {
37859
37922
  throw new InstallStop(
37860
37923
  EXIT_REFUSED,
@@ -37928,23 +37991,23 @@ function backupStamp(now) {
37928
37991
  }
37929
37992
  function chooseBackupPath(configPath, now = /* @__PURE__ */ new Date()) {
37930
37993
  const base = `${configPath}.bak-${backupStamp(now)}`;
37931
- if (!fs32.existsSync(base)) return base;
37994
+ if (!fs31.existsSync(base)) return base;
37932
37995
  for (let i = 2; ; i++) {
37933
37996
  const candidate = `${base}-${i}`;
37934
- if (!fs32.existsSync(candidate)) return candidate;
37997
+ if (!fs31.existsSync(candidate)) return candidate;
37935
37998
  }
37936
37999
  }
37937
38000
  function writeVerifiedBackup(configPath, originalBytes) {
37938
38001
  const backupPath = chooseBackupPath(configPath);
37939
38002
  try {
37940
- fs32.writeFileSync(backupPath, originalBytes);
37941
- const readBack = fs32.readFileSync(backupPath);
38003
+ fs31.writeFileSync(backupPath, originalBytes);
38004
+ const readBack = fs31.readFileSync(backupPath);
37942
38005
  if (!readBack.equals(originalBytes)) {
37943
38006
  throw new Error("backup read-back did not match");
37944
38007
  }
37945
38008
  } catch (e) {
37946
38009
  try {
37947
- fs32.rmSync(backupPath, { force: true });
38010
+ fs31.rmSync(backupPath, { force: true });
37948
38011
  } catch {
37949
38012
  }
37950
38013
  throw new InstallStop(
@@ -37955,7 +38018,7 @@ function writeVerifiedBackup(configPath, originalBytes) {
37955
38018
  return backupPath;
37956
38019
  }
37957
38020
  function sha256(bytes) {
37958
- return (0, import_node_crypto11.createHash)("sha256").update(bytes).digest("hex");
38021
+ return (0, import_node_crypto10.createHash)("sha256").update(bytes).digest("hex");
37959
38022
  }
37960
38023
  function baselineOf(bytes, stat) {
37961
38024
  return { size: stat.size, mtimeMs: stat.mtimeMs, hash: sha256(bytes) };
@@ -37963,9 +38026,9 @@ function baselineOf(bytes, stat) {
37963
38026
  function assertNotStale(configPath, baseline) {
37964
38027
  let ok = false;
37965
38028
  try {
37966
- const st = fs32.statSync(configPath);
38029
+ const st = fs31.statSync(configPath);
37967
38030
  if (st.size === baseline.size && st.mtimeMs === baseline.mtimeMs) {
37968
- ok = sha256(fs32.readFileSync(configPath)) === baseline.hash;
38031
+ ok = sha256(fs31.readFileSync(configPath)) === baseline.hash;
37969
38032
  } else {
37970
38033
  ok = false;
37971
38034
  }
@@ -37980,14 +38043,14 @@ function assertNotStale(configPath, baseline) {
37980
38043
  }
37981
38044
  }
37982
38045
  async function atomicReplace(opts) {
37983
- const dir = path30.dirname(opts.configPath);
37984
- const tempPath = path30.join(dir, `.${path30.basename(opts.configPath)}.tmp-${process.pid}-${(0, import_node_crypto11.randomBytes)(4).toString("hex")}`);
37985
- const fd = fs32.openSync(tempPath, "w");
38046
+ const dir = path29.dirname(opts.configPath);
38047
+ const tempPath = path29.join(dir, `.${path29.basename(opts.configPath)}.tmp-${process.pid}-${(0, import_node_crypto10.randomBytes)(4).toString("hex")}`);
38048
+ const fd = fs31.openSync(tempPath, "w");
37986
38049
  try {
37987
- fs32.writeFileSync(fd, opts.newBytes);
37988
- fs32.fsyncSync(fd);
38050
+ fs31.writeFileSync(fd, opts.newBytes);
38051
+ fs31.fsyncSync(fd);
37989
38052
  } finally {
37990
- fs32.closeSync(fd);
38053
+ fs31.closeSync(fd);
37991
38054
  }
37992
38055
  try {
37993
38056
  for (let attempt = 0; ; attempt++) {
@@ -38012,17 +38075,17 @@ async function atomicReplace(opts) {
38012
38075
  }
38013
38076
  } catch (e) {
38014
38077
  try {
38015
- fs32.rmSync(tempPath, { force: true });
38078
+ fs31.rmSync(tempPath, { force: true });
38016
38079
  } catch {
38017
38080
  }
38018
38081
  throw e;
38019
38082
  }
38020
38083
  try {
38021
- const dirFd = fs32.openSync(dir, "r");
38084
+ const dirFd = fs31.openSync(dir, "r");
38022
38085
  try {
38023
- fs32.fsyncSync(dirFd);
38086
+ fs31.fsyncSync(dirFd);
38024
38087
  } finally {
38025
- fs32.closeSync(dirFd);
38088
+ fs31.closeSync(dirFd);
38026
38089
  }
38027
38090
  } catch {
38028
38091
  }
@@ -38080,7 +38143,7 @@ async function runInstall(argv, ioOverride) {
38080
38143
  try {
38081
38144
  const resolved2 = resolveConfigPath(flags.path);
38082
38145
  const configPath = resolveSymlinkPolicy(resolved2.configPath, flags.path !== void 0);
38083
- const exists = fs32.existsSync(configPath);
38146
+ const exists = fs31.existsSync(configPath);
38084
38147
  let read2 = null;
38085
38148
  let outcome;
38086
38149
  if (exists) {
@@ -38112,7 +38175,7 @@ async function runInstall(argv, ioOverride) {
38112
38175
  return EXIT_OK;
38113
38176
  }
38114
38177
  const backupPath = exists && read2 ? writeVerifiedBackup(configPath, read2.bytes) : null;
38115
- if (!exists) fs32.mkdirSync(path30.dirname(configPath), { recursive: true });
38178
+ if (!exists) fs31.mkdirSync(path29.dirname(configPath), { recursive: true });
38116
38179
  await atomicReplace({
38117
38180
  configPath,
38118
38181
  newBytes,
@@ -38131,14 +38194,14 @@ async function runInstall(argv, ioOverride) {
38131
38194
  return EXIT_ABORTED;
38132
38195
  }
38133
38196
  }
38134
- var fs32, os6, path30, import_node_crypto11, 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;
38197
+ var fs31, os6, path29, import_node_crypto10, 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;
38135
38198
  var init_config_installer = __esm({
38136
38199
  "src/config-installer.ts"() {
38137
38200
  "use strict";
38138
- fs32 = __toESM(require("node:fs"));
38201
+ fs31 = __toESM(require("node:fs"));
38139
38202
  os6 = __toESM(require("node:os"));
38140
- path30 = __toESM(require("node:path"));
38141
- import_node_crypto11 = require("node:crypto");
38203
+ path29 = __toESM(require("node:path"));
38204
+ import_node_crypto10 = require("node:crypto");
38142
38205
  import_node_util = require("node:util");
38143
38206
  import_json5 = __toESM(require("json5"));
38144
38207
  init_npx_cache_check();
@@ -38171,9 +38234,9 @@ function errLine(msg3) {
38171
38234
  function preflightWritable() {
38172
38235
  try {
38173
38236
  const dir = ensureAppDataDir();
38174
- const probe = path31.join(dir, `.write-probe.${process.pid}.${(0, import_crypto2.randomBytes)(4).toString("hex")}`);
38175
- fs33.writeFileSync(probe, "ok");
38176
- fs33.unlinkSync(probe);
38237
+ const probe = path30.join(dir, `.write-probe.${process.pid}.${(0, import_crypto2.randomBytes)(4).toString("hex")}`);
38238
+ fs32.writeFileSync(probe, "ok");
38239
+ fs32.unlinkSync(probe);
38177
38240
  return true;
38178
38241
  } catch (error) {
38179
38242
  errLine(`Config dir is not writable: ${error instanceof Error ? error.message : String(error)}`);
@@ -38442,13 +38505,13 @@ async function runCli(subcommand, argv) {
38442
38505
  return EXIT_USAGE2;
38443
38506
  }
38444
38507
  }
38445
- var import_node_util2, fs33, path31, import_crypto2, EXIT_OK2, EXIT_USAGE2, EXIT_VALIDATION, EXIT_FS, USAGE;
38508
+ var import_node_util2, fs32, path30, import_crypto2, EXIT_OK2, EXIT_USAGE2, EXIT_VALIDATION, EXIT_FS, USAGE;
38446
38509
  var init_cli = __esm({
38447
38510
  "src/cli.ts"() {
38448
38511
  "use strict";
38449
38512
  import_node_util2 = require("node:util");
38450
- fs33 = __toESM(require("fs"));
38451
- path31 = __toESM(require("path"));
38513
+ fs32 = __toESM(require("fs"));
38514
+ path30 = __toESM(require("path"));
38452
38515
  import_crypto2 = require("crypto");
38453
38516
  init_ghl_client();
38454
38517
  init_token_registry();
@@ -38994,11 +39057,11 @@ __export(intake_overlay_exports, {
38994
39057
  writeOverlay: () => writeOverlay
38995
39058
  });
38996
39059
  function overlayPath() {
38997
- return path32.join(appDataDir(), "intake-overlay.json");
39060
+ return path31.join(appDataDir(), "intake-overlay.json");
38998
39061
  }
38999
39062
  function readOverlay() {
39000
39063
  try {
39001
- const raw = JSON.parse(fs34.readFileSync(overlayPath(), "utf8"));
39064
+ const raw = JSON.parse(fs33.readFileSync(overlayPath(), "utf8"));
39002
39065
  if (raw && typeof raw === "object") return raw;
39003
39066
  } catch {
39004
39067
  }
@@ -39006,14 +39069,14 @@ function readOverlay() {
39006
39069
  }
39007
39070
  function writeOverlay(layer) {
39008
39071
  ensureAppDataDir();
39009
- fs34.writeFileSync(overlayPath(), JSON.stringify(layer, null, 2), { mode: 384 });
39072
+ fs33.writeFileSync(overlayPath(), JSON.stringify(layer, null, 2), { mode: 384 });
39010
39073
  }
39011
- var fs34, path32;
39074
+ var fs33, path31;
39012
39075
  var init_intake_overlay = __esm({
39013
39076
  "src/intake-overlay.ts"() {
39014
39077
  "use strict";
39015
- fs34 = __toESM(require("fs"));
39016
- path32 = __toESM(require("path"));
39078
+ fs33 = __toESM(require("fs"));
39079
+ path31 = __toESM(require("path"));
39017
39080
  init_credentials_store();
39018
39081
  }
39019
39082
  });
@@ -39661,7 +39724,7 @@ function registerAssessmentTools(server2, client) {
39661
39724
  const dir = args.outDir ?? (0, import_node_path6.join)((0, import_node_os.homedir)(), "Documents", "assessments");
39662
39725
  (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
39663
39726
  const slug3 = (state.biz || "assessment").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
39664
- const file2 = (0, import_node_path6.join)(dir, `${slug3}-${(0, import_node_crypto12.randomBytes)(4).toString("hex")}.html`);
39727
+ const file2 = (0, import_node_path6.join)(dir, `${slug3}-${(0, import_node_crypto11.randomBytes)(4).toString("hex")}.html`);
39665
39728
  (0, import_node_fs6.writeFileSync)(file2, html2, "utf8");
39666
39729
  return {
39667
39730
  written: file2,
@@ -39684,7 +39747,7 @@ function registerAssessmentTools(server2, client) {
39684
39747
  }
39685
39748
  );
39686
39749
  }
39687
- var import_node_util3, import_zod61, import_node_crypto12, import_node_fs6, import_node_os, import_node_path6, QUESTION_UNITS, AREA_TITLE, ASK, AREA_OF, ASSUMPTION_LABEL, LOOKUP, StateSchema;
39750
+ var import_node_util3, import_zod61, import_node_crypto11, import_node_fs6, import_node_os, import_node_path6, QUESTION_UNITS, AREA_TITLE, ASK, AREA_OF, ASSUMPTION_LABEL, LOOKUP, StateSchema;
39688
39751
  var init_assessment = __esm({
39689
39752
  "src/tools/assessment.ts"() {
39690
39753
  "use strict";
@@ -39698,7 +39761,7 @@ var init_assessment = __esm({
39698
39761
  init_engine();
39699
39762
  init_transcript();
39700
39763
  init_report();
39701
- import_node_crypto12 = require("node:crypto");
39764
+ import_node_crypto11 = require("node:crypto");
39702
39765
  import_node_fs6 = require("node:fs");
39703
39766
  import_node_os = require("node:os");
39704
39767
  import_node_path6 = require("node:path");
@@ -39884,11 +39947,11 @@ function recoverStuckStages(state) {
39884
39947
  return { state: { ...state, clients }, recovered };
39885
39948
  }
39886
39949
  function cockpitStatePath() {
39887
- return path33.join(appDataDir(), "cockpit-state.json");
39950
+ return path32.join(appDataDir(), "cockpit-state.json");
39888
39951
  }
39889
39952
  function readCockpitState() {
39890
39953
  try {
39891
- const raw = JSON.parse(fs35.readFileSync(cockpitStatePath(), "utf8"));
39954
+ const raw = JSON.parse(fs34.readFileSync(cockpitStatePath(), "utf8"));
39892
39955
  if (raw && raw.v === 1 && raw.clients && typeof raw.clients === "object") return raw;
39893
39956
  } catch {
39894
39957
  }
@@ -39896,7 +39959,7 @@ function readCockpitState() {
39896
39959
  }
39897
39960
  function writeCockpitState(state) {
39898
39961
  ensureAppDataDir();
39899
- fs35.writeFileSync(cockpitStatePath(), JSON.stringify(state, null, 2), { mode: 384 });
39962
+ fs34.writeFileSync(cockpitStatePath(), JSON.stringify(state, null, 2), { mode: 384 });
39900
39963
  }
39901
39964
  function setStage(state, locationId2, stageIndex, status) {
39902
39965
  if (!Number.isInteger(stageIndex) || stageIndex < 0 || stageIndex >= STAGES2.length) throw new Error("bad stage index");
@@ -40227,7 +40290,7 @@ function notify(message) {
40227
40290
  `);
40228
40291
  try {
40229
40292
  ensureAppDataDir();
40230
- fs35.appendFileSync(path33.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
40293
+ fs34.appendFileSync(path32.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
40231
40294
  `);
40232
40295
  } catch {
40233
40296
  }
@@ -40297,20 +40360,20 @@ function withCockpitShell(page, screen, extraHead = "") {
40297
40360
  function clientDocsDir(locationId2, base = appDataDir()) {
40298
40361
  const safeLoc = String(locationId2).replace(/[^A-Za-z0-9_-]/g, "");
40299
40362
  if (!safeLoc) throw new Error("no client");
40300
- return path33.join(base, "clients", safeLoc, "documents");
40363
+ return path32.join(base, "clients", safeLoc, "documents");
40301
40364
  }
40302
40365
  function safeDocName(name) {
40303
- const cleaned = path33.basename(String(name ?? "")).replace(/[^A-Za-z0-9._ -]/g, "_").replace(/\s+/g, " ").trim();
40304
- const ext = path33.extname(cleaned).toLowerCase();
40366
+ const cleaned = path32.basename(String(name ?? "")).replace(/[^A-Za-z0-9._ -]/g, "_").replace(/\s+/g, " ").trim();
40367
+ const ext = path32.extname(cleaned).toLowerCase();
40305
40368
  if (!cleaned || cleaned.startsWith(".") || !DOC_EXTS.has(ext)) throw new Error("Only plain text (.txt, .md, .csv), .vtt and .srt files can be saved here.");
40306
40369
  const stem = cleaned.slice(0, cleaned.length - ext.length).slice(0, 120 - ext.length).trim();
40307
40370
  return `${stem || "document"}${ext}`;
40308
40371
  }
40309
40372
  function listClientDocs(locationId2, base = appDataDir()) {
40310
40373
  const dir = clientDocsDir(locationId2, base);
40311
- if (!fs35.existsSync(dir)) return [];
40312
- return fs35.readdirSync(dir).filter((f) => DOC_EXTS.has(path33.extname(f).toLowerCase())).map((f) => {
40313
- const st = fs35.statSync(path33.join(dir, f));
40374
+ if (!fs34.existsSync(dir)) return [];
40375
+ return fs34.readdirSync(dir).filter((f) => DOC_EXTS.has(path32.extname(f).toLowerCase())).map((f) => {
40376
+ const st = fs34.statSync(path32.join(dir, f));
40314
40377
  return { name: f, bytes: st.size, savedAt: st.mtime.toISOString() };
40315
40378
  }).sort((a, b) => b.savedAt.localeCompare(a.savedAt));
40316
40379
  }
@@ -40328,7 +40391,7 @@ function readFailureText(e) {
40328
40391
  function logQuietly(message) {
40329
40392
  try {
40330
40393
  ensureAppDataDir();
40331
- fs35.appendFileSync(path33.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
40394
+ fs34.appendFileSync(path32.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
40332
40395
  `);
40333
40396
  } catch {
40334
40397
  }
@@ -40401,40 +40464,40 @@ function newClientFailure(error, surface = "command-os", account2) {
40401
40464
  }
40402
40465
  function insideDir(dir, p) {
40403
40466
  try {
40404
- const real = fs35.realpathSync(p);
40405
- const base = fs35.realpathSync(dir);
40406
- return real === base || real.startsWith(base + path33.sep);
40467
+ const real = fs34.realpathSync(p);
40468
+ const base = fs34.realpathSync(dir);
40469
+ return real === base || real.startsWith(base + path32.sep);
40407
40470
  } catch {
40408
40471
  return false;
40409
40472
  }
40410
40473
  }
40411
40474
  function uniqueDocName(dir, name) {
40412
- const ext = path33.extname(name), stem = name.slice(0, name.length - ext.length);
40475
+ const ext = path32.extname(name), stem = name.slice(0, name.length - ext.length);
40413
40476
  let candidate = name;
40414
- for (let n = 2; fs35.existsSync(path33.join(dir, candidate)); n++) candidate = `${stem} (${n})${ext}`;
40477
+ for (let n = 2; fs34.existsSync(path32.join(dir, candidate)); n++) candidate = `${stem} (${n})${ext}`;
40415
40478
  return candidate;
40416
40479
  }
40417
40480
  function writeDocAtomically(dir, name, bytes) {
40418
- fs35.mkdirSync(dir, { recursive: true, mode: 448 });
40481
+ fs34.mkdirSync(dir, { recursive: true, mode: 448 });
40419
40482
  const finalName = uniqueDocName(dir, name);
40420
- const tmp = path33.join(dir, `.${finalName}.${process.pid}.tmp`);
40421
- const fd = fs35.openSync(tmp, fs35.constants.O_WRONLY | fs35.constants.O_CREAT | fs35.constants.O_EXCL | (fs35.constants.O_NOFOLLOW ?? 0), 384);
40483
+ const tmp = path32.join(dir, `.${finalName}.${process.pid}.tmp`);
40484
+ const fd = fs34.openSync(tmp, fs34.constants.O_WRONLY | fs34.constants.O_CREAT | fs34.constants.O_EXCL | (fs34.constants.O_NOFOLLOW ?? 0), 384);
40422
40485
  try {
40423
- fs35.writeSync(fd, bytes);
40424
- fs35.fsyncSync(fd);
40486
+ fs34.writeSync(fd, bytes);
40487
+ fs34.fsyncSync(fd);
40425
40488
  } finally {
40426
- fs35.closeSync(fd);
40489
+ fs34.closeSync(fd);
40427
40490
  }
40428
- const dest = path33.join(dir, finalName);
40491
+ const dest = path32.join(dir, finalName);
40429
40492
  try {
40430
- if (fs35.lstatSync(dest).isSymbolicLink()) {
40431
- fs35.unlinkSync(tmp);
40493
+ if (fs34.lstatSync(dest).isSymbolicLink()) {
40494
+ fs34.unlinkSync(tmp);
40432
40495
  throw new Error("that name is taken by a link");
40433
40496
  }
40434
40497
  } catch (e) {
40435
40498
  if (e.code !== "ENOENT") throw e;
40436
40499
  }
40437
- fs35.renameSync(tmp, dest);
40500
+ fs34.renameSync(tmp, dest);
40438
40501
  return finalName;
40439
40502
  }
40440
40503
  function readableAccount(locationId2, roster = currentRosterRef(), state = readCockpitState()) {
@@ -42238,8 +42301,8 @@ ${opportunityNoteFailure?.detail ?? ""}`);
42238
42301
  if (!bytes.length) throw new Error("that file is empty");
42239
42302
  if (bytes.length > DOC_MAX_BYTES) throw new Error("that file is over 20 MB");
42240
42303
  const dir = clientDocsDir(args.locationId);
42241
- fs35.mkdirSync(dir, { recursive: true, mode: 448 });
42242
- if (!insideDir(path33.join(appDataDir(), "clients"), dir)) throw new Error("This client's documents folder is not where it should be, so nothing was saved.");
42304
+ fs34.mkdirSync(dir, { recursive: true, mode: 448 });
42305
+ if (!insideDir(path32.join(appDataDir(), "clients"), dir)) throw new Error("This client's documents folder is not where it should be, so nothing was saved.");
42243
42306
  const saved = writeDocAtomically(dir, name, bytes);
42244
42307
  res.end(JSON.stringify({ ok: true, name: saved, files: listClientDocs(args.locationId) }));
42245
42308
  } catch (e) {
@@ -42593,10 +42656,10 @@ ${opportunityNoteFailure?.detail ?? ""}`);
42593
42656
  if (args.file) {
42594
42657
  const name = safeDocName(args.file);
42595
42658
  const dir = clientDocsDir(args.locationId);
42596
- const p = path33.join(dir, name);
42597
- if (!fs35.existsSync(p)) throw new Error("that document is not saved for this client");
42598
- if (fs35.lstatSync(p).isSymbolicLink() || !insideDir(dir, p)) throw new Error("that document is not saved for this client");
42599
- const text2 = fs35.readFileSync(p, "utf8");
42659
+ const p = path32.join(dir, name);
42660
+ if (!fs34.existsSync(p)) throw new Error("that document is not saved for this client");
42661
+ if (fs34.lstatSync(p).isSymbolicLink() || !insideDir(dir, p)) throw new Error("that document is not saved for this client");
42662
+ const text2 = fs34.readFileSync(p, "utf8");
42600
42663
  if (text2.length > 6e4) throw new Error("The limit is 60,000 characters. Paste an excerpt or shorten this text file.");
42601
42664
  fileSource = { kind: "text", text: text2 };
42602
42665
  }
@@ -42670,14 +42733,14 @@ ${opportunityNoteFailure?.detail ?? ""}`);
42670
42733
  }
42671
42734
  if (req.method === "GET" && /^\/brand\/[a-z0-9-]+\/screenshot\.png$/.test(url)) {
42672
42735
  const slug3 = url.split("/")[2];
42673
- const file2 = path33.join(brandDir(slug3), "screenshot.png");
42674
- if (!fs35.existsSync(file2)) {
42736
+ const file2 = path32.join(brandDir(slug3), "screenshot.png");
42737
+ if (!fs34.existsSync(file2)) {
42675
42738
  res.writeHead(404);
42676
42739
  res.end();
42677
42740
  return;
42678
42741
  }
42679
42742
  res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "no-store" });
42680
- res.end(fs35.readFileSync(file2));
42743
+ res.end(fs34.readFileSync(file2));
42681
42744
  return;
42682
42745
  }
42683
42746
  if (req.method === "GET" && /^\/brand\/[a-z0-9-]+$/.test(url)) {
@@ -42686,7 +42749,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
42686
42749
  const dna = houseLooks().find((d) => d.slug === slug3) ?? readBrand(slug3);
42687
42750
  const dir = brandExists(slug3) ? brandDir(slug3) : void 0;
42688
42751
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
42689
- res.end(brandCardHtml(dna, { screenshot: dir ? fs35.existsSync(path33.join(dir, "screenshot.png")) : false, dir, seatToken: mayServeSeat(req, port) ? seatToken : "" }));
42752
+ res.end(brandCardHtml(dna, { screenshot: dir ? fs34.existsSync(path32.join(dir, "screenshot.png")) : false, dir, seatToken: mayServeSeat(req, port) ? seatToken : "" }));
42690
42753
  } catch (e) {
42691
42754
  res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
42692
42755
  res.end(e.message);
@@ -42848,7 +42911,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
42848
42911
  }
42849
42912
  try {
42850
42913
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
42851
- res.end(fs35.readFileSync(localCopyPath(locationId2), "utf8"));
42914
+ res.end(fs34.readFileSync(localCopyPath(locationId2), "utf8"));
42852
42915
  } catch {
42853
42916
  res.end("The handoff is not prepared yet. Run Verify first.");
42854
42917
  }
@@ -43454,7 +43517,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
43454
43517
  process.on("SIGTERM", stop);
43455
43518
  });
43456
43519
  }
43457
- var import_zod62, import_node_util4, fs35, path33, http, import_child_process4, import_child_process5, osmod, STAGES2, ACCOUNT_TYPES, activeRun2, handoffEmailPreviews, UPGRADE_MSG, DOC_EXTS, DOC_MAX_BYTES, NEEDS_AGENCY_KEY, INTAKE_UNREADABLE, INTAKE_FORM_REQUIRED, INTAKE_CONNECT_REQUIRED, INTAKE_OWN_MESSAGES, currentRosterRef, BOARD_ROUTES, BOARD_TITLES, anthropicKeyWrites, SEAT_TOKEN_HEADER, NOT_SIGNED_IN_MSG, SEAT_GUARDED_READS, ConnectionRequest, DisconnectRequest;
43520
+ var import_zod62, import_node_util4, fs34, path32, http, import_child_process4, import_child_process5, osmod, STAGES2, ACCOUNT_TYPES, activeRun2, handoffEmailPreviews, UPGRADE_MSG, DOC_EXTS, DOC_MAX_BYTES, NEEDS_AGENCY_KEY, INTAKE_UNREADABLE, INTAKE_FORM_REQUIRED, INTAKE_CONNECT_REQUIRED, INTAKE_OWN_MESSAGES, currentRosterRef, BOARD_ROUTES, BOARD_TITLES, anthropicKeyWrites, SEAT_TOKEN_HEADER, NOT_SIGNED_IN_MSG, SEAT_GUARDED_READS, ConnectionRequest, DisconnectRequest;
43458
43521
  var init_dashboard = __esm({
43459
43522
  "src/dashboard.ts"() {
43460
43523
  "use strict";
@@ -43482,8 +43545,8 @@ var init_dashboard = __esm({
43482
43545
  init_handoff_snapshot();
43483
43546
  init_member_progress();
43484
43547
  init_build_obligations();
43485
- fs35 = __toESM(require("fs"));
43486
- path33 = __toESM(require("path"));
43548
+ fs34 = __toESM(require("fs"));
43549
+ path32 = __toESM(require("path"));
43487
43550
  http = __toESM(require("http"));
43488
43551
  import_child_process4 = require("child_process");
43489
43552
  init_credentials_store();
@@ -43589,8 +43652,8 @@ var init_dashboard = __esm({
43589
43652
  NOT_SIGNED_IN_MSG = "This browser isn't signed in to Command OS on this computer. Open Command OS on the machine it runs on, and use the page it opens for you.";
43590
43653
  SEAT_GUARDED_READS = ["/api/brief", "/api/brief/panel", "/api/connections", "/api/capability", "/api/client-intake", "/api/intake-documents", "/api/snapshots", "/api/agency-connection", "/api/client-preflight"];
43591
43654
  ConnectionRequest = import_zod62.z.discriminatedUnion("system", [
43592
- import_zod62.z.object({ system: import_zod62.z.literal("stripe"), key: import_zod62.z.string().min(8), label: import_zod62.z.string().optional() }).strict(),
43593
- import_zod62.z.object({ system: import_zod62.z.literal("slack"), key: import_zod62.z.string().min(8), label: import_zod62.z.string().optional() }).strict(),
43655
+ import_zod62.z.object({ system: import_zod62.z.literal("stripe"), key: import_zod62.z.string().min(8).max(4096), label: import_zod62.z.string().optional() }).strict(),
43656
+ import_zod62.z.object({ system: import_zod62.z.literal("slack"), key: import_zod62.z.string().min(8).max(4096), label: import_zod62.z.string().optional() }).strict(),
43594
43657
  import_zod62.z.object({ system: import_zod62.z.literal("google-calendar"), action: import_zod62.z.enum(["start", "finish", "status"]).default("start") }).strict()
43595
43658
  ]);
43596
43659
  DisconnectRequest = import_zod62.z.object({ system: import_zod62.z.enum(["stripe", "slack", "google-calendar"]) }).strict();
@@ -45345,13 +45408,13 @@ function contactServiceNote(payload) {
45345
45408
  function registerSmartListTools(server2, builderClient) {
45346
45409
  if (!builderClient) return;
45347
45410
  const client = builderClient;
45348
- async function smartListRequest(method, path42, body) {
45349
- const url = `${SMARTLIST_BASE}${path42}`;
45411
+ async function smartListRequest(method, path41, body) {
45412
+ const url = `${SMARTLIST_BASE}${path41}`;
45350
45413
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
45351
45414
  const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
45352
45415
  if (!response.ok) {
45353
45416
  const text3 = await response.text();
45354
- throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path42}
45417
+ throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path41}
45355
45418
  ${text3}`);
45356
45419
  }
45357
45420
  const text2 = await response.text();
@@ -45596,11 +45659,11 @@ var init_smart_lists = __esm({
45596
45659
  function registerReputationTools(server2, builderClient) {
45597
45660
  if (!builderClient) return;
45598
45661
  const client = builderClient;
45599
- async function reputationRequest(method, path42) {
45600
- const response = await builderRequest(client, method, `${REPUTATION_BASE}${path42}`);
45662
+ async function reputationRequest(method, path41) {
45663
+ const response = await builderRequest(client, method, `${REPUTATION_BASE}${path41}`);
45601
45664
  if (!response.ok) {
45602
45665
  const text3 = await response.text();
45603
- throw new Error(`Reputation API Error ${response.status}: ${method} ${path42}
45666
+ throw new Error(`Reputation API Error ${response.status}: ${method} ${path41}
45604
45667
  ${text3}`);
45605
45668
  }
45606
45669
  const text2 = await response.text();
@@ -45738,11 +45801,11 @@ var init_email_campaigns = __esm({
45738
45801
  function registerMembershipTools(server2, builderClient) {
45739
45802
  if (!builderClient) return;
45740
45803
  const client = builderClient;
45741
- async function membershipRequest(path42, method = "GET", body) {
45742
- const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${path42}`, body ? { body } : {});
45804
+ async function membershipRequest(path41, method = "GET", body) {
45805
+ const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${path41}`, body ? { body } : {});
45743
45806
  if (!response.ok) {
45744
45807
  const text3 = await response.text();
45745
- throw new Error(`Membership API Error ${response.status}: ${method} ${path42}
45808
+ throw new Error(`Membership API Error ${response.status}: ${method} ${path41}
45746
45809
  ${text3}`);
45747
45810
  }
45748
45811
  const text2 = await response.text();
@@ -45935,21 +45998,21 @@ function isAlreadyExistsError(message) {
45935
45998
  }
45936
45999
  function registerTemplateDeployerTools(server2, client) {
45937
46000
  const builderClient = WorkflowBuilderClient.fromEnv();
45938
- const templatesDir = path34.resolve(__dirname, "..", "templates");
46001
+ const templatesDir = path33.resolve(__dirname, "..", "templates");
45939
46002
  function validateTemplatePath(templateFile) {
45940
- const resolved2 = path34.resolve(templateFile);
45941
- const realPath = fs36.existsSync(resolved2) ? fs36.realpathSync(resolved2) : resolved2;
46003
+ const resolved2 = path33.resolve(templateFile);
46004
+ const realPath = fs35.existsSync(resolved2) ? fs35.realpathSync(resolved2) : resolved2;
45942
46005
  const allowedDirs = [
45943
46006
  templatesDir,
45944
- path34.resolve(process.cwd(), "templates"),
45945
- path34.resolve(__dirname, "..", "..", "templates")
45946
- ].map((d) => fs36.existsSync(d) ? fs36.realpathSync(d) : d);
45947
- const isAllowed = allowedDirs.some((dir) => realPath.startsWith(dir + path34.sep));
46007
+ path33.resolve(process.cwd(), "templates"),
46008
+ path33.resolve(__dirname, "..", "..", "templates")
46009
+ ].map((d) => fs35.existsSync(d) ? fs35.realpathSync(d) : d);
46010
+ const isAllowed = allowedDirs.some((dir) => realPath.startsWith(dir + path33.sep));
45948
46011
  if (!isAllowed) {
45949
46012
  throw new Error(`Template file must be inside a templates/ directory. Got: ${realPath}`);
45950
46013
  }
45951
- if (path34.relative(allowedDirs[0], realPath).startsWith("..")) {
45952
- const otherMatch = allowedDirs.slice(1).some((d) => !path34.relative(d, realPath).startsWith(".."));
46014
+ if (path33.relative(allowedDirs[0], realPath).startsWith("..")) {
46015
+ const otherMatch = allowedDirs.slice(1).some((d) => !path33.relative(d, realPath).startsWith(".."));
45953
46016
  if (!otherMatch) {
45954
46017
  throw new Error(`Template path escapes allowed directory.`);
45955
46018
  }
@@ -45964,26 +46027,26 @@ function registerTemplateDeployerTools(server2, client) {
45964
46027
  try {
45965
46028
  const dirs = [
45966
46029
  templatesDir,
45967
- path34.resolve(process.cwd(), "templates"),
45968
- path34.resolve(__dirname, "..", "..", "templates")
46030
+ path33.resolve(process.cwd(), "templates"),
46031
+ path33.resolve(__dirname, "..", "..", "templates")
45969
46032
  ];
45970
46033
  const templates = [];
45971
46034
  const seen = /* @__PURE__ */ new Set();
45972
46035
  for (const dir of dirs) {
45973
- if (!fs36.existsSync(dir)) continue;
45974
- const files = fs36.readdirSync(dir).filter((f) => f.endsWith(".json"));
46036
+ if (!fs35.existsSync(dir)) continue;
46037
+ const files = fs35.readdirSync(dir).filter((f) => f.endsWith(".json"));
45975
46038
  for (const file2 of files) {
45976
- const full = path34.join(dir, file2);
46039
+ const full = path33.join(dir, file2);
45977
46040
  let real;
45978
46041
  try {
45979
- real = fs36.realpathSync(full);
46042
+ real = fs35.realpathSync(full);
45980
46043
  } catch {
45981
46044
  continue;
45982
46045
  }
45983
46046
  if (seen.has(real)) continue;
45984
46047
  seen.add(real);
45985
46048
  try {
45986
- const content = JSON.parse(fs36.readFileSync(full, "utf-8"));
46049
+ const content = JSON.parse(fs35.readFileSync(full, "utf-8"));
45987
46050
  if (typeof content.templateName !== "string" || !content.templateName) continue;
45988
46051
  const parsed2 = TemplateSchema.safeParse(content);
45989
46052
  templates.push({
@@ -46020,7 +46083,7 @@ function registerTemplateDeployerTools(server2, client) {
46020
46083
  async ({ templateFile }) => {
46021
46084
  try {
46022
46085
  const safePath = validateTemplatePath(templateFile);
46023
- const content = JSON.parse(fs36.readFileSync(safePath, "utf-8"));
46086
+ const content = JSON.parse(fs35.readFileSync(safePath, "utf-8"));
46024
46087
  return {
46025
46088
  content: [
46026
46089
  {
@@ -46060,7 +46123,7 @@ function registerTemplateDeployerTools(server2, client) {
46060
46123
  try {
46061
46124
  const locId = client.resolveLocationId(locationId2);
46062
46125
  const safePath = validateTemplatePath(templateFile);
46063
- const template = TemplateSchema.parse(JSON.parse(fs36.readFileSync(safePath, "utf-8")));
46126
+ const template = TemplateSchema.parse(JSON.parse(fs35.readFileSync(safePath, "utf-8")));
46064
46127
  const resolve12 = (text2) => {
46065
46128
  if (typeof text2 !== "string") return text2;
46066
46129
  let result = text2;
@@ -46432,15 +46495,15 @@ ${errors.join("\n")}` : dryRun ? "\nNo errors!" : "\nNo errors \u2014 every item
46432
46495
  }
46433
46496
  );
46434
46497
  }
46435
- var import_zod71, fs36, path34, TemplateSchema;
46498
+ var import_zod71, fs35, path33, TemplateSchema;
46436
46499
  var init_template_deployer = __esm({
46437
46500
  "src/tools/template-deployer.ts"() {
46438
46501
  "use strict";
46439
46502
  import_zod71 = require("zod");
46440
46503
  init_workflow_builder_client();
46441
46504
  init_tool_helpers();
46442
- fs36 = __toESM(require("fs"));
46443
- path34 = __toESM(require("path"));
46505
+ fs35 = __toESM(require("fs"));
46506
+ path33 = __toESM(require("path"));
46444
46507
  init_workflow_builder_client();
46445
46508
  TemplateSchema = import_zod71.z.object({
46446
46509
  templateName: import_zod71.z.string(),
@@ -46761,10 +46824,10 @@ async function confirm(run) {
46761
46824
  async function runProbes(client, loc) {
46762
46825
  return Promise.all(
46763
46826
  PROBES.map((probe) => confirm(async () => {
46764
- const path42 = probe.path.replace("{loc}", loc);
46827
+ const path41 = probe.path.replace("{loc}", loc);
46765
46828
  const params = probe.params ? Object.fromEntries(Object.entries(probe.params).map(([k, v]) => [k, substitute(v, loc)])) : void 0;
46766
46829
  try {
46767
- const raw = await client.get(path42, { params, noRetry: true });
46830
+ const raw = await client.get(path41, { params, noRetry: true });
46768
46831
  const count2 = countRows(raw, probe.listKeys);
46769
46832
  return {
46770
46833
  key: probe.key,
@@ -47040,14 +47103,14 @@ var init_checkup = __esm({
47040
47103
 
47041
47104
  // src/tools/user-guide.ts
47042
47105
  function resolveGuidePath() {
47043
- const bundled = path35.resolve(__dirname, "..", "guide", "guide.html");
47044
- if (fs37.existsSync(bundled)) return bundled;
47045
- const devRoot = path35.resolve(__dirname, "..", "..");
47106
+ const bundled = path34.resolve(__dirname, "..", "guide", "guide.html");
47107
+ if (fs36.existsSync(bundled)) return bundled;
47108
+ const devRoot = path34.resolve(__dirname, "..", "..");
47046
47109
  try {
47047
- const pkg2 = JSON.parse(fs37.readFileSync(path35.join(devRoot, "package.json"), "utf8"));
47110
+ const pkg2 = JSON.parse(fs36.readFileSync(path34.join(devRoot, "package.json"), "utf8"));
47048
47111
  if (pkg2.name === "@elitedcs/ghl-mcp") {
47049
- const dev = path35.join(devRoot, "guide", "guide.html");
47050
- if (fs37.existsSync(dev)) return dev;
47112
+ const dev = path34.join(devRoot, "guide", "guide.html");
47113
+ if (fs36.existsSync(dev)) return dev;
47051
47114
  }
47052
47115
  } catch {
47053
47116
  }
@@ -47056,7 +47119,7 @@ function resolveGuidePath() {
47056
47119
  function guideContents(file2) {
47057
47120
  let html2 = "";
47058
47121
  try {
47059
- html2 = fs37.readFileSync(file2, "utf8");
47122
+ html2 = fs36.readFileSync(file2, "utf8");
47060
47123
  } catch {
47061
47124
  return "The guide is installed but could not be read.";
47062
47125
  }
@@ -47080,7 +47143,7 @@ function registerUserGuideTools(server2) {
47080
47143
  { open: import_zod73.z.boolean().optional().describe("Open the guide in the browser. Takes over the person's screen \u2014 only when they asked for it.") },
47081
47144
  async ({ open }) => {
47082
47145
  const guidePath = resolveGuidePath();
47083
- if (!fs37.existsSync(guidePath)) {
47146
+ if (!fs36.existsSync(guidePath)) {
47084
47147
  return {
47085
47148
  content: [{
47086
47149
  type: "text",
@@ -47113,14 +47176,14 @@ ${guidePath}`;
47113
47176
  }
47114
47177
  );
47115
47178
  }
47116
- var import_child_process6, import_zod73, fs37, path35;
47179
+ var import_child_process6, import_zod73, fs36, path34;
47117
47180
  var init_user_guide = __esm({
47118
47181
  "src/tools/user-guide.ts"() {
47119
47182
  "use strict";
47120
47183
  import_child_process6 = require("child_process");
47121
47184
  import_zod73 = require("zod");
47122
- fs37 = __toESM(require("fs"));
47123
- path35 = __toESM(require("path"));
47185
+ fs36 = __toESM(require("fs"));
47186
+ path34 = __toESM(require("path"));
47124
47187
  }
47125
47188
  });
47126
47189
 
@@ -49330,9 +49393,9 @@ async function settle(page) {
49330
49393
  }
49331
49394
  async function readTarget(target) {
49332
49395
  if (isUrl(target)) return { html: null, url: target };
49333
- const abs = path36.resolve(target);
49334
- if (!fs38.existsSync(abs)) throw new Error(`No file at ${abs}.`);
49335
- return { html: fs38.readFileSync(abs, "utf8"), url: (0, import_node_url.pathToFileURL)(abs).toString() };
49396
+ const abs = path35.resolve(target);
49397
+ if (!fs37.existsSync(abs)) throw new Error(`No file at ${abs}.`);
49398
+ return { html: fs37.readFileSync(abs, "utf8"), url: (0, import_node_url.pathToFileURL)(abs).toString() };
49336
49399
  }
49337
49400
  function slidePixels(index, png, file2, sec, brand) {
49338
49401
  let img;
@@ -49380,7 +49443,7 @@ async function verifyDesign(opts) {
49380
49443
  const { html: html2, url } = await readTarget(opts.target);
49381
49444
  const placement = opts.placement ?? "html";
49382
49445
  const medium = opts.medium;
49383
- fs38.mkdirSync(opts.outDir, { recursive: true });
49446
+ fs37.mkdirSync(opts.outDir, { recursive: true });
49384
49447
  const files = [];
49385
49448
  const screenshots = [];
49386
49449
  const at = (/* @__PURE__ */ new Date()).toISOString();
@@ -49425,8 +49488,8 @@ async function verifyDesign(opts) {
49425
49488
  try {
49426
49489
  await loc.scrollIntoViewIfNeeded({ timeout: 5e3 });
49427
49490
  const png = await loc.screenshot({ type: "png", timeout: 15e3 });
49428
- fs38.writeFileSync(path36.join(opts.outDir, file2), png);
49429
- files.push(path36.join(opts.outDir, file2));
49491
+ fs37.writeFileSync(path35.join(opts.outDir, file2), png);
49492
+ files.push(path35.join(opts.outDir, file2));
49430
49493
  screenshots.push(file2);
49431
49494
  pixels.push(slidePixels(sec.index, png, file2, sec, opts.brand));
49432
49495
  } catch {
@@ -49458,8 +49521,8 @@ async function verifyDesign(opts) {
49458
49521
  const shot = "page-1440.png";
49459
49522
  try {
49460
49523
  const png = await page.screenshot({ type: "png", fullPage: true, timeout: 2e4 });
49461
- fs38.writeFileSync(path36.join(opts.outDir, shot), png);
49462
- files.push(path36.join(opts.outDir, shot));
49524
+ fs37.writeFileSync(path35.join(opts.outDir, shot), png);
49525
+ files.push(path35.join(opts.outDir, shot));
49463
49526
  screenshots.push(shot);
49464
49527
  } catch {
49465
49528
  }
@@ -49467,8 +49530,8 @@ async function verifyDesign(opts) {
49467
49530
  await page.setViewportSize({ width: 390, height: 844 });
49468
49531
  await page.evaluate(SETTLE_SCROLL_JS).catch(() => void 0);
49469
49532
  const png = await page.screenshot({ type: "png", fullPage: true, timeout: 2e4 });
49470
- fs38.writeFileSync(path36.join(opts.outDir, "page-390.png"), png);
49471
- files.push(path36.join(opts.outDir, "page-390.png"));
49533
+ fs37.writeFileSync(path35.join(opts.outDir, "page-390.png"), png);
49534
+ files.push(path35.join(opts.outDir, "page-390.png"));
49472
49535
  screenshots.push("page-390.png");
49473
49536
  } catch {
49474
49537
  }
@@ -49541,21 +49604,21 @@ async function verifyDesign(opts) {
49541
49604
  screenshots
49542
49605
  };
49543
49606
  const checked = VerificationSchema.parse(report2);
49544
- const jsonPath = path36.join(opts.outDir, "verification.json");
49545
- fs38.writeFileSync(jsonPath, JSON.stringify(checked, null, 2) + "\n");
49607
+ const jsonPath = path35.join(opts.outDir, "verification.json");
49608
+ fs37.writeFileSync(jsonPath, JSON.stringify(checked, null, 2) + "\n");
49546
49609
  files.push(jsonPath);
49547
49610
  const reportHtml = renderVerificationHtml(checked, opts.branding);
49548
- const htmlPath = path36.join(opts.outDir, "verification.html");
49549
- fs38.writeFileSync(htmlPath, reportHtml);
49611
+ const htmlPath = path35.join(opts.outDir, "verification.html");
49612
+ fs37.writeFileSync(htmlPath, reportHtml);
49550
49613
  files.push(htmlPath);
49551
49614
  return { report: checked, files, reportHtml };
49552
49615
  }
49553
- var fs38, path36, import_node_url, WEB_WIDTHS, SETTLE_SCROLL_JS, FOCUS_JS;
49616
+ var fs37, path35, import_node_url, WEB_WIDTHS, SETTLE_SCROLL_JS, FOCUS_JS;
49554
49617
  var init_verify = __esm({
49555
49618
  "src/command-os/design/verify.ts"() {
49556
49619
  "use strict";
49557
- fs38 = __toESM(require("node:fs"));
49558
- path36 = __toESM(require("node:path"));
49620
+ fs37 = __toESM(require("node:fs"));
49621
+ path35 = __toESM(require("node:path"));
49559
49622
  import_node_url = require("node:url");
49560
49623
  init_lint();
49561
49624
  init_probe();
@@ -49974,7 +50037,7 @@ function registerDesignStudioTools(server2) {
49974
50037
  const { dna, logoSvg, logoPng } = deriveBrandDna(raw, { name, slug: slug3, rights: { declaration: a.rights, at: (/* @__PURE__ */ new Date()).toISOString() }, browser, firecrawl: fc });
49975
50038
  if (a.rights === "none" && dna.logo) notes.push("Rights declared as none: the logo is stored for reference only; do not place it on a client-facing page.");
49976
50039
  const written = writeBrand(dna, { logoSvg, logoPng, screenshotPng: browser?.screenshotPng });
49977
- return { ok: true, brand: summarise2(dna), passes: { static: true, browser: Boolean(browser), firecrawl: Boolean(fc) }, spaShell: raw.spaShell, dir: written.dir, files: written.files.map((f) => path37.basename(f)), notes };
50040
+ return { ok: true, brand: summarise2(dna), passes: { static: true, browser: Boolean(browser), firecrawl: Boolean(fc) }, spaShell: raw.spaShell, dir: written.dir, files: written.files.map((f) => path36.basename(f)), notes };
49978
50041
  }
49979
50042
  );
49980
50043
  safeTool(
@@ -50141,9 +50204,9 @@ function registerDesignStudioTools(server2) {
50141
50204
  "Check a written HTML file honours the output contract before grading: section and role markers present and consistent, no outside scripts, one h1 on a page, every image described. Deterministic; no browser. A file that fails this is not graded by verify_design.",
50142
50205
  { file: import_zod76.z.string().describe("Path to the .html file."), medium: import_zod76.z.enum(MEDIA) },
50143
50206
  async ({ file: file2, medium }) => {
50144
- const abs = path37.resolve(file2);
50145
- if (!fs39.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50146
- const r = lintDesignContract(fs39.readFileSync(abs, "utf8"), medium);
50207
+ const abs = path36.resolve(file2);
50208
+ if (!fs38.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50209
+ const r = lintDesignContract(fs38.readFileSync(abs, "utf8"), medium);
50147
50210
  return { ok: r.ok, problems: r.problems, warnings: r.warnings, facts: r.facts };
50148
50211
  }
50149
50212
  );
@@ -50164,7 +50227,7 @@ function registerDesignStudioTools(server2) {
50164
50227
  async (a) => {
50165
50228
  const brand = a.brandSlug ? houseLooks().find((d) => d.slug === a.brandSlug) ?? readBrand(slugify(a.brandSlug)) : void 0;
50166
50229
  const isUrl2 = /^https?:\/\//i.test(a.target);
50167
- const outDir = a.outDir ?? (isUrl2 ? path37.resolve(`verify-${new URL(a.target).hostname.replace(/[^a-z0-9.-]/gi, "_")}`) : path37.join(path37.dirname(path37.resolve(a.target)), `verify-${path37.basename(a.target, ".html")}`));
50230
+ const outDir = a.outDir ?? (isUrl2 ? path36.resolve(`verify-${new URL(a.target).hostname.replace(/[^a-z0-9.-]/gi, "_")}`) : path36.join(path36.dirname(path36.resolve(a.target)), `verify-${path36.basename(a.target, ".html")}`));
50168
50231
  const r = await verifyDesign({ target: a.target, medium: a.medium, brand, outDir, placement: a.placement, mode: a.mode, ratio: a.ratio, logo: a.logo, branding: readAgencyBranding() });
50169
50232
  const v = r.report;
50170
50233
  const failed = v.rules.filter((x) => x.state === "MEASURED-FAIL").map((x) => `${x.ruleId} ${x.name}: ${x.measured ?? ""}`);
@@ -50179,7 +50242,7 @@ function registerDesignStudioTools(server2) {
50179
50242
  judgments: v.rules.filter((x) => x.state === "ASSERTED").map((x) => `${x.ruleId} ${x.name}: ${x.detail ?? ""}`),
50180
50243
  notApplicable: v.rules.filter((x) => x.state === "N-A").map((x) => `${x.ruleId}: ${x.detail ?? ""}`),
50181
50244
  brandMatch: v.brandMatch,
50182
- report: path37.join(outDir, "verification.html"),
50245
+ report: path36.join(outDir, "verification.html"),
50183
50246
  files: r.files,
50184
50247
  ...a.placement === "ghl" && { builderOwned: builderOwnedRules().map((b) => `${b.rule.id} ${b.rule.name}: ${b.why}`) }
50185
50248
  };
@@ -50207,9 +50270,9 @@ function registerDesignStudioTools(server2) {
50207
50270
  if (!a.pageDataDownloadUrl && !a.file) throw new Error("Pass pageDataDownloadUrl (from get_page_full) or file.");
50208
50271
  let page;
50209
50272
  if (a.file) {
50210
- const abs = path37.resolve(a.file);
50211
- if (!fs39.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50212
- page = JSON.parse(fs39.readFileSync(abs, "utf8"));
50273
+ const abs = path36.resolve(a.file);
50274
+ if (!fs38.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50275
+ page = JSON.parse(fs38.readFileSync(abs, "utf8"));
50213
50276
  } else {
50214
50277
  const response = await fetch(a.pageDataDownloadUrl, { headers: { Accept: "application/json,*/*" } });
50215
50278
  if (!response.ok) throw new Error(`Could not download the page data: HTTP ${response.status}. Re-read get_page_full \u2014 the download URL expires.`);
@@ -50250,9 +50313,9 @@ function registerDesignStudioTools(server2) {
50250
50313
  if (!a.file && !a.text) throw new Error("Pass file or text.");
50251
50314
  let html2 = a.text ?? "";
50252
50315
  if (a.file) {
50253
- const abs = path37.resolve(a.file);
50254
- if (!fs39.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50255
- html2 = fs39.readFileSync(abs, "utf8");
50316
+ const abs = path36.resolve(a.file);
50317
+ if (!fs38.existsSync(abs)) throw new Error(`No file at ${abs}.`);
50318
+ html2 = fs38.readFileSync(abs, "utf8");
50256
50319
  }
50257
50320
  const r = await gradeCopy(html2, claudeGenerate(a.model), { icp: a.icp });
50258
50321
  if (!r.grade) {
@@ -50287,13 +50350,13 @@ function registerDesignStudioTools(server2) {
50287
50350
  }
50288
50351
  );
50289
50352
  }
50290
- var import_zod76, fs39, path37, summarise2;
50353
+ var import_zod76, fs38, path36, summarise2;
50291
50354
  var init_design_studio = __esm({
50292
50355
  "src/tools/design-studio.ts"() {
50293
50356
  "use strict";
50294
50357
  import_zod76 = require("zod");
50295
- fs39 = __toESM(require("node:fs"));
50296
- path37 = __toESM(require("node:path"));
50358
+ fs38 = __toESM(require("node:fs"));
50359
+ path36 = __toESM(require("node:path"));
50297
50360
  init_tool_helpers();
50298
50361
  init_extract();
50299
50362
  init_extract_browser();
@@ -50553,18 +50616,18 @@ function owedByClient(owing, identities, links, nameFor2) {
50553
50616
  const byCurrency = /* @__PURE__ */ new Map();
50554
50617
  const unattributedByCurrency = /* @__PURE__ */ new Map();
50555
50618
  let unattributedCount = 0;
50556
- const add = (m, currency, amount) => {
50619
+ const add2 = (m, currency, amount) => {
50557
50620
  const c = currency ?? "unstated";
50558
50621
  m.set(c, (m.get(c) ?? 0) + amount);
50559
50622
  };
50560
50623
  for (const o of owing) {
50561
50624
  const tenant = tenantOfCustomer.get(o.customerId);
50562
50625
  if (!tenant) {
50563
- add(unattributedByCurrency, o.currency, o.amount);
50626
+ add2(unattributedByCurrency, o.currency, o.amount);
50564
50627
  unattributedCount += 1;
50565
50628
  continue;
50566
50629
  }
50567
- add(byCurrency, o.currency, o.amount);
50630
+ add2(byCurrency, o.currency, o.amount);
50568
50631
  lines.push({
50569
50632
  client: nameFor2(tenant),
50570
50633
  amount: o.amount,
@@ -50597,7 +50660,7 @@ function registerConnectorTools(server2) {
50597
50660
  "Store a connector's credentials on THIS machine so that system can be read. The key is written next to your GoHighLevel credentials, readable only by you, and is never sent anywhere, never returned by any tool, and never written to a log. Stripe answers who owes you money, what each person or company pays you and when they renew. Slack lets the morning brief and a stopped build land in the channel you already look at, and shows what is waiting unanswered in the channels the bot is in. Your own Gmail, Google Calendar and Drive need no key here: the brief asks the connectors your assistant already has.",
50598
50661
  {
50599
50662
  system: import_zod77.z.enum(["stripe", "slack"]).describe("The system to connect: stripe or slack."),
50600
- key: import_zod77.z.string().min(8).describe("Stripe: a RESTRICTED key with read access to subscriptions, invoices and customers. Slack: a bot token (starts with xoxb-) from a Slack app you own, with chat:write to post and channels:read plus channels:history to read what is waiting. Nothing here needs a key that can do more."),
50663
+ key: import_zod77.z.string().min(8).max(4096).describe("Stripe: a RESTRICTED key with read access to subscriptions, invoices and customers. Slack: a bot token (starts with xoxb-) from a Slack app you own, with chat:write to post and channels:read plus channels:history to read what is waiting. Nothing here needs a key that can do more."),
50601
50664
  label: import_zod77.z.string().optional().describe("Which account this is, so you can tell two apart later.")
50602
50665
  },
50603
50666
  connectSystem
@@ -51017,11 +51080,11 @@ var init_audit = __esm({
51017
51080
  // src/command-os/delivery-audit/store.ts
51018
51081
  function deliveryAuditPath() {
51019
51082
  const override = process.env[DELIVERY_AUDIT_ENV];
51020
- return override && override.trim() ? override : path38.join(appDataDir(), "delivery-audit.json");
51083
+ return override && override.trim() ? override : path37.join(appDataDir(), "delivery-audit.json");
51021
51084
  }
51022
51085
  function readDeliveryAudit() {
51023
51086
  try {
51024
- const parsed2 = JSON.parse(fs40.readFileSync(deliveryAuditPath(), "utf-8"));
51087
+ const parsed2 = JSON.parse(fs39.readFileSync(deliveryAuditPath(), "utf-8"));
51025
51088
  if (!parsed2 || typeof parsed2 !== "object" || !parsed2.answers || typeof parsed2.answers !== "object") return { ...EMPTY3 };
51026
51089
  return { v: 1, answers: parsed2.answers, updated_at: parsed2.updated_at };
51027
51090
  } catch {
@@ -51032,7 +51095,7 @@ function readForWrite2() {
51032
51095
  const target = deliveryAuditPath();
51033
51096
  let raw;
51034
51097
  try {
51035
- raw = fs40.readFileSync(target, "utf-8");
51098
+ raw = fs39.readFileSync(target, "utf-8");
51036
51099
  } catch (e) {
51037
51100
  if (e?.code === "ENOENT") return { ...EMPTY3 };
51038
51101
  throw new Error("Your saved audit could not be read, so nothing was changed. Nothing was lost.");
@@ -51044,7 +51107,7 @@ function readForWrite2() {
51044
51107
  } catch {
51045
51108
  const kept = `${target}.unreadable-${Date.now()}`;
51046
51109
  try {
51047
- fs40.copyFileSync(target, kept);
51110
+ fs39.copyFileSync(target, kept);
51048
51111
  } catch {
51049
51112
  }
51050
51113
  throw new Error(`Your saved audit is damaged, so nothing was written over it. A copy is at ${kept}. Start again with reset:true when you are ready.`);
@@ -51056,13 +51119,13 @@ function writeFile2(f) {
51056
51119
  const tmp = `${target}.${process.pid}.tmp`;
51057
51120
  let renamed = false;
51058
51121
  try {
51059
- fs40.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
51060
- fs40.renameSync(tmp, target);
51122
+ fs39.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
51123
+ fs39.renameSync(tmp, target);
51061
51124
  renamed = true;
51062
51125
  } finally {
51063
51126
  if (!renamed) {
51064
51127
  try {
51065
- fs40.unlinkSync(tmp);
51128
+ fs39.unlinkSync(tmp);
51066
51129
  } catch {
51067
51130
  }
51068
51131
  }
@@ -51083,12 +51146,12 @@ function resetDeliveryAudit(now = () => /* @__PURE__ */ new Date()) {
51083
51146
  writeFile2(next);
51084
51147
  return next;
51085
51148
  }
51086
- var fs40, path38, EMPTY3, DELIVERY_AUDIT_ENV;
51149
+ var fs39, path37, EMPTY3, DELIVERY_AUDIT_ENV;
51087
51150
  var init_store4 = __esm({
51088
51151
  "src/command-os/delivery-audit/store.ts"() {
51089
51152
  "use strict";
51090
- fs40 = __toESM(require("node:fs"));
51091
- path38 = __toESM(require("node:path"));
51153
+ fs39 = __toESM(require("node:fs"));
51154
+ path37 = __toESM(require("node:path"));
51092
51155
  init_credentials_store();
51093
51156
  EMPTY3 = { v: 1, answers: {} };
51094
51157
  DELIVERY_AUDIT_ENV = "GHL_MCP_DELIVERY_AUDIT";
@@ -51313,7 +51376,7 @@ function planFingerprint(goal, steps) {
51313
51376
  goal,
51314
51377
  steps: steps.map((s) => ({ id: s.id, tool: s.tool, targets: s.targets, creates: s.creates ?? [], args: s.args ?? {} }))
51315
51378
  });
51316
- return (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 16);
51379
+ return (0, import_node_crypto12.createHash)("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 16);
51317
51380
  }
51318
51381
  function checkPlan(goal, findings, steps, now = /* @__PURE__ */ new Date(), knownTools) {
51319
51382
  const refusals = [];
@@ -51530,11 +51593,11 @@ function abandon(a, why) {
51530
51593
  const stillApplied = position(a).undo;
51531
51594
  return { ok: true, automation: { ...a, phase: "abandoned", goal: a.goal, abandonedBecause: why }, stillApplied };
51532
51595
  }
51533
- var import_node_crypto13, isExisting, FINDINGS_STALE_AFTER_MINUTES;
51596
+ var import_node_crypto12, isExisting, FINDINGS_STALE_AFTER_MINUTES;
51534
51597
  var init_automation = __esm({
51535
51598
  "src/command-os/build/automation.ts"() {
51536
51599
  "use strict";
51537
- import_node_crypto13 = require("node:crypto");
51600
+ import_node_crypto12 = require("node:crypto");
51538
51601
  init_verify_findings();
51539
51602
  isExisting = (t) => "existing" in t;
51540
51603
  FINDINGS_STALE_AFTER_MINUTES = 60;
@@ -51544,7 +51607,7 @@ var init_automation = __esm({
51544
51607
  // src/command-os/build/store.ts
51545
51608
  function automationsPath() {
51546
51609
  const override = process.env[AUTOMATIONS_ENV];
51547
- return override && override.trim() ? override : path39.join(appDataDir(), "automations.json");
51610
+ return override && override.trim() ? override : path38.join(appDataDir(), "automations.json");
51548
51611
  }
51549
51612
  function parse4(raw) {
51550
51613
  const p = JSON.parse(raw);
@@ -51553,7 +51616,7 @@ function parse4(raw) {
51553
51616
  }
51554
51617
  function readAutomations() {
51555
51618
  try {
51556
- return parse4(fs41.readFileSync(automationsPath(), "utf-8")).builds;
51619
+ return parse4(fs40.readFileSync(automationsPath(), "utf-8")).builds;
51557
51620
  } catch {
51558
51621
  return { ...EMPTY4.builds };
51559
51622
  }
@@ -51562,7 +51625,7 @@ function readForWrite3() {
51562
51625
  const target = automationsPath();
51563
51626
  let raw;
51564
51627
  try {
51565
- raw = fs41.readFileSync(target, "utf-8");
51628
+ raw = fs40.readFileSync(target, "utf-8");
51566
51629
  } catch (e) {
51567
51630
  if (e?.code === "ENOENT") return { v: 1, builds: {} };
51568
51631
  throw new Error("Your builds file could not be read, so nothing was changed. Nothing was lost.");
@@ -51572,7 +51635,7 @@ function readForWrite3() {
51572
51635
  } catch {
51573
51636
  const kept = `${target}.unreadable-${Date.now()}`;
51574
51637
  try {
51575
- fs41.copyFileSync(target, kept);
51638
+ fs40.copyFileSync(target, kept);
51576
51639
  } catch {
51577
51640
  }
51578
51641
  throw new Error(
@@ -51586,13 +51649,13 @@ function writeFile3(f) {
51586
51649
  const tmp = `${target}.${process.pid}.tmp`;
51587
51650
  let renamed = false;
51588
51651
  try {
51589
- fs41.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
51590
- fs41.renameSync(tmp, target);
51652
+ fs40.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
51653
+ fs40.renameSync(tmp, target);
51591
51654
  renamed = true;
51592
51655
  } finally {
51593
51656
  if (!renamed) {
51594
51657
  try {
51595
- fs41.unlinkSync(tmp);
51658
+ fs40.unlinkSync(tmp);
51596
51659
  } catch {
51597
51660
  }
51598
51661
  }
@@ -51618,12 +51681,12 @@ function newAutomationId(now = () => /* @__PURE__ */ new Date()) {
51618
51681
  }
51619
51682
  return id;
51620
51683
  }
51621
- var fs41, path39, AUTOMATIONS_ENV, EMPTY4;
51684
+ var fs40, path38, AUTOMATIONS_ENV, EMPTY4;
51622
51685
  var init_store5 = __esm({
51623
51686
  "src/command-os/build/store.ts"() {
51624
51687
  "use strict";
51625
- fs41 = __toESM(require("node:fs"));
51626
- path39 = __toESM(require("node:path"));
51688
+ fs40 = __toESM(require("node:fs"));
51689
+ path38 = __toESM(require("node:path"));
51627
51690
  init_credentials_store();
51628
51691
  AUTOMATIONS_ENV = "GHL_MCP_AUTOMATIONS";
51629
51692
  EMPTY4 = { v: 1, builds: {} };
@@ -51636,7 +51699,7 @@ function isIdShapedKey(key) {
51636
51699
  }
51637
51700
  function scanArgs(args, maxNodes = MAX_ARG_NODES) {
51638
51701
  const out = { ids: [], locations: [], unknown: [], uncheckable: [] };
51639
- const add = (kind, v, key) => {
51702
+ const add2 = (kind, v, key) => {
51640
51703
  const list2 = Array.isArray(v) ? v : [v];
51641
51704
  for (const x of list2) {
51642
51705
  const id = typeof x === "number" ? String(x) : x;
@@ -51672,28 +51735,28 @@ function scanArgs(args, maxNodes = MAX_ARG_NODES) {
51672
51735
  if (k === "locationId") {
51673
51736
  if (typeof x === "string" && x.length > 0) out.locations.push(x);
51674
51737
  } else if (k === "traffic_weightage" && isRecord10(x)) {
51675
- add("user", Object.keys(x), k);
51738
+ add2("user", Object.keys(x), k);
51676
51739
  continue;
51677
51740
  } else if (k === "traffic_index" && Array.isArray(x)) {
51678
- add("user", x.map((e) => isRecord10(e) ? e.id : void 0), k);
51741
+ add2("user", x.map((e) => isRecord10(e) ? e.id : void 0), k);
51679
51742
  } else if (k === "selectedUser") {
51680
- if (v.userType !== "all") add("user", x, k);
51743
+ if (v.userType !== "all") add2("user", x, k);
51681
51744
  } else if (k === "field" && inFields) {
51682
51745
  if (typeof x === "string") {
51683
51746
  const standardKey = STANDARD_CONTACT_FIELDS.has(x.toLowerCase());
51684
- if (!standardKey || isIdShaped(x)) add("custom_field", x, "fields[].field");
51747
+ if (!standardKey || isIdShaped(x)) add2("custom_field", x, "fields[].field");
51685
51748
  }
51686
51749
  } else if (k === "customFields" && Array.isArray(x)) {
51687
- add("custom_field", x.map((e) => isRecord10(e) ? e.id : void 0), "customFields[].id");
51750
+ add2("custom_field", x.map((e) => isRecord10(e) ? e.id : void 0), "customFields[].id");
51688
51751
  } else if (k === "customField" && isRecord10(x)) {
51689
- add("custom_field", x.id, "customField.id");
51752
+ add2("custom_field", x.id, "customField.id");
51690
51753
  } else if (Object.hasOwn(ID_ARG_KINDS, k)) {
51691
- add(ID_ARG_KINDS[k], x, k);
51754
+ add2(ID_ARG_KINDS[k], x, k);
51692
51755
  } else if (isIdShapedKey(k) && !Object.hasOwn(NOT_CHECKABLE_ID_ARGS, k) && hasValue(x)) {
51693
51756
  out.unknown.push({ key: k, value: JSON.stringify(x).slice(0, 80), ...nodeType ? { nodeType } : {} });
51694
51757
  }
51695
51758
  if ((k === "filterField" || k === "field" && !inFields) && typeof x === "string" && Object.hasOwn(CONDITION_FIELD_KINDS, x)) {
51696
- add(CONDITION_FIELD_KINDS[x], Object.hasOwn(v, "secondValue") ? v.secondValue : v.value, `${k} ${x}`);
51759
+ add2(CONDITION_FIELD_KINDS[x], Object.hasOwn(v, "secondValue") ? v.secondValue : v.value, `${k} ${x}`);
51697
51760
  }
51698
51761
  if (x && typeof x === "object") stack.push({ v: x, inFields: k === "fields" && Array.isArray(x), nodeType });
51699
51762
  }
@@ -53770,11 +53833,11 @@ function previewShowsPlanBody(preview, planHtml) {
53770
53833
  }
53771
53834
  function bindingIdentities(plan) {
53772
53835
  const result = [];
53773
- const add = (type, ref, name, identity2 = name) => result.push({ ref, type, name, identity: `${type}:${norm5(identity2)}` });
53774
- for (const u of planUsers(plan)) add("user", u.ref, userDisplayName(u), u.email);
53836
+ const add2 = (type, ref, name, identity2 = name) => result.push({ ref, type, name, identity: `${type}:${norm5(identity2)}` });
53837
+ for (const u of planUsers(plan)) add2("user", u.ref, userDisplayName(u), u.email);
53775
53838
  for (const p of plan.pipelines ?? []) {
53776
- add("pipeline", p.ref, p.name);
53777
- for (const stage of p.stages) add("stage", stage.ref, stage.name, `${p.ref}:${p.name}:${stage.name}`);
53839
+ add2("pipeline", p.ref, p.name);
53840
+ for (const stage of p.stages) add2("stage", stage.ref, stage.name, `${p.ref}:${p.name}:${stage.name}`);
53778
53841
  }
53779
53842
  for (const [type, objects] of [
53780
53843
  ["field", plan.customFields],
@@ -53785,7 +53848,7 @@ function bindingIdentities(plan) {
53785
53848
  ["workflow", plan.workflows],
53786
53849
  ["email_template", planEmailTemplates(plan)],
53787
53850
  ["sms_template", planSmsTemplates(plan)]
53788
- ]) for (const obj of objects ?? []) add(type, obj.ref, obj.name);
53851
+ ]) for (const obj of objects ?? []) add2(type, obj.ref, obj.name);
53789
53852
  return result;
53790
53853
  }
53791
53854
  function matchingPriorBindings(plan, previous, ids = {}) {
@@ -55011,13 +55074,13 @@ ${text3}`);
55011
55074
  };
55012
55075
  }
55013
55076
  function makePipelineApi(builderClient) {
55014
- return async (method, path42, body) => {
55015
- const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path42}`;
55077
+ return async (method, path41, body) => {
55078
+ const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path41}`;
55016
55079
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
55017
55080
  const response = await builderRequest(builderClient, method, url, sendsBody ? { body } : {});
55018
55081
  if (!response.ok) {
55019
55082
  const text3 = await response.text();
55020
- throw new Error(`Pipeline API ${response.status}: ${method} ${path42}
55083
+ throw new Error(`Pipeline API ${response.status}: ${method} ${path41}
55021
55084
  ${text3}`);
55022
55085
  }
55023
55086
  const text2 = await response.text();
@@ -55030,8 +55093,8 @@ ${text3}`);
55030
55093
  };
55031
55094
  }
55032
55095
  function makeFunnelApi(builderClient) {
55033
- return async (method, path42, body) => {
55034
- const url = `https://backend.leadconnectorhq.com/funnels${path42}`;
55096
+ return async (method, path41, body) => {
55097
+ const url = `https://backend.leadconnectorhq.com/funnels${path41}`;
55035
55098
  const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
55036
55099
  const response = await builderRequest(builderClient, method, url, {
55037
55100
  ...sendsBody ? { body } : {},
@@ -55044,7 +55107,7 @@ function makeFunnelApi(builderClient) {
55044
55107
  });
55045
55108
  if (!response.ok) {
55046
55109
  const text3 = await response.text();
55047
- throw new Error(`Funnel API ${response.status}: ${method} ${path42}
55110
+ throw new Error(`Funnel API ${response.status}: ${method} ${path41}
55048
55111
  ${text3.slice(0, 300)}`);
55049
55112
  }
55050
55113
  const text2 = await response.text();
@@ -56359,7 +56422,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env2 = process
56359
56422
  return findings.map((finding) => ({ finding, because: `"${finding.id}" cannot be checked: no saved key for sub-account ${loc}. Register it (register_location) or point the server at it first.` }));
56360
56423
  }
56361
56424
  const reader = token2 ? new GHLClient({ apiKey: token2.apiKey, locationId: loc }) : client;
56362
- return refuseUnseenFindings2((path42, params) => reader.get(path42, params ? { params } : void 0), loc, findings);
56425
+ return refuseUnseenFindings2((path41, params) => reader.get(path41, params ? { params } : void 0), loc, findings);
56363
56426
  }, () => client.defaultLocationId);
56364
56427
  registerClientEngagementTools(wrap(CLIENT_ENGAGEMENTS_MODULE), registry2);
56365
56428
  registerAuditReportTools(wrap(AUDIT_REPORT_MODULE));
@@ -56779,8 +56842,8 @@ __export(index_exports, {
56779
56842
  });
56780
56843
  module.exports = __toCommonJS(index_exports);
56781
56844
  var dotenv2 = __toESM(require("dotenv"));
56782
- var path41 = __toESM(require("path"));
56783
- var fs43 = __toESM(require("fs"));
56845
+ var path40 = __toESM(require("path"));
56846
+ var fs42 = __toESM(require("fs"));
56784
56847
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
56785
56848
 
56786
56849
  // src/version-compare.ts
@@ -56851,12 +56914,12 @@ init_setup_tool();
56851
56914
  var import_zod87 = require("zod");
56852
56915
 
56853
56916
  // src/skill-installer.ts
56854
- var import_node_crypto14 = require("node:crypto");
56855
- var fs42 = __toESM(require("node:fs"));
56856
- var path40 = __toESM(require("node:path"));
56917
+ var import_node_crypto13 = require("node:crypto");
56918
+ var fs41 = __toESM(require("node:fs"));
56919
+ var path39 = __toESM(require("node:path"));
56857
56920
  var os7 = __toESM(require("node:os"));
56858
56921
  function sha2562(buf) {
56859
- return (0, import_node_crypto14.createHash)("sha256").update(buf).digest("hex");
56922
+ return (0, import_node_crypto13.createHash)("sha256").update(buf).digest("hex");
56860
56923
  }
56861
56924
  function isOlderRelease(candidate, installed) {
56862
56925
  const parts = (v) => v.trim().split(".").map((n) => Number.parseInt(n, 10));
@@ -56868,9 +56931,9 @@ function isOlderRelease(candidate, installed) {
56868
56931
  return false;
56869
56932
  }
56870
56933
  function bundledSkillsDir(baseDir) {
56871
- const candidate = path40.resolve(baseDir, "..", "skills");
56934
+ const candidate = path39.resolve(baseDir, "..", "skills");
56872
56935
  try {
56873
- return fs42.statSync(candidate).isDirectory() ? candidate : null;
56936
+ return fs41.statSync(candidate).isDirectory() ? candidate : null;
56874
56937
  } catch {
56875
56938
  return null;
56876
56939
  }
@@ -56878,10 +56941,10 @@ function bundledSkillsDir(baseDir) {
56878
56941
  function listFiles(root) {
56879
56942
  const out = [];
56880
56943
  const walk = (dir) => {
56881
- for (const entry of fs42.readdirSync(dir, { withFileTypes: true })) {
56882
- const full = path40.join(dir, entry.name);
56944
+ for (const entry of fs41.readdirSync(dir, { withFileTypes: true })) {
56945
+ const full = path39.join(dir, entry.name);
56883
56946
  if (entry.isDirectory()) walk(full);
56884
- else if (entry.isFile()) out.push(path40.relative(root, full));
56947
+ else if (entry.isFile()) out.push(path39.relative(root, full));
56885
56948
  }
56886
56949
  };
56887
56950
  walk(root);
@@ -56889,7 +56952,7 @@ function listFiles(root) {
56889
56952
  }
56890
56953
  function readMarker(markerPath) {
56891
56954
  try {
56892
- const parsed2 = JSON.parse(fs42.readFileSync(markerPath, "utf8"));
56955
+ const parsed2 = JSON.parse(fs41.readFileSync(markerPath, "utf8"));
56893
56956
  return parsed2 && typeof parsed2 === "object" && parsed2.files ? parsed2 : null;
56894
56957
  } catch {
56895
56958
  return null;
@@ -56903,35 +56966,35 @@ function installBundledSkills(opts) {
56903
56966
  skippedOlderPackage: [],
56904
56967
  unchanged: [],
56905
56968
  errors: [],
56906
- targetDir: opts.targetDir ?? path40.join(os7.homedir(), ".claude", "skills"),
56969
+ targetDir: opts.targetDir ?? path39.join(os7.homedir(), ".claude", "skills"),
56907
56970
  bundledDir: null
56908
56971
  };
56909
56972
  const bundled = bundledSkillsDir(opts.baseDir);
56910
56973
  result.bundledDir = bundled;
56911
56974
  if (!bundled) return result;
56912
56975
  try {
56913
- fs42.mkdirSync(result.targetDir, { recursive: true });
56976
+ fs41.mkdirSync(result.targetDir, { recursive: true });
56914
56977
  } catch (e) {
56915
56978
  result.errors.push(`cannot create ${result.targetDir}: ${String(e)}`);
56916
56979
  return result;
56917
56980
  }
56918
- const markerPath = path40.join(result.targetDir, ".ghl-command-skills.json");
56981
+ const markerPath = path39.join(result.targetDir, ".ghl-command-skills.json");
56919
56982
  const marker = readMarker(markerPath) ?? { packageVersion: "", files: {} };
56920
56983
  const newMarker = { packageVersion: opts.packageVersion, files: { ...marker.files } };
56921
56984
  for (const rel of listFiles(bundled)) {
56922
56985
  try {
56923
- const src = fs42.readFileSync(path40.join(bundled, rel));
56924
- const dest = path40.join(result.targetDir, rel);
56986
+ const src = fs41.readFileSync(path39.join(bundled, rel));
56987
+ const dest = path39.join(result.targetDir, rel);
56925
56988
  const srcHash = sha2562(src);
56926
56989
  let destBuf = null;
56927
56990
  try {
56928
- destBuf = fs42.readFileSync(dest);
56991
+ destBuf = fs41.readFileSync(dest);
56929
56992
  } catch {
56930
56993
  destBuf = null;
56931
56994
  }
56932
56995
  if (destBuf === null) {
56933
- fs42.mkdirSync(path40.dirname(dest), { recursive: true });
56934
- fs42.writeFileSync(dest, src);
56996
+ fs41.mkdirSync(path39.dirname(dest), { recursive: true });
56997
+ fs41.writeFileSync(dest, src);
56935
56998
  newMarker.files[rel] = srcHash;
56936
56999
  result.installed.push(rel);
56937
57000
  continue;
@@ -56948,7 +57011,7 @@ function installBundledSkills(opts) {
56948
57011
  newMarker.packageVersion = marker.packageVersion;
56949
57012
  result.skippedOlderPackage.push(rel);
56950
57013
  } else if (lastWritten && destHash === lastWritten) {
56951
- fs42.writeFileSync(dest, src);
57014
+ fs41.writeFileSync(dest, src);
56952
57015
  newMarker.files[rel] = srcHash;
56953
57016
  result.updated.push(rel);
56954
57017
  } else {
@@ -56959,7 +57022,7 @@ function installBundledSkills(opts) {
56959
57022
  }
56960
57023
  }
56961
57024
  try {
56962
- fs42.writeFileSync(markerPath, JSON.stringify(newMarker, null, 2));
57025
+ fs41.writeFileSync(markerPath, JSON.stringify(newMarker, null, 2));
56963
57026
  } catch (e) {
56964
57027
  result.errors.push(`marker write failed: ${String(e)}`);
56965
57028
  }
@@ -57115,7 +57178,7 @@ dotenv2.config();
57115
57178
  setPkgVersion(pkg.version);
57116
57179
  {
57117
57180
  const configDirOverride = process.env.GHL_MCP_CONFIG_DIR?.trim();
57118
- if (configDirOverride && !path41.isAbsolute(configDirOverride)) {
57181
+ if (configDirOverride && !path40.isAbsolute(configDirOverride)) {
57119
57182
  process.stderr.write(
57120
57183
  `[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.
57121
57184
  `
@@ -57128,20 +57191,20 @@ process.on("unhandledRejection", (reason3) => {
57128
57191
  `);
57129
57192
  });
57130
57193
  function hardenSecretFilePerms() {
57131
- const repoDir = path41.resolve(__dirname, "..");
57194
+ const repoDir = path40.resolve(__dirname, "..");
57132
57195
  const candidates = [
57133
- { file: path41.join(repoDir, "start-mcp.sh"), mode: 448 },
57196
+ { file: path40.join(repoDir, "start-mcp.sh"), mode: 448 },
57134
57197
  // Legacy registry location (pre-migration); new location lives in app-data.
57135
- { file: path41.join(repoDir, ".ghl-tokens.json"), mode: 384 },
57198
+ { file: path40.join(repoDir, ".ghl-tokens.json"), mode: 384 },
57136
57199
  { file: tokenRegistryPath(), mode: 384 }
57137
57200
  ];
57138
57201
  for (const { file: file2, mode } of candidates) {
57139
57202
  let current;
57140
57203
  try {
57141
- if (!fs43.existsSync(file2)) continue;
57142
- current = fs43.statSync(file2).mode & 511;
57204
+ if (!fs42.existsSync(file2)) continue;
57205
+ current = fs42.statSync(file2).mode & 511;
57143
57206
  if (current !== mode) {
57144
- fs43.chmodSync(file2, mode);
57207
+ fs42.chmodSync(file2, mode);
57145
57208
  }
57146
57209
  } catch (error) {
57147
57210
  const message = error instanceof Error ? error.message : String(error);