gufi-cli 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/security.js +5 -0
- package/dist/mcp.js +135 -52
- package/package.json +1 -1
package/dist/lib/security.js
CHANGED
|
@@ -114,6 +114,11 @@ const ALLOWED_PATTERNS = [
|
|
|
114
114
|
// CSRF token reading from cookies - legitimate security practice
|
|
115
115
|
/csrf-token/i,
|
|
116
116
|
/getCsrfToken/,
|
|
117
|
+
// Auth cookie management - legitimate for ecommerce auth
|
|
118
|
+
/strong_store_auth/,
|
|
119
|
+
/setAuthCookie/,
|
|
120
|
+
/clearAuthCookie/,
|
|
121
|
+
/document\.cookie/,
|
|
117
122
|
];
|
|
118
123
|
/**
|
|
119
124
|
* Scan a file for suspicious patterns
|
package/dist/mcp.js
CHANGED
|
@@ -502,22 +502,24 @@ const SCHEMA_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
|
502
502
|
const PHYSICAL_TABLE_RE = /^m\d+_t\d+$/;
|
|
503
503
|
/**
|
|
504
504
|
* Get company schema (cached)
|
|
505
|
+
* Returns { schema, error } - error is set if fetch failed
|
|
505
506
|
*/
|
|
506
507
|
async function getCompanySchema(companyId, env) {
|
|
507
508
|
// Include env in cache key to avoid mixing schemas from different environments
|
|
508
509
|
const cacheKey = `${companyId}:${env || 'prod'}`;
|
|
509
510
|
const cached = schemaCache.get(cacheKey);
|
|
510
511
|
if (cached && Date.now() - cached.timestamp < SCHEMA_CACHE_TTL) {
|
|
511
|
-
return cached.schema;
|
|
512
|
+
return { schema: cached.schema };
|
|
512
513
|
}
|
|
513
514
|
try {
|
|
514
515
|
const data = await apiRequest("/api/cli/schema", {}, companyId, true, env);
|
|
515
516
|
schemaCache.set(cacheKey, { schema: data, timestamp: Date.now() });
|
|
516
|
-
return data;
|
|
517
|
+
return { schema: data };
|
|
517
518
|
}
|
|
518
519
|
catch (err) {
|
|
519
|
-
|
|
520
|
-
|
|
520
|
+
const errorMsg = err.message;
|
|
521
|
+
console.error(`[MCP] Failed to get schema for company ${companyId}:`, errorMsg);
|
|
522
|
+
return { schema: null, error: errorMsg };
|
|
521
523
|
}
|
|
522
524
|
}
|
|
523
525
|
/**
|
|
@@ -538,19 +540,20 @@ async function resolveTableName(tableName, companyId, env) {
|
|
|
538
540
|
throw new Error(`Invalid table name: "${tableName}". Use physical (m123_t456) or logical (module.entity) format`);
|
|
539
541
|
}
|
|
540
542
|
const [moduleName, entityName] = parts;
|
|
541
|
-
const schema = await getCompanySchema(companyId, env);
|
|
543
|
+
const { schema, error } = await getCompanySchema(companyId, env);
|
|
542
544
|
if (!schema?.modules) {
|
|
543
|
-
|
|
545
|
+
const reason = error || "unknown error";
|
|
546
|
+
throw new Error(`Cannot resolve logical table name "${tableName}": ${reason}`);
|
|
544
547
|
}
|
|
545
548
|
// Find module and entity
|
|
546
549
|
for (const mod of schema.modules) {
|
|
547
550
|
const modMatch = mod.name?.toLowerCase() === moduleName.toLowerCase() ||
|
|
548
|
-
mod.
|
|
551
|
+
mod.display_name?.toLowerCase() === moduleName.toLowerCase();
|
|
549
552
|
if (!modMatch)
|
|
550
553
|
continue;
|
|
551
554
|
for (const ent of mod.entities || []) {
|
|
552
555
|
const entMatch = ent.name?.toLowerCase() === entityName.toLowerCase() ||
|
|
553
|
-
ent.
|
|
556
|
+
ent.display_name?.toLowerCase() === entityName.toLowerCase();
|
|
554
557
|
if (entMatch) {
|
|
555
558
|
// Found! Build physical name from entity ID
|
|
556
559
|
const moduleId = mod.id;
|
|
@@ -856,20 +859,20 @@ Solo Admin y Consultant pueden gestionar endpoints.`,
|
|
|
856
859
|
name: "gufi_view_pull",
|
|
857
860
|
description: `📥 Download view files to local directory for editing.
|
|
858
861
|
|
|
859
|
-
Downloads to: ~/gufi-dev/view_<id>/
|
|
862
|
+
Downloads to: ~/gufi-dev/company_<id>/view_<id>/
|
|
860
863
|
|
|
861
864
|
After pulling, use Read/Edit tools to work with local files.
|
|
862
865
|
Then use gufi_view_push to upload changes.
|
|
863
866
|
|
|
864
|
-
Example: gufi_view_pull({ view_id: 13 })`,
|
|
867
|
+
Example: gufi_view_pull({ view_id: 13, company_id: '150' })`,
|
|
865
868
|
inputSchema: {
|
|
866
869
|
type: "object",
|
|
867
870
|
properties: {
|
|
868
871
|
view_id: { type: "number", description: "View ID to pull" },
|
|
869
|
-
company_id: { type: "string", description: "Company ID (required
|
|
872
|
+
company_id: { type: "string", description: "Company ID (required)" },
|
|
870
873
|
env: ENV_PARAM,
|
|
871
874
|
},
|
|
872
|
-
required: ["view_id"],
|
|
875
|
+
required: ["view_id", "company_id"],
|
|
873
876
|
},
|
|
874
877
|
},
|
|
875
878
|
// 📤 Push local changes to draft
|
|
@@ -941,25 +944,9 @@ Examples:
|
|
|
941
944
|
},
|
|
942
945
|
},
|
|
943
946
|
// ─────────────────────────────────────────────────────────────────────────
|
|
944
|
-
// Packages (
|
|
947
|
+
// 💜 DISABLED: Packages (not actively used, keeping MCP simple)
|
|
945
948
|
// ─────────────────────────────────────────────────────────────────────────
|
|
946
|
-
|
|
947
|
-
name: "gufi_package",
|
|
948
|
-
description: getDesc("gufi_package"),
|
|
949
|
-
inputSchema: {
|
|
950
|
-
type: "object",
|
|
951
|
-
properties: {
|
|
952
|
-
action: { type: "string", description: "Action: list, get, create, delete, add_module, remove_module, publish" },
|
|
953
|
-
id: { type: "string", description: "Package ID (for get, delete, add_module, remove_module, publish)" },
|
|
954
|
-
name: { type: "string", description: "Package name (for create)" },
|
|
955
|
-
description: { type: "string", description: "Package description (for create)" },
|
|
956
|
-
module_id: { type: "string", description: "Module ID (for add_module, remove_module)" },
|
|
957
|
-
company_id: { type: "string", description: "Source company ID (for add_module)" },
|
|
958
|
-
env: ENV_PARAM,
|
|
959
|
-
},
|
|
960
|
-
required: ["action"],
|
|
961
|
-
},
|
|
962
|
-
},
|
|
949
|
+
// gufi_package → Re-enable when marketplace packages become priority
|
|
963
950
|
];
|
|
964
951
|
// ════════════════════════════════════════════════════════════════════════════
|
|
965
952
|
// Tool Handlers
|
|
@@ -1469,9 +1456,9 @@ const toolHandlers = {
|
|
|
1469
1456
|
let tableName = null;
|
|
1470
1457
|
// Resolve entity if provided (optional for standalone scripts)
|
|
1471
1458
|
if (entity) {
|
|
1472
|
-
const schema = await getCompanySchema(company_id, env);
|
|
1459
|
+
const { schema, error } = await getCompanySchema(company_id, env);
|
|
1473
1460
|
if (!schema?.modules) {
|
|
1474
|
-
throw new Error(
|
|
1461
|
+
throw new Error(`Cannot get schema: ${error || "unknown error"}`);
|
|
1475
1462
|
}
|
|
1476
1463
|
// Parse entity (module.entity format)
|
|
1477
1464
|
const parts = entity.split(".");
|
|
@@ -1482,13 +1469,13 @@ const toolHandlers = {
|
|
|
1482
1469
|
// Find module and entity IDs
|
|
1483
1470
|
for (const mod of schema.modules) {
|
|
1484
1471
|
const modMatch = mod.name?.toLowerCase() === moduleName.toLowerCase() ||
|
|
1485
|
-
mod.
|
|
1472
|
+
mod.display_name?.toLowerCase() === moduleName.toLowerCase();
|
|
1486
1473
|
if (!modMatch)
|
|
1487
1474
|
continue;
|
|
1488
1475
|
moduleId = mod.id;
|
|
1489
1476
|
for (const ent of mod.entities || []) {
|
|
1490
1477
|
const entMatch = ent.name?.toLowerCase() === entityName.toLowerCase() ||
|
|
1491
|
-
ent.
|
|
1478
|
+
ent.display_name?.toLowerCase() === entityName.toLowerCase();
|
|
1492
1479
|
if (entMatch) {
|
|
1493
1480
|
tableId = ent.id;
|
|
1494
1481
|
tableName = `m${moduleId}_t${tableId}`;
|
|
@@ -1801,7 +1788,9 @@ const toolHandlers = {
|
|
|
1801
1788
|
// ─────────────────────────────────────────────────────────────────────────
|
|
1802
1789
|
async gufi_view_pull(params) {
|
|
1803
1790
|
const viewId = params.view_id;
|
|
1804
|
-
const companyId = params.company_id;
|
|
1791
|
+
const companyId = params.company_id != null ? String(params.company_id) : undefined;
|
|
1792
|
+
if (!companyId)
|
|
1793
|
+
throw new Error("company_id is required for view pull");
|
|
1805
1794
|
const env = params.env;
|
|
1806
1795
|
const useLocal = canWriteLocal();
|
|
1807
1796
|
// Get view info
|
|
@@ -1814,9 +1803,14 @@ const toolHandlers = {
|
|
|
1814
1803
|
const filesResponse = await apiRequest(`/api/marketplace/views/${viewId}/files`, {}, companyId, true, env);
|
|
1815
1804
|
const files = Array.isArray(filesResponse) ? filesResponse : (filesResponse.data || []);
|
|
1816
1805
|
if (useLocal) {
|
|
1817
|
-
// 💜 CLI: Save to ~/gufi-dev/view_<id>/
|
|
1818
|
-
const viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
|
|
1806
|
+
// 💜 CLI: Save to ~/gufi-dev/company_<id>/view_<id>/
|
|
1807
|
+
const viewDir = path.join(LOCAL_VIEWS_DIR, `company_${companyId}`, `view_${viewId}`);
|
|
1819
1808
|
fs.mkdirSync(viewDir, { recursive: true });
|
|
1809
|
+
// 💜 Migrate: if old path exists (~/gufi-dev/view_<id>/), remove it
|
|
1810
|
+
const oldViewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
|
|
1811
|
+
if (fs.existsSync(oldViewDir)) {
|
|
1812
|
+
fs.rmSync(oldViewDir, { recursive: true, force: true });
|
|
1813
|
+
}
|
|
1820
1814
|
// 💜 Get latest snapshot for version tracking
|
|
1821
1815
|
let latestSnapshot;
|
|
1822
1816
|
try {
|
|
@@ -1839,9 +1833,10 @@ const toolHandlers = {
|
|
|
1839
1833
|
const meta = {
|
|
1840
1834
|
viewId,
|
|
1841
1835
|
viewName: `view_${viewId}`,
|
|
1836
|
+
company_id: Number(companyId),
|
|
1842
1837
|
packageId: view.package_id || 0,
|
|
1843
1838
|
lastSync: new Date().toISOString(),
|
|
1844
|
-
lastPulledSnapshot: latestSnapshot,
|
|
1839
|
+
lastPulledSnapshot: latestSnapshot,
|
|
1845
1840
|
files: fileMeta,
|
|
1846
1841
|
};
|
|
1847
1842
|
fs.writeFileSync(path.join(viewDir, ".gufi-view.json"), JSON.stringify(meta, null, 2));
|
|
@@ -1853,14 +1848,23 @@ const toolHandlers = {
|
|
|
1853
1848
|
local_path: viewDir,
|
|
1854
1849
|
storage: "local",
|
|
1855
1850
|
files_count: files.length,
|
|
1856
|
-
_hint: `📥 View downloaded to ${viewDir}/. Use Read/Edit tools to modify files. Then gufi_view_push({ view_id: ${viewId},
|
|
1851
|
+
_hint: `📥 View downloaded to ${viewDir}/. Use Read/Edit tools to modify files. Then gufi_view_push({ view_id: ${viewId}, company_id: '${companyId}' }) to upload.`,
|
|
1857
1852
|
};
|
|
1858
1853
|
}
|
|
1859
1854
|
else {
|
|
1860
1855
|
// 💜 Web: Save to Claude Workspace BD
|
|
1856
|
+
// Get latest snapshot for version tracking
|
|
1857
|
+
let latestSnapshot;
|
|
1858
|
+
try {
|
|
1859
|
+
const snapshotResp = await apiRequest(`/api/marketplace/views/${viewId}/latest-snapshot`, {}, companyId, true, env);
|
|
1860
|
+
latestSnapshot = snapshotResp.latest_snapshot;
|
|
1861
|
+
}
|
|
1862
|
+
catch {
|
|
1863
|
+
// If endpoint not available, continue without snapshot tracking
|
|
1864
|
+
}
|
|
1861
1865
|
const saveResponse = await apiRequest(`/api/claude/workspace/view`, {
|
|
1862
1866
|
method: "POST",
|
|
1863
|
-
body: JSON.stringify({ view_id: viewId, files }),
|
|
1867
|
+
body: JSON.stringify({ view_id: viewId, files, snapshot: latestSnapshot, company_id: companyId }),
|
|
1864
1868
|
}, companyId, true, env);
|
|
1865
1869
|
const saveResult = saveResponse.data || saveResponse;
|
|
1866
1870
|
const viewFolder = saveResult?.folder || `views/view_${viewId}`;
|
|
@@ -1872,26 +1876,65 @@ const toolHandlers = {
|
|
|
1872
1876
|
local_path: `~/workspace/${viewFolder}`,
|
|
1873
1877
|
storage: "workspace",
|
|
1874
1878
|
files_count: files.length,
|
|
1875
|
-
_hint: `📥 View downloaded to Claude Workspace. Use Read/Edit tools to modify files. Then gufi_view_push({ view_id: ${viewId} }) to upload.`,
|
|
1879
|
+
_hint: `📥 View downloaded to Claude Workspace. Use Read/Edit tools to modify files. Then gufi_view_push({ view_id: ${viewId}, company_id: '${companyId}' }) to upload.`,
|
|
1876
1880
|
};
|
|
1877
1881
|
}
|
|
1878
1882
|
},
|
|
1879
1883
|
async gufi_view_push(params) {
|
|
1880
1884
|
const viewId = params.view_id;
|
|
1885
|
+
let companyId = params.company_id != null ? String(params.company_id) : undefined;
|
|
1881
1886
|
const env = params.env;
|
|
1882
1887
|
const useLocal = canWriteLocal();
|
|
1883
1888
|
if (!viewId) {
|
|
1884
1889
|
throw new Error("view_id is required");
|
|
1885
1890
|
}
|
|
1891
|
+
// 💜 Try to get company_id from view metadata if not provided
|
|
1892
|
+
if (!companyId && useLocal) {
|
|
1893
|
+
// Try new path first (company_*/view_*)
|
|
1894
|
+
const companyDirs = fs.existsSync(LOCAL_VIEWS_DIR)
|
|
1895
|
+
? fs.readdirSync(LOCAL_VIEWS_DIR).filter(d => d.startsWith("company_"))
|
|
1896
|
+
: [];
|
|
1897
|
+
for (const cd of companyDirs) {
|
|
1898
|
+
const metaPath = path.join(LOCAL_VIEWS_DIR, cd, `view_${viewId}`, ".gufi-view.json");
|
|
1899
|
+
if (fs.existsSync(metaPath)) {
|
|
1900
|
+
try {
|
|
1901
|
+
const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
1902
|
+
if (meta.company_id)
|
|
1903
|
+
companyId = String(meta.company_id);
|
|
1904
|
+
}
|
|
1905
|
+
catch { /* ignore */ }
|
|
1906
|
+
break;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
// Fallback: old path (view_*)
|
|
1910
|
+
if (!companyId) {
|
|
1911
|
+
const oldMetaPath = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`, ".gufi-view.json");
|
|
1912
|
+
if (fs.existsSync(oldMetaPath)) {
|
|
1913
|
+
try {
|
|
1914
|
+
const meta = JSON.parse(fs.readFileSync(oldMetaPath, "utf-8"));
|
|
1915
|
+
if (meta.company_id)
|
|
1916
|
+
companyId = String(meta.company_id);
|
|
1917
|
+
}
|
|
1918
|
+
catch { /* ignore */ }
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
if (!companyId) {
|
|
1923
|
+
throw new Error("company_id is required. Pass it as parameter or pull the view first.");
|
|
1924
|
+
}
|
|
1886
1925
|
let files = [];
|
|
1887
|
-
let lastPulledSnapshot;
|
|
1926
|
+
let lastPulledSnapshot;
|
|
1888
1927
|
if (useLocal) {
|
|
1889
|
-
// 💜 CLI: Read from ~/gufi-dev/view_<id>/
|
|
1890
|
-
|
|
1928
|
+
// 💜 CLI: Read from ~/gufi-dev/company_<id>/view_<id>/ (or legacy ~/gufi-dev/view_<id>/)
|
|
1929
|
+
let viewDir = path.join(LOCAL_VIEWS_DIR, `company_${companyId}`, `view_${viewId}`);
|
|
1891
1930
|
if (!fs.existsSync(viewDir)) {
|
|
1892
|
-
|
|
1931
|
+
// Fallback to old path
|
|
1932
|
+
viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
|
|
1893
1933
|
}
|
|
1894
|
-
|
|
1934
|
+
if (!fs.existsSync(viewDir)) {
|
|
1935
|
+
throw new Error(`View directory not found. Run gufi_view_pull({ view_id: ${viewId}, company_id: '${companyId}' }) first.`);
|
|
1936
|
+
}
|
|
1937
|
+
// 💜 Read metadata for version tracking
|
|
1895
1938
|
const metaPath = path.join(viewDir, ".gufi-view.json");
|
|
1896
1939
|
if (fs.existsSync(metaPath)) {
|
|
1897
1940
|
try {
|
|
@@ -1933,13 +1976,26 @@ const toolHandlers = {
|
|
|
1933
1976
|
}
|
|
1934
1977
|
else {
|
|
1935
1978
|
// 💜 Web: Read from Claude Workspace BD
|
|
1936
|
-
const workspaceResponse = await apiRequest(`/api/claude/workspace/view/${viewId}/files`, {},
|
|
1979
|
+
const workspaceResponse = await apiRequest(`/api/claude/workspace/view/${viewId}/files`, {}, companyId, true, env);
|
|
1937
1980
|
files = workspaceResponse.data || workspaceResponse || [];
|
|
1981
|
+
// 💜 Also read metadata for version tracking
|
|
1982
|
+
try {
|
|
1983
|
+
const metaResponse = await apiRequest(`/api/claude/workspace/view/${viewId}/meta`, {}, companyId, true, env);
|
|
1984
|
+
// sendData wraps response in { data: [...] } format
|
|
1985
|
+
const meta = metaResponse.data?.[0] || metaResponse;
|
|
1986
|
+
lastPulledSnapshot = meta.lastPulledSnapshot;
|
|
1987
|
+
if (!companyId && meta.company_id) {
|
|
1988
|
+
companyId = String(meta.company_id);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
catch {
|
|
1992
|
+
// Metadata not found - view wasn't pulled through workspace
|
|
1993
|
+
}
|
|
1938
1994
|
}
|
|
1939
1995
|
// 💜 VERSION CHECK: Always verify before push (don't rely on backend alone)
|
|
1940
1996
|
// This prevents overwriting changes from other developers
|
|
1941
1997
|
try {
|
|
1942
|
-
const snapshotResp = await apiRequest(`/api/marketplace/views/${viewId}/latest-snapshot`, {},
|
|
1998
|
+
const snapshotResp = await apiRequest(`/api/marketplace/views/${viewId}/latest-snapshot`, {}, companyId, true, env);
|
|
1943
1999
|
const serverSnapshot = snapshotResp.latest_snapshot;
|
|
1944
2000
|
// If server has versions but we don't have a local snapshot → conflict
|
|
1945
2001
|
// (means we pulled with an old CLI that didn't track versions)
|
|
@@ -1981,7 +2037,7 @@ const toolHandlers = {
|
|
|
1981
2037
|
result = await apiRequest(`/api/marketplace/views/${viewId}/files/bulk`, {
|
|
1982
2038
|
method: "POST",
|
|
1983
2039
|
body: JSON.stringify({ files, message: params.message, sync: true, lastPulledSnapshot }),
|
|
1984
|
-
},
|
|
2040
|
+
}, companyId, true, env);
|
|
1985
2041
|
}
|
|
1986
2042
|
catch (err) {
|
|
1987
2043
|
// 💜 Handle version conflict from backend
|
|
@@ -1999,7 +2055,9 @@ const toolHandlers = {
|
|
|
1999
2055
|
}
|
|
2000
2056
|
// 💜 Update local metadata with new snapshot number (for version tracking)
|
|
2001
2057
|
if (useLocal && result.snapshot) {
|
|
2002
|
-
|
|
2058
|
+
let viewDir = path.join(LOCAL_VIEWS_DIR, `company_${companyId}`, `view_${viewId}`);
|
|
2059
|
+
if (!fs.existsSync(viewDir))
|
|
2060
|
+
viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
|
|
2003
2061
|
const metaPath = path.join(viewDir, ".gufi-view.json");
|
|
2004
2062
|
if (fs.existsSync(metaPath)) {
|
|
2005
2063
|
try {
|
|
@@ -2015,11 +2073,36 @@ const toolHandlers = {
|
|
|
2015
2073
|
}
|
|
2016
2074
|
// Get view info for package
|
|
2017
2075
|
let packageInfo = null;
|
|
2018
|
-
const viewResponse = await apiRequest(`/api/marketplace/views/${viewId}`, {},
|
|
2076
|
+
const viewResponse = await apiRequest(`/api/marketplace/views/${viewId}`, {}, companyId, true, env);
|
|
2019
2077
|
const view = viewResponse.data || viewResponse;
|
|
2020
2078
|
if (view?.package_id) {
|
|
2021
2079
|
packageInfo = { id: view.package_id, publish_cmd: `gufi package:publish ${view.package_id}` };
|
|
2022
2080
|
}
|
|
2081
|
+
// 💜 Extract and save publicAutomations from core/automations.ts
|
|
2082
|
+
const automationsFile = files.find(f => f.file_path === '/core/automations.ts' || f.file_path === 'core/automations.ts');
|
|
2083
|
+
if (automationsFile && view?.company_id && view?.entity_id) {
|
|
2084
|
+
try {
|
|
2085
|
+
// Parse publicAutomations from the file content
|
|
2086
|
+
const content = automationsFile.content;
|
|
2087
|
+
const publicMatch = content.match(/export\s+const\s+publicAutomations\s*=\s*\[([\s\S]*?)\]/);
|
|
2088
|
+
if (publicMatch) {
|
|
2089
|
+
// Extract string values from the array
|
|
2090
|
+
const arrContent = publicMatch[1];
|
|
2091
|
+
const publicAutomations = [...arrContent.matchAll(/['"]([^'"]+)['"]/g)].map(m => m[1]);
|
|
2092
|
+
if (publicAutomations.length > 0) {
|
|
2093
|
+
// Update entity config with publicAutomations
|
|
2094
|
+
await apiRequest(`/api/entities/${view.entity_id}/config`, {
|
|
2095
|
+
method: "PATCH",
|
|
2096
|
+
body: JSON.stringify({ publicAutomations }),
|
|
2097
|
+
}, String(view.company_id), true, env);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
catch (err) {
|
|
2102
|
+
// Non-fatal: log but continue
|
|
2103
|
+
console.error("Warning: Could not update publicAutomations:", err);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2023
2106
|
// Build response
|
|
2024
2107
|
const response = {
|
|
2025
2108
|
success: true,
|
|
@@ -2512,7 +2595,7 @@ function findTableInModulesMcp(modules, tableName) {
|
|
|
2512
2595
|
fields: (ent.fields || []).map((f) => ({
|
|
2513
2596
|
name: f.name,
|
|
2514
2597
|
type: f.type,
|
|
2515
|
-
|
|
2598
|
+
display_name: f.display_name,
|
|
2516
2599
|
required: f.required || false,
|
|
2517
2600
|
options: f.options?.map((o) => o.value || o),
|
|
2518
2601
|
})),
|