@remixhq/mcp 0.1.18 → 0.1.20

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.
package/dist/index.js CHANGED
@@ -251,6 +251,15 @@ function normalizeByMessage(err) {
251
251
  category: "remote_state"
252
252
  });
253
253
  }
254
+ if (statusCode === 409) {
255
+ return makeNormalized({
256
+ code: ERROR_CODES.REMOTE_ERROR,
257
+ message,
258
+ hint,
259
+ retryable: true,
260
+ category: "remote_state"
261
+ });
262
+ }
254
263
  if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
255
264
  return makeNormalized({
256
265
  code: ERROR_CODES.REMOTE_ERROR,
@@ -427,7 +436,6 @@ function makeSuccessResult(envelope) {
427
436
  function makeErrorResult(envelope) {
428
437
  return {
429
438
  content: [{ type: "text", text: toJsonText(envelope) }],
430
- structuredContent: envelope,
431
439
  isError: true
432
440
  };
433
441
  }
@@ -1711,13 +1719,34 @@ async function accessDebug(params) {
1711
1719
 
1712
1720
  // src/tools/collab/autoSpawnHistoryImport.ts
1713
1721
  import { spawn } from "child_process";
1714
- import { existsSync, mkdirSync, openSync } from "fs";
1722
+ import { createHash } from "crypto";
1723
+ import { existsSync } from "fs";
1724
+ import os from "os";
1715
1725
  import path2 from "path";
1716
- var MARKER_REL_PATH = path2.join(".remix", ".history-imported");
1717
- var LOG_REL_PATH = path2.join(".remix", "history-import.log");
1718
- function shouldAutoSpawnHistoryImport(repoRoot) {
1726
+ var LEGACY_MARKER_REL_PATH = path2.join(".remix", ".history-imported");
1727
+ function collabStateRoot() {
1728
+ const configured = process.env.REMIX_COLLAB_STATE_ROOT?.trim();
1729
+ return configured || path2.join(os.homedir(), ".remix", "collab-state");
1730
+ }
1731
+ function sha256Hex(value) {
1732
+ return createHash("sha256").update(value).digest("hex");
1733
+ }
1734
+ function autoSpawnMarkerPath(repoRoot, repoFingerprint) {
1735
+ const identityKey = typeof repoFingerprint === "string" && repoFingerprint.trim() ? `repoFingerprint:${repoFingerprint.trim()}` : `repoRoot:${repoRoot}`;
1736
+ return path2.join(collabStateRoot(), "history-import", sha256Hex(identityKey), "history-imported.json");
1737
+ }
1738
+ function fallbackRepoRootMarkerPath(repoRoot) {
1739
+ return autoSpawnMarkerPath(repoRoot, null);
1740
+ }
1741
+ function legacyLocalRepoRootMarkerPath(repoRoot) {
1742
+ return path2.join(collabStateRoot(), "history-import", sha256Hex(repoRoot), "history-imported.json");
1743
+ }
1744
+ function legacyAutoSpawnMarkerPath(repoRoot) {
1745
+ return path2.join(repoRoot, LEGACY_MARKER_REL_PATH);
1746
+ }
1747
+ function shouldAutoSpawnHistoryImport(repoRoot, repoFingerprint) {
1719
1748
  try {
1720
- return !existsSync(path2.join(repoRoot, MARKER_REL_PATH));
1749
+ return !existsSync(autoSpawnMarkerPath(repoRoot, repoFingerprint)) && !existsSync(fallbackRepoRootMarkerPath(repoRoot)) && !existsSync(legacyLocalRepoRootMarkerPath(repoRoot)) && !existsSync(legacyAutoSpawnMarkerPath(repoRoot));
1721
1750
  } catch {
1722
1751
  return false;
1723
1752
  }
@@ -1726,14 +1755,6 @@ function isAutoSpawnEligibleBindingMode(bindingMode) {
1726
1755
  return bindingMode === "explicit_root";
1727
1756
  }
1728
1757
  function spawnHistoryImportDetached(repoRoot, options) {
1729
- const remixDir = path2.join(repoRoot, ".remix");
1730
- try {
1731
- mkdirSync(remixDir, { recursive: true });
1732
- } catch {
1733
- }
1734
- const logPath = path2.join(repoRoot, LOG_REL_PATH);
1735
- const out = openSync(logPath, "a");
1736
- const err = openSync(logPath, "a");
1737
1758
  const child = spawn(
1738
1759
  "remix",
1739
1760
  [
@@ -1750,12 +1771,12 @@ function spawnHistoryImportDetached(repoRoot, options) {
1750
1771
  ],
1751
1772
  {
1752
1773
  detached: true,
1753
- stdio: ["ignore", out, err],
1774
+ stdio: "ignore",
1754
1775
  env: { ...process.env, REMIX_HISTORY_AUTO_SPAWN: "1" }
1755
1776
  }
1756
1777
  );
1757
1778
  child.unref();
1758
- return { pid: child.pid, logPath };
1779
+ return { pid: child.pid };
1759
1780
  }
1760
1781
 
1761
1782
  // src/tools/collab/register.ts
@@ -1812,6 +1833,24 @@ function buildErrorEnvelope(tool, requestId, error) {
1812
1833
  recommendedNextActions
1813
1834
  };
1814
1835
  }
1836
+ function buildOutputValidationErrorEnvelope(tool, requestId, error) {
1837
+ return {
1838
+ schemaVersion: SCHEMA_VERSION,
1839
+ ok: false,
1840
+ tool,
1841
+ requestId: requestId ?? null,
1842
+ error: {
1843
+ code: ERROR_CODES.INTERNAL_ERROR,
1844
+ message: "Tool output failed validation against its declared MCP schema.",
1845
+ hint: error.issues.map((issue) => `${issue.path.join(".") || "output"}: ${issue.message}`).join("; "),
1846
+ retryable: false,
1847
+ category: "internal"
1848
+ },
1849
+ warnings: [],
1850
+ risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
1851
+ recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
1852
+ };
1853
+ }
1815
1854
  function registerTool(server, context, params) {
1816
1855
  const errorSchema = makeErrorSchema();
1817
1856
  server.registerTool(
@@ -1830,7 +1869,20 @@ function registerTool(server, context, params) {
1830
1869
  assertToolAccess(context.policy, params.access);
1831
1870
  const result = await params.run(rawArgs);
1832
1871
  const envelope = buildSuccessEnvelope(params.name, requestId, result);
1833
- params.outputSchema.parse(envelope);
1872
+ const parsedEnvelope = params.outputSchema.safeParse(envelope);
1873
+ if (!parsedEnvelope.success) {
1874
+ const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
1875
+ context.logger.log({
1876
+ level: "error",
1877
+ message: "tool_output_validation_failed",
1878
+ tool: params.name,
1879
+ requestId: errorEnvelope.requestId,
1880
+ durationMs: Date.now() - startedAt,
1881
+ result: "error",
1882
+ errorCode: errorEnvelope.error.code
1883
+ });
1884
+ return makeErrorResult(errorEnvelope);
1885
+ }
1834
1886
  context.logger.log({
1835
1887
  level: "info",
1836
1888
  message: "tool_completed",
@@ -1894,12 +1946,14 @@ function registerCollabTools(server, context) {
1894
1946
  try {
1895
1947
  const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
1896
1948
  const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
1897
- if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot)) {
1949
+ const resultData = result && typeof result === "object" && "data" in result && result.data && typeof result.data === "object" ? result.data : null;
1950
+ const repoFingerprint = typeof resultData?.repoFingerprint === "string" ? resultData.repoFingerprint : null;
1951
+ if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot, repoFingerprint)) {
1898
1952
  const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
1899
1953
  const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
1900
1954
  context.logger.log({
1901
1955
  level: "info",
1902
- message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath} cutoffAt=${cutoffAt}`,
1956
+ message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} cutoffAt=${cutoffAt}`,
1903
1957
  tool: "remix_collab_init",
1904
1958
  repoRoot
1905
1959
  });