md4ai 0.9.8 → 0.9.10

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.
@@ -1,12 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
- }) : x)(function(x) {
7
- if (typeof require !== "undefined") return require.apply(this, arguments);
8
- throw Error('Dynamic require of "' + x + '" is not supported');
9
- });
10
4
  var __esm = (fn, res) => function __init() {
11
5
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
6
  };
@@ -893,20 +887,26 @@ var init_tooling_detector = __esm({
893
887
  import { readFile as readFile5 } from "node:fs/promises";
894
888
  import { join as join7 } from "node:path";
895
889
  import { homedir as homedir5 } from "node:os";
896
- async function resolveVercelToken() {
890
+ async function resolveVercelTokenWithSource() {
897
891
  const creds = await loadCredentials();
898
- if (creds?.vercelToken)
899
- return creds.vercelToken;
892
+ if (creds?.vercelToken) {
893
+ return {
894
+ token: creds.vercelToken,
895
+ source: "md4ai-credentials",
896
+ sourcePath: join7(homedir5(), ".md4ai", "credentials.json")
897
+ };
898
+ }
900
899
  const possiblePaths = [
901
- join7(homedir5(), ".config", "com.vercel.cli", "auth.json"),
902
- join7(homedir5(), ".local", "share", "com.vercel.cli", "auth.json")
900
+ { path: join7(homedir5(), ".config", "com.vercel.cli", "auth.json"), source: "vercel-cli-config" },
901
+ { path: join7(homedir5(), ".local", "share", "com.vercel.cli", "auth.json"), source: "vercel-cli-local-share" }
903
902
  ];
904
- for (const authPath of possiblePaths) {
903
+ for (const { path: authPath, source } of possiblePaths) {
905
904
  try {
906
905
  const data = await readFile5(authPath, "utf-8");
907
906
  const parsed = JSON.parse(data);
908
- if (parsed.token)
909
- return parsed.token;
907
+ if (parsed.token) {
908
+ return { token: parsed.token, source, sourcePath: authPath };
909
+ }
910
910
  } catch {
911
911
  }
912
912
  }
@@ -962,7 +962,21 @@ async function fetchVercelEnvVars(projectId, orgId, token) {
962
962
  });
963
963
  if (!res.ok) {
964
964
  const body = await res.text().catch(() => "");
965
- throw new Error(`Vercel API ${res.status}: ${body.slice(0, 200)}`);
965
+ let errorCode = null;
966
+ let invalidToken = false;
967
+ try {
968
+ const parsed = JSON.parse(body);
969
+ errorCode = parsed.error?.code ?? null;
970
+ invalidToken = parsed.error?.invalidToken === true;
971
+ } catch {
972
+ }
973
+ if (invalidToken || res.status === 401) {
974
+ throw new VercelApiError("Token is invalid or expired", res.status, errorCode, true);
975
+ }
976
+ if (res.status === 403) {
977
+ throw new VercelApiError("Token lacks permission for this project/team", res.status, errorCode, false);
978
+ }
979
+ throw new VercelApiError(`Vercel API ${res.status}: ${body.slice(0, 200)}`, res.status, errorCode, false);
966
980
  }
967
981
  const data = await res.json();
968
982
  const envs = data.envs ?? [];
@@ -974,9 +988,22 @@ async function fetchVercelEnvVars(projectId, orgId, token) {
974
988
  // populated later by the scanner
975
989
  }));
976
990
  }
991
+ var VercelApiError;
977
992
  var init_fetch_env_vars = __esm({
978
993
  "dist/vercel/fetch-env-vars.js"() {
979
994
  "use strict";
995
+ VercelApiError = class extends Error {
996
+ statusCode;
997
+ errorCode;
998
+ isInvalidToken;
999
+ constructor(message, statusCode, errorCode, isInvalidToken) {
1000
+ super(message);
1001
+ this.statusCode = statusCode;
1002
+ this.errorCode = errorCode;
1003
+ this.isInvalidToken = isInvalidToken;
1004
+ this.name = "VercelApiError";
1005
+ }
1006
+ };
980
1007
  }
981
1008
  });
982
1009
 
@@ -1018,18 +1045,48 @@ async function scanEnvManifest(projectRoot) {
1018
1045
  checkedAt: (/* @__PURE__ */ new Date()).toISOString()
1019
1046
  };
1020
1047
  }
