@elitedcs/ghl-mcp 3.84.6 → 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/CHANGELOG.md +4 -0
- package/README.md +1 -1
- package/dist/index.js +551 -626
- package/guide/guide.html +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -446,13 +446,13 @@ function setProtectedAccount(locationId2, name, file2 = accountRulesPath()) {
|
|
|
446
446
|
function isWriteMethod(method) {
|
|
447
447
|
return WRITE_METHODS.has(method.toUpperCase());
|
|
448
448
|
}
|
|
449
|
-
function locationIdsInRequest(
|
|
449
|
+
function locationIdsInRequest(path41, opts = {}) {
|
|
450
450
|
const found = /* @__PURE__ */ new Set();
|
|
451
451
|
const add2 = (v) => {
|
|
452
452
|
if (typeof v === "string" && v.trim()) found.add(v.trim());
|
|
453
453
|
else if (Array.isArray(v)) v.forEach(add2);
|
|
454
454
|
};
|
|
455
|
-
const seg = /\/locations\/([^/?#]+)/i.exec(
|
|
455
|
+
const seg = /\/locations\/([^/?#]+)/i.exec(path41);
|
|
456
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;
|
|
@@ -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,
|
|
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(
|
|
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(
|
|
650
|
-
const url = new 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,
|
|
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,
|
|
663
|
+
return retryAccountRead(() => this.request(method, path41, options, attempt), `${method} ${path41}`);
|
|
664
664
|
}
|
|
665
665
|
if (attempt === 0) {
|
|
666
|
-
assertWriteAllowed(method,
|
|
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(
|
|
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} ${
|
|
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} ${
|
|
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,
|
|
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} ${
|
|
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,
|
|
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} ${
|
|
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(
|
|
742
|
-
return this.request("GET",
|
|
741
|
+
async get(path41, options) {
|
|
742
|
+
return this.request("GET", path41, options);
|
|
743
743
|
}
|
|
744
|
-
async post(
|
|
745
|
-
return this.request("POST",
|
|
744
|
+
async post(path41, options) {
|
|
745
|
+
return this.request("POST", path41, options);
|
|
746
746
|
}
|
|
747
|
-
async put(
|
|
748
|
-
return this.request("PUT",
|
|
747
|
+
async put(path41, options) {
|
|
748
|
+
return this.request("PUT", path41, options);
|
|
749
749
|
}
|
|
750
|
-
async patch(
|
|
751
|
-
return this.request("PATCH",
|
|
750
|
+
async patch(path41, options) {
|
|
751
|
+
return this.request("PATCH", path41, options);
|
|
752
752
|
}
|
|
753
|
-
async delete(
|
|
754
|
-
return this.request("DELETE",
|
|
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,
|
|
7111
|
-
const response = await builderRequest(client, method, `${EMAIL_BUILDER_BASE}${
|
|
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${
|
|
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
|
|
10925
|
-
const response = await fetcher(`https://backend.leadconnectorhq.com/funnels${
|
|
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 ${
|
|
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(
|
|
10988
|
-
return client.request("GET",
|
|
10985
|
+
async function internalGet(path41) {
|
|
10986
|
+
return client.request("GET", path41);
|
|
10989
10987
|
}
|
|
10990
|
-
async function internalPost(
|
|
10991
|
-
return client.request("POST",
|
|
10988
|
+
async function internalPost(path41, body) {
|
|
10989
|
+
return client.request("POST", path41, body);
|
|
10992
10990
|
}
|
|
10993
|
-
async function internalPut(
|
|
10994
|
-
return client.request("PUT",
|
|
10991
|
+
async function internalPut(path41, body) {
|
|
10992
|
+
return client.request("PUT", path41, body);
|
|
10995
10993
|
}
|
|
10996
|
-
async function internalDelete(
|
|
10997
|
-
return client.request("DELETE",
|
|
10994
|
+
async function internalDelete(path41) {
|
|
10995
|
+
return client.request("DELETE", path41);
|
|
10998
10996
|
}
|
|
10999
|
-
async function funnelRequest(method,
|
|
11000
|
-
const url = `https://backend.leadconnectorhq.com/funnels${
|
|
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} ${
|
|
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,
|
|
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) =>
|
|
11607
|
-
assertWriteAllowed("POST", SVC +
|
|
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 +
|
|
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 ${
|
|
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,
|
|
11972
|
-
if (Array.isArray(node)) return void node.forEach((x, i) => walk(x, `${
|
|
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, `${
|
|
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:
|
|
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 = (
|
|
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(
|
|
16654
|
+
function brandedPath(path41, name, taken) {
|
|
16657
16655
|
const normalize = (s) => s.replace(/^\/+|\/+$/g, "").toLowerCase();
|
|
16658
|
-
const base = normalize(
|
|
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 [
|
|
16687
|
-
suffix = from.slice(
|
|
16688
|
-
matches = destinations.filter((d2) => d2.path && normalize(d2.path) === normalize(
|
|
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,
|
|
16772
|
-
const response = await builderRequest(client, method, `https://backend.leadconnectorhq.com/funnels${
|
|
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} ${
|
|
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,
|
|
17651
|
-
const url = `https://backend.leadconnectorhq.com/forms${
|
|
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} ${
|
|
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,
|
|
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
|
|
17833
|
-
if (formId)
|
|
17834
|
-
if (skip)
|
|
17835
|
-
const result = await formRequest("GET",
|
|
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,
|
|
18244
|
-
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${
|
|
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} ${
|
|
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-
|
|
20010
|
-
|
|
20011
|
-
|
|
20012
|
-
|
|
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
|
|
|
@@ -20156,7 +20115,6 @@ var init_registry = __esm({
|
|
|
20156
20115
|
revoke: "Disconnect Google Drive in your Claude's connector settings.",
|
|
20157
20116
|
tools: {}
|
|
20158
20117
|
},
|
|
20159
|
-
{ id: "meta-ads", name: "Meta Ads", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} },
|
|
20160
20118
|
{ id: "zoom", name: "Zoom", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} },
|
|
20161
20119
|
{ id: "plaud", name: "Plaud", builtState: "not-built", whatItIs: "", checkedOn: null, gives: "Not built yet", needs: [], steps: [], say: [], revoke: "", tools: {} }
|
|
20162
20120
|
];
|
|
@@ -20165,11 +20123,11 @@ var init_registry = __esm({
|
|
|
20165
20123
|
|
|
20166
20124
|
// src/command-os/connectors/store.ts
|
|
20167
20125
|
function connectorsPath() {
|
|
20168
|
-
return
|
|
20126
|
+
return path10.join(appDataDir(), "connectors.json");
|
|
20169
20127
|
}
|
|
20170
20128
|
function readFile() {
|
|
20171
20129
|
try {
|
|
20172
|
-
const raw =
|
|
20130
|
+
const raw = fs11.readFileSync(connectorsPath(), "utf-8");
|
|
20173
20131
|
const parsed2 = JSON.parse(raw);
|
|
20174
20132
|
if (!parsed2 || typeof parsed2 !== "object" || !parsed2.connectors) return { v: 1, connectors: {} };
|
|
20175
20133
|
return parsed2;
|
|
@@ -20181,7 +20139,7 @@ function readForWrite() {
|
|
|
20181
20139
|
const target = connectorsPath();
|
|
20182
20140
|
let raw;
|
|
20183
20141
|
try {
|
|
20184
|
-
raw =
|
|
20142
|
+
raw = fs11.readFileSync(target, "utf-8");
|
|
20185
20143
|
} catch (e) {
|
|
20186
20144
|
if (e?.code === "ENOENT") return { v: 1, connectors: {} };
|
|
20187
20145
|
throw new Error("Your connector file could not be read, so nothing was changed. Nothing was lost.");
|
|
@@ -20193,8 +20151,8 @@ function readForWrite() {
|
|
|
20193
20151
|
} catch {
|
|
20194
20152
|
const kept = `${target}.unreadable-${Date.now()}`;
|
|
20195
20153
|
try {
|
|
20196
|
-
|
|
20197
|
-
|
|
20154
|
+
fs11.copyFileSync(target, kept);
|
|
20155
|
+
fs11.chmodSync(kept, 384);
|
|
20198
20156
|
} catch {
|
|
20199
20157
|
}
|
|
20200
20158
|
throw new Error(
|
|
@@ -20208,31 +20166,36 @@ function writeFile(f) {
|
|
|
20208
20166
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
20209
20167
|
let renamed = false;
|
|
20210
20168
|
try {
|
|
20211
|
-
|
|
20169
|
+
fs11.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
20212
20170
|
try {
|
|
20213
|
-
|
|
20171
|
+
fs11.chmodSync(tmp, 384);
|
|
20214
20172
|
} catch {
|
|
20215
20173
|
}
|
|
20216
|
-
|
|
20174
|
+
fs11.renameSync(tmp, target);
|
|
20217
20175
|
renamed = true;
|
|
20218
20176
|
} finally {
|
|
20219
20177
|
if (!renamed) {
|
|
20220
20178
|
try {
|
|
20221
|
-
|
|
20179
|
+
fs11.unlinkSync(tmp);
|
|
20222
20180
|
} catch {
|
|
20223
20181
|
}
|
|
20224
20182
|
}
|
|
20225
20183
|
}
|
|
20226
20184
|
try {
|
|
20227
|
-
|
|
20185
|
+
fs11.chmodSync(target, 384);
|
|
20228
20186
|
} catch {
|
|
20229
20187
|
}
|
|
20230
20188
|
}
|
|
20231
20189
|
function safeLabel(label, key) {
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
const
|
|
20235
|
-
|
|
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;
|
|
20236
20199
|
}
|
|
20237
20200
|
function connect(system, key, label, now = () => /* @__PURE__ */ new Date(), verified = true) {
|
|
20238
20201
|
const trimmed = String(key ?? "").trim();
|
|
@@ -20255,7 +20218,7 @@ function summaryOf(s) {
|
|
|
20255
20218
|
}
|
|
20256
20219
|
function listConnectors(options = {}) {
|
|
20257
20220
|
try {
|
|
20258
|
-
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(
|
|
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")));
|
|
20259
20222
|
const summaries = [];
|
|
20260
20223
|
for (const [system, value] of Object.entries(file2.connectors)) {
|
|
20261
20224
|
if (!SystemSchema.safeParse(system).success) continue;
|
|
@@ -20281,16 +20244,16 @@ async function withKey(system, fn) {
|
|
|
20281
20244
|
if (!s) throw new Error(`${system} is not connected on this machine.`);
|
|
20282
20245
|
return fn(s.key);
|
|
20283
20246
|
}
|
|
20284
|
-
var
|
|
20247
|
+
var fs11, import_zod50, path10, hintOf, SystemSchema, SummarySourceSchema;
|
|
20285
20248
|
var init_store2 = __esm({
|
|
20286
20249
|
"src/command-os/connectors/store.ts"() {
|
|
20287
20250
|
"use strict";
|
|
20288
|
-
|
|
20251
|
+
fs11 = __toESM(require("node:fs"));
|
|
20289
20252
|
import_zod50 = require("zod");
|
|
20290
|
-
|
|
20253
|
+
path10 = __toESM(require("node:path"));
|
|
20291
20254
|
init_credentials_store();
|
|
20292
20255
|
hintOf = (key) => `\u2026${String(key).slice(-4)}`;
|
|
20293
|
-
SystemSchema = import_zod50.z.enum(["ghl", "stripe", "google-workspace", "meeting-capture", "slack", "
|
|
20256
|
+
SystemSchema = import_zod50.z.enum(["ghl", "stripe", "google-workspace", "meeting-capture", "slack", "byo"]);
|
|
20294
20257
|
SummarySourceSchema = import_zod50.z.object({
|
|
20295
20258
|
system: SystemSchema,
|
|
20296
20259
|
key: import_zod50.z.string().min(1),
|
|
@@ -20764,7 +20727,7 @@ var init_stripe = __esm({
|
|
|
20764
20727
|
// src/command-os/connectors/google-calendar-store.ts
|
|
20765
20728
|
function read() {
|
|
20766
20729
|
try {
|
|
20767
|
-
return SecretSchema.parse(JSON.parse(
|
|
20730
|
+
return SecretSchema.parse(JSON.parse(fs12.readFileSync(googleCalendarPath(), "utf8")));
|
|
20768
20731
|
} catch (error) {
|
|
20769
20732
|
if (error.code === "ENOENT") return null;
|
|
20770
20733
|
throw new Error("The Google Calendar sign-in on this machine could not be read. Connect your Google Calendar again.");
|
|
@@ -20787,16 +20750,16 @@ function saveCalendarSecret(secret) {
|
|
|
20787
20750
|
try {
|
|
20788
20751
|
const validated = SecretSchema.parse(secret);
|
|
20789
20752
|
const dir = ensureAppDataDir();
|
|
20790
|
-
if (process.platform !== "win32")
|
|
20791
|
-
tmp = `${googleCalendarPath()}.${(0,
|
|
20792
|
-
|
|
20793
|
-
|
|
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());
|
|
20794
20757
|
} catch {
|
|
20795
20758
|
throw new Error("The Google Calendar sign-in could not be saved privately on this machine. Nothing new was saved.");
|
|
20796
20759
|
} finally {
|
|
20797
20760
|
if (tmp) {
|
|
20798
20761
|
try {
|
|
20799
|
-
|
|
20762
|
+
fs12.unlinkSync(tmp);
|
|
20800
20763
|
} catch {
|
|
20801
20764
|
}
|
|
20802
20765
|
}
|
|
@@ -20804,20 +20767,20 @@ function saveCalendarSecret(secret) {
|
|
|
20804
20767
|
}
|
|
20805
20768
|
function removeCalendarSecret() {
|
|
20806
20769
|
try {
|
|
20807
|
-
|
|
20770
|
+
fs12.unlinkSync(googleCalendarPath());
|
|
20808
20771
|
return true;
|
|
20809
20772
|
} catch (error) {
|
|
20810
20773
|
if (error.code === "ENOENT") return false;
|
|
20811
20774
|
throw new Error("The Google Calendar sign-in could not be removed from this machine.");
|
|
20812
20775
|
}
|
|
20813
20776
|
}
|
|
20814
|
-
var
|
|
20777
|
+
var fs12, path11, import_node_crypto4, import_zod51, CALENDAR_SCOPE, SecretSchema, googleCalendarPath;
|
|
20815
20778
|
var init_google_calendar_store = __esm({
|
|
20816
20779
|
"src/command-os/connectors/google-calendar-store.ts"() {
|
|
20817
20780
|
"use strict";
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
|
|
20781
|
+
fs12 = __toESM(require("node:fs"));
|
|
20782
|
+
path11 = __toESM(require("node:path"));
|
|
20783
|
+
import_node_crypto4 = require("node:crypto");
|
|
20821
20784
|
import_zod51 = require("zod");
|
|
20822
20785
|
init_credentials_store();
|
|
20823
20786
|
CALENDAR_SCOPE = "https://www.googleapis.com/auth/calendar.readonly";
|
|
@@ -20828,7 +20791,7 @@ var init_google_calendar_store = __esm({
|
|
|
20828
20791
|
scope: import_zod51.z.literal(CALENDAR_SCOPE),
|
|
20829
20792
|
connectedAt: import_zod51.z.string()
|
|
20830
20793
|
});
|
|
20831
|
-
googleCalendarPath = () =>
|
|
20794
|
+
googleCalendarPath = () => path11.join(appDataDir(), "google-calendar.json");
|
|
20832
20795
|
}
|
|
20833
20796
|
});
|
|
20834
20797
|
|
|
@@ -20950,16 +20913,16 @@ function createGoogleCalendar(deps = {}) {
|
|
|
20950
20913
|
requireOnlyCalendar(result.scope);
|
|
20951
20914
|
return result.access_token;
|
|
20952
20915
|
}
|
|
20953
|
-
async function pages(
|
|
20916
|
+
async function pages(path41, access, item, query = {}) {
|
|
20954
20917
|
const result = [];
|
|
20955
20918
|
const seen = /* @__PURE__ */ new Set();
|
|
20956
20919
|
let pageToken;
|
|
20957
20920
|
for (let page = 0; page < 100; page++) {
|
|
20958
|
-
const url = new URL(`${API}${
|
|
20921
|
+
const url = new URL(`${API}${path41}`);
|
|
20959
20922
|
for (const [k, v] of Object.entries(query)) url.searchParams.set(k, v);
|
|
20960
20923
|
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
20961
20924
|
const data = parsed(
|
|
20962
|
-
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 === (
|
|
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")),
|
|
20963
20926
|
await request(url.href, { headers: { Authorization: `Bearer ${access}` } })
|
|
20964
20927
|
);
|
|
20965
20928
|
result.push(...data.items ?? []);
|
|
@@ -20977,8 +20940,8 @@ function createGoogleCalendar(deps = {}) {
|
|
|
20977
20940
|
async function start() {
|
|
20978
20941
|
const app = appConfig();
|
|
20979
20942
|
clearPending2();
|
|
20980
|
-
const state = (0,
|
|
20981
|
-
const verifier = (0,
|
|
20943
|
+
const state = (0, import_node_crypto5.randomBytes)(32).toString("base64url");
|
|
20944
|
+
const verifier = (0, import_node_crypto5.randomBytes)(32).toString("base64url");
|
|
20982
20945
|
const server2 = (deps.createServer ?? import_node_http.createServer)((req, res) => {
|
|
20983
20946
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
20984
20947
|
res.setHeader("Cache-Control", "no-store");
|
|
@@ -21032,7 +20995,7 @@ function createGoogleCalendar(deps = {}) {
|
|
|
21032
20995
|
response_type: "code",
|
|
21033
20996
|
scope: CALENDAR_SCOPE,
|
|
21034
20997
|
state,
|
|
21035
|
-
code_challenge: (0,
|
|
20998
|
+
code_challenge: (0, import_node_crypto5.createHash)("sha256").update(verifier).digest("base64url"),
|
|
21036
20999
|
code_challenge_method: "S256",
|
|
21037
21000
|
access_type: "offline",
|
|
21038
21001
|
prompt: "consent"
|
|
@@ -21162,13 +21125,13 @@ function createGoogleCalendar(deps = {}) {
|
|
|
21162
21125
|
close: clearPending2
|
|
21163
21126
|
};
|
|
21164
21127
|
}
|
|
21165
|
-
var import_node_http,
|
|
21128
|
+
var import_node_http, import_node_crypto5, import_node_child_process, import_zod52, TOKEN_URL, REVOKE_URL, API, tokenSchema, calendarSchema, eventSchema;
|
|
21166
21129
|
var init_google_calendar = __esm({
|
|
21167
21130
|
"src/command-os/connectors/google-calendar.ts"() {
|
|
21168
21131
|
"use strict";
|
|
21169
21132
|
init_any_signal();
|
|
21170
21133
|
import_node_http = require("node:http");
|
|
21171
|
-
|
|
21134
|
+
import_node_crypto5 = require("node:crypto");
|
|
21172
21135
|
import_node_child_process = require("node:child_process");
|
|
21173
21136
|
import_zod52 = require("zod");
|
|
21174
21137
|
init_credentials_store();
|
|
@@ -21210,8 +21173,8 @@ function redactConnectionKey(value, key) {
|
|
|
21210
21173
|
return value;
|
|
21211
21174
|
}
|
|
21212
21175
|
function stripeFetcher(key, signal) {
|
|
21213
|
-
return async (
|
|
21214
|
-
const url = new URL(`https://api.stripe.com${
|
|
21176
|
+
return async (path41, query) => {
|
|
21177
|
+
const url = new URL(`https://api.stripe.com${path41}`);
|
|
21215
21178
|
for (const [k, v] of Object.entries(query ?? {})) url.searchParams.set(k, v);
|
|
21216
21179
|
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` }, signal });
|
|
21217
21180
|
if (!res.ok) {
|
|
@@ -21300,11 +21263,11 @@ var init_handlers = __esm({
|
|
|
21300
21263
|
});
|
|
21301
21264
|
|
|
21302
21265
|
// src/command-os/connectors/stripe-read.ts
|
|
21303
|
-
async function listAll(f,
|
|
21266
|
+
async function listAll(f, path41, schema, extra = {}) {
|
|
21304
21267
|
const out = [];
|
|
21305
21268
|
let after;
|
|
21306
21269
|
for (let page = 0; page < 20; page++) {
|
|
21307
|
-
const result = import_zod53.z.object({ data: import_zod53.z.array(schema), has_more: import_zod53.z.boolean().optional() }).parse(await f(
|
|
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 } : {} }));
|
|
21308
21271
|
out.push(...result.data);
|
|
21309
21272
|
if (!result.has_more) return out;
|
|
21310
21273
|
const last = import_zod53.z.object({ id: import_zod53.z.string().min(1) }).parse(result.data.at(-1));
|
|
@@ -21383,7 +21346,7 @@ var init_stripe_read = __esm({
|
|
|
21383
21346
|
// src/client-engagements.ts
|
|
21384
21347
|
function clientEngagementsPath() {
|
|
21385
21348
|
const override = process.env[CLIENT_ENGAGEMENTS_ENV];
|
|
21386
|
-
return override && override.trim() ? override :
|
|
21349
|
+
return override && override.trim() ? override : path12.join(appDataDir(), "client-engagements.json");
|
|
21387
21350
|
}
|
|
21388
21351
|
function isAgencyClient(e) {
|
|
21389
21352
|
return (e.kind ?? DEFAULT_ENGAGEMENT_KIND) === "client";
|
|
@@ -21442,7 +21405,7 @@ function sanitizeEngagements(raw) {
|
|
|
21442
21405
|
}
|
|
21443
21406
|
function readClientEngagements(file2 = clientEngagementsPath()) {
|
|
21444
21407
|
try {
|
|
21445
|
-
const raw = JSON.parse(
|
|
21408
|
+
const raw = JSON.parse(fs13.readFileSync(file2, "utf8"));
|
|
21446
21409
|
if (raw && typeof raw === "object") return sanitizeEngagements(raw);
|
|
21447
21410
|
} catch {
|
|
21448
21411
|
}
|
|
@@ -21469,7 +21432,7 @@ function writeClientEngagement(locationId2, patch, file2 = clientEngagementsPath
|
|
|
21469
21432
|
if (!id || FORBIDDEN_KEY.has(id)) throw new Error("An id is required.");
|
|
21470
21433
|
const stamp = () => {
|
|
21471
21434
|
try {
|
|
21472
|
-
return
|
|
21435
|
+
return fs13.readFileSync(file2, "utf8");
|
|
21473
21436
|
} catch {
|
|
21474
21437
|
return "";
|
|
21475
21438
|
}
|
|
@@ -21489,20 +21452,20 @@ function writeClientEngagement(locationId2, patch, file2 = clientEngagementsPath
|
|
|
21489
21452
|
};
|
|
21490
21453
|
const persist = (next) => {
|
|
21491
21454
|
if (file2 === clientEngagementsPath() && !process.env[CLIENT_ENGAGEMENTS_ENV]) ensureAppDataDir();
|
|
21492
|
-
|
|
21455
|
+
fs13.mkdirSync(path12.dirname(file2), { recursive: true });
|
|
21493
21456
|
const tmp = `${file2}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
21494
21457
|
try {
|
|
21495
|
-
|
|
21458
|
+
fs13.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
21496
21459
|
if (process.platform !== "win32") {
|
|
21497
21460
|
try {
|
|
21498
|
-
|
|
21461
|
+
fs13.chmodSync(tmp, 384);
|
|
21499
21462
|
} catch {
|
|
21500
21463
|
}
|
|
21501
21464
|
}
|
|
21502
|
-
|
|
21465
|
+
fs13.renameSync(tmp, file2);
|
|
21503
21466
|
} catch (e) {
|
|
21504
21467
|
try {
|
|
21505
|
-
|
|
21468
|
+
fs13.unlinkSync(tmp);
|
|
21506
21469
|
} catch {
|
|
21507
21470
|
}
|
|
21508
21471
|
throw e;
|
|
@@ -21574,12 +21537,12 @@ function monthlyFloor(roster, profile) {
|
|
|
21574
21537
|
byKind
|
|
21575
21538
|
};
|
|
21576
21539
|
}
|
|
21577
|
-
var
|
|
21540
|
+
var fs13, path12, CLIENT_ENGAGEMENTS_ENV, ENGAGEMENT_STATUSES, ENGAGEMENT_KINDS, DEFAULT_ENGAGEMENT_KIND, EMPTY2, MAX_NOTES, MAX_SOP2, MAX_CLIENTS, FORBIDDEN_KEY;
|
|
21578
21541
|
var init_client_engagements = __esm({
|
|
21579
21542
|
"src/client-engagements.ts"() {
|
|
21580
21543
|
"use strict";
|
|
21581
|
-
|
|
21582
|
-
|
|
21544
|
+
fs13 = __toESM(require("fs"));
|
|
21545
|
+
path12 = __toESM(require("path"));
|
|
21583
21546
|
init_credentials_store();
|
|
21584
21547
|
init_field_sanitize();
|
|
21585
21548
|
CLIENT_ENGAGEMENTS_ENV = "GHL_MCP_CLIENT_ENGAGEMENTS";
|
|
@@ -21597,7 +21560,7 @@ var init_client_engagements = __esm({
|
|
|
21597
21560
|
// src/board-roster.ts
|
|
21598
21561
|
function readBoardState() {
|
|
21599
21562
|
try {
|
|
21600
|
-
const raw = JSON.parse(
|
|
21563
|
+
const raw = JSON.parse(fs14.readFileSync(path13.join(appDataDir(), "cockpit-state.json"), "utf8"));
|
|
21601
21564
|
if (raw && typeof raw === "object" && raw.clients && typeof raw.clients === "object") return raw;
|
|
21602
21565
|
} catch {
|
|
21603
21566
|
}
|
|
@@ -21615,12 +21578,12 @@ function knownClients(registry2, state) {
|
|
|
21615
21578
|
}
|
|
21616
21579
|
return [...out.values()];
|
|
21617
21580
|
}
|
|
21618
|
-
var
|
|
21581
|
+
var fs14, path13;
|
|
21619
21582
|
var init_board_roster = __esm({
|
|
21620
21583
|
"src/board-roster.ts"() {
|
|
21621
21584
|
"use strict";
|
|
21622
|
-
|
|
21623
|
-
|
|
21585
|
+
fs14 = __toESM(require("fs"));
|
|
21586
|
+
path13 = __toESM(require("path"));
|
|
21624
21587
|
init_credentials_store();
|
|
21625
21588
|
init_client_engagements();
|
|
21626
21589
|
}
|
|
@@ -21835,17 +21798,17 @@ var init_stage_boundary = __esm({
|
|
|
21835
21798
|
// src/plan-guide.ts
|
|
21836
21799
|
function skillRoot() {
|
|
21837
21800
|
const candidates = [
|
|
21838
|
-
|
|
21801
|
+
path14.join(__dirname, "..", "skills", "blueprint"),
|
|
21839
21802
|
// dist/ → package root
|
|
21840
|
-
|
|
21803
|
+
path14.join(__dirname, "..", "..", "skills", "blueprint"),
|
|
21841
21804
|
// src/ in dev
|
|
21842
|
-
|
|
21805
|
+
path14.join(process.cwd(), "skills", "blueprint")
|
|
21843
21806
|
];
|
|
21844
|
-
return candidates.find((c) =>
|
|
21807
|
+
return candidates.find((c) => fs15.existsSync(path14.join(c, "references", "build-plan-schema.md"))) ?? null;
|
|
21845
21808
|
}
|
|
21846
21809
|
function readIf(p, max) {
|
|
21847
21810
|
try {
|
|
21848
|
-
const t =
|
|
21811
|
+
const t = fs15.readFileSync(p, "utf8");
|
|
21849
21812
|
return t.length > max ? t.slice(0, max) : t;
|
|
21850
21813
|
} catch {
|
|
21851
21814
|
return null;
|
|
@@ -21858,12 +21821,12 @@ function presetForIndustry(industry) {
|
|
|
21858
21821
|
function loadPlanGuide(industry) {
|
|
21859
21822
|
const root = skillRoot();
|
|
21860
21823
|
if (!root) return "";
|
|
21861
|
-
const schema = readIf(
|
|
21824
|
+
const schema = readIf(path14.join(root, "references", "build-plan-schema.md"), CAP_SCHEMA);
|
|
21862
21825
|
const presetName = presetForIndustry(industry);
|
|
21863
|
-
const preset = readIf(
|
|
21826
|
+
const preset = readIf(path14.join(root, "presets", `${presetName}.preset.json`), CAP_PRESET);
|
|
21864
21827
|
const exampleFile = EXAMPLE_FOR_PRESET[presetName] ?? "sample-build-plan.json";
|
|
21865
|
-
const example = readIf(
|
|
21866
|
-
const copyGuide = readIf(
|
|
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);
|
|
21867
21830
|
if (!schema) return "";
|
|
21868
21831
|
return `
|
|
21869
21832
|
PLAN GUIDE \u2014 everything you need to write the build plan is below. Do NOT try to read files; you cannot.
|
|
@@ -21881,12 +21844,12 @@ ${example}
|
|
|
21881
21844
|
` : "") + `=== End of plan guide ===
|
|
21882
21845
|
`;
|
|
21883
21846
|
}
|
|
21884
|
-
var
|
|
21847
|
+
var fs15, path14, PRESET_FOR_INDUSTRY, EXAMPLE_FOR_PRESET, COPY_INSTRUCTION, CALENDAR_INSTRUCTION, CAP_SCHEMA, CAP_PRESET, CAP_EXAMPLE, CAP_COPY_GUIDE;
|
|
21885
21848
|
var init_plan_guide = __esm({
|
|
21886
21849
|
"src/plan-guide.ts"() {
|
|
21887
21850
|
"use strict";
|
|
21888
|
-
|
|
21889
|
-
|
|
21851
|
+
fs15 = __toESM(require("fs"));
|
|
21852
|
+
path14 = __toESM(require("path"));
|
|
21890
21853
|
PRESET_FOR_INDUSTRY = {
|
|
21891
21854
|
"med-spa": "med-spa",
|
|
21892
21855
|
clinic: "clinic",
|
|
@@ -24506,10 +24469,10 @@ function progressLine(e) {
|
|
|
24506
24469
|
}
|
|
24507
24470
|
}
|
|
24508
24471
|
function defaultProgressDir(base = appDataDir()) {
|
|
24509
|
-
return
|
|
24472
|
+
return path15.join(base, "progress");
|
|
24510
24473
|
}
|
|
24511
24474
|
function progressFilePath(dir, locationId2) {
|
|
24512
|
-
return
|
|
24475
|
+
return path15.join(dir, `${locationId2.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
|
|
24513
24476
|
}
|
|
24514
24477
|
function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DIR_ENV]) {
|
|
24515
24478
|
if (!dir) return null;
|
|
@@ -24517,10 +24480,10 @@ function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DI
|
|
|
24517
24480
|
const file2 = progressFilePath(dir, locationId2);
|
|
24518
24481
|
const write = () => {
|
|
24519
24482
|
try {
|
|
24520
|
-
|
|
24483
|
+
fs16.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
24521
24484
|
const tmp = `${file2}.tmp`;
|
|
24522
|
-
|
|
24523
|
-
|
|
24485
|
+
fs16.writeFileSync(tmp, JSON.stringify({ locationId: locationId2, progress: tracker.snapshot() }), { mode: 384 });
|
|
24486
|
+
fs16.renameSync(tmp, file2);
|
|
24524
24487
|
} catch {
|
|
24525
24488
|
}
|
|
24526
24489
|
};
|
|
@@ -24538,7 +24501,7 @@ function createProgressFileSink(locationId2, plan, dir = process.env[PROGRESS_DI
|
|
|
24538
24501
|
}
|
|
24539
24502
|
function readProgressSnapshot(dir, locationId2) {
|
|
24540
24503
|
try {
|
|
24541
|
-
const raw = JSON.parse(
|
|
24504
|
+
const raw = JSON.parse(fs16.readFileSync(progressFilePath(dir, locationId2), "utf8"));
|
|
24542
24505
|
const p = raw?.progress;
|
|
24543
24506
|
if (!p || !Array.isArray(p.groups) || typeof p.updatedAt !== "string") return null;
|
|
24544
24507
|
return p;
|
|
@@ -24567,12 +24530,12 @@ function tapPush(arr, onItem) {
|
|
|
24567
24530
|
};
|
|
24568
24531
|
Object.defineProperty(arr, "push", { value: tapped, writable: true, configurable: true, enumerable: false });
|
|
24569
24532
|
}
|
|
24570
|
-
var
|
|
24533
|
+
var fs16, path15, PROGRESS_GROUPS, GROUP_INDEX, TYPE_TO_GROUP, HALT_TYPE_TO_GROUP, CREATING_LINE, BuildProgressTracker, PROGRESS_DIR_ENV;
|
|
24571
24534
|
var init_build_progress = __esm({
|
|
24572
24535
|
"src/build-progress.ts"() {
|
|
24573
24536
|
"use strict";
|
|
24574
|
-
|
|
24575
|
-
|
|
24537
|
+
fs16 = __toESM(require("fs"));
|
|
24538
|
+
path15 = __toESM(require("path"));
|
|
24576
24539
|
init_executor();
|
|
24577
24540
|
init_credentials_store();
|
|
24578
24541
|
PROGRESS_GROUPS = [
|
|
@@ -24710,10 +24673,10 @@ var init_build_progress = __esm({
|
|
|
24710
24673
|
|
|
24711
24674
|
// src/build-journal.ts
|
|
24712
24675
|
function journalDir(base = appDataDir()) {
|
|
24713
|
-
return
|
|
24676
|
+
return path16.join(base, "build-journal");
|
|
24714
24677
|
}
|
|
24715
24678
|
function journalPath(locationId2, base) {
|
|
24716
|
-
return
|
|
24679
|
+
return path16.join(journalDir(base), `${locationId2}.jsonl`);
|
|
24717
24680
|
}
|
|
24718
24681
|
function newRunId(now = /* @__PURE__ */ new Date(), rand = defaultRand) {
|
|
24719
24682
|
const iso2 = now.toISOString();
|
|
@@ -24787,40 +24750,40 @@ function directoryFlushUnsupported(e) {
|
|
|
24787
24750
|
}
|
|
24788
24751
|
function appendJournal(record, base) {
|
|
24789
24752
|
const dir = journalDir(base);
|
|
24790
|
-
|
|
24753
|
+
fs17.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
24791
24754
|
const file2 = journalPath(record.locationId, base);
|
|
24792
24755
|
let needsBoundary = false;
|
|
24793
24756
|
try {
|
|
24794
|
-
const st =
|
|
24757
|
+
const st = fs17.statSync(file2);
|
|
24795
24758
|
if (st.size > 0) {
|
|
24796
|
-
const fd2 =
|
|
24759
|
+
const fd2 = fs17.openSync(file2, "r");
|
|
24797
24760
|
try {
|
|
24798
24761
|
const buf = Buffer.alloc(1);
|
|
24799
|
-
|
|
24762
|
+
fs17.readSync(fd2, buf, 0, 1, st.size - 1);
|
|
24800
24763
|
needsBoundary = buf[0] !== 10;
|
|
24801
24764
|
} finally {
|
|
24802
|
-
|
|
24765
|
+
fs17.closeSync(fd2);
|
|
24803
24766
|
}
|
|
24804
24767
|
}
|
|
24805
24768
|
} catch {
|
|
24806
24769
|
}
|
|
24807
|
-
const fd =
|
|
24770
|
+
const fd = fs17.openSync(file2, "a", 384);
|
|
24808
24771
|
try {
|
|
24809
|
-
|
|
24772
|
+
fs17.appendFileSync(fd, `${needsBoundary ? "\n" : ""}${JSON.stringify(record)}
|
|
24810
24773
|
`);
|
|
24811
|
-
|
|
24774
|
+
fs17.fsyncSync(fd);
|
|
24812
24775
|
} finally {
|
|
24813
|
-
|
|
24776
|
+
fs17.closeSync(fd);
|
|
24814
24777
|
}
|
|
24815
|
-
for (const directory of [dir,
|
|
24778
|
+
for (const directory of [dir, path16.dirname(dir)]) {
|
|
24816
24779
|
let dirFd;
|
|
24817
24780
|
try {
|
|
24818
|
-
dirFd =
|
|
24819
|
-
|
|
24781
|
+
dirFd = fs17.openSync(directory, "r");
|
|
24782
|
+
fs17.fsyncSync(dirFd);
|
|
24820
24783
|
} catch (e) {
|
|
24821
24784
|
if (!directoryFlushUnsupported(e)) throw e;
|
|
24822
24785
|
} finally {
|
|
24823
|
-
if (dirFd !== void 0)
|
|
24786
|
+
if (dirFd !== void 0) fs17.closeSync(dirFd);
|
|
24824
24787
|
}
|
|
24825
24788
|
}
|
|
24826
24789
|
return file2;
|
|
@@ -24828,7 +24791,7 @@ function appendJournal(record, base) {
|
|
|
24828
24791
|
function readJournal(locationId2, base) {
|
|
24829
24792
|
let raw;
|
|
24830
24793
|
try {
|
|
24831
|
-
raw =
|
|
24794
|
+
raw = fs17.readFileSync(journalPath(locationId2, base), "utf8");
|
|
24832
24795
|
} catch {
|
|
24833
24796
|
return [];
|
|
24834
24797
|
}
|
|
@@ -24899,12 +24862,12 @@ function describeRuns(locationId2, base) {
|
|
|
24899
24862
|
reverted: reverted.has(r.runId)
|
|
24900
24863
|
})).reverse();
|
|
24901
24864
|
}
|
|
24902
|
-
var
|
|
24865
|
+
var fs17, path16, DIRECTORY_FLUSH_UNSUPPORTED;
|
|
24903
24866
|
var init_build_journal = __esm({
|
|
24904
24867
|
"src/build-journal.ts"() {
|
|
24905
24868
|
"use strict";
|
|
24906
|
-
|
|
24907
|
-
|
|
24869
|
+
fs17 = __toESM(require("fs"));
|
|
24870
|
+
path16 = __toESM(require("path"));
|
|
24908
24871
|
init_credentials_store();
|
|
24909
24872
|
DIRECTORY_FLUSH_UNSUPPORTED = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "ENOSYS", "EISDIR", "EBADF"]);
|
|
24910
24873
|
}
|
|
@@ -24916,7 +24879,7 @@ function unusableShimMessage(shim) {
|
|
|
24916
24879
|
}
|
|
24917
24880
|
function runnable(p) {
|
|
24918
24881
|
try {
|
|
24919
|
-
|
|
24882
|
+
fs18.accessSync(p, fs18.constants.X_OK);
|
|
24920
24883
|
return true;
|
|
24921
24884
|
} catch {
|
|
24922
24885
|
return false;
|
|
@@ -24928,27 +24891,27 @@ function claudeFileNames(platform2, env2) {
|
|
|
24928
24891
|
return [...exts.map((ext) => `claude${ext}`), "claude"];
|
|
24929
24892
|
}
|
|
24930
24893
|
function isShim(file2) {
|
|
24931
|
-
const ext =
|
|
24894
|
+
const ext = path17.extname(file2).toLowerCase();
|
|
24932
24895
|
return ext === ".cmd" || ext === ".bat";
|
|
24933
24896
|
}
|
|
24934
24897
|
function shimTarget(shim) {
|
|
24935
24898
|
let text2;
|
|
24936
24899
|
try {
|
|
24937
|
-
text2 =
|
|
24900
|
+
text2 = fs18.readFileSync(shim, "utf8");
|
|
24938
24901
|
} catch {
|
|
24939
24902
|
return null;
|
|
24940
24903
|
}
|
|
24941
24904
|
const refs = [...text2.matchAll(/"%~?dp0%?\\([^"\r\n]+)"/g)].map((m) => m[1]);
|
|
24942
|
-
const resolve12 = (rel) =>
|
|
24905
|
+
const resolve12 = (rel) => path17.join(path17.dirname(shim), ...rel.split(/[\\/]/));
|
|
24943
24906
|
const script = refs.find((r) => /\.(?:js|cjs|mjs)$/i.test(r));
|
|
24944
24907
|
if (script) {
|
|
24945
24908
|
const p = resolve12(script);
|
|
24946
|
-
return
|
|
24909
|
+
return fs18.existsSync(p) ? { kind: "script", path: p } : null;
|
|
24947
24910
|
}
|
|
24948
24911
|
const program = refs.find((r) => /\.exe$/i.test(r) && !/(^|[\\/])node\.exe$/i.test(r));
|
|
24949
24912
|
if (program) {
|
|
24950
24913
|
const p = resolve12(program);
|
|
24951
|
-
return
|
|
24914
|
+
return fs18.existsSync(p) ? { kind: "program", path: p } : null;
|
|
24952
24915
|
}
|
|
24953
24916
|
return null;
|
|
24954
24917
|
}
|
|
@@ -24961,7 +24924,7 @@ function claudeBin(lookup = {}) {
|
|
|
24961
24924
|
let unusableShim = null;
|
|
24962
24925
|
for (const dir of dirs) {
|
|
24963
24926
|
for (const name of names) {
|
|
24964
|
-
const candidate =
|
|
24927
|
+
const candidate = path17.join(dir, name);
|
|
24965
24928
|
if (!runnable(candidate)) continue;
|
|
24966
24929
|
if (platform2 === "win32" && isShim(candidate) && !shimTarget(candidate)) {
|
|
24967
24930
|
unusableShim ??= candidate;
|
|
@@ -24970,7 +24933,7 @@ function claudeBin(lookup = {}) {
|
|
|
24970
24933
|
return candidate;
|
|
24971
24934
|
}
|
|
24972
24935
|
}
|
|
24973
|
-
const fallback =
|
|
24936
|
+
const fallback = path17.join(home, ".local", "bin", platform2 === "win32" ? "claude.exe" : "claude");
|
|
24974
24937
|
if (runnable(fallback)) return fallback;
|
|
24975
24938
|
throw new Error(unusableShim ? unusableShimMessage(unusableShim) : NOT_FOUND_MESSAGE);
|
|
24976
24939
|
}
|
|
@@ -24990,13 +24953,13 @@ function claudeCommand(bin, args, lookup = {}) {
|
|
|
24990
24953
|
if (!target) return { command: resolved2, args };
|
|
24991
24954
|
return target.kind === "script" ? { command: lookup.execPath ?? process.execPath, args: [target.path, ...args] } : { command: target.path, args };
|
|
24992
24955
|
}
|
|
24993
|
-
var
|
|
24956
|
+
var fs18, os3, path17, NOT_FOUND_MESSAGE;
|
|
24994
24957
|
var init_claude_locate = __esm({
|
|
24995
24958
|
"src/claude-locate.ts"() {
|
|
24996
24959
|
"use strict";
|
|
24997
|
-
|
|
24960
|
+
fs18 = __toESM(require("node:fs"));
|
|
24998
24961
|
os3 = __toESM(require("node:os"));
|
|
24999
|
-
|
|
24962
|
+
path17 = __toESM(require("node:path"));
|
|
25000
24963
|
NOT_FOUND_MESSAGE = "Claude Code CLI not found. Install it, then reopen the cockpit.";
|
|
25001
24964
|
}
|
|
25002
24965
|
});
|
|
@@ -25032,21 +24995,21 @@ function tooOldMessage(found) {
|
|
|
25032
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.`;
|
|
25033
24996
|
}
|
|
25034
24997
|
function enginePath() {
|
|
25035
|
-
return
|
|
24998
|
+
return path18.join(appDataDir(), "command-os-engine.json");
|
|
25036
24999
|
}
|
|
25037
25000
|
function readEngineRecord(file2 = enginePath()) {
|
|
25038
25001
|
try {
|
|
25039
|
-
const r = JSON.parse(
|
|
25002
|
+
const r = JSON.parse(fs19.readFileSync(file2, "utf8"));
|
|
25040
25003
|
return typeof r?.version === "string" ? r : null;
|
|
25041
25004
|
} catch {
|
|
25042
25005
|
return null;
|
|
25043
25006
|
}
|
|
25044
25007
|
}
|
|
25045
25008
|
function writeEngineRecord(rec, file2 = enginePath()) {
|
|
25046
|
-
|
|
25047
|
-
|
|
25009
|
+
fs19.mkdirSync(path18.dirname(file2), { recursive: true });
|
|
25010
|
+
fs19.writeFileSync(file2, JSON.stringify(rec, null, 2), { mode: 384 });
|
|
25048
25011
|
try {
|
|
25049
|
-
|
|
25012
|
+
fs19.chmodSync(file2, 384);
|
|
25050
25013
|
} catch {
|
|
25051
25014
|
}
|
|
25052
25015
|
}
|
|
@@ -25185,13 +25148,13 @@ async function ensureEngineReady(bin, onNote = () => {
|
|
|
25185
25148
|
onNote(`Claude Code ${version} checked out${smoke.model ? ` (${smoke.model})` : ""}. Starting the step.`);
|
|
25186
25149
|
return { ok: true, version, smoked: true, smokeCostUsd: smoke.costUsd, smokeModel: smoke.model };
|
|
25187
25150
|
}
|
|
25188
|
-
var import_child_process2,
|
|
25151
|
+
var import_child_process2, fs19, path18, MIN_CLAUDE_VERSION, SMOKE_PROMPT;
|
|
25189
25152
|
var init_claude_cli = __esm({
|
|
25190
25153
|
"src/claude-cli.ts"() {
|
|
25191
25154
|
"use strict";
|
|
25192
25155
|
import_child_process2 = require("child_process");
|
|
25193
|
-
|
|
25194
|
-
|
|
25156
|
+
fs19 = __toESM(require("fs"));
|
|
25157
|
+
path18 = __toESM(require("path"));
|
|
25195
25158
|
init_credentials_store();
|
|
25196
25159
|
init_claude_locate();
|
|
25197
25160
|
MIN_CLAUDE_VERSION = "2.1.0";
|
|
@@ -25312,7 +25275,7 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
|
|
|
25312
25275
|
const progressDir = opts.onProgress ? defaultProgressDir() : void 0;
|
|
25313
25276
|
if (progressDir) {
|
|
25314
25277
|
try {
|
|
25315
|
-
|
|
25278
|
+
fs20.rmSync(progressFilePath(progressDir, locationId2), { force: true });
|
|
25316
25279
|
} catch {
|
|
25317
25280
|
}
|
|
25318
25281
|
}
|
|
@@ -25426,13 +25389,13 @@ function runStage(locationId2, stage, onEvent, opts = {}) {
|
|
|
25426
25389
|
});
|
|
25427
25390
|
});
|
|
25428
25391
|
}
|
|
25429
|
-
var import_child_process3,
|
|
25392
|
+
var import_child_process3, fs20, STAFF_NOTIFICATION_RULE, MISSING_STEP_RULE, NO_INVENTED_CAUSE_RULE, STAGE_SPECS, HUMAN_GATE_STAGES;
|
|
25430
25393
|
var init_stage_runner = __esm({
|
|
25431
25394
|
"src/stage-runner.ts"() {
|
|
25432
25395
|
"use strict";
|
|
25433
25396
|
init_intake_notification();
|
|
25434
25397
|
import_child_process3 = require("child_process");
|
|
25435
|
-
|
|
25398
|
+
fs20 = __toESM(require("fs"));
|
|
25436
25399
|
init_stage_boundary();
|
|
25437
25400
|
init_plan_guide();
|
|
25438
25401
|
init_question_set();
|
|
@@ -28509,19 +28472,6 @@ async function readDailyBrief(registry2, options = {}) {
|
|
|
28509
28472
|
return { brief, ownDay, accounts: { total: roster.filter((r) => !r.pending).length, unread: liveRead?.unreachable?.length ?? 0 } };
|
|
28510
28473
|
}
|
|
28511
28474
|
function registerDailyBriefTools(server2, registry2) {
|
|
28512
|
-
const recordTool = server2.tool(
|
|
28513
|
-
"record_brief_answers",
|
|
28514
|
-
"Save up to 50 Gmail or Google Drive findings from a chat brief as a private file on this machine, one source per call; replaces that source's previous rows and makes no provider calls. The cockpit's Daily brief page does not display them. Call it only when the user asks to save them.",
|
|
28515
|
-
BriefAnswersInput.shape,
|
|
28516
|
-
async (input) => {
|
|
28517
|
-
try {
|
|
28518
|
-
return jsonResponse(recordBriefAnswers(input));
|
|
28519
|
-
} catch (error) {
|
|
28520
|
-
return errorResponse(error);
|
|
28521
|
-
}
|
|
28522
|
-
}
|
|
28523
|
-
);
|
|
28524
|
-
if (recordTool) recordTool.inputSchema = BriefAnswersInput;
|
|
28525
28475
|
safeTool(
|
|
28526
28476
|
server2,
|
|
28527
28477
|
"daily_brief",
|
|
@@ -28542,7 +28492,6 @@ var init_daily_brief2 = __esm({
|
|
|
28542
28492
|
"src/tools/daily-brief.ts"() {
|
|
28543
28493
|
"use strict";
|
|
28544
28494
|
import_zod56 = require("zod");
|
|
28545
|
-
init_brief_answers();
|
|
28546
28495
|
init_tool_helpers();
|
|
28547
28496
|
init_ghl_client();
|
|
28548
28497
|
init_agency_profile();
|
|
@@ -28562,16 +28511,11 @@ var init_daily_brief2 = __esm({
|
|
|
28562
28511
|
|
|
28563
28512
|
// src/command-os/connectors/brief-panels.ts
|
|
28564
28513
|
function briefPanelDeps(input) {
|
|
28565
|
-
return {
|
|
28566
|
-
stripe: () => stripePanel(input),
|
|
28567
|
-
slack: () => slackPanel(input),
|
|
28568
|
-
calendar: () => calendarPanel(input),
|
|
28569
|
-
chat: (id, name) => chatPanel(id, name)(input)
|
|
28570
|
-
};
|
|
28514
|
+
return { stripe: () => stripePanel(input), slack: () => slackPanel(input), calendar: () => calendarPanel(input) };
|
|
28571
28515
|
}
|
|
28572
28516
|
function readTimes() {
|
|
28573
28517
|
try {
|
|
28574
|
-
return TimesSchema.parse(JSON.parse(
|
|
28518
|
+
return TimesSchema.parse(JSON.parse(fs21.readFileSync(timesPath(), "utf8")));
|
|
28575
28519
|
} catch {
|
|
28576
28520
|
return {};
|
|
28577
28521
|
}
|
|
@@ -28580,13 +28524,13 @@ function remember(id, readAt) {
|
|
|
28580
28524
|
const times = readTimes();
|
|
28581
28525
|
times[id] = readAt;
|
|
28582
28526
|
ensureAppDataDir();
|
|
28583
|
-
const tmp = `${timesPath()}.${(0,
|
|
28527
|
+
const tmp = `${timesPath()}.${(0, import_node_crypto6.randomUUID)()}.tmp`;
|
|
28584
28528
|
try {
|
|
28585
|
-
|
|
28586
|
-
|
|
28529
|
+
fs21.writeFileSync(tmp, JSON.stringify(times) + "\n", { mode: 384, flag: "wx" });
|
|
28530
|
+
fs21.renameSync(tmp, timesPath());
|
|
28587
28531
|
} finally {
|
|
28588
28532
|
try {
|
|
28589
|
-
|
|
28533
|
+
fs21.unlinkSync(tmp);
|
|
28590
28534
|
} catch {
|
|
28591
28535
|
}
|
|
28592
28536
|
}
|
|
@@ -28630,39 +28574,20 @@ function money2(rows2) {
|
|
|
28630
28574
|
}
|
|
28631
28575
|
return { count: rows2.length, totals: [...totals2].map(([currency, amount]) => ({ currency, amount })), unpriced };
|
|
28632
28576
|
}
|
|
28633
|
-
function chatPanel(id, name) {
|
|
28634
|
-
return async (_deps) => {
|
|
28635
|
-
try {
|
|
28636
|
-
const record = readBriefAnswers()[id];
|
|
28637
|
-
return {
|
|
28638
|
-
id,
|
|
28639
|
-
name,
|
|
28640
|
-
ok: Boolean(record),
|
|
28641
|
-
state: record ? "read" : "not-recorded",
|
|
28642
|
-
readAt: record?.readAt ?? null,
|
|
28643
|
-
why: record ? "Filled by your last chat brief" : "Nothing recorded yet. Ask Claude: run my morning brief",
|
|
28644
|
-
rows: record?.rows ?? [],
|
|
28645
|
-
needsYou: []
|
|
28646
|
-
};
|
|
28647
|
-
} catch {
|
|
28648
|
-
return failure(id, name, "The saved chat brief could not be read; ask Claude to record it again.");
|
|
28649
|
-
}
|
|
28650
|
-
};
|
|
28651
|
-
}
|
|
28652
28577
|
async function readBriefPanels(deps) {
|
|
28653
28578
|
return Promise.all(CONNECTOR_REGISTRY.flatMap((entry) => entry.panel ? [entry.panel(briefPanelDeps(deps))] : []));
|
|
28654
28579
|
}
|
|
28655
|
-
var
|
|
28580
|
+
var fs21, path19, import_node_crypto6, import_zod57, MoneySchema, TotalsSchema, SummarySchema, BriefPanelSchema, TimesSchema, timesPath, NotConnected, safeLink, amountText, stripePanel, slackPanel, calendarPanel;
|
|
28656
28581
|
var init_brief_panels = __esm({
|
|
28657
28582
|
"src/command-os/connectors/brief-panels.ts"() {
|
|
28658
28583
|
"use strict";
|
|
28659
28584
|
init_brief_deadline();
|
|
28660
|
-
|
|
28661
|
-
|
|
28662
|
-
|
|
28585
|
+
fs21 = __toESM(require("node:fs"));
|
|
28586
|
+
path19 = __toESM(require("node:path"));
|
|
28587
|
+
import_node_crypto6 = require("node:crypto");
|
|
28663
28588
|
import_zod57 = require("zod");
|
|
28664
28589
|
init_credentials_store();
|
|
28665
|
-
|
|
28590
|
+
init_brief_row();
|
|
28666
28591
|
init_registry();
|
|
28667
28592
|
init_store2();
|
|
28668
28593
|
init_handlers();
|
|
@@ -28697,7 +28622,7 @@ var init_brief_panels = __esm({
|
|
|
28697
28622
|
money: import_zod57.z.object({ owed: MoneySchema, renewals: MoneySchema, summary: SummarySchema.optional() }).optional()
|
|
28698
28623
|
});
|
|
28699
28624
|
TimesSchema = import_zod57.z.record(import_zod57.z.string(), import_zod57.z.iso.datetime({ offset: true }));
|
|
28700
|
-
timesPath = () =>
|
|
28625
|
+
timesPath = () => path19.join(appDataDir(), "brief-read-times.json");
|
|
28701
28626
|
NotConnected = class extends Error {
|
|
28702
28627
|
constructor() {
|
|
28703
28628
|
super("not connected");
|
|
@@ -28838,7 +28763,7 @@ var init_client_capabilities = __esm({
|
|
|
28838
28763
|
{ key: "reputation", label: "Reputation and content", blurb: "Reviews, social posts and the blog." },
|
|
28839
28764
|
{ key: "health", label: "Health and handoff", blurb: "Proving it works, keeping it clean, and handing it over." }
|
|
28840
28765
|
];
|
|
28841
|
-
N = (label,
|
|
28766
|
+
N = (label, path41, params, key, nameField, version) => ({ label, path: path41, params, key, nameField, version });
|
|
28842
28767
|
AI2 = "2021-04-15";
|
|
28843
28768
|
CAPABILITIES = [
|
|
28844
28769
|
// ── Set up ──────────────────────────────────────────────────────────────
|
|
@@ -29099,7 +29024,7 @@ var require_package = __commonJS({
|
|
|
29099
29024
|
"package.json"(exports2, module2) {
|
|
29100
29025
|
module2.exports = {
|
|
29101
29026
|
name: "@elitedcs/ghl-mcp",
|
|
29102
|
-
version: "3.84.
|
|
29027
|
+
version: "3.84.7",
|
|
29103
29028
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
29104
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.",
|
|
29105
29030
|
main: "dist/index.js",
|
|
@@ -29198,17 +29123,17 @@ var require_package = __commonJS({
|
|
|
29198
29123
|
});
|
|
29199
29124
|
|
|
29200
29125
|
// src/package-version.ts
|
|
29201
|
-
var
|
|
29126
|
+
var fs22, path20, bundledPkg, pkg;
|
|
29202
29127
|
var init_package_version = __esm({
|
|
29203
29128
|
"src/package-version.ts"() {
|
|
29204
29129
|
"use strict";
|
|
29205
|
-
|
|
29206
|
-
|
|
29130
|
+
fs22 = __toESM(require("fs"));
|
|
29131
|
+
path20 = __toESM(require("path"));
|
|
29207
29132
|
bundledPkg = require_package();
|
|
29208
29133
|
pkg = (() => {
|
|
29209
29134
|
try {
|
|
29210
29135
|
const onDisk = JSON.parse(
|
|
29211
|
-
|
|
29136
|
+
fs22.readFileSync(path20.resolve(__dirname, "..", "package.json"), "utf8")
|
|
29212
29137
|
);
|
|
29213
29138
|
if (typeof onDisk.version === "string" && onDisk.version.length > 0) {
|
|
29214
29139
|
return { version: onDisk.version };
|
|
@@ -31797,11 +31722,11 @@ var init_client_status = __esm({
|
|
|
31797
31722
|
|
|
31798
31723
|
// src/command-os/client-status-placement.ts
|
|
31799
31724
|
function statusStorePath(base = appDataDir()) {
|
|
31800
|
-
return
|
|
31725
|
+
return path21.join(base, "client-status.json");
|
|
31801
31726
|
}
|
|
31802
31727
|
function readStatusStore(base) {
|
|
31803
31728
|
try {
|
|
31804
|
-
const raw = JSON.parse(
|
|
31729
|
+
const raw = JSON.parse(fs23.readFileSync(statusStorePath(base), "utf8"));
|
|
31805
31730
|
if (raw && raw.v === 1 && raw.clients) return raw;
|
|
31806
31731
|
} catch {
|
|
31807
31732
|
}
|
|
@@ -31809,8 +31734,8 @@ function readStatusStore(base) {
|
|
|
31809
31734
|
}
|
|
31810
31735
|
function writeStatusStore(store, base) {
|
|
31811
31736
|
const file2 = statusStorePath(base);
|
|
31812
|
-
|
|
31813
|
-
|
|
31737
|
+
fs23.mkdirSync(path21.dirname(file2), { recursive: true, mode: 448 });
|
|
31738
|
+
fs23.writeFileSync(file2, JSON.stringify(store, null, 2), { mode: 384 });
|
|
31814
31739
|
}
|
|
31815
31740
|
function readStatusRecord(locationId2, base) {
|
|
31816
31741
|
return readStatusStore(base).clients[locationId2] ?? { locationId: locationId2 };
|
|
@@ -31842,9 +31767,9 @@ function describePlacement(placement) {
|
|
|
31842
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.`;
|
|
31843
31768
|
}
|
|
31844
31769
|
if (placement.kind === "agency-site") {
|
|
31845
|
-
return `A file on your own site: ${
|
|
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.`;
|
|
31846
31771
|
}
|
|
31847
|
-
return `A page written to ${
|
|
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}` : ""}.`;
|
|
31848
31773
|
}
|
|
31849
31774
|
function placementReadiness(placement) {
|
|
31850
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."];
|
|
@@ -31903,12 +31828,12 @@ function artifactPublishSteps(filePath, existingUrl) {
|
|
|
31903
31828
|
"Send the client the link once. From then on they just revisit it."
|
|
31904
31829
|
];
|
|
31905
31830
|
}
|
|
31906
|
-
var
|
|
31831
|
+
var fs23, path21, STATUS_SLUG, OUR_HOSTS;
|
|
31907
31832
|
var init_client_status_placement = __esm({
|
|
31908
31833
|
"src/command-os/client-status-placement.ts"() {
|
|
31909
31834
|
"use strict";
|
|
31910
|
-
|
|
31911
|
-
|
|
31835
|
+
fs23 = __toESM(require("node:fs"));
|
|
31836
|
+
path21 = __toESM(require("node:path"));
|
|
31912
31837
|
init_credentials_store();
|
|
31913
31838
|
init_client_status();
|
|
31914
31839
|
STATUS_SLUG = "status";
|
|
@@ -31928,7 +31853,7 @@ var init_client_status_placement = __esm({
|
|
|
31928
31853
|
// src/build-contract.ts
|
|
31929
31854
|
function contentHash(value) {
|
|
31930
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;
|
|
31931
|
-
return (0,
|
|
31856
|
+
return (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(canonical2(value)) ?? "null").digest("hex");
|
|
31932
31857
|
}
|
|
31933
31858
|
function assertBuildApproval(approval, inputHash) {
|
|
31934
31859
|
if (!approval?.at) throw new Error("Approve building before running Build.");
|
|
@@ -32103,11 +32028,11 @@ function executablePlanLines(saved) {
|
|
|
32103
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}`);
|
|
32104
32029
|
return lines.map(sentence);
|
|
32105
32030
|
}
|
|
32106
|
-
var
|
|
32031
|
+
var import_node_crypto7, import_node_fs3, import_node_path3, INTAKE_CHANGED;
|
|
32107
32032
|
var init_build_contract = __esm({
|
|
32108
32033
|
"src/build-contract.ts"() {
|
|
32109
32034
|
"use strict";
|
|
32110
|
-
|
|
32035
|
+
import_node_crypto7 = require("node:crypto");
|
|
32111
32036
|
import_node_fs3 = require("node:fs");
|
|
32112
32037
|
import_node_path3 = require("node:path");
|
|
32113
32038
|
init_credentials_store();
|
|
@@ -32367,30 +32292,30 @@ var init_client_status_page = __esm({
|
|
|
32367
32292
|
|
|
32368
32293
|
// src/command-os/client-status-publish.ts
|
|
32369
32294
|
function handoffSnapshotDir(base = appDataDir()) {
|
|
32370
|
-
return
|
|
32295
|
+
return path22.join(base, "handoffs");
|
|
32371
32296
|
}
|
|
32372
32297
|
function handoffSnapshotPath(locationId2, base) {
|
|
32373
|
-
return
|
|
32298
|
+
return path22.join(handoffSnapshotDir(base), `${locationId2}-handoff.json`);
|
|
32374
32299
|
}
|
|
32375
32300
|
function saveHandoffSnapshot(saved, base) {
|
|
32376
32301
|
const file2 = handoffSnapshotPath(saved.locationId, base);
|
|
32377
|
-
|
|
32378
|
-
|
|
32302
|
+
fs24.mkdirSync(path22.dirname(file2), { recursive: true, mode: 448 });
|
|
32303
|
+
fs24.writeFileSync(file2, JSON.stringify(saved, null, 2), { mode: 384 });
|
|
32379
32304
|
return file2;
|
|
32380
32305
|
}
|
|
32381
32306
|
function readHandoffSnapshot(locationId2, base) {
|
|
32382
32307
|
try {
|
|
32383
|
-
return JSON.parse(
|
|
32308
|
+
return JSON.parse(fs24.readFileSync(handoffSnapshotPath(locationId2, base), "utf8"));
|
|
32384
32309
|
} catch {
|
|
32385
32310
|
return null;
|
|
32386
32311
|
}
|
|
32387
32312
|
}
|
|
32388
32313
|
function localCopyPath(locationId2, base = appDataDir()) {
|
|
32389
|
-
return
|
|
32314
|
+
return path22.join(base, "client-status", `${locationId2}-status.html`);
|
|
32390
32315
|
}
|
|
32391
32316
|
function readVerifyOutcome(locationId2, base = appDataDir()) {
|
|
32392
32317
|
try {
|
|
32393
|
-
const st = JSON.parse(
|
|
32318
|
+
const st = JSON.parse(fs24.readFileSync(path22.join(base, "cockpit-state.json"), "utf8"));
|
|
32394
32319
|
const o = st.outcomes?.[`${locationId2}:4`];
|
|
32395
32320
|
if (!o) return null;
|
|
32396
32321
|
const src = o.plain ?? { summary: o.summary, issues: o.issues };
|
|
@@ -32400,9 +32325,9 @@ function readVerifyOutcome(locationId2, base = appDataDir()) {
|
|
|
32400
32325
|
}
|
|
32401
32326
|
}
|
|
32402
32327
|
function writeFileFor(dir, fileName, html2) {
|
|
32403
|
-
|
|
32404
|
-
const file2 =
|
|
32405
|
-
|
|
32328
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
32329
|
+
const file2 = path22.join(dir, fileName);
|
|
32330
|
+
fs24.writeFileSync(file2, html2);
|
|
32406
32331
|
return file2;
|
|
32407
32332
|
}
|
|
32408
32333
|
async function refreshClientStatus(opts) {
|
|
@@ -32438,7 +32363,7 @@ async function refreshClientStatus(opts) {
|
|
|
32438
32363
|
record.preparedSentences = input.items.map((i) => i.sentence);
|
|
32439
32364
|
if (!opts.dryRun) saveStatusRecord({ ...record, locationId: opts.locationId }, opts.base);
|
|
32440
32365
|
const localPath = localCopyPath(opts.locationId, opts.base);
|
|
32441
|
-
if (!opts.dryRun) writeFileFor(
|
|
32366
|
+
if (!opts.dryRun) writeFileFor(path22.dirname(localPath), path22.basename(localPath), html2);
|
|
32442
32367
|
const placement = record.placement;
|
|
32443
32368
|
const missing = placementReadiness(placement);
|
|
32444
32369
|
if (!placement || missing.length) {
|
|
@@ -32485,7 +32410,7 @@ async function publishTo(placement, input, html2, opts) {
|
|
|
32485
32410
|
if (placement.kind === "agency-site") {
|
|
32486
32411
|
assertNotOurHost(placement.publicUrl, "The address you chose for this page");
|
|
32487
32412
|
const fileName = placement.fileName ?? "status.html";
|
|
32488
|
-
const destinationPath = opts.dryRun ?
|
|
32413
|
+
const destinationPath = opts.dryRun ? path22.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
|
|
32489
32414
|
return {
|
|
32490
32415
|
...placement.publicUrl && { url: placement.publicUrl },
|
|
32491
32416
|
destinationPath,
|
|
@@ -32499,7 +32424,7 @@ async function publishTo(placement, input, html2, opts) {
|
|
|
32499
32424
|
const safety = artifactSafety(html2);
|
|
32500
32425
|
if (!safety.ok) throw new Error(safety.problems.join(" "));
|
|
32501
32426
|
const fileName = placement.fileName ?? "status.html";
|
|
32502
|
-
const destinationPath = opts.dryRun ?
|
|
32427
|
+
const destinationPath = opts.dryRun ? path22.join(placement.directory, fileName) : writeFileFor(placement.directory, fileName, html2);
|
|
32503
32428
|
assertNotOurHost(placement.publicUrl, "The Artifact link saved for this client");
|
|
32504
32429
|
return {
|
|
32505
32430
|
...placement.publicUrl && { url: placement.publicUrl },
|
|
@@ -32540,13 +32465,13 @@ async function refreshAfterVerify(locationId2, accountName, emit2, base, approve
|
|
|
32540
32465
|
emit2(`The client's status page was not updated: ${e instanceof Error ? e.message : String(e)}`);
|
|
32541
32466
|
}
|
|
32542
32467
|
}
|
|
32543
|
-
var
|
|
32468
|
+
var fs24, path22;
|
|
32544
32469
|
var init_client_status_publish = __esm({
|
|
32545
32470
|
"src/command-os/client-status-publish.ts"() {
|
|
32546
32471
|
"use strict";
|
|
32547
32472
|
init_publication_proof();
|
|
32548
|
-
|
|
32549
|
-
|
|
32473
|
+
fs24 = __toESM(require("node:fs"));
|
|
32474
|
+
path22 = __toESM(require("node:path"));
|
|
32550
32475
|
init_credentials_store();
|
|
32551
32476
|
init_branding();
|
|
32552
32477
|
init_client_status();
|
|
@@ -32625,11 +32550,11 @@ var init_handoff_snapshot = __esm({
|
|
|
32625
32550
|
// src/build-obligations.ts
|
|
32626
32551
|
function fileFor(id) {
|
|
32627
32552
|
if (!/^[a-zA-Z0-9_-]+$/.test(id)) throw new Error("Choose a registered client.");
|
|
32628
|
-
return
|
|
32553
|
+
return path23.join(appDataDir(), "build-obligations", id + ".json");
|
|
32629
32554
|
}
|
|
32630
32555
|
function readBuildObligations(id) {
|
|
32631
32556
|
try {
|
|
32632
|
-
const data = JSON.parse(
|
|
32557
|
+
const data = JSON.parse(fs25.readFileSync(fileFor(id), "utf8"));
|
|
32633
32558
|
return Array.isArray(data) ? data : [];
|
|
32634
32559
|
} catch (e) {
|
|
32635
32560
|
if (e.code === "ENOENT") return [];
|
|
@@ -32640,9 +32565,9 @@ function saveBuildObligations(id, items) {
|
|
|
32640
32565
|
const merged = new Map(readBuildObligations(id).map((m) => [`${m.type}:${m.ref}`, m]));
|
|
32641
32566
|
for (const item of items) merged.set(`${item.type}:${item.ref}`, item);
|
|
32642
32567
|
const file2 = fileFor(id);
|
|
32643
|
-
|
|
32644
|
-
|
|
32645
|
-
|
|
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);
|
|
32646
32571
|
}
|
|
32647
32572
|
function planObjectRefs(plan) {
|
|
32648
32573
|
const refs = /* @__PURE__ */ new Set();
|
|
@@ -32667,16 +32592,16 @@ function reconcileBuildObligations(id, checks, currentPlan) {
|
|
|
32667
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)));
|
|
32668
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()));
|
|
32669
32594
|
const file2 = fileFor(id);
|
|
32670
|
-
|
|
32671
|
-
|
|
32672
|
-
|
|
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);
|
|
32673
32598
|
}
|
|
32674
|
-
var
|
|
32599
|
+
var fs25, path23;
|
|
32675
32600
|
var init_build_obligations = __esm({
|
|
32676
32601
|
"src/build-obligations.ts"() {
|
|
32677
32602
|
"use strict";
|
|
32678
|
-
|
|
32679
|
-
|
|
32603
|
+
fs25 = __toESM(require("node:fs"));
|
|
32604
|
+
path23 = __toESM(require("node:path"));
|
|
32680
32605
|
init_credentials_store();
|
|
32681
32606
|
}
|
|
32682
32607
|
});
|
|
@@ -32686,7 +32611,7 @@ function engineRepair(version) {
|
|
|
32686
32611
|
return !version ? CLAUDE_REPAIR_MESSAGES[0] : !meetsFloor(version) ? CLAUDE_REPAIR_MESSAGES[1] : CLAUDE_REPAIR_MESSAGES[2];
|
|
32687
32612
|
}
|
|
32688
32613
|
function keyFingerprint(key) {
|
|
32689
|
-
return (0,
|
|
32614
|
+
return (0, import_node_crypto8.createHash)("sha256").update(key).digest("hex");
|
|
32690
32615
|
}
|
|
32691
32616
|
async function clientPreflight(registry2, locationId2) {
|
|
32692
32617
|
const lines = [];
|
|
@@ -32753,7 +32678,7 @@ async function agencyConnectionReady(registry2, companyId) {
|
|
|
32753
32678
|
return false;
|
|
32754
32679
|
}
|
|
32755
32680
|
}
|
|
32756
|
-
var
|
|
32681
|
+
var import_node_crypto8, CLAUDE_REPAIR_MESSAGES;
|
|
32757
32682
|
var init_client_preflight = __esm({
|
|
32758
32683
|
"src/client-preflight.ts"() {
|
|
32759
32684
|
"use strict";
|
|
@@ -32763,7 +32688,7 @@ var init_client_preflight = __esm({
|
|
|
32763
32688
|
init_stage_runner();
|
|
32764
32689
|
init_tool_filter();
|
|
32765
32690
|
init_credentials_store();
|
|
32766
|
-
|
|
32691
|
+
import_node_crypto8 = require("node:crypto");
|
|
32767
32692
|
CLAUDE_REPAIR_MESSAGES = [
|
|
32768
32693
|
"Install Claude Code from Your agency before reading this source.",
|
|
32769
32694
|
"Update Claude Code to version 2.1.0 or newer from Your agency.",
|
|
@@ -32870,7 +32795,7 @@ function startDesignRun(request, opts = {}) {
|
|
|
32870
32795
|
const checked = validateRunRequest(request);
|
|
32871
32796
|
if (!checked.ok) throw new Error(checked.error);
|
|
32872
32797
|
request = checked.value;
|
|
32873
|
-
const id = (0,
|
|
32798
|
+
const id = (0, import_node_crypto9.randomUUID)();
|
|
32874
32799
|
const outDir = (0, import_node_path5.join)(designRunsDir(), id);
|
|
32875
32800
|
(0, import_node_fs5.mkdirSync)(outDir, { recursive: true });
|
|
32876
32801
|
const job = { id, status: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString(), outDir, request, tail: [] };
|
|
@@ -32937,14 +32862,14 @@ function cancelDesignRun(id) {
|
|
|
32937
32862
|
}
|
|
32938
32863
|
return true;
|
|
32939
32864
|
}
|
|
32940
|
-
var import_node_child_process3, import_node_fs5, import_node_path5,
|
|
32865
|
+
var import_node_child_process3, import_node_fs5, import_node_path5, import_node_crypto9, SLUG2, MODEL, JOINED_FLAG, jobs, children;
|
|
32941
32866
|
var init_run_jobs = __esm({
|
|
32942
32867
|
"src/command-os/design/run-jobs.ts"() {
|
|
32943
32868
|
"use strict";
|
|
32944
32869
|
import_node_child_process3 = require("node:child_process");
|
|
32945
32870
|
import_node_fs5 = require("node:fs");
|
|
32946
32871
|
import_node_path5 = require("node:path");
|
|
32947
|
-
|
|
32872
|
+
import_node_crypto9 = require("node:crypto");
|
|
32948
32873
|
init_credentials_store();
|
|
32949
32874
|
init_schema();
|
|
32950
32875
|
init_brief_validation();
|
|
@@ -32972,20 +32897,20 @@ var init_run_expectations = __esm({
|
|
|
32972
32897
|
|
|
32973
32898
|
// src/run-cost.ts
|
|
32974
32899
|
function runCostPath() {
|
|
32975
|
-
return
|
|
32900
|
+
return path24.join(appDataDir(), "command-os-run-cost.jsonl");
|
|
32976
32901
|
}
|
|
32977
32902
|
function recordRunCost(rec, file2 = runCostPath()) {
|
|
32978
|
-
|
|
32979
|
-
|
|
32903
|
+
fs26.mkdirSync(path24.dirname(file2), { recursive: true });
|
|
32904
|
+
fs26.appendFileSync(file2, `${JSON.stringify(rec)}
|
|
32980
32905
|
`, { mode: 384 });
|
|
32981
32906
|
try {
|
|
32982
|
-
|
|
32907
|
+
fs26.chmodSync(file2, 384);
|
|
32983
32908
|
} catch {
|
|
32984
32909
|
}
|
|
32985
32910
|
}
|
|
32986
32911
|
function readRunCosts(file2 = runCostPath()) {
|
|
32987
32912
|
try {
|
|
32988
|
-
return
|
|
32913
|
+
return fs26.readFileSync(file2, "utf8").split("\n").filter((l) => l.trim()).map((l) => {
|
|
32989
32914
|
try {
|
|
32990
32915
|
return JSON.parse(l);
|
|
32991
32916
|
} catch {
|
|
@@ -33016,12 +32941,12 @@ function costLines(o) {
|
|
|
33016
32941
|
if (o.engineCheckRan && o.engineCheckCostUsd === void 0) out.push("Claude readiness check: cost not reported.");
|
|
33017
32942
|
return out;
|
|
33018
32943
|
}
|
|
33019
|
-
var
|
|
32944
|
+
var fs26, path24;
|
|
33020
32945
|
var init_run_cost = __esm({
|
|
33021
32946
|
"src/run-cost.ts"() {
|
|
33022
32947
|
"use strict";
|
|
33023
|
-
|
|
33024
|
-
|
|
32948
|
+
fs26 = __toESM(require("fs"));
|
|
32949
|
+
path24 = __toESM(require("path"));
|
|
33025
32950
|
init_credentials_store();
|
|
33026
32951
|
}
|
|
33027
32952
|
});
|
|
@@ -33823,9 +33748,9 @@ function presetForBusinessType(type) {
|
|
|
33823
33748
|
return "generic";
|
|
33824
33749
|
}
|
|
33825
33750
|
}
|
|
33826
|
-
function setPath(target,
|
|
33751
|
+
function setPath(target, path41, value) {
|
|
33827
33752
|
if (value === void 0) return;
|
|
33828
|
-
const parts =
|
|
33753
|
+
const parts = path41.split(".");
|
|
33829
33754
|
let node = target;
|
|
33830
33755
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
33831
33756
|
const k = parts[i];
|
|
@@ -34624,17 +34549,17 @@ function planFromPreset(input) {
|
|
|
34624
34549
|
}
|
|
34625
34550
|
function presetsRoot() {
|
|
34626
34551
|
const candidates = [
|
|
34627
|
-
|
|
34552
|
+
path25.join(__dirname, "..", "skills", "blueprint", "presets"),
|
|
34628
34553
|
// dist/ → package root
|
|
34629
|
-
|
|
34554
|
+
path25.join(__dirname, "..", "..", "skills", "blueprint", "presets"),
|
|
34630
34555
|
// src/intake-to-build in dev
|
|
34631
|
-
|
|
34556
|
+
path25.join(process.cwd(), "skills", "blueprint", "presets")
|
|
34632
34557
|
];
|
|
34633
|
-
return candidates.find((c) =>
|
|
34558
|
+
return candidates.find((c) => fs27.existsSync(c)) ?? null;
|
|
34634
34559
|
}
|
|
34635
34560
|
function readPresetFile(dir, base) {
|
|
34636
34561
|
try {
|
|
34637
|
-
const raw = JSON.parse(
|
|
34562
|
+
const raw = JSON.parse(fs27.readFileSync(path25.join(dir, `${base}.preset.json`), "utf8"));
|
|
34638
34563
|
if (raw && typeof raw === "object" && typeof raw.presetId === "string" && raw.skeleton) return raw;
|
|
34639
34564
|
return null;
|
|
34640
34565
|
} catch {
|
|
@@ -34646,7 +34571,7 @@ function loadPresetChoice(requested, briefPreset) {
|
|
|
34646
34571
|
if (!dir) {
|
|
34647
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." };
|
|
34648
34573
|
}
|
|
34649
|
-
const bases =
|
|
34574
|
+
const bases = fs27.readdirSync(dir).filter((f) => f.endsWith(".preset.json")).map((f) => f.replace(/\.preset\.json$/, ""));
|
|
34650
34575
|
const tryMatch = (want) => {
|
|
34651
34576
|
const norm6 = slugify2(want);
|
|
34652
34577
|
for (const base of bases) {
|
|
@@ -34677,12 +34602,12 @@ function loadPresetChoice(requested, briefPreset) {
|
|
|
34677
34602
|
if (generic) return { ok: true, preset: generic, file: "generic-client.preset.json", note: "Using the generic preset." };
|
|
34678
34603
|
return { ok: false, error: "No usable preset file was found in the library." };
|
|
34679
34604
|
}
|
|
34680
|
-
var
|
|
34605
|
+
var fs27, path25, PRESET_TOKEN_ROOTS, FLAG_ALIASES, INLINE_TOKEN_RE, ADMIN_ROLE_RE, BRIEF_CALENDAR_TYPE_MAP;
|
|
34681
34606
|
var init_plan_from_preset = __esm({
|
|
34682
34607
|
"src/intake-to-build/plan-from-preset.ts"() {
|
|
34683
34608
|
"use strict";
|
|
34684
|
-
|
|
34685
|
-
|
|
34609
|
+
fs27 = __toESM(require("fs"));
|
|
34610
|
+
path25 = __toESM(require("path"));
|
|
34686
34611
|
init_plan();
|
|
34687
34612
|
init_brief2();
|
|
34688
34613
|
init_normalizer();
|
|
@@ -36005,13 +35930,13 @@ var init_client_intake = __esm({
|
|
|
36005
35930
|
|
|
36006
35931
|
// src/plan-store.ts
|
|
36007
35932
|
function plansDir(base = appDataDir()) {
|
|
36008
|
-
return
|
|
35933
|
+
return path26.join(base, "plans");
|
|
36009
35934
|
}
|
|
36010
35935
|
function savePlanRecord(rec, base) {
|
|
36011
35936
|
const dir = plansDir(base);
|
|
36012
|
-
|
|
36013
|
-
const file2 =
|
|
36014
|
-
|
|
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 });
|
|
36015
35940
|
return file2;
|
|
36016
35941
|
}
|
|
36017
35942
|
function savedPlanMatchesScope(saved, current) {
|
|
@@ -36026,7 +35951,7 @@ function savedPlanMatchesScope(saved, current) {
|
|
|
36026
35951
|
}
|
|
36027
35952
|
function readSavedPlan(locationId2, base) {
|
|
36028
35953
|
try {
|
|
36029
|
-
return JSON.parse(
|
|
35954
|
+
return JSON.parse(fs28.readFileSync(path26.join(plansDir(base), `${locationId2}.json`), "utf8"));
|
|
36030
35955
|
} catch {
|
|
36031
35956
|
return null;
|
|
36032
35957
|
}
|
|
@@ -36049,12 +35974,12 @@ function planSummary(rec) {
|
|
|
36049
35974
|
if (wfs.length) parts.push(`workflows: ${wfs.map((w) => `${w.name} (${Array.isArray(w.actions) ? w.actions.length : "?"} actions)`).join("; ")}`);
|
|
36050
35975
|
return parts.join("\n") || "(plan has no recognisable sections)";
|
|
36051
35976
|
}
|
|
36052
|
-
var
|
|
35977
|
+
var fs28, path26;
|
|
36053
35978
|
var init_plan_store = __esm({
|
|
36054
35979
|
"src/plan-store.ts"() {
|
|
36055
35980
|
"use strict";
|
|
36056
|
-
|
|
36057
|
-
|
|
35981
|
+
fs28 = __toESM(require("fs"));
|
|
35982
|
+
path26 = __toESM(require("path"));
|
|
36058
35983
|
init_credentials_store();
|
|
36059
35984
|
init_build_contract();
|
|
36060
35985
|
}
|
|
@@ -37717,7 +37642,7 @@ function launchCommand(port = 7300) {
|
|
|
37717
37642
|
return `npx -y @elitedcs/ghl-mcp@latest dashboard --port=${port}`;
|
|
37718
37643
|
}
|
|
37719
37644
|
function installingEntry() {
|
|
37720
|
-
return
|
|
37645
|
+
return path27.join(__dirname, "index.js");
|
|
37721
37646
|
}
|
|
37722
37647
|
function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
|
|
37723
37648
|
const cmd = launchCommand(port);
|
|
@@ -37725,12 +37650,12 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
|
|
|
37725
37650
|
const systemApps = "/Applications";
|
|
37726
37651
|
let base = home;
|
|
37727
37652
|
try {
|
|
37728
|
-
|
|
37653
|
+
fs29.accessSync(systemApps, fs29.constants.W_OK);
|
|
37729
37654
|
base = "";
|
|
37730
37655
|
} catch {
|
|
37731
37656
|
}
|
|
37732
|
-
const appDir = base ?
|
|
37733
|
-
const macOSDir =
|
|
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");
|
|
37734
37659
|
const script = [
|
|
37735
37660
|
"#!/bin/bash",
|
|
37736
37661
|
"# GHL Command \u2014 Command OS launcher (regenerate: ghl-mcp install-launcher)",
|
|
@@ -37759,13 +37684,13 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
|
|
|
37759
37684
|
targetPath: appDir,
|
|
37760
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",
|
|
37761
37686
|
files: [
|
|
37762
|
-
{ path:
|
|
37763
|
-
{ path:
|
|
37687
|
+
{ path: path27.join(macOSDir, "command-os"), contents: script, executable: true },
|
|
37688
|
+
{ path: path27.join(appDir, "Contents", "Info.plist"), contents: plist, executable: false }
|
|
37764
37689
|
]
|
|
37765
37690
|
};
|
|
37766
37691
|
}
|
|
37767
37692
|
if (platform2 === "win32") {
|
|
37768
|
-
const target2 =
|
|
37693
|
+
const target2 = path27.join(home, "Desktop", "Command OS.cmd");
|
|
37769
37694
|
return {
|
|
37770
37695
|
platform: platform2,
|
|
37771
37696
|
targetPath: target2,
|
|
@@ -37778,7 +37703,7 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
|
|
|
37778
37703
|
].join("\r\n"), executable: false }]
|
|
37779
37704
|
};
|
|
37780
37705
|
}
|
|
37781
|
-
const target =
|
|
37706
|
+
const target = path27.join(home, ".local", "share", "applications", "command-os.desktop");
|
|
37782
37707
|
return {
|
|
37783
37708
|
platform: platform2,
|
|
37784
37709
|
targetPath: target,
|
|
@@ -37802,7 +37727,7 @@ function planLauncher(platform2, home, port = 7300, entry = installingEntry()) {
|
|
|
37802
37727
|
function launcherInstalled(port = 7300, platform2 = process.platform, home = os4.homedir()) {
|
|
37803
37728
|
try {
|
|
37804
37729
|
const plan = planLauncher(platform2, home, port, installingEntry());
|
|
37805
|
-
return plan.files.every((f) =>
|
|
37730
|
+
return plan.files.every((f) => fs29.existsSync(f.path));
|
|
37806
37731
|
} catch {
|
|
37807
37732
|
return false;
|
|
37808
37733
|
}
|
|
@@ -37813,8 +37738,8 @@ function installLauncher(argv = []) {
|
|
|
37813
37738
|
const plan = planLauncher(process.platform, os4.homedir(), port, installingEntry());
|
|
37814
37739
|
try {
|
|
37815
37740
|
for (const f of plan.files) {
|
|
37816
|
-
|
|
37817
|
-
|
|
37741
|
+
fs29.mkdirSync(path27.dirname(f.path), { recursive: true });
|
|
37742
|
+
fs29.writeFileSync(f.path, f.contents, { mode: f.executable ? 493 : 420 });
|
|
37818
37743
|
}
|
|
37819
37744
|
} catch (e) {
|
|
37820
37745
|
process.stderr.write(`
|
|
@@ -37834,47 +37759,47 @@ function installLauncher(argv = []) {
|
|
|
37834
37759
|
].join("\n"));
|
|
37835
37760
|
return 0;
|
|
37836
37761
|
}
|
|
37837
|
-
var
|
|
37762
|
+
var fs29, os4, path27;
|
|
37838
37763
|
var init_launcher = __esm({
|
|
37839
37764
|
"src/launcher.ts"() {
|
|
37840
37765
|
"use strict";
|
|
37841
|
-
|
|
37766
|
+
fs29 = __toESM(require("fs"));
|
|
37842
37767
|
os4 = __toESM(require("os"));
|
|
37843
|
-
|
|
37768
|
+
path27 = __toESM(require("path"));
|
|
37844
37769
|
}
|
|
37845
37770
|
});
|
|
37846
37771
|
|
|
37847
37772
|
// src/npx-cache-check.ts
|
|
37848
37773
|
function defaultNpxCacheDir(env2 = process.env, platform2 = process.platform, home = os5.homedir()) {
|
|
37849
37774
|
const configured = env2.npm_config_cache?.trim();
|
|
37850
|
-
const cache = configured ? configured : platform2 === "win32" ?
|
|
37851
|
-
return
|
|
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");
|
|
37852
37777
|
}
|
|
37853
37778
|
function damagedNpxDownloads(npxDir) {
|
|
37854
37779
|
let entries;
|
|
37855
37780
|
try {
|
|
37856
|
-
entries =
|
|
37781
|
+
entries = fs30.readdirSync(npxDir, { withFileTypes: true });
|
|
37857
37782
|
} catch {
|
|
37858
37783
|
return [];
|
|
37859
37784
|
}
|
|
37860
37785
|
const damaged = [];
|
|
37861
37786
|
const gone = (p) => {
|
|
37862
37787
|
try {
|
|
37863
|
-
|
|
37788
|
+
fs30.statSync(p);
|
|
37864
37789
|
return false;
|
|
37865
37790
|
} catch (e) {
|
|
37866
37791
|
return e.code === "ENOENT";
|
|
37867
37792
|
}
|
|
37868
37793
|
};
|
|
37869
37794
|
for (const entry of entries) {
|
|
37870
|
-
const dir =
|
|
37871
|
-
const pkg2 =
|
|
37795
|
+
const dir = path28.join(npxDir, entry.name);
|
|
37796
|
+
const pkg2 = path28.join(dir, PACKAGE_SUBDIR);
|
|
37872
37797
|
try {
|
|
37873
|
-
if (!
|
|
37798
|
+
if (!fs30.statSync(dir).isDirectory() || !fs30.statSync(pkg2).isDirectory()) continue;
|
|
37874
37799
|
} catch {
|
|
37875
37800
|
continue;
|
|
37876
37801
|
}
|
|
37877
|
-
if (gone(
|
|
37802
|
+
if (gone(path28.join(dir, "package.json")) || gone(path28.join(pkg2, "package.json"))) damaged.push(dir);
|
|
37878
37803
|
}
|
|
37879
37804
|
return damaged.sort();
|
|
37880
37805
|
}
|
|
@@ -37883,14 +37808,14 @@ function damagedDownloadLine(dirs) {
|
|
|
37883
37808
|
const one = dirs.length === 1;
|
|
37884
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 ")}`;
|
|
37885
37810
|
}
|
|
37886
|
-
var
|
|
37811
|
+
var fs30, os5, path28, PACKAGE_SUBDIR;
|
|
37887
37812
|
var init_npx_cache_check = __esm({
|
|
37888
37813
|
"src/npx-cache-check.ts"() {
|
|
37889
37814
|
"use strict";
|
|
37890
|
-
|
|
37815
|
+
fs30 = __toESM(require("node:fs"));
|
|
37891
37816
|
os5 = __toESM(require("node:os"));
|
|
37892
|
-
|
|
37893
|
-
PACKAGE_SUBDIR =
|
|
37817
|
+
path28 = __toESM(require("node:path"));
|
|
37818
|
+
PACKAGE_SUBDIR = path28.join("node_modules", "@elitedcs", "ghl-mcp");
|
|
37894
37819
|
}
|
|
37895
37820
|
});
|
|
37896
37821
|
|
|
@@ -37914,7 +37839,7 @@ function defaultIO() {
|
|
|
37914
37839
|
npxCacheDir: defaultNpxCacheDir(),
|
|
37915
37840
|
out: (l) => process.stdout.write(l + "\n"),
|
|
37916
37841
|
err: (l) => process.stderr.write(l + "\n"),
|
|
37917
|
-
rename: (from, to) =>
|
|
37842
|
+
rename: (from, to) => fs31.renameSync(from, to),
|
|
37918
37843
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
37919
37844
|
};
|
|
37920
37845
|
}
|
|
@@ -37924,32 +37849,32 @@ function candidateConfigPaths(opts) {
|
|
|
37924
37849
|
const file2 = "claude_desktop_config.json";
|
|
37925
37850
|
const candidates = [];
|
|
37926
37851
|
if (platform2 === "darwin") {
|
|
37927
|
-
candidates.push(
|
|
37852
|
+
candidates.push(path29.join(home, "Library", "Application Support", "Claude", file2));
|
|
37928
37853
|
} else if (platform2 === "win32") {
|
|
37929
|
-
const appData = opts?.appData ?? process.env.APPDATA ??
|
|
37930
|
-
candidates.push(
|
|
37931
|
-
const localAppData = opts?.localAppData ?? process.env.LOCALAPPDATA ??
|
|
37932
|
-
const packagesDir =
|
|
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");
|
|
37933
37858
|
try {
|
|
37934
|
-
for (const entry of
|
|
37859
|
+
for (const entry of fs31.readdirSync(packagesDir)) {
|
|
37935
37860
|
if (entry.startsWith("Claude_")) {
|
|
37936
|
-
candidates.push(
|
|
37861
|
+
candidates.push(path29.join(packagesDir, entry, "LocalCache", "Roaming", "Claude", file2));
|
|
37937
37862
|
}
|
|
37938
37863
|
}
|
|
37939
37864
|
} catch {
|
|
37940
37865
|
}
|
|
37941
37866
|
} else {
|
|
37942
|
-
candidates.push(
|
|
37867
|
+
candidates.push(path29.join(home, ".config", "Claude", file2));
|
|
37943
37868
|
}
|
|
37944
37869
|
return candidates;
|
|
37945
37870
|
}
|
|
37946
37871
|
function resolveConfigPath(explicitPath) {
|
|
37947
37872
|
if (explicitPath) {
|
|
37948
|
-
const p =
|
|
37949
|
-
return { configPath: p, exists:
|
|
37873
|
+
const p = path29.resolve(explicitPath);
|
|
37874
|
+
return { configPath: p, exists: fs31.existsSync(p) };
|
|
37950
37875
|
}
|
|
37951
37876
|
const candidates = candidateConfigPaths();
|
|
37952
|
-
const existing = candidates.filter((c) =>
|
|
37877
|
+
const existing = candidates.filter((c) => fs31.existsSync(c));
|
|
37953
37878
|
if (existing.length > 1) {
|
|
37954
37879
|
throw new InstallStop(
|
|
37955
37880
|
EXIT_REFUSED,
|
|
@@ -37966,22 +37891,22 @@ function resolveConfigPath(explicitPath) {
|
|
|
37966
37891
|
function resolveSymlinkPolicy(configPath, explicitPath, home = os6.homedir()) {
|
|
37967
37892
|
let st;
|
|
37968
37893
|
try {
|
|
37969
|
-
st =
|
|
37894
|
+
st = fs31.lstatSync(configPath);
|
|
37970
37895
|
} catch {
|
|
37971
37896
|
return configPath;
|
|
37972
37897
|
}
|
|
37973
37898
|
if (!st.isSymbolicLink()) return configPath;
|
|
37974
37899
|
let real;
|
|
37975
37900
|
try {
|
|
37976
|
-
real =
|
|
37901
|
+
real = fs31.realpathSync(configPath);
|
|
37977
37902
|
} catch {
|
|
37978
37903
|
throw new InstallStop(
|
|
37979
37904
|
EXIT_REFUSED,
|
|
37980
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.`
|
|
37981
37906
|
);
|
|
37982
37907
|
}
|
|
37983
|
-
const rel =
|
|
37984
|
-
const outsideHome = rel.startsWith("..") ||
|
|
37908
|
+
const rel = path29.relative(path29.resolve(home), real);
|
|
37909
|
+
const outsideHome = rel.startsWith("..") || path29.isAbsolute(rel);
|
|
37985
37910
|
if (outsideHome && !explicitPath) {
|
|
37986
37911
|
throw new InstallStop(
|
|
37987
37912
|
EXIT_REFUSED,
|
|
@@ -37991,8 +37916,8 @@ function resolveSymlinkPolicy(configPath, explicitPath, home = os6.homedir()) {
|
|
|
37991
37916
|
return real;
|
|
37992
37917
|
}
|
|
37993
37918
|
function readConfigBytes(configPath) {
|
|
37994
|
-
const bytes =
|
|
37995
|
-
const stat =
|
|
37919
|
+
const bytes = fs31.readFileSync(configPath);
|
|
37920
|
+
const stat = fs31.statSync(configPath);
|
|
37996
37921
|
if (bytes.length >= 2 && (bytes[0] === 255 && bytes[1] === 254 || bytes[0] === 254 && bytes[1] === 255)) {
|
|
37997
37922
|
throw new InstallStop(
|
|
37998
37923
|
EXIT_REFUSED,
|
|
@@ -38066,23 +37991,23 @@ function backupStamp(now) {
|
|
|
38066
37991
|
}
|
|
38067
37992
|
function chooseBackupPath(configPath, now = /* @__PURE__ */ new Date()) {
|
|
38068
37993
|
const base = `${configPath}.bak-${backupStamp(now)}`;
|
|
38069
|
-
if (!
|
|
37994
|
+
if (!fs31.existsSync(base)) return base;
|
|
38070
37995
|
for (let i = 2; ; i++) {
|
|
38071
37996
|
const candidate = `${base}-${i}`;
|
|
38072
|
-
if (!
|
|
37997
|
+
if (!fs31.existsSync(candidate)) return candidate;
|
|
38073
37998
|
}
|
|
38074
37999
|
}
|
|
38075
38000
|
function writeVerifiedBackup(configPath, originalBytes) {
|
|
38076
38001
|
const backupPath = chooseBackupPath(configPath);
|
|
38077
38002
|
try {
|
|
38078
|
-
|
|
38079
|
-
const readBack =
|
|
38003
|
+
fs31.writeFileSync(backupPath, originalBytes);
|
|
38004
|
+
const readBack = fs31.readFileSync(backupPath);
|
|
38080
38005
|
if (!readBack.equals(originalBytes)) {
|
|
38081
38006
|
throw new Error("backup read-back did not match");
|
|
38082
38007
|
}
|
|
38083
38008
|
} catch (e) {
|
|
38084
38009
|
try {
|
|
38085
|
-
|
|
38010
|
+
fs31.rmSync(backupPath, { force: true });
|
|
38086
38011
|
} catch {
|
|
38087
38012
|
}
|
|
38088
38013
|
throw new InstallStop(
|
|
@@ -38093,7 +38018,7 @@ function writeVerifiedBackup(configPath, originalBytes) {
|
|
|
38093
38018
|
return backupPath;
|
|
38094
38019
|
}
|
|
38095
38020
|
function sha256(bytes) {
|
|
38096
|
-
return (0,
|
|
38021
|
+
return (0, import_node_crypto10.createHash)("sha256").update(bytes).digest("hex");
|
|
38097
38022
|
}
|
|
38098
38023
|
function baselineOf(bytes, stat) {
|
|
38099
38024
|
return { size: stat.size, mtimeMs: stat.mtimeMs, hash: sha256(bytes) };
|
|
@@ -38101,9 +38026,9 @@ function baselineOf(bytes, stat) {
|
|
|
38101
38026
|
function assertNotStale(configPath, baseline) {
|
|
38102
38027
|
let ok = false;
|
|
38103
38028
|
try {
|
|
38104
|
-
const st =
|
|
38029
|
+
const st = fs31.statSync(configPath);
|
|
38105
38030
|
if (st.size === baseline.size && st.mtimeMs === baseline.mtimeMs) {
|
|
38106
|
-
ok = sha256(
|
|
38031
|
+
ok = sha256(fs31.readFileSync(configPath)) === baseline.hash;
|
|
38107
38032
|
} else {
|
|
38108
38033
|
ok = false;
|
|
38109
38034
|
}
|
|
@@ -38118,14 +38043,14 @@ function assertNotStale(configPath, baseline) {
|
|
|
38118
38043
|
}
|
|
38119
38044
|
}
|
|
38120
38045
|
async function atomicReplace(opts) {
|
|
38121
|
-
const dir =
|
|
38122
|
-
const tempPath =
|
|
38123
|
-
const fd =
|
|
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");
|
|
38124
38049
|
try {
|
|
38125
|
-
|
|
38126
|
-
|
|
38050
|
+
fs31.writeFileSync(fd, opts.newBytes);
|
|
38051
|
+
fs31.fsyncSync(fd);
|
|
38127
38052
|
} finally {
|
|
38128
|
-
|
|
38053
|
+
fs31.closeSync(fd);
|
|
38129
38054
|
}
|
|
38130
38055
|
try {
|
|
38131
38056
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -38150,17 +38075,17 @@ async function atomicReplace(opts) {
|
|
|
38150
38075
|
}
|
|
38151
38076
|
} catch (e) {
|
|
38152
38077
|
try {
|
|
38153
|
-
|
|
38078
|
+
fs31.rmSync(tempPath, { force: true });
|
|
38154
38079
|
} catch {
|
|
38155
38080
|
}
|
|
38156
38081
|
throw e;
|
|
38157
38082
|
}
|
|
38158
38083
|
try {
|
|
38159
|
-
const dirFd =
|
|
38084
|
+
const dirFd = fs31.openSync(dir, "r");
|
|
38160
38085
|
try {
|
|
38161
|
-
|
|
38086
|
+
fs31.fsyncSync(dirFd);
|
|
38162
38087
|
} finally {
|
|
38163
|
-
|
|
38088
|
+
fs31.closeSync(dirFd);
|
|
38164
38089
|
}
|
|
38165
38090
|
} catch {
|
|
38166
38091
|
}
|
|
@@ -38218,7 +38143,7 @@ async function runInstall(argv, ioOverride) {
|
|
|
38218
38143
|
try {
|
|
38219
38144
|
const resolved2 = resolveConfigPath(flags.path);
|
|
38220
38145
|
const configPath = resolveSymlinkPolicy(resolved2.configPath, flags.path !== void 0);
|
|
38221
|
-
const exists =
|
|
38146
|
+
const exists = fs31.existsSync(configPath);
|
|
38222
38147
|
let read2 = null;
|
|
38223
38148
|
let outcome;
|
|
38224
38149
|
if (exists) {
|
|
@@ -38250,7 +38175,7 @@ async function runInstall(argv, ioOverride) {
|
|
|
38250
38175
|
return EXIT_OK;
|
|
38251
38176
|
}
|
|
38252
38177
|
const backupPath = exists && read2 ? writeVerifiedBackup(configPath, read2.bytes) : null;
|
|
38253
|
-
if (!exists)
|
|
38178
|
+
if (!exists) fs31.mkdirSync(path29.dirname(configPath), { recursive: true });
|
|
38254
38179
|
await atomicReplace({
|
|
38255
38180
|
configPath,
|
|
38256
38181
|
newBytes,
|
|
@@ -38269,14 +38194,14 @@ async function runInstall(argv, ioOverride) {
|
|
|
38269
38194
|
return EXIT_ABORTED;
|
|
38270
38195
|
}
|
|
38271
38196
|
}
|
|
38272
|
-
var
|
|
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;
|
|
38273
38198
|
var init_config_installer = __esm({
|
|
38274
38199
|
"src/config-installer.ts"() {
|
|
38275
38200
|
"use strict";
|
|
38276
|
-
|
|
38201
|
+
fs31 = __toESM(require("node:fs"));
|
|
38277
38202
|
os6 = __toESM(require("node:os"));
|
|
38278
|
-
|
|
38279
|
-
|
|
38203
|
+
path29 = __toESM(require("node:path"));
|
|
38204
|
+
import_node_crypto10 = require("node:crypto");
|
|
38280
38205
|
import_node_util = require("node:util");
|
|
38281
38206
|
import_json5 = __toESM(require("json5"));
|
|
38282
38207
|
init_npx_cache_check();
|
|
@@ -38309,9 +38234,9 @@ function errLine(msg3) {
|
|
|
38309
38234
|
function preflightWritable() {
|
|
38310
38235
|
try {
|
|
38311
38236
|
const dir = ensureAppDataDir();
|
|
38312
|
-
const probe =
|
|
38313
|
-
|
|
38314
|
-
|
|
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);
|
|
38315
38240
|
return true;
|
|
38316
38241
|
} catch (error) {
|
|
38317
38242
|
errLine(`Config dir is not writable: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -38580,13 +38505,13 @@ async function runCli(subcommand, argv) {
|
|
|
38580
38505
|
return EXIT_USAGE2;
|
|
38581
38506
|
}
|
|
38582
38507
|
}
|
|
38583
|
-
var import_node_util2,
|
|
38508
|
+
var import_node_util2, fs32, path30, import_crypto2, EXIT_OK2, EXIT_USAGE2, EXIT_VALIDATION, EXIT_FS, USAGE;
|
|
38584
38509
|
var init_cli = __esm({
|
|
38585
38510
|
"src/cli.ts"() {
|
|
38586
38511
|
"use strict";
|
|
38587
38512
|
import_node_util2 = require("node:util");
|
|
38588
|
-
|
|
38589
|
-
|
|
38513
|
+
fs32 = __toESM(require("fs"));
|
|
38514
|
+
path30 = __toESM(require("path"));
|
|
38590
38515
|
import_crypto2 = require("crypto");
|
|
38591
38516
|
init_ghl_client();
|
|
38592
38517
|
init_token_registry();
|
|
@@ -39132,11 +39057,11 @@ __export(intake_overlay_exports, {
|
|
|
39132
39057
|
writeOverlay: () => writeOverlay
|
|
39133
39058
|
});
|
|
39134
39059
|
function overlayPath() {
|
|
39135
|
-
return
|
|
39060
|
+
return path31.join(appDataDir(), "intake-overlay.json");
|
|
39136
39061
|
}
|
|
39137
39062
|
function readOverlay() {
|
|
39138
39063
|
try {
|
|
39139
|
-
const raw = JSON.parse(
|
|
39064
|
+
const raw = JSON.parse(fs33.readFileSync(overlayPath(), "utf8"));
|
|
39140
39065
|
if (raw && typeof raw === "object") return raw;
|
|
39141
39066
|
} catch {
|
|
39142
39067
|
}
|
|
@@ -39144,14 +39069,14 @@ function readOverlay() {
|
|
|
39144
39069
|
}
|
|
39145
39070
|
function writeOverlay(layer) {
|
|
39146
39071
|
ensureAppDataDir();
|
|
39147
|
-
|
|
39072
|
+
fs33.writeFileSync(overlayPath(), JSON.stringify(layer, null, 2), { mode: 384 });
|
|
39148
39073
|
}
|
|
39149
|
-
var
|
|
39074
|
+
var fs33, path31;
|
|
39150
39075
|
var init_intake_overlay = __esm({
|
|
39151
39076
|
"src/intake-overlay.ts"() {
|
|
39152
39077
|
"use strict";
|
|
39153
|
-
|
|
39154
|
-
|
|
39078
|
+
fs33 = __toESM(require("fs"));
|
|
39079
|
+
path31 = __toESM(require("path"));
|
|
39155
39080
|
init_credentials_store();
|
|
39156
39081
|
}
|
|
39157
39082
|
});
|
|
@@ -39799,7 +39724,7 @@ function registerAssessmentTools(server2, client) {
|
|
|
39799
39724
|
const dir = args.outDir ?? (0, import_node_path6.join)((0, import_node_os.homedir)(), "Documents", "assessments");
|
|
39800
39725
|
(0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
39801
39726
|
const slug3 = (state.biz || "assessment").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
39802
|
-
const file2 = (0, import_node_path6.join)(dir, `${slug3}-${(0,
|
|
39727
|
+
const file2 = (0, import_node_path6.join)(dir, `${slug3}-${(0, import_node_crypto11.randomBytes)(4).toString("hex")}.html`);
|
|
39803
39728
|
(0, import_node_fs6.writeFileSync)(file2, html2, "utf8");
|
|
39804
39729
|
return {
|
|
39805
39730
|
written: file2,
|
|
@@ -39822,7 +39747,7 @@ function registerAssessmentTools(server2, client) {
|
|
|
39822
39747
|
}
|
|
39823
39748
|
);
|
|
39824
39749
|
}
|
|
39825
|
-
var import_node_util3, import_zod61,
|
|
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;
|
|
39826
39751
|
var init_assessment = __esm({
|
|
39827
39752
|
"src/tools/assessment.ts"() {
|
|
39828
39753
|
"use strict";
|
|
@@ -39836,7 +39761,7 @@ var init_assessment = __esm({
|
|
|
39836
39761
|
init_engine();
|
|
39837
39762
|
init_transcript();
|
|
39838
39763
|
init_report();
|
|
39839
|
-
|
|
39764
|
+
import_node_crypto11 = require("node:crypto");
|
|
39840
39765
|
import_node_fs6 = require("node:fs");
|
|
39841
39766
|
import_node_os = require("node:os");
|
|
39842
39767
|
import_node_path6 = require("node:path");
|
|
@@ -40022,11 +39947,11 @@ function recoverStuckStages(state) {
|
|
|
40022
39947
|
return { state: { ...state, clients }, recovered };
|
|
40023
39948
|
}
|
|
40024
39949
|
function cockpitStatePath() {
|
|
40025
|
-
return
|
|
39950
|
+
return path32.join(appDataDir(), "cockpit-state.json");
|
|
40026
39951
|
}
|
|
40027
39952
|
function readCockpitState() {
|
|
40028
39953
|
try {
|
|
40029
|
-
const raw = JSON.parse(
|
|
39954
|
+
const raw = JSON.parse(fs34.readFileSync(cockpitStatePath(), "utf8"));
|
|
40030
39955
|
if (raw && raw.v === 1 && raw.clients && typeof raw.clients === "object") return raw;
|
|
40031
39956
|
} catch {
|
|
40032
39957
|
}
|
|
@@ -40034,7 +39959,7 @@ function readCockpitState() {
|
|
|
40034
39959
|
}
|
|
40035
39960
|
function writeCockpitState(state) {
|
|
40036
39961
|
ensureAppDataDir();
|
|
40037
|
-
|
|
39962
|
+
fs34.writeFileSync(cockpitStatePath(), JSON.stringify(state, null, 2), { mode: 384 });
|
|
40038
39963
|
}
|
|
40039
39964
|
function setStage(state, locationId2, stageIndex, status) {
|
|
40040
39965
|
if (!Number.isInteger(stageIndex) || stageIndex < 0 || stageIndex >= STAGES2.length) throw new Error("bad stage index");
|
|
@@ -40365,7 +40290,7 @@ function notify(message) {
|
|
|
40365
40290
|
`);
|
|
40366
40291
|
try {
|
|
40367
40292
|
ensureAppDataDir();
|
|
40368
|
-
|
|
40293
|
+
fs34.appendFileSync(path32.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
40369
40294
|
`);
|
|
40370
40295
|
} catch {
|
|
40371
40296
|
}
|
|
@@ -40435,20 +40360,20 @@ function withCockpitShell(page, screen, extraHead = "") {
|
|
|
40435
40360
|
function clientDocsDir(locationId2, base = appDataDir()) {
|
|
40436
40361
|
const safeLoc = String(locationId2).replace(/[^A-Za-z0-9_-]/g, "");
|
|
40437
40362
|
if (!safeLoc) throw new Error("no client");
|
|
40438
|
-
return
|
|
40363
|
+
return path32.join(base, "clients", safeLoc, "documents");
|
|
40439
40364
|
}
|
|
40440
40365
|
function safeDocName(name) {
|
|
40441
|
-
const cleaned =
|
|
40442
|
-
const ext =
|
|
40366
|
+
const cleaned = path32.basename(String(name ?? "")).replace(/[^A-Za-z0-9._ -]/g, "_").replace(/\s+/g, " ").trim();
|
|
40367
|
+
const ext = path32.extname(cleaned).toLowerCase();
|
|
40443
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.");
|
|
40444
40369
|
const stem = cleaned.slice(0, cleaned.length - ext.length).slice(0, 120 - ext.length).trim();
|
|
40445
40370
|
return `${stem || "document"}${ext}`;
|
|
40446
40371
|
}
|
|
40447
40372
|
function listClientDocs(locationId2, base = appDataDir()) {
|
|
40448
40373
|
const dir = clientDocsDir(locationId2, base);
|
|
40449
|
-
if (!
|
|
40450
|
-
return
|
|
40451
|
-
const st =
|
|
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));
|
|
40452
40377
|
return { name: f, bytes: st.size, savedAt: st.mtime.toISOString() };
|
|
40453
40378
|
}).sort((a, b) => b.savedAt.localeCompare(a.savedAt));
|
|
40454
40379
|
}
|
|
@@ -40466,7 +40391,7 @@ function readFailureText(e) {
|
|
|
40466
40391
|
function logQuietly(message) {
|
|
40467
40392
|
try {
|
|
40468
40393
|
ensureAppDataDir();
|
|
40469
|
-
|
|
40394
|
+
fs34.appendFileSync(path32.join(appDataDir(), "cockpit.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
40470
40395
|
`);
|
|
40471
40396
|
} catch {
|
|
40472
40397
|
}
|
|
@@ -40539,40 +40464,40 @@ function newClientFailure(error, surface = "command-os", account2) {
|
|
|
40539
40464
|
}
|
|
40540
40465
|
function insideDir(dir, p) {
|
|
40541
40466
|
try {
|
|
40542
|
-
const real =
|
|
40543
|
-
const base =
|
|
40544
|
-
return real === base || real.startsWith(base +
|
|
40467
|
+
const real = fs34.realpathSync(p);
|
|
40468
|
+
const base = fs34.realpathSync(dir);
|
|
40469
|
+
return real === base || real.startsWith(base + path32.sep);
|
|
40545
40470
|
} catch {
|
|
40546
40471
|
return false;
|
|
40547
40472
|
}
|
|
40548
40473
|
}
|
|
40549
40474
|
function uniqueDocName(dir, name) {
|
|
40550
|
-
const ext =
|
|
40475
|
+
const ext = path32.extname(name), stem = name.slice(0, name.length - ext.length);
|
|
40551
40476
|
let candidate = name;
|
|
40552
|
-
for (let n = 2;
|
|
40477
|
+
for (let n = 2; fs34.existsSync(path32.join(dir, candidate)); n++) candidate = `${stem} (${n})${ext}`;
|
|
40553
40478
|
return candidate;
|
|
40554
40479
|
}
|
|
40555
40480
|
function writeDocAtomically(dir, name, bytes) {
|
|
40556
|
-
|
|
40481
|
+
fs34.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
40557
40482
|
const finalName = uniqueDocName(dir, name);
|
|
40558
|
-
const tmp =
|
|
40559
|
-
const fd =
|
|
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);
|
|
40560
40485
|
try {
|
|
40561
|
-
|
|
40562
|
-
|
|
40486
|
+
fs34.writeSync(fd, bytes);
|
|
40487
|
+
fs34.fsyncSync(fd);
|
|
40563
40488
|
} finally {
|
|
40564
|
-
|
|
40489
|
+
fs34.closeSync(fd);
|
|
40565
40490
|
}
|
|
40566
|
-
const dest =
|
|
40491
|
+
const dest = path32.join(dir, finalName);
|
|
40567
40492
|
try {
|
|
40568
|
-
if (
|
|
40569
|
-
|
|
40493
|
+
if (fs34.lstatSync(dest).isSymbolicLink()) {
|
|
40494
|
+
fs34.unlinkSync(tmp);
|
|
40570
40495
|
throw new Error("that name is taken by a link");
|
|
40571
40496
|
}
|
|
40572
40497
|
} catch (e) {
|
|
40573
40498
|
if (e.code !== "ENOENT") throw e;
|
|
40574
40499
|
}
|
|
40575
|
-
|
|
40500
|
+
fs34.renameSync(tmp, dest);
|
|
40576
40501
|
return finalName;
|
|
40577
40502
|
}
|
|
40578
40503
|
function readableAccount(locationId2, roster = currentRosterRef(), state = readCockpitState()) {
|
|
@@ -42376,8 +42301,8 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
42376
42301
|
if (!bytes.length) throw new Error("that file is empty");
|
|
42377
42302
|
if (bytes.length > DOC_MAX_BYTES) throw new Error("that file is over 20 MB");
|
|
42378
42303
|
const dir = clientDocsDir(args.locationId);
|
|
42379
|
-
|
|
42380
|
-
if (!insideDir(
|
|
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.");
|
|
42381
42306
|
const saved = writeDocAtomically(dir, name, bytes);
|
|
42382
42307
|
res.end(JSON.stringify({ ok: true, name: saved, files: listClientDocs(args.locationId) }));
|
|
42383
42308
|
} catch (e) {
|
|
@@ -42731,10 +42656,10 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
42731
42656
|
if (args.file) {
|
|
42732
42657
|
const name = safeDocName(args.file);
|
|
42733
42658
|
const dir = clientDocsDir(args.locationId);
|
|
42734
|
-
const p =
|
|
42735
|
-
if (!
|
|
42736
|
-
if (
|
|
42737
|
-
const text2 =
|
|
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");
|
|
42738
42663
|
if (text2.length > 6e4) throw new Error("The limit is 60,000 characters. Paste an excerpt or shorten this text file.");
|
|
42739
42664
|
fileSource = { kind: "text", text: text2 };
|
|
42740
42665
|
}
|
|
@@ -42808,14 +42733,14 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
42808
42733
|
}
|
|
42809
42734
|
if (req.method === "GET" && /^\/brand\/[a-z0-9-]+\/screenshot\.png$/.test(url)) {
|
|
42810
42735
|
const slug3 = url.split("/")[2];
|
|
42811
|
-
const file2 =
|
|
42812
|
-
if (!
|
|
42736
|
+
const file2 = path32.join(brandDir(slug3), "screenshot.png");
|
|
42737
|
+
if (!fs34.existsSync(file2)) {
|
|
42813
42738
|
res.writeHead(404);
|
|
42814
42739
|
res.end();
|
|
42815
42740
|
return;
|
|
42816
42741
|
}
|
|
42817
42742
|
res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "no-store" });
|
|
42818
|
-
res.end(
|
|
42743
|
+
res.end(fs34.readFileSync(file2));
|
|
42819
42744
|
return;
|
|
42820
42745
|
}
|
|
42821
42746
|
if (req.method === "GET" && /^\/brand\/[a-z0-9-]+$/.test(url)) {
|
|
@@ -42824,7 +42749,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
42824
42749
|
const dna = houseLooks().find((d) => d.slug === slug3) ?? readBrand(slug3);
|
|
42825
42750
|
const dir = brandExists(slug3) ? brandDir(slug3) : void 0;
|
|
42826
42751
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
|
|
42827
|
-
res.end(brandCardHtml(dna, { screenshot: dir ?
|
|
42752
|
+
res.end(brandCardHtml(dna, { screenshot: dir ? fs34.existsSync(path32.join(dir, "screenshot.png")) : false, dir, seatToken: mayServeSeat(req, port) ? seatToken : "" }));
|
|
42828
42753
|
} catch (e) {
|
|
42829
42754
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
42830
42755
|
res.end(e.message);
|
|
@@ -42986,7 +42911,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
42986
42911
|
}
|
|
42987
42912
|
try {
|
|
42988
42913
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
42989
|
-
res.end(
|
|
42914
|
+
res.end(fs34.readFileSync(localCopyPath(locationId2), "utf8"));
|
|
42990
42915
|
} catch {
|
|
42991
42916
|
res.end("The handoff is not prepared yet. Run Verify first.");
|
|
42992
42917
|
}
|
|
@@ -43592,7 +43517,7 @@ ${opportunityNoteFailure?.detail ?? ""}`);
|
|
|
43592
43517
|
process.on("SIGTERM", stop);
|
|
43593
43518
|
});
|
|
43594
43519
|
}
|
|
43595
|
-
var import_zod62, import_node_util4,
|
|
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;
|
|
43596
43521
|
var init_dashboard = __esm({
|
|
43597
43522
|
"src/dashboard.ts"() {
|
|
43598
43523
|
"use strict";
|
|
@@ -43620,8 +43545,8 @@ var init_dashboard = __esm({
|
|
|
43620
43545
|
init_handoff_snapshot();
|
|
43621
43546
|
init_member_progress();
|
|
43622
43547
|
init_build_obligations();
|
|
43623
|
-
|
|
43624
|
-
|
|
43548
|
+
fs34 = __toESM(require("fs"));
|
|
43549
|
+
path32 = __toESM(require("path"));
|
|
43625
43550
|
http = __toESM(require("http"));
|
|
43626
43551
|
import_child_process4 = require("child_process");
|
|
43627
43552
|
init_credentials_store();
|
|
@@ -43727,8 +43652,8 @@ var init_dashboard = __esm({
|
|
|
43727
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.";
|
|
43728
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"];
|
|
43729
43654
|
ConnectionRequest = import_zod62.z.discriminatedUnion("system", [
|
|
43730
|
-
import_zod62.z.object({ system: import_zod62.z.literal("stripe"), key: import_zod62.z.string().min(8), label: import_zod62.z.string().optional() }).strict(),
|
|
43731
|
-
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(),
|
|
43732
43657
|
import_zod62.z.object({ system: import_zod62.z.literal("google-calendar"), action: import_zod62.z.enum(["start", "finish", "status"]).default("start") }).strict()
|
|
43733
43658
|
]);
|
|
43734
43659
|
DisconnectRequest = import_zod62.z.object({ system: import_zod62.z.enum(["stripe", "slack", "google-calendar"]) }).strict();
|
|
@@ -45483,13 +45408,13 @@ function contactServiceNote(payload) {
|
|
|
45483
45408
|
function registerSmartListTools(server2, builderClient) {
|
|
45484
45409
|
if (!builderClient) return;
|
|
45485
45410
|
const client = builderClient;
|
|
45486
|
-
async function smartListRequest(method,
|
|
45487
|
-
const url = `${SMARTLIST_BASE}${
|
|
45411
|
+
async function smartListRequest(method, path41, body) {
|
|
45412
|
+
const url = `${SMARTLIST_BASE}${path41}`;
|
|
45488
45413
|
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
45489
45414
|
const response = await builderRequest(client, method, url, sendsBody ? { body } : {});
|
|
45490
45415
|
if (!response.ok) {
|
|
45491
45416
|
const text3 = await response.text();
|
|
45492
|
-
throw new Error(`Smart Lists API Error ${response.status}: ${method} ${
|
|
45417
|
+
throw new Error(`Smart Lists API Error ${response.status}: ${method} ${path41}
|
|
45493
45418
|
${text3}`);
|
|
45494
45419
|
}
|
|
45495
45420
|
const text2 = await response.text();
|
|
@@ -45734,11 +45659,11 @@ var init_smart_lists = __esm({
|
|
|
45734
45659
|
function registerReputationTools(server2, builderClient) {
|
|
45735
45660
|
if (!builderClient) return;
|
|
45736
45661
|
const client = builderClient;
|
|
45737
|
-
async function reputationRequest(method,
|
|
45738
|
-
const response = await builderRequest(client, method, `${REPUTATION_BASE}${
|
|
45662
|
+
async function reputationRequest(method, path41) {
|
|
45663
|
+
const response = await builderRequest(client, method, `${REPUTATION_BASE}${path41}`);
|
|
45739
45664
|
if (!response.ok) {
|
|
45740
45665
|
const text3 = await response.text();
|
|
45741
|
-
throw new Error(`Reputation API Error ${response.status}: ${method} ${
|
|
45666
|
+
throw new Error(`Reputation API Error ${response.status}: ${method} ${path41}
|
|
45742
45667
|
${text3}`);
|
|
45743
45668
|
}
|
|
45744
45669
|
const text2 = await response.text();
|
|
@@ -45876,11 +45801,11 @@ var init_email_campaigns = __esm({
|
|
|
45876
45801
|
function registerMembershipTools(server2, builderClient) {
|
|
45877
45802
|
if (!builderClient) return;
|
|
45878
45803
|
const client = builderClient;
|
|
45879
|
-
async function membershipRequest(
|
|
45880
|
-
const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${
|
|
45804
|
+
async function membershipRequest(path41, method = "GET", body) {
|
|
45805
|
+
const response = await builderRequest(client, method, `${MEMBERSHIP_BASE2}${path41}`, body ? { body } : {});
|
|
45881
45806
|
if (!response.ok) {
|
|
45882
45807
|
const text3 = await response.text();
|
|
45883
|
-
throw new Error(`Membership API Error ${response.status}: ${method} ${
|
|
45808
|
+
throw new Error(`Membership API Error ${response.status}: ${method} ${path41}
|
|
45884
45809
|
${text3}`);
|
|
45885
45810
|
}
|
|
45886
45811
|
const text2 = await response.text();
|
|
@@ -46073,21 +45998,21 @@ function isAlreadyExistsError(message) {
|
|
|
46073
45998
|
}
|
|
46074
45999
|
function registerTemplateDeployerTools(server2, client) {
|
|
46075
46000
|
const builderClient = WorkflowBuilderClient.fromEnv();
|
|
46076
|
-
const templatesDir =
|
|
46001
|
+
const templatesDir = path33.resolve(__dirname, "..", "templates");
|
|
46077
46002
|
function validateTemplatePath(templateFile) {
|
|
46078
|
-
const resolved2 =
|
|
46079
|
-
const realPath =
|
|
46003
|
+
const resolved2 = path33.resolve(templateFile);
|
|
46004
|
+
const realPath = fs35.existsSync(resolved2) ? fs35.realpathSync(resolved2) : resolved2;
|
|
46080
46005
|
const allowedDirs = [
|
|
46081
46006
|
templatesDir,
|
|
46082
|
-
|
|
46083
|
-
|
|
46084
|
-
].map((d) =>
|
|
46085
|
-
const isAllowed = allowedDirs.some((dir) => realPath.startsWith(dir +
|
|
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));
|
|
46086
46011
|
if (!isAllowed) {
|
|
46087
46012
|
throw new Error(`Template file must be inside a templates/ directory. Got: ${realPath}`);
|
|
46088
46013
|
}
|
|
46089
|
-
if (
|
|
46090
|
-
const otherMatch = allowedDirs.slice(1).some((d) => !
|
|
46014
|
+
if (path33.relative(allowedDirs[0], realPath).startsWith("..")) {
|
|
46015
|
+
const otherMatch = allowedDirs.slice(1).some((d) => !path33.relative(d, realPath).startsWith(".."));
|
|
46091
46016
|
if (!otherMatch) {
|
|
46092
46017
|
throw new Error(`Template path escapes allowed directory.`);
|
|
46093
46018
|
}
|
|
@@ -46102,26 +46027,26 @@ function registerTemplateDeployerTools(server2, client) {
|
|
|
46102
46027
|
try {
|
|
46103
46028
|
const dirs = [
|
|
46104
46029
|
templatesDir,
|
|
46105
|
-
|
|
46106
|
-
|
|
46030
|
+
path33.resolve(process.cwd(), "templates"),
|
|
46031
|
+
path33.resolve(__dirname, "..", "..", "templates")
|
|
46107
46032
|
];
|
|
46108
46033
|
const templates = [];
|
|
46109
46034
|
const seen = /* @__PURE__ */ new Set();
|
|
46110
46035
|
for (const dir of dirs) {
|
|
46111
|
-
if (!
|
|
46112
|
-
const files =
|
|
46036
|
+
if (!fs35.existsSync(dir)) continue;
|
|
46037
|
+
const files = fs35.readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
46113
46038
|
for (const file2 of files) {
|
|
46114
|
-
const full =
|
|
46039
|
+
const full = path33.join(dir, file2);
|
|
46115
46040
|
let real;
|
|
46116
46041
|
try {
|
|
46117
|
-
real =
|
|
46042
|
+
real = fs35.realpathSync(full);
|
|
46118
46043
|
} catch {
|
|
46119
46044
|
continue;
|
|
46120
46045
|
}
|
|
46121
46046
|
if (seen.has(real)) continue;
|
|
46122
46047
|
seen.add(real);
|
|
46123
46048
|
try {
|
|
46124
|
-
const content = JSON.parse(
|
|
46049
|
+
const content = JSON.parse(fs35.readFileSync(full, "utf-8"));
|
|
46125
46050
|
if (typeof content.templateName !== "string" || !content.templateName) continue;
|
|
46126
46051
|
const parsed2 = TemplateSchema.safeParse(content);
|
|
46127
46052
|
templates.push({
|
|
@@ -46158,7 +46083,7 @@ function registerTemplateDeployerTools(server2, client) {
|
|
|
46158
46083
|
async ({ templateFile }) => {
|
|
46159
46084
|
try {
|
|
46160
46085
|
const safePath = validateTemplatePath(templateFile);
|
|
46161
|
-
const content = JSON.parse(
|
|
46086
|
+
const content = JSON.parse(fs35.readFileSync(safePath, "utf-8"));
|
|
46162
46087
|
return {
|
|
46163
46088
|
content: [
|
|
46164
46089
|
{
|
|
@@ -46198,7 +46123,7 @@ function registerTemplateDeployerTools(server2, client) {
|
|
|
46198
46123
|
try {
|
|
46199
46124
|
const locId = client.resolveLocationId(locationId2);
|
|
46200
46125
|
const safePath = validateTemplatePath(templateFile);
|
|
46201
|
-
const template = TemplateSchema.parse(JSON.parse(
|
|
46126
|
+
const template = TemplateSchema.parse(JSON.parse(fs35.readFileSync(safePath, "utf-8")));
|
|
46202
46127
|
const resolve12 = (text2) => {
|
|
46203
46128
|
if (typeof text2 !== "string") return text2;
|
|
46204
46129
|
let result = text2;
|
|
@@ -46570,15 +46495,15 @@ ${errors.join("\n")}` : dryRun ? "\nNo errors!" : "\nNo errors \u2014 every item
|
|
|
46570
46495
|
}
|
|
46571
46496
|
);
|
|
46572
46497
|
}
|
|
46573
|
-
var import_zod71,
|
|
46498
|
+
var import_zod71, fs35, path33, TemplateSchema;
|
|
46574
46499
|
var init_template_deployer = __esm({
|
|
46575
46500
|
"src/tools/template-deployer.ts"() {
|
|
46576
46501
|
"use strict";
|
|
46577
46502
|
import_zod71 = require("zod");
|
|
46578
46503
|
init_workflow_builder_client();
|
|
46579
46504
|
init_tool_helpers();
|
|
46580
|
-
|
|
46581
|
-
|
|
46505
|
+
fs35 = __toESM(require("fs"));
|
|
46506
|
+
path33 = __toESM(require("path"));
|
|
46582
46507
|
init_workflow_builder_client();
|
|
46583
46508
|
TemplateSchema = import_zod71.z.object({
|
|
46584
46509
|
templateName: import_zod71.z.string(),
|
|
@@ -46899,10 +46824,10 @@ async function confirm(run) {
|
|
|
46899
46824
|
async function runProbes(client, loc) {
|
|
46900
46825
|
return Promise.all(
|
|
46901
46826
|
PROBES.map((probe) => confirm(async () => {
|
|
46902
|
-
const
|
|
46827
|
+
const path41 = probe.path.replace("{loc}", loc);
|
|
46903
46828
|
const params = probe.params ? Object.fromEntries(Object.entries(probe.params).map(([k, v]) => [k, substitute(v, loc)])) : void 0;
|
|
46904
46829
|
try {
|
|
46905
|
-
const raw = await client.get(
|
|
46830
|
+
const raw = await client.get(path41, { params, noRetry: true });
|
|
46906
46831
|
const count2 = countRows(raw, probe.listKeys);
|
|
46907
46832
|
return {
|
|
46908
46833
|
key: probe.key,
|
|
@@ -47178,14 +47103,14 @@ var init_checkup = __esm({
|
|
|
47178
47103
|
|
|
47179
47104
|
// src/tools/user-guide.ts
|
|
47180
47105
|
function resolveGuidePath() {
|
|
47181
|
-
const bundled =
|
|
47182
|
-
if (
|
|
47183
|
-
const devRoot =
|
|
47106
|
+
const bundled = path34.resolve(__dirname, "..", "guide", "guide.html");
|
|
47107
|
+
if (fs36.existsSync(bundled)) return bundled;
|
|
47108
|
+
const devRoot = path34.resolve(__dirname, "..", "..");
|
|
47184
47109
|
try {
|
|
47185
|
-
const pkg2 = JSON.parse(
|
|
47110
|
+
const pkg2 = JSON.parse(fs36.readFileSync(path34.join(devRoot, "package.json"), "utf8"));
|
|
47186
47111
|
if (pkg2.name === "@elitedcs/ghl-mcp") {
|
|
47187
|
-
const dev =
|
|
47188
|
-
if (
|
|
47112
|
+
const dev = path34.join(devRoot, "guide", "guide.html");
|
|
47113
|
+
if (fs36.existsSync(dev)) return dev;
|
|
47189
47114
|
}
|
|
47190
47115
|
} catch {
|
|
47191
47116
|
}
|
|
@@ -47194,7 +47119,7 @@ function resolveGuidePath() {
|
|
|
47194
47119
|
function guideContents(file2) {
|
|
47195
47120
|
let html2 = "";
|
|
47196
47121
|
try {
|
|
47197
|
-
html2 =
|
|
47122
|
+
html2 = fs36.readFileSync(file2, "utf8");
|
|
47198
47123
|
} catch {
|
|
47199
47124
|
return "The guide is installed but could not be read.";
|
|
47200
47125
|
}
|
|
@@ -47218,7 +47143,7 @@ function registerUserGuideTools(server2) {
|
|
|
47218
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.") },
|
|
47219
47144
|
async ({ open }) => {
|
|
47220
47145
|
const guidePath = resolveGuidePath();
|
|
47221
|
-
if (!
|
|
47146
|
+
if (!fs36.existsSync(guidePath)) {
|
|
47222
47147
|
return {
|
|
47223
47148
|
content: [{
|
|
47224
47149
|
type: "text",
|
|
@@ -47251,14 +47176,14 @@ ${guidePath}`;
|
|
|
47251
47176
|
}
|
|
47252
47177
|
);
|
|
47253
47178
|
}
|
|
47254
|
-
var import_child_process6, import_zod73,
|
|
47179
|
+
var import_child_process6, import_zod73, fs36, path34;
|
|
47255
47180
|
var init_user_guide = __esm({
|
|
47256
47181
|
"src/tools/user-guide.ts"() {
|
|
47257
47182
|
"use strict";
|
|
47258
47183
|
import_child_process6 = require("child_process");
|
|
47259
47184
|
import_zod73 = require("zod");
|
|
47260
|
-
|
|
47261
|
-
|
|
47185
|
+
fs36 = __toESM(require("fs"));
|
|
47186
|
+
path34 = __toESM(require("path"));
|
|
47262
47187
|
}
|
|
47263
47188
|
});
|
|
47264
47189
|
|
|
@@ -49468,9 +49393,9 @@ async function settle(page) {
|
|
|
49468
49393
|
}
|
|
49469
49394
|
async function readTarget(target) {
|
|
49470
49395
|
if (isUrl(target)) return { html: null, url: target };
|
|
49471
|
-
const abs =
|
|
49472
|
-
if (!
|
|
49473
|
-
return { html:
|
|
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() };
|
|
49474
49399
|
}
|
|
49475
49400
|
function slidePixels(index, png, file2, sec, brand) {
|
|
49476
49401
|
let img;
|
|
@@ -49518,7 +49443,7 @@ async function verifyDesign(opts) {
|
|
|
49518
49443
|
const { html: html2, url } = await readTarget(opts.target);
|
|
49519
49444
|
const placement = opts.placement ?? "html";
|
|
49520
49445
|
const medium = opts.medium;
|
|
49521
|
-
|
|
49446
|
+
fs37.mkdirSync(opts.outDir, { recursive: true });
|
|
49522
49447
|
const files = [];
|
|
49523
49448
|
const screenshots = [];
|
|
49524
49449
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -49563,8 +49488,8 @@ async function verifyDesign(opts) {
|
|
|
49563
49488
|
try {
|
|
49564
49489
|
await loc.scrollIntoViewIfNeeded({ timeout: 5e3 });
|
|
49565
49490
|
const png = await loc.screenshot({ type: "png", timeout: 15e3 });
|
|
49566
|
-
|
|
49567
|
-
files.push(
|
|
49491
|
+
fs37.writeFileSync(path35.join(opts.outDir, file2), png);
|
|
49492
|
+
files.push(path35.join(opts.outDir, file2));
|
|
49568
49493
|
screenshots.push(file2);
|
|
49569
49494
|
pixels.push(slidePixels(sec.index, png, file2, sec, opts.brand));
|
|
49570
49495
|
} catch {
|
|
@@ -49596,8 +49521,8 @@ async function verifyDesign(opts) {
|
|
|
49596
49521
|
const shot = "page-1440.png";
|
|
49597
49522
|
try {
|
|
49598
49523
|
const png = await page.screenshot({ type: "png", fullPage: true, timeout: 2e4 });
|
|
49599
|
-
|
|
49600
|
-
files.push(
|
|
49524
|
+
fs37.writeFileSync(path35.join(opts.outDir, shot), png);
|
|
49525
|
+
files.push(path35.join(opts.outDir, shot));
|
|
49601
49526
|
screenshots.push(shot);
|
|
49602
49527
|
} catch {
|
|
49603
49528
|
}
|
|
@@ -49605,8 +49530,8 @@ async function verifyDesign(opts) {
|
|
|
49605
49530
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
49606
49531
|
await page.evaluate(SETTLE_SCROLL_JS).catch(() => void 0);
|
|
49607
49532
|
const png = await page.screenshot({ type: "png", fullPage: true, timeout: 2e4 });
|
|
49608
|
-
|
|
49609
|
-
files.push(
|
|
49533
|
+
fs37.writeFileSync(path35.join(opts.outDir, "page-390.png"), png);
|
|
49534
|
+
files.push(path35.join(opts.outDir, "page-390.png"));
|
|
49610
49535
|
screenshots.push("page-390.png");
|
|
49611
49536
|
} catch {
|
|
49612
49537
|
}
|
|
@@ -49679,21 +49604,21 @@ async function verifyDesign(opts) {
|
|
|
49679
49604
|
screenshots
|
|
49680
49605
|
};
|
|
49681
49606
|
const checked = VerificationSchema.parse(report2);
|
|
49682
|
-
const jsonPath =
|
|
49683
|
-
|
|
49607
|
+
const jsonPath = path35.join(opts.outDir, "verification.json");
|
|
49608
|
+
fs37.writeFileSync(jsonPath, JSON.stringify(checked, null, 2) + "\n");
|
|
49684
49609
|
files.push(jsonPath);
|
|
49685
49610
|
const reportHtml = renderVerificationHtml(checked, opts.branding);
|
|
49686
|
-
const htmlPath =
|
|
49687
|
-
|
|
49611
|
+
const htmlPath = path35.join(opts.outDir, "verification.html");
|
|
49612
|
+
fs37.writeFileSync(htmlPath, reportHtml);
|
|
49688
49613
|
files.push(htmlPath);
|
|
49689
49614
|
return { report: checked, files, reportHtml };
|
|
49690
49615
|
}
|
|
49691
|
-
var
|
|
49616
|
+
var fs37, path35, import_node_url, WEB_WIDTHS, SETTLE_SCROLL_JS, FOCUS_JS;
|
|
49692
49617
|
var init_verify = __esm({
|
|
49693
49618
|
"src/command-os/design/verify.ts"() {
|
|
49694
49619
|
"use strict";
|
|
49695
|
-
|
|
49696
|
-
|
|
49620
|
+
fs37 = __toESM(require("node:fs"));
|
|
49621
|
+
path35 = __toESM(require("node:path"));
|
|
49697
49622
|
import_node_url = require("node:url");
|
|
49698
49623
|
init_lint();
|
|
49699
49624
|
init_probe();
|
|
@@ -50112,7 +50037,7 @@ function registerDesignStudioTools(server2) {
|
|
|
50112
50037
|
const { dna, logoSvg, logoPng } = deriveBrandDna(raw, { name, slug: slug3, rights: { declaration: a.rights, at: (/* @__PURE__ */ new Date()).toISOString() }, browser, firecrawl: fc });
|
|
50113
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.");
|
|
50114
50039
|
const written = writeBrand(dna, { logoSvg, logoPng, screenshotPng: browser?.screenshotPng });
|
|
50115
|
-
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) =>
|
|
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 };
|
|
50116
50041
|
}
|
|
50117
50042
|
);
|
|
50118
50043
|
safeTool(
|
|
@@ -50279,9 +50204,9 @@ function registerDesignStudioTools(server2) {
|
|
|
50279
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.",
|
|
50280
50205
|
{ file: import_zod76.z.string().describe("Path to the .html file."), medium: import_zod76.z.enum(MEDIA) },
|
|
50281
50206
|
async ({ file: file2, medium }) => {
|
|
50282
|
-
const abs =
|
|
50283
|
-
if (!
|
|
50284
|
-
const r = lintDesignContract(
|
|
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);
|
|
50285
50210
|
return { ok: r.ok, problems: r.problems, warnings: r.warnings, facts: r.facts };
|
|
50286
50211
|
}
|
|
50287
50212
|
);
|
|
@@ -50302,7 +50227,7 @@ function registerDesignStudioTools(server2) {
|
|
|
50302
50227
|
async (a) => {
|
|
50303
50228
|
const brand = a.brandSlug ? houseLooks().find((d) => d.slug === a.brandSlug) ?? readBrand(slugify(a.brandSlug)) : void 0;
|
|
50304
50229
|
const isUrl2 = /^https?:\/\//i.test(a.target);
|
|
50305
|
-
const outDir = a.outDir ?? (isUrl2 ?
|
|
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")}`));
|
|
50306
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() });
|
|
50307
50232
|
const v = r.report;
|
|
50308
50233
|
const failed = v.rules.filter((x) => x.state === "MEASURED-FAIL").map((x) => `${x.ruleId} ${x.name}: ${x.measured ?? ""}`);
|
|
@@ -50317,7 +50242,7 @@ function registerDesignStudioTools(server2) {
|
|
|
50317
50242
|
judgments: v.rules.filter((x) => x.state === "ASSERTED").map((x) => `${x.ruleId} ${x.name}: ${x.detail ?? ""}`),
|
|
50318
50243
|
notApplicable: v.rules.filter((x) => x.state === "N-A").map((x) => `${x.ruleId}: ${x.detail ?? ""}`),
|
|
50319
50244
|
brandMatch: v.brandMatch,
|
|
50320
|
-
report:
|
|
50245
|
+
report: path36.join(outDir, "verification.html"),
|
|
50321
50246
|
files: r.files,
|
|
50322
50247
|
...a.placement === "ghl" && { builderOwned: builderOwnedRules().map((b) => `${b.rule.id} ${b.rule.name}: ${b.why}`) }
|
|
50323
50248
|
};
|
|
@@ -50345,9 +50270,9 @@ function registerDesignStudioTools(server2) {
|
|
|
50345
50270
|
if (!a.pageDataDownloadUrl && !a.file) throw new Error("Pass pageDataDownloadUrl (from get_page_full) or file.");
|
|
50346
50271
|
let page;
|
|
50347
50272
|
if (a.file) {
|
|
50348
|
-
const abs =
|
|
50349
|
-
if (!
|
|
50350
|
-
page = JSON.parse(
|
|
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"));
|
|
50351
50276
|
} else {
|
|
50352
50277
|
const response = await fetch(a.pageDataDownloadUrl, { headers: { Accept: "application/json,*/*" } });
|
|
50353
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.`);
|
|
@@ -50388,9 +50313,9 @@ function registerDesignStudioTools(server2) {
|
|
|
50388
50313
|
if (!a.file && !a.text) throw new Error("Pass file or text.");
|
|
50389
50314
|
let html2 = a.text ?? "";
|
|
50390
50315
|
if (a.file) {
|
|
50391
|
-
const abs =
|
|
50392
|
-
if (!
|
|
50393
|
-
html2 =
|
|
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");
|
|
50394
50319
|
}
|
|
50395
50320
|
const r = await gradeCopy(html2, claudeGenerate(a.model), { icp: a.icp });
|
|
50396
50321
|
if (!r.grade) {
|
|
@@ -50425,13 +50350,13 @@ function registerDesignStudioTools(server2) {
|
|
|
50425
50350
|
}
|
|
50426
50351
|
);
|
|
50427
50352
|
}
|
|
50428
|
-
var import_zod76,
|
|
50353
|
+
var import_zod76, fs38, path36, summarise2;
|
|
50429
50354
|
var init_design_studio = __esm({
|
|
50430
50355
|
"src/tools/design-studio.ts"() {
|
|
50431
50356
|
"use strict";
|
|
50432
50357
|
import_zod76 = require("zod");
|
|
50433
|
-
|
|
50434
|
-
|
|
50358
|
+
fs38 = __toESM(require("node:fs"));
|
|
50359
|
+
path36 = __toESM(require("node:path"));
|
|
50435
50360
|
init_tool_helpers();
|
|
50436
50361
|
init_extract();
|
|
50437
50362
|
init_extract_browser();
|
|
@@ -50735,7 +50660,7 @@ function registerConnectorTools(server2) {
|
|
|
50735
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.",
|
|
50736
50661
|
{
|
|
50737
50662
|
system: import_zod77.z.enum(["stripe", "slack"]).describe("The system to connect: stripe or slack."),
|
|
50738
|
-
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."),
|
|
50739
50664
|
label: import_zod77.z.string().optional().describe("Which account this is, so you can tell two apart later.")
|
|
50740
50665
|
},
|
|
50741
50666
|
connectSystem
|
|
@@ -51155,11 +51080,11 @@ var init_audit = __esm({
|
|
|
51155
51080
|
// src/command-os/delivery-audit/store.ts
|
|
51156
51081
|
function deliveryAuditPath() {
|
|
51157
51082
|
const override = process.env[DELIVERY_AUDIT_ENV];
|
|
51158
|
-
return override && override.trim() ? override :
|
|
51083
|
+
return override && override.trim() ? override : path37.join(appDataDir(), "delivery-audit.json");
|
|
51159
51084
|
}
|
|
51160
51085
|
function readDeliveryAudit() {
|
|
51161
51086
|
try {
|
|
51162
|
-
const parsed2 = JSON.parse(
|
|
51087
|
+
const parsed2 = JSON.parse(fs39.readFileSync(deliveryAuditPath(), "utf-8"));
|
|
51163
51088
|
if (!parsed2 || typeof parsed2 !== "object" || !parsed2.answers || typeof parsed2.answers !== "object") return { ...EMPTY3 };
|
|
51164
51089
|
return { v: 1, answers: parsed2.answers, updated_at: parsed2.updated_at };
|
|
51165
51090
|
} catch {
|
|
@@ -51170,7 +51095,7 @@ function readForWrite2() {
|
|
|
51170
51095
|
const target = deliveryAuditPath();
|
|
51171
51096
|
let raw;
|
|
51172
51097
|
try {
|
|
51173
|
-
raw =
|
|
51098
|
+
raw = fs39.readFileSync(target, "utf-8");
|
|
51174
51099
|
} catch (e) {
|
|
51175
51100
|
if (e?.code === "ENOENT") return { ...EMPTY3 };
|
|
51176
51101
|
throw new Error("Your saved audit could not be read, so nothing was changed. Nothing was lost.");
|
|
@@ -51182,7 +51107,7 @@ function readForWrite2() {
|
|
|
51182
51107
|
} catch {
|
|
51183
51108
|
const kept = `${target}.unreadable-${Date.now()}`;
|
|
51184
51109
|
try {
|
|
51185
|
-
|
|
51110
|
+
fs39.copyFileSync(target, kept);
|
|
51186
51111
|
} catch {
|
|
51187
51112
|
}
|
|
51188
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.`);
|
|
@@ -51194,13 +51119,13 @@ function writeFile2(f) {
|
|
|
51194
51119
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
51195
51120
|
let renamed = false;
|
|
51196
51121
|
try {
|
|
51197
|
-
|
|
51198
|
-
|
|
51122
|
+
fs39.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
51123
|
+
fs39.renameSync(tmp, target);
|
|
51199
51124
|
renamed = true;
|
|
51200
51125
|
} finally {
|
|
51201
51126
|
if (!renamed) {
|
|
51202
51127
|
try {
|
|
51203
|
-
|
|
51128
|
+
fs39.unlinkSync(tmp);
|
|
51204
51129
|
} catch {
|
|
51205
51130
|
}
|
|
51206
51131
|
}
|
|
@@ -51221,12 +51146,12 @@ function resetDeliveryAudit(now = () => /* @__PURE__ */ new Date()) {
|
|
|
51221
51146
|
writeFile2(next);
|
|
51222
51147
|
return next;
|
|
51223
51148
|
}
|
|
51224
|
-
var
|
|
51149
|
+
var fs39, path37, EMPTY3, DELIVERY_AUDIT_ENV;
|
|
51225
51150
|
var init_store4 = __esm({
|
|
51226
51151
|
"src/command-os/delivery-audit/store.ts"() {
|
|
51227
51152
|
"use strict";
|
|
51228
|
-
|
|
51229
|
-
|
|
51153
|
+
fs39 = __toESM(require("node:fs"));
|
|
51154
|
+
path37 = __toESM(require("node:path"));
|
|
51230
51155
|
init_credentials_store();
|
|
51231
51156
|
EMPTY3 = { v: 1, answers: {} };
|
|
51232
51157
|
DELIVERY_AUDIT_ENV = "GHL_MCP_DELIVERY_AUDIT";
|
|
@@ -51451,7 +51376,7 @@ function planFingerprint(goal, steps) {
|
|
|
51451
51376
|
goal,
|
|
51452
51377
|
steps: steps.map((s) => ({ id: s.id, tool: s.tool, targets: s.targets, creates: s.creates ?? [], args: s.args ?? {} }))
|
|
51453
51378
|
});
|
|
51454
|
-
return (0,
|
|
51379
|
+
return (0, import_node_crypto12.createHash)("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 16);
|
|
51455
51380
|
}
|
|
51456
51381
|
function checkPlan(goal, findings, steps, now = /* @__PURE__ */ new Date(), knownTools) {
|
|
51457
51382
|
const refusals = [];
|
|
@@ -51668,11 +51593,11 @@ function abandon(a, why) {
|
|
|
51668
51593
|
const stillApplied = position(a).undo;
|
|
51669
51594
|
return { ok: true, automation: { ...a, phase: "abandoned", goal: a.goal, abandonedBecause: why }, stillApplied };
|
|
51670
51595
|
}
|
|
51671
|
-
var
|
|
51596
|
+
var import_node_crypto12, isExisting, FINDINGS_STALE_AFTER_MINUTES;
|
|
51672
51597
|
var init_automation = __esm({
|
|
51673
51598
|
"src/command-os/build/automation.ts"() {
|
|
51674
51599
|
"use strict";
|
|
51675
|
-
|
|
51600
|
+
import_node_crypto12 = require("node:crypto");
|
|
51676
51601
|
init_verify_findings();
|
|
51677
51602
|
isExisting = (t) => "existing" in t;
|
|
51678
51603
|
FINDINGS_STALE_AFTER_MINUTES = 60;
|
|
@@ -51682,7 +51607,7 @@ var init_automation = __esm({
|
|
|
51682
51607
|
// src/command-os/build/store.ts
|
|
51683
51608
|
function automationsPath() {
|
|
51684
51609
|
const override = process.env[AUTOMATIONS_ENV];
|
|
51685
|
-
return override && override.trim() ? override :
|
|
51610
|
+
return override && override.trim() ? override : path38.join(appDataDir(), "automations.json");
|
|
51686
51611
|
}
|
|
51687
51612
|
function parse4(raw) {
|
|
51688
51613
|
const p = JSON.parse(raw);
|
|
@@ -51691,7 +51616,7 @@ function parse4(raw) {
|
|
|
51691
51616
|
}
|
|
51692
51617
|
function readAutomations() {
|
|
51693
51618
|
try {
|
|
51694
|
-
return parse4(
|
|
51619
|
+
return parse4(fs40.readFileSync(automationsPath(), "utf-8")).builds;
|
|
51695
51620
|
} catch {
|
|
51696
51621
|
return { ...EMPTY4.builds };
|
|
51697
51622
|
}
|
|
@@ -51700,7 +51625,7 @@ function readForWrite3() {
|
|
|
51700
51625
|
const target = automationsPath();
|
|
51701
51626
|
let raw;
|
|
51702
51627
|
try {
|
|
51703
|
-
raw =
|
|
51628
|
+
raw = fs40.readFileSync(target, "utf-8");
|
|
51704
51629
|
} catch (e) {
|
|
51705
51630
|
if (e?.code === "ENOENT") return { v: 1, builds: {} };
|
|
51706
51631
|
throw new Error("Your builds file could not be read, so nothing was changed. Nothing was lost.");
|
|
@@ -51710,7 +51635,7 @@ function readForWrite3() {
|
|
|
51710
51635
|
} catch {
|
|
51711
51636
|
const kept = `${target}.unreadable-${Date.now()}`;
|
|
51712
51637
|
try {
|
|
51713
|
-
|
|
51638
|
+
fs40.copyFileSync(target, kept);
|
|
51714
51639
|
} catch {
|
|
51715
51640
|
}
|
|
51716
51641
|
throw new Error(
|
|
@@ -51724,13 +51649,13 @@ function writeFile3(f) {
|
|
|
51724
51649
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
51725
51650
|
let renamed = false;
|
|
51726
51651
|
try {
|
|
51727
|
-
|
|
51728
|
-
|
|
51652
|
+
fs40.writeFileSync(tmp, JSON.stringify(f, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
51653
|
+
fs40.renameSync(tmp, target);
|
|
51729
51654
|
renamed = true;
|
|
51730
51655
|
} finally {
|
|
51731
51656
|
if (!renamed) {
|
|
51732
51657
|
try {
|
|
51733
|
-
|
|
51658
|
+
fs40.unlinkSync(tmp);
|
|
51734
51659
|
} catch {
|
|
51735
51660
|
}
|
|
51736
51661
|
}
|
|
@@ -51756,12 +51681,12 @@ function newAutomationId(now = () => /* @__PURE__ */ new Date()) {
|
|
|
51756
51681
|
}
|
|
51757
51682
|
return id;
|
|
51758
51683
|
}
|
|
51759
|
-
var
|
|
51684
|
+
var fs40, path38, AUTOMATIONS_ENV, EMPTY4;
|
|
51760
51685
|
var init_store5 = __esm({
|
|
51761
51686
|
"src/command-os/build/store.ts"() {
|
|
51762
51687
|
"use strict";
|
|
51763
|
-
|
|
51764
|
-
|
|
51688
|
+
fs40 = __toESM(require("node:fs"));
|
|
51689
|
+
path38 = __toESM(require("node:path"));
|
|
51765
51690
|
init_credentials_store();
|
|
51766
51691
|
AUTOMATIONS_ENV = "GHL_MCP_AUTOMATIONS";
|
|
51767
51692
|
EMPTY4 = { v: 1, builds: {} };
|
|
@@ -55149,13 +55074,13 @@ ${text3}`);
|
|
|
55149
55074
|
};
|
|
55150
55075
|
}
|
|
55151
55076
|
function makePipelineApi(builderClient) {
|
|
55152
|
-
return async (method,
|
|
55153
|
-
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${
|
|
55077
|
+
return async (method, path41, body) => {
|
|
55078
|
+
const url = `https://backend.leadconnectorhq.com/opportunities/pipelines${path41}`;
|
|
55154
55079
|
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
55155
55080
|
const response = await builderRequest(builderClient, method, url, sendsBody ? { body } : {});
|
|
55156
55081
|
if (!response.ok) {
|
|
55157
55082
|
const text3 = await response.text();
|
|
55158
|
-
throw new Error(`Pipeline API ${response.status}: ${method} ${
|
|
55083
|
+
throw new Error(`Pipeline API ${response.status}: ${method} ${path41}
|
|
55159
55084
|
${text3}`);
|
|
55160
55085
|
}
|
|
55161
55086
|
const text2 = await response.text();
|
|
@@ -55168,8 +55093,8 @@ ${text3}`);
|
|
|
55168
55093
|
};
|
|
55169
55094
|
}
|
|
55170
55095
|
function makeFunnelApi(builderClient) {
|
|
55171
|
-
return async (method,
|
|
55172
|
-
const url = `https://backend.leadconnectorhq.com/funnels${
|
|
55096
|
+
return async (method, path41, body) => {
|
|
55097
|
+
const url = `https://backend.leadconnectorhq.com/funnels${path41}`;
|
|
55173
55098
|
const sendsBody = body !== void 0 && (method === "POST" || method === "PUT");
|
|
55174
55099
|
const response = await builderRequest(builderClient, method, url, {
|
|
55175
55100
|
...sendsBody ? { body } : {},
|
|
@@ -55182,7 +55107,7 @@ function makeFunnelApi(builderClient) {
|
|
|
55182
55107
|
});
|
|
55183
55108
|
if (!response.ok) {
|
|
55184
55109
|
const text3 = await response.text();
|
|
55185
|
-
throw new Error(`Funnel API ${response.status}: ${method} ${
|
|
55110
|
+
throw new Error(`Funnel API ${response.status}: ${method} ${path41}
|
|
55186
55111
|
${text3.slice(0, 300)}`);
|
|
55187
55112
|
}
|
|
55188
55113
|
const text2 = await response.text();
|
|
@@ -56497,7 +56422,7 @@ function registerAllTools(server2, client, registry2, mcpVersion, env2 = process
|
|
|
56497
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.` }));
|
|
56498
56423
|
}
|
|
56499
56424
|
const reader = token2 ? new GHLClient({ apiKey: token2.apiKey, locationId: loc }) : client;
|
|
56500
|
-
return refuseUnseenFindings2((
|
|
56425
|
+
return refuseUnseenFindings2((path41, params) => reader.get(path41, params ? { params } : void 0), loc, findings);
|
|
56501
56426
|
}, () => client.defaultLocationId);
|
|
56502
56427
|
registerClientEngagementTools(wrap(CLIENT_ENGAGEMENTS_MODULE), registry2);
|
|
56503
56428
|
registerAuditReportTools(wrap(AUDIT_REPORT_MODULE));
|
|
@@ -56917,8 +56842,8 @@ __export(index_exports, {
|
|
|
56917
56842
|
});
|
|
56918
56843
|
module.exports = __toCommonJS(index_exports);
|
|
56919
56844
|
var dotenv2 = __toESM(require("dotenv"));
|
|
56920
|
-
var
|
|
56921
|
-
var
|
|
56845
|
+
var path40 = __toESM(require("path"));
|
|
56846
|
+
var fs42 = __toESM(require("fs"));
|
|
56922
56847
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
56923
56848
|
|
|
56924
56849
|
// src/version-compare.ts
|
|
@@ -56989,12 +56914,12 @@ init_setup_tool();
|
|
|
56989
56914
|
var import_zod87 = require("zod");
|
|
56990
56915
|
|
|
56991
56916
|
// src/skill-installer.ts
|
|
56992
|
-
var
|
|
56993
|
-
var
|
|
56994
|
-
var
|
|
56917
|
+
var import_node_crypto13 = require("node:crypto");
|
|
56918
|
+
var fs41 = __toESM(require("node:fs"));
|
|
56919
|
+
var path39 = __toESM(require("node:path"));
|
|
56995
56920
|
var os7 = __toESM(require("node:os"));
|
|
56996
56921
|
function sha2562(buf) {
|
|
56997
|
-
return (0,
|
|
56922
|
+
return (0, import_node_crypto13.createHash)("sha256").update(buf).digest("hex");
|
|
56998
56923
|
}
|
|
56999
56924
|
function isOlderRelease(candidate, installed) {
|
|
57000
56925
|
const parts = (v) => v.trim().split(".").map((n) => Number.parseInt(n, 10));
|
|
@@ -57006,9 +56931,9 @@ function isOlderRelease(candidate, installed) {
|
|
|
57006
56931
|
return false;
|
|
57007
56932
|
}
|
|
57008
56933
|
function bundledSkillsDir(baseDir) {
|
|
57009
|
-
const candidate =
|
|
56934
|
+
const candidate = path39.resolve(baseDir, "..", "skills");
|
|
57010
56935
|
try {
|
|
57011
|
-
return
|
|
56936
|
+
return fs41.statSync(candidate).isDirectory() ? candidate : null;
|
|
57012
56937
|
} catch {
|
|
57013
56938
|
return null;
|
|
57014
56939
|
}
|
|
@@ -57016,10 +56941,10 @@ function bundledSkillsDir(baseDir) {
|
|
|
57016
56941
|
function listFiles(root) {
|
|
57017
56942
|
const out = [];
|
|
57018
56943
|
const walk = (dir) => {
|
|
57019
|
-
for (const entry of
|
|
57020
|
-
const full =
|
|
56944
|
+
for (const entry of fs41.readdirSync(dir, { withFileTypes: true })) {
|
|
56945
|
+
const full = path39.join(dir, entry.name);
|
|
57021
56946
|
if (entry.isDirectory()) walk(full);
|
|
57022
|
-
else if (entry.isFile()) out.push(
|
|
56947
|
+
else if (entry.isFile()) out.push(path39.relative(root, full));
|
|
57023
56948
|
}
|
|
57024
56949
|
};
|
|
57025
56950
|
walk(root);
|
|
@@ -57027,7 +56952,7 @@ function listFiles(root) {
|
|
|
57027
56952
|
}
|
|
57028
56953
|
function readMarker(markerPath) {
|
|
57029
56954
|
try {
|
|
57030
|
-
const parsed2 = JSON.parse(
|
|
56955
|
+
const parsed2 = JSON.parse(fs41.readFileSync(markerPath, "utf8"));
|
|
57031
56956
|
return parsed2 && typeof parsed2 === "object" && parsed2.files ? parsed2 : null;
|
|
57032
56957
|
} catch {
|
|
57033
56958
|
return null;
|
|
@@ -57041,35 +56966,35 @@ function installBundledSkills(opts) {
|
|
|
57041
56966
|
skippedOlderPackage: [],
|
|
57042
56967
|
unchanged: [],
|
|
57043
56968
|
errors: [],
|
|
57044
|
-
targetDir: opts.targetDir ??
|
|
56969
|
+
targetDir: opts.targetDir ?? path39.join(os7.homedir(), ".claude", "skills"),
|
|
57045
56970
|
bundledDir: null
|
|
57046
56971
|
};
|
|
57047
56972
|
const bundled = bundledSkillsDir(opts.baseDir);
|
|
57048
56973
|
result.bundledDir = bundled;
|
|
57049
56974
|
if (!bundled) return result;
|
|
57050
56975
|
try {
|
|
57051
|
-
|
|
56976
|
+
fs41.mkdirSync(result.targetDir, { recursive: true });
|
|
57052
56977
|
} catch (e) {
|
|
57053
56978
|
result.errors.push(`cannot create ${result.targetDir}: ${String(e)}`);
|
|
57054
56979
|
return result;
|
|
57055
56980
|
}
|
|
57056
|
-
const markerPath =
|
|
56981
|
+
const markerPath = path39.join(result.targetDir, ".ghl-command-skills.json");
|
|
57057
56982
|
const marker = readMarker(markerPath) ?? { packageVersion: "", files: {} };
|
|
57058
56983
|
const newMarker = { packageVersion: opts.packageVersion, files: { ...marker.files } };
|
|
57059
56984
|
for (const rel of listFiles(bundled)) {
|
|
57060
56985
|
try {
|
|
57061
|
-
const src =
|
|
57062
|
-
const dest =
|
|
56986
|
+
const src = fs41.readFileSync(path39.join(bundled, rel));
|
|
56987
|
+
const dest = path39.join(result.targetDir, rel);
|
|
57063
56988
|
const srcHash = sha2562(src);
|
|
57064
56989
|
let destBuf = null;
|
|
57065
56990
|
try {
|
|
57066
|
-
destBuf =
|
|
56991
|
+
destBuf = fs41.readFileSync(dest);
|
|
57067
56992
|
} catch {
|
|
57068
56993
|
destBuf = null;
|
|
57069
56994
|
}
|
|
57070
56995
|
if (destBuf === null) {
|
|
57071
|
-
|
|
57072
|
-
|
|
56996
|
+
fs41.mkdirSync(path39.dirname(dest), { recursive: true });
|
|
56997
|
+
fs41.writeFileSync(dest, src);
|
|
57073
56998
|
newMarker.files[rel] = srcHash;
|
|
57074
56999
|
result.installed.push(rel);
|
|
57075
57000
|
continue;
|
|
@@ -57086,7 +57011,7 @@ function installBundledSkills(opts) {
|
|
|
57086
57011
|
newMarker.packageVersion = marker.packageVersion;
|
|
57087
57012
|
result.skippedOlderPackage.push(rel);
|
|
57088
57013
|
} else if (lastWritten && destHash === lastWritten) {
|
|
57089
|
-
|
|
57014
|
+
fs41.writeFileSync(dest, src);
|
|
57090
57015
|
newMarker.files[rel] = srcHash;
|
|
57091
57016
|
result.updated.push(rel);
|
|
57092
57017
|
} else {
|
|
@@ -57097,7 +57022,7 @@ function installBundledSkills(opts) {
|
|
|
57097
57022
|
}
|
|
57098
57023
|
}
|
|
57099
57024
|
try {
|
|
57100
|
-
|
|
57025
|
+
fs41.writeFileSync(markerPath, JSON.stringify(newMarker, null, 2));
|
|
57101
57026
|
} catch (e) {
|
|
57102
57027
|
result.errors.push(`marker write failed: ${String(e)}`);
|
|
57103
57028
|
}
|
|
@@ -57253,7 +57178,7 @@ dotenv2.config();
|
|
|
57253
57178
|
setPkgVersion(pkg.version);
|
|
57254
57179
|
{
|
|
57255
57180
|
const configDirOverride = process.env.GHL_MCP_CONFIG_DIR?.trim();
|
|
57256
|
-
if (configDirOverride && !
|
|
57181
|
+
if (configDirOverride && !path40.isAbsolute(configDirOverride)) {
|
|
57257
57182
|
process.stderr.write(
|
|
57258
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.
|
|
57259
57184
|
`
|
|
@@ -57266,20 +57191,20 @@ process.on("unhandledRejection", (reason3) => {
|
|
|
57266
57191
|
`);
|
|
57267
57192
|
});
|
|
57268
57193
|
function hardenSecretFilePerms() {
|
|
57269
|
-
const repoDir =
|
|
57194
|
+
const repoDir = path40.resolve(__dirname, "..");
|
|
57270
57195
|
const candidates = [
|
|
57271
|
-
{ file:
|
|
57196
|
+
{ file: path40.join(repoDir, "start-mcp.sh"), mode: 448 },
|
|
57272
57197
|
// Legacy registry location (pre-migration); new location lives in app-data.
|
|
57273
|
-
{ file:
|
|
57198
|
+
{ file: path40.join(repoDir, ".ghl-tokens.json"), mode: 384 },
|
|
57274
57199
|
{ file: tokenRegistryPath(), mode: 384 }
|
|
57275
57200
|
];
|
|
57276
57201
|
for (const { file: file2, mode } of candidates) {
|
|
57277
57202
|
let current;
|
|
57278
57203
|
try {
|
|
57279
|
-
if (!
|
|
57280
|
-
current =
|
|
57204
|
+
if (!fs42.existsSync(file2)) continue;
|
|
57205
|
+
current = fs42.statSync(file2).mode & 511;
|
|
57281
57206
|
if (current !== mode) {
|
|
57282
|
-
|
|
57207
|
+
fs42.chmodSync(file2, mode);
|
|
57283
57208
|
}
|
|
57284
57209
|
} catch (error) {
|
|
57285
57210
|
const message = error instanceof Error ? error.message : String(error);
|