@codexguild/mcp 1.6.1 → 1.7.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.
@@ -1460,6 +1460,7 @@ async function scanCode(root, deps) {
1460
1460
  }
1461
1461
  return { hits, files: files.length };
1462
1462
  }
1463
+ var KEY_REJECTED = "CODEXGUILD_API_KEY was rejected (revoked or deleted). Create a new agent key at https://codexguild.com/dashboard/agents, set it as CODEXGUILD_API_KEY and restart the MCP client.";
1463
1464
  async function applicableDeprecations(api, key, deps) {
1464
1465
  const packages = deps.filter((d) => d.version && !d.runtime).slice(0, 300).map((d) => ({ name: d.name, version: d.version, ...d.ecosystem ? { ecosystem: d.ecosystem } : {} }));
1465
1466
  if (!packages.length || !key) return [];
@@ -1469,6 +1470,7 @@ async function applicableDeprecations(api, key, deps) {
1469
1470
  body: JSON.stringify({ packages }),
1470
1471
  signal: AbortSignal.timeout(15e3)
1471
1472
  });
1473
+ if (res.status === 401 || res.status === 403) throw new Error(KEY_REJECTED);
1472
1474
  if (!res.ok) throw new Error(`deprecation check failed (${res.status})`);
1473
1475
  return (await res.json()).items;
1474
1476
  }