1048
+ function tokenSourceLabel(source) {
1049
+ switch (source) {
1050
+ case "md4ai-credentials":
1051
+ return "md4ai credentials (~/.md4ai/credentials.json)";
1052
+ case "vercel-cli-config":
1053
+ return "Vercel CLI (~/.config/com.vercel.cli/auth.json)";
1054
+ case "vercel-cli-local-share":
1055
+ return "Vercel CLI (~/.local/share/com.vercel.cli/auth.json)";
1056
+ }
1057
+ }
1058
+ function tokenFixInstructions(source) {
1059
+ switch (source) {
1060
+ case "md4ai-credentials":
1061
+ return [
1062
+ "Generate a new token at https://vercel.com/account/tokens",
1063
+ "Then run: md4ai config set vercel-token <new-token>"
1064
+ ];
1065
+ case "vercel-cli-config":
1066
+ case "vercel-cli-local-share":
1067
+ return [
1068
+ "Re-authenticate the Vercel CLI: npx vercel login",
1069
+ "Ensure you log into the correct team account",
1070
+ "Or set a dedicated token: md4ai config set vercel-token <token>"
1071
+ ];
1072
+ }
1073
+ }
1021
1074
  async function checkVercelEnvVars(projectRoot, variables) {
1022
- const token = await resolveVercelToken();
1023
- if (!token) {
1075
+ const tokenResult = await resolveVercelTokenWithSource();
1076
+ if (!tokenResult) {
1024
1077
  console.log(chalk8.dim(" Vercel checks skipped (no token configured)"));
1078
+ console.log(chalk8.dim(" To enable: md4ai config set vercel-token <token>"));
1079
+ console.log(chalk8.dim(" Generate a token at https://vercel.com/account/tokens"));
1025
1080
  return null;
1026
1081
  }
1082
+ const { token, source } = tokenResult;
1027
1083
  const projects = await discoverVercelProjects(projectRoot);
1028
1084
  if (projects.length === 0)
1029
1085
  return null;
1030
1086
  console.log(chalk8.dim(` Checking ${projects.length} Vercel project(s)...`));
1031
1087
  const discovered = [];
1032
1088
  const manifestVarNames = new Set(variables.map((v) => v.name));
1089
+ let tokenErrorShown = false;
1033
1090
  for (const proj of projects) {
1034
1091
  try {
1035
1092
  const vars = await fetchVercelEnvVars(proj.projectId, proj.orgId, token);
@@ -1050,7 +1107,22 @@ async function checkVercelEnvVars(projectRoot, variables) {
1050
1107
  }
1051
1108
  console.log(chalk8.dim(` ${proj.projectName}: ${vars.length} var(s)`));
1052
1109
  } catch (err) {
1053
- console.log(chalk8.yellow(` ${proj.projectName}: ${err instanceof Error ? err.message : "API error"}`));
1110
+ if (err instanceof VercelApiError && err.isInvalidToken && !tokenErrorShown) {
1111
+ tokenErrorShown = true;
1112
+ console.log(chalk8.red(` ${proj.projectName}: Token is invalid or expired`));
1113
+ console.log(chalk8.yellow(` Token source: ${tokenSourceLabel(source)}`));
1114
+ console.log(chalk8.yellow(" To fix:"));
1115
+ for (const step of tokenFixInstructions(source)) {
1116
+ console.log(chalk8.yellow(` \u2192 ${step}`));
1117
+ }
1118
+ } else if (err instanceof VercelApiError && err.statusCode === 403) {
1119
+ console.log(chalk8.yellow(` ${proj.projectName}: ${err.message}`));
1120
+ console.log(chalk8.dim(` Token source: ${tokenSourceLabel(source)}`));
1121
+ console.log(chalk8.dim(" Ensure the token has access to this team/project"));
1122
+ console.log(chalk8.dim(" Check: https://vercel.com/account/tokens"));
1123
+ } else {
1124
+ console.log(chalk8.yellow(` ${proj.projectName}: ${err instanceof Error ? err.message : "API error"}`));
1125
+ }
1054
1126
  }
1055
1127
  }
1056
1128
  return discovered.length > 0 ? discovered : null;
@@ -1651,7 +1723,7 @@ var CURRENT_VERSION;
1651
1723
  var init_check_update = __esm({
1652
1724
  "dist/check-update.js"() {
1653
1725
  "use strict";
1654
- CURRENT_VERSION = true ? "0.9.8" : "0.0.0-dev";
1726
+ CURRENT_VERSION = true ? "0.9.10" : "0.0.0-dev";
1655
1727
  }
1656
1728
  });
1657
1729
 
@@ -2261,6 +2333,7 @@ var init_read_configs = __esm({
2261
2333
 
2262
2334
  // dist/mcp/scan-processes.js
2263
2335
  import { execFileSync as execFileSync4 } from "node:child_process";
2336
+ import { readlinkSync } from "node:fs";
2264
2337
  function parsePsOutput(output) {
2265
2338
  const lines = output.trim().split("\n").slice(1);
2266
2339
  const entries = [];
@@ -2350,7 +2423,6 @@ function getProcessTable() {
2350
2423
  }
2351
2424
  }
2352
2425
  function detectSessionCwds(processes) {
2353
- const { readlinkSync } = __require("node:fs");
2354
2426
  const cwdByTty = /* @__PURE__ */ new Map();
2355
2427
  const claudeProcs = processes.filter((p) => {
2356
2428
  const lower = p.args.toLowerCase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "md4ai",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
4
4
  "description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
5
5
  "type": "module",
6
6
  "bin": {