@remixhq/mcp 0.1.12 → 0.1.13
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 +231 -54
- package/dist/cli.js.map +1 -1
- package/dist/index.js +221 -50
- package/dist/index.js.map +1 -1
- package/dist/server.js +221 -50
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -352,14 +352,6 @@ function assertConfirm(confirm, operation) {
|
|
|
352
352
|
if (confirm) return;
|
|
353
353
|
throw createPolicyError(`${operation} requires explicit confirmation.`, "Pass confirm=true to run this tool.");
|
|
354
354
|
}
|
|
355
|
-
function assertDiffWithinLimit(policy, diff) {
|
|
356
|
-
const sizeBytes = Buffer.byteLength(diff, "utf8");
|
|
357
|
-
if (sizeBytes <= policy.maxDiffBytes) return;
|
|
358
|
-
throw createPolicyError(
|
|
359
|
-
"Diff exceeds the configured maximum size for Remix MCP.",
|
|
360
|
-
`Configured limit=${policy.maxDiffBytes} bytes actual=${sizeBytes} bytes.`
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
355
|
|
|
364
356
|
// src/bootstrap/context.ts
|
|
365
357
|
function createServerContext(params) {
|
|
@@ -507,8 +499,6 @@ var finalizeTurnInputSchema = {
|
|
|
507
499
|
...commonRequestFieldsSchema,
|
|
508
500
|
prompt: z2.string().trim().min(1),
|
|
509
501
|
assistantResponse: z2.string().trim().min(1),
|
|
510
|
-
diffSource: z2.enum(["worktree", "external"]).optional(),
|
|
511
|
-
externalDiff: z2.string().optional(),
|
|
512
502
|
sync: z2.boolean().optional(),
|
|
513
503
|
allowBranchMismatch: z2.boolean().optional(),
|
|
514
504
|
idempotencyKey: z2.string().trim().min(1).optional()
|
|
@@ -516,11 +506,17 @@ var finalizeTurnInputSchema = {
|
|
|
516
506
|
var previewInputSchema = {
|
|
517
507
|
...commonRequestFieldsSchema
|
|
518
508
|
};
|
|
509
|
+
var drainFinalizeQueueInputSchema = {
|
|
510
|
+
...commonRequestFieldsSchema
|
|
511
|
+
};
|
|
519
512
|
var applyInputSchema = {
|
|
520
513
|
...commonRequestFieldsSchema,
|
|
521
514
|
confirm: z2.boolean(),
|
|
522
515
|
allowBranchMismatch: z2.boolean().optional()
|
|
523
516
|
};
|
|
517
|
+
var reAnchorInputSchema = {
|
|
518
|
+
...applyInputSchema
|
|
519
|
+
};
|
|
524
520
|
var requestMergeInputSchema = {
|
|
525
521
|
...commonRequestFieldsSchema
|
|
526
522
|
};
|
|
@@ -632,7 +628,8 @@ var initDataSchema = z2.object({
|
|
|
632
628
|
bindingPath: z2.string(),
|
|
633
629
|
repoRoot: z2.string(),
|
|
634
630
|
bindingMode: z2.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
635
|
-
createdCanonicalFamily: z2.boolean().optional()
|
|
631
|
+
createdCanonicalFamily: z2.boolean().optional(),
|
|
632
|
+
baselineStatus: z2.enum(["seeded", "existing", "requires_re_anchor", "requires_sync"]).optional()
|
|
636
633
|
});
|
|
637
634
|
var listDataSchema = z2.object({
|
|
638
635
|
apps: genericArraySchema,
|
|
@@ -655,19 +652,26 @@ var checkoutDataSchema = z2.object({
|
|
|
655
652
|
repoRoot: z2.string()
|
|
656
653
|
});
|
|
657
654
|
var addDataSchema = z2.object({
|
|
658
|
-
changeStep: genericRecordSchema
|
|
659
|
-
autoSync: genericRecordSchema
|
|
655
|
+
changeStep: genericRecordSchema
|
|
660
656
|
});
|
|
661
657
|
var recordTurnDataSchema = genericRecordSchema;
|
|
662
658
|
var finalizeTurnDataSchema = z2.object({
|
|
663
659
|
mode: z2.enum(["changed_turn", "no_diff_turn"]),
|
|
664
660
|
idempotencyKey: z2.string().min(1),
|
|
661
|
+
queued: z2.boolean(),
|
|
662
|
+
jobId: z2.string().nullable(),
|
|
663
|
+
repoState: z2.string().nullable(),
|
|
665
664
|
changeStep: genericRecordSchema.nullable(),
|
|
666
665
|
collabTurn: genericRecordSchema.nullable(),
|
|
667
666
|
autoSync: genericRecordSchema.nullable(),
|
|
668
667
|
warnings: z2.array(z2.string())
|
|
669
668
|
});
|
|
669
|
+
var drainFinalizeQueueDataSchema = z2.object({
|
|
670
|
+
processed: z2.number().int().nonnegative(),
|
|
671
|
+
results: z2.array(genericRecordSchema)
|
|
672
|
+
});
|
|
670
673
|
var syncDataSchema = genericRecordSchema;
|
|
674
|
+
var reAnchorDataSchema = genericRecordSchema;
|
|
671
675
|
var requestMergeDataSchema = genericRecordSchema;
|
|
672
676
|
var mergeRequestQueueDataSchema = z2.object({
|
|
673
677
|
queue: mergeRequestQueueSchema,
|
|
@@ -742,7 +746,9 @@ var checkoutSuccessSchema = makeSuccessSchema(checkoutDataSchema);
|
|
|
742
746
|
var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
743
747
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
744
748
|
var finalizeTurnSuccessSchema = makeSuccessSchema(finalizeTurnDataSchema);
|
|
749
|
+
var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
|
|
745
750
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
751
|
+
var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
|
|
746
752
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
747
753
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
748
754
|
var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
|
|
@@ -760,17 +766,18 @@ var accessDebugSuccessSchema = makeSuccessSchema(accessDebugDataSchema);
|
|
|
760
766
|
var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema);
|
|
761
767
|
|
|
762
768
|
// src/domain/coreAdapter.ts
|
|
769
|
+
import { spawn } from "child_process";
|
|
763
770
|
import {
|
|
764
771
|
collabList as coreCollabList,
|
|
765
772
|
collabListMembers as coreCollabListMembers,
|
|
766
773
|
collabUpdateMemberRole as coreCollabUpdateMemberRole,
|
|
767
|
-
|
|
774
|
+
drainPendingFinalizeQueue as coreDrainPendingFinalizeQueue,
|
|
768
775
|
collabFinalizeTurn as coreCollabFinalizeTurn,
|
|
769
|
-
collabRecordTurn as coreCollabRecordTurn,
|
|
770
776
|
collabApprove as coreCollabApprove,
|
|
771
777
|
collabCheckout as coreCollabCheckout,
|
|
772
778
|
collabListMergeRequests as coreCollabListMergeRequests,
|
|
773
779
|
collabInit as coreCollabInit,
|
|
780
|
+
collabReAnchor as coreCollabReAnchor,
|
|
774
781
|
collabInvite as coreCollabInvite,
|
|
775
782
|
collabReconcile as coreCollabReconcile,
|
|
776
783
|
collabReject as coreCollabReject,
|
|
@@ -781,11 +788,13 @@ import {
|
|
|
781
788
|
collabSyncUpstream as coreCollabSyncUpstream,
|
|
782
789
|
collabView as coreCollabView
|
|
783
790
|
} from "@remixhq/core/collab";
|
|
784
|
-
import { findGitRoot
|
|
791
|
+
import { findGitRoot } from "@remixhq/core/repo";
|
|
785
792
|
function getRiskLevel(status) {
|
|
786
793
|
if (status.recommendedAction === "reconcile") return "high";
|
|
787
|
-
if (status.recommendedAction === "choose_family") return "medium";
|
|
788
|
-
if (status.recommendedAction === "
|
|
794
|
+
if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
|
|
795
|
+
if (status.recommendedAction === "pull" || status.recommendedAction === "re_anchor" || status.remote.incomingOpenMergeRequestCount) {
|
|
796
|
+
return "medium";
|
|
797
|
+
}
|
|
789
798
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
790
799
|
return "low";
|
|
791
800
|
}
|
|
@@ -798,10 +807,16 @@ function getRecommendedNextActions(status) {
|
|
|
798
807
|
switch (status.recommendedAction) {
|
|
799
808
|
case "init":
|
|
800
809
|
return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
|
|
801
|
-
case "
|
|
802
|
-
return ["Run remix_collab_sync_preview, then remix_collab_sync_apply if the preview is acceptable.
|
|
810
|
+
case "pull":
|
|
811
|
+
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."];
|
|
812
|
+
case "re_anchor":
|
|
813
|
+
return ["Run remix_collab_re_anchor_preview, then remix_collab_re_anchor_apply to re-anchor the lane after manual Git/GitHub history movement."];
|
|
803
814
|
case "reconcile":
|
|
804
|
-
return ["Run remix_collab_reconcile_preview before attempting remix_collab_reconcile_apply. Reconcile
|
|
815
|
+
return ["Run remix_collab_reconcile_preview before attempting remix_collab_reconcile_apply. Reconcile now routes through the explicit Remix recovery/re-anchor flow for diverged state."];
|
|
816
|
+
case "await_finalize":
|
|
817
|
+
return [
|
|
818
|
+
"Run remix_collab_drain_finalize_queue before merge-related or recovery flows. finalize_turn is queued only until the local finalize queue is drained."
|
|
819
|
+
];
|
|
805
820
|
case "review_queue":
|
|
806
821
|
return ["Run remix_collab_review_queue to inspect reviewable merge requests instead of using local git merge flows."];
|
|
807
822
|
case "choose_family":
|
|
@@ -835,6 +850,17 @@ function truncateText(value, maxChars) {
|
|
|
835
850
|
originalChars: value.length
|
|
836
851
|
};
|
|
837
852
|
}
|
|
853
|
+
function spawnFinalizeQueueDrainer() {
|
|
854
|
+
const entrypoint = process.argv[1];
|
|
855
|
+
if (!entrypoint) return false;
|
|
856
|
+
const child = spawn(process.execPath, [...process.execArgv, entrypoint, "--drain-finalize-queue"], {
|
|
857
|
+
detached: true,
|
|
858
|
+
stdio: "ignore",
|
|
859
|
+
env: process.env
|
|
860
|
+
});
|
|
861
|
+
child.unref();
|
|
862
|
+
return true;
|
|
863
|
+
}
|
|
838
864
|
async function getStatus(params) {
|
|
839
865
|
const api = params.includeRemote ? await createCollabApiClient() : null;
|
|
840
866
|
const status = await coreCollabStatus({
|
|
@@ -865,7 +891,11 @@ async function initCollab(params) {
|
|
|
865
891
|
return {
|
|
866
892
|
data: result,
|
|
867
893
|
warnings: collectResultWarnings(result),
|
|
868
|
-
recommendedNextActions:
|
|
894
|
+
recommendedNextActions: result.baselineStatus === "requires_re_anchor" ? [
|
|
895
|
+
"Run remix_collab_re_anchor_preview, then remix_collab_re_anchor_apply to anchor this checkout before recording turns."
|
|
896
|
+
] : result.baselineStatus === "requires_sync" ? [
|
|
897
|
+
"Run remix_collab_sync_preview, then remix_collab_sync_apply to pull the server delta and create the first local baseline for this checkout."
|
|
898
|
+
] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
|
|
869
899
|
logContext: {
|
|
870
900
|
repoRoot: result.repoRoot,
|
|
871
901
|
appId: result.appId
|
|
@@ -935,23 +965,44 @@ async function finalizeCollabTurn(params) {
|
|
|
935
965
|
cwd: params.cwd,
|
|
936
966
|
prompt: params.prompt,
|
|
937
967
|
assistantResponse: params.assistantResponse,
|
|
938
|
-
diff: params.externalDiff ?? null,
|
|
939
|
-
diffSource: params.diffSource,
|
|
940
968
|
sync: params.sync,
|
|
941
969
|
allowBranchMismatch: params.allowBranchMismatch ?? false,
|
|
942
970
|
idempotencyKey: params.idempotencyKey ?? null,
|
|
943
971
|
actor: params.agent
|
|
944
972
|
});
|
|
973
|
+
if (result.queued) {
|
|
974
|
+
if (!spawnFinalizeQueueDrainer()) {
|
|
975
|
+
await coreDrainPendingFinalizeQueue({ api });
|
|
976
|
+
}
|
|
977
|
+
}
|
|
945
978
|
return {
|
|
946
979
|
data: result,
|
|
947
980
|
warnings: result.warnings,
|
|
948
|
-
recommendedNextActions: [],
|
|
981
|
+
recommendedNextActions: result.queued ? ["Run remix_collab_drain_finalize_queue before merge-related flows if you need this queued turn recorded immediately."] : [],
|
|
949
982
|
logContext: {
|
|
950
983
|
repoRoot,
|
|
951
984
|
appId: result.changeStep?.appId ?? result.collabTurn?.appId ?? null
|
|
952
985
|
}
|
|
953
986
|
};
|
|
954
987
|
}
|
|
988
|
+
async function drainFinalizeQueue(params) {
|
|
989
|
+
const api = await createCollabApiClient();
|
|
990
|
+
const repoRoot = await findGitRoot(params.cwd);
|
|
991
|
+
const results = await coreDrainPendingFinalizeQueue({ api });
|
|
992
|
+
const warnings = results.flatMap((result) => collectResultWarnings(result));
|
|
993
|
+
return {
|
|
994
|
+
data: {
|
|
995
|
+
processed: results.length,
|
|
996
|
+
results
|
|
997
|
+
},
|
|
998
|
+
warnings,
|
|
999
|
+
recommendedNextActions: [],
|
|
1000
|
+
logContext: {
|
|
1001
|
+
repoRoot,
|
|
1002
|
+
appId: null
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
955
1006
|
async function syncCollab(params) {
|
|
956
1007
|
const api = await createCollabApiClient();
|
|
957
1008
|
const result = await coreCollabSync({
|
|
@@ -963,12 +1014,33 @@ async function syncCollab(params) {
|
|
|
963
1014
|
return {
|
|
964
1015
|
data: result,
|
|
965
1016
|
warnings: collectResultWarnings(result),
|
|
966
|
-
recommendedNextActions: params.dryRun ? ["Run remix_collab_sync_apply with confirm=true to apply this
|
|
1017
|
+
recommendedNextActions: params.dryRun ? result.status === "delta_ready" ? ["Run remix_collab_sync_apply with confirm=true to apply this server delta into the local working tree."] : result.status === "base_unknown" ? [
|
|
1018
|
+
"Direct pull is unavailable because Remix cannot diff from the last acknowledged server head.",
|
|
1019
|
+
"Run remix_collab_reconcile_preview next to inspect recovery options before applying any recovery flow."
|
|
1020
|
+
] : [] : [],
|
|
967
1021
|
logContext: {
|
|
968
1022
|
repoRoot: result.repoRoot
|
|
969
1023
|
}
|
|
970
1024
|
};
|
|
971
1025
|
}
|
|
1026
|
+
async function reAnchor(params) {
|
|
1027
|
+
const api = await createCollabApiClient();
|
|
1028
|
+
const result = await coreCollabReAnchor({
|
|
1029
|
+
api,
|
|
1030
|
+
cwd: params.cwd,
|
|
1031
|
+
dryRun: params.dryRun,
|
|
1032
|
+
allowBranchMismatch: params.allowBranchMismatch ?? false
|
|
1033
|
+
});
|
|
1034
|
+
return {
|
|
1035
|
+
data: result,
|
|
1036
|
+
warnings: collectWarnings(result.warnings),
|
|
1037
|
+
recommendedNextActions: params.dryRun ? ["Run remix_collab_re_anchor_apply with confirm=true to re-anchor this lane after manual Git/GitHub history movement."] : [],
|
|
1038
|
+
logContext: {
|
|
1039
|
+
repoRoot: result.repoRoot,
|
|
1040
|
+
appId: result.currentAppId
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
972
1044
|
async function requestMerge(params) {
|
|
973
1045
|
const api = await createCollabApiClient();
|
|
974
1046
|
const result = await coreCollabRequestMerge({
|
|
@@ -1142,8 +1214,8 @@ async function reconcile(params) {
|
|
|
1142
1214
|
return {
|
|
1143
1215
|
data: result,
|
|
1144
1216
|
warnings: collectWarnings(result.warnings),
|
|
1145
|
-
recommendedNextActions: params.dryRun ? ["Run remix_collab_reconcile_apply with confirm=true only if the preview is acceptable.
|
|
1146
|
-
risks: params.dryRun ? ["Reconcile
|
|
1217
|
+
recommendedNextActions: params.dryRun ? ["Run remix_collab_reconcile_apply with confirm=true only if the preview is acceptable. This is the explicit Remix recovery flow for diverged state."] : [],
|
|
1218
|
+
risks: params.dryRun ? ["Reconcile may upload local history to re-anchor the server lane before future recording continues."] : [],
|
|
1147
1219
|
logContext: {
|
|
1148
1220
|
repoRoot: result.repoRoot ?? null
|
|
1149
1221
|
}
|
|
@@ -1719,9 +1791,6 @@ function buildSuccessEnvelope(tool, requestId, result) {
|
|
|
1719
1791
|
};
|
|
1720
1792
|
}
|
|
1721
1793
|
function deriveErrorRisks(tool, normalized) {
|
|
1722
|
-
if (isFinalizeTurnLocalSyncFailure(tool, normalized)) {
|
|
1723
|
-
return ["The change step succeeded remotely, but the local repository may need manual recovery or a follow-up sync."];
|
|
1724
|
-
}
|
|
1725
1794
|
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
1726
1795
|
return ["A policy guard blocked a potentially destructive or state-mutating operation."];
|
|
1727
1796
|
}
|
|
@@ -1733,16 +1802,9 @@ function deriveErrorRisks(tool, normalized) {
|
|
|
1733
1802
|
}
|
|
1734
1803
|
return [];
|
|
1735
1804
|
}
|
|
1736
|
-
function isFinalizeTurnLocalSyncFailure(tool, normalized) {
|
|
1737
|
-
return tool === "remix_collab_finalize_turn" && normalized.message === "Change step succeeded remotely, but automatic local sync failed.";
|
|
1738
|
-
}
|
|
1739
1805
|
function buildErrorEnvelope(tool, requestId, error) {
|
|
1740
1806
|
const normalized = normalizeToolError(error);
|
|
1741
|
-
const recommendedNextActions =
|
|
1742
|
-
"Run `remix_collab_status` to confirm the bound repo state before attempting recovery.",
|
|
1743
|
-
"Run `remix_collab_sync_preview` next, then `remix_collab_sync_apply` with `confirm=true` if the preview looks correct.",
|
|
1744
|
-
"Inspect `error.hint` for any preserved diff backup path before retrying local recovery, and do not rerun `remix_collab_finalize_turn` immediately."
|
|
1745
|
-
] : normalized.code === "AUTH_REQUIRED" ? ["Set COMERGE_ACCESS_TOKEN, then retry the tool call."] : normalized.code === "REPO_LOCK_TIMEOUT" ? ["Wait for the active Remix mutation to finish, then retry the tool call."] : normalized.code === "REPO_STATE_CHANGED_DURING_OPERATION" ? ["Review local repository changes, then rerun the tool once the worktree is stable."] : normalized.code === "PREFERRED_BRANCH_MISMATCH" ? ["Switch to the repository's preferred Remix branch, or rerun with allowBranchMismatch=true if intentional."] : [];
|
|
1807
|
+
const recommendedNextActions = normalized.code === "AUTH_REQUIRED" ? ["Set COMERGE_ACCESS_TOKEN, then retry the tool call."] : normalized.code === "REPO_LOCK_TIMEOUT" ? ["Wait for the active Remix mutation to finish, then retry the tool call."] : normalized.code === "REPO_STATE_CHANGED_DURING_OPERATION" ? ["Review local repository changes, then rerun the tool once the worktree is stable."] : normalized.code === "PREFERRED_BRANCH_MISMATCH" ? ["Switch to the repository's preferred Remix branch, or rerun with allowBranchMismatch=true if intentional."] : [];
|
|
1746
1808
|
return {
|
|
1747
1809
|
schemaVersion: SCHEMA_VERSION,
|
|
1748
1810
|
ok: false,
|
|
@@ -1888,7 +1950,7 @@ function registerCollabTools(server, context) {
|
|
|
1888
1950
|
});
|
|
1889
1951
|
registerTool(server, context, {
|
|
1890
1952
|
name: "remix_collab_finalize_turn",
|
|
1891
|
-
description: "Primary turn recorder for the current bound repository. Call this exactly once before the final response; it
|
|
1953
|
+
description: "Primary turn recorder for the current bound repository. Call this exactly once before the final response; it captures the current boundary locally and queues remote processing. Queued only: no remote change step exists yet until the finalize queue is drained.",
|
|
1892
1954
|
access: "local_write",
|
|
1893
1955
|
inputSchema: finalizeTurnInputSchema,
|
|
1894
1956
|
outputSchema: finalizeTurnSuccessSchema,
|
|
@@ -1896,15 +1958,10 @@ function registerCollabTools(server, context) {
|
|
|
1896
1958
|
run: async (args) => {
|
|
1897
1959
|
const input = z3.object(finalizeTurnInputSchema).parse(args);
|
|
1898
1960
|
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
1899
|
-
if ((input.diffSource ?? "worktree") === "external" || typeof input.externalDiff === "string") {
|
|
1900
|
-
assertDiffWithinLimit(context.policy, input.externalDiff ?? "");
|
|
1901
|
-
}
|
|
1902
1961
|
return finalizeCollabTurn({
|
|
1903
1962
|
cwd,
|
|
1904
1963
|
prompt: input.prompt,
|
|
1905
1964
|
assistantResponse: input.assistantResponse,
|
|
1906
|
-
diffSource: input.diffSource,
|
|
1907
|
-
externalDiff: input.externalDiff,
|
|
1908
1965
|
sync: input.sync,
|
|
1909
1966
|
allowBranchMismatch: input.allowBranchMismatch ?? false,
|
|
1910
1967
|
idempotencyKey: input.idempotencyKey,
|
|
@@ -1912,9 +1969,22 @@ function registerCollabTools(server, context) {
|
|
|
1912
1969
|
});
|
|
1913
1970
|
}
|
|
1914
1971
|
});
|
|
1972
|
+
registerTool(server, context, {
|
|
1973
|
+
name: "remix_collab_drain_finalize_queue",
|
|
1974
|
+
description: "Drain the local finalize queue and record queued finalize_turn jobs immediately. Use this before request-merge, reconcile, or other flows that require the remote change step to exist already.",
|
|
1975
|
+
access: "local_write",
|
|
1976
|
+
inputSchema: drainFinalizeQueueInputSchema,
|
|
1977
|
+
outputSchema: drainFinalizeQueueSuccessSchema,
|
|
1978
|
+
annotations: getAnnotations("local_write", { idempotent: true }),
|
|
1979
|
+
run: async (args) => {
|
|
1980
|
+
const input = z3.object(drainFinalizeQueueInputSchema).parse(args);
|
|
1981
|
+
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
1982
|
+
return drainFinalizeQueue({ cwd });
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1915
1985
|
registerTool(server, context, {
|
|
1916
1986
|
name: "remix_collab_sync_preview",
|
|
1917
|
-
description: "Preview whether the current bound repository can
|
|
1987
|
+
description: "Preview whether the current bound repository can pull the server delta into the working tree. Use this instead of raw git pull or rebase for bound-repo alignment.",
|
|
1918
1988
|
access: "read",
|
|
1919
1989
|
inputSchema: previewInputSchema,
|
|
1920
1990
|
outputSchema: syncSuccessSchema,
|
|
@@ -1926,7 +1996,7 @@ function registerCollabTools(server, context) {
|
|
|
1926
1996
|
});
|
|
1927
1997
|
registerTool(server, context, {
|
|
1928
1998
|
name: "remix_collab_sync_apply",
|
|
1929
|
-
description: "
|
|
1999
|
+
description: "Pull the server delta into the local working tree without moving local git history. This is the Remix-native replacement for raw git pull or rebase in a bound repo.",
|
|
1930
2000
|
access: "local_write",
|
|
1931
2001
|
inputSchema: applyInputSchema,
|
|
1932
2002
|
outputSchema: syncSuccessSchema,
|
|
@@ -1937,6 +2007,31 @@ function registerCollabTools(server, context) {
|
|
|
1937
2007
|
return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
1938
2008
|
}
|
|
1939
2009
|
});
|
|
2010
|
+
registerTool(server, context, {
|
|
2011
|
+
name: "remix_collab_re_anchor_preview",
|
|
2012
|
+
description: "Preview whether the current checkout needs an explicit re-anchor to adopt or recover external Git/GitHub history.",
|
|
2013
|
+
access: "read",
|
|
2014
|
+
inputSchema: previewInputSchema,
|
|
2015
|
+
outputSchema: reAnchorSuccessSchema,
|
|
2016
|
+
run: async (args) => {
|
|
2017
|
+
const input = z3.object(previewInputSchema).parse(args);
|
|
2018
|
+
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2019
|
+
return reAnchor({ cwd, dryRun: true });
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
registerTool(server, context, {
|
|
2023
|
+
name: "remix_collab_re_anchor_apply",
|
|
2024
|
+
description: "Explicitly re-anchor the current lane to adopted or recovered external Git/GitHub history, without rewriting the local checkout afterward.",
|
|
2025
|
+
access: "local_write",
|
|
2026
|
+
inputSchema: reAnchorInputSchema,
|
|
2027
|
+
outputSchema: reAnchorSuccessSchema,
|
|
2028
|
+
run: async (args) => {
|
|
2029
|
+
const input = z3.object(reAnchorInputSchema).parse(args);
|
|
2030
|
+
assertConfirm(input.confirm, "remix_collab_re_anchor_apply");
|
|
2031
|
+
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
2032
|
+
return reAnchor({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
2033
|
+
}
|
|
2034
|
+
});
|
|
1940
2035
|
registerTool(server, context, {
|
|
1941
2036
|
name: "remix_collab_request_merge",
|
|
1942
2037
|
description: "Open a prompt-backed Remix merge request from the current bound repository to its upstream app instead of merging locally with raw git.",
|
|
@@ -2077,7 +2172,7 @@ function registerCollabTools(server, context) {
|
|
|
2077
2172
|
});
|
|
2078
2173
|
registerTool(server, context, {
|
|
2079
2174
|
name: "remix_collab_reconcile_preview",
|
|
2080
|
-
description: "Preview
|
|
2175
|
+
description: "Preview the explicit Remix recovery flow when local and server state diverged beyond a simple pull.",
|
|
2081
2176
|
access: "read",
|
|
2082
2177
|
inputSchema: previewInputSchema,
|
|
2083
2178
|
outputSchema: reconcileSuccessSchema,
|
|
@@ -2089,7 +2184,7 @@ function registerCollabTools(server, context) {
|
|
|
2089
2184
|
});
|
|
2090
2185
|
registerTool(server, context, {
|
|
2091
2186
|
name: "remix_collab_reconcile_apply",
|
|
2092
|
-
description: "
|
|
2187
|
+
description: "Run the explicit Remix recovery flow for diverged local/server state.",
|
|
2093
2188
|
access: "local_write",
|
|
2094
2189
|
inputSchema: applyInputSchema,
|
|
2095
2190
|
outputSchema: reconcileSuccessSchema,
|
|
@@ -3214,6 +3309,19 @@ import { z as z9 } from "zod";
|
|
|
3214
3309
|
// src/contracts/ops.ts
|
|
3215
3310
|
import { z as z8 } from "zod";
|
|
3216
3311
|
var genericRecordSchema4 = z8.record(z8.string(), z8.unknown());
|
|
3312
|
+
var appJobKindSchema = z8.enum([
|
|
3313
|
+
"fork",
|
|
3314
|
+
"edit",
|
|
3315
|
+
"bundle",
|
|
3316
|
+
"import_github",
|
|
3317
|
+
"import_upload",
|
|
3318
|
+
"merge",
|
|
3319
|
+
"revert",
|
|
3320
|
+
"change_step",
|
|
3321
|
+
"reconcile",
|
|
3322
|
+
"change_step_replay"
|
|
3323
|
+
]);
|
|
3324
|
+
var appJobStatusSchema = z8.enum(["pending", "enqueued", "processing", "succeeded", "failed", "cancelled"]);
|
|
3217
3325
|
var appScopedInputSchema = {
|
|
3218
3326
|
...commonRequestFieldsSchema,
|
|
3219
3327
|
appId: z8.string().trim().min(1).optional()
|
|
@@ -3223,6 +3331,13 @@ var editQueueInputSchema = {
|
|
|
3223
3331
|
limit: z8.number().int().positive().max(100).optional(),
|
|
3224
3332
|
offset: z8.number().int().nonnegative().optional()
|
|
3225
3333
|
};
|
|
3334
|
+
var appJobQueueInputSchema = {
|
|
3335
|
+
...appScopedInputSchema,
|
|
3336
|
+
limit: z8.number().int().positive().max(100).optional(),
|
|
3337
|
+
offset: z8.number().int().nonnegative().optional(),
|
|
3338
|
+
kind: z8.array(appJobKindSchema).min(1).optional(),
|
|
3339
|
+
status: z8.array(appJobStatusSchema).min(1).optional()
|
|
3340
|
+
};
|
|
3226
3341
|
var bundleInputSchema = {
|
|
3227
3342
|
...appScopedInputSchema,
|
|
3228
3343
|
bundleId: z8.string().trim().min(1)
|
|
@@ -3255,6 +3370,7 @@ var agentRunEventsInputSchema = {
|
|
|
3255
3370
|
};
|
|
3256
3371
|
var appOverviewSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
3257
3372
|
var editQueueSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
3373
|
+
var appJobQueueSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
3258
3374
|
var bundleSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
3259
3375
|
var timelineSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
3260
3376
|
var agentRunsSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
@@ -3288,7 +3404,7 @@ async function getAppOverview(params) {
|
|
|
3288
3404
|
data,
|
|
3289
3405
|
warnings: [],
|
|
3290
3406
|
recommendedNextActions: [
|
|
3291
|
-
"Use `remix_ops_list_timeline`, `remix_ops_list_agent_runs`, `remix_ops_get_edit_queue`, or `remix_ops_get_sandbox_status` for the next operational drill-down on this app."
|
|
3407
|
+
"Use `remix_ops_list_timeline`, `remix_ops_list_agent_runs`, `remix_ops_get_edit_queue`, `remix_ops_list_app_job_queue`, or `remix_ops_get_sandbox_status` for the next operational drill-down on this app."
|
|
3292
3408
|
],
|
|
3293
3409
|
logContext: target
|
|
3294
3410
|
};
|
|
@@ -3311,6 +3427,42 @@ async function getEditQueue(params) {
|
|
|
3311
3427
|
logContext: target
|
|
3312
3428
|
};
|
|
3313
3429
|
}
|
|
3430
|
+
async function listAppJobQueue(params) {
|
|
3431
|
+
const api = await createApiClient();
|
|
3432
|
+
const target = await resolveAppTarget(api, params);
|
|
3433
|
+
const data = unwrapResponseObject(
|
|
3434
|
+
await api.listAppJobQueue(target.appId, {
|
|
3435
|
+
limit: params.limit,
|
|
3436
|
+
offset: params.offset,
|
|
3437
|
+
kind: params.kind,
|
|
3438
|
+
status: params.status
|
|
3439
|
+
}),
|
|
3440
|
+
"app job queue"
|
|
3441
|
+
);
|
|
3442
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
3443
|
+
const items = Array.isArray(data.items) ? data.items : [];
|
|
3444
|
+
const activeBlockingKinds = /* @__PURE__ */ new Set(["merge", "change_step", "change_step_replay", "reconcile", "revert"]);
|
|
3445
|
+
const hasBlockingJobs = items.some((item) => {
|
|
3446
|
+
if (!item || typeof item !== "object") return false;
|
|
3447
|
+
const record = item;
|
|
3448
|
+
return typeof record.kind === "string" && activeBlockingKinds.has(record.kind) && (typeof record.status !== "string" || ["pending", "enqueued", "processing"].includes(record.status));
|
|
3449
|
+
});
|
|
3450
|
+
const recommendedNextActions = [];
|
|
3451
|
+
if (hasBlockingJobs) {
|
|
3452
|
+
recommendedNextActions.push(
|
|
3453
|
+
"Inspect the returned active workflow jobs before concluding that merge, replay, reconcile, or revert work is stuck. This surface reflects backend app-scoped queue state, not local finalize state."
|
|
3454
|
+
);
|
|
3455
|
+
}
|
|
3456
|
+
if (pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number") {
|
|
3457
|
+
recommendedNextActions.push(`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next app job queue page.`);
|
|
3458
|
+
}
|
|
3459
|
+
return {
|
|
3460
|
+
data,
|
|
3461
|
+
warnings: [],
|
|
3462
|
+
recommendedNextActions,
|
|
3463
|
+
logContext: target
|
|
3464
|
+
};
|
|
3465
|
+
}
|
|
3314
3466
|
async function getBundle(params) {
|
|
3315
3467
|
const api = await createApiClient();
|
|
3316
3468
|
const target = await resolveAppTarget(api, params);
|
|
@@ -3537,6 +3689,25 @@ function registerOpsTools(server, context) {
|
|
|
3537
3689
|
});
|
|
3538
3690
|
}
|
|
3539
3691
|
});
|
|
3692
|
+
registerTool4(server, context, {
|
|
3693
|
+
name: "remix_ops_list_app_job_queue",
|
|
3694
|
+
description: "Inspect bounded app-scoped workflow queue jobs for one app, including active backend work such as merge, replay, reconcile, revert, bundle, or import processing.",
|
|
3695
|
+
access: "read",
|
|
3696
|
+
inputSchema: appJobQueueInputSchema,
|
|
3697
|
+
outputSchema: appJobQueueSuccessSchema,
|
|
3698
|
+
run: async (args) => {
|
|
3699
|
+
const input = z9.object(appJobQueueInputSchema).parse(args);
|
|
3700
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
3701
|
+
return listAppJobQueue({
|
|
3702
|
+
appId: input.appId,
|
|
3703
|
+
cwd,
|
|
3704
|
+
limit: input.limit,
|
|
3705
|
+
offset: input.offset,
|
|
3706
|
+
kind: input.kind,
|
|
3707
|
+
status: input.status
|
|
3708
|
+
});
|
|
3709
|
+
}
|
|
3710
|
+
});
|
|
3540
3711
|
registerTool4(server, context, {
|
|
3541
3712
|
name: "remix_ops_get_bundle",
|
|
3542
3713
|
description: "Inspect one app bundle by id without downloading the artifact payload.",
|