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