@leanmcp/cli 0.5.7 → 0.5.8

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.
Files changed (2) hide show
  1. package/dist/index.js +165 -113
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/index.ts
5
5
  import { Command } from "commander";
6
- import fs12 from "fs-extra";
7
- import path12 from "path";
6
+ import fs13 from "fs-extra";
7
+ import path13 from "path";
8
8
  import ora9 from "ora";
9
9
  import { createRequire } from "module";
10
10
  import { confirm as confirm4 } from "@inquirer/prompts";
@@ -13,8 +13,8 @@ import { spawn as spawn4 } from "child_process";
13
13
  // src/commands/dev.ts
14
14
  import { spawn } from "child_process";
15
15
  import ora from "ora";
16
- import path3 from "path";
17
- import fs3 from "fs-extra";
16
+ import path4 from "path";
17
+ import fs4 from "fs-extra";
18
18
  import crypto2 from "crypto";
19
19
  import chokidar from "chokidar";
20
20
 
@@ -471,6 +471,8 @@ __name(deleteUIComponent, "deleteUIComponent");
471
471
  import chalk from "chalk";
472
472
  import os from "os";
473
473
  import crypto from "crypto";
474
+ import path3 from "path";
475
+ import fs3 from "fs-extra";
474
476
  import { execSync } from "child_process";
475
477
  var POSTHOG_API_KEY = "phc_EoMHKFbx6j2wUFsf8ywqgHntY4vEXC3ZzLFoPJVjRRT";
476
478
  var POSTHOG_API_HOST = "https://d18m0xvdtnkibr.cloudfront.net";
@@ -568,12 +570,40 @@ var sendToPostHog = /* @__PURE__ */ __name((eventName, properties = {}) => {
568
570
  }
569
571
  });
570
572
  }, "sendToPostHog");
573
+ var LOG_DIR = path3.join(os.homedir(), ".leanmcp", "logs");
574
+ try {
575
+ fs3.ensureDirSync(LOG_DIR);
576
+ } catch (err) {
577
+ }
578
+ function getTimestamp() {
579
+ return (/* @__PURE__ */ new Date()).toISOString();
580
+ }
581
+ __name(getTimestamp, "getTimestamp");
582
+ function getLogFilePath() {
583
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
584
+ return path3.join(LOG_DIR, `cli-${date}.log`);
585
+ }
586
+ __name(getLogFilePath, "getLogFilePath");
587
+ function redactSensitive(text) {
588
+ if (!text) return text;
589
+ return text.replace(/(leanmcp_|airtain_)[a-zA-Z0-9]{20,}/g, "$1********************");
590
+ }
591
+ __name(redactSensitive, "redactSensitive");
571
592
  var LoggerClass = class LoggerClass2 {
572
593
  static {
573
594
  __name(this, "LoggerClass");
574
595
  }
596
+ writeToFile(level, message) {
597
+ try {
598
+ const timestamp = getTimestamp();
599
+ const logLine = `[${timestamp}] [${level.toUpperCase()}] ${redactSensitive(message)}
600
+ `;
601
+ fs3.appendFileSync(getLogFilePath(), logLine);
602
+ } catch (err) {
603
+ }
604
+ }
575
605
  /**
576
- * Log a message to console and send cli_log event to PostHog
606
+ * Log a message to console, file, and send cli_log event to PostHog
577
607
  * @param text - The text to log
578
608
  * @param styleFn - Optional chalk style function (e.g., chalk.cyan, chalk.green)
579
609
  */
@@ -583,32 +613,35 @@ var LoggerClass = class LoggerClass2 {
583
613
  } else {
584
614
  console.log(text);
585
615
  }
616
+ this.writeToFile("log", text);
586
617
  sendToPostHog("cli_log", {
587
618
  message: text,
588
619
  level: "log"
589
620
  });
590
621
  }
591
622
  /**
592
- * Log a warning to console and send cli_warn event to PostHog
623
+ * Log a warning to console, file, and send cli_warn event to PostHog
593
624
  * @param text - The warning text
594
625
  * @param styleFn - Optional chalk style function (defaults to chalk.yellow)
595
626
  */
596
627
  warn(text, styleFn) {
597
628
  const style = styleFn || chalk.yellow;
598
629
  console.log(style(text));
630
+ this.writeToFile("warn", text);
599
631
  sendToPostHog("cli_warn", {
600
632
  message: text,
601
633
  level: "warn"
602
634
  });
603
635
  }
604
636
  /**
605
- * Log an error to console and send cli_error event to PostHog
637
+ * Log an error to console, file, and send cli_error event to PostHog
606
638
  * @param text - The error text
607
639
  * @param styleFn - Optional chalk style function (defaults to chalk.red)
608
640
  */
