@remixhq/mcp 0.1.17 → 0.1.19
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 +56 -65
- package/dist/cli.js.map +1 -1
- package/dist/index.js +56 -65
- package/dist/index.js.map +1 -1
- package/dist/server.js +56 -65
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
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
|
}
|
|
@@ -506,9 +514,6 @@ var applyInputSchema = {
|
|
|
506
514
|
confirm: z2.boolean(),
|
|
507
515
|
allowBranchMismatch: z2.boolean().optional()
|
|
508
516
|
};
|
|
509
|
-
var reAnchorInputSchema = {
|
|
510
|
-
...applyInputSchema
|
|
511
|
-
};
|
|
512
517
|
var requestMergeInputSchema = {
|
|
513
518
|
...commonRequestFieldsSchema
|
|
514
519
|
};
|
|
@@ -621,7 +626,7 @@ var initSyncDataSchema = z2.object({
|
|
|
621
626
|
repoRoot: z2.string(),
|
|
622
627
|
bindingMode: z2.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
623
628
|
createdCanonicalFamily: z2.boolean().optional(),
|
|
624
|
-
baselineStatus: z2.enum(["seeded", "existing", "
|
|
629
|
+
baselineStatus: z2.enum(["seeded", "existing", "baseline_missing", "requires_sync"]).optional()
|
|
625
630
|
});
|
|
626
631
|
var initQueuedDataSchema = z2.object({
|
|
627
632
|
queued: z2.literal(true),
|
|
@@ -669,7 +674,6 @@ var drainFinalizeQueueDataSchema = z2.object({
|
|
|
669
674
|
results: z2.array(genericRecordSchema)
|
|
670
675
|
});
|
|
671
676
|
var syncDataSchema = genericRecordSchema;
|
|
672
|
-
var reAnchorDataSchema = genericRecordSchema;
|
|
673
677
|
var requestMergeDataSchema = genericRecordSchema;
|
|
674
678
|
var mergeRequestQueueDataSchema = z2.object({
|
|
675
679
|
queue: mergeRequestQueueSchema,
|
|
@@ -745,7 +749,6 @@ var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
|
745
749
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
746
750
|
var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
|
|
747
751
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
748
|
-
var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
|
|
749
752
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
750
753
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
751
754
|
var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
|
|
@@ -772,7 +775,6 @@ import {
|
|
|
772
775
|
collabCheckout as coreCollabCheckout,
|
|
773
776
|
collabListMergeRequests as coreCollabListMergeRequests,
|
|
774
777
|
collabInit as coreCollabInit,
|
|
775
|
-
collabReAnchor as coreCollabReAnchor,
|
|
776
778
|
collabInvite as coreCollabInvite,
|
|
777
779
|
collabReconcile as coreCollabReconcile,
|
|
778
780
|
collabReject as coreCollabReject,
|
|
@@ -787,7 +789,7 @@ import { findGitRoot } from "@remixhq/core/repo";
|
|
|
787
789
|
function getRiskLevel(status) {
|
|
788
790
|
if (status.recommendedAction === "reconcile") return "high";
|
|
789
791
|
if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
|
|
790
|
-
if (status.recommendedAction === "pull" || status.
|
|
792
|
+
if (status.recommendedAction === "pull" || status.remote.incomingOpenMergeRequestCount) {
|
|
791
793
|
return "medium";
|
|
792
794
|
}
|
|
793
795
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
@@ -804,10 +806,6 @@ function getRecommendedNextActions(status) {
|
|
|
804
806
|
return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
|
|
805
807
|
case "pull":
|
|
806
808
|
return ["Run remix_collab_sync_preview, then remix_collab_sync_apply if the preview is acceptable. This pulls the server delta into the local working tree without rewriting local git history."];
|
|
807
|
-
case "re_anchor":
|
|
808
|
-
return [
|
|
809
|
-
"Run remix_collab_re_anchor_preview, then remix_collab_re_anchor_apply. This seeds a local Remix baseline. It is required because no local baseline exists for this lane yet (fresh clone, deleted .remix/ state, or first init didn't seed) \u2014 not because of any specific git operation. After it succeeds, automatic hook recording can capture completed turns."
|
|
810
|
-
];
|
|
811
809
|
case "record":
|
|
812
810
|
return [
|
|
813
811
|
"No MCP recording tool is required. Automatic hook finalization will capture the local boundary at the end of the completed turn; this covers agent edits, manual user edits, git commit, git pull, git merge, git rebase, and git reset."
|
|
@@ -892,8 +890,8 @@ async function initCollab(params) {
|
|
|
892
890
|
return {
|
|
893
891
|
data: syncResult,
|
|
894
892
|
warnings: collectResultWarnings(result),
|
|
895
|
-
recommendedNextActions: syncResult.baselineStatus === "
|
|
896
|
-
"This checkout has no local Remix baseline yet. Run
|
|
893
|
+
recommendedNextActions: syncResult.baselineStatus === "baseline_missing" ? [
|
|
894
|
+
"This checkout has no local Remix revision baseline yet. Run remix_collab_init or remix_collab_sync_preview/apply to seed one. After it succeeds, automatic hook recording can capture completed turns."
|
|
897
895
|
] : syncResult.baselineStatus === "requires_sync" ? [
|
|
898
896
|
"Run remix_collab_sync_preview, then remix_collab_sync_apply to pull the server delta and create the first local baseline for this checkout."
|
|
899
897
|
] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
|
|
@@ -996,26 +994,6 @@ async function syncCollab(params) {
|
|
|
996
994
|
}
|
|
997
995
|
};
|
|
998
996
|
}
|
|
999
|
-
async function reAnchor(params) {
|
|
1000
|
-
const api = await createCollabApiClient();
|
|
1001
|
-
const result = await coreCollabReAnchor({
|
|
1002
|
-
api,
|
|
1003
|
-
cwd: params.cwd,
|
|
1004
|
-
dryRun: params.dryRun,
|
|
1005
|
-
allowBranchMismatch: params.allowBranchMismatch ?? false
|
|
1006
|
-
});
|
|
1007
|
-
return {
|
|
1008
|
-
data: result,
|
|
1009
|
-
warnings: collectWarnings(result.warnings),
|
|
1010
|
-
recommendedNextActions: params.dryRun ? [
|
|
1011
|
-
"Run remix_collab_re_anchor_apply with confirm=true to seed a local Remix baseline for this checkout. Re-anchor is for missing-baseline cases only and does not replace automatic hook recording for ordinary local content changes."
|
|
1012
|
-
] : [],
|
|
1013
|
-
logContext: {
|
|
1014
|
-
repoRoot: result.repoRoot,
|
|
1015
|
-
appId: result.currentAppId
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
997
|
async function requestMerge(params) {
|
|
1020
998
|
const api = await createCollabApiClient();
|
|
1021
999
|
const drainWarnings = await drainBeforeMutation(api);
|
|
@@ -1752,7 +1730,10 @@ function shouldAutoSpawnHistoryImport(repoRoot) {
|
|
|
1752
1730
|
return false;
|
|
1753
1731
|
}
|
|
1754
1732
|
}
|
|
1755
|
-
function
|
|
1733
|
+
function isAutoSpawnEligibleBindingMode(bindingMode) {
|
|
1734
|
+
return bindingMode === "explicit_root";
|
|
1735
|
+
}
|
|
1736
|
+
function spawnHistoryImportDetached(repoRoot, options) {
|
|
1756
1737
|
const remixDir = path2.join(repoRoot, ".remix");
|
|
1757
1738
|
try {
|
|
1758
1739
|
mkdirSync(remixDir, { recursive: true });
|
|
@@ -1768,6 +1749,8 @@ function spawnHistoryImportDetached(repoRoot) {
|
|
|
1768
1749
|
"import",
|
|
1769
1750
|
"--repo",
|
|
1770
1751
|
repoRoot,
|
|
1752
|
+
"--before",
|
|
1753
|
+
options.cutoffAt,
|
|
1771
1754
|
// Include prompt text for parity with the CLI auto-spawn path:
|
|
1772
1755
|
// first-time UX is a lot worse if the dashboard renders every
|
|
1773
1756
|
// historical row as "(prompt not uploaded)".
|
|
@@ -1837,6 +1820,24 @@ function buildErrorEnvelope(tool, requestId, error) {
|
|
|
1837
1820
|
recommendedNextActions
|
|
1838
1821
|
};
|
|
1839
1822
|
}
|
|
1823
|
+
function buildOutputValidationErrorEnvelope(tool, requestId, error) {
|
|
1824
|
+
return {
|
|
1825
|
+
schemaVersion: SCHEMA_VERSION,
|
|
1826
|
+
ok: false,
|
|
1827
|
+
tool,
|
|
1828
|
+
requestId: requestId ?? null,
|
|
1829
|
+
error: {
|
|
1830
|
+
code: ERROR_CODES.INTERNAL_ERROR,
|
|
1831
|
+
message: "Tool output failed validation against its declared MCP schema.",
|
|
1832
|
+
hint: error.issues.map((issue) => `${issue.path.join(".") || "output"}: ${issue.message}`).join("; "),
|
|
1833
|
+
retryable: false,
|
|
1834
|
+
category: "internal"
|
|
1835
|
+
},
|
|
1836
|
+
warnings: [],
|
|
1837
|
+
risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
|
|
1838
|
+
recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1840
1841
|
function registerTool(server, context, params) {
|
|
1841
1842
|
const errorSchema = makeErrorSchema();
|
|
1842
1843
|
server.registerTool(
|
|
@@ -1855,7 +1856,20 @@ function registerTool(server, context, params) {
|
|
|
1855
1856
|
assertToolAccess(context.policy, params.access);
|
|
1856
1857
|
const result = await params.run(rawArgs);
|
|
1857
1858
|
const envelope = buildSuccessEnvelope(params.name, requestId, result);
|
|
1858
|
-
params.outputSchema.
|
|
1859
|
+
const parsedEnvelope = params.outputSchema.safeParse(envelope);
|
|
1860
|
+
if (!parsedEnvelope.success) {
|
|
1861
|
+
const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
|
|
1862
|
+
context.logger.log({
|
|
1863
|
+
level: "error",
|
|
1864
|
+
message: "tool_output_validation_failed",
|
|
1865
|
+
tool: params.name,
|
|
1866
|
+
requestId: errorEnvelope.requestId,
|
|
1867
|
+
durationMs: Date.now() - startedAt,
|
|
1868
|
+
result: "error",
|
|
1869
|
+
errorCode: errorEnvelope.error.code
|
|
1870
|
+
});
|
|
1871
|
+
return makeErrorResult(errorEnvelope);
|
|
1872
|
+
}
|
|
1859
1873
|
context.logger.log({
|
|
1860
1874
|
level: "info",
|
|
1861
1875
|
message: "tool_completed",
|
|
@@ -1918,11 +1932,13 @@ function registerCollabTools(server, context) {
|
|
|
1918
1932
|
});
|
|
1919
1933
|
try {
|
|
1920
1934
|
const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
|
|
1921
|
-
|
|
1922
|
-
|
|
1935
|
+
const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
|
|
1936
|
+
if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot)) {
|
|
1937
|
+
const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1938
|
+
const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
|
|
1923
1939
|
context.logger.log({
|
|
1924
1940
|
level: "info",
|
|
1925
|
-
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath}`,
|
|
1941
|
+
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath} cutoffAt=${cutoffAt}`,
|
|
1926
1942
|
tool: "remix_collab_init",
|
|
1927
1943
|
repoRoot
|
|
1928
1944
|
});
|
|
@@ -2026,31 +2042,6 @@ function registerCollabTools(server, context) {
|
|
|
2026
2042
|
return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
2027
2043
|
}
|
|
2028
2044
|
});
|
|
2029
|
-
registerTool(server, context, {
|
|
2030
|
-
name: "remix_collab_re_anchor_preview",
|
|
2031
|
-
description: "Preview whether this checkout needs a fresh local Remix baseline. Use only when status reports `re_anchor` (no local baseline exists for this lane yet \u2014 fresh clone, deleted `.remix/` state, or first init didn't seed). Re-anchor does not replace automatic hook recording; ordinary local content changes (including merges, pulls, and rebases) are captured at the completed-turn boundary, not by re-anchor.",
|
|
2032
|
-
access: "read",
|
|
2033
|
-
inputSchema: previewInputSchema,
|
|
2034
|
-
outputSchema: reAnchorSuccessSchema,
|
|
2035
|
-
run: async (args) => {
|
|
2036
|
-
const input = z3.object(previewInputSchema).parse(args);
|
|
2037
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2038
|
-
return reAnchor({ cwd, dryRun: true });
|
|
2039
|
-
}
|
|
2040
|
-
});
|
|
2041
|
-
registerTool(server, context, {
|
|
2042
|
-
name: "remix_collab_re_anchor_apply",
|
|
2043
|
-
description: "Establish a local Remix baseline for the current checkout against the existing app head, without rewriting the local checkout afterward. Required only when status reports `re_anchor` (missing local baseline). It does not replace automatic hook recording \u2014 local commits, pulls, merges, and rebases are still captured at the completed-turn boundary.",
|
|
2044
|
-
access: "local_write",
|
|
2045
|
-
inputSchema: reAnchorInputSchema,
|
|
2046
|
-
outputSchema: reAnchorSuccessSchema,
|
|
2047
|
-
run: async (args) => {
|
|
2048
|
-
const input = z3.object(reAnchorInputSchema).parse(args);
|
|
2049
|
-
assertConfirm(input.confirm, "remix_collab_re_anchor_apply");
|
|
2050
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2051
|
-
return reAnchor({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
2052
|
-
}
|
|
2053
|
-
});
|
|
2054
2045
|
registerTool(server, context, {
|
|
2055
2046
|
name: "remix_collab_request_merge",
|
|
2056
2047
|
description: "Open a prompt-backed Remix merge request from the current bound repository to its upstream app instead of merging locally with raw git.",
|