@@ -1499,7 +1501,7 @@ function formatCodeScan(hits, files, checked) {
1499
1501
  // src/index.ts
1500
1502
  var API = (process.env.CODEXGUILD_API_URL || "https://api.codexguild.com/v1").replace(/\/$/, "");
1501
1503
  var KEY = process.env.CODEXGUILD_API_KEY ?? "";
1502
- var VERSION = "1.6.1";
1504
+ var VERSION = "1.7.0";
1503
1505
  if (process.argv[2] === "guard") process.exit(await runGuard({ api: API, key: KEY }));
1504
1506
  var INSTRUCTION_FILES = ["CLAUDE.md", ".claude/CLAUDE.md", "AGENTS.md", "AGENTS.override.md", ".hermes.md", "HERMES.md", "GEMINI.md", ".cursorrules"];
1505
1507
  async function existingInstructionFiles(cwd) {
@@ -1507,14 +1509,21 @@ async function existingInstructionFiles(cwd) {
1507
1509
  return present.filter((f) => f !== null);
1508
1510
  }
1509
1511
  var remote = null;
1512
+ var keyRejected = false;
1510
1513
  function remoteClient() {
1511
1514
  if (!KEY) return Promise.reject(new Error("CODEXGUILD_API_KEY is not set \u2014 create an agent key in the CodexGuild dashboard."));
1515
+ if (keyRejected) return Promise.reject(new Error(KEY_REJECTED));
1512
1516
  remote ??= (async () => {
1513
1517
  const client = new Client({ name: "codexguild-local", version: VERSION });
1514
1518
  await client.connect(new StreamableHTTPClientTransport(new URL(`${API}/mcp`), { requestInit: { headers: { Authorization: `Bearer ${KEY}` } } }));
1515
1519
  return client;
1516
1520
  })().catch((e) => {
1517
1521
  remote = null;
1522
+ const code = e.code;
1523
+ if (code === 401 || code === 403) {
1524
+ keyRejected = true;
1525
+ throw new Error(KEY_REJECTED);
1526
+ }
1518
1527
  throw e;
1519
1528
  });
1520
1529
  return remote;
@@ -1535,7 +1544,8 @@ var ENHANCED = {
1535
1544
  codexguild_sync: "Runs locally first: the stack (package.json, requirements.txt, go.mod, \u2026) and installed skill NAMES are detected automatically \u2014 only names/versions are sent, never file contents; you only need force/since.",
1536
1545
  codexguild_advise: "Runs locally first: stack, installed skills and the instruction files present in the project are detected automatically; you only need harness.",
1537
1546
  codexguild_debug: "Runs locally first: the project's package versions are read from its lockfiles and sent with the error \u2014 you only need error (and stack).",
1538
- codexguild_upgrade_plan: "Runs locally first: `from` (and the ecosystem) is read from the lockfile when you only give `package`."
1547
+ codexguild_upgrade_plan: "Runs locally first: `from` (and the ecosystem) is read from the lockfile when you only give `package`.",
1548
+ codexguild_fix_submit: "Runs locally first: `packages` (names and versions after your changes) is read from the project's manifests and lockfiles \u2014 you only need task_id and summary. Run the package manager first so the lockfile is current."
1539
1549
  };
1540
1550
  function enhance(t) {
1541
1551
  const note = ENHANCED[t.name];
@@ -1548,7 +1558,8 @@ ${note}`,
1548
1558
  ...t.inputSchema,
1549
1559
  properties: { ...t.inputSchema.properties, cwd: { type: "string", description: "Project directory (defaults to the current directory)" } },
1550
1560
  // Filled from the lockfile here, so the agent need not pass it.
1551
- ...t.name === "codexguild_upgrade_plan" && Array.isArray(t.inputSchema.required) ? { required: t.inputSchema.required.filter((r) => r !== "from") } : {}
1561
+ ...t.name === "codexguild_upgrade_plan" && Array.isArray(t.inputSchema.required) ? { required: t.inputSchema.required.filter((r) => r !== "from") } : {},
1562
+ ...t.name === "codexguild_fix_submit" && Array.isArray(t.inputSchema.required) ? { required: t.inputSchema.required.filter((r) => r !== "packages") } : {}
1552
1563
  }
1553
1564
  };
1554
1565
  }
@@ -1559,6 +1570,11 @@ async function detected(name, cwd, explicit = {}) {
1559
1570
  const d = deps2.find((x) => !x.runtime && x.name === pkg && x.version);
1560
1571
  return { args: d ? { from: d.version, ...d.ecosystem ? { ecosystem: d.ecosystem } : {} } : {} };
1561
1572
  }
1573
+ if (name === "codexguild_fix_submit") {
1574
+ const { deps: deps2, lockfiles: lockfiles2 } = await detectStack2(cwd);
1575
+ const packages = deps2.slice(0, 300).map((d) => ({ name: d.name, ...d.version ? { version: d.version } : {}, ...d.ecosystem ? { ecosystem: d.ecosystem } : {}, ...d.runtime ? { runtime: true } : {} }));
1576
+ return { args: { packages }, summary: `CodexGuild: submitted ${packages.length} dependencies from ${lockfiles2.length ? lockfiles2.join(", ") : "manifests (no lockfile \u2014 versions are ranges)"}.` };
1577
+ }
1562
1578
  if (name === "codexguild_debug") {
1563
1579
  const { deps: deps2 } = await detectStack2(cwd);
1564
1580
  return { args: { packages: deps2.slice(0, 300).map((d) => ({ name: d.name, ...d.version ? { version: d.version } : {}, ...d.ecosystem ? { ecosystem: d.ecosystem } : {} })) } };
@@ -1655,13 +1671,13 @@ async function remoteTools() {
1655
1671
  try {
1656
1672
  return (await (await remoteClient()).listTools()).tools;
1657
1673
  } catch (e) {
1658
- if (!KEY || attempt >= RETRY_MS.length) throw e;
1674
+ if (!KEY || keyRejected || attempt >= RETRY_MS.length) throw e;
1659
1675
  await new Promise((r) => setTimeout(r, RETRY_MS[attempt]));
1660
1676
  }
1661
1677
  }
1662
1678
  }
1663
1679
  function scheduleReconnect() {
1664
- if (reconnectTimer || !KEY) return;
1680
+ if (reconnectTimer || !KEY || keyRejected) return;
1665
1681
  reconnectTimer = setInterval(async () => {
1666
1682
  try {
1667
1683
  await (await remoteClient()).listTools();
@@ -1678,7 +1694,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
1678
1694
  try {
1679
1695
  return { tools: [...LOCAL_TOOLS, ...(await remoteTools()).map(enhance)] };
1680
1696
  } catch (e) {
1681
- console.error(`CodexGuild: remote tools unavailable (${e instanceof Error ? e.message : String(e)}) \u2014 serving local tools only; retrying in the background.`);
1697
+ const retry = KEY && !keyRejected ? "; retrying in the background" : "";
1698
+ console.error(`CodexGuild: remote tools unavailable (${e instanceof Error ? e.message : String(e)}) \u2014 serving local tools only${retry}.`);
1682
1699
  scheduleReconnect();
1683
1700
  return { tools: LOCAL_TOOLS };
1684
1701
  }
@@ -1711,7 +1728,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1711
1728
  }
1712
1729
  const r = await (await remoteClient()).callTool({ name, arguments: args2 });
1713
1730
  const codeNote = name === "codexguild_sync" && !r.isError ? await codeScanLocal(cwd).catch(() => null) : null;
1714
- const extra = [...summary ? [{ type: "text", text: summary }] : []];
1731
+ const extra = [...summary && !r.isError ? [{ type: "text", text: summary }] : []];
1715
1732
  const tail = codeNote && !codeNote.startsWith("Code check:") ? [{ type: "text", text: codeNote }] : [];
1716
1733
  return extra.length || tail.length ? { ...r, content: [...extra, ...r.content ?? [], ...tail] } : r;
1717
1734
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexguild/mcp",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "CodexGuild MCP server (stdio) \u2014 boosts your coding agent: remote CodexGuild tools plus local stack detection from lockfiles, deprecated APIs found in your own code, and offline security audits of skills, instructions and agent workflows",
5
5
  "keywords": [
6
6
  "mcp",