609
641
  error(text, styleFn) {
610
642
  const style = styleFn || chalk.red;
611
643
  console.error(style(text));
644
+ this.writeToFile("error", text);
612
645
  sendToPostHog("cli_error", {
613
646
  message: text,
614
647
  level: "error"
@@ -620,6 +653,7 @@ var LoggerClass = class LoggerClass2 {
620
653
  */
621
654
  info(text) {
622
655
  console.log(chalk.cyan(text));
656
+ this.writeToFile("info", text);
623
657
  sendToPostHog("cli_log", {
624
658
  message: text,
625
659
  level: "info"
@@ -631,6 +665,7 @@ var LoggerClass = class LoggerClass2 {
631
665
  */
632
666
  success(text) {
633
667
  console.log(chalk.green(text));
668
+ this.writeToFile("success", text);
634
669
  sendToPostHog("cli_log", {
635
670
  message: text,
636
671
  level: "success"
@@ -642,6 +677,7 @@ var LoggerClass = class LoggerClass2 {
642
677
  */
643
678
  gray(text) {
644
679
  console.log(chalk.gray(text));
680
+ this.writeToFile("debug", text);
645
681
  sendToPostHog("cli_log", {
646
682
  message: text,
647
683
  level: "gray"
@@ -658,7 +694,7 @@ var trackCommand = /* @__PURE__ */ __name((command, options = {}) => {
658
694
 
659
695
  // src/commands/dev.ts
660
696
  function computeHash(filePath) {
661
- const content = fs3.readFileSync(filePath, "utf-8");
697
+ const content = fs4.readFileSync(filePath, "utf-8");
662
698
  return crypto2.createHash("md5").update(content).digest("hex");
663
699
  }
664
700
  __name(computeHash, "computeHash");
@@ -675,7 +711,7 @@ function computeDiff(previousUIApps, currentUIApps, hashCache) {
675
711
  } else {
676
712
  const oldHash = hashCache.get(app.resourceUri);
677
713
  let newHash;
678
- if (fs3.existsSync(app.componentPath)) {
714
+ if (fs4.existsSync(app.componentPath)) {
679
715
  newHash = computeHash(app.componentPath);
680
716
  }
681
717
  if (oldHash !== newHash) {
@@ -692,7 +728,7 @@ function computeDiff(previousUIApps, currentUIApps, hashCache) {
692
728
  __name(computeDiff, "computeDiff");
693
729
  async function devCommand() {
694
730
  const cwd = process.cwd();
695
- if (!await fs3.pathExists(path3.join(cwd, "main.ts"))) {
731
+ if (!await fs4.pathExists(path4.join(cwd, "main.ts"))) {
696
732
  logger.error("ERROR: Not a LeanMCP project (main.ts not found).");
697
733
  logger.gray("Run this command from your project root.");
698
734
  process.exit(1);
@@ -748,12 +784,12 @@ async function devCommand() {
748
784
  let watcher = null;
749
785
  const componentHashCache = /* @__PURE__ */ new Map();
750
786
  for (const app of uiApps) {
751
- if (await fs3.pathExists(app.componentPath)) {
787
+ if (await fs4.pathExists(app.componentPath)) {
752
788
  componentHashCache.set(app.resourceUri, computeHash(app.componentPath));
753
789
  }
754
790
  }
755
791
  let previousUIApps = uiApps;
756
- const mcpPath = path3.join(cwd, "mcp");
792
+ const mcpPath = path4.join(cwd, "mcp");
757
793
  watcher = chokidar.watch(mcpPath, {
758
794
  ignoreInitial: true,
759
795
  ignored: [
@@ -795,7 +831,7 @@ async function devCommand() {
795
831
  } else {
796
832
  manifest[app.resourceUri] = result.htmlPath;
797
833
  }
798
- if (await fs3.pathExists(app.componentPath)) {
834
+ if (await fs4.pathExists(app.componentPath)) {
799
835
  componentHashCache.set(app.resourceUri, computeHash(app.componentPath));
800
836
  }
801
837
  logger.success(`${app.componentName} ${action.toLowerCase()} complete`);
@@ -841,12 +877,12 @@ __name(devCommand, "devCommand");
841
877
  // src/commands/build.ts
842
878
  import { spawn as spawn2 } from "child_process";
843
879
  import ora2 from "ora";
844
- import path5 from "path";
845
- import fs5 from "fs-extra";
880
+ import path6 from "path";
881
+ import fs6 from "fs-extra";
846
882
 
847
883
  // src/schema-extractor.ts
848
- import path4 from "path";
849
- import fs4 from "fs-extra";
884
+ import path5 from "path";
885
+ import fs5 from "fs-extra";
850
886
  import { Project, Node } from "ts-morph";
851
887
  async function generateSchemaMetadata(projectDir) {
852
888
  const metadata = {};
@@ -921,9 +957,9 @@ async function generateSchemaMetadata(projectDir) {
921
957
  }
922
958
  processedClasses.add(className);
923
959
  }
924
- const outputPath = path4.join(projectDir, "dist", "schema-metadata.json");
925
- await fs4.ensureDir(path4.dirname(outputPath));
926
- await fs4.writeJSON(outputPath, metadata, {
960
+ const outputPath = path5.join(projectDir, "dist", "schema-metadata.json");
961
+ await fs5.ensureDir(path5.dirname(outputPath));
962
+ await fs5.writeJSON(outputPath, metadata, {
927
963
  spaces: 2
928
964
  });
929
965
  }
@@ -958,11 +994,11 @@ __name(extractBaseClassName, "extractBaseClassName");
958
994
  async function findTsFiles(dir) {
959
995
  const files = [];
960
996
  async function scan(currentDir) {
961
- const entries = await fs4.readdir(currentDir, {
997
+ const entries = await fs5.readdir(currentDir, {
962
998
  withFileTypes: true
963
999
  });
964
1000
  for (const entry of entries) {
965
- const fullPath = path4.join(currentDir, entry.name);
1001
+ const fullPath = path5.join(currentDir, entry.name);
966
1002
  if (entry.isDirectory()) {
967
1003
  if ([
968
1004
  "node_modules",
@@ -1028,7 +1064,7 @@ __name(mapPrimitiveType, "mapPrimitiveType");
1028
1064
  // src/commands/build.ts
1029
1065
  async function buildCommand() {
1030
1066
  const cwd = process.cwd();
1031
- if (!await fs5.pathExists(path5.join(cwd, "main.ts"))) {
1067
+ if (!await fs6.pathExists(path6.join(cwd, "main.ts"))) {
1032
1068
  logger.error("ERROR: Not a LeanMCP project (main.ts not found).");
1033
1069
  logger.gray("Run this command from your project root.");
1034
1070
  process.exit(1);
@@ -1110,11 +1146,11 @@ __name(buildCommand, "buildCommand");
1110
1146
  // src/commands/start.ts
1111
1147
  import { spawn as spawn3 } from "child_process";
1112
1148
  import ora3 from "ora";
1113
- import path6 from "path";
1114
- import fs6 from "fs-extra";
1149
+ import path7 from "path";
1150
+ import fs7 from "fs-extra";
1115
1151
  async function startCommand() {
1116
1152
  const cwd = process.cwd();
1117
- if (!await fs6.pathExists(path6.join(cwd, "main.ts"))) {
1153
+ if (!await fs7.pathExists(path7.join(cwd, "main.ts"))) {
1118
1154
  logger.error("ERROR: Not a LeanMCP project (main.ts not found).");
1119
1155
  logger.gray("Run this command from your project root.");
1120
1156
  process.exit(1);
@@ -1216,8 +1252,8 @@ __name(startCommand, "startCommand");
1216
1252
 
1217
1253
  // src/commands/login.ts
1218
1254
  import ora4 from "ora";
1219
- import path7 from "path";
1220
- import fs7 from "fs-extra";
1255
+ import path8 from "path";
1256
+ import fs8 from "fs-extra";
1221
1257
  import os2 from "os";
1222
1258
  import { input, confirm } from "@inquirer/prompts";
1223
1259
  var DEBUG_MODE2 = false;
@@ -1231,12 +1267,12 @@ function debug2(message, ...args) {
1231
1267
  }
1232
1268
  }
1233
1269
  __name(debug2, "debug");
1234
- var CONFIG_DIR = path7.join(os2.homedir(), ".leanmcp");
1235
- var CONFIG_FILE = path7.join(CONFIG_DIR, "config.json");
1270
+ var CONFIG_DIR = path8.join(os2.homedir(), ".leanmcp");
1271
+ var CONFIG_FILE = path8.join(CONFIG_DIR, "config.json");
1236
1272
  async function loadConfig() {
1237
1273
  try {
1238
- if (await fs7.pathExists(CONFIG_FILE)) {
1239
- return await fs7.readJSON(CONFIG_FILE);
1274
+ if (await fs8.pathExists(CONFIG_FILE)) {
1275
+ return await fs8.readJSON(CONFIG_FILE);
1240
1276
  }
1241
1277
  } catch (error) {
1242
1278
  }
@@ -1244,8 +1280,8 @@ async function loadConfig() {
1244
1280
  }
1245
1281
  __name(loadConfig, "loadConfig");
1246
1282
  async function saveConfig(config) {
1247
- await fs7.ensureDir(CONFIG_DIR);
1248
- await fs7.writeJSON(CONFIG_FILE, config, {
1283
+ await fs8.ensureDir(CONFIG_DIR);
1284
+ await fs8.writeJSON(CONFIG_FILE, config, {
1249
1285
  spaces: 2
1250
1286
  });
1251
1287
  }
@@ -1452,8 +1488,8 @@ __name(whoamiCommand, "whoamiCommand");
1452
1488
 
1453
1489
  // src/commands/deploy.ts
1454
1490
  import ora5 from "ora";
1455
- import path9 from "path";
1456
- import fs9 from "fs-extra";
1491
+ import path10 from "path";
1492
+ import fs10 from "fs-extra";
1457
1493
  import os3 from "os";
1458
1494
  import archiver from "archiver";
1459
1495
  import { input as input2, confirm as confirm2, select } from "@inquirer/prompts";
@@ -1636,8 +1672,8 @@ function generateProjectName() {
1636
1672
  __name(generateProjectName, "generateProjectName");
1637
1673
 
1638
1674
  // src/utils/env-parser.ts
1639
- import fs8 from "fs-extra";
1640
- import path8 from "path";
1675
+ import fs9 from "fs-extra";
1676
+ import path9 from "path";
1641
1677
  var RESERVED_ENV_KEYS = [
1642
1678
  "AWS_REGION",
1643
1679
  "AWS_ACCESS_KEY_ID",
@@ -1700,16 +1736,16 @@ function parseEnvFile(content) {
1700
1736
  }
1701
1737
  __name(parseEnvFile, "parseEnvFile");
1702
1738
  async function loadEnvFile(filePath) {
1703
- const absolutePath = path8.resolve(filePath);
1704
- if (!await fs8.pathExists(absolutePath)) {
1739
+ const absolutePath = path9.resolve(filePath);
1740
+ if (!await fs9.pathExists(absolutePath)) {
1705
1741
  throw new Error(`Env file not found: ${absolutePath}`);
1706
1742
  }
1707
- const content = await fs8.readFile(absolutePath, "utf-8");
1743
+ const content = await fs9.readFile(absolutePath, "utf-8");
1708
1744
  return parseEnvFile(content);
1709
1745
  }
1710
1746
  __name(loadEnvFile, "loadEnvFile");
1711
1747
  async function writeEnvFile(filePath, vars) {
1712
- const absolutePath = path8.resolve(filePath);
1748
+ const absolutePath = path9.resolve(filePath);
1713
1749
  const lines = [
1714
1750
  "# Environment variables",
1715
1751
  `# Generated by leanmcp CLI at ${(/* @__PURE__ */ new Date()).toISOString()}`,
@@ -1725,7 +1761,7 @@ async function writeEnvFile(filePath, vars) {
1725
1761
  }
1726
1762
  }
1727
1763
  lines.push("");
1728
- await fs8.writeFile(absolutePath, lines.join("\n"));
1764
+ await fs9.writeFile(absolutePath, lines.join("\n"));
1729
1765
  }
1730
1766
  __name(writeEnvFile, "writeEnvFile");
1731
1767
  function isValidEnvKey(key) {
@@ -1839,10 +1875,10 @@ var API_ENDPOINTS = {
1839
1875
  var LEANMCP_CONFIG_DIR = ".leanmcp";
1840
1876
  var LEANMCP_CONFIG_FILE = "config.json";
1841
1877
  async function readLeanMCPConfig(projectPath) {
1842
- const configPath = path9.join(projectPath, LEANMCP_CONFIG_DIR, LEANMCP_CONFIG_FILE);
1878
+ const configPath = path10.join(projectPath, LEANMCP_CONFIG_DIR, LEANMCP_CONFIG_FILE);
1843
1879
  try {
1844
- if (await fs9.pathExists(configPath)) {
1845
- const config = await fs9.readJSON(configPath);
1880
+ if (await fs10.pathExists(configPath)) {
1881
+ const config = await fs10.readJSON(configPath);
1846
1882
  debug3("Found existing .leanmcp config:", config);
1847
1883
  return config;
1848
1884
  }
@@ -1853,10 +1889,10 @@ async function readLeanMCPConfig(projectPath) {
1853
1889
  }
1854
1890
  __name(readLeanMCPConfig, "readLeanMCPConfig");
1855
1891
  async function writeLeanMCPConfig(projectPath, config) {
1856
- const configDir = path9.join(projectPath, LEANMCP_CONFIG_DIR);
1857
- const configPath = path9.join(configDir, LEANMCP_CONFIG_FILE);
1858
- await fs9.ensureDir(configDir);
1859
- await fs9.writeJSON(configPath, config, {
1892
+ const configDir = path10.join(projectPath, LEANMCP_CONFIG_DIR);
1893
+ const configPath = path10.join(configDir, LEANMCP_CONFIG_FILE);
1894
+ await fs10.ensureDir(configDir);
1895
+ await fs10.writeJSON(configPath, config, {
1860
1896
  spaces: 2
1861
1897
  });
1862
1898
  debug3("Saved .leanmcp config:", config);
@@ -1864,7 +1900,7 @@ async function writeLeanMCPConfig(projectPath, config) {
1864
1900
  __name(writeLeanMCPConfig, "writeLeanMCPConfig");
1865
1901
  async function createZipArchive(folderPath, outputPath) {
1866
1902
  return new Promise((resolve, reject) => {
1867
- const output = fs9.createWriteStream(outputPath);
1903
+ const output = fs10.createWriteStream(outputPath);
1868
1904
  const archive = archiver("zip", {
1869
1905
  zlib: {
1870
1906
  level: 9
@@ -1982,16 +2018,16 @@ async function deployCommand(folderPath, options = {}) {
1982
2018
  }
1983
2019
  const apiUrl = await getApiUrl();
1984
2020
  debug3("API URL:", apiUrl);
1985
- const absolutePath = path9.resolve(process.cwd(), folderPath);
1986
- if (!await fs9.pathExists(absolutePath)) {
2021
+ const absolutePath = path10.resolve(process.cwd(), folderPath);
2022
+ if (!await fs10.pathExists(absolutePath)) {
1987
2023
  logger.error(`Folder not found: ${absolutePath}`);
1988
2024
  process.exit(1);
1989
2025
  }
1990
- const hasMainTs = await fs9.pathExists(path9.join(absolutePath, "main.ts"));
1991
- const hasPackageJson = await fs9.pathExists(path9.join(absolutePath, "package.json"));
1992
- const hasMainPy = await fs9.pathExists(path9.join(absolutePath, "main.py"));
1993
- const hasRequirementsTxt = await fs9.pathExists(path9.join(absolutePath, "requirements.txt"));
1994
- const hasPyprojectToml = await fs9.pathExists(path9.join(absolutePath, "pyproject.toml"));
2026
+ const hasMainTs = await fs10.pathExists(path10.join(absolutePath, "main.ts"));
2027
+ const hasPackageJson = await fs10.pathExists(path10.join(absolutePath, "package.json"));
2028
+ const hasMainPy = await fs10.pathExists(path10.join(absolutePath, "main.py"));
2029
+ const hasRequirementsTxt = await fs10.pathExists(path10.join(absolutePath, "requirements.txt"));
2030
+ const hasPyprojectToml = await fs10.pathExists(path10.join(absolutePath, "pyproject.toml"));
1995
2031
  const isNodeProject = hasMainTs || hasPackageJson;
1996
2032
  const isPythonProject = hasMainPy || hasRequirementsTxt || hasPyprojectToml;
1997
2033
  if (!isNodeProject && !isPythonProject) {
@@ -2063,10 +2099,10 @@ Generated project name: ${chalk.bold(projectName)}
2063
2099
  } catch (e) {
2064
2100
  debug3("Could not fetch existing projects");
2065
2101
  }
2066
- let folderName = path9.basename(absolutePath);
2102
+ let folderName = path10.basename(absolutePath);
2067
2103
  if (hasPackageJson) {
2068
2104
  try {
2069
- const pkg2 = await fs9.readJSON(path9.join(absolutePath, "package.json"));
2105
+ const pkg2 = await fs10.readJSON(path10.join(absolutePath, "package.json"));
2070
2106
  folderName = pkg2.name || folderName;
2071
2107
  } catch (e) {
2072
2108
  }
@@ -2217,7 +2253,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2217
2253
  }
2218
2254
  const uploadSpinner = ora5("Packaging and uploading...").start();
2219
2255
  try {
2220
- const tempZip = path9.join(os3.tmpdir(), `leanmcp-${Date.now()}.zip`);
2256
+ const tempZip = path10.join(os3.tmpdir(), `leanmcp-${Date.now()}.zip`);
2221
2257
  const zipSize = await createZipArchive(absolutePath, tempZip);
2222
2258
  uploadSpinner.text = `Packaging... (${Math.round(zipSize / 1024)}KB)`;
2223
2259
  debug3("Step 2a: Getting upload URL for project:", projectId);
@@ -2244,7 +2280,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2244
2280
  throw new Error("Backend did not return upload URL");
2245
2281
  }
2246
2282
  debug3("Step 2b: Uploading to S3...");
2247
- const zipBuffer = await fs9.readFile(tempZip);
2283
+ const zipBuffer = await fs10.readFile(tempZip);
2248
2284
  const s3Response = await fetch(uploadUrl, {
2249
2285
  method: "PUT",
2250
2286
  body: zipBuffer,
@@ -2267,7 +2303,7 @@ ${error instanceof Error ? error.message : String(error)}`);
2267
2303
  s3Location
2268
2304
  })
2269
2305
  });
2270
- await fs9.remove(tempZip);
2306
+ await fs10.remove(tempZip);
2271
2307
  uploadSpinner.succeed("Project uploaded");
2272
2308
  } catch (error) {
2273
2309
  uploadSpinner.fail("Failed to upload");
@@ -2406,8 +2442,8 @@ __name(deployCommand, "deployCommand");
2406
2442
 
2407
2443
  // src/commands/feedback.ts
2408
2444
  import ora6 from "ora";
2409
- import fs10 from "fs-extra";
2410
- import path10 from "path";
2445
+ import fs11 from "fs-extra";
2446
+ import path11 from "path";
2411
2447
  import os4 from "os";
2412
2448
  var DEBUG_MODE4 = false;
2413
2449
  function debug4(message, ...args) {
@@ -2418,13 +2454,13 @@ function debug4(message, ...args) {
2418
2454
  __name(debug4, "debug");
2419
2455
  async function readFileAsBase64(filePath) {
2420
2456
  try {
2421
- const absolutePath = path10.resolve(filePath);
2422
- const stats = await fs10.stat(absolutePath);
2457
+ const absolutePath = path11.resolve(filePath);
2458
+ const stats = await fs11.stat(absolutePath);
2423
2459
  if (!stats.isFile()) {
2424
2460
  throw new Error(`${filePath} is not a file`);
2425
2461
  }
2426
- const content = await fs10.readFile(absolutePath, "base64");
2427
- const ext = path10.extname(absolutePath).toLowerCase();
2462
+ const content = await fs11.readFile(absolutePath, "base64");
2463
+ const ext = path11.extname(absolutePath).toLowerCase();
2428
2464
  let mimeType = "application/octet-stream";
2429
2465
  switch (ext) {
2430
2466
  case ".txt":
@@ -2457,24 +2493,40 @@ __name(readFileAsBase64, "readFileAsBase64");
2457
2493
  async function collectLogFiles() {
2458
2494
  const attachments = [];
2459
2495
  const logLocations = [
2460
- path10.join(os4.homedir(), ".leanmcp", "logs"),
2461
- path10.join(process.cwd(), "logs"),
2462
- path10.join(process.cwd(), ".leanmcp", "logs")
2496
+ path11.join(os4.homedir(), ".leanmcp", "logs"),
2497
+ path11.join(process.cwd(), "logs"),
2498
+ path11.join(process.cwd(), ".leanmcp", "logs")
2463
2499
  ];
2464
2500
  for (const logDir of logLocations) {
2465
2501
  try {
2466
- if (await fs10.pathExists(logDir)) {
2467
- const files = await fs10.readdir(logDir);
2502
+ if (await fs11.pathExists(logDir)) {
2503
+ const files = await fs11.readdir(logDir);
2504
+ const logFiles = [];
2468
2505
  for (const file of files) {
2469
- const filePath = path10.join(logDir, file);
2506
+ if (!file.endsWith(".log")) continue;
2470
2507
  try {
2471
- const fileData = await readFileAsBase64(filePath);
2472
- attachments.push({
2473
- name: file,
2474
- ...fileData
2508
+ const filePath = path11.join(logDir, file);
2509
+ const stats = await fs11.stat(filePath);
2510
+ logFiles.push({
2511
+ file,
2512
+ filePath,
2513
+ mtime: stats.mtimeMs
2475
2514
  });
2515
+ } catch (e) {
2516
+ }
2517
+ }
2518
+ const recentLogs = logFiles.sort((a, b) => b.mtime - a.mtime).slice(0, 3);
2519
+ for (const log of recentLogs) {
2520
+ try {
2521
+ const fileData = await readFileAsBase64(log.filePath);
2522
+ if (!attachments.some((a) => a.name === log.file)) {
2523
+ attachments.push({
2524
+ name: log.file,
2525
+ ...fileData
2526
+ });
2527
+ }
2476
2528
  } catch (error) {
2477
- debug4(`Failed to read log file ${filePath}: ${error}`);
2529
+ debug4(`Failed to read log file ${log.filePath}: ${error}`);
2478
2530
  }
2479
2531
  }
2480
2532
  }
@@ -2482,13 +2534,13 @@ async function collectLogFiles() {
2482
2534
  debug4(`Failed to scan log directory ${logDir}: ${error}`);
2483
2535
  }
2484
2536
  }
2485
- const npmDebugLog = path10.join(os4.homedir(), ".npm", "_logs");
2537
+ const npmDebugLog = path11.join(os4.homedir(), ".npm", "_logs");
2486
2538
  try {
2487
- if (await fs10.pathExists(npmDebugLog)) {
2488
- const logFiles = await fs10.readdir(npmDebugLog);
2539
+ if (await fs11.pathExists(npmDebugLog)) {
2540
+ const logFiles = await fs11.readdir(npmDebugLog);
2489
2541
  const latestLog = logFiles.filter((file) => file.endsWith(".log")).sort().pop();
2490
2542
  if (latestLog) {
2491
- const filePath = path10.join(npmDebugLog, latestLog);
2543
+ const filePath = path11.join(npmDebugLog, latestLog);
2492
2544
  try {
2493
2545
  const fileData = await readFileAsBase64(filePath);
2494
2546
  attachments.push({
@@ -2791,8 +2843,8 @@ __name(projectsDeleteCommand, "projectsDeleteCommand");
2791
2843
 
2792
2844
  // src/commands/env.ts
2793
2845
  import ora8 from "ora";
2794
- import path11 from "path";
2795
- import fs11 from "fs-extra";
2846
+ import path12 from "path";
2847
+ import fs12 from "fs-extra";
2796
2848
  import { confirm as confirm3 } from "@inquirer/prompts";
2797
2849
  var DEBUG_MODE5 = false;
2798
2850
  function setEnvDebugMode(enabled) {
@@ -2825,10 +2877,10 @@ __name(debugFetch2, "debugFetch");
2825
2877
  var LEANMCP_CONFIG_DIR2 = ".leanmcp";
2826
2878
  var LEANMCP_CONFIG_FILE2 = "config.json";
2827
2879
  async function readLeanMCPConfig2(projectPath) {
2828
- const configPath = path11.join(projectPath, LEANMCP_CONFIG_DIR2, LEANMCP_CONFIG_FILE2);
2880
+ const configPath = path12.join(projectPath, LEANMCP_CONFIG_DIR2, LEANMCP_CONFIG_FILE2);
2829
2881
  try {
2830
- if (await fs11.pathExists(configPath)) {
2831
- const config = await fs11.readJSON(configPath);
2882
+ if (await fs12.pathExists(configPath)) {
2883
+ const config = await fs12.readJSON(configPath);
2832
2884
  debug5("Found existing .leanmcp config:", config);
2833
2885
  return config;
2834
2886
  }
@@ -2846,7 +2898,7 @@ async function getDeploymentContext(folderPath) {
2846
2898
  return null;
2847
2899
  }
2848
2900
  const apiUrl = await getApiUrl();
2849
- const absolutePath = path11.resolve(process.cwd(), folderPath);
2901
+ const absolutePath = path12.resolve(process.cwd(), folderPath);
2850
2902
  const config = await readLeanMCPConfig2(absolutePath);
2851
2903
  if (!config) {
2852
2904
  logger.error("No deployment found.");
@@ -3983,29 +4035,29 @@ program.command("create <projectName>").description("Create a new LeanMCP projec
3983
4035
  ...options
3984
4036
  });
3985
4037
  const spinner = ora9(`Creating project ${projectName}...`).start();
3986
- const targetDir = path12.join(process.cwd(), projectName);
3987
- if (fs12.existsSync(targetDir)) {
4038
+ const targetDir = path13.join(process.cwd(), projectName);
4039
+ if (fs13.existsSync(targetDir)) {
3988
4040
  spinner.fail(`Folder ${projectName} already exists.`);
3989
4041
  process.exit(1);
3990
4042
  }
3991
- await fs12.mkdirp(targetDir);
4043
+ await fs13.mkdirp(targetDir);
3992
4044
  const isPython = options.python === true;
3993
4045
  if (isPython) {
3994
4046
  const requirements = getPythonRequirementsTemplate();
3995
- await fs12.writeFile(path12.join(targetDir, "requirements.txt"), requirements);
4047
+ await fs13.writeFile(path13.join(targetDir, "requirements.txt"), requirements);
3996
4048
  const mainPy = getPythonMainTemplate(projectName);
3997
- await fs12.writeFile(path12.join(targetDir, "main.py"), mainPy);
3998
- await fs12.writeFile(path12.join(targetDir, ".gitignore"), pythonGitignoreTemplate);
4049
+ await fs13.writeFile(path13.join(targetDir, "main.py"), mainPy);
4050
+ await fs13.writeFile(path13.join(targetDir, ".gitignore"), pythonGitignoreTemplate);
3999
4051
  const env = `# Server Configuration
4000
4052
  PORT=3001
4001
4053
 
4002
4054
  # Add your environment variables here
4003
4055
  `;
4004
- await fs12.writeFile(path12.join(targetDir, ".env"), env);
4056
+ await fs13.writeFile(path13.join(targetDir, ".env"), env);
4005
4057
  const readme = getPythonReadmeTemplate(projectName);
4006
- await fs12.writeFile(path12.join(targetDir, "README.md"), readme);
4058
+ await fs13.writeFile(path13.join(targetDir, "README.md"), readme);
4007
4059
  } else {
4008
- await fs12.mkdirp(path12.join(targetDir, "mcp", "example"));
4060
+ await fs13.mkdirp(path13.join(targetDir, "mcp", "example"));
4009
4061
  const pkg2 = {
4010
4062
  name: projectName,
4011
4063
  version: "1.0.0",
@@ -4041,7 +4093,7 @@ PORT=3001
4041
4093
  typescript: "^5.6.3"
4042
4094
  }
4043
4095
  };
4044
- await fs12.writeJSON(path12.join(targetDir, "package.json"), pkg2, {
4096
+ await fs13.writeJSON(path13.join(targetDir, "package.json"), pkg2, {
4045
4097
  spaces: 2
4046
4098
  });
4047
4099
  const tsconfig = {
@@ -4064,15 +4116,15 @@ PORT=3001
4064
4116
  "dist"
4065
4117
  ]
4066
4118
  };
4067
- await fs12.writeJSON(path12.join(targetDir, "tsconfig.json"), tsconfig, {
4119
+ await fs13.writeJSON(path13.join(targetDir, "tsconfig.json"), tsconfig, {
4068
4120
  spaces: 2
4069
4121
  });
4070
4122
  const dashboardLine = options.dashboard === false ? `
4071
4123
  dashboard: false, // Dashboard disabled via --no-dashboard` : "";
4072
4124
  const mainTs = getMainTsTemplate(projectName, dashboardLine);
4073
- await fs12.writeFile(path12.join(targetDir, "main.ts"), mainTs);
4125
+ await fs13.writeFile(path13.join(targetDir, "main.ts"), mainTs);
4074
4126
  const exampleServiceTs = getExampleServiceTemplate(projectName);
4075
- await fs12.writeFile(path12.join(targetDir, "mcp", "example", "index.ts"), exampleServiceTs);
4127
+ await fs13.writeFile(path13.join(targetDir, "mcp", "example", "index.ts"), exampleServiceTs);
4076
4128
  const gitignore = gitignoreTemplate;
4077
4129
  const env = `# Server Configuration
4078
4130
  PORT=3001
@@ -4080,10 +4132,10 @@ NODE_ENV=development
4080
4132
 
4081
4133
  # Add your environment variables here
4082
4134
  `;
4083
- await fs12.writeFile(path12.join(targetDir, ".gitignore"), gitignore);
4084
- await fs12.writeFile(path12.join(targetDir, ".env"), env);
4135
+ await fs13.writeFile(path13.join(targetDir, ".gitignore"), gitignore);
4136
+ await fs13.writeFile(path13.join(targetDir, ".env"), env);
4085
4137
  const readme = getReadmeTemplate(projectName);
4086
- await fs12.writeFile(path12.join(targetDir, "README.md"), readme);
4138
+ await fs13.writeFile(path13.join(targetDir, "README.md"), readme);
4087
4139
  }
4088
4140
  spinner.succeed(`Project ${projectName} created!`);
4089
4141
  logger.log("\nSuccess! Your MCP server is ready.\n", chalk.green);
@@ -4216,20 +4268,20 @@ program.command("send-feedback [message]").description("Send feedback to the Lea
4216
4268
  });
4217
4269
  program.command("add <serviceName>").description("Add a new MCP service to your project").action(async (serviceName) => {
4218
4270
  const cwd = process.cwd();
4219
- const mcpDir = path12.join(cwd, "mcp");
4220
- if (!fs12.existsSync(path12.join(cwd, "main.ts"))) {
4271
+ const mcpDir = path13.join(cwd, "mcp");
4272
+ if (!fs13.existsSync(path13.join(cwd, "main.ts"))) {
4221
4273
  logger.log("ERROR: Not a LeanMCP project (main.ts missing).", chalk.red);
4222
4274
  process.exit(1);
4223
4275
  }
4224
- const serviceDir = path12.join(mcpDir, serviceName);
4225
- const serviceFile = path12.join(serviceDir, "index.ts");
4226
- if (fs12.existsSync(serviceDir)) {
4276
+ const serviceDir = path13.join(mcpDir, serviceName);
4277
+ const serviceFile = path13.join(serviceDir, "index.ts");
4278
+ if (fs13.existsSync(serviceDir)) {
4227
4279
  logger.log(`ERROR: Service ${serviceName} already exists.`, chalk.red);
4228
4280
  process.exit(1);
4229
4281
  }
4230
- await fs12.mkdirp(serviceDir);
4282
+ await fs13.mkdirp(serviceDir);
4231
4283
  const indexTs = getServiceIndexTemplate(serviceName, capitalize(serviceName));
4232
- await fs12.writeFile(serviceFile, indexTs);
4284
+ await fs13.writeFile(serviceFile, indexTs);
4233
4285
  logger.log(`\\nCreated new service: ${chalk.bold(serviceName)}`, chalk.green);
4234
4286
  logger.log(` File: mcp/${serviceName}/index.ts`, chalk.gray);
4235
4287
  logger.log(` Tool: greet`, chalk.gray);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanmcp/cli",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Command-line interface for scaffolding LeanMCP projects",
5
5
  "bin": {
6
6
  "leanmcp": "bin/leanmcp.js"