@costlens/mcp-server 0.5.0 → 0.6.0

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/cli.js +143 -1
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -398,6 +398,11 @@ var CONFIG_FILE = (0, import_path2.join)(CONFIG_DIR, "config.json");
398
398
  var API_BASE2 = process.env.COSTLENS_API_URL || "https://api.costlens.dev";
399
399
  var APP_URL = process.env.COSTLENS_APP_URL || "https://costlens.dev";
400
400
  function readConfig() {
401
+ try {
402
+ const projectConfig = JSON.parse((0, import_fs2.readFileSync)((0, import_path2.join)(process.cwd(), ".costlens.json"), "utf-8"));
403
+ if (projectConfig.key) return { apiKey: projectConfig.key };
404
+ } catch {
405
+ }
401
406
  try {
402
407
  return JSON.parse((0, import_fs2.readFileSync)(CONFIG_FILE, "utf-8"));
403
408
  } catch {
@@ -646,7 +651,8 @@ else if (command === "setup") setup();
646
651
  else if (command === "hooks") {
647
652
  installHooks();
648
653
  process.exit(0);
649
- } else {
654
+ } else if (command === "doctor") doctor();
655
+ else {
650
656
  init_index();
651
657
  }
652
658
  async function setup() {
@@ -659,3 +665,139 @@ async function setup() {
659
665
  }
660
666
  await login();
661
667
  }
668
+ async function doctor() {
669
+ console.log("\n CostLens Doctor\n");
670
+ const config = readConfig();
671
+ const issues = [];
672
+ let keyValid = false;
673
+ let planData = null;
674
+ let spendData = null;
675
+ if (!config.apiKey) {
676
+ console.log(" Key: not configured");
677
+ issues.push("No API key. Run: npx @costlens/mcp-server setup");
678
+ } else {
679
+ try {
680
+ const res = await fetch(`${API_BASE2}/v1/plan`, {
681
+ headers: { Authorization: `Bearer ${config.apiKey}` },
682
+ signal: AbortSignal.timeout(5e3)
683
+ });
684
+ if (res.ok) {
685
+ planData = await res.json();
686
+ keyValid = true;
687
+ console.log(` Key: valid (${config.apiKey.slice(0, 10)}...)`);
688
+ } else {
689
+ console.log(` Key: invalid (${res.status})`);
690
+ issues.push("API key is invalid or expired. Run: npx @costlens/mcp-server login");
691
+ }
692
+ } catch (e) {
693
+ console.log(` Key: error (${e.message})`);
694
+ issues.push("Cannot reach CostLens API. Check your network.");
695
+ }
696
+ }
697
+ if (planData) {
698
+ console.log(` Plan: ${planData.plan}`);
699
+ console.log(` Tracking: ${planData.keySettings?.trackingMode || "manual"}`);
700
+ }
701
+ if (keyValid) {
702
+ try {
703
+ const res = await fetch(`${API_BASE2}/v1/spend`, {
704
+ headers: { Authorization: `Bearer ${config.apiKey}` },
705
+ signal: AbortSignal.timeout(5e3)
706
+ });
707
+ if (res.ok) {
708
+ spendData = await res.json();
709
+ const daily = spendData.daily?.cost ?? 0;
710
+ const budget = spendData.dailyBudget;
711
+ if (budget) {
712
+ console.log(` Budget: $${daily.toFixed(2)} / $${budget.toFixed(2)} today`);
713
+ } else {
714
+ console.log(` Spend: $${daily.toFixed(4)} today`);
715
+ }
716
+ }
717
+ } catch {
718
+ }
719
+ }
720
+ const kiroPath = (0, import_path2.join)((0, import_os2.homedir)(), ".kiro", "settings", "mcp.json");
721
+ const cursorPath = (0, import_path2.join)((0, import_os2.homedir)(), ".cursor", "mcp.json");
722
+ const claudePath = (0, import_path2.join)((0, import_os2.homedir)(), ".claude", "mcp_servers.json");
723
+ const agents = [
724
+ { name: "Kiro", path: kiroPath },
725
+ { name: "Cursor", path: cursorPath },
726
+ { name: "Claude Code", path: claudePath }
727
+ ];
728
+ let agentConfigured = false;
729
+ for (const { name, path } of agents) {
730
+ if ((0, import_fs2.existsSync)(path)) {
731
+ try {
732
+ const content = JSON.parse((0, import_fs2.readFileSync)(path, "utf-8"));
733
+ if (content.mcpServers?.costlens) {
734
+ console.log(` MCP: ${name} (configured)`);
735
+ agentConfigured = true;
736
+ break;
737
+ }
738
+ } catch {
739
+ }
740
+ }
741
+ }
742
+ if (!agentConfigured) {
743
+ console.log(" MCP: not configured");
744
+ issues.push("No agent configured. Run: npx @costlens/mcp-server setup");
745
+ }
746
+ const cwd = process.cwd();
747
+ const hookPath = (0, import_path2.join)(cwd, ".git", "hooks", "post-commit");
748
+ if ((0, import_fs2.existsSync)(hookPath)) {
749
+ try {
750
+ const content = (0, import_fs2.readFileSync)(hookPath, "utf-8");
751
+ if (content.includes(HOOK_MARKER)) {
752
+ console.log(" Git hook: installed (post-commit)");
753
+ } else {
754
+ console.log(" Git hook: exists (not CostLens)");
755
+ }
756
+ } catch {
757
+ console.log(" Git hook: error reading");
758
+ }
759
+ } else if ((0, import_fs2.existsSync)((0, import_path2.join)(cwd, ".git"))) {
760
+ console.log(" Git hook: not installed");
761
+ issues.push("Git hook not installed. Run: npx @costlens/mcp-server hooks");
762
+ } else {
763
+ console.log(" Git hook: no git repo in cwd");
764
+ }
765
+ const pkgPath = (0, import_path2.join)(cwd, "package.json");
766
+ if ((0, import_fs2.existsSync)(pkgPath)) {
767
+ try {
768
+ const pkg = JSON.parse((0, import_fs2.readFileSync)(pkgPath, "utf-8"));
769
+ const sdkVersion = pkg.dependencies?.costlens || pkg.devDependencies?.costlens;
770
+ if (sdkVersion) {
771
+ console.log(` SDK: installed (${sdkVersion})`);
772
+ } else {
773
+ console.log(" SDK: not installed");
774
+ }
775
+ } catch {
776
+ }
777
+ }
778
+ if (keyValid) {
779
+ try {
780
+ const res = await fetch(`${API_BASE2}/v1/productivity/github?period=week`, {
781
+ headers: { Authorization: `Bearer ${config.apiKey}` },
782
+ signal: AbortSignal.timeout(5e3)
783
+ });
784
+ if (res.ok) {
785
+ console.log(" GitHub: connected");
786
+ } else if (res.status === 404) {
787
+ console.log(" GitHub: not connected");
788
+ }
789
+ } catch {
790
+ }
791
+ }
792
+ console.log("");
793
+ if (issues.length === 0) {
794
+ console.log(" All good.\n");
795
+ } else {
796
+ console.log(" Issues:\n");
797
+ for (const issue of issues) {
798
+ console.log(` - ${issue}`);
799
+ }
800
+ console.log("");
801
+ }
802
+ process.exit(issues.length > 0 ? 1 : 0);
803
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@costlens/mcp-server",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "MCP server for AI cost optimization with prompt complexity classification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",