@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/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
|
}
|
|
@@ -510,9 +518,6 @@ var applyInputSchema = {
|
|
|
510
518
|
confirm: z2.boolean(),
|
|
511
519
|
allowBranchMismatch: z2.boolean().optional()
|
|
512
520
|
};
|
|
513
|
-
var reAnchorInputSchema = {
|
|
514
|
-
...applyInputSchema
|
|
515
|
-
};
|
|
516
521
|
var requestMergeInputSchema = {
|
|
517
522
|
...commonRequestFieldsSchema
|
|
518
523
|
};
|
|
@@ -625,7 +630,7 @@ var initSyncDataSchema = z2.object({
|
|
|
625
630
|
repoRoot: z2.string(),
|
|
626
631
|
bindingMode: z2.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
627
632
|
createdCanonicalFamily: z2.boolean().optional(),
|
|
628
|
-
baselineStatus: z2.enum(["seeded", "existing", "
|
|
633
|
+
baselineStatus: z2.enum(["seeded", "existing", "baseline_missing", "requires_sync"]).optional()
|
|
629
634
|
});
|
|
630
635
|
var initQueuedDataSchema = z2.object({
|
|
631
636
|
queued: z2.literal(true),
|
|
@@ -673,7 +678,6 @@ var drainFinalizeQueueDataSchema = z2.object({
|
|
|
673
678
|
results: z2.array(genericRecordSchema)
|
|
674
679
|
});
|
|
675
680
|
var syncDataSchema = genericRecordSchema;
|
|
676
|
-
var reAnchorDataSchema = genericRecordSchema;
|
|
677
681
|
var requestMergeDataSchema = genericRecordSchema;
|
|
678
682
|
var mergeRequestQueueDataSchema = z2.object({
|
|
679
683
|
queue: mergeRequestQueueSchema,
|
|
@@ -749,7 +753,6 @@ var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
|
749
753
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
750
754
|
var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
|
|
751
755
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
752
|
-
var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
|
|
753
756
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
754
757
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
755
758
|
var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
|
|
@@ -776,7 +779,6 @@ import {
|
|
|
776
779
|
collabCheckout as coreCollabCheckout,
|
|
777
780
|
collabListMergeRequests as coreCollabListMergeRequests,
|
|
778
781
|
collabInit as coreCollabInit,
|
|
779
|
-
collabReAnchor as coreCollabReAnchor,
|
|
780
782
|
collabInvite as coreCollabInvite,
|
|
781
783
|
collabReconcile as coreCollabReconcile,
|
|
782
784
|
collabReject as coreCollabReject,
|
|
@@ -791,7 +793,7 @@ import { findGitRoot } from "@remixhq/core/repo";
|
|
|
791
793
|
function getRiskLevel(status) {
|
|
792
794
|
if (status.recommendedAction === "reconcile") return "high";
|
|
793
795
|
if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
|
|
794
|
-
if (status.recommendedAction === "pull" || status.
|
|
796
|
+
if (status.recommendedAction === "pull" || status.remote.incomingOpenMergeRequestCount) {
|
|
795
797
|
return "medium";
|
|
796
798
|
}
|
|
797
799
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
@@ -808,10 +810,6 @@ function getRecommendedNextActions(status) {
|
|
|
808
810
|
return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
|
|
809
811
|
case "pull":
|
|
810
812
|
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."];
|
|
811
|
-
case "re_anchor":
|
|
812
|
-
return [
|
|
813
|
-
"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."
|
|
814
|
-
];
|
|
815
813
|
case "record":
|
|
816
814
|
return [
|
|
817
815
|
"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."
|
|
@@ -896,8 +894,8 @@ async function initCollab(params) {
|
|
|
896
894
|
return {
|
|
897
895
|
data: syncResult,
|
|
898
896
|
warnings: collectResultWarnings(result),
|
|
899
|
-
recommendedNextActions: syncResult.baselineStatus === "
|
|
900
|
-
"This checkout has no local Remix baseline yet. Run
|
|
897
|
+
recommendedNextActions: syncResult.baselineStatus === "baseline_missing" ? [
|
|
898
|
+
"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."
|
|
901
899
|
] : syncResult.baselineStatus === "requires_sync" ? [
|
|
902
900
|
"Run remix_collab_sync_preview, then remix_collab_sync_apply to pull the server delta and create the first local baseline for this checkout."
|
|
903
901
|
] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
|
|
@@ -1000,26 +998,6 @@ async function syncCollab(params) {
|
|
|
1000
998
|
}
|
|
1001
999
|
};
|
|
1002
1000
|
}
|
|
1003
|
-
async function reAnchor(params) {
|
|
1004
|
-
const api = await createCollabApiClient();
|
|
1005
|
-
const result = await coreCollabReAnchor({
|
|
1006
|
-
api,
|
|
1007
|
-
cwd: params.cwd,
|
|
1008
|
-
dryRun: params.dryRun,
|
|
1009
|
-
allowBranchMismatch: params.allowBranchMismatch ?? false
|
|
1010
|
-
});
|
|
1011
|
-
return {
|
|
1012
|
-
data: result,
|
|
1013
|
-
warnings: collectWarnings(result.warnings),
|
|
1014
|
-
recommendedNextActions: params.dryRun ? [
|
|
1015
|
-
"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."
|
|
1016
|
-
] : [],
|
|
1017
|
-
logContext: {
|
|
1018
|
-
repoRoot: result.repoRoot,
|
|
1019
|
-
appId: result.currentAppId
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
}
|
|
1023
1001
|
async function requestMerge(params) {
|
|
1024
1002
|
const api = await createCollabApiClient();
|
|
1025
1003
|
const drainWarnings = await drainBeforeMutation(api);
|
|
@@ -1756,7 +1734,10 @@ function shouldAutoSpawnHistoryImport(repoRoot) {
|
|
|
1756
1734
|
return false;
|
|
1757
1735
|
}
|
|
1758
1736
|
}
|
|
1759
|
-
function
|
|
1737
|
+
function isAutoSpawnEligibleBindingMode(bindingMode) {
|
|
1738
|
+
return bindingMode === "explicit_root";
|
|
1739
|
+
}
|
|
1740
|
+
function spawnHistoryImportDetached(repoRoot, options) {
|
|
1760
1741
|
const remixDir = path2.join(repoRoot, ".remix");
|
|
1761
1742
|
try {
|
|
1762
1743
|
mkdirSync(remixDir, { recursive: true });
|
|
@@ -1772,6 +1753,8 @@ function spawnHistoryImportDetached(repoRoot) {
|
|
|
1772
1753
|
"import",
|
|
1773
1754
|
"--repo",
|
|
1774
1755
|
repoRoot,
|
|
1756
|
+
"--before",
|
|
1757
|
+
options.cutoffAt,
|
|
1775
1758
|
// Include prompt text for parity with the CLI auto-spawn path:
|
|
1776
1759
|
// first-time UX is a lot worse if the dashboard renders every
|
|
1777
1760
|
// historical row as "(prompt not uploaded)".
|
|
@@ -1841,6 +1824,24 @@ function buildErrorEnvelope(tool, requestId, error) {
|
|
|
1841
1824
|
recommendedNextActions
|
|
1842
1825
|
};
|
|
1843
1826
|
}
|
|
1827
|
+
function buildOutputValidationErrorEnvelope(tool, requestId, error) {
|
|
1828
|
+
return {
|
|
1829
|
+
schemaVersion: SCHEMA_VERSION,
|
|
1830
|
+
ok: false,
|
|
1831
|
+
tool,
|
|
1832
|
+
requestId: requestId ?? null,
|
|
1833
|
+
error: {
|
|
1834
|
+
code: ERROR_CODES.INTERNAL_ERROR,
|
|
1835
|
+
message: "Tool output failed validation against its declared MCP schema.",
|
|
1836
|
+
hint: error.issues.map((issue) => `${issue.path.join(".") || "output"}: ${issue.message}`).join("; "),
|
|
1837
|
+
retryable: false,
|
|
1838
|
+
category: "internal"
|
|
1839
|
+
},
|
|
1840
|
+
warnings: [],
|
|
1841
|
+
risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
|
|
1842
|
+
recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1844
1845
|
function registerTool(server, context, params) {
|
|
1845
1846
|
const errorSchema = makeErrorSchema();
|
|
1846
1847
|
server.registerTool(
|
|
@@ -1859,7 +1860,20 @@ function registerTool(server, context, params) {
|
|
|
1859
1860
|
assertToolAccess(context.policy, params.access);
|
|
1860
1861
|
const result = await params.run(rawArgs);
|
|
1861
1862
|
const envelope = buildSuccessEnvelope(params.name, requestId, result);
|
|
1862
|
-
params.outputSchema.
|
|
1863
|
+
const parsedEnvelope = params.outputSchema.safeParse(envelope);
|
|
1864
|
+
if (!parsedEnvelope.success) {
|
|
1865
|
+
const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
|
|
1866
|
+
context.logger.log({
|
|
1867
|
+
level: "error",
|
|
1868
|
+
message: "tool_output_validation_failed",
|
|
1869
|
+
tool: params.name,
|
|
1870
|
+
requestId: errorEnvelope.requestId,
|
|
1871
|
+
durationMs: Date.now() - startedAt,
|
|
1872
|
+
result: "error",
|
|
1873
|
+
errorCode: errorEnvelope.error.code
|
|
1874
|
+
});
|
|
1875
|
+
return makeErrorResult(errorEnvelope);
|
|
1876
|
+
}
|
|
1863
1877
|
context.logger.log({
|
|
1864
1878
|
level: "info",
|
|
1865
1879
|
message: "tool_completed",
|
|
@@ -1922,11 +1936,13 @@ function registerCollabTools(server, context) {
|
|
|
1922
1936
|
});
|
|
1923
1937
|
try {
|
|
1924
1938
|
const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
|
|
1925
|
-
|
|
1926
|
-
|
|
1939
|
+
const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
|
|
1940
|
+
if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot)) {
|
|
1941
|
+
const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1942
|
+
const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
|
|
1927
1943
|
context.logger.log({
|
|
1928
1944
|
level: "info",
|
|
1929
|
-
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath}`,
|
|
1945
|
+
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath} cutoffAt=${cutoffAt}`,
|
|
1930
1946
|
tool: "remix_collab_init",
|
|
1931
1947
|
repoRoot
|
|
1932
1948
|
});
|
|
@@ -2030,31 +2046,6 @@ function registerCollabTools(server, context) {
|
|
|
2030
2046
|
return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
2031
2047
|
}
|
|
2032
2048
|
});
|
|
2033
|
-
registerTool(server, context, {
|
|
2034
|
-
name: "remix_collab_re_anchor_preview",
|
|
2035
|
-
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.",
|
|
2036
|
-
access: "read",
|
|
2037
|
-
inputSchema: previewInputSchema,
|
|
2038
|
-
outputSchema: reAnchorSuccessSchema,
|
|
2039
|
-
run: async (args) => {
|
|
2040
|
-
const input = z3.object(previewInputSchema).parse(args);
|
|
2041
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2042
|
-
return reAnchor({ cwd, dryRun: true });
|
|
2043
|
-
}
|
|
2044
|
-
});
|
|
2045
|
-
registerTool(server, context, {
|
|
2046
|
-
name: "remix_collab_re_anchor_apply",
|
|
2047
|
-
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.",
|
|
2048
|
-
access: "local_write",
|
|
2049
|
-
inputSchema: reAnchorInputSchema,
|
|
2050
|
-
outputSchema: reAnchorSuccessSchema,
|
|
2051
|
-
run: async (args) => {
|
|
2052
|
-
const input = z3.object(reAnchorInputSchema).parse(args);
|
|
2053
|
-
assertConfirm(input.confirm, "remix_collab_re_anchor_apply");
|
|
2054
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2055
|
-
return reAnchor({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
2056
|
-
}
|
|
2057
|
-
});
|
|
2058
2049
|
registerTool(server, context, {
|
|
2059
2050
|
name: "remix_collab_request_merge",
|
|
2060
2051
|
description: "Open a prompt-backed Remix merge request from the current bound repository to its upstream app instead of merging locally with raw git.",
|