@remixhq/claude-plugin 0.1.16 → 0.1.17
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/.claude-plugin/plugin.json +1 -1
- package/dist/hook-post-collab.cjs +47 -13
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +135 -30
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +3 -3
- package/dist/hook-user-prompt.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +568 -172
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
package/dist/mcp-server.cjs
CHANGED
|
@@ -49218,7 +49218,7 @@ function summarizeUnifiedDiff(diff) {
|
|
|
49218
49218
|
return { changedFilesCount, insertions, deletions };
|
|
49219
49219
|
}
|
|
49220
49220
|
|
|
49221
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
49221
|
+
// node_modules/@remixhq/core/dist/chunk-IXWQWFYT.js
|
|
49222
49222
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
49223
49223
|
var import_path3 = __toESM(require("path"), 1);
|
|
49224
49224
|
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
@@ -49272,7 +49272,8 @@ function buildBindingFileV3(params) {
|
|
|
49272
49272
|
repoFingerprint: params.repoFingerprint,
|
|
49273
49273
|
remoteUrl: params.remoteUrl,
|
|
49274
49274
|
defaultBranch: params.defaultBranch,
|
|
49275
|
-
branchBindings: params.branchBindings
|
|
49275
|
+
branchBindings: params.branchBindings,
|
|
49276
|
+
...params.explicitRootBinding ? { explicitRootBinding: params.explicitRootBinding } : {}
|
|
49276
49277
|
};
|
|
49277
49278
|
}
|
|
49278
49279
|
function normalizeBranchName(value) {
|
|
@@ -49291,7 +49292,7 @@ function normalizeBranchBinding(value) {
|
|
|
49291
49292
|
upstreamAppId: value.upstreamAppId,
|
|
49292
49293
|
threadId: value.threadId ?? null,
|
|
49293
49294
|
laneId: value.laneId ?? null,
|
|
49294
|
-
bindingMode: value.bindingMode === "legacy" ? "legacy" : "lane"
|
|
49295
|
+
bindingMode: value.bindingMode === "legacy" ? "legacy" : value.bindingMode === "explicit_root" ? "explicit_root" : "lane"
|
|
49295
49296
|
};
|
|
49296
49297
|
}
|
|
49297
49298
|
function buildResolvedBinding(params) {
|
|
@@ -49365,6 +49366,7 @@ async function readCollabBindingState(repoRoot, options) {
|
|
|
49365
49366
|
defaultBranch: migratedFile.defaultBranch,
|
|
49366
49367
|
currentBranch,
|
|
49367
49368
|
branchBindings: migratedFile.branchBindings,
|
|
49369
|
+
explicitRootBinding: null,
|
|
49368
49370
|
binding: buildResolvedBinding({
|
|
49369
49371
|
fallbackProjectId: projectId,
|
|
49370
49372
|
repoFingerprint: migratedFile.repoFingerprint,
|
|
@@ -49408,7 +49410,22 @@ async function readCollabBindingState(repoRoot, options) {
|
|
|
49408
49410
|
};
|
|
49409
49411
|
shouldPersistNormalizedBranchBindings = true;
|
|
49410
49412
|
}
|
|
49411
|
-
|
|
49413
|
+
let explicitRootBinding = normalizeBranchBinding(file.explicitRootBinding ?? null);
|
|
49414
|
+
if (explicitRootBinding && !explicitRootBinding.projectId && legacyProjectId) {
|
|
49415
|
+
explicitRootBinding = {
|
|
49416
|
+
...explicitRootBinding,
|
|
49417
|
+
projectId: legacyProjectId
|
|
49418
|
+
};
|
|
49419
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49420
|
+
}
|
|
49421
|
+
if (explicitRootBinding && explicitRootBinding.bindingMode !== "explicit_root") {
|
|
49422
|
+
explicitRootBinding = {
|
|
49423
|
+
...explicitRootBinding,
|
|
49424
|
+
bindingMode: "explicit_root"
|
|
49425
|
+
};
|
|
49426
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49427
|
+
}
|
|
49428
|
+
if (persist && ("explicitBinding" in file || "explicitRootBinding" in file || shouldPersistNormalizedBranchBindings || parsed.schemaVersion === 2)) {
|
|
49412
49429
|
try {
|
|
49413
49430
|
await writeJsonAtomic2(
|
|
49414
49431
|
filePath,
|
|
@@ -49416,7 +49433,8 @@ async function readCollabBindingState(repoRoot, options) {
|
|
|
49416
49433
|
repoFingerprint: file.repoFingerprint ?? null,
|
|
49417
49434
|
remoteUrl: file.remoteUrl ?? null,
|
|
49418
49435
|
defaultBranch: file.defaultBranch ?? null,
|
|
49419
|
-
branchBindings
|
|
49436
|
+
branchBindings,
|
|
49437
|
+
explicitRootBinding
|
|
49420
49438
|
})
|
|
49421
49439
|
);
|
|
49422
49440
|
} catch {
|
|
@@ -49427,8 +49445,23 @@ async function readCollabBindingState(repoRoot, options) {
|
|
|
49427
49445
|
branchBindings,
|
|
49428
49446
|
currentBranch: resolvedBranch,
|
|
49429
49447
|
defaultBranch: normalizeBranchName(file.defaultBranch),
|
|
49430
|
-
legacyProjectId
|
|
49448
|
+
legacyProjectId: explicitRootBinding?.projectId ?? legacyProjectId
|
|
49431
49449
|
});
|
|
49450
|
+
const resolvedBinding = buildResolvedBinding({
|
|
49451
|
+
fallbackProjectId,
|
|
49452
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49453
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49454
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49455
|
+
branchName: resolvedBranch,
|
|
49456
|
+
binding: resolvedBranch ? branchBindings[resolvedBranch] ?? null : null
|
|
49457
|
+
}) ?? (resolvedBranch && resolvedBranch === normalizeBranchName(file.defaultBranch) && explicitRootBinding ? buildResolvedBinding({
|
|
49458
|
+
fallbackProjectId,
|
|
49459
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49460
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49461
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49462
|
+
branchName: normalizeBranchName(file.defaultBranch),
|
|
49463
|
+
binding: explicitRootBinding
|
|
49464
|
+
}) : null);
|
|
49432
49465
|
return {
|
|
49433
49466
|
schemaVersion: parsed.schemaVersion,
|
|
49434
49467
|
projectId: fallbackProjectId,
|
|
@@ -49437,14 +49470,15 @@ async function readCollabBindingState(repoRoot, options) {
|
|
|
49437
49470
|
defaultBranch: file.defaultBranch ?? null,
|
|
49438
49471
|
currentBranch,
|
|
49439
49472
|
branchBindings,
|
|
49440
|
-
|
|
49473
|
+
explicitRootBinding: buildResolvedBinding({
|
|
49441
49474
|
fallbackProjectId,
|
|
49442
49475
|
repoFingerprint: file.repoFingerprint ?? null,
|
|
49443
49476
|
remoteUrl: file.remoteUrl ?? null,
|
|
49444
49477
|
defaultBranch: file.defaultBranch ?? null,
|
|
49445
|
-
branchName:
|
|
49446
|
-
binding:
|
|
49447
|
-
})
|
|
49478
|
+
branchName: normalizeBranchName(file.defaultBranch),
|
|
49479
|
+
binding: explicitRootBinding
|
|
49480
|
+
}),
|
|
49481
|
+
binding: resolvedBinding
|
|
49448
49482
|
};
|
|
49449
49483
|
} catch {
|
|
49450
49484
|
return null;
|
|
@@ -49468,13 +49502,39 @@ async function writeCollabBinding(repoRoot, binding) {
|
|
|
49468
49502
|
laneId: binding.laneId ?? null,
|
|
49469
49503
|
bindingMode: binding.bindingMode ?? "lane"
|
|
49470
49504
|
};
|
|
49505
|
+
const explicitRootBinding = binding.bindingMode === "explicit_root" ? {
|
|
49506
|
+
...branchBindings[branchName],
|
|
49507
|
+
bindingMode: "explicit_root"
|
|
49508
|
+
} : existing?.explicitRootBinding ? {
|
|
49509
|
+
projectId: existing.explicitRootBinding.projectId,
|
|
49510
|
+
currentAppId: existing.explicitRootBinding.currentAppId,
|
|
49511
|
+
upstreamAppId: existing.explicitRootBinding.upstreamAppId,
|
|
49512
|
+
threadId: existing.explicitRootBinding.threadId,
|
|
49513
|
+
laneId: existing.explicitRootBinding.laneId,
|
|
49514
|
+
bindingMode: "explicit_root"
|
|
49515
|
+
} : null;
|
|
49471
49516
|
await writeJsonAtomic2(
|
|
49472
49517
|
filePath,
|
|
49473
49518
|
buildBindingFileV3({
|
|
49474
49519
|
repoFingerprint: binding.repoFingerprint ?? null,
|
|
49475
49520
|
remoteUrl: binding.remoteUrl ?? null,
|
|
49476
49521
|
defaultBranch: binding.defaultBranch ?? null,
|
|
49477
|
-
branchBindings
|
|
49522
|
+
branchBindings,
|
|
49523
|
+
explicitRootBinding
|
|
49524
|
+
})
|
|
49525
|
+
);
|
|
49526
|
+
return filePath;
|
|
49527
|
+
}
|
|
49528
|
+
async function writeCollabBindingSnapshot(params) {
|
|
49529
|
+
const filePath = getCollabBindingPath(params.repoRoot);
|
|
49530
|
+
await writeJsonAtomic2(
|
|
49531
|
+
filePath,
|
|
49532
|
+
buildBindingFileV3({
|
|
49533
|
+
repoFingerprint: params.repoFingerprint,
|
|
49534
|
+
remoteUrl: params.remoteUrl,
|
|
49535
|
+
defaultBranch: params.defaultBranch,
|
|
49536
|
+
branchBindings: params.branchBindings,
|
|
49537
|
+
explicitRootBinding: params.explicitRootBinding ?? null
|
|
49478
49538
|
})
|
|
49479
49539
|
);
|
|
49480
49540
|
return filePath;
|
|
@@ -49784,6 +49844,10 @@ function normalizeBranchName2(value) {
|
|
|
49784
49844
|
}
|
|
49785
49845
|
function buildBindingFromLane(state, lane) {
|
|
49786
49846
|
if (!lane.currentAppId || !lane.upstreamAppId) return null;
|
|
49847
|
+
const resolvedBranch = normalizeBranchName2(lane.branchName) ?? state.currentBranch ?? null;
|
|
49848
|
+
const resolvedDefaultBranch = normalizeBranchName2(lane.defaultBranch) ?? normalizeBranchName2(state.defaultBranch);
|
|
49849
|
+
const explicitRootProjectId = state.explicitRootBinding?.projectId ?? null;
|
|
49850
|
+
const bindingMode = explicitRootProjectId && lane.projectId === explicitRootProjectId && resolvedBranch && resolvedBranch === resolvedDefaultBranch ? "explicit_root" : "lane";
|
|
49787
49851
|
return {
|
|
49788
49852
|
schemaVersion: 3,
|
|
49789
49853
|
projectId: lane.projectId ?? state.projectId,
|
|
@@ -49794,8 +49858,8 @@ function buildBindingFromLane(state, lane) {
|
|
|
49794
49858
|
remoteUrl: lane.remoteUrl ?? state.remoteUrl ?? null,
|
|
49795
49859
|
defaultBranch: lane.defaultBranch ?? state.defaultBranch ?? null,
|
|
49796
49860
|
laneId: lane.laneId ?? null,
|
|
49797
|
-
branchName:
|
|
49798
|
-
bindingMode
|
|
49861
|
+
branchName: resolvedBranch,
|
|
49862
|
+
bindingMode
|
|
49799
49863
|
};
|
|
49800
49864
|
}
|
|
49801
49865
|
function shouldPersistRemoteLaneMetadata(localBinding, lane) {
|
|
@@ -49824,6 +49888,16 @@ async function persistResolvedLane(repoRoot, binding) {
|
|
|
49824
49888
|
});
|
|
49825
49889
|
return readCollabBinding(repoRoot);
|
|
49826
49890
|
}
|
|
49891
|
+
function buildAmbiguousResolution(params) {
|
|
49892
|
+
return {
|
|
49893
|
+
status: "ambiguous_family_selection",
|
|
49894
|
+
currentBranch: params.currentBranch,
|
|
49895
|
+
projectIds: Array.isArray(params.lane.projectIds) ? params.lane.projectIds.filter((value) => typeof value === "string" && value.trim().length > 0) : [],
|
|
49896
|
+
repoFingerprint: params.lane.repoFingerprint ?? params.state.repoFingerprint,
|
|
49897
|
+
remoteUrl: params.lane.remoteUrl ?? params.state.remoteUrl,
|
|
49898
|
+
defaultBranch: params.lane.defaultBranch ?? params.state.defaultBranch
|
|
49899
|
+
};
|
|
49900
|
+
}
|
|
49827
49901
|
async function resolveActiveLaneBinding(params) {
|
|
49828
49902
|
const state = await readCollabBindingState(params.repoRoot);
|
|
49829
49903
|
if (!state) {
|
|
@@ -49846,13 +49920,16 @@ async function resolveActiveLaneBinding(params) {
|
|
|
49846
49920
|
};
|
|
49847
49921
|
}
|
|
49848
49922
|
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
49849
|
-
projectId: localBinding.projectId ?? state.projectId ?? void 0,
|
|
49923
|
+
projectId: state.explicitRootBinding?.projectId ?? (requireRemoteLane ? void 0 : localBinding.projectId ?? state.projectId ?? void 0),
|
|
49850
49924
|
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
49851
49925
|
remoteUrl: state.remoteUrl ?? void 0,
|
|
49852
49926
|
defaultBranch: state.defaultBranch ?? void 0,
|
|
49853
49927
|
branchName: currentBranch
|
|
49854
49928
|
});
|
|
49855
49929
|
const lane2 = unwrapResponseObject(laneResp2, "project lane binding");
|
|
49930
|
+
if (lane2.status === "ambiguous_family_selection") {
|
|
49931
|
+
return buildAmbiguousResolution({ state, currentBranch, lane: lane2 });
|
|
49932
|
+
}
|
|
49856
49933
|
if (lane2.status === "resolved") {
|
|
49857
49934
|
const resolvedBranch = normalizeBranchName2(lane2.branchName);
|
|
49858
49935
|
const resolvedProjectId = lane2.projectId ?? state.projectId;
|
|
@@ -49895,12 +49972,12 @@ async function resolveActiveLaneBinding(params) {
|
|
|
49895
49972
|
return {
|
|
49896
49973
|
status: "missing_branch_binding",
|
|
49897
49974
|
currentBranch,
|
|
49898
|
-
projectId: state.projectId,
|
|
49899
|
-
repoFingerprint: state.repoFingerprint,
|
|
49900
|
-
remoteUrl: state.remoteUrl,
|
|
49901
|
-
defaultBranch: state.defaultBranch,
|
|
49902
|
-
upstreamAppId: localBinding.upstreamAppId ?? null,
|
|
49903
|
-
threadId: localBinding.threadId ?? null
|
|
49975
|
+
projectId: lane2.projectId ?? state.projectId,
|
|
49976
|
+
repoFingerprint: lane2.repoFingerprint ?? state.repoFingerprint,
|
|
49977
|
+
remoteUrl: lane2.remoteUrl ?? state.remoteUrl,
|
|
49978
|
+
defaultBranch: lane2.defaultBranch ?? state.defaultBranch,
|
|
49979
|
+
upstreamAppId: lane2.upstreamAppId ?? localBinding.upstreamAppId ?? null,
|
|
49980
|
+
threadId: lane2.threadId ?? localBinding.threadId ?? null
|
|
49904
49981
|
};
|
|
49905
49982
|
}
|
|
49906
49983
|
return {
|
|
@@ -49923,13 +50000,16 @@ async function resolveActiveLaneBinding(params) {
|
|
|
49923
50000
|
};
|
|
49924
50001
|
}
|
|
49925
50002
|
const laneResp = await params.api.resolveProjectLaneBinding({
|
|
49926
|
-
projectId: state.projectId ?? void 0,
|
|
50003
|
+
projectId: state.explicitRootBinding?.projectId ?? state.projectId ?? void 0,
|
|
49927
50004
|
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
49928
50005
|
remoteUrl: state.remoteUrl ?? void 0,
|
|
49929
50006
|
defaultBranch: state.defaultBranch ?? void 0,
|
|
49930
50007
|
branchName: currentBranch
|
|
49931
50008
|
});
|
|
49932
50009
|
const lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
50010
|
+
if (lane.status === "ambiguous_family_selection") {
|
|
50011
|
+
return buildAmbiguousResolution({ state, currentBranch, lane });
|
|
50012
|
+
}
|
|
49933
50013
|
if (lane.status === "resolved") {
|
|
49934
50014
|
const binding = buildBindingFromLane(state, lane);
|
|
49935
50015
|
if (binding) {
|
|
@@ -49941,18 +50021,15 @@ async function resolveActiveLaneBinding(params) {
|
|
|
49941
50021
|
};
|
|
49942
50022
|
}
|
|
49943
50023
|
}
|
|
49944
|
-
if (lane.status === "binding_not_found") {
|
|
49945
|
-
return { status: "not_bound", currentBranch };
|
|
49946
|
-
}
|
|
49947
50024
|
return {
|
|
49948
50025
|
status: "missing_branch_binding",
|
|
49949
50026
|
currentBranch,
|
|
49950
|
-
projectId: lane.projectId ?? state.projectId,
|
|
50027
|
+
projectId: lane.projectId ?? state.explicitRootBinding?.projectId ?? state.projectId,
|
|
49951
50028
|
repoFingerprint: lane.repoFingerprint ?? state.repoFingerprint,
|
|
49952
50029
|
remoteUrl: lane.remoteUrl ?? state.remoteUrl,
|
|
49953
50030
|
defaultBranch: lane.defaultBranch ?? state.defaultBranch,
|
|
49954
|
-
upstreamAppId: lane.upstreamAppId ?? null,
|
|
49955
|
-
threadId: lane.threadId ?? null
|
|
50031
|
+
upstreamAppId: lane.upstreamAppId ?? state.explicitRootBinding?.upstreamAppId ?? null,
|
|
50032
|
+
threadId: lane.threadId ?? state.explicitRootBinding?.threadId ?? null
|
|
49956
50033
|
};
|
|
49957
50034
|
}
|
|
49958
50035
|
async function ensureActiveLaneBinding(params) {
|
|
@@ -49972,6 +50049,12 @@ async function ensureActiveLaneBinding(params) {
|
|
|
49972
50049
|
hint: `Local app ${resolved.binding.currentAppId}; server app ${resolved.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before running ${params.operation ?? "this command"}.`
|
|
49973
50050
|
});
|
|
49974
50051
|
}
|
|
50052
|
+
if (resolved.status === "ambiguous_family_selection") {
|
|
50053
|
+
throw new RemixError("Multiple canonical Remix families match this repository.", {
|
|
50054
|
+
exitCode: 2,
|
|
50055
|
+
hint: "This checkout is not specific enough to choose a single family for the current branch. Continue from a checkout already bound to the intended family, or run `remix collab init --force-new` to create a new canonical family."
|
|
50056
|
+
});
|
|
50057
|
+
}
|
|
49975
50058
|
if (resolved.status === "not_bound") {
|
|
49976
50059
|
return null;
|
|
49977
50060
|
}
|
|
@@ -49986,65 +50069,6 @@ async function ensureActiveLaneBinding(params) {
|
|
|
49986
50069
|
hint: `Run \`remix collab init\` on branch ${resolved.currentBranch} before running ${params.operation ?? "this command"}.`
|
|
49987
50070
|
});
|
|
49988
50071
|
}
|
|
49989
|
-
async function provisionActiveLaneBinding(params) {
|
|
49990
|
-
const resolved = await resolveActiveLaneBinding(params);
|
|
49991
|
-
if (resolved.status === "resolved") {
|
|
49992
|
-
if (resolved.source === "local") {
|
|
49993
|
-
return { binding: resolved.binding, warnings: [] };
|
|
49994
|
-
}
|
|
49995
|
-
const persisted2 = await persistResolvedLane(params.repoRoot, resolved.binding);
|
|
49996
|
-
return { binding: persisted2, warnings: [] };
|
|
49997
|
-
}
|
|
49998
|
-
if (resolved.status === "binding_conflict") {
|
|
49999
|
-
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
50000
|
-
exitCode: 2,
|
|
50001
|
-
hint: `Local app ${resolved.binding.currentAppId}; server app ${resolved.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before running ${params.operation}.`
|
|
50002
|
-
});
|
|
50003
|
-
}
|
|
50004
|
-
if (resolved.status === "not_bound") {
|
|
50005
|
-
return { binding: null, warnings: [] };
|
|
50006
|
-
}
|
|
50007
|
-
if (!resolved.currentBranch) {
|
|
50008
|
-
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50009
|
-
exitCode: 2,
|
|
50010
|
-
hint: `Switch to a named branch before running ${params.operation}.`
|
|
50011
|
-
});
|
|
50012
|
-
}
|
|
50013
|
-
let lane;
|
|
50014
|
-
try {
|
|
50015
|
-
const laneResp = await params.api.ensureProjectLaneBinding({
|
|
50016
|
-
projectId: resolved.projectId ?? void 0,
|
|
50017
|
-
repoFingerprint: resolved.repoFingerprint ?? void 0,
|
|
50018
|
-
remoteUrl: resolved.remoteUrl ?? void 0,
|
|
50019
|
-
defaultBranch: resolved.defaultBranch ?? void 0,
|
|
50020
|
-
branchName: resolved.currentBranch
|
|
50021
|
-
});
|
|
50022
|
-
lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
50023
|
-
} catch (error2) {
|
|
50024
|
-
throw new RemixError(`Failed to provision a Remix lane for branch ${resolved.currentBranch}.`, {
|
|
50025
|
-
exitCode: error2 instanceof RemixError ? error2.exitCode : 1,
|
|
50026
|
-
hint: formatCliErrorDetail(error2) || `Remix could not create or recover the branch lane required before ${params.operation}.`
|
|
50027
|
-
});
|
|
50028
|
-
}
|
|
50029
|
-
const state = await readCollabBindingState(params.repoRoot);
|
|
50030
|
-
if (!state) {
|
|
50031
|
-
return { binding: null, warnings: [] };
|
|
50032
|
-
}
|
|
50033
|
-
const binding = buildBindingFromLane(state, lane);
|
|
50034
|
-
if (!binding) {
|
|
50035
|
-
throw new RemixError(`Failed to provision a Remix lane for branch ${resolved.currentBranch}.`, {
|
|
50036
|
-
exitCode: 1,
|
|
50037
|
-
hint: "The server returned incomplete lane binding metadata."
|
|
50038
|
-
});
|
|
50039
|
-
}
|
|
50040
|
-
const persisted = await persistResolvedLane(params.repoRoot, binding);
|
|
50041
|
-
return {
|
|
50042
|
-
binding: persisted,
|
|
50043
|
-
warnings: [
|
|
50044
|
-
lane.created ? `Provisioned Remix lane for branch ${resolved.currentBranch}.` : `Recovered existing Remix lane binding for branch ${resolved.currentBranch}.`
|
|
50045
|
-
]
|
|
50046
|
-
};
|
|
50047
|
-
}
|
|
50048
50072
|
async function collabRecordingPreflight(params) {
|
|
50049
50073
|
let repoRoot;
|
|
50050
50074
|
try {
|
|
@@ -50105,6 +50129,24 @@ async function collabRecordingPreflight(params) {
|
|
|
50105
50129
|
hint: `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`
|
|
50106
50130
|
};
|
|
50107
50131
|
}
|
|
50132
|
+
if (bindingResolution.status === "ambiguous_family_selection") {
|
|
50133
|
+
return {
|
|
50134
|
+
status: "family_ambiguous",
|
|
50135
|
+
repoRoot,
|
|
50136
|
+
appId: null,
|
|
50137
|
+
currentBranch: bindingResolution.currentBranch,
|
|
50138
|
+
branchName: bindingResolution.currentBranch,
|
|
50139
|
+
headCommitHash: null,
|
|
50140
|
+
worktreeClean: false,
|
|
50141
|
+
syncStatus: null,
|
|
50142
|
+
syncTargetCommitHash: null,
|
|
50143
|
+
syncTargetCommitId: null,
|
|
50144
|
+
reconcileTargetHeadCommitHash: null,
|
|
50145
|
+
reconcileTargetHeadCommitId: null,
|
|
50146
|
+
warnings: [],
|
|
50147
|
+
hint: "Multiple canonical Remix families match this repository. Continue from a checkout already bound to the intended family, or run `remix collab init --force-new` to create a new canonical family."
|
|
50148
|
+
};
|
|
50149
|
+
}
|
|
50108
50150
|
if (bindingResolution.status === "binding_conflict") {
|
|
50109
50151
|
return {
|
|
50110
50152
|
status: "metadata_conflict",
|
|
@@ -50614,6 +50656,12 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50614
50656
|
hint: preflight.hint
|
|
50615
50657
|
});
|
|
50616
50658
|
}
|
|
50659
|
+
if (preflight.status === "family_ambiguous") {
|
|
50660
|
+
throw new RemixError("Multiple canonical Remix families match this repository.", {
|
|
50661
|
+
exitCode: 2,
|
|
50662
|
+
hint: preflight.hint
|
|
50663
|
+
});
|
|
50664
|
+
}
|
|
50617
50665
|
if (preflight.status === "not_git_repo") {
|
|
50618
50666
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50619
50667
|
exitCode: 2,
|
|
@@ -50929,6 +50977,12 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50929
50977
|
hint: preflight.hint
|
|
50930
50978
|
});
|
|
50931
50979
|
}
|
|
50980
|
+
if (preflight.status === "family_ambiguous") {
|
|
50981
|
+
throw new RemixError("Multiple canonical Remix families match this repository.", {
|
|
50982
|
+
exitCode: 2,
|
|
50983
|
+
hint: preflight.hint
|
|
50984
|
+
});
|
|
50985
|
+
}
|
|
50932
50986
|
if (preflight.status === "not_git_repo") {
|
|
50933
50987
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50934
50988
|
exitCode: 2,
|
|
@@ -51424,6 +51478,12 @@ async function resolveQueueAppId(params) {
|
|
|
51424
51478
|
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51425
51479
|
});
|
|
51426
51480
|
}
|
|
51481
|
+
if (bindingResolution.status === "ambiguous_family_selection") {
|
|
51482
|
+
throw new RemixError("Multiple canonical Remix families match this repository.", {
|
|
51483
|
+
exitCode: 2,
|
|
51484
|
+
hint: "This checkout does not identify a single canonical family. Continue from a checkout already bound to the intended family, or pass `appId` explicitly for the queue request."
|
|
51485
|
+
});
|
|
51486
|
+
}
|
|
51427
51487
|
return bindingResolution.binding.currentAppId;
|
|
51428
51488
|
}
|
|
51429
51489
|
async function collabListMergeRequests(params) {
|
|
@@ -51468,6 +51528,12 @@ async function resolveScopeTarget(params) {
|
|
|
51468
51528
|
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51469
51529
|
});
|
|
51470
51530
|
}
|
|
51531
|
+
if (bindingResolution.status === "ambiguous_family_selection") {
|
|
51532
|
+
throw new RemixError("Multiple canonical Remix families match this repository and no explicit target id was provided.", {
|
|
51533
|
+
exitCode: 2,
|
|
51534
|
+
hint: "This checkout does not identify a single canonical family. Continue from a checkout already bound to the intended family, or pass `targetId` explicitly."
|
|
51535
|
+
});
|
|
51536
|
+
}
|
|
51471
51537
|
const binding = bindingResolution.binding;
|
|
51472
51538
|
if (params.scope === "project") {
|
|
51473
51539
|
if (!binding.projectId) {
|
|
@@ -51582,6 +51648,85 @@ ${text}`.trim() || null
|
|
|
51582
51648
|
});
|
|
51583
51649
|
}
|
|
51584
51650
|
}
|
|
51651
|
+
function requireResolvedLaneBinding(lane, params) {
|
|
51652
|
+
if (lane.status === "resolved" && lane.currentAppId && lane.upstreamAppId) {
|
|
51653
|
+
return lane;
|
|
51654
|
+
}
|
|
51655
|
+
const branchLabel = params.branchName ?? "the current branch";
|
|
51656
|
+
const laneStatus = String(lane.status ?? "");
|
|
51657
|
+
throw new RemixError(`Failed to resolve a Remix lane for ${branchLabel}.`, {
|
|
51658
|
+
exitCode: 1,
|
|
51659
|
+
hint: laneStatus === "binding_not_found" ? `Run ${params.operation} again after the repository has been initialized.` : laneStatus === "ambiguous_family_selection" ? "Multiple canonical Remix families match this repository. Continue from a checkout already bound to the intended family, or rerun with `--force-new` to create a new family." : `Remix did not return complete lane metadata for ${branchLabel}.`
|
|
51660
|
+
});
|
|
51661
|
+
}
|
|
51662
|
+
function resolveProjectBindingResult(response) {
|
|
51663
|
+
const payload = response?.responseObject;
|
|
51664
|
+
if (!payload || typeof payload !== "object") {
|
|
51665
|
+
return { status: "not_found" };
|
|
51666
|
+
}
|
|
51667
|
+
if (payload.status === "ambiguous_family_selection") {
|
|
51668
|
+
const projectIds = Array.isArray(payload.projectIds) ? payload.projectIds.filter((value) => typeof value === "string" && value.trim().length > 0) : [];
|
|
51669
|
+
return {
|
|
51670
|
+
status: "ambiguous_family_selection",
|
|
51671
|
+
candidateCount: typeof payload.candidateCount === "number" && Number.isFinite(payload.candidateCount) ? payload.candidateCount : projectIds.length,
|
|
51672
|
+
projectIds
|
|
51673
|
+
};
|
|
51674
|
+
}
|
|
51675
|
+
if (payload.projectId && payload.appId) {
|
|
51676
|
+
return {
|
|
51677
|
+
status: "resolved",
|
|
51678
|
+
projectId: String(payload.projectId),
|
|
51679
|
+
appId: String(payload.appId),
|
|
51680
|
+
upstreamAppId: String(payload.upstreamAppId ?? payload.appId),
|
|
51681
|
+
threadId: payload.threadId ? String(payload.threadId) : null
|
|
51682
|
+
};
|
|
51683
|
+
}
|
|
51684
|
+
return { status: "not_found" };
|
|
51685
|
+
}
|
|
51686
|
+
function throwAmbiguousFamilyError(params) {
|
|
51687
|
+
const familyCount = params.candidateCount || params.projectIds.length;
|
|
51688
|
+
const projectHint = params.projectIds.length > 0 ? ` Matching project ids: ${params.projectIds.join(", ")}.` : "";
|
|
51689
|
+
throw new RemixError("Multiple canonical Remix families already match this repository.", {
|
|
51690
|
+
exitCode: 2,
|
|
51691
|
+
hint: `Plain \`remix collab init\` cannot safely choose among ${familyCount} matching canonical families for repo fingerprint ${params.repoFingerprint}${params.remoteUrl ? ` (${params.remoteUrl})` : ""}.${projectHint} Run \`remix collab init --force-new\` to create a new canonical family, or continue from a checkout already bound to the intended family.`
|
|
51692
|
+
});
|
|
51693
|
+
}
|
|
51694
|
+
async function resolveOrEnsureLaneBinding(params) {
|
|
51695
|
+
const resolvePayload = {
|
|
51696
|
+
projectId: params.projectId ?? void 0,
|
|
51697
|
+
repoFingerprint: params.repoFingerprint,
|
|
51698
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
51699
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
51700
|
+
branchName: params.branchName
|
|
51701
|
+
};
|
|
51702
|
+
let lane = unwrapResponseObject(
|
|
51703
|
+
await params.api.resolveProjectLaneBinding(resolvePayload),
|
|
51704
|
+
"project lane binding"
|
|
51705
|
+
);
|
|
51706
|
+
if (lane.status !== "resolved") {
|
|
51707
|
+
lane = unwrapResponseObject(
|
|
51708
|
+
await params.api.ensureProjectLaneBinding({
|
|
51709
|
+
...resolvePayload,
|
|
51710
|
+
seedAppId: params.seedAppId ?? void 0
|
|
51711
|
+
}),
|
|
51712
|
+
"project lane binding"
|
|
51713
|
+
);
|
|
51714
|
+
}
|
|
51715
|
+
return requireResolvedLaneBinding(lane, {
|
|
51716
|
+
branchName: params.branchName,
|
|
51717
|
+
operation: params.operation
|
|
51718
|
+
});
|
|
51719
|
+
}
|
|
51720
|
+
function branchBindingFromLane(lane, mode, fallback) {
|
|
51721
|
+
return {
|
|
51722
|
+
projectId: lane.projectId ?? fallback.projectId,
|
|
51723
|
+
currentAppId: lane.currentAppId ?? fallback.currentAppId,
|
|
51724
|
+
upstreamAppId: lane.upstreamAppId ?? fallback.upstreamAppId,
|
|
51725
|
+
threadId: lane.threadId ?? fallback.threadId,
|
|
51726
|
+
laneId: lane.laneId ?? null,
|
|
51727
|
+
bindingMode: mode
|
|
51728
|
+
};
|
|
51729
|
+
}
|
|
51585
51730
|
async function collabInit(params) {
|
|
51586
51731
|
return withRepoMutationLock(
|
|
51587
51732
|
{
|
|
@@ -51603,72 +51748,207 @@ async function collabInit(params) {
|
|
|
51603
51748
|
const branchName = currentBranch ?? defaultBranch ?? null;
|
|
51604
51749
|
const repoFingerprint = await buildRepoFingerprint({ gitRoot: repoRoot, remoteUrl, defaultBranch });
|
|
51605
51750
|
const repoSnapshot = await captureRepoSnapshot(repoRoot);
|
|
51606
|
-
|
|
51607
|
-
|
|
51608
|
-
|
|
51609
|
-
|
|
51610
|
-
|
|
51611
|
-
|
|
51612
|
-
|
|
51613
|
-
|
|
51614
|
-
|
|
51615
|
-
|
|
51616
|
-
|
|
51751
|
+
const localBindingState = await readCollabBindingState(repoRoot, { persist: true });
|
|
51752
|
+
if (!params.forceNew && localBindingState?.explicitRootBinding && branchName) {
|
|
51753
|
+
const explicitRoot = localBindingState.explicitRootBinding;
|
|
51754
|
+
const explicitProjectId = explicitRoot.projectId ?? localBindingState.projectId;
|
|
51755
|
+
let canonicalLane2 = null;
|
|
51756
|
+
let boundProjectId2 = explicitProjectId;
|
|
51757
|
+
let boundCurrentAppId2 = explicitRoot.currentAppId;
|
|
51758
|
+
let boundUpstreamAppId2 = explicitRoot.upstreamAppId;
|
|
51759
|
+
let boundThreadId2 = explicitRoot.threadId;
|
|
51760
|
+
let boundLaneId2 = explicitRoot.laneId;
|
|
51761
|
+
if (defaultBranch && branchName !== defaultBranch) {
|
|
51762
|
+
canonicalLane2 = await resolveOrEnsureLaneBinding({
|
|
51763
|
+
api: params.api,
|
|
51764
|
+
projectId: explicitProjectId ?? void 0,
|
|
51765
|
+
repoFingerprint,
|
|
51766
|
+
remoteUrl,
|
|
51767
|
+
defaultBranch,
|
|
51768
|
+
branchName: defaultBranch,
|
|
51769
|
+
operation: "`remix collab init`"
|
|
51617
51770
|
});
|
|
51618
|
-
|
|
51619
|
-
|
|
51620
|
-
|
|
51621
|
-
|
|
51622
|
-
|
|
51623
|
-
|
|
51624
|
-
|
|
51625
|
-
|
|
51626
|
-
const existing = bindingResp?.responseObject;
|
|
51627
|
-
if (existing?.projectId && existing?.appId) {
|
|
51628
|
-
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
51629
|
-
operation: "`remix collab init`",
|
|
51630
|
-
recoveryHint: "The repository changed while the local binding was being initialized. Review the local changes and rerun `remix collab init`."
|
|
51771
|
+
const lane = await resolveOrEnsureLaneBinding({
|
|
51772
|
+
api: params.api,
|
|
51773
|
+
projectId: canonicalLane2.projectId ?? explicitProjectId ?? void 0,
|
|
51774
|
+
repoFingerprint,
|
|
51775
|
+
remoteUrl,
|
|
51776
|
+
defaultBranch,
|
|
51777
|
+
branchName,
|
|
51778
|
+
operation: "`remix collab init`"
|
|
51631
51779
|
});
|
|
51632
|
-
|
|
51633
|
-
|
|
51634
|
-
|
|
51635
|
-
|
|
51636
|
-
|
|
51637
|
-
|
|
51638
|
-
|
|
51639
|
-
|
|
51640
|
-
|
|
51780
|
+
boundProjectId2 = lane.projectId ?? boundProjectId2;
|
|
51781
|
+
boundCurrentAppId2 = lane.currentAppId ?? boundCurrentAppId2;
|
|
51782
|
+
boundUpstreamAppId2 = lane.upstreamAppId ?? boundUpstreamAppId2;
|
|
51783
|
+
boundThreadId2 = lane.threadId ?? boundThreadId2;
|
|
51784
|
+
boundLaneId2 = lane.laneId ?? null;
|
|
51785
|
+
} else {
|
|
51786
|
+
canonicalLane2 = await resolveOrEnsureLaneBinding({
|
|
51787
|
+
api: params.api,
|
|
51788
|
+
projectId: explicitProjectId ?? void 0,
|
|
51789
|
+
repoFingerprint,
|
|
51790
|
+
remoteUrl,
|
|
51791
|
+
defaultBranch,
|
|
51792
|
+
branchName,
|
|
51793
|
+
operation: "`remix collab init`"
|
|
51794
|
+
});
|
|
51795
|
+
boundProjectId2 = canonicalLane2.projectId ?? boundProjectId2;
|
|
51796
|
+
boundCurrentAppId2 = canonicalLane2.currentAppId ?? boundCurrentAppId2;
|
|
51797
|
+
boundUpstreamAppId2 = canonicalLane2.upstreamAppId ?? boundUpstreamAppId2;
|
|
51798
|
+
boundThreadId2 = canonicalLane2.threadId ?? boundThreadId2;
|
|
51799
|
+
boundLaneId2 = canonicalLane2.laneId ?? null;
|
|
51800
|
+
}
|
|
51801
|
+
const readyApp = await pollAppReady(params.api, boundCurrentAppId2);
|
|
51802
|
+
boundProjectId2 = String(readyApp.projectId ?? boundProjectId2);
|
|
51803
|
+
boundThreadId2 = readyApp.threadId ? String(readyApp.threadId) : boundThreadId2;
|
|
51804
|
+
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
51805
|
+
operation: "`remix collab init`",
|
|
51806
|
+
recoveryHint: "The repository changed while the local binding was being initialized. Review the local changes and rerun `remix collab init`."
|
|
51807
|
+
});
|
|
51808
|
+
await writeCollabBinding(repoRoot, {
|
|
51809
|
+
projectId: canonicalLane2?.projectId ?? explicitProjectId ?? null,
|
|
51810
|
+
currentAppId: canonicalLane2?.currentAppId ?? explicitRoot.currentAppId,
|
|
51811
|
+
upstreamAppId: canonicalLane2?.upstreamAppId ?? canonicalLane2?.currentAppId ?? explicitRoot.upstreamAppId ?? explicitRoot.currentAppId,
|
|
51812
|
+
threadId: canonicalLane2?.threadId ?? explicitRoot.threadId,
|
|
51813
|
+
repoFingerprint: canonicalLane2?.repoFingerprint ?? explicitRoot.repoFingerprint ?? repoFingerprint,
|
|
51814
|
+
remoteUrl: canonicalLane2?.remoteUrl ?? explicitRoot.remoteUrl ?? remoteUrl,
|
|
51815
|
+
defaultBranch: canonicalLane2?.defaultBranch ?? explicitRoot.defaultBranch ?? defaultBranch ?? null,
|
|
51816
|
+
laneId: canonicalLane2?.laneId ?? explicitRoot.laneId,
|
|
51817
|
+
branchName: defaultBranch,
|
|
51818
|
+
bindingMode: "explicit_root"
|
|
51819
|
+
});
|
|
51820
|
+
if (defaultBranch && branchName !== defaultBranch) {
|
|
51821
|
+
await writeCollabBinding(repoRoot, {
|
|
51822
|
+
projectId: boundProjectId2,
|
|
51823
|
+
currentAppId: boundCurrentAppId2,
|
|
51824
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
51825
|
+
threadId: boundThreadId2,
|
|
51641
51826
|
repoFingerprint,
|
|
51642
51827
|
remoteUrl,
|
|
51643
51828
|
defaultBranch: defaultBranch ?? null,
|
|
51644
|
-
laneId:
|
|
51829
|
+
laneId: boundLaneId2,
|
|
51645
51830
|
branchName,
|
|
51646
51831
|
bindingMode: "lane"
|
|
51647
51832
|
});
|
|
51833
|
+
}
|
|
51834
|
+
return {
|
|
51835
|
+
reused: true,
|
|
51836
|
+
projectId: boundProjectId2 ?? explicitProjectId ?? "",
|
|
51837
|
+
appId: boundCurrentAppId2,
|
|
51838
|
+
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId2),
|
|
51839
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
51840
|
+
bindingPath: import_path9.default.join(repoRoot, ".remix", "config.json"),
|
|
51841
|
+
repoRoot,
|
|
51842
|
+
bindingMode: defaultBranch && branchName !== defaultBranch ? "lane" : "explicit_root",
|
|
51843
|
+
createdCanonicalFamily: false,
|
|
51844
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
51845
|
+
};
|
|
51846
|
+
}
|
|
51847
|
+
if (!params.forceNew) {
|
|
51848
|
+
const bindingResolution = resolveProjectBindingResult(
|
|
51849
|
+
await params.api.resolveProjectBinding({
|
|
51850
|
+
repoFingerprint,
|
|
51851
|
+
remoteUrl: remoteUrl ?? void 0,
|
|
51852
|
+
branchName: branchName ?? void 0
|
|
51853
|
+
})
|
|
51854
|
+
);
|
|
51855
|
+
if (bindingResolution.status === "ambiguous_family_selection") {
|
|
51856
|
+
throwAmbiguousFamilyError({
|
|
51857
|
+
repoFingerprint,
|
|
51858
|
+
remoteUrl,
|
|
51859
|
+
projectIds: bindingResolution.projectIds,
|
|
51860
|
+
candidateCount: bindingResolution.candidateCount
|
|
51861
|
+
});
|
|
51862
|
+
}
|
|
51863
|
+
if (bindingResolution.status === "resolved") {
|
|
51864
|
+
const initialProjectId = bindingResolution.projectId;
|
|
51865
|
+
const initialCurrentAppId = bindingResolution.appId;
|
|
51866
|
+
const initialUpstreamAppId = bindingResolution.upstreamAppId;
|
|
51867
|
+
const initialThreadId = bindingResolution.threadId;
|
|
51648
51868
|
let boundProjectId2 = initialProjectId;
|
|
51649
51869
|
let boundCurrentAppId2 = initialCurrentAppId;
|
|
51650
51870
|
let boundUpstreamAppId2 = initialUpstreamAppId;
|
|
51651
51871
|
let boundThreadId2 = initialThreadId;
|
|
51652
|
-
let
|
|
51872
|
+
let boundLaneId2 = null;
|
|
51873
|
+
let canonicalLane2 = null;
|
|
51653
51874
|
if (branchName) {
|
|
51654
|
-
|
|
51655
|
-
|
|
51656
|
-
|
|
51657
|
-
|
|
51658
|
-
|
|
51659
|
-
|
|
51660
|
-
|
|
51661
|
-
|
|
51662
|
-
|
|
51663
|
-
|
|
51875
|
+
if (defaultBranch && branchName !== defaultBranch) {
|
|
51876
|
+
canonicalLane2 = await resolveOrEnsureLaneBinding({
|
|
51877
|
+
api: params.api,
|
|
51878
|
+
repoFingerprint,
|
|
51879
|
+
remoteUrl,
|
|
51880
|
+
defaultBranch,
|
|
51881
|
+
branchName: defaultBranch,
|
|
51882
|
+
seedAppId: initialCurrentAppId,
|
|
51883
|
+
operation: "`remix collab init`"
|
|
51884
|
+
});
|
|
51885
|
+
const lane = await resolveOrEnsureLaneBinding({
|
|
51886
|
+
api: params.api,
|
|
51887
|
+
projectId: canonicalLane2.projectId ?? void 0,
|
|
51888
|
+
repoFingerprint,
|
|
51889
|
+
remoteUrl,
|
|
51890
|
+
defaultBranch,
|
|
51891
|
+
branchName,
|
|
51892
|
+
operation: "`remix collab init`"
|
|
51893
|
+
});
|
|
51894
|
+
boundProjectId2 = lane.projectId ?? boundProjectId2;
|
|
51895
|
+
boundCurrentAppId2 = lane.currentAppId ?? boundCurrentAppId2;
|
|
51896
|
+
boundUpstreamAppId2 = lane.upstreamAppId ?? boundUpstreamAppId2;
|
|
51897
|
+
boundThreadId2 = lane.threadId ?? boundThreadId2;
|
|
51898
|
+
boundLaneId2 = lane.laneId ?? null;
|
|
51899
|
+
} else {
|
|
51900
|
+
const lane = await resolveOrEnsureLaneBinding({
|
|
51901
|
+
api: params.api,
|
|
51902
|
+
repoFingerprint,
|
|
51903
|
+
remoteUrl,
|
|
51904
|
+
defaultBranch,
|
|
51905
|
+
branchName,
|
|
51906
|
+
seedAppId: initialCurrentAppId,
|
|
51907
|
+
operation: "`remix collab init`"
|
|
51908
|
+
});
|
|
51909
|
+
canonicalLane2 = lane;
|
|
51910
|
+
boundProjectId2 = lane.projectId ?? boundProjectId2;
|
|
51911
|
+
boundCurrentAppId2 = lane.currentAppId ?? boundCurrentAppId2;
|
|
51912
|
+
boundUpstreamAppId2 = lane.upstreamAppId ?? boundUpstreamAppId2;
|
|
51913
|
+
boundThreadId2 = lane.threadId ?? boundThreadId2;
|
|
51914
|
+
boundLaneId2 = lane.laneId ?? null;
|
|
51664
51915
|
}
|
|
51665
|
-
finalWarnings = [...finalWarnings, ...provisioned.warnings];
|
|
51666
51916
|
}
|
|
51667
51917
|
if (boundCurrentAppId2) {
|
|
51668
51918
|
const readyApp = await pollAppReady(params.api, boundCurrentAppId2);
|
|
51669
51919
|
boundProjectId2 = String(readyApp.projectId ?? boundProjectId2);
|
|
51670
51920
|
boundThreadId2 = readyApp.threadId ? String(readyApp.threadId) : boundThreadId2;
|
|
51671
51921
|
}
|
|
51922
|
+
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
51923
|
+
operation: "`remix collab init`",
|
|
51924
|
+
recoveryHint: "The repository changed while the local binding was being initialized. Review the local changes and rerun `remix collab init`."
|
|
51925
|
+
});
|
|
51926
|
+
if (canonicalLane2 && defaultBranch && branchName && branchName !== defaultBranch) {
|
|
51927
|
+
await writeCollabBinding(repoRoot, {
|
|
51928
|
+
projectId: canonicalLane2.projectId ?? null,
|
|
51929
|
+
currentAppId: canonicalLane2.currentAppId ?? boundCurrentAppId2,
|
|
51930
|
+
upstreamAppId: canonicalLane2.upstreamAppId ?? canonicalLane2.currentAppId ?? boundCurrentAppId2,
|
|
51931
|
+
threadId: canonicalLane2.threadId ?? null,
|
|
51932
|
+
repoFingerprint: canonicalLane2.repoFingerprint ?? repoFingerprint,
|
|
51933
|
+
remoteUrl: canonicalLane2.remoteUrl ?? remoteUrl,
|
|
51934
|
+
defaultBranch: canonicalLane2.defaultBranch ?? defaultBranch,
|
|
51935
|
+
laneId: canonicalLane2.laneId ?? null,
|
|
51936
|
+
branchName: defaultBranch,
|
|
51937
|
+
bindingMode: "lane"
|
|
51938
|
+
});
|
|
51939
|
+
}
|
|
51940
|
+
const bindingPath2 = await writeCollabBinding(repoRoot, {
|
|
51941
|
+
projectId: boundProjectId2,
|
|
51942
|
+
currentAppId: boundCurrentAppId2,
|
|
51943
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
51944
|
+
threadId: boundThreadId2,
|
|
51945
|
+
repoFingerprint,
|
|
51946
|
+
remoteUrl,
|
|
51947
|
+
defaultBranch: defaultBranch ?? null,
|
|
51948
|
+
laneId: boundLaneId2,
|
|
51949
|
+
branchName,
|
|
51950
|
+
bindingMode: "lane"
|
|
51951
|
+
});
|
|
51672
51952
|
return {
|
|
51673
51953
|
reused: true,
|
|
51674
51954
|
projectId: boundProjectId2,
|
|
@@ -51677,7 +51957,9 @@ async function collabInit(params) {
|
|
|
51677
51957
|
upstreamAppId: boundUpstreamAppId2,
|
|
51678
51958
|
bindingPath: bindingPath2,
|
|
51679
51959
|
repoRoot,
|
|
51680
|
-
|
|
51960
|
+
bindingMode: "lane",
|
|
51961
|
+
createdCanonicalFamily: false,
|
|
51962
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
51681
51963
|
};
|
|
51682
51964
|
}
|
|
51683
51965
|
}
|
|
@@ -51704,7 +51986,7 @@ async function collabInit(params) {
|
|
|
51704
51986
|
path: params.path?.trim() || void 0,
|
|
51705
51987
|
platform: "generic",
|
|
51706
51988
|
isPublic: false,
|
|
51707
|
-
branch: currentBranch ?? void 0,
|
|
51989
|
+
branch: defaultBranch && branchName && branchName !== defaultBranch ? defaultBranch : currentBranch ?? void 0,
|
|
51708
51990
|
remoteUrl: remoteUrl ?? void 0,
|
|
51709
51991
|
defaultBranch: defaultBranch ?? void 0,
|
|
51710
51992
|
repoFingerprint,
|
|
@@ -51717,28 +51999,51 @@ async function collabInit(params) {
|
|
|
51717
51999
|
let boundUpstreamAppId = String(app.id);
|
|
51718
52000
|
let boundThreadId = app.threadId ? String(app.threadId) : null;
|
|
51719
52001
|
let boundLaneId = null;
|
|
52002
|
+
let canonicalLane = null;
|
|
51720
52003
|
if (branchName) {
|
|
51721
|
-
|
|
51722
|
-
|
|
51723
|
-
|
|
51724
|
-
|
|
51725
|
-
|
|
51726
|
-
|
|
51727
|
-
|
|
51728
|
-
|
|
51729
|
-
|
|
51730
|
-
|
|
51731
|
-
|
|
51732
|
-
|
|
51733
|
-
|
|
51734
|
-
|
|
51735
|
-
|
|
51736
|
-
|
|
51737
|
-
|
|
51738
|
-
|
|
51739
|
-
|
|
51740
|
-
|
|
51741
|
-
|
|
52004
|
+
if (defaultBranch && branchName !== defaultBranch) {
|
|
52005
|
+
canonicalLane = await resolveOrEnsureLaneBinding({
|
|
52006
|
+
api: params.api,
|
|
52007
|
+
projectId: boundProjectId,
|
|
52008
|
+
repoFingerprint,
|
|
52009
|
+
remoteUrl,
|
|
52010
|
+
defaultBranch,
|
|
52011
|
+
branchName: defaultBranch,
|
|
52012
|
+
seedAppId: String(app.id),
|
|
52013
|
+
operation: "`remix collab init`"
|
|
52014
|
+
});
|
|
52015
|
+
const lane = await resolveOrEnsureLaneBinding({
|
|
52016
|
+
api: params.api,
|
|
52017
|
+
projectId: canonicalLane.projectId ?? boundProjectId,
|
|
52018
|
+
repoFingerprint,
|
|
52019
|
+
remoteUrl,
|
|
52020
|
+
defaultBranch,
|
|
52021
|
+
branchName,
|
|
52022
|
+
operation: "`remix collab init`"
|
|
52023
|
+
});
|
|
52024
|
+
boundProjectId = lane.projectId ?? boundProjectId;
|
|
52025
|
+
boundCurrentAppId = lane.currentAppId ?? boundCurrentAppId;
|
|
52026
|
+
boundUpstreamAppId = lane.upstreamAppId ?? boundUpstreamAppId;
|
|
52027
|
+
boundThreadId = lane.threadId ?? boundThreadId;
|
|
52028
|
+
boundLaneId = lane.laneId ?? null;
|
|
52029
|
+
} else {
|
|
52030
|
+
const lane = await resolveOrEnsureLaneBinding({
|
|
52031
|
+
api: params.api,
|
|
52032
|
+
projectId: boundProjectId,
|
|
52033
|
+
repoFingerprint,
|
|
52034
|
+
remoteUrl,
|
|
52035
|
+
defaultBranch,
|
|
52036
|
+
branchName,
|
|
52037
|
+
seedAppId: String(app.id),
|
|
52038
|
+
operation: "`remix collab init`"
|
|
52039
|
+
});
|
|
52040
|
+
canonicalLane = lane;
|
|
52041
|
+
boundProjectId = lane.projectId ?? boundProjectId;
|
|
52042
|
+
boundCurrentAppId = lane.currentAppId ?? boundCurrentAppId;
|
|
52043
|
+
boundUpstreamAppId = lane.upstreamAppId ?? boundUpstreamAppId;
|
|
52044
|
+
boundThreadId = lane.threadId ?? boundThreadId;
|
|
52045
|
+
boundLaneId = lane.laneId ?? null;
|
|
52046
|
+
}
|
|
51742
52047
|
}
|
|
51743
52048
|
if (boundCurrentAppId) {
|
|
51744
52049
|
const readyApp = await pollAppReady(params.api, boundCurrentAppId);
|
|
@@ -51749,18 +52054,64 @@ async function collabInit(params) {
|
|
|
51749
52054
|
operation: "`remix collab init`",
|
|
51750
52055
|
recoveryHint: "The repository changed before the Remix binding was written. Review the local changes and rerun `remix collab init`."
|
|
51751
52056
|
});
|
|
51752
|
-
const
|
|
51753
|
-
|
|
51754
|
-
|
|
51755
|
-
|
|
51756
|
-
|
|
51757
|
-
|
|
51758
|
-
|
|
51759
|
-
|
|
51760
|
-
|
|
51761
|
-
|
|
51762
|
-
|
|
51763
|
-
|
|
52057
|
+
const bindingMode = params.forceNew && (!defaultBranch || branchName === defaultBranch) ? "explicit_root" : "lane";
|
|
52058
|
+
let bindingPath;
|
|
52059
|
+
if (params.forceNew && defaultBranch && canonicalLane) {
|
|
52060
|
+
const canonicalBinding = branchBindingFromLane(canonicalLane, "explicit_root", {
|
|
52061
|
+
projectId: canonicalLane.projectId ?? boundProjectId,
|
|
52062
|
+
currentAppId: canonicalLane.currentAppId ?? boundCurrentAppId,
|
|
52063
|
+
upstreamAppId: canonicalLane.upstreamAppId ?? canonicalLane.currentAppId ?? boundCurrentAppId,
|
|
52064
|
+
threadId: canonicalLane.threadId ?? boundThreadId
|
|
52065
|
+
});
|
|
52066
|
+
const branchBindings = {
|
|
52067
|
+
[defaultBranch]: canonicalBinding
|
|
52068
|
+
};
|
|
52069
|
+
if (branchName && branchName !== defaultBranch) {
|
|
52070
|
+
branchBindings[branchName] = {
|
|
52071
|
+
projectId: boundProjectId,
|
|
52072
|
+
currentAppId: boundCurrentAppId,
|
|
52073
|
+
upstreamAppId: boundUpstreamAppId,
|
|
52074
|
+
threadId: boundThreadId,
|
|
52075
|
+
laneId: boundLaneId,
|
|
52076
|
+
bindingMode: "lane"
|
|
52077
|
+
};
|
|
52078
|
+
}
|
|
52079
|
+
bindingPath = await writeCollabBindingSnapshot({
|
|
52080
|
+
repoRoot,
|
|
52081
|
+
repoFingerprint,
|
|
52082
|
+
remoteUrl,
|
|
52083
|
+
defaultBranch,
|
|
52084
|
+
branchBindings,
|
|
52085
|
+
explicitRootBinding: canonicalBinding
|
|
52086
|
+
});
|
|
52087
|
+
} else {
|
|
52088
|
+
if (canonicalLane && defaultBranch && branchName && branchName !== defaultBranch) {
|
|
52089
|
+
await writeCollabBinding(repoRoot, {
|
|
52090
|
+
projectId: canonicalLane.projectId ?? null,
|
|
52091
|
+
currentAppId: canonicalLane.currentAppId ?? boundCurrentAppId,
|
|
52092
|
+
upstreamAppId: canonicalLane.upstreamAppId ?? canonicalLane.currentAppId ?? boundCurrentAppId,
|
|
52093
|
+
threadId: canonicalLane.threadId ?? null,
|
|
52094
|
+
repoFingerprint: canonicalLane.repoFingerprint ?? repoFingerprint,
|
|
52095
|
+
remoteUrl: canonicalLane.remoteUrl ?? remoteUrl,
|
|
52096
|
+
defaultBranch: canonicalLane.defaultBranch ?? defaultBranch,
|
|
52097
|
+
laneId: canonicalLane.laneId ?? null,
|
|
52098
|
+
branchName: defaultBranch,
|
|
52099
|
+
bindingMode: params.forceNew ? "explicit_root" : "lane"
|
|
52100
|
+
});
|
|
52101
|
+
}
|
|
52102
|
+
bindingPath = await writeCollabBinding(repoRoot, {
|
|
52103
|
+
projectId: boundProjectId,
|
|
52104
|
+
currentAppId: boundCurrentAppId,
|
|
52105
|
+
upstreamAppId: boundUpstreamAppId,
|
|
52106
|
+
threadId: boundThreadId,
|
|
52107
|
+
repoFingerprint,
|
|
52108
|
+
remoteUrl,
|
|
52109
|
+
defaultBranch: defaultBranch ?? null,
|
|
52110
|
+
laneId: boundLaneId,
|
|
52111
|
+
branchName,
|
|
52112
|
+
bindingMode
|
|
52113
|
+
});
|
|
52114
|
+
}
|
|
51764
52115
|
return {
|
|
51765
52116
|
reused: false,
|
|
51766
52117
|
projectId: boundProjectId,
|
|
@@ -51769,6 +52120,8 @@ async function collabInit(params) {
|
|
|
51769
52120
|
upstreamAppId: boundUpstreamAppId,
|
|
51770
52121
|
bindingPath,
|
|
51771
52122
|
repoRoot,
|
|
52123
|
+
bindingMode,
|
|
52124
|
+
createdCanonicalFamily: Boolean(params.forceNew),
|
|
51772
52125
|
remoteUrl,
|
|
51773
52126
|
defaultBranch,
|
|
51774
52127
|
...warnings.length > 0 ? { warnings } : {}
|
|
@@ -52211,7 +52564,32 @@ async function collabStatus(params) {
|
|
|
52211
52564
|
addBlockedReason(status.sync, "branch_binding_missing");
|
|
52212
52565
|
addBlockedReason(status.reconcile, "branch_binding_missing");
|
|
52213
52566
|
addWarning(status, `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`);
|
|
52214
|
-
status.recommendedAction = "
|
|
52567
|
+
status.recommendedAction = "init";
|
|
52568
|
+
return status;
|
|
52569
|
+
}
|
|
52570
|
+
if (bindingResolution.status === "ambiguous_family_selection") {
|
|
52571
|
+
status.binding = {
|
|
52572
|
+
isBound: true,
|
|
52573
|
+
path: getCollabBindingPath(repoRoot),
|
|
52574
|
+
projectId: null,
|
|
52575
|
+
currentAppId: null,
|
|
52576
|
+
upstreamAppId: null,
|
|
52577
|
+
isRemix: null,
|
|
52578
|
+
threadId: null,
|
|
52579
|
+
repoFingerprint: bindingResolution.repoFingerprint,
|
|
52580
|
+
remoteUrl: bindingResolution.remoteUrl,
|
|
52581
|
+
defaultBranch: bindingResolution.defaultBranch,
|
|
52582
|
+
laneId: null,
|
|
52583
|
+
branchName: bindingResolution.currentBranch,
|
|
52584
|
+
bindingMode: null
|
|
52585
|
+
};
|
|
52586
|
+
addBlockedReason(status.sync, "family_ambiguous");
|
|
52587
|
+
addBlockedReason(status.reconcile, "family_ambiguous");
|
|
52588
|
+
addWarning(
|
|
52589
|
+
status,
|
|
52590
|
+
`Multiple canonical Remix families match ${bindingResolution.currentBranch ?? "the current branch"}. Switch to a checkout already bound to the intended family or run \`remix collab init --force-new\`.`
|
|
52591
|
+
);
|
|
52592
|
+
status.recommendedAction = "choose_family";
|
|
52215
52593
|
return status;
|
|
52216
52594
|
}
|
|
52217
52595
|
const binding = bindingResolution.binding;
|
|
@@ -52363,6 +52741,8 @@ async function collabStatus(params) {
|
|
|
52363
52741
|
status.recommendedAction = "reconcile";
|
|
52364
52742
|
} else if ((status.remote.incomingOpenMergeRequestCount ?? 0) > 0) {
|
|
52365
52743
|
status.recommendedAction = "review_queue";
|
|
52744
|
+
} else if (status.sync.blockedReasons.includes("family_ambiguous") || status.reconcile.blockedReasons.includes("family_ambiguous")) {
|
|
52745
|
+
status.recommendedAction = "choose_family";
|
|
52366
52746
|
} else {
|
|
52367
52747
|
status.recommendedAction = "no_action";
|
|
52368
52748
|
}
|
|
@@ -52506,6 +52886,7 @@ var ERROR_CODES = {
|
|
|
52506
52886
|
DIRTY_WORKTREE: "DIRTY_WORKTREE",
|
|
52507
52887
|
DETACHED_HEAD: "DETACHED_HEAD",
|
|
52508
52888
|
PREFERRED_BRANCH_MISMATCH: "PREFERRED_BRANCH_MISMATCH",
|
|
52889
|
+
FAMILY_SELECTION_AMBIGUOUS: "FAMILY_SELECTION_AMBIGUOUS",
|
|
52509
52890
|
MISSING_HEAD: "MISSING_HEAD",
|
|
52510
52891
|
REPO_LOCK_HELD: "REPO_LOCK_HELD",
|
|
52511
52892
|
REPO_LOCK_TIMEOUT: "REPO_LOCK_TIMEOUT",
|
|
@@ -52640,6 +53021,14 @@ function normalizeByMessage(err) {
|
|
|
52640
53021
|
category: "local_state"
|
|
52641
53022
|
});
|
|
52642
53023
|
}
|
|
53024
|
+
if (message.includes("Multiple canonical Remix families") || message.includes("family selection is ambiguous")) {
|
|
53025
|
+
return makeNormalized({
|
|
53026
|
+
code: ERROR_CODES.FAMILY_SELECTION_AMBIGUOUS,
|
|
53027
|
+
message,
|
|
53028
|
+
hint,
|
|
53029
|
+
category: "local_state"
|
|
53030
|
+
});
|
|
53031
|
+
}
|
|
52643
53032
|
if (message.includes("Failed to resolve local HEAD")) {
|
|
52644
53033
|
return makeNormalized({
|
|
52645
53034
|
code: ERROR_CODES.MISSING_HEAD,
|
|
@@ -53036,7 +53425,9 @@ var initDataSchema = external_exports.object({
|
|
|
53036
53425
|
dashboardUrl: external_exports.string().url(),
|
|
53037
53426
|
upstreamAppId: external_exports.string(),
|
|
53038
53427
|
bindingPath: external_exports.string(),
|
|
53039
|
-
repoRoot: external_exports.string()
|
|
53428
|
+
repoRoot: external_exports.string(),
|
|
53429
|
+
bindingMode: external_exports.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
53430
|
+
createdCanonicalFamily: external_exports.boolean().optional()
|
|
53040
53431
|
});
|
|
53041
53432
|
var listDataSchema = external_exports.object({
|
|
53042
53433
|
apps: genericArraySchema,
|
|
@@ -53164,6 +53555,7 @@ var accessDebugSuccessSchema = makeSuccessSchema(accessDebugDataSchema);
|
|
|
53164
53555
|
var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema);
|
|
53165
53556
|
function getRiskLevel(status) {
|
|
53166
53557
|
if (status.recommendedAction === "reconcile") return "high";
|
|
53558
|
+
if (status.recommendedAction === "choose_family") return "medium";
|
|
53167
53559
|
if (status.recommendedAction === "sync" || status.remote.incomingOpenMergeRequestCount) return "medium";
|
|
53168
53560
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
53169
53561
|
return "low";
|
|
@@ -53183,6 +53575,10 @@ function getRecommendedNextActions(status) {
|
|
|
53183
53575
|
return ["Run remix_collab_reconcile_preview before attempting remix_collab_reconcile_apply. Reconcile is the explicit Remix recovery path when fast-forward sync is no longer possible."];
|
|
53184
53576
|
case "review_queue":
|
|
53185
53577
|
return ["Run remix_collab_review_queue to inspect reviewable merge requests instead of using local git merge flows."];
|
|
53578
|
+
case "choose_family":
|
|
53579
|
+
return [
|
|
53580
|
+
"This checkout is ambiguous across multiple canonical Remix families. Continue from a checkout already bound to the intended family, or run remix_collab_init with forceNew=true to create and bind a new canonical family."
|
|
53581
|
+
];
|
|
53186
53582
|
default:
|
|
53187
53583
|
return [];
|
|
53188
53584
|
}
|
|
@@ -56133,7 +56529,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
56133
56529
|
// package.json
|
|
56134
56530
|
var package_default = {
|
|
56135
56531
|
name: "@remixhq/claude-plugin",
|
|
56136
|
-
version: "0.1.
|
|
56532
|
+
version: "0.1.17",
|
|
56137
56533
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
56138
56534
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
56139
56535
|
license: "MIT",
|
|
@@ -56164,8 +56560,8 @@ var package_default = {
|
|
|
56164
56560
|
prepack: "npm run build"
|
|
56165
56561
|
},
|
|
56166
56562
|
dependencies: {
|
|
56167
|
-
"@remixhq/core": "^0.1.
|
|
56168
|
-
"@remixhq/mcp": "^0.1.
|
|
56563
|
+
"@remixhq/core": "^0.1.12",
|
|
56564
|
+
"@remixhq/mcp": "^0.1.12"
|
|
56169
56565
|
},
|
|
56170
56566
|
devDependencies: {
|
|
56171
56567
|
"@types/node": "^25.4.0",
|