metheus-governance-mcp-cli 0.2.7 → 0.2.9

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/cli.mjs +83 -14
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -168,9 +168,33 @@ function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
168
168
  return resolveWorkspaceDir(candidate);
169
169
  }
170
170
 
171
+ function extractWorkspaceCandidateFromEnv() {
172
+ const rawCandidate = firstNonEmptyString([
173
+ process.env.METHEUS_WORKSPACE_DIR,
174
+ process.env.CLAUDE_WORKSPACE_DIR,
175
+ process.env.CLAUDE_PROJECT_DIR,
176
+ process.env.CODEX_WORKSPACE_DIR,
177
+ process.env.WORKSPACE_DIR,
178
+ process.env.WORKSPACE_FOLDER,
179
+ process.env.VSCODE_CWD,
180
+ process.env.PWD,
181
+ process.env.INIT_CWD,
182
+ ]);
183
+ const fileCandidate = fileURIToLocalPath(rawCandidate);
184
+ const candidate = firstNonEmptyString([fileCandidate, rawCandidate]);
185
+ if (!candidate) return "";
186
+ return resolveWorkspaceDir(candidate);
187
+ }
188
+
171
189
  function resolveWorkspaceDirForRequest(defaultWorkspaceDir, requestObj, toolArgs) {
172
190
  const requestCandidate = extractWorkspaceCandidateFromRequest(requestObj, toolArgs);
173
- const candidate = firstNonEmptyString([requestCandidate, defaultWorkspaceDir, process.cwd()]);
191
+ const envCandidate = extractWorkspaceCandidateFromEnv();
192
+ const candidate = firstNonEmptyString([
193
+ requestCandidate,
194
+ envCandidate,
195
+ defaultWorkspaceDir,
196
+ process.cwd(),
197
+ ]);
174
198
  return resolveWorkspaceDir(candidate);
175
199
  }
176
200
 
@@ -1387,6 +1411,19 @@ function addDoctorCheck(rows, status, label, detail) {
1387
1411
  });
1388
1412
  }
1389
1413
 
1414
+ function isUnauthorizedLike(rawText) {
1415
+ const text = String(rawText || "").trim().toLowerCase();
1416
+ if (!text) return false;
1417
+ return (
1418
+ text.includes("unauthorized") ||
1419
+ text.includes("access denied") ||
1420
+ text.includes("status 401") ||
1421
+ text.includes("status 403") ||
1422
+ text.includes("http 401") ||
1423
+ text.includes("http 403")
1424
+ );
1425
+ }
1426
+
1390
1427
  function statusIcon(status) {
1391
1428
  if (status === "ok") return "OK";
1392
1429
  if (status === "fail") return "FAIL";
@@ -1671,12 +1708,25 @@ async function runDoctor(flags) {
1671
1708
  addDoctorCheck(rows, "ok", "server mode", "ctxpack writable");
1672
1709
  }
1673
1710
  } catch (err) {
1674
- addDoctorCheck(
1675
- rows,
1676
- "warn",
1677
- "server ctxpack policy",
1678
- `unable to read /ctxpack/stats (${String(err?.message || err)})`,
1679
- );
1711
+ const statusCode = Number(err?.statusCode || 0);
1712
+ const message = String(err?.message || err);
1713
+ if (statusCode === 404) {
1714
+ addDoctorCheck(
1715
+ rows,
1716
+ "ok",
1717
+ "server ctxpack policy",
1718
+ "ctxpack/stats endpoint is not exposed in this deployment (optional check skipped)",
1719
+ );
1720
+ } else if (statusCode === 401 || statusCode === 403 || isUnauthorizedLike(message)) {
1721
+ addDoctorCheck(
1722
+ rows,
1723
+ "warn",
1724
+ "server ctxpack policy",
1725
+ "no permission to read ctxpack/stats in this environment",
1726
+ );
1727
+ } else {
1728
+ addDoctorCheck(rows, "warn", "server ctxpack policy", `unable to read /ctxpack/stats (${message})`);
1729
+ }
1680
1730
  }
1681
1731
  }
1682
1732
 
@@ -1712,7 +1762,17 @@ async function runDoctor(flags) {
1712
1762
  },
1713
1763
  });
1714
1764
  if (!rpc.ok) {
1715
- addDoctorCheck(rows, "fail", `smoke ${row.tool}`, rpc.error || "rpc error");
1765
+ const errorText = String(rpc.error || "rpc error");
1766
+ if (isUnauthorizedLike(errorText)) {
1767
+ addDoctorCheck(
1768
+ rows,
1769
+ "warn",
1770
+ `smoke ${row.tool}`,
1771
+ "unauthorized for this tool with current token/project role",
1772
+ );
1773
+ } else {
1774
+ addDoctorCheck(rows, "fail", `smoke ${row.tool}`, errorText);
1775
+ }
1716
1776
  continue;
1717
1777
  }
1718
1778
  const envelope = parseToolEnvelopeFromRPCResult(safeObject(rpc.response).result);
@@ -1725,12 +1785,21 @@ async function runDoctor(flags) {
1725
1785
  if (ok && status >= 200 && status < 300) {
1726
1786
  addDoctorCheck(rows, "ok", `smoke ${row.tool}`, `status ${status}`);
1727
1787
  } else {
1728
- addDoctorCheck(
1729
- rows,
1730
- "fail",
1731
- `smoke ${row.tool}`,
1732
- `status ${status || "-"}, ok=${ok ? "true" : "false"}`,
1733
- );
1788
+ if (status === 401 || status === 403) {
1789
+ addDoctorCheck(
1790
+ rows,
1791
+ "warn",
1792
+ `smoke ${row.tool}`,
1793
+ `status ${status}: unauthorized for this tool with current token/project role`,
1794
+ );
1795
+ } else {
1796
+ addDoctorCheck(
1797
+ rows,
1798
+ "fail",
1799
+ `smoke ${row.tool}`,
1800
+ `status ${status || "-"}, ok=${ok ? "true" : "false"}`,
1801
+ );
1802
+ }
1734
1803
  }
1735
1804
  }
1736
1805
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [