gufi-cli 0.1.49 → 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.
@@ -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
- console.error(`[MCP] Failed to get schema for company ${companyId}:`, err.message);
520
- return null;
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
- throw new Error(`Cannot resolve logical table name "${tableName}": schema not available. Use physical name (m123_t456) instead`);
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.label?.toLowerCase() === moduleName.toLowerCase();
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.label?.toLowerCase() === entityName.toLowerCase();
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 for company-specific views)" },
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
@@ -1453,9 +1456,9 @@ const toolHandlers = {
1453
1456
  let tableName = null;
1454
1457
  // Resolve entity if provided (optional for standalone scripts)
1455
1458
  if (entity) {
1456
- const schema = await getCompanySchema(company_id, env);
1459
+ const { schema, error } = await getCompanySchema(company_id, env);
1457
1460
  if (!schema?.modules) {
1458
- throw new Error("Cannot get schema. Make sure company_id is correct.");
1461
+ throw new Error(`Cannot get schema: ${error || "unknown error"}`);
1459
1462
  }
1460
1463
  // Parse entity (module.entity format)
1461
1464
  const parts = entity.split(".");
@@ -1466,13 +1469,13 @@ const toolHandlers = {
1466
1469
  // Find module and entity IDs
1467
1470
  for (const mod of schema.modules) {
1468
1471
  const modMatch = mod.name?.toLowerCase() === moduleName.toLowerCase() ||
1469
- mod.label?.toLowerCase() === moduleName.toLowerCase();
1472
+ mod.display_name?.toLowerCase() === moduleName.toLowerCase();
1470
1473
  if (!modMatch)
1471
1474
  continue;
1472
1475
  moduleId = mod.id;
1473
1476
  for (const ent of mod.entities || []) {
1474
1477
  const entMatch = ent.name?.toLowerCase() === entityName.toLowerCase() ||
1475
- ent.label?.toLowerCase() === entityName.toLowerCase();
1478
+ ent.display_name?.toLowerCase() === entityName.toLowerCase();
1476
1479
  if (entMatch) {
1477
1480
  tableId = ent.id;
1478
1481
  tableName = `m${moduleId}_t${tableId}`;
@@ -1785,7 +1788,9 @@ const toolHandlers = {
1785
1788
  // ─────────────────────────────────────────────────────────────────────────
1786
1789
  async gufi_view_pull(params) {
1787
1790
  const viewId = params.view_id;
1788
- 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");
1789
1794
  const env = params.env;
1790
1795
  const useLocal = canWriteLocal();
1791
1796
  // Get view info
@@ -1798,9 +1803,14 @@ const toolHandlers = {
1798
1803
  const filesResponse = await apiRequest(`/api/marketplace/views/${viewId}/files`, {}, companyId, true, env);
1799
1804
  const files = Array.isArray(filesResponse) ? filesResponse : (filesResponse.data || []);
1800
1805
  if (useLocal) {
1801
- // 💜 CLI: Save to ~/gufi-dev/view_<id>/
1802
- 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}`);
1803
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
+ }
1804
1814
  // 💜 Get latest snapshot for version tracking
1805
1815
  let latestSnapshot;
1806
1816
  try {
@@ -1823,9 +1833,10 @@ const toolHandlers = {
1823
1833
  const meta = {
1824
1834
  viewId,
1825
1835
  viewName: `view_${viewId}`,
1836
+ company_id: Number(companyId),
1826
1837
  packageId: view.package_id || 0,
1827
1838
  lastSync: new Date().toISOString(),
1828
- lastPulledSnapshot: latestSnapshot, // 💜 For version conflict detection
1839
+ lastPulledSnapshot: latestSnapshot,
1829
1840
  files: fileMeta,
1830
1841
  };
1831
1842
  fs.writeFileSync(path.join(viewDir, ".gufi-view.json"), JSON.stringify(meta, null, 2));
@@ -1837,7 +1848,7 @@ const toolHandlers = {
1837
1848
  local_path: viewDir,
1838
1849
  storage: "local",
1839
1850
  files_count: files.length,
1840
- _hint: `📥 View downloaded to ${viewDir}/. Use Read/Edit tools to modify files. Then gufi_view_push({ view_id: ${viewId}, env: '${env || 'prod'}' }) to upload.`,
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.`,
1841
1852
  };
1842
1853
  }
1843
1854
  else {
@@ -1871,33 +1882,59 @@ const toolHandlers = {
1871
1882
  },
1872
1883
  async gufi_view_push(params) {
1873
1884
  const viewId = params.view_id;
1874
- let companyId = params.company_id;
1885
+ let companyId = params.company_id != null ? String(params.company_id) : undefined;
1875
1886
  const env = params.env;
1876
1887
  const useLocal = canWriteLocal();
1888
+ if (!viewId) {
1889
+ throw new Error("view_id is required");
1890
+ }
1877
1891
  // 💜 Try to get company_id from view metadata if not provided
1878
- if (!companyId && viewId && useLocal) {
1879
- const metaPath = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`, ".gufi-view.json");
1880
- if (fs.existsSync(metaPath)) {
1881
- try {
1882
- const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
1883
- if (meta.company_id)
1884
- companyId = String(meta.company_id);
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 */ }
1885
1919
  }
1886
- catch { /* ignore */ }
1887
1920
  }
1888
1921
  }
1889
- if (!viewId) {
1890
- throw new Error("view_id is required");
1922
+ if (!companyId) {
1923
+ throw new Error("company_id is required. Pass it as parameter or pull the view first.");
1891
1924
  }
1892
1925
  let files = [];
1893
- let lastPulledSnapshot; // 💜 For version conflict detection
1926
+ let lastPulledSnapshot;
1894
1927
  if (useLocal) {
1895
- // 💜 CLI: Read from ~/gufi-dev/view_<id>/
1896
- const viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
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}`);
1930
+ if (!fs.existsSync(viewDir)) {
1931
+ // Fallback to old path
1932
+ viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
1933
+ }
1897
1934
  if (!fs.existsSync(viewDir)) {
1898
- throw new Error(`View directory not found: ${viewDir}. Run gufi_view_pull first.`);
1935
+ throw new Error(`View directory not found. Run gufi_view_pull({ view_id: ${viewId}, company_id: '${companyId}' }) first.`);
1899
1936
  }
1900
- // 💜 Read metadata for version tracking (backend handles the check)
1937
+ // 💜 Read metadata for version tracking
1901
1938
  const metaPath = path.join(viewDir, ".gufi-view.json");
1902
1939
  if (fs.existsSync(metaPath)) {
1903
1940
  try {
@@ -2018,7 +2055,9 @@ const toolHandlers = {
2018
2055
  }
2019
2056
  // 💜 Update local metadata with new snapshot number (for version tracking)
2020
2057
  if (useLocal && result.snapshot) {
2021
- const viewDir = path.join(LOCAL_VIEWS_DIR, `view_${viewId}`);
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}`);
2022
2061
  const metaPath = path.join(viewDir, ".gufi-view.json");
2023
2062
  if (fs.existsSync(metaPath)) {
2024
2063
  try {
@@ -2556,7 +2595,7 @@ function findTableInModulesMcp(modules, tableName) {
2556
2595
  fields: (ent.fields || []).map((f) => ({
2557
2596
  name: f.name,
2558
2597
  type: f.type,
2559
- label: f.label,
2598
+ display_name: f.display_name,
2560
2599
  required: f.required || false,
2561
2600
  options: f.options?.map((o) => o.value || o),
2562
2601
  })),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gufi-cli",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "CLI for developing Gufi Marketplace views locally with Claude Code",
5
5
  "bin": {
6
6
  "gufi": "./bin/gufi.js"