@remixhq/claude-plugin 0.1.15 → 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/agents/remix-collab.md +8 -0
- package/dist/hook-post-collab.cjs +7542 -38
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +794 -196
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +4 -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 +1557 -357
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/safe-collab-workflow/SKILL.md +9 -0
package/dist/mcp-server.cjs
CHANGED
|
@@ -3223,8 +3223,8 @@ var require_utils = __commonJS({
|
|
|
3223
3223
|
}
|
|
3224
3224
|
return ind;
|
|
3225
3225
|
}
|
|
3226
|
-
function removeDotSegments(
|
|
3227
|
-
let input =
|
|
3226
|
+
function removeDotSegments(path13) {
|
|
3227
|
+
let input = path13;
|
|
3228
3228
|
const output = [];
|
|
3229
3229
|
let nextSlash = -1;
|
|
3230
3230
|
let len = 0;
|
|
@@ -3423,8 +3423,8 @@ var require_schemes = __commonJS({
|
|
|
3423
3423
|
wsComponent.secure = void 0;
|
|
3424
3424
|
}
|
|
3425
3425
|
if (wsComponent.resourceName) {
|
|
3426
|
-
const [
|
|
3427
|
-
wsComponent.path =
|
|
3426
|
+
const [path13, query] = wsComponent.resourceName.split("?");
|
|
3427
|
+
wsComponent.path = path13 && path13 !== "/" ? path13 : void 0;
|
|
3428
3428
|
wsComponent.query = query;
|
|
3429
3429
|
wsComponent.resourceName = void 0;
|
|
3430
3430
|
}
|
|
@@ -6806,7 +6806,7 @@ var require_windows = __commonJS({
|
|
|
6806
6806
|
module2.exports = isexe;
|
|
6807
6807
|
isexe.sync = sync;
|
|
6808
6808
|
var fs11 = require("fs");
|
|
6809
|
-
function checkPathExt(
|
|
6809
|
+
function checkPathExt(path13, options) {
|
|
6810
6810
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
6811
6811
|
if (!pathext) {
|
|
6812
6812
|
return true;
|
|
@@ -6817,25 +6817,25 @@ var require_windows = __commonJS({
|
|
|
6817
6817
|
}
|
|
6818
6818
|
for (var i2 = 0; i2 < pathext.length; i2++) {
|
|
6819
6819
|
var p = pathext[i2].toLowerCase();
|
|
6820
|
-
if (p &&
|
|
6820
|
+
if (p && path13.substr(-p.length).toLowerCase() === p) {
|
|
6821
6821
|
return true;
|
|
6822
6822
|
}
|
|
6823
6823
|
}
|
|
6824
6824
|
return false;
|
|
6825
6825
|
}
|
|
6826
|
-
function checkStat(stat,
|
|
6826
|
+
function checkStat(stat, path13, options) {
|
|
6827
6827
|
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
6828
6828
|
return false;
|
|
6829
6829
|
}
|
|
6830
|
-
return checkPathExt(
|
|
6830
|
+
return checkPathExt(path13, options);
|
|
6831
6831
|
}
|
|
6832
|
-
function isexe(
|
|
6833
|
-
fs11.stat(
|
|
6834
|
-
cb(er, er ? false : checkStat(stat,
|
|
6832
|
+
function isexe(path13, options, cb) {
|
|
6833
|
+
fs11.stat(path13, function(er, stat) {
|
|
6834
|
+
cb(er, er ? false : checkStat(stat, path13, options));
|
|
6835
6835
|
});
|
|
6836
6836
|
}
|
|
6837
|
-
function sync(
|
|
6838
|
-
return checkStat(fs11.statSync(
|
|
6837
|
+
function sync(path13, options) {
|
|
6838
|
+
return checkStat(fs11.statSync(path13), path13, options);
|
|
6839
6839
|
}
|
|
6840
6840
|
}
|
|
6841
6841
|
});
|
|
@@ -6847,13 +6847,13 @@ var require_mode = __commonJS({
|
|
|
6847
6847
|
module2.exports = isexe;
|
|
6848
6848
|
isexe.sync = sync;
|
|
6849
6849
|
var fs11 = require("fs");
|
|
6850
|
-
function isexe(
|
|
6851
|
-
fs11.stat(
|
|
6850
|
+
function isexe(path13, options, cb) {
|
|
6851
|
+
fs11.stat(path13, function(er, stat) {
|
|
6852
6852
|
cb(er, er ? false : checkStat(stat, options));
|
|
6853
6853
|
});
|
|
6854
6854
|
}
|
|
6855
|
-
function sync(
|
|
6856
|
-
return checkStat(fs11.statSync(
|
|
6855
|
+
function sync(path13, options) {
|
|
6856
|
+
return checkStat(fs11.statSync(path13), options);
|
|
6857
6857
|
}
|
|
6858
6858
|
function checkStat(stat, options) {
|
|
6859
6859
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -6887,7 +6887,7 @@ var require_isexe = __commonJS({
|
|
|
6887
6887
|
}
|
|
6888
6888
|
module2.exports = isexe;
|
|
6889
6889
|
isexe.sync = sync;
|
|
6890
|
-
function isexe(
|
|
6890
|
+
function isexe(path13, options, cb) {
|
|
6891
6891
|
if (typeof options === "function") {
|
|
6892
6892
|
cb = options;
|
|
6893
6893
|
options = {};
|
|
@@ -6897,7 +6897,7 @@ var require_isexe = __commonJS({
|
|
|
6897
6897
|
throw new TypeError("callback not provided");
|
|
6898
6898
|
}
|
|
6899
6899
|
return new Promise(function(resolve, reject) {
|
|
6900
|
-
isexe(
|
|
6900
|
+
isexe(path13, options || {}, function(er, is) {
|
|
6901
6901
|
if (er) {
|
|
6902
6902
|
reject(er);
|
|
6903
6903
|
} else {
|
|
@@ -6906,7 +6906,7 @@ var require_isexe = __commonJS({
|
|
|
6906
6906
|
});
|
|
6907
6907
|
});
|
|
6908
6908
|
}
|
|
6909
|
-
core(
|
|
6909
|
+
core(path13, options || {}, function(er, is) {
|
|
6910
6910
|
if (er) {
|
|
6911
6911
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
6912
6912
|
er = null;
|
|
@@ -6916,9 +6916,9 @@ var require_isexe = __commonJS({
|
|
|
6916
6916
|
cb(er, is);
|
|
6917
6917
|
});
|
|
6918
6918
|
}
|
|
6919
|
-
function sync(
|
|
6919
|
+
function sync(path13, options) {
|
|
6920
6920
|
try {
|
|
6921
|
-
return core.sync(
|
|
6921
|
+
return core.sync(path13, options || {});
|
|
6922
6922
|
} catch (er) {
|
|
6923
6923
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
6924
6924
|
return false;
|
|
@@ -6935,7 +6935,7 @@ var require_which = __commonJS({
|
|
|
6935
6935
|
"node_modules/which/which.js"(exports2, module2) {
|
|
6936
6936
|
"use strict";
|
|
6937
6937
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
6938
|
-
var
|
|
6938
|
+
var path13 = require("path");
|
|
6939
6939
|
var COLON = isWindows ? ";" : ":";
|
|
6940
6940
|
var isexe = require_isexe();
|
|
6941
6941
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -6973,7 +6973,7 @@ var require_which = __commonJS({
|
|
|
6973
6973
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
6974
6974
|
const ppRaw = pathEnv[i2];
|
|
6975
6975
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
6976
|
-
const pCmd =
|
|
6976
|
+
const pCmd = path13.join(pathPart, cmd);
|
|
6977
6977
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
6978
6978
|
resolve(subStep(p, i2, 0));
|
|
6979
6979
|
});
|
|
@@ -7000,7 +7000,7 @@ var require_which = __commonJS({
|
|
|
7000
7000
|
for (let i2 = 0; i2 < pathEnv.length; i2++) {
|
|
7001
7001
|
const ppRaw = pathEnv[i2];
|
|
7002
7002
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
7003
|
-
const pCmd =
|
|
7003
|
+
const pCmd = path13.join(pathPart, cmd);
|
|
7004
7004
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
7005
7005
|
for (let j = 0; j < pathExt.length; j++) {
|
|
7006
7006
|
const cur = p + pathExt[j];
|
|
@@ -7048,7 +7048,7 @@ var require_path_key = __commonJS({
|
|
|
7048
7048
|
var require_resolveCommand = __commonJS({
|
|
7049
7049
|
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
|
|
7050
7050
|
"use strict";
|
|
7051
|
-
var
|
|
7051
|
+
var path13 = require("path");
|
|
7052
7052
|
var which = require_which();
|
|
7053
7053
|
var getPathKey = require_path_key();
|
|
7054
7054
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -7066,7 +7066,7 @@ var require_resolveCommand = __commonJS({
|
|
|
7066
7066
|
try {
|
|
7067
7067
|
resolved = which.sync(parsed.command, {
|
|
7068
7068
|
path: env[getPathKey({ env })],
|
|
7069
|
-
pathExt: withoutPathExt ?
|
|
7069
|
+
pathExt: withoutPathExt ? path13.delimiter : void 0
|
|
7070
7070
|
});
|
|
7071
7071
|
} catch (e) {
|
|
7072
7072
|
} finally {
|
|
@@ -7075,7 +7075,7 @@ var require_resolveCommand = __commonJS({
|
|
|
7075
7075
|
}
|
|
7076
7076
|
}
|
|
7077
7077
|
if (resolved) {
|
|
7078
|
-
resolved =
|
|
7078
|
+
resolved = path13.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
7079
7079
|
}
|
|
7080
7080
|
return resolved;
|
|
7081
7081
|
}
|
|
@@ -7129,8 +7129,8 @@ var require_shebang_command = __commonJS({
|
|
|
7129
7129
|
if (!match) {
|
|
7130
7130
|
return null;
|
|
7131
7131
|
}
|
|
7132
|
-
const [
|
|
7133
|
-
const binary =
|
|
7132
|
+
const [path13, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
7133
|
+
const binary = path13.split("/").pop();
|
|
7134
7134
|
if (binary === "env") {
|
|
7135
7135
|
return argument;
|
|
7136
7136
|
}
|
|
@@ -7165,7 +7165,7 @@ var require_readShebang = __commonJS({
|
|
|
7165
7165
|
var require_parse = __commonJS({
|
|
7166
7166
|
"node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
|
|
7167
7167
|
"use strict";
|
|
7168
|
-
var
|
|
7168
|
+
var path13 = require("path");
|
|
7169
7169
|
var resolveCommand = require_resolveCommand();
|
|
7170
7170
|
var escape2 = require_escape();
|
|
7171
7171
|
var readShebang = require_readShebang();
|
|
@@ -7190,7 +7190,7 @@ var require_parse = __commonJS({
|
|
|
7190
7190
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
7191
7191
|
if (parsed.options.forceShell || needsShell) {
|
|
7192
7192
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
7193
|
-
parsed.command =
|
|
7193
|
+
parsed.command = path13.normalize(parsed.command);
|
|
7194
7194
|
parsed.command = escape2.command(parsed.command);
|
|
7195
7195
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
7196
7196
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -7498,10 +7498,10 @@ function assignProp(target, prop, value) {
|
|
|
7498
7498
|
configurable: true
|
|
7499
7499
|
});
|
|
7500
7500
|
}
|
|
7501
|
-
function getElementAtPath(obj,
|
|
7502
|
-
if (!
|
|
7501
|
+
function getElementAtPath(obj, path13) {
|
|
7502
|
+
if (!path13)
|
|
7503
7503
|
return obj;
|
|
7504
|
-
return
|
|
7504
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
7505
7505
|
}
|
|
7506
7506
|
function promiseAllObject(promisesObj) {
|
|
7507
7507
|
const keys = Object.keys(promisesObj);
|
|
@@ -7821,11 +7821,11 @@ function aborted(x, startIndex = 0) {
|
|
|
7821
7821
|
}
|
|
7822
7822
|
return false;
|
|
7823
7823
|
}
|
|
7824
|
-
function prefixIssues(
|
|
7824
|
+
function prefixIssues(path13, issues) {
|
|
7825
7825
|
return issues.map((iss) => {
|
|
7826
7826
|
var _a;
|
|
7827
7827
|
(_a = iss).path ?? (_a.path = []);
|
|
7828
|
-
iss.path.unshift(
|
|
7828
|
+
iss.path.unshift(path13);
|
|
7829
7829
|
return iss;
|
|
7830
7830
|
});
|
|
7831
7831
|
}
|
|
@@ -13886,8 +13886,8 @@ function getErrorMap() {
|
|
|
13886
13886
|
|
|
13887
13887
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
13888
13888
|
var makeIssue = (params) => {
|
|
13889
|
-
const { data, path:
|
|
13890
|
-
const fullPath = [...
|
|
13889
|
+
const { data, path: path13, errorMaps, issueData } = params;
|
|
13890
|
+
const fullPath = [...path13, ...issueData.path || []];
|
|
13891
13891
|
const fullIssue = {
|
|
13892
13892
|
...issueData,
|
|
13893
13893
|
path: fullPath
|
|
@@ -14003,11 +14003,11 @@ var errorUtil;
|
|
|
14003
14003
|
|
|
14004
14004
|
// node_modules/zod/v3/types.js
|
|
14005
14005
|
var ParseInputLazyPath = class {
|
|
14006
|
-
constructor(parent, value,
|
|
14006
|
+
constructor(parent, value, path13, key) {
|
|
14007
14007
|
this._cachedPath = [];
|
|
14008
14008
|
this.parent = parent;
|
|
14009
14009
|
this.data = value;
|
|
14010
|
-
this._path =
|
|
14010
|
+
this._path = path13;
|
|
14011
14011
|
this._key = key;
|
|
14012
14012
|
}
|
|
14013
14013
|
get path() {
|
|
@@ -21513,7 +21513,7 @@ var RemixError = class extends Error {
|
|
|
21513
21513
|
}
|
|
21514
21514
|
};
|
|
21515
21515
|
|
|
21516
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
21516
|
+
// node_modules/@remixhq/core/dist/chunk-BNKPTE2U.js
|
|
21517
21517
|
async function readJsonSafe(res) {
|
|
21518
21518
|
const ct = res.headers.get("content-type") ?? "";
|
|
21519
21519
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -21527,7 +21527,7 @@ function createApiClient(config2, opts) {
|
|
|
21527
21527
|
const apiKey = (opts?.apiKey ?? "").trim();
|
|
21528
21528
|
const tokenProvider = opts?.tokenProvider;
|
|
21529
21529
|
const CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
21530
|
-
async function request(
|
|
21530
|
+
async function request(path13, init) {
|
|
21531
21531
|
if (!tokenProvider) {
|
|
21532
21532
|
throw new RemixError("API client is missing a token provider.", {
|
|
21533
21533
|
exitCode: 1,
|
|
@@ -21535,7 +21535,7 @@ function createApiClient(config2, opts) {
|
|
|
21535
21535
|
});
|
|
21536
21536
|
}
|
|
21537
21537
|
const auth = await tokenProvider();
|
|
21538
|
-
const url = new URL(
|
|
21538
|
+
const url = new URL(path13, config2.apiUrl).toString();
|
|
21539
21539
|
const doFetch = async (bearer) => fetch(url, {
|
|
21540
21540
|
...init,
|
|
21541
21541
|
headers: {
|
|
@@ -21559,7 +21559,7 @@ function createApiClient(config2, opts) {
|
|
|
21559
21559
|
const json = await readJsonSafe(res);
|
|
21560
21560
|
return json ?? null;
|
|
21561
21561
|
}
|
|
21562
|
-
async function requestBinary(
|
|
21562
|
+
async function requestBinary(path13, init) {
|
|
21563
21563
|
if (!tokenProvider) {
|
|
21564
21564
|
throw new RemixError("API client is missing a token provider.", {
|
|
21565
21565
|
exitCode: 1,
|
|
@@ -21567,7 +21567,7 @@ function createApiClient(config2, opts) {
|
|
|
21567
21567
|
});
|
|
21568
21568
|
}
|
|
21569
21569
|
const auth = await tokenProvider();
|
|
21570
|
-
const url = new URL(
|
|
21570
|
+
const url = new URL(path13, config2.apiUrl).toString();
|
|
21571
21571
|
const doFetch = async (bearer) => fetch(url, {
|
|
21572
21572
|
...init,
|
|
21573
21573
|
headers: {
|
|
@@ -21611,8 +21611,20 @@ function createApiClient(config2, opts) {
|
|
|
21611
21611
|
const qs = new URLSearchParams();
|
|
21612
21612
|
if (params.repoFingerprint) qs.set("repoFingerprint", params.repoFingerprint);
|
|
21613
21613
|
if (params.remoteUrl) qs.set("remoteUrl", params.remoteUrl);
|
|
21614
|
+
if (params.branchName) qs.set("branchName", params.branchName);
|
|
21614
21615
|
return request(`/v1/projects/bindings/resolve?${qs.toString()}`, { method: "GET" });
|
|
21615
21616
|
},
|
|
21617
|
+
resolveProjectLaneBinding: (params) => {
|
|
21618
|
+
const qs = new URLSearchParams();
|
|
21619
|
+
if (params.projectId) qs.set("projectId", params.projectId);
|
|
21620
|
+
if (params.repoFingerprint) qs.set("repoFingerprint", params.repoFingerprint);
|
|
21621
|
+
if (params.remoteUrl) qs.set("remoteUrl", params.remoteUrl);
|
|
21622
|
+
if (params.defaultBranch) qs.set("defaultBranch", params.defaultBranch);
|
|
21623
|
+
qs.set("branchName", params.branchName);
|
|
21624
|
+
return request(`/v1/projects/bindings/resolve-lane?${qs.toString()}`, { method: "GET" });
|
|
21625
|
+
},
|
|
21626
|
+
ensureProjectLaneBinding: (payload) => request("/v1/projects/bindings/ensure-lane", { method: "POST", body: JSON.stringify(payload) }),
|
|
21627
|
+
bootstrapFreshProjectLane: (payload) => request("/v1/projects/bindings/bootstrap-fresh-lane", { method: "POST", body: JSON.stringify(payload) }),
|
|
21616
21628
|
autoEnableDeveloper: () => request("/v1/developer/auto-enable", { method: "POST" }),
|
|
21617
21629
|
listClientApps: (params) => {
|
|
21618
21630
|
const qs = params?.orgId ? `?orgId=${encodeURIComponent(params.orgId)}` : "";
|
|
@@ -21676,6 +21688,7 @@ function createApiClient(config2, opts) {
|
|
|
21676
21688
|
if (params?.offset !== void 0) qs.set("offset", String(params.offset));
|
|
21677
21689
|
if (params?.changeStepId) qs.set("changeStepId", params.changeStepId);
|
|
21678
21690
|
if (params?.threadId) qs.set("threadId", params.threadId);
|
|
21691
|
+
if (params?.collabLaneId) qs.set("collabLaneId", params.collabLaneId);
|
|
21679
21692
|
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21680
21693
|
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21681
21694
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
@@ -30785,8 +30798,8 @@ var IcebergError = class extends Error {
|
|
|
30785
30798
|
return this.status === 419;
|
|
30786
30799
|
}
|
|
30787
30800
|
};
|
|
30788
|
-
function buildUrl(baseUrl,
|
|
30789
|
-
const url = new URL(
|
|
30801
|
+
function buildUrl(baseUrl, path13, query) {
|
|
30802
|
+
const url = new URL(path13, baseUrl);
|
|
30790
30803
|
if (query) {
|
|
30791
30804
|
for (const [key, value] of Object.entries(query)) {
|
|
30792
30805
|
if (value !== void 0) {
|
|
@@ -30816,12 +30829,12 @@ function createFetchClient(options) {
|
|
|
30816
30829
|
return {
|
|
30817
30830
|
async request({
|
|
30818
30831
|
method,
|
|
30819
|
-
path:
|
|
30832
|
+
path: path13,
|
|
30820
30833
|
query,
|
|
30821
30834
|
body,
|
|
30822
30835
|
headers
|
|
30823
30836
|
}) {
|
|
30824
|
-
const url = buildUrl(options.baseUrl,
|
|
30837
|
+
const url = buildUrl(options.baseUrl, path13, query);
|
|
30825
30838
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
30826
30839
|
const res = await fetchFn(url, {
|
|
30827
30840
|
method,
|
|
@@ -31640,7 +31653,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31640
31653
|
* @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
|
|
31641
31654
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
31642
31655
|
*/
|
|
31643
|
-
async uploadOrUpdate(method,
|
|
31656
|
+
async uploadOrUpdate(method, path13, fileBody, fileOptions) {
|
|
31644
31657
|
var _this = this;
|
|
31645
31658
|
return _this.handleOperation(async () => {
|
|
31646
31659
|
let body;
|
|
@@ -31664,7 +31677,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31664
31677
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
31665
31678
|
}
|
|
31666
31679
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) headers = _objectSpread22(_objectSpread22({}, headers), fileOptions.headers);
|
|
31667
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
31680
|
+
const cleanPath = _this._removeEmptyFolders(path13);
|
|
31668
31681
|
const _path = _this._getFinalPath(cleanPath);
|
|
31669
31682
|
const data = await (method == "PUT" ? put : post)(_this.fetch, `${_this.url}/object/${_path}`, body, _objectSpread22({ headers }, (options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {}));
|
|
31670
31683
|
return {
|
|
@@ -31725,8 +31738,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31725
31738
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31726
31739
|
* - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below.
|
|
31727
31740
|
*/
|
|
31728
|
-
async upload(
|
|
31729
|
-
return this.uploadOrUpdate("POST",
|
|
31741
|
+
async upload(path13, fileBody, fileOptions) {
|
|
31742
|
+
return this.uploadOrUpdate("POST", path13, fileBody, fileOptions);
|
|
31730
31743
|
}
|
|
31731
31744
|
/**
|
|
31732
31745
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -31765,9 +31778,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31765
31778
|
* - `objects` table permissions: none
|
|
31766
31779
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31767
31780
|
*/
|
|
31768
|
-
async uploadToSignedUrl(
|
|
31781
|
+
async uploadToSignedUrl(path13, token, fileBody, fileOptions) {
|
|
31769
31782
|
var _this3 = this;
|
|
31770
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
31783
|
+
const cleanPath = _this3._removeEmptyFolders(path13);
|
|
31771
31784
|
const _path = _this3._getFinalPath(cleanPath);
|
|
31772
31785
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
31773
31786
|
url.searchParams.set("token", token);
|
|
@@ -31829,10 +31842,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31829
31842
|
* - `objects` table permissions: `insert`
|
|
31830
31843
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31831
31844
|
*/
|
|
31832
|
-
async createSignedUploadUrl(
|
|
31845
|
+
async createSignedUploadUrl(path13, options) {
|
|
31833
31846
|
var _this4 = this;
|
|
31834
31847
|
return _this4.handleOperation(async () => {
|
|
31835
|
-
let _path = _this4._getFinalPath(
|
|
31848
|
+
let _path = _this4._getFinalPath(path13);
|
|
31836
31849
|
const headers = _objectSpread22({}, _this4.headers);
|
|
31837
31850
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
31838
31851
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -31841,7 +31854,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31841
31854
|
if (!token) throw new StorageError("No token returned by API");
|
|
31842
31855
|
return {
|
|
31843
31856
|
signedUrl: url.toString(),
|
|
31844
|
-
path:
|
|
31857
|
+
path: path13,
|
|
31845
31858
|
token
|
|
31846
31859
|
};
|
|
31847
31860
|
});
|
|
@@ -31897,8 +31910,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31897
31910
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31898
31911
|
* - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below.
|
|
31899
31912
|
*/
|
|
31900
|
-
async update(
|
|
31901
|
-
return this.uploadOrUpdate("PUT",
|
|
31913
|
+
async update(path13, fileBody, fileOptions) {
|
|
31914
|
+
return this.uploadOrUpdate("PUT", path13, fileBody, fileOptions);
|
|
31902
31915
|
}
|
|
31903
31916
|
/**
|
|
31904
31917
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -32045,10 +32058,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32045
32058
|
* - `objects` table permissions: `select`
|
|
32046
32059
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32047
32060
|
*/
|
|
32048
|
-
async createSignedUrl(
|
|
32061
|
+
async createSignedUrl(path13, expiresIn, options) {
|
|
32049
32062
|
var _this8 = this;
|
|
32050
32063
|
return _this8.handleOperation(async () => {
|
|
32051
|
-
let _path = _this8._getFinalPath(
|
|
32064
|
+
let _path = _this8._getFinalPath(path13);
|
|
32052
32065
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
32053
32066
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
32054
32067
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `&download=${options.download === true ? "" : options.download}` : "";
|
|
@@ -32175,11 +32188,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32175
32188
|
* - `objects` table permissions: `select`
|
|
32176
32189
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32177
32190
|
*/
|
|
32178
|
-
download(
|
|
32191
|
+
download(path13, options, parameters) {
|
|
32179
32192
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) !== "undefined" ? "render/image/authenticated" : "object";
|
|
32180
32193
|
const transformationQuery = this.transformOptsToQueryString((options === null || options === void 0 ? void 0 : options.transform) || {});
|
|
32181
32194
|
const queryString = transformationQuery ? `?${transformationQuery}` : "";
|
|
32182
|
-
const _path = this._getFinalPath(
|
|
32195
|
+
const _path = this._getFinalPath(path13);
|
|
32183
32196
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString}`, {
|
|
32184
32197
|
headers: this.headers,
|
|
32185
32198
|
noResolveJson: true
|
|
@@ -32209,9 +32222,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32209
32222
|
* }
|
|
32210
32223
|
* ```
|
|
32211
32224
|
*/
|
|
32212
|
-
async info(
|
|
32225
|
+
async info(path13) {
|
|
32213
32226
|
var _this10 = this;
|
|
32214
|
-
const _path = _this10._getFinalPath(
|
|
32227
|
+
const _path = _this10._getFinalPath(path13);
|
|
32215
32228
|
return _this10.handleOperation(async () => {
|
|
32216
32229
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
32217
32230
|
});
|
|
@@ -32231,9 +32244,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32231
32244
|
* .exists('folder/avatar1.png')
|
|
32232
32245
|
* ```
|
|
32233
32246
|
*/
|
|
32234
|
-
async exists(
|
|
32247
|
+
async exists(path13) {
|
|
32235
32248
|
var _this11 = this;
|
|
32236
|
-
const _path = _this11._getFinalPath(
|
|
32249
|
+
const _path = _this11._getFinalPath(path13);
|
|
32237
32250
|
try {
|
|
32238
32251
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
32239
32252
|
return {
|
|
@@ -32310,8 +32323,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32310
32323
|
* - `objects` table permissions: none
|
|
32311
32324
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32312
32325
|
*/
|
|
32313
|
-
getPublicUrl(
|
|
32314
|
-
const _path = this._getFinalPath(
|
|
32326
|
+
getPublicUrl(path13, options) {
|
|
32327
|
+
const _path = this._getFinalPath(path13);
|
|
32315
32328
|
const _queryString = [];
|
|
32316
32329
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `download=${options.download === true ? "" : options.download}` : "";
|
|
32317
32330
|
if (downloadQueryParam !== "") _queryString.push(downloadQueryParam);
|
|
@@ -32450,10 +32463,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32450
32463
|
* - `objects` table permissions: `select`
|
|
32451
32464
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32452
32465
|
*/
|
|
32453
|
-
async list(
|
|
32466
|
+
async list(path13, options, parameters) {
|
|
32454
32467
|
var _this13 = this;
|
|
32455
32468
|
return _this13.handleOperation(async () => {
|
|
32456
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
32469
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path13 || "" });
|
|
32457
32470
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
32458
32471
|
});
|
|
32459
32472
|
}
|
|
@@ -32517,11 +32530,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32517
32530
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
32518
32531
|
return btoa(data);
|
|
32519
32532
|
}
|
|
32520
|
-
_getFinalPath(
|
|
32521
|
-
return `${this.bucketId}/${
|
|
32533
|
+
_getFinalPath(path13) {
|
|
32534
|
+
return `${this.bucketId}/${path13.replace(/^\/+/, "")}`;
|
|
32522
32535
|
}
|
|
32523
|
-
_removeEmptyFolders(
|
|
32524
|
-
return
|
|
32536
|
+
_removeEmptyFolders(path13) {
|
|
32537
|
+
return path13.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
32525
32538
|
}
|
|
32526
32539
|
transformOptsToQueryString(transform2) {
|
|
32527
32540
|
const params = [];
|
|
@@ -41792,89 +41805,11 @@ var REMIX_ERROR_CODES = {
|
|
|
41792
41805
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
41793
41806
|
var import_path11 = __toESM(require("path"), 1);
|
|
41794
41807
|
|
|
41795
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41796
|
-
var
|
|
41797
|
-
var import_path2 = __toESM(require("path"), 1);
|
|
41798
|
-
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
41799
|
-
var import_path3 = __toESM(require("path"), 1);
|
|
41800
|
-
async function reserveDirectory(targetDir) {
|
|
41801
|
-
try {
|
|
41802
|
-
await import_promises3.default.mkdir(targetDir);
|
|
41803
|
-
return targetDir;
|
|
41804
|
-
} catch (error2) {
|
|
41805
|
-
if (error2?.code === "EEXIST") {
|
|
41806
|
-
throw new RemixError("Output directory already exists.", {
|
|
41807
|
-
exitCode: 2,
|
|
41808
|
-
hint: `Choose an empty destination path: ${targetDir}`
|
|
41809
|
-
});
|
|
41810
|
-
}
|
|
41811
|
-
throw error2;
|
|
41812
|
-
}
|
|
41813
|
-
}
|
|
41814
|
-
async function reserveAvailableDirPath(preferredDir) {
|
|
41815
|
-
const parent = import_path3.default.dirname(preferredDir);
|
|
41816
|
-
const base = import_path3.default.basename(preferredDir);
|
|
41817
|
-
for (let i2 = 1; i2 <= 1e3; i2 += 1) {
|
|
41818
|
-
const candidate = i2 === 1 ? preferredDir : import_path3.default.join(parent, `${base}-${i2}`);
|
|
41819
|
-
try {
|
|
41820
|
-
await import_promises3.default.mkdir(candidate);
|
|
41821
|
-
return candidate;
|
|
41822
|
-
} catch (error2) {
|
|
41823
|
-
if (error2?.code === "EEXIST") continue;
|
|
41824
|
-
throw error2;
|
|
41825
|
-
}
|
|
41826
|
-
}
|
|
41827
|
-
throw new RemixError("No available output directory name.", {
|
|
41828
|
-
exitCode: 2,
|
|
41829
|
-
hint: `Tried ${base} through ${base}-1000 under ${parent}.`
|
|
41830
|
-
});
|
|
41831
|
-
}
|
|
41832
|
-
async function writeJsonAtomic2(filePath, value) {
|
|
41833
|
-
const dir = import_path3.default.dirname(filePath);
|
|
41834
|
-
await import_promises3.default.mkdir(dir, { recursive: true });
|
|
41835
|
-
const tmp = `${filePath}.tmp-${Date.now()}`;
|
|
41836
|
-
await import_promises3.default.writeFile(tmp, `${JSON.stringify(value, null, 2)}
|
|
41837
|
-
`, "utf8");
|
|
41838
|
-
await import_promises3.default.rename(tmp, filePath);
|
|
41839
|
-
}
|
|
41840
|
-
function getCollabBindingPath(repoRoot) {
|
|
41841
|
-
return import_path2.default.join(repoRoot, ".remix", "config.json");
|
|
41842
|
-
}
|
|
41843
|
-
async function readCollabBinding(repoRoot) {
|
|
41844
|
-
try {
|
|
41845
|
-
const raw = await import_promises2.default.readFile(getCollabBindingPath(repoRoot), "utf8");
|
|
41846
|
-
const parsed = JSON.parse(raw);
|
|
41847
|
-
if (parsed?.schemaVersion !== 1) return null;
|
|
41848
|
-
if (!parsed.projectId || !parsed.currentAppId || !parsed.upstreamAppId) return null;
|
|
41849
|
-
return {
|
|
41850
|
-
schemaVersion: 1,
|
|
41851
|
-
projectId: parsed.projectId,
|
|
41852
|
-
currentAppId: parsed.currentAppId,
|
|
41853
|
-
upstreamAppId: parsed.upstreamAppId,
|
|
41854
|
-
threadId: parsed.threadId ?? null,
|
|
41855
|
-
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
41856
|
-
remoteUrl: parsed.remoteUrl ?? null,
|
|
41857
|
-
defaultBranch: parsed.defaultBranch ?? null,
|
|
41858
|
-
preferredBranch: parsed.preferredBranch ?? parsed.defaultBranch ?? null
|
|
41859
|
-
};
|
|
41860
|
-
} catch {
|
|
41861
|
-
return null;
|
|
41862
|
-
}
|
|
41863
|
-
}
|
|
41864
|
-
async function writeCollabBinding(repoRoot, binding) {
|
|
41865
|
-
const filePath = getCollabBindingPath(repoRoot);
|
|
41866
|
-
await writeJsonAtomic2(filePath, {
|
|
41867
|
-
schemaVersion: 1,
|
|
41868
|
-
...binding
|
|
41869
|
-
});
|
|
41870
|
-
return filePath;
|
|
41871
|
-
}
|
|
41872
|
-
|
|
41873
|
-
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
41874
|
-
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
41808
|
+
// node_modules/@remixhq/core/dist/chunk-RREREIGW.js
|
|
41809
|
+
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
41875
41810
|
var import_crypto = require("crypto");
|
|
41876
41811
|
var import_os2 = __toESM(require("os"), 1);
|
|
41877
|
-
var
|
|
41812
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
41878
41813
|
|
|
41879
41814
|
// node_modules/is-plain-obj/index.js
|
|
41880
41815
|
function isPlainObject4(value) {
|
|
@@ -42806,7 +42741,7 @@ var npmRunPathEnv = ({ env = import_node_process6.default.env, ...options } = {}
|
|
|
42806
42741
|
};
|
|
42807
42742
|
|
|
42808
42743
|
// node_modules/execa/lib/terminate/kill.js
|
|
42809
|
-
var
|
|
42744
|
+
var import_promises2 = require("timers/promises");
|
|
42810
42745
|
|
|
42811
42746
|
// node_modules/execa/lib/return/final-error.js
|
|
42812
42747
|
var getFinalError = (originalError, message, isSync) => {
|
|
@@ -43313,7 +43248,7 @@ var killOnTimeout = async ({ kill, forceKillAfterDelay, context, controllerSigna
|
|
|
43313
43248
|
return;
|
|
43314
43249
|
}
|
|
43315
43250
|
try {
|
|
43316
|
-
await (0,
|
|
43251
|
+
await (0, import_promises2.setTimeout)(forceKillAfterDelay, void 0, { signal: controllerSignal });
|
|
43317
43252
|
if (kill("SIGKILL")) {
|
|
43318
43253
|
context.isForcefullyTerminated ??= true;
|
|
43319
43254
|
}
|
|
@@ -43344,7 +43279,7 @@ var terminateOnCancel = async (subprocess, cancelSignal, context, { signal }) =>
|
|
|
43344
43279
|
};
|
|
43345
43280
|
|
|
43346
43281
|
// node_modules/execa/lib/ipc/graceful.js
|
|
43347
|
-
var
|
|
43282
|
+
var import_promises4 = require("timers/promises");
|
|
43348
43283
|
|
|
43349
43284
|
// node_modules/execa/lib/ipc/send.js
|
|
43350
43285
|
var import_node_util5 = require("util");
|
|
@@ -43531,7 +43466,7 @@ var import_node_events4 = require("events");
|
|
|
43531
43466
|
|
|
43532
43467
|
// node_modules/execa/lib/ipc/incoming.js
|
|
43533
43468
|
var import_node_events3 = require("events");
|
|
43534
|
-
var
|
|
43469
|
+
var import_promises3 = require("timers/promises");
|
|
43535
43470
|
|
|
43536
43471
|
// node_modules/execa/lib/ipc/reference.js
|
|
43537
43472
|
var addReference = (channel, reference) => {
|
|
@@ -43578,7 +43513,7 @@ var onMessage = async ({ anyProcess, channel, isSubprocess, ipcEmitter }, wrappe
|
|
|
43578
43513
|
}
|
|
43579
43514
|
while (incomingMessages.length > 0) {
|
|
43580
43515
|
await waitForOutgoingMessages(anyProcess, ipcEmitter, wrappedMessage);
|
|
43581
|
-
await
|
|
43516
|
+
await import_promises3.scheduler.yield();
|
|
43582
43517
|
const message = await handleStrictRequest({
|
|
43583
43518
|
wrappedMessage: incomingMessages[0],
|
|
43584
43519
|
anyProcess,
|
|
@@ -43858,7 +43793,7 @@ var startIpc = async ({ anyProcess, channel, isSubprocess, ipc }) => {
|
|
|
43858
43793
|
return;
|
|
43859
43794
|
}
|
|
43860
43795
|
getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
43861
|
-
await
|
|
43796
|
+
await import_promises4.scheduler.yield();
|
|
43862
43797
|
};
|
|
43863
43798
|
var cancelListening = false;
|
|
43864
43799
|
var handleAbort = (wrappedMessage) => {
|
|
@@ -43931,7 +43866,7 @@ var getReason = ({ reason }) => {
|
|
|
43931
43866
|
};
|
|
43932
43867
|
|
|
43933
43868
|
// node_modules/execa/lib/terminate/timeout.js
|
|
43934
|
-
var
|
|
43869
|
+
var import_promises5 = require("timers/promises");
|
|
43935
43870
|
var validateTimeout = ({ timeout }) => {
|
|
43936
43871
|
if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
|
|
43937
43872
|
throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);
|
|
@@ -43939,7 +43874,7 @@ var validateTimeout = ({ timeout }) => {
|
|
|
43939
43874
|
};
|
|
43940
43875
|
var throwOnTimeout = (subprocess, timeout, context, controller) => timeout === 0 || timeout === void 0 ? [] : [killAfterTimeout(subprocess, timeout, context, controller)];
|
|
43941
43876
|
var killAfterTimeout = async (subprocess, timeout, context, { signal }) => {
|
|
43942
|
-
await (0,
|
|
43877
|
+
await (0, import_promises5.setTimeout)(timeout, void 0, { signal });
|
|
43943
43878
|
context.terminationReason ??= "timeout";
|
|
43944
43879
|
subprocess.kill();
|
|
43945
43880
|
throw new DiscardedError();
|
|
@@ -44196,7 +44131,7 @@ var CR_BINARY = CR.codePointAt(0);
|
|
|
44196
44131
|
|
|
44197
44132
|
// node_modules/get-stream/source/index.js
|
|
44198
44133
|
var import_node_events6 = require("events");
|
|
44199
|
-
var
|
|
44134
|
+
var import_promises6 = require("stream/promises");
|
|
44200
44135
|
|
|
44201
44136
|
// node_modules/is-stream/index.js
|
|
44202
44137
|
function isStream(stream, { checkOpen = true } = {}) {
|
|
@@ -44562,7 +44497,7 @@ var stringMethods = {
|
|
|
44562
44497
|
};
|
|
44563
44498
|
|
|
44564
44499
|
// node_modules/get-stream/source/index.js
|
|
44565
|
-
Object.assign(nodeImports, { on: import_node_events6.on, finished:
|
|
44500
|
+
Object.assign(nodeImports, { on: import_node_events6.on, finished: import_promises6.finished });
|
|
44566
44501
|
|
|
44567
44502
|
// node_modules/execa/lib/io/max-buffer.js
|
|
44568
44503
|
var handleMaxBuffer = ({ error: error2, stream, readableObjectMode, lines, encoding, fdNumber }) => {
|
|
@@ -46257,13 +46192,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
|
|
|
46257
46192
|
}
|
|
46258
46193
|
};
|
|
46259
46194
|
var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
46260
|
-
for (const { path:
|
|
46261
|
-
const pathString = typeof
|
|
46195
|
+
for (const { path: path13, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
|
|
46196
|
+
const pathString = typeof path13 === "string" ? path13 : path13.toString();
|
|
46262
46197
|
if (append || outputFiles.has(pathString)) {
|
|
46263
|
-
(0, import_node_fs4.appendFileSync)(
|
|
46198
|
+
(0, import_node_fs4.appendFileSync)(path13, serializedResult);
|
|
46264
46199
|
} else {
|
|
46265
46200
|
outputFiles.add(pathString);
|
|
46266
|
-
(0, import_node_fs4.writeFileSync)(
|
|
46201
|
+
(0, import_node_fs4.writeFileSync)(path13, serializedResult);
|
|
46267
46202
|
}
|
|
46268
46203
|
}
|
|
46269
46204
|
};
|
|
@@ -46754,7 +46689,7 @@ var addPropertiesAsync = {
|
|
|
46754
46689
|
// node_modules/@sindresorhus/merge-streams/index.js
|
|
46755
46690
|
var import_node_events10 = require("events");
|
|
46756
46691
|
var import_node_stream4 = require("stream");
|
|
46757
|
-
var
|
|
46692
|
+
var import_promises7 = require("stream/promises");
|
|
46758
46693
|
function mergeStreams(streams) {
|
|
46759
46694
|
if (!Array.isArray(streams)) {
|
|
46760
46695
|
throw new TypeError(`Expected an array, got \`${typeof streams}\`.`);
|
|
@@ -46837,7 +46772,7 @@ var onMergedStreamFinished = async (passThroughStream, streams, unpipeEvent) =>
|
|
|
46837
46772
|
};
|
|
46838
46773
|
var onMergedStreamEnd = async (passThroughStream, { signal }) => {
|
|
46839
46774
|
try {
|
|
46840
|
-
await (0,
|
|
46775
|
+
await (0, import_promises7.finished)(passThroughStream, { signal, cleanup: true });
|
|
46841
46776
|
} catch (error2) {
|
|
46842
46777
|
errorOrAbortStream(passThroughStream, error2);
|
|
46843
46778
|
throw error2;
|
|
@@ -46904,7 +46839,7 @@ var afterMergedStreamFinished = async (onFinished, stream, { signal }) => {
|
|
|
46904
46839
|
};
|
|
46905
46840
|
var onInputStreamEnd = async ({ passThroughStream, stream, streams, ended, aborted: aborted3, controller: { signal } }) => {
|
|
46906
46841
|
try {
|
|
46907
|
-
await (0,
|
|
46842
|
+
await (0, import_promises7.finished)(stream, {
|
|
46908
46843
|
signal,
|
|
46909
46844
|
cleanup: true,
|
|
46910
46845
|
readable: true,
|
|
@@ -46969,7 +46904,7 @@ var PASSTHROUGH_LISTENERS_COUNT = 2;
|
|
|
46969
46904
|
var PASSTHROUGH_LISTENERS_PER_STREAM = 1;
|
|
46970
46905
|
|
|
46971
46906
|
// node_modules/execa/lib/io/pipeline.js
|
|
46972
|
-
var
|
|
46907
|
+
var import_promises8 = require("stream/promises");
|
|
46973
46908
|
var pipeStreams = (source, destination) => {
|
|
46974
46909
|
source.pipe(destination);
|
|
46975
46910
|
onSourceFinish(source, destination);
|
|
@@ -46980,7 +46915,7 @@ var onSourceFinish = async (source, destination) => {
|
|
|
46980
46915
|
return;
|
|
46981
46916
|
}
|
|
46982
46917
|
try {
|
|
46983
|
-
await (0,
|
|
46918
|
+
await (0, import_promises8.finished)(source, { cleanup: true, readable: true, writable: false });
|
|
46984
46919
|
} catch {
|
|
46985
46920
|
}
|
|
46986
46921
|
endDestinationStream(destination);
|
|
@@ -46995,7 +46930,7 @@ var onDestinationFinish = async (source, destination) => {
|
|
|
46995
46930
|
return;
|
|
46996
46931
|
}
|
|
46997
46932
|
try {
|
|
46998
|
-
await (0,
|
|
46933
|
+
await (0, import_promises8.finished)(destination, { cleanup: true, readable: false, writable: true });
|
|
46999
46934
|
} catch {
|
|
47000
46935
|
}
|
|
47001
46936
|
abortSourceStream(source);
|
|
@@ -47466,7 +47401,7 @@ var waitForBothSubprocesses = async (subprocessPromises) => {
|
|
|
47466
47401
|
};
|
|
47467
47402
|
|
|
47468
47403
|
// node_modules/execa/lib/pipe/streaming.js
|
|
47469
|
-
var
|
|
47404
|
+
var import_promises9 = require("stream/promises");
|
|
47470
47405
|
var pipeSubprocessStream = (sourceStream, destinationStream, maxListenersController) => {
|
|
47471
47406
|
const mergedStream = MERGED_STREAMS.has(destinationStream) ? pipeMoreSubprocessStream(sourceStream, destinationStream) : pipeFirstSubprocessStream(sourceStream, destinationStream);
|
|
47472
47407
|
incrementMaxListeners(sourceStream, SOURCE_LISTENERS_PER_PIPE, maxListenersController.signal);
|
|
@@ -47487,7 +47422,7 @@ var pipeMoreSubprocessStream = (sourceStream, destinationStream) => {
|
|
|
47487
47422
|
};
|
|
47488
47423
|
var cleanupMergedStreamsMap = async (destinationStream) => {
|
|
47489
47424
|
try {
|
|
47490
|
-
await (0,
|
|
47425
|
+
await (0, import_promises9.finished)(destinationStream, { cleanup: true, readable: false, writable: true });
|
|
47491
47426
|
} catch {
|
|
47492
47427
|
}
|
|
47493
47428
|
MERGED_STREAMS.delete(destinationStream);
|
|
@@ -47571,7 +47506,7 @@ var handlePipePromise = async ({
|
|
|
47571
47506
|
var getSubprocessPromises = (sourcePromise, destination) => Promise.allSettled([sourcePromise, destination]);
|
|
47572
47507
|
|
|
47573
47508
|
// node_modules/execa/lib/io/contents.js
|
|
47574
|
-
var
|
|
47509
|
+
var import_promises10 = require("timers/promises");
|
|
47575
47510
|
|
|
47576
47511
|
// node_modules/execa/lib/io/iterate.js
|
|
47577
47512
|
var import_node_events12 = require("events");
|
|
@@ -47723,7 +47658,7 @@ var logOutputAsync = async ({ stream, onStreamEnd, fdNumber, encoding, allMixed,
|
|
|
47723
47658
|
await logLines(linesIterable, stream, fdNumber, verboseInfo);
|
|
47724
47659
|
};
|
|
47725
47660
|
var resumeStream = async (stream) => {
|
|
47726
|
-
await (0,
|
|
47661
|
+
await (0, import_promises10.setImmediate)();
|
|
47727
47662
|
if (stream.readableFlowing === null) {
|
|
47728
47663
|
stream.resume();
|
|
47729
47664
|
}
|
|
@@ -47758,14 +47693,14 @@ var getBufferedData = async (streamPromise) => {
|
|
|
47758
47693
|
var handleBufferedData = ({ bufferedData }) => isArrayBuffer(bufferedData) ? new Uint8Array(bufferedData) : bufferedData;
|
|
47759
47694
|
|
|
47760
47695
|
// node_modules/execa/lib/resolve/wait-stream.js
|
|
47761
|
-
var
|
|
47696
|
+
var import_promises11 = require("stream/promises");
|
|
47762
47697
|
var waitForStream = async (stream, fdNumber, streamInfo, { isSameDirection, stopOnExit = false } = {}) => {
|
|
47763
47698
|
const state = handleStdinDestroy(stream, streamInfo);
|
|
47764
47699
|
const abortController = new AbortController();
|
|
47765
47700
|
try {
|
|
47766
47701
|
await Promise.race([
|
|
47767
47702
|
...stopOnExit ? [streamInfo.exitPromise] : [],
|
|
47768
|
-
(0,
|
|
47703
|
+
(0, import_promises11.finished)(stream, { cleanup: true, signal: abortController.signal })
|
|
47769
47704
|
]);
|
|
47770
47705
|
} catch (error2) {
|
|
47771
47706
|
if (!state.stdinCleanedUp) {
|
|
@@ -48079,7 +48014,7 @@ var import_node_stream6 = require("stream");
|
|
|
48079
48014
|
var import_node_util9 = require("util");
|
|
48080
48015
|
|
|
48081
48016
|
// node_modules/execa/lib/convert/shared.js
|
|
48082
|
-
var
|
|
48017
|
+
var import_promises12 = require("stream/promises");
|
|
48083
48018
|
var safeWaitForSubprocessStdin = async (subprocessStdin) => {
|
|
48084
48019
|
if (subprocessStdin === void 0) {
|
|
48085
48020
|
return;
|
|
@@ -48099,10 +48034,10 @@ var safeWaitForSubprocessStdout = async (subprocessStdout) => {
|
|
|
48099
48034
|
}
|
|
48100
48035
|
};
|
|
48101
48036
|
var waitForSubprocessStdin = async (subprocessStdin) => {
|
|
48102
|
-
await (0,
|
|
48037
|
+
await (0, import_promises12.finished)(subprocessStdin, { cleanup: true, readable: false, writable: true });
|
|
48103
48038
|
};
|
|
48104
48039
|
var waitForSubprocessStdout = async (subprocessStdout) => {
|
|
48105
|
-
await (0,
|
|
48040
|
+
await (0, import_promises12.finished)(subprocessStdout, { cleanup: true, readable: true, writable: false });
|
|
48106
48041
|
};
|
|
48107
48042
|
var waitForSubprocess = async (subprocess, error2) => {
|
|
48108
48043
|
await subprocess;
|
|
@@ -48651,7 +48586,7 @@ var {
|
|
|
48651
48586
|
getCancelSignal: getCancelSignal2
|
|
48652
48587
|
} = getIpcExport();
|
|
48653
48588
|
|
|
48654
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
48589
|
+
// node_modules/@remixhq/core/dist/chunk-RREREIGW.js
|
|
48655
48590
|
var GIT_REMOTE_PROTOCOL_RE = /^(https?|ssh):\/\//i;
|
|
48656
48591
|
var SCP_LIKE_GIT_REMOTE_RE = /^(?<user>[^@\s]+)@(?<host>[^:\s]+):(?<path>[^\\\s]+)$/;
|
|
48657
48592
|
var CANONICAL_GIT_REMOTE_RE = /^(?<host>(?:localhost|[a-z0-9.-]+))\/(?<path>[^\\\s]+)$/i;
|
|
@@ -48709,8 +48644,8 @@ function sanitizeRefFragment(value) {
|
|
|
48709
48644
|
return value.trim().replace(/[^A-Za-z0-9._/-]+/g, "-").replace(/\/{2,}/g, "/").replace(/^\/+|\/+$/g, "").replace(/^-+|-+$/g, "").slice(0, 120);
|
|
48710
48645
|
}
|
|
48711
48646
|
function normalizeRepoRelativePath(value) {
|
|
48712
|
-
const normalized =
|
|
48713
|
-
if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../") ||
|
|
48647
|
+
const normalized = import_path2.default.posix.normalize(value.replace(/\\/g, "/").trim());
|
|
48648
|
+
if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../") || import_path2.default.posix.isAbsolute(normalized)) {
|
|
48714
48649
|
throw new RemixError("Git returned an invalid repository-relative path.", {
|
|
48715
48650
|
exitCode: 1,
|
|
48716
48651
|
hint: `Path: ${value}`
|
|
@@ -48719,11 +48654,11 @@ function normalizeRepoRelativePath(value) {
|
|
|
48719
48654
|
return normalized;
|
|
48720
48655
|
}
|
|
48721
48656
|
function resolveRepoRelativePath(repoRoot, relativePath) {
|
|
48722
|
-
return
|
|
48657
|
+
return import_path2.default.resolve(repoRoot, ...relativePath.split("/"));
|
|
48723
48658
|
}
|
|
48724
48659
|
function isWithinRepoRoot(repoRoot, targetPath) {
|
|
48725
|
-
const relative =
|
|
48726
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
48660
|
+
const relative = import_path2.default.relative(repoRoot, targetPath);
|
|
48661
|
+
return relative === "" || !relative.startsWith("..") && !import_path2.default.isAbsolute(relative);
|
|
48727
48662
|
}
|
|
48728
48663
|
function sha256Hex(value) {
|
|
48729
48664
|
return (0, import_crypto.createHash)("sha256").update(value).digest("hex");
|
|
@@ -48733,7 +48668,7 @@ function resolveGitReportedPath(cwd, reportedPath) {
|
|
|
48733
48668
|
if (!value) {
|
|
48734
48669
|
throw new RemixError("Git returned an empty internal path.", { exitCode: 1 });
|
|
48735
48670
|
}
|
|
48736
|
-
return
|
|
48671
|
+
return import_path2.default.isAbsolute(value) ? value : import_path2.default.resolve(cwd, value);
|
|
48737
48672
|
}
|
|
48738
48673
|
function parseGitNameStatusZ(stdout) {
|
|
48739
48674
|
const tokens = stdout.split("\0");
|
|
@@ -48804,12 +48739,12 @@ function classifyGitApplyFailure(detail) {
|
|
|
48804
48739
|
return "unknown";
|
|
48805
48740
|
}
|
|
48806
48741
|
async function pruneEmptyParentDirectories(repoRoot, filePath) {
|
|
48807
|
-
let current =
|
|
48742
|
+
let current = import_path2.default.dirname(filePath);
|
|
48808
48743
|
while (current !== repoRoot && isWithinRepoRoot(repoRoot, current)) {
|
|
48809
|
-
const entries = await
|
|
48744
|
+
const entries = await import_promises13.default.readdir(current).catch(() => null);
|
|
48810
48745
|
if (!entries || entries.length > 0) return;
|
|
48811
|
-
await
|
|
48812
|
-
current =
|
|
48746
|
+
await import_promises13.default.rmdir(current).catch(() => void 0);
|
|
48747
|
+
current = import_path2.default.dirname(current);
|
|
48813
48748
|
}
|
|
48814
48749
|
}
|
|
48815
48750
|
async function findGitRoot(startDir) {
|
|
@@ -48911,8 +48846,8 @@ async function getWorkspaceSnapshot(cwd) {
|
|
|
48911
48846
|
throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
|
|
48912
48847
|
}
|
|
48913
48848
|
const includedUntrackedPaths = Array.from(new Set((await listUntrackedFiles(cwd)).map((entry) => normalizeRepoRelativePath(entry))));
|
|
48914
|
-
const tempDir = await
|
|
48915
|
-
const tempIndexPath =
|
|
48849
|
+
const tempDir = await import_promises13.default.mkdtemp(import_path2.default.join(import_os2.default.tmpdir(), "remix-index-"));
|
|
48850
|
+
const tempIndexPath = import_path2.default.join(tempDir, "index");
|
|
48916
48851
|
const env = { ...process.env, GIT_INDEX_FILE: tempIndexPath };
|
|
48917
48852
|
try {
|
|
48918
48853
|
try {
|
|
@@ -48935,14 +48870,14 @@ async function getWorkspaceSnapshot(cwd) {
|
|
|
48935
48870
|
});
|
|
48936
48871
|
}
|
|
48937
48872
|
} finally {
|
|
48938
|
-
await
|
|
48873
|
+
await import_promises13.default.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
|
|
48939
48874
|
}
|
|
48940
48875
|
}
|
|
48941
48876
|
async function writeTempUnifiedDiffBackup(diff, prefix = "remix-add-backup") {
|
|
48942
48877
|
const safePrefix = prefix.replace(/[^a-zA-Z0-9._-]+/g, "-") || "remix-add-backup";
|
|
48943
|
-
const tmpDir = await
|
|
48944
|
-
const backupPath =
|
|
48945
|
-
await
|
|
48878
|
+
const tmpDir = await import_promises13.default.mkdtemp(import_path2.default.join(import_os2.default.tmpdir(), `${safePrefix}-`));
|
|
48879
|
+
const backupPath = import_path2.default.join(tmpDir, "submitted.diff");
|
|
48880
|
+
await import_promises13.default.writeFile(backupPath, diff, "utf8");
|
|
48946
48881
|
return { backupPath, diffSha256: sha256Hex(diff) };
|
|
48947
48882
|
}
|
|
48948
48883
|
async function validateUnifiedDiff(cwd, diff) {
|
|
@@ -48959,7 +48894,7 @@ async function validateUnifiedDiff(cwd, diff) {
|
|
|
48959
48894
|
detail
|
|
48960
48895
|
};
|
|
48961
48896
|
} finally {
|
|
48962
|
-
await
|
|
48897
|
+
await import_promises13.default.rm(import_path2.default.dirname(backupPath), { recursive: true, force: true }).catch(() => void 0);
|
|
48963
48898
|
}
|
|
48964
48899
|
}
|
|
48965
48900
|
async function preserveWorkspaceChanges(cwd, prefix = "remix-add-preserve") {
|
|
@@ -48979,7 +48914,7 @@ async function preserveWorkspaceChanges(cwd, prefix = "remix-add-preserve") {
|
|
|
48979
48914
|
}
|
|
48980
48915
|
async function reapplyPreservedWorkspaceChanges(cwd, preserved, operation = "`remix collab add`") {
|
|
48981
48916
|
const patchFilePath = preserved.preservedDiffPath;
|
|
48982
|
-
const tempPatchHash = await
|
|
48917
|
+
const tempPatchHash = await import_promises13.default.readFile(patchFilePath, "utf8").then((content) => sha256Hex(content)).catch(() => null);
|
|
48983
48918
|
if (!tempPatchHash) {
|
|
48984
48919
|
return { status: "failed", detail: "Preserved diff artifact is missing." };
|
|
48985
48920
|
}
|
|
@@ -49019,8 +48954,8 @@ async function createGitBundle(cwd, bundleName = "repository.bundle") {
|
|
|
49019
48954
|
throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
|
|
49020
48955
|
}
|
|
49021
48956
|
const safeName = bundleName.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
49022
|
-
const tmpDir = await
|
|
49023
|
-
const bundlePath =
|
|
48957
|
+
const tmpDir = await import_promises13.default.mkdtemp(import_path2.default.join(import_os2.default.tmpdir(), "remix-bundle-"));
|
|
48958
|
+
const bundlePath = import_path2.default.join(tmpDir, safeName);
|
|
49024
48959
|
const res = await runGitDetailed(["bundle", "create", bundlePath, "--all"], cwd);
|
|
49025
48960
|
if (res.exitCode !== 0) {
|
|
49026
48961
|
const detail = [res.stderr.trim(), res.stdout.trim()].filter(Boolean).join("\n\n");
|
|
@@ -49129,7 +49064,7 @@ async function discardCapturedUntrackedChanges(repoRoot, capturedPaths) {
|
|
|
49129
49064
|
hint: `Path: ${relativePath}`
|
|
49130
49065
|
});
|
|
49131
49066
|
}
|
|
49132
|
-
await
|
|
49067
|
+
await import_promises13.default.rm(absolutePath, { recursive: true, force: true }).catch((err) => {
|
|
49133
49068
|
throw new RemixError("Failed to remove a captured untracked path before syncing.", {
|
|
49134
49069
|
exitCode: 1,
|
|
49135
49070
|
hint: err instanceof Error ? `${relativePath}
|
|
@@ -49171,7 +49106,7 @@ async function importGitBundle(cwd, bundlePath, bundleRef) {
|
|
|
49171
49106
|
}
|
|
49172
49107
|
}
|
|
49173
49108
|
async function cloneGitBundleToDirectory(bundlePath, targetDir) {
|
|
49174
|
-
const parentDir =
|
|
49109
|
+
const parentDir = import_path2.default.dirname(targetDir);
|
|
49175
49110
|
const cloneRes = await runGitDetailed(["clone", bundlePath, targetDir], parentDir);
|
|
49176
49111
|
if (cloneRes.exitCode !== 0) {
|
|
49177
49112
|
const detail = [cloneRes.stderr.trim(), cloneRes.stdout.trim()].filter(Boolean).join("\n\n");
|
|
@@ -49191,10 +49126,10 @@ async function cloneGitBundleToDirectory(bundlePath, targetDir) {
|
|
|
49191
49126
|
}
|
|
49192
49127
|
async function ensureGitInfoExcludeEntries(cwd, entries) {
|
|
49193
49128
|
const excludePath = await getGitPath(cwd, "info/exclude");
|
|
49194
|
-
await
|
|
49129
|
+
await import_promises13.default.mkdir(import_path2.default.dirname(excludePath), { recursive: true });
|
|
49195
49130
|
let current = "";
|
|
49196
49131
|
try {
|
|
49197
|
-
current = await
|
|
49132
|
+
current = await import_promises13.default.readFile(excludePath, "utf8");
|
|
49198
49133
|
} catch {
|
|
49199
49134
|
}
|
|
49200
49135
|
const lines = new Set(current.split("\n").map((line) => line.trim()).filter(Boolean));
|
|
@@ -49206,7 +49141,7 @@ async function ensureGitInfoExcludeEntries(cwd, entries) {
|
|
|
49206
49141
|
changed = true;
|
|
49207
49142
|
}
|
|
49208
49143
|
if (!changed) return;
|
|
49209
|
-
await
|
|
49144
|
+
await import_promises13.default.writeFile(excludePath, `${Array.from(lines).join("\n")}
|
|
49210
49145
|
`, "utf8");
|
|
49211
49146
|
}
|
|
49212
49147
|
async function ensureCommitExists(cwd, commitHash) {
|
|
@@ -49267,7 +49202,7 @@ async function hardResetToCommit(cwd, commitHash, operation = "`remix collab rec
|
|
|
49267
49202
|
async function buildRepoFingerprint(params) {
|
|
49268
49203
|
const remote = normalizeGitRemote(params.remoteUrl);
|
|
49269
49204
|
const defaultBranch = params.defaultBranch?.trim().toLowerCase() || "";
|
|
49270
|
-
const payload = remote ? { remote, defaultBranch } : { local:
|
|
49205
|
+
const payload = remote ? { remote, defaultBranch } : { local: import_path2.default.resolve(params.gitRoot).toLowerCase(), defaultBranch };
|
|
49271
49206
|
return (0, import_crypto.createHash)("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
49272
49207
|
}
|
|
49273
49208
|
function summarizeUnifiedDiff(diff) {
|
|
@@ -49283,6 +49218,328 @@ function summarizeUnifiedDiff(diff) {
|
|
|
49283
49218
|
return { changedFilesCount, insertions, deletions };
|
|
49284
49219
|
}
|
|
49285
49220
|
|
|
49221
|
+
// node_modules/@remixhq/core/dist/chunk-IXWQWFYT.js
|
|
49222
|
+
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
49223
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
49224
|
+
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
49225
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
49226
|
+
async function reserveDirectory(targetDir) {
|
|
49227
|
+
try {
|
|
49228
|
+
await import_promises15.default.mkdir(targetDir);
|
|
49229
|
+
return targetDir;
|
|
49230
|
+
} catch (error2) {
|
|
49231
|
+
if (error2?.code === "EEXIST") {
|
|
49232
|
+
throw new RemixError("Output directory already exists.", {
|
|
49233
|
+
exitCode: 2,
|
|
49234
|
+
hint: `Choose an empty destination path: ${targetDir}`
|
|
49235
|
+
});
|
|
49236
|
+
}
|
|
49237
|
+
throw error2;
|
|
49238
|
+
}
|
|
49239
|
+
}
|
|
49240
|
+
async function reserveAvailableDirPath(preferredDir) {
|
|
49241
|
+
const parent = import_path4.default.dirname(preferredDir);
|
|
49242
|
+
const base = import_path4.default.basename(preferredDir);
|
|
49243
|
+
for (let i2 = 1; i2 <= 1e3; i2 += 1) {
|
|
49244
|
+
const candidate = i2 === 1 ? preferredDir : import_path4.default.join(parent, `${base}-${i2}`);
|
|
49245
|
+
try {
|
|
49246
|
+
await import_promises15.default.mkdir(candidate);
|
|
49247
|
+
return candidate;
|
|
49248
|
+
} catch (error2) {
|
|
49249
|
+
if (error2?.code === "EEXIST") continue;
|
|
49250
|
+
throw error2;
|
|
49251
|
+
}
|
|
49252
|
+
}
|
|
49253
|
+
throw new RemixError("No available output directory name.", {
|
|
49254
|
+
exitCode: 2,
|
|
49255
|
+
hint: `Tried ${base} through ${base}-1000 under ${parent}.`
|
|
49256
|
+
});
|
|
49257
|
+
}
|
|
49258
|
+
async function writeJsonAtomic2(filePath, value) {
|
|
49259
|
+
const dir = import_path4.default.dirname(filePath);
|
|
49260
|
+
await import_promises15.default.mkdir(dir, { recursive: true });
|
|
49261
|
+
const tmp = `${filePath}.tmp-${Date.now()}`;
|
|
49262
|
+
await import_promises15.default.writeFile(tmp, `${JSON.stringify(value, null, 2)}
|
|
49263
|
+
`, "utf8");
|
|
49264
|
+
await import_promises15.default.rename(tmp, filePath);
|
|
49265
|
+
}
|
|
49266
|
+
function getCollabBindingPath(repoRoot) {
|
|
49267
|
+
return import_path3.default.join(repoRoot, ".remix", "config.json");
|
|
49268
|
+
}
|
|
49269
|
+
function buildBindingFileV3(params) {
|
|
49270
|
+
return {
|
|
49271
|
+
schemaVersion: 3,
|
|
49272
|
+
repoFingerprint: params.repoFingerprint,
|
|
49273
|
+
remoteUrl: params.remoteUrl,
|
|
49274
|
+
defaultBranch: params.defaultBranch,
|
|
49275
|
+
branchBindings: params.branchBindings,
|
|
49276
|
+
...params.explicitRootBinding ? { explicitRootBinding: params.explicitRootBinding } : {}
|
|
49277
|
+
};
|
|
49278
|
+
}
|
|
49279
|
+
function normalizeBranchName(value) {
|
|
49280
|
+
const normalized = String(value ?? "").trim();
|
|
49281
|
+
return normalized || null;
|
|
49282
|
+
}
|
|
49283
|
+
function normalizeProjectId(value) {
|
|
49284
|
+
const normalized = String(value ?? "").trim();
|
|
49285
|
+
return normalized || null;
|
|
49286
|
+
}
|
|
49287
|
+
function normalizeBranchBinding(value) {
|
|
49288
|
+
if (!value?.currentAppId || !value?.upstreamAppId) return null;
|
|
49289
|
+
return {
|
|
49290
|
+
projectId: normalizeProjectId(value.projectId),
|
|
49291
|
+
currentAppId: value.currentAppId,
|
|
49292
|
+
upstreamAppId: value.upstreamAppId,
|
|
49293
|
+
threadId: value.threadId ?? null,
|
|
49294
|
+
laneId: value.laneId ?? null,
|
|
49295
|
+
bindingMode: value.bindingMode === "legacy" ? "legacy" : value.bindingMode === "explicit_root" ? "explicit_root" : "lane"
|
|
49296
|
+
};
|
|
49297
|
+
}
|
|
49298
|
+
function buildResolvedBinding(params) {
|
|
49299
|
+
if (!params.binding) return null;
|
|
49300
|
+
return {
|
|
49301
|
+
schemaVersion: 3,
|
|
49302
|
+
projectId: params.binding.projectId ?? params.fallbackProjectId,
|
|
49303
|
+
currentAppId: params.binding.currentAppId,
|
|
49304
|
+
upstreamAppId: params.binding.upstreamAppId,
|
|
49305
|
+
threadId: params.binding.threadId,
|
|
49306
|
+
repoFingerprint: params.repoFingerprint,
|
|
49307
|
+
remoteUrl: params.remoteUrl,
|
|
49308
|
+
defaultBranch: params.defaultBranch,
|
|
49309
|
+
laneId: params.binding.laneId,
|
|
49310
|
+
branchName: params.branchName,
|
|
49311
|
+
bindingMode: params.binding.bindingMode
|
|
49312
|
+
};
|
|
49313
|
+
}
|
|
49314
|
+
function deriveFallbackProjectId(params) {
|
|
49315
|
+
const candidates = [
|
|
49316
|
+
params.currentBranch ? params.branchBindings[params.currentBranch]?.projectId ?? null : null,
|
|
49317
|
+
params.defaultBranch ? params.branchBindings[params.defaultBranch]?.projectId ?? null : null,
|
|
49318
|
+
...Object.values(params.branchBindings).map((binding) => binding.projectId),
|
|
49319
|
+
params.legacyProjectId
|
|
49320
|
+
];
|
|
49321
|
+
for (const candidate of candidates) {
|
|
49322
|
+
if (candidate) return candidate;
|
|
49323
|
+
}
|
|
49324
|
+
return null;
|
|
49325
|
+
}
|
|
49326
|
+
async function readCollabBindingState(repoRoot, options) {
|
|
49327
|
+
try {
|
|
49328
|
+
const persist = options?.persist === true;
|
|
49329
|
+
const filePath = getCollabBindingPath(repoRoot);
|
|
49330
|
+
const raw = await import_promises14.default.readFile(filePath, "utf8");
|
|
49331
|
+
const parsed = JSON.parse(raw);
|
|
49332
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
49333
|
+
const currentBranch = normalizeBranchName(await getCurrentBranch(repoRoot).catch(() => null));
|
|
49334
|
+
if (parsed.schemaVersion === 1) {
|
|
49335
|
+
if (!parsed.currentAppId || !parsed.upstreamAppId) return null;
|
|
49336
|
+
const projectId = normalizeProjectId(parsed.projectId);
|
|
49337
|
+
const preferredBranch = normalizeBranchName(parsed.preferredBranch ?? parsed.defaultBranch ?? null);
|
|
49338
|
+
const branchKey = preferredBranch ?? currentBranch ?? null;
|
|
49339
|
+
const branchBindings2 = branchKey ? {
|
|
49340
|
+
[branchKey]: {
|
|
49341
|
+
projectId,
|
|
49342
|
+
currentAppId: parsed.currentAppId,
|
|
49343
|
+
upstreamAppId: parsed.upstreamAppId,
|
|
49344
|
+
threadId: parsed.threadId ?? null,
|
|
49345
|
+
laneId: null,
|
|
49346
|
+
bindingMode: "legacy"
|
|
49347
|
+
}
|
|
49348
|
+
} : {};
|
|
49349
|
+
const migratedFile = buildBindingFileV3({
|
|
49350
|
+
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
49351
|
+
remoteUrl: parsed.remoteUrl ?? null,
|
|
49352
|
+
defaultBranch: parsed.defaultBranch ?? null,
|
|
49353
|
+
branchBindings: branchBindings2
|
|
49354
|
+
});
|
|
49355
|
+
if (persist) {
|
|
49356
|
+
try {
|
|
49357
|
+
await writeJsonAtomic2(filePath, migratedFile);
|
|
49358
|
+
} catch {
|
|
49359
|
+
}
|
|
49360
|
+
}
|
|
49361
|
+
return {
|
|
49362
|
+
schemaVersion: 3,
|
|
49363
|
+
projectId,
|
|
49364
|
+
repoFingerprint: migratedFile.repoFingerprint,
|
|
49365
|
+
remoteUrl: migratedFile.remoteUrl,
|
|
49366
|
+
defaultBranch: migratedFile.defaultBranch,
|
|
49367
|
+
currentBranch,
|
|
49368
|
+
branchBindings: migratedFile.branchBindings,
|
|
49369
|
+
explicitRootBinding: null,
|
|
49370
|
+
binding: buildResolvedBinding({
|
|
49371
|
+
fallbackProjectId: projectId,
|
|
49372
|
+
repoFingerprint: migratedFile.repoFingerprint,
|
|
49373
|
+
remoteUrl: migratedFile.remoteUrl,
|
|
49374
|
+
defaultBranch: migratedFile.defaultBranch,
|
|
49375
|
+
branchName: branchKey,
|
|
49376
|
+
binding: branchKey ? migratedFile.branchBindings[branchKey] : null
|
|
49377
|
+
})
|
|
49378
|
+
};
|
|
49379
|
+
}
|
|
49380
|
+
if (parsed.schemaVersion !== 2 && parsed.schemaVersion !== 3) return null;
|
|
49381
|
+
const file = parsed;
|
|
49382
|
+
let shouldPersistNormalizedBranchBindings = false;
|
|
49383
|
+
const legacyProjectId = normalizeProjectId(file.projectId);
|
|
49384
|
+
const branchBindings = Object.fromEntries(
|
|
49385
|
+
Object.entries(file.branchBindings ?? {}).map(([branchName, branchBinding]) => {
|
|
49386
|
+
const normalized = normalizeBranchBinding(branchBinding);
|
|
49387
|
+
const rawProjectId = branchBinding && typeof branchBinding === "object" && "projectId" in branchBinding ? normalizeProjectId(branchBinding.projectId) : null;
|
|
49388
|
+
const rawBindingMode = branchBinding && typeof branchBinding === "object" && "bindingMode" in branchBinding ? branchBinding.bindingMode : null;
|
|
49389
|
+
const hasLegacyPreferredBranch = Boolean(branchBinding) && typeof branchBinding === "object" && "preferredBranch" in branchBinding;
|
|
49390
|
+
let normalizedWithProject = normalized;
|
|
49391
|
+
if (normalizedWithProject && !normalizedWithProject.projectId && legacyProjectId) {
|
|
49392
|
+
normalizedWithProject = {
|
|
49393
|
+
...normalizedWithProject,
|
|
49394
|
+
projectId: legacyProjectId
|
|
49395
|
+
};
|
|
49396
|
+
}
|
|
49397
|
+
if (normalizedWithProject && (rawBindingMode !== normalizedWithProject.bindingMode || hasLegacyPreferredBranch || rawProjectId !== normalizedWithProject.projectId)) {
|
|
49398
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49399
|
+
}
|
|
49400
|
+
return [branchName, normalizedWithProject];
|
|
49401
|
+
}).filter((entry) => Boolean(entry[1]))
|
|
49402
|
+
);
|
|
49403
|
+
const legacyExplicitBinding = normalizeBranchBinding(file.explicitBinding ?? null);
|
|
49404
|
+
const legacyExplicitBranch = currentBranch ?? normalizeBranchName(file.defaultBranch);
|
|
49405
|
+
if (legacyExplicitBinding && legacyExplicitBranch) {
|
|
49406
|
+
branchBindings[legacyExplicitBranch] = {
|
|
49407
|
+
...legacyExplicitBinding,
|
|
49408
|
+
projectId: legacyExplicitBinding.projectId ?? branchBindings[legacyExplicitBranch]?.projectId ?? legacyProjectId,
|
|
49409
|
+
bindingMode: "lane"
|
|
49410
|
+
};
|
|
49411
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49412
|
+
}
|
|
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)) {
|
|
49429
|
+
try {
|
|
49430
|
+
await writeJsonAtomic2(
|
|
49431
|
+
filePath,
|
|
49432
|
+
buildBindingFileV3({
|
|
49433
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49434
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49435
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49436
|
+
branchBindings,
|
|
49437
|
+
explicitRootBinding
|
|
49438
|
+
})
|
|
49439
|
+
);
|
|
49440
|
+
} catch {
|
|
49441
|
+
}
|
|
49442
|
+
}
|
|
49443
|
+
const resolvedBranch = currentBranch ?? normalizeBranchName(file.defaultBranch);
|
|
49444
|
+
const fallbackProjectId = deriveFallbackProjectId({
|
|
49445
|
+
branchBindings,
|
|
49446
|
+
currentBranch: resolvedBranch,
|
|
49447
|
+
defaultBranch: normalizeBranchName(file.defaultBranch),
|
|
49448
|
+
legacyProjectId: explicitRootBinding?.projectId ?? legacyProjectId
|
|
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);
|
|
49465
|
+
return {
|
|
49466
|
+
schemaVersion: parsed.schemaVersion,
|
|
49467
|
+
projectId: fallbackProjectId,
|
|
49468
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49469
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49470
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49471
|
+
currentBranch,
|
|
49472
|
+
branchBindings,
|
|
49473
|
+
explicitRootBinding: buildResolvedBinding({
|
|
49474
|
+
fallbackProjectId,
|
|
49475
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49476
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49477
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49478
|
+
branchName: normalizeBranchName(file.defaultBranch),
|
|
49479
|
+
binding: explicitRootBinding
|
|
49480
|
+
}),
|
|
49481
|
+
binding: resolvedBinding
|
|
49482
|
+
};
|
|
49483
|
+
} catch {
|
|
49484
|
+
return null;
|
|
49485
|
+
}
|
|
49486
|
+
}
|
|
49487
|
+
async function readCollabBinding(repoRoot) {
|
|
49488
|
+
const state = await readCollabBindingState(repoRoot);
|
|
49489
|
+
return state?.binding ?? null;
|
|
49490
|
+
}
|
|
49491
|
+
async function writeCollabBinding(repoRoot, binding) {
|
|
49492
|
+
const filePath = getCollabBindingPath(repoRoot);
|
|
49493
|
+
const currentBranch = normalizeBranchName(await getCurrentBranch(repoRoot).catch(() => null));
|
|
49494
|
+
const branchName = normalizeBranchName(binding.branchName) ?? currentBranch ?? binding.defaultBranch ?? "main";
|
|
49495
|
+
const existing = await readCollabBindingState(repoRoot, { persist: true });
|
|
49496
|
+
const branchBindings = { ...existing?.branchBindings ?? {} };
|
|
49497
|
+
branchBindings[branchName] = {
|
|
49498
|
+
projectId: normalizeProjectId(binding.projectId) ?? branchBindings[branchName]?.projectId ?? existing?.projectId ?? null,
|
|
49499
|
+
currentAppId: binding.currentAppId,
|
|
49500
|
+
upstreamAppId: binding.upstreamAppId,
|
|
49501
|
+
threadId: binding.threadId ?? null,
|
|
49502
|
+
laneId: binding.laneId ?? null,
|
|
49503
|
+
bindingMode: binding.bindingMode ?? "lane"
|
|
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;
|
|
49516
|
+
await writeJsonAtomic2(
|
|
49517
|
+
filePath,
|
|
49518
|
+
buildBindingFileV3({
|
|
49519
|
+
repoFingerprint: binding.repoFingerprint ?? null,
|
|
49520
|
+
remoteUrl: binding.remoteUrl ?? null,
|
|
49521
|
+
defaultBranch: binding.defaultBranch ?? null,
|
|
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
|
|
49538
|
+
})
|
|
49539
|
+
);
|
|
49540
|
+
return filePath;
|
|
49541
|
+
}
|
|
49542
|
+
|
|
49286
49543
|
// node_modules/@remixhq/core/dist/collab.js
|
|
49287
49544
|
var import_promises16 = __toESM(require("fs/promises"), 1);
|
|
49288
49545
|
var import_path5 = __toESM(require("path"), 1);
|
|
@@ -49309,29 +49566,29 @@ function describeBranch(value) {
|
|
|
49309
49566
|
const normalized = String(value ?? "").trim();
|
|
49310
49567
|
return normalized || "(detached)";
|
|
49311
49568
|
}
|
|
49312
|
-
function
|
|
49569
|
+
function isBoundBranchMatch(currentBranch, branchName) {
|
|
49313
49570
|
const current = String(currentBranch ?? "").trim();
|
|
49314
|
-
const
|
|
49315
|
-
if (!
|
|
49316
|
-
return current ===
|
|
49571
|
+
const expected = String(branchName ?? "").trim();
|
|
49572
|
+
if (!expected || !current) return true;
|
|
49573
|
+
return current === expected;
|
|
49317
49574
|
}
|
|
49318
|
-
function
|
|
49575
|
+
function buildBranchMismatchHint(params) {
|
|
49319
49576
|
const overrideFlag = params.overrideFlag?.trim() || "--allow-branch-mismatch";
|
|
49320
49577
|
return [
|
|
49321
49578
|
`Current branch: ${describeBranch(params.currentBranch)}`,
|
|
49322
|
-
`
|
|
49323
|
-
`Switch to ${describeBranch(params.
|
|
49579
|
+
`Bound branch: ${describeBranch(params.branchName)}`,
|
|
49580
|
+
`Switch to ${describeBranch(params.branchName)} or rerun with ${overrideFlag} if this is intentional.`
|
|
49324
49581
|
].join("\n");
|
|
49325
49582
|
}
|
|
49326
|
-
function
|
|
49583
|
+
function assertBoundBranchMatch(params) {
|
|
49327
49584
|
if (params.allowBranchMismatch) return;
|
|
49328
|
-
if (
|
|
49329
|
-
throw new RemixError(`Current branch does not match this checkout's Remix
|
|
49585
|
+
if (isBoundBranchMatch(params.currentBranch, params.branchName)) return;
|
|
49586
|
+
throw new RemixError(`Current branch does not match this checkout's bound Remix branch while running ${params.operation}.`, {
|
|
49330
49587
|
code: REMIX_ERROR_CODES.PREFERRED_BRANCH_MISMATCH,
|
|
49331
49588
|
exitCode: 2,
|
|
49332
|
-
hint:
|
|
49589
|
+
hint: buildBranchMismatchHint({
|
|
49333
49590
|
currentBranch: params.currentBranch,
|
|
49334
|
-
|
|
49591
|
+
branchName: params.branchName,
|
|
49335
49592
|
overrideFlag: params.overrideFlag
|
|
49336
49593
|
})
|
|
49337
49594
|
});
|
|
@@ -49392,6 +49649,52 @@ function sanitizeCheckoutDirName(value) {
|
|
|
49392
49649
|
function buildDashboardAppUrl(appId) {
|
|
49393
49650
|
return `https://dashboard.remix.one/apps/${encodeURIComponent(appId)}`;
|
|
49394
49651
|
}
|
|
49652
|
+
async function resolveProjectLaneIfAuthoritative(api, params) {
|
|
49653
|
+
const branchName = String(params.branchName ?? "").trim();
|
|
49654
|
+
if (!branchName) return null;
|
|
49655
|
+
if (!params.projectId && !params.repoFingerprint && !params.remoteUrl) return null;
|
|
49656
|
+
const readLane = async () => {
|
|
49657
|
+
const laneResp = await api.resolveProjectLaneBinding({
|
|
49658
|
+
projectId: params.projectId ?? void 0,
|
|
49659
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49660
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49661
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49662
|
+
branchName
|
|
49663
|
+
});
|
|
49664
|
+
return unwrapResponseObject(laneResp, "project lane binding");
|
|
49665
|
+
};
|
|
49666
|
+
let lane = await readLane();
|
|
49667
|
+
const shouldRepairResolvedLane = lane.status === "resolved" && Boolean(
|
|
49668
|
+
params.expectedUpstreamAppId && (!lane.upstreamAppId || lane.upstreamAppId !== params.expectedUpstreamAppId)
|
|
49669
|
+
);
|
|
49670
|
+
if (shouldRepairResolvedLane && params.createIfMissing && params.seedAppId) {
|
|
49671
|
+
const ensuredResp = await api.ensureProjectLaneBinding({
|
|
49672
|
+
projectId: params.projectId ?? void 0,
|
|
49673
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49674
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49675
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49676
|
+
branchName,
|
|
49677
|
+
seedAppId: params.seedAppId
|
|
49678
|
+
});
|
|
49679
|
+
lane = unwrapResponseObject(ensuredResp, "project lane binding");
|
|
49680
|
+
}
|
|
49681
|
+
if (lane.status !== "resolved" && params.createIfMissing && params.seedAppId) {
|
|
49682
|
+
const ensuredResp = await api.ensureProjectLaneBinding({
|
|
49683
|
+
projectId: params.projectId ?? void 0,
|
|
49684
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49685
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49686
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49687
|
+
branchName,
|
|
49688
|
+
seedAppId: params.seedAppId
|
|
49689
|
+
});
|
|
49690
|
+
lane = unwrapResponseObject(ensuredResp, "project lane binding");
|
|
49691
|
+
}
|
|
49692
|
+
if (lane.status !== "resolved") return null;
|
|
49693
|
+
if (params.projectId && lane.projectId && lane.projectId !== params.projectId) return null;
|
|
49694
|
+
if (params.currentAppId && lane.currentAppId && lane.currentAppId !== params.currentAppId) return null;
|
|
49695
|
+
if (params.expectedUpstreamAppId && lane.upstreamAppId && lane.upstreamAppId !== params.expectedUpstreamAppId) return null;
|
|
49696
|
+
return lane;
|
|
49697
|
+
}
|
|
49395
49698
|
async function pollAppReady(api, appId) {
|
|
49396
49699
|
const started = Date.now();
|
|
49397
49700
|
let delay = 2e3;
|
|
@@ -49535,6 +49838,237 @@ async function pollMergeRequestCompletion(api, mrId, params) {
|
|
|
49535
49838
|
}
|
|
49536
49839
|
throw new RemixError("Timed out waiting for merge approval to complete.", { exitCode: 1 });
|
|
49537
49840
|
}
|
|
49841
|
+
function normalizeBranchName2(value) {
|
|
49842
|
+
const normalized = String(value ?? "").trim();
|
|
49843
|
+
return normalized || null;
|
|
49844
|
+
}
|
|
49845
|
+
function buildBindingFromLane(state, lane) {
|
|
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";
|
|
49851
|
+
return {
|
|
49852
|
+
schemaVersion: 3,
|
|
49853
|
+
projectId: lane.projectId ?? state.projectId,
|
|
49854
|
+
currentAppId: lane.currentAppId,
|
|
49855
|
+
upstreamAppId: lane.upstreamAppId,
|
|
49856
|
+
threadId: lane.threadId ?? null,
|
|
49857
|
+
repoFingerprint: lane.repoFingerprint ?? state.repoFingerprint ?? null,
|
|
49858
|
+
remoteUrl: lane.remoteUrl ?? state.remoteUrl ?? null,
|
|
49859
|
+
defaultBranch: lane.defaultBranch ?? state.defaultBranch ?? null,
|
|
49860
|
+
laneId: lane.laneId ?? null,
|
|
49861
|
+
branchName: resolvedBranch,
|
|
49862
|
+
bindingMode
|
|
49863
|
+
};
|
|
49864
|
+
}
|
|
49865
|
+
function shouldPersistRemoteLaneMetadata(localBinding, lane) {
|
|
49866
|
+
return Boolean(
|
|
49867
|
+
!localBinding.laneId && lane.laneId || !localBinding.threadId && lane.threadId || !localBinding.repoFingerprint && lane.repoFingerprint || !localBinding.remoteUrl && lane.remoteUrl || !localBinding.defaultBranch && lane.defaultBranch || !localBinding.branchName && lane.branchName
|
|
49868
|
+
);
|
|
49869
|
+
}
|
|
49870
|
+
function shouldRequireRemoteLaneForCurrentBranch(params) {
|
|
49871
|
+
if (!params.currentBranch) return false;
|
|
49872
|
+
const defaultBranch = normalizeBranchName2(params.defaultBranch);
|
|
49873
|
+
if (params.currentBranch === defaultBranch) return false;
|
|
49874
|
+
return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
|
|
49875
|
+
}
|
|
49876
|
+
async function persistResolvedLane(repoRoot, binding) {
|
|
49877
|
+
await writeCollabBinding(repoRoot, {
|
|
49878
|
+
projectId: binding.projectId,
|
|
49879
|
+
currentAppId: binding.currentAppId,
|
|
49880
|
+
upstreamAppId: binding.upstreamAppId,
|
|
49881
|
+
threadId: binding.threadId,
|
|
49882
|
+
repoFingerprint: binding.repoFingerprint,
|
|
49883
|
+
remoteUrl: binding.remoteUrl,
|
|
49884
|
+
defaultBranch: binding.defaultBranch,
|
|
49885
|
+
laneId: binding.laneId,
|
|
49886
|
+
branchName: binding.branchName,
|
|
49887
|
+
bindingMode: binding.bindingMode
|
|
49888
|
+
});
|
|
49889
|
+
return readCollabBinding(repoRoot);
|
|
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
|
+
}
|
|
49901
|
+
async function resolveActiveLaneBinding(params) {
|
|
49902
|
+
const state = await readCollabBindingState(params.repoRoot);
|
|
49903
|
+
if (!state) {
|
|
49904
|
+
return { status: "not_bound", currentBranch: null };
|
|
49905
|
+
}
|
|
49906
|
+
const currentBranch = normalizeBranchName2(state.currentBranch);
|
|
49907
|
+
const localBinding = state.binding;
|
|
49908
|
+
if (localBinding) {
|
|
49909
|
+
const requireRemoteLane = shouldRequireRemoteLaneForCurrentBranch({
|
|
49910
|
+
binding: localBinding,
|
|
49911
|
+
currentBranch,
|
|
49912
|
+
defaultBranch: state.defaultBranch
|
|
49913
|
+
});
|
|
49914
|
+
if (!params.api || !currentBranch) {
|
|
49915
|
+
return {
|
|
49916
|
+
status: "resolved",
|
|
49917
|
+
source: "local",
|
|
49918
|
+
binding: localBinding,
|
|
49919
|
+
currentBranch
|
|
49920
|
+
};
|
|
49921
|
+
}
|
|
49922
|
+
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
49923
|
+
projectId: state.explicitRootBinding?.projectId ?? (requireRemoteLane ? void 0 : localBinding.projectId ?? state.projectId ?? void 0),
|
|
49924
|
+
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
49925
|
+
remoteUrl: state.remoteUrl ?? void 0,
|
|
49926
|
+
defaultBranch: state.defaultBranch ?? void 0,
|
|
49927
|
+
branchName: currentBranch
|
|
49928
|
+
});
|
|
49929
|
+
const lane2 = unwrapResponseObject(laneResp2, "project lane binding");
|
|
49930
|
+
if (lane2.status === "ambiguous_family_selection") {
|
|
49931
|
+
return buildAmbiguousResolution({ state, currentBranch, lane: lane2 });
|
|
49932
|
+
}
|
|
49933
|
+
if (lane2.status === "resolved") {
|
|
49934
|
+
const resolvedBranch = normalizeBranchName2(lane2.branchName);
|
|
49935
|
+
const resolvedProjectId = lane2.projectId ?? state.projectId;
|
|
49936
|
+
const branchConflict = Boolean(resolvedBranch && localBinding.branchName && resolvedBranch !== localBinding.branchName);
|
|
49937
|
+
const appConflict = Boolean(lane2.currentAppId && lane2.currentAppId !== localBinding.currentAppId);
|
|
49938
|
+
const upstreamConflict = Boolean(lane2.upstreamAppId && lane2.upstreamAppId !== localBinding.upstreamAppId);
|
|
49939
|
+
const projectConflict = Boolean(resolvedProjectId && localBinding.projectId && resolvedProjectId !== localBinding.projectId);
|
|
49940
|
+
if (branchConflict || appConflict || upstreamConflict || projectConflict) {
|
|
49941
|
+
if (requireRemoteLane) {
|
|
49942
|
+
const binding = buildBindingFromLane(state, lane2);
|
|
49943
|
+
if (binding) {
|
|
49944
|
+
return {
|
|
49945
|
+
status: "resolved",
|
|
49946
|
+
source: "remote",
|
|
49947
|
+
binding,
|
|
49948
|
+
currentBranch
|
|
49949
|
+
};
|
|
49950
|
+
}
|
|
49951
|
+
}
|
|
49952
|
+
return {
|
|
49953
|
+
status: "binding_conflict",
|
|
49954
|
+
binding: localBinding,
|
|
49955
|
+
resolvedLane: lane2,
|
|
49956
|
+
currentBranch
|
|
49957
|
+
};
|
|
49958
|
+
}
|
|
49959
|
+
if (shouldPersistRemoteLaneMetadata(localBinding, lane2)) {
|
|
49960
|
+
const binding = buildBindingFromLane(state, lane2);
|
|
49961
|
+
if (binding) {
|
|
49962
|
+
return {
|
|
49963
|
+
status: "resolved",
|
|
49964
|
+
source: "remote",
|
|
49965
|
+
binding,
|
|
49966
|
+
currentBranch
|
|
49967
|
+
};
|
|
49968
|
+
}
|
|
49969
|
+
}
|
|
49970
|
+
}
|
|
49971
|
+
if (requireRemoteLane) {
|
|
49972
|
+
return {
|
|
49973
|
+
status: "missing_branch_binding",
|
|
49974
|
+
currentBranch,
|
|
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
|
|
49981
|
+
};
|
|
49982
|
+
}
|
|
49983
|
+
return {
|
|
49984
|
+
status: "resolved",
|
|
49985
|
+
source: "local",
|
|
49986
|
+
binding: localBinding,
|
|
49987
|
+
currentBranch
|
|
49988
|
+
};
|
|
49989
|
+
}
|
|
49990
|
+
if (!params.api || !currentBranch) {
|
|
49991
|
+
return {
|
|
49992
|
+
status: "missing_branch_binding",
|
|
49993
|
+
currentBranch,
|
|
49994
|
+
projectId: state.projectId,
|
|
49995
|
+
repoFingerprint: state.repoFingerprint,
|
|
49996
|
+
remoteUrl: state.remoteUrl,
|
|
49997
|
+
defaultBranch: state.defaultBranch,
|
|
49998
|
+
upstreamAppId: null,
|
|
49999
|
+
threadId: null
|
|
50000
|
+
};
|
|
50001
|
+
}
|
|
50002
|
+
const laneResp = await params.api.resolveProjectLaneBinding({
|
|
50003
|
+
projectId: state.explicitRootBinding?.projectId ?? state.projectId ?? void 0,
|
|
50004
|
+
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
50005
|
+
remoteUrl: state.remoteUrl ?? void 0,
|
|
50006
|
+
defaultBranch: state.defaultBranch ?? void 0,
|
|
50007
|
+
branchName: currentBranch
|
|
50008
|
+
});
|
|
50009
|
+
const lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
50010
|
+
if (lane.status === "ambiguous_family_selection") {
|
|
50011
|
+
return buildAmbiguousResolution({ state, currentBranch, lane });
|
|
50012
|
+
}
|
|
50013
|
+
if (lane.status === "resolved") {
|
|
50014
|
+
const binding = buildBindingFromLane(state, lane);
|
|
50015
|
+
if (binding) {
|
|
50016
|
+
return {
|
|
50017
|
+
status: "resolved",
|
|
50018
|
+
source: "remote",
|
|
50019
|
+
binding,
|
|
50020
|
+
currentBranch
|
|
50021
|
+
};
|
|
50022
|
+
}
|
|
50023
|
+
}
|
|
50024
|
+
return {
|
|
50025
|
+
status: "missing_branch_binding",
|
|
50026
|
+
currentBranch,
|
|
50027
|
+
projectId: lane.projectId ?? state.explicitRootBinding?.projectId ?? state.projectId,
|
|
50028
|
+
repoFingerprint: lane.repoFingerprint ?? state.repoFingerprint,
|
|
50029
|
+
remoteUrl: lane.remoteUrl ?? state.remoteUrl,
|
|
50030
|
+
defaultBranch: lane.defaultBranch ?? state.defaultBranch,
|
|
50031
|
+
upstreamAppId: lane.upstreamAppId ?? state.explicitRootBinding?.upstreamAppId ?? null,
|
|
50032
|
+
threadId: lane.threadId ?? state.explicitRootBinding?.threadId ?? null
|
|
50033
|
+
};
|
|
50034
|
+
}
|
|
50035
|
+
async function ensureActiveLaneBinding(params) {
|
|
50036
|
+
const resolved = await resolveActiveLaneBinding({
|
|
50037
|
+
repoRoot: params.repoRoot,
|
|
50038
|
+
api: params.api
|
|
50039
|
+
});
|
|
50040
|
+
if (resolved.status === "resolved") {
|
|
50041
|
+
if (resolved.source === "local") {
|
|
50042
|
+
return resolved.binding;
|
|
50043
|
+
}
|
|
50044
|
+
return persistResolvedLane(params.repoRoot, resolved.binding);
|
|
50045
|
+
}
|
|
50046
|
+
if (resolved.status === "binding_conflict") {
|
|
50047
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
50048
|
+
exitCode: 2,
|
|
50049
|
+
hint: `Local app ${resolved.binding.currentAppId}; server app ${resolved.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before running ${params.operation ?? "this command"}.`
|
|
50050
|
+
});
|
|
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
|
+
}
|
|
50058
|
+
if (resolved.status === "not_bound") {
|
|
50059
|
+
return null;
|
|
50060
|
+
}
|
|
50061
|
+
if (!resolved.currentBranch) {
|
|
50062
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50063
|
+
exitCode: 2,
|
|
50064
|
+
hint: `Switch to a named branch before running ${params.operation ?? "this command"}.`
|
|
50065
|
+
});
|
|
50066
|
+
}
|
|
50067
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50068
|
+
exitCode: 2,
|
|
50069
|
+
hint: `Run \`remix collab init\` on branch ${resolved.currentBranch} before running ${params.operation ?? "this command"}.`
|
|
50070
|
+
});
|
|
50071
|
+
}
|
|
49538
50072
|
async function collabRecordingPreflight(params) {
|
|
49539
50073
|
let repoRoot;
|
|
49540
50074
|
try {
|
|
@@ -49546,7 +50080,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49546
50080
|
repoRoot: null,
|
|
49547
50081
|
appId: null,
|
|
49548
50082
|
currentBranch: null,
|
|
49549
|
-
|
|
50083
|
+
branchName: null,
|
|
49550
50084
|
headCommitHash: null,
|
|
49551
50085
|
worktreeClean: false,
|
|
49552
50086
|
syncStatus: null,
|
|
@@ -49558,14 +50092,14 @@ async function collabRecordingPreflight(params) {
|
|
|
49558
50092
|
hint: message
|
|
49559
50093
|
};
|
|
49560
50094
|
}
|
|
49561
|
-
const
|
|
49562
|
-
if (
|
|
50095
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot, api: params.api });
|
|
50096
|
+
if (bindingResolution.status === "not_bound") {
|
|
49563
50097
|
return {
|
|
49564
50098
|
status: "not_bound",
|
|
49565
50099
|
repoRoot,
|
|
49566
50100
|
appId: null,
|
|
49567
50101
|
currentBranch: null,
|
|
49568
|
-
|
|
50102
|
+
branchName: null,
|
|
49569
50103
|
headCommitHash: null,
|
|
49570
50104
|
worktreeClean: false,
|
|
49571
50105
|
syncStatus: null,
|
|
@@ -49577,19 +50111,74 @@ async function collabRecordingPreflight(params) {
|
|
|
49577
50111
|
hint: "Run `remix collab init` first."
|
|
49578
50112
|
};
|
|
49579
50113
|
}
|
|
50114
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
50115
|
+
return {
|
|
50116
|
+
status: "branch_binding_missing",
|
|
50117
|
+
repoRoot,
|
|
50118
|
+
appId: null,
|
|
50119
|
+
currentBranch: bindingResolution.currentBranch,
|
|
50120
|
+
branchName: bindingResolution.currentBranch,
|
|
50121
|
+
headCommitHash: null,
|
|
50122
|
+
worktreeClean: false,
|
|
50123
|
+
syncStatus: null,
|
|
50124
|
+
syncTargetCommitHash: null,
|
|
50125
|
+
syncTargetCommitId: null,
|
|
50126
|
+
reconcileTargetHeadCommitHash: null,
|
|
50127
|
+
reconcileTargetHeadCommitId: null,
|
|
50128
|
+
warnings: [],
|
|
50129
|
+
hint: `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`
|
|
50130
|
+
};
|
|
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
|
+
}
|
|
50150
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
50151
|
+
return {
|
|
50152
|
+
status: "metadata_conflict",
|
|
50153
|
+
repoRoot,
|
|
50154
|
+
appId: bindingResolution.binding.currentAppId,
|
|
50155
|
+
currentBranch: bindingResolution.currentBranch,
|
|
50156
|
+
branchName: bindingResolution.binding.branchName,
|
|
50157
|
+
headCommitHash: null,
|
|
50158
|
+
worktreeClean: false,
|
|
50159
|
+
syncStatus: null,
|
|
50160
|
+
syncTargetCommitHash: null,
|
|
50161
|
+
syncTargetCommitId: null,
|
|
50162
|
+
reconcileTargetHeadCommitHash: null,
|
|
50163
|
+
reconcileTargetHeadCommitId: null,
|
|
50164
|
+
warnings: [],
|
|
50165
|
+
hint: `Local binding for ${bindingResolution.currentBranch ?? "(detached)"} points to app ${bindingResolution.binding.currentAppId}, but the server resolved lane ${bindingResolution.resolvedLane.laneId ?? "(unknown)"} / app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before recording work.`
|
|
50166
|
+
};
|
|
50167
|
+
}
|
|
50168
|
+
const binding = bindingResolution.binding;
|
|
49580
50169
|
const [currentBranch, headCommitHash, worktreeStatus] = await Promise.all([
|
|
49581
50170
|
getCurrentBranch(repoRoot),
|
|
49582
50171
|
getHeadCommitHash(repoRoot),
|
|
49583
50172
|
getWorktreeStatus(repoRoot)
|
|
49584
50173
|
]);
|
|
49585
|
-
const
|
|
50174
|
+
const branchName = binding.branchName ?? null;
|
|
49586
50175
|
if (!headCommitHash) {
|
|
49587
50176
|
return {
|
|
49588
50177
|
status: "missing_head",
|
|
49589
50178
|
repoRoot,
|
|
49590
50179
|
appId: binding.currentAppId,
|
|
49591
50180
|
currentBranch,
|
|
49592
|
-
|
|
50181
|
+
branchName,
|
|
49593
50182
|
headCommitHash: null,
|
|
49594
50183
|
worktreeClean: worktreeStatus.isClean,
|
|
49595
50184
|
syncStatus: null,
|
|
@@ -49601,13 +50190,13 @@ async function collabRecordingPreflight(params) {
|
|
|
49601
50190
|
hint: "Failed to resolve local HEAD commit."
|
|
49602
50191
|
};
|
|
49603
50192
|
}
|
|
49604
|
-
if (!params.allowBranchMismatch && !
|
|
50193
|
+
if (!params.allowBranchMismatch && !isBoundBranchMatch(currentBranch, branchName)) {
|
|
49605
50194
|
return {
|
|
49606
50195
|
status: "branch_mismatch",
|
|
49607
50196
|
repoRoot,
|
|
49608
50197
|
appId: binding.currentAppId,
|
|
49609
50198
|
currentBranch,
|
|
49610
|
-
|
|
50199
|
+
branchName,
|
|
49611
50200
|
headCommitHash,
|
|
49612
50201
|
worktreeClean: worktreeStatus.isClean,
|
|
49613
50202
|
syncStatus: null,
|
|
@@ -49616,9 +50205,9 @@ async function collabRecordingPreflight(params) {
|
|
|
49616
50205
|
reconcileTargetHeadCommitHash: null,
|
|
49617
50206
|
reconcileTargetHeadCommitId: null,
|
|
49618
50207
|
warnings: [],
|
|
49619
|
-
hint:
|
|
50208
|
+
hint: buildBranchMismatchHint({
|
|
49620
50209
|
currentBranch,
|
|
49621
|
-
|
|
50210
|
+
branchName
|
|
49622
50211
|
})
|
|
49623
50212
|
};
|
|
49624
50213
|
}
|
|
@@ -49636,7 +50225,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49636
50225
|
repoRoot,
|
|
49637
50226
|
appId: binding.currentAppId,
|
|
49638
50227
|
currentBranch,
|
|
49639
|
-
|
|
50228
|
+
branchName,
|
|
49640
50229
|
headCommitHash,
|
|
49641
50230
|
worktreeClean: worktreeStatus.isClean,
|
|
49642
50231
|
syncStatus: sync.status,
|
|
@@ -49654,7 +50243,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49654
50243
|
repoRoot,
|
|
49655
50244
|
appId: binding.currentAppId,
|
|
49656
50245
|
currentBranch,
|
|
49657
|
-
|
|
50246
|
+
branchName,
|
|
49658
50247
|
headCommitHash,
|
|
49659
50248
|
worktreeClean: worktreeStatus.isClean,
|
|
49660
50249
|
syncStatus: sync.status,
|
|
@@ -49679,7 +50268,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49679
50268
|
repoRoot,
|
|
49680
50269
|
appId: binding.currentAppId,
|
|
49681
50270
|
currentBranch,
|
|
49682
|
-
|
|
50271
|
+
branchName,
|
|
49683
50272
|
headCommitHash,
|
|
49684
50273
|
worktreeClean: worktreeStatus.isClean,
|
|
49685
50274
|
syncStatus: sync.status,
|
|
@@ -49697,7 +50286,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49697
50286
|
repoRoot,
|
|
49698
50287
|
appId: binding.currentAppId,
|
|
49699
50288
|
currentBranch,
|
|
49700
|
-
|
|
50289
|
+
branchName,
|
|
49701
50290
|
headCommitHash,
|
|
49702
50291
|
worktreeClean: worktreeStatus.isClean,
|
|
49703
50292
|
syncStatus: sync.status,
|
|
@@ -49714,7 +50303,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49714
50303
|
repoRoot,
|
|
49715
50304
|
appId: binding.currentAppId,
|
|
49716
50305
|
currentBranch,
|
|
49717
|
-
|
|
50306
|
+
branchName,
|
|
49718
50307
|
headCommitHash,
|
|
49719
50308
|
worktreeClean: worktreeStatus.isClean,
|
|
49720
50309
|
syncStatus: sync.status,
|
|
@@ -49936,7 +50525,11 @@ async function withRepoMutationLock(options, fn) {
|
|
|
49936
50525
|
}
|
|
49937
50526
|
async function collabSync(params) {
|
|
49938
50527
|
const repoRoot = await findGitRoot(params.cwd);
|
|
49939
|
-
const binding = await
|
|
50528
|
+
const binding = await ensureActiveLaneBinding({
|
|
50529
|
+
repoRoot,
|
|
50530
|
+
api: params.api,
|
|
50531
|
+
operation: "`remix collab sync`"
|
|
50532
|
+
});
|
|
49940
50533
|
if (!binding) {
|
|
49941
50534
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
49942
50535
|
exitCode: 2,
|
|
@@ -49945,9 +50538,9 @@ async function collabSync(params) {
|
|
|
49945
50538
|
}
|
|
49946
50539
|
await ensureCleanWorktree(repoRoot);
|
|
49947
50540
|
const branch = await requireCurrentBranch(repoRoot);
|
|
49948
|
-
|
|
50541
|
+
assertBoundBranchMatch({
|
|
49949
50542
|
currentBranch: branch,
|
|
49950
|
-
|
|
50543
|
+
branchName: binding.branchName,
|
|
49951
50544
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
49952
50545
|
operation: "`remix collab sync`"
|
|
49953
50546
|
});
|
|
@@ -50024,9 +50617,9 @@ async function collabSync(params) {
|
|
|
50024
50617
|
});
|
|
50025
50618
|
await ensureCleanWorktree(lockedRepoRoot);
|
|
50026
50619
|
const lockedBranch = await requireCurrentBranch(lockedRepoRoot);
|
|
50027
|
-
|
|
50620
|
+
assertBoundBranchMatch({
|
|
50028
50621
|
currentBranch: lockedBranch,
|
|
50029
|
-
|
|
50622
|
+
branchName: binding.branchName,
|
|
50030
50623
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50031
50624
|
operation: "`remix collab sync`"
|
|
50032
50625
|
});
|
|
@@ -50057,6 +50650,18 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50057
50650
|
hint: preflight.hint
|
|
50058
50651
|
});
|
|
50059
50652
|
}
|
|
50653
|
+
if (preflight.status === "branch_binding_missing") {
|
|
50654
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50655
|
+
exitCode: 2,
|
|
50656
|
+
hint: preflight.hint
|
|
50657
|
+
});
|
|
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
|
+
}
|
|
50060
50665
|
if (preflight.status === "not_git_repo") {
|
|
50061
50666
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50062
50667
|
exitCode: 2,
|
|
@@ -50070,9 +50675,9 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50070
50675
|
});
|
|
50071
50676
|
}
|
|
50072
50677
|
if (preflight.status === "branch_mismatch") {
|
|
50073
|
-
|
|
50678
|
+
assertBoundBranchMatch({
|
|
50074
50679
|
currentBranch: preflight.currentBranch,
|
|
50075
|
-
|
|
50680
|
+
branchName: preflight.branchName,
|
|
50076
50681
|
allowBranchMismatch: false,
|
|
50077
50682
|
operation: "`remix collab add`"
|
|
50078
50683
|
});
|
|
@@ -50092,7 +50697,11 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50092
50697
|
}
|
|
50093
50698
|
async function collabAdd(params) {
|
|
50094
50699
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50095
|
-
const binding = await
|
|
50700
|
+
const binding = await ensureActiveLaneBinding({
|
|
50701
|
+
repoRoot,
|
|
50702
|
+
api: params.api,
|
|
50703
|
+
operation: "`remix collab add`"
|
|
50704
|
+
});
|
|
50096
50705
|
if (!binding) {
|
|
50097
50706
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50098
50707
|
exitCode: 2,
|
|
@@ -50113,9 +50722,9 @@ async function collabAdd(params) {
|
|
|
50113
50722
|
});
|
|
50114
50723
|
assertSupportedRecordingPreflight(preflight);
|
|
50115
50724
|
const branch = preflight.currentBranch;
|
|
50116
|
-
|
|
50725
|
+
assertBoundBranchMatch({
|
|
50117
50726
|
currentBranch: branch,
|
|
50118
|
-
|
|
50727
|
+
branchName: binding.branchName,
|
|
50119
50728
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50120
50729
|
operation: "`remix collab add`"
|
|
50121
50730
|
});
|
|
@@ -50288,6 +50897,7 @@ async function collabAdd(params) {
|
|
|
50288
50897
|
});
|
|
50289
50898
|
const resp = await params.api.createChangeStep(binding.currentAppId, {
|
|
50290
50899
|
threadId: binding.threadId ?? void 0,
|
|
50900
|
+
collabLaneId: binding.laneId ?? void 0,
|
|
50291
50901
|
prompt,
|
|
50292
50902
|
assistantResponse: assistantResponse ?? void 0,
|
|
50293
50903
|
diff,
|
|
@@ -50361,6 +50971,18 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50361
50971
|
hint: preflight.hint
|
|
50362
50972
|
});
|
|
50363
50973
|
}
|
|
50974
|
+
if (preflight.status === "branch_binding_missing") {
|
|
50975
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50976
|
+
exitCode: 2,
|
|
50977
|
+
hint: preflight.hint
|
|
50978
|
+
});
|
|
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
|
+
}
|
|
50364
50986
|
if (preflight.status === "not_git_repo") {
|
|
50365
50987
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50366
50988
|
exitCode: 2,
|
|
@@ -50374,9 +50996,9 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50374
50996
|
});
|
|
50375
50997
|
}
|
|
50376
50998
|
if (preflight.status === "branch_mismatch") {
|
|
50377
|
-
|
|
50999
|
+
assertBoundBranchMatch({
|
|
50378
51000
|
currentBranch: preflight.currentBranch,
|
|
50379
|
-
|
|
51001
|
+
branchName: preflight.branchName,
|
|
50380
51002
|
allowBranchMismatch: false,
|
|
50381
51003
|
operation: "`remix collab record-turn`"
|
|
50382
51004
|
});
|
|
@@ -50396,7 +51018,11 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50396
51018
|
}
|
|
50397
51019
|
async function collabRecordTurn(params) {
|
|
50398
51020
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50399
|
-
const binding = await
|
|
51021
|
+
const binding = await ensureActiveLaneBinding({
|
|
51022
|
+
repoRoot,
|
|
51023
|
+
api: params.api,
|
|
51024
|
+
operation: "`remix collab record-turn`"
|
|
51025
|
+
});
|
|
50400
51026
|
if (!binding) {
|
|
50401
51027
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50402
51028
|
exitCode: 2,
|
|
@@ -50428,9 +51054,9 @@ async function collabRecordTurn(params) {
|
|
|
50428
51054
|
});
|
|
50429
51055
|
}
|
|
50430
51056
|
const branch = await getCurrentBranch(repoRoot);
|
|
50431
|
-
|
|
51057
|
+
assertBoundBranchMatch({
|
|
50432
51058
|
currentBranch: branch,
|
|
50433
|
-
|
|
51059
|
+
branchName: binding.branchName,
|
|
50434
51060
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50435
51061
|
operation: "`remix collab record-turn`"
|
|
50436
51062
|
});
|
|
@@ -50444,6 +51070,7 @@ async function collabRecordTurn(params) {
|
|
|
50444
51070
|
});
|
|
50445
51071
|
const resp = await params.api.createCollabTurn(binding.currentAppId, {
|
|
50446
51072
|
threadId: binding.threadId ?? void 0,
|
|
51073
|
+
collabLaneId: binding.laneId ?? void 0,
|
|
50447
51074
|
prompt,
|
|
50448
51075
|
assistantResponse,
|
|
50449
51076
|
actor: params.actor,
|
|
@@ -50456,7 +51083,8 @@ async function collabRecordTurn(params) {
|
|
|
50456
51083
|
},
|
|
50457
51084
|
idempotencyKey
|
|
50458
51085
|
});
|
|
50459
|
-
|
|
51086
|
+
const turn = unwrapResponseObject(resp, "collab turn");
|
|
51087
|
+
return turn;
|
|
50460
51088
|
}
|
|
50461
51089
|
function collectWarnings(value) {
|
|
50462
51090
|
if (!Array.isArray(value)) return [];
|
|
@@ -50464,7 +51092,11 @@ function collectWarnings(value) {
|
|
|
50464
51092
|
}
|
|
50465
51093
|
async function collabFinalizeTurn(params) {
|
|
50466
51094
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50467
|
-
const binding = await
|
|
51095
|
+
const binding = await ensureActiveLaneBinding({
|
|
51096
|
+
repoRoot,
|
|
51097
|
+
api: params.api,
|
|
51098
|
+
operation: "`remix collab finalize-turn`"
|
|
51099
|
+
});
|
|
50468
51100
|
if (!binding) {
|
|
50469
51101
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50470
51102
|
exitCode: 2,
|
|
@@ -50570,7 +51202,11 @@ async function collabApprove(params) {
|
|
|
50570
51202
|
operation: "collabApproveSyncTarget"
|
|
50571
51203
|
},
|
|
50572
51204
|
async ({ repoRoot, warnings }) => {
|
|
50573
|
-
const binding = await
|
|
51205
|
+
const binding = await ensureActiveLaneBinding({
|
|
51206
|
+
repoRoot,
|
|
51207
|
+
api: params.api,
|
|
51208
|
+
operation: "`remix collab approve --sync-target-repo`"
|
|
51209
|
+
});
|
|
50574
51210
|
if (!binding) {
|
|
50575
51211
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50576
51212
|
exitCode: 2,
|
|
@@ -50579,9 +51215,9 @@ async function collabApprove(params) {
|
|
|
50579
51215
|
}
|
|
50580
51216
|
await ensureCleanWorktree(repoRoot, "`remix collab approve --sync-target-repo`");
|
|
50581
51217
|
const branch = await requireCurrentBranch(repoRoot);
|
|
50582
|
-
|
|
51218
|
+
assertBoundBranchMatch({
|
|
50583
51219
|
currentBranch: branch,
|
|
50584
|
-
|
|
51220
|
+
branchName: binding.branchName,
|
|
50585
51221
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50586
51222
|
operation: "`remix collab approve --sync-target-repo`"
|
|
50587
51223
|
});
|
|
@@ -50659,10 +51295,6 @@ function isSubpath(parentPath, candidatePath) {
|
|
|
50659
51295
|
const relative = import_path8.default.relative(parentPath, candidatePath);
|
|
50660
51296
|
return relative === "" || !relative.startsWith("..") && !import_path8.default.isAbsolute(relative);
|
|
50661
51297
|
}
|
|
50662
|
-
function buildPreferredCheckoutBranch(appId) {
|
|
50663
|
-
const normalized = appId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
50664
|
-
return `remix/remix/${normalized || "app"}`;
|
|
50665
|
-
}
|
|
50666
51298
|
async function resolveCheckoutDestination(params) {
|
|
50667
51299
|
if (params.outputDir?.trim()) {
|
|
50668
51300
|
const preferredRepoRoot = import_path8.default.resolve(params.outputDir.trim());
|
|
@@ -50727,7 +51359,9 @@ async function materializeAppCheckout(params) {
|
|
|
50727
51359
|
const bundle = await params.api.downloadAppBundle(params.appId);
|
|
50728
51360
|
await import_promises19.default.writeFile(bundlePath, bundle.data);
|
|
50729
51361
|
await cloneGitBundleToDirectory(bundlePath, repoRoot);
|
|
50730
|
-
|
|
51362
|
+
if (params.expectedBranchName?.trim()) {
|
|
51363
|
+
await checkoutLocalBranch(repoRoot, params.expectedBranchName.trim());
|
|
51364
|
+
}
|
|
50731
51365
|
await ensureGitInfoExcludeEntries(repoRoot, [".remix/"]);
|
|
50732
51366
|
} catch (err) {
|
|
50733
51367
|
await import_promises19.default.rm(repoRoot, { recursive: true, force: true }).catch(() => {
|
|
@@ -50736,15 +51370,15 @@ async function materializeAppCheckout(params) {
|
|
|
50736
51370
|
} finally {
|
|
50737
51371
|
await import_promises19.default.rm(bundleTempDir, { recursive: true, force: true });
|
|
50738
51372
|
}
|
|
50739
|
-
const
|
|
50740
|
-
const
|
|
50741
|
-
const
|
|
51373
|
+
const branchName = await getCurrentBranch(repoRoot) ?? params.expectedBranchName?.trim() ?? null;
|
|
51374
|
+
const remoteUrl = normalizeGitRemote(params.expectedRemoteUrl ?? await getRemoteOriginUrl(repoRoot));
|
|
51375
|
+
const defaultBranch = params.expectedDefaultBranch?.trim() ?? await getDefaultBranch(repoRoot) ?? branchName ?? null;
|
|
50742
51376
|
const repoFingerprint = remoteUrl ? await buildRepoFingerprint({ gitRoot: repoRoot, remoteUrl, defaultBranch }) : null;
|
|
50743
51377
|
return {
|
|
50744
51378
|
repoRoot,
|
|
50745
51379
|
remoteUrl,
|
|
50746
51380
|
defaultBranch,
|
|
50747
|
-
|
|
51381
|
+
branchName,
|
|
50748
51382
|
repoFingerprint
|
|
50749
51383
|
};
|
|
50750
51384
|
}
|
|
@@ -50757,29 +51391,55 @@ async function collabCheckout(params) {
|
|
|
50757
51391
|
});
|
|
50758
51392
|
}
|
|
50759
51393
|
const app = await pollAppReady(params.api, appId);
|
|
51394
|
+
const collab = app.collab && typeof app.collab === "object" ? app.collab : null;
|
|
51395
|
+
const source = app.source && typeof app.source === "object" ? app.source : null;
|
|
51396
|
+
const authoritativeBranchName = typeof collab?.branchName === "string" && collab.branchName.trim() || typeof source?.branch === "string" && source.branch.trim() || typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
51397
|
+
const authoritativeRemoteUrl = typeof source?.remoteUrl === "string" && source.remoteUrl.trim() || null;
|
|
51398
|
+
const authoritativeDefaultBranch = typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
50760
51399
|
const checkout = await materializeAppCheckout({
|
|
50761
51400
|
api: params.api,
|
|
50762
51401
|
cwd: params.cwd,
|
|
50763
51402
|
appId: String(app.id),
|
|
50764
51403
|
outputDir: params.outputDir ?? null,
|
|
50765
|
-
defaultDirName: sanitizeCheckoutDirName(String(app.name || app.id))
|
|
51404
|
+
defaultDirName: sanitizeCheckoutDirName(String(app.name || app.id)),
|
|
51405
|
+
expectedBranchName: authoritativeBranchName,
|
|
51406
|
+
expectedRemoteUrl: authoritativeRemoteUrl,
|
|
51407
|
+
expectedDefaultBranch: authoritativeDefaultBranch
|
|
50766
51408
|
});
|
|
50767
51409
|
const upstreamAppId = String(app.forkedFromAppId ?? app.id);
|
|
50768
|
-
const
|
|
51410
|
+
const laneId = typeof collab?.laneId === "string" ? collab.laneId : null;
|
|
51411
|
+
const repoFingerprint = typeof source?.repoFingerprint === "string" ? source.repoFingerprint : checkout.repoFingerprint;
|
|
51412
|
+
const remoteUrl = typeof source?.remoteUrl === "string" ? source.remoteUrl : checkout.remoteUrl;
|
|
51413
|
+
const defaultBranch = typeof source?.defaultBranch === "string" ? source.defaultBranch : checkout.defaultBranch;
|
|
51414
|
+
const branchName = authoritativeBranchName ?? checkout.branchName;
|
|
51415
|
+
const authoritativeLane = await resolveProjectLaneIfAuthoritative(params.api, {
|
|
50769
51416
|
projectId: String(app.projectId),
|
|
51417
|
+
repoFingerprint,
|
|
51418
|
+
remoteUrl,
|
|
51419
|
+
defaultBranch,
|
|
51420
|
+
branchName,
|
|
50770
51421
|
currentAppId: String(app.id),
|
|
50771
|
-
upstreamAppId,
|
|
50772
|
-
|
|
50773
|
-
|
|
50774
|
-
|
|
50775
|
-
|
|
50776
|
-
|
|
51422
|
+
expectedUpstreamAppId: upstreamAppId,
|
|
51423
|
+
createIfMissing: true,
|
|
51424
|
+
seedAppId: String(app.id)
|
|
51425
|
+
});
|
|
51426
|
+
const bindingPath = await writeCollabBinding(checkout.repoRoot, {
|
|
51427
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
51428
|
+
currentAppId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
51429
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? upstreamAppId,
|
|
51430
|
+
threadId: authoritativeLane?.threadId ?? (app.threadId ? String(app.threadId) : null),
|
|
51431
|
+
repoFingerprint: authoritativeLane?.repoFingerprint ?? repoFingerprint,
|
|
51432
|
+
remoteUrl: authoritativeLane?.remoteUrl ?? remoteUrl,
|
|
51433
|
+
defaultBranch: authoritativeLane?.defaultBranch ?? defaultBranch,
|
|
51434
|
+
laneId: authoritativeLane?.laneId ?? laneId,
|
|
51435
|
+
branchName: authoritativeLane?.branchName ?? branchName,
|
|
51436
|
+
bindingMode: "lane"
|
|
50777
51437
|
});
|
|
50778
51438
|
return {
|
|
50779
|
-
appId: String(app.id),
|
|
50780
|
-
dashboardUrl: buildDashboardAppUrl(String(app.id)),
|
|
50781
|
-
projectId: String(app.projectId),
|
|
50782
|
-
upstreamAppId,
|
|
51439
|
+
appId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
51440
|
+
dashboardUrl: buildDashboardAppUrl(authoritativeLane?.currentAppId ?? String(app.id)),
|
|
51441
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
51442
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? upstreamAppId,
|
|
50783
51443
|
bindingPath,
|
|
50784
51444
|
repoRoot: checkout.repoRoot
|
|
50785
51445
|
};
|
|
@@ -50799,14 +51459,32 @@ async function resolveQueueAppId(params) {
|
|
|
50799
51459
|
});
|
|
50800
51460
|
}
|
|
50801
51461
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50802
|
-
const
|
|
50803
|
-
if (
|
|
51462
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot });
|
|
51463
|
+
if (bindingResolution.status === "not_bound") {
|
|
50804
51464
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50805
51465
|
exitCode: 2,
|
|
50806
51466
|
hint: "Bind the repository first or pass `appId` explicitly for the app-scoped merge-request queue."
|
|
50807
51467
|
});
|
|
50808
51468
|
}
|
|
50809
|
-
|
|
51469
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
51470
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
51471
|
+
exitCode: 2,
|
|
51472
|
+
hint: `Switch back to a bound branch or create a lane by recording work on ${bindingResolution.currentBranch ?? "this branch"}.`
|
|
51473
|
+
});
|
|
51474
|
+
}
|
|
51475
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
51476
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
51477
|
+
exitCode: 2,
|
|
51478
|
+
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51479
|
+
});
|
|
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
|
+
}
|
|
51487
|
+
return bindingResolution.binding.currentAppId;
|
|
50810
51488
|
}
|
|
50811
51489
|
async function collabListMergeRequests(params) {
|
|
50812
51490
|
const appId = await resolveQueueAppId({
|
|
@@ -50835,12 +51513,38 @@ async function collabListMergeRequests(params) {
|
|
|
50835
51513
|
async function resolveScopeTarget(params) {
|
|
50836
51514
|
if (params.targetId?.trim()) return params.targetId.trim();
|
|
50837
51515
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50838
|
-
const
|
|
50839
|
-
if (
|
|
51516
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot, api: params.api });
|
|
51517
|
+
if (bindingResolution.status === "not_bound") {
|
|
50840
51518
|
throw new RemixError("Repository is not bound to Remix and no explicit target id was provided.", { exitCode: 2 });
|
|
50841
51519
|
}
|
|
50842
|
-
if (
|
|
51520
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
51521
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane and no explicit target id was provided.", {
|
|
51522
|
+
exitCode: 2
|
|
51523
|
+
});
|
|
51524
|
+
}
|
|
51525
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
51526
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
51527
|
+
exitCode: 2,
|
|
51528
|
+
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51529
|
+
});
|
|
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
|
+
}
|
|
51537
|
+
const binding = bindingResolution.binding;
|
|
51538
|
+
if (params.scope === "project") {
|
|
51539
|
+
if (!binding.projectId) {
|
|
51540
|
+
throw new RemixError("Could not resolve the project for the current repository binding.", { exitCode: 2 });
|
|
51541
|
+
}
|
|
51542
|
+
return binding.projectId;
|
|
51543
|
+
}
|
|
50843
51544
|
if (params.scope === "app") return binding.currentAppId;
|
|
51545
|
+
if (!binding.projectId) {
|
|
51546
|
+
throw new RemixError("Could not resolve the project for the current repository binding.", { exitCode: 2 });
|
|
51547
|
+
}
|
|
50844
51548
|
const project = unwrapResponseObject(await params.api.getProject(binding.projectId), "project");
|
|
50845
51549
|
const organizationId = typeof project.organizationId === "string" ? project.organizationId : null;
|
|
50846
51550
|
if (!organizationId) {
|
|
@@ -50944,6 +51648,85 @@ ${text}`.trim() || null
|
|
|
50944
51648
|
});
|
|
50945
51649
|
}
|
|
50946
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
|
+
}
|
|
50947
51730
|
async function collabInit(params) {
|
|
50948
51731
|
return withRepoMutationLock(
|
|
50949
51732
|
{
|
|
@@ -50962,38 +51745,220 @@ async function collabInit(params) {
|
|
|
50962
51745
|
const remoteUrl = normalizeGitRemote(await getRemoteOriginUrl(repoRoot));
|
|
50963
51746
|
const currentBranch = await getCurrentBranch(repoRoot);
|
|
50964
51747
|
const defaultBranch = await getDefaultBranch(repoRoot) ?? currentBranch;
|
|
50965
|
-
const
|
|
51748
|
+
const branchName = currentBranch ?? defaultBranch ?? null;
|
|
50966
51749
|
const repoFingerprint = await buildRepoFingerprint({ gitRoot: repoRoot, remoteUrl, defaultBranch });
|
|
50967
51750
|
const repoSnapshot = await captureRepoSnapshot(repoRoot);
|
|
50968
|
-
|
|
50969
|
-
|
|
50970
|
-
|
|
50971
|
-
|
|
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`"
|
|
51770
|
+
});
|
|
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`"
|
|
51779
|
+
});
|
|
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`."
|
|
50972
51807
|
});
|
|
50973
|
-
|
|
50974
|
-
|
|
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,
|
|
51826
|
+
repoFingerprint,
|
|
51827
|
+
remoteUrl,
|
|
51828
|
+
defaultBranch: defaultBranch ?? null,
|
|
51829
|
+
laneId: boundLaneId2,
|
|
51830
|
+
branchName,
|
|
51831
|
+
bindingMode: "lane"
|
|
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;
|
|
51868
|
+
let boundProjectId2 = initialProjectId;
|
|
51869
|
+
let boundCurrentAppId2 = initialCurrentAppId;
|
|
51870
|
+
let boundUpstreamAppId2 = initialUpstreamAppId;
|
|
51871
|
+
let boundThreadId2 = initialThreadId;
|
|
51872
|
+
let boundLaneId2 = null;
|
|
51873
|
+
let canonicalLane2 = null;
|
|
51874
|
+
if (branchName) {
|
|
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;
|
|
51915
|
+
}
|
|
51916
|
+
}
|
|
51917
|
+
if (boundCurrentAppId2) {
|
|
51918
|
+
const readyApp = await pollAppReady(params.api, boundCurrentAppId2);
|
|
51919
|
+
boundProjectId2 = String(readyApp.projectId ?? boundProjectId2);
|
|
51920
|
+
boundThreadId2 = readyApp.threadId ? String(readyApp.threadId) : boundThreadId2;
|
|
51921
|
+
}
|
|
50975
51922
|
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
50976
51923
|
operation: "`remix collab init`",
|
|
50977
51924
|
recoveryHint: "The repository changed while the local binding was being initialized. Review the local changes and rerun `remix collab init`."
|
|
50978
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
|
+
}
|
|
50979
51940
|
const bindingPath2 = await writeCollabBinding(repoRoot, {
|
|
50980
|
-
projectId:
|
|
50981
|
-
currentAppId:
|
|
50982
|
-
upstreamAppId:
|
|
50983
|
-
threadId:
|
|
51941
|
+
projectId: boundProjectId2,
|
|
51942
|
+
currentAppId: boundCurrentAppId2,
|
|
51943
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
51944
|
+
threadId: boundThreadId2,
|
|
50984
51945
|
repoFingerprint,
|
|
50985
51946
|
remoteUrl,
|
|
50986
51947
|
defaultBranch: defaultBranch ?? null,
|
|
50987
|
-
|
|
51948
|
+
laneId: boundLaneId2,
|
|
51949
|
+
branchName,
|
|
51950
|
+
bindingMode: "lane"
|
|
50988
51951
|
});
|
|
50989
51952
|
return {
|
|
50990
51953
|
reused: true,
|
|
50991
|
-
projectId:
|
|
50992
|
-
appId:
|
|
50993
|
-
dashboardUrl: buildDashboardAppUrl(
|
|
50994
|
-
upstreamAppId:
|
|
51954
|
+
projectId: boundProjectId2,
|
|
51955
|
+
appId: boundCurrentAppId2,
|
|
51956
|
+
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId2),
|
|
51957
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
50995
51958
|
bindingPath: bindingPath2,
|
|
50996
51959
|
repoRoot,
|
|
51960
|
+
bindingMode: "lane",
|
|
51961
|
+
createdCanonicalFamily: false,
|
|
50997
51962
|
...warnings.length > 0 ? { warnings } : {}
|
|
50998
51963
|
};
|
|
50999
51964
|
}
|
|
@@ -51021,6 +51986,7 @@ async function collabInit(params) {
|
|
|
51021
51986
|
path: params.path?.trim() || void 0,
|
|
51022
51987
|
platform: "generic",
|
|
51023
51988
|
isPublic: false,
|
|
51989
|
+
branch: defaultBranch && branchName && branchName !== defaultBranch ? defaultBranch : currentBranch ?? void 0,
|
|
51024
51990
|
remoteUrl: remoteUrl ?? void 0,
|
|
51025
51991
|
defaultBranch: defaultBranch ?? void 0,
|
|
51026
51992
|
repoFingerprint,
|
|
@@ -51028,31 +51994,136 @@ async function collabInit(params) {
|
|
|
51028
51994
|
});
|
|
51029
51995
|
const imported = unwrapResponseObject(importResp, "import");
|
|
51030
51996
|
const app = await pollAppReady(params.api, String(imported.appId));
|
|
51997
|
+
let boundProjectId = String(app.projectId);
|
|
51998
|
+
let boundCurrentAppId = String(app.id);
|
|
51999
|
+
let boundUpstreamAppId = String(app.id);
|
|
52000
|
+
let boundThreadId = app.threadId ? String(app.threadId) : null;
|
|
52001
|
+
let boundLaneId = null;
|
|
52002
|
+
let canonicalLane = null;
|
|
52003
|
+
if (branchName) {
|
|
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
|
+
}
|
|
52047
|
+
}
|
|
52048
|
+
if (boundCurrentAppId) {
|
|
52049
|
+
const readyApp = await pollAppReady(params.api, boundCurrentAppId);
|
|
52050
|
+
boundProjectId = String(readyApp.projectId ?? boundProjectId);
|
|
52051
|
+
boundThreadId = readyApp.threadId ? String(readyApp.threadId) : boundThreadId;
|
|
52052
|
+
}
|
|
51031
52053
|
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
51032
52054
|
operation: "`remix collab init`",
|
|
51033
52055
|
recoveryHint: "The repository changed before the Remix binding was written. Review the local changes and rerun `remix collab init`."
|
|
51034
52056
|
});
|
|
51035
|
-
const
|
|
51036
|
-
|
|
51037
|
-
|
|
51038
|
-
|
|
51039
|
-
|
|
51040
|
-
|
|
51041
|
-
|
|
51042
|
-
|
|
51043
|
-
|
|
51044
|
-
|
|
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
|
+
}
|
|
51045
52115
|
return {
|
|
51046
52116
|
reused: false,
|
|
51047
|
-
projectId:
|
|
51048
|
-
appId:
|
|
51049
|
-
dashboardUrl: buildDashboardAppUrl(
|
|
51050
|
-
upstreamAppId:
|
|
52117
|
+
projectId: boundProjectId,
|
|
52118
|
+
appId: boundCurrentAppId,
|
|
52119
|
+
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId),
|
|
52120
|
+
upstreamAppId: boundUpstreamAppId,
|
|
51051
52121
|
bindingPath,
|
|
51052
52122
|
repoRoot,
|
|
52123
|
+
bindingMode,
|
|
52124
|
+
createdCanonicalFamily: Boolean(params.forceNew),
|
|
51053
52125
|
remoteUrl,
|
|
51054
52126
|
defaultBranch,
|
|
51055
|
-
preferredBranch,
|
|
51056
52127
|
...warnings.length > 0 ? { warnings } : {}
|
|
51057
52128
|
};
|
|
51058
52129
|
}
|
|
@@ -51098,7 +52169,11 @@ async function collabList(params) {
|
|
|
51098
52169
|
}
|
|
51099
52170
|
async function collabReconcile(params) {
|
|
51100
52171
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51101
|
-
const binding = await
|
|
52172
|
+
const binding = await ensureActiveLaneBinding({
|
|
52173
|
+
repoRoot,
|
|
52174
|
+
api: params.api,
|
|
52175
|
+
operation: "`remix collab reconcile`"
|
|
52176
|
+
});
|
|
51102
52177
|
if (!binding) {
|
|
51103
52178
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
51104
52179
|
exitCode: 2,
|
|
@@ -51107,9 +52182,9 @@ async function collabReconcile(params) {
|
|
|
51107
52182
|
}
|
|
51108
52183
|
await ensureCleanWorktree(repoRoot, "`remix collab reconcile`");
|
|
51109
52184
|
const branch = await requireCurrentBranch(repoRoot);
|
|
51110
|
-
|
|
52185
|
+
assertBoundBranchMatch({
|
|
51111
52186
|
currentBranch: branch,
|
|
51112
|
-
|
|
52187
|
+
branchName: binding.branchName,
|
|
51113
52188
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
51114
52189
|
operation: "`remix collab reconcile`"
|
|
51115
52190
|
});
|
|
@@ -51218,9 +52293,9 @@ async function collabReconcile(params) {
|
|
|
51218
52293
|
});
|
|
51219
52294
|
await ensureCleanWorktree(lockedRepoRoot, "`remix collab reconcile`");
|
|
51220
52295
|
const lockedBranch = await requireCurrentBranch(lockedRepoRoot);
|
|
51221
|
-
|
|
52296
|
+
assertBoundBranchMatch({
|
|
51222
52297
|
currentBranch: lockedBranch,
|
|
51223
|
-
|
|
52298
|
+
branchName: binding.branchName,
|
|
51224
52299
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
51225
52300
|
operation: "`remix collab reconcile`"
|
|
51226
52301
|
});
|
|
@@ -51275,38 +52350,76 @@ async function collabRemix(params) {
|
|
|
51275
52350
|
hint: "Pass the source app id to remix."
|
|
51276
52351
|
});
|
|
51277
52352
|
}
|
|
51278
|
-
const
|
|
52353
|
+
const sourceApp = await pollAppReady(params.api, sourceAppId);
|
|
52354
|
+
const sourceCollab = sourceApp.collab && typeof sourceApp.collab === "object" ? sourceApp.collab : null;
|
|
52355
|
+
const sourceSource = sourceApp.source && typeof sourceApp.source === "object" ? sourceApp.source : null;
|
|
52356
|
+
const sourceBranchName = typeof sourceCollab?.branchName === "string" && sourceCollab.branchName.trim() || typeof sourceSource?.branch === "string" && sourceSource.branch.trim() || typeof sourceSource?.defaultBranch === "string" && sourceSource.defaultBranch.trim() || void 0;
|
|
52357
|
+
const forkResp = await params.api.forkApp(sourceAppId, {
|
|
52358
|
+
name: params.name?.trim() || void 0,
|
|
52359
|
+
platform: "generic",
|
|
52360
|
+
branchName: sourceBranchName
|
|
52361
|
+
});
|
|
51279
52362
|
const forked = unwrapResponseObject(forkResp, "fork");
|
|
51280
52363
|
const app = await pollAppReady(params.api, String(forked.id));
|
|
52364
|
+
const collab = app.collab && typeof app.collab === "object" ? app.collab : null;
|
|
52365
|
+
const source = app.source && typeof app.source === "object" ? app.source : null;
|
|
52366
|
+
const authoritativeBranchName = typeof collab?.branchName === "string" && collab.branchName.trim() || typeof source?.branch === "string" && source.branch.trim() || typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || sourceBranchName || null;
|
|
52367
|
+
const authoritativeRemoteUrl = typeof source?.remoteUrl === "string" && source.remoteUrl.trim() || null;
|
|
52368
|
+
const authoritativeDefaultBranch = typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
51281
52369
|
const checkout = await materializeAppCheckout({
|
|
51282
52370
|
api: params.api,
|
|
51283
52371
|
cwd: params.cwd,
|
|
51284
52372
|
appId: String(app.id),
|
|
51285
52373
|
outputDir: params.outputDir ?? null,
|
|
51286
|
-
defaultDirName: sanitizeCheckoutDirName(String(params.name?.trim() || app.name || app.id))
|
|
51287
|
-
|
|
51288
|
-
|
|
52374
|
+
defaultDirName: sanitizeCheckoutDirName(String(params.name?.trim() || app.name || app.id)),
|
|
52375
|
+
expectedBranchName: authoritativeBranchName,
|
|
52376
|
+
expectedRemoteUrl: authoritativeRemoteUrl,
|
|
52377
|
+
expectedDefaultBranch: authoritativeDefaultBranch
|
|
52378
|
+
});
|
|
52379
|
+
const laneId = typeof collab?.laneId === "string" ? collab.laneId : null;
|
|
52380
|
+
const repoFingerprint = typeof source?.repoFingerprint === "string" ? source.repoFingerprint : checkout.repoFingerprint;
|
|
52381
|
+
const remoteUrl = typeof source?.remoteUrl === "string" ? source.remoteUrl : checkout.remoteUrl;
|
|
52382
|
+
const defaultBranch = typeof source?.defaultBranch === "string" ? source.defaultBranch : checkout.defaultBranch;
|
|
52383
|
+
const branchName = authoritativeBranchName ?? checkout.branchName;
|
|
52384
|
+
const authoritativeLane = await resolveProjectLaneIfAuthoritative(params.api, {
|
|
51289
52385
|
projectId: String(app.projectId),
|
|
52386
|
+
repoFingerprint,
|
|
52387
|
+
remoteUrl,
|
|
52388
|
+
defaultBranch,
|
|
52389
|
+
branchName,
|
|
51290
52390
|
currentAppId: String(app.id),
|
|
51291
|
-
|
|
51292
|
-
|
|
51293
|
-
|
|
51294
|
-
|
|
51295
|
-
|
|
51296
|
-
|
|
52391
|
+
expectedUpstreamAppId: String(app.forkedFromAppId ?? sourceAppId),
|
|
52392
|
+
createIfMissing: true,
|
|
52393
|
+
seedAppId: String(app.id)
|
|
52394
|
+
});
|
|
52395
|
+
const bindingPath = await writeCollabBinding(checkout.repoRoot, {
|
|
52396
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
52397
|
+
currentAppId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
52398
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? String(app.forkedFromAppId ?? sourceAppId),
|
|
52399
|
+
threadId: authoritativeLane?.threadId ?? (app.threadId ? String(app.threadId) : null),
|
|
52400
|
+
repoFingerprint: authoritativeLane?.repoFingerprint ?? repoFingerprint,
|
|
52401
|
+
remoteUrl: authoritativeLane?.remoteUrl ?? remoteUrl,
|
|
52402
|
+
defaultBranch: authoritativeLane?.defaultBranch ?? defaultBranch,
|
|
52403
|
+
laneId: authoritativeLane?.laneId ?? laneId,
|
|
52404
|
+
branchName: authoritativeLane?.branchName ?? branchName,
|
|
52405
|
+
bindingMode: "lane"
|
|
51297
52406
|
});
|
|
51298
52407
|
return {
|
|
51299
|
-
appId: String(app.id),
|
|
51300
|
-
dashboardUrl: buildDashboardAppUrl(String(app.id)),
|
|
51301
|
-
projectId: String(app.projectId),
|
|
51302
|
-
upstreamAppId: String(app.forkedFromAppId ?? sourceAppId),
|
|
52408
|
+
appId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
52409
|
+
dashboardUrl: buildDashboardAppUrl(authoritativeLane?.currentAppId ?? String(app.id)),
|
|
52410
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
52411
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? String(app.forkedFromAppId ?? sourceAppId),
|
|
51303
52412
|
bindingPath,
|
|
51304
52413
|
repoRoot: checkout.repoRoot
|
|
51305
52414
|
};
|
|
51306
52415
|
}
|
|
51307
52416
|
async function collabRequestMerge(params) {
|
|
51308
52417
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51309
|
-
const binding = await
|
|
52418
|
+
const binding = await ensureActiveLaneBinding({
|
|
52419
|
+
repoRoot,
|
|
52420
|
+
api: params.api,
|
|
52421
|
+
operation: "`remix collab request-merge`"
|
|
52422
|
+
});
|
|
51310
52423
|
if (!binding) throw new RemixError("Repository is not bound to Remix.", { exitCode: 2 });
|
|
51311
52424
|
const resp = await params.api.openMergeRequest(binding.currentAppId);
|
|
51312
52425
|
return unwrapResponseObject(resp, "merge request");
|
|
@@ -51339,7 +52452,9 @@ function createBaseStatus() {
|
|
|
51339
52452
|
repoFingerprint: null,
|
|
51340
52453
|
remoteUrl: null,
|
|
51341
52454
|
defaultBranch: null,
|
|
51342
|
-
|
|
52455
|
+
laneId: null,
|
|
52456
|
+
branchName: null,
|
|
52457
|
+
bindingMode: null
|
|
51343
52458
|
},
|
|
51344
52459
|
remote: {
|
|
51345
52460
|
checked: false,
|
|
@@ -51403,12 +52518,13 @@ async function collabStatus(params) {
|
|
|
51403
52518
|
}
|
|
51404
52519
|
status.repo.isGitRepo = true;
|
|
51405
52520
|
status.repo.repoRoot = repoRoot;
|
|
51406
|
-
const [branch,
|
|
52521
|
+
const [branch, initialHeadCommitHash, worktreeStatus, bindingResolution] = await Promise.all([
|
|
51407
52522
|
getCurrentBranch(repoRoot),
|
|
51408
52523
|
getHeadCommitHash(repoRoot),
|
|
51409
52524
|
getWorktreeStatus(repoRoot),
|
|
51410
|
-
|
|
52525
|
+
resolveActiveLaneBinding({ repoRoot, api: params.api ?? void 0 })
|
|
51411
52526
|
]);
|
|
52527
|
+
let headCommitHash = initialHeadCommitHash;
|
|
51412
52528
|
status.repo.branch = branch;
|
|
51413
52529
|
status.repo.branchMismatch = false;
|
|
51414
52530
|
status.repo.headCommitHash = headCommitHash;
|
|
@@ -51422,13 +52538,61 @@ async function collabStatus(params) {
|
|
|
51422
52538
|
if (!status.repo.worktree.isClean) addWarning(status, "Working tree has local changes.");
|
|
51423
52539
|
if (!branch) addWarning(status, "Repository is in a detached HEAD state.");
|
|
51424
52540
|
if (!headCommitHash) addWarning(status, "Failed to resolve local HEAD commit.");
|
|
51425
|
-
if (
|
|
52541
|
+
if (bindingResolution.status === "not_bound") {
|
|
51426
52542
|
status.binding.path = null;
|
|
51427
52543
|
addBlockedReason(status.sync, "not_bound");
|
|
51428
52544
|
addBlockedReason(status.reconcile, "not_bound");
|
|
51429
52545
|
status.recommendedAction = "init";
|
|
51430
52546
|
return status;
|
|
51431
52547
|
}
|
|
52548
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
52549
|
+
status.binding = {
|
|
52550
|
+
isBound: true,
|
|
52551
|
+
path: getCollabBindingPath(repoRoot),
|
|
52552
|
+
projectId: bindingResolution.projectId,
|
|
52553
|
+
currentAppId: null,
|
|
52554
|
+
upstreamAppId: bindingResolution.upstreamAppId,
|
|
52555
|
+
isRemix: null,
|
|
52556
|
+
threadId: bindingResolution.threadId,
|
|
52557
|
+
repoFingerprint: bindingResolution.repoFingerprint,
|
|
52558
|
+
remoteUrl: bindingResolution.remoteUrl,
|
|
52559
|
+
defaultBranch: bindingResolution.defaultBranch,
|
|
52560
|
+
laneId: null,
|
|
52561
|
+
branchName: bindingResolution.currentBranch,
|
|
52562
|
+
bindingMode: "lane"
|
|
52563
|
+
};
|
|
52564
|
+
addBlockedReason(status.sync, "branch_binding_missing");
|
|
52565
|
+
addBlockedReason(status.reconcile, "branch_binding_missing");
|
|
52566
|
+
addWarning(status, `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`);
|
|
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";
|
|
52593
|
+
return status;
|
|
52594
|
+
}
|
|
52595
|
+
const binding = bindingResolution.binding;
|
|
51432
52596
|
status.binding = {
|
|
51433
52597
|
isBound: true,
|
|
51434
52598
|
path: getCollabBindingPath(repoRoot),
|
|
@@ -51440,13 +52604,21 @@ async function collabStatus(params) {
|
|
|
51440
52604
|
repoFingerprint: binding.repoFingerprint,
|
|
51441
52605
|
remoteUrl: binding.remoteUrl,
|
|
51442
52606
|
defaultBranch: binding.defaultBranch,
|
|
51443
|
-
|
|
52607
|
+
laneId: binding.laneId,
|
|
52608
|
+
branchName: binding.branchName,
|
|
52609
|
+
bindingMode: binding.bindingMode
|
|
51444
52610
|
};
|
|
51445
|
-
status.repo.branchMismatch = !
|
|
52611
|
+
status.repo.branchMismatch = !isBoundBranchMatch(branch, binding.branchName);
|
|
51446
52612
|
if (status.repo.branchMismatch) {
|
|
51447
52613
|
addWarning(
|
|
51448
52614
|
status,
|
|
51449
|
-
`Current branch ${branch ?? "(detached)"} does not match
|
|
52615
|
+
`Current branch ${branch ?? "(detached)"} does not match bound branch ${binding.branchName ?? "(unset)"}.`
|
|
52616
|
+
);
|
|
52617
|
+
}
|
|
52618
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
52619
|
+
addWarning(
|
|
52620
|
+
status,
|
|
52621
|
+
`Local binding app ${binding.currentAppId} conflicts with server-resolved app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"} for branch ${bindingResolution.currentBranch ?? "(detached)"}.`
|
|
51450
52622
|
);
|
|
51451
52623
|
}
|
|
51452
52624
|
if (!params.api) {
|
|
@@ -51494,8 +52666,14 @@ async function collabStatus(params) {
|
|
|
51494
52666
|
const syncResp = syncResult.value;
|
|
51495
52667
|
if (syncResp) {
|
|
51496
52668
|
const sync = unwrapResponseObject(syncResp, "sync result");
|
|
52669
|
+
const latestHeadCommitHash = sync.targetCommitHash && sync.status !== "up_to_date" ? await getHeadCommitHash(repoRoot) : headCommitHash;
|
|
52670
|
+
if (latestHeadCommitHash) {
|
|
52671
|
+
headCommitHash = latestHeadCommitHash;
|
|
52672
|
+
status.repo.headCommitHash = latestHeadCommitHash;
|
|
52673
|
+
}
|
|
52674
|
+
const normalizedSyncStatus = headCommitHash && sync.targetCommitHash && headCommitHash === sync.targetCommitHash ? "up_to_date" : sync.status;
|
|
51497
52675
|
status.sync.checked = true;
|
|
51498
|
-
status.sync.status =
|
|
52676
|
+
status.sync.status = normalizedSyncStatus;
|
|
51499
52677
|
status.sync.warnings = sync.warnings;
|
|
51500
52678
|
status.sync.targetCommitHash = sync.targetCommitHash;
|
|
51501
52679
|
status.sync.targetCommitId = sync.targetCommitId;
|
|
@@ -51503,9 +52681,9 @@ async function collabStatus(params) {
|
|
|
51503
52681
|
if (!status.repo.worktree.isClean) addBlockedReason(status.sync, "dirty_worktree");
|
|
51504
52682
|
if (!branch) addBlockedReason(status.sync, "detached_head");
|
|
51505
52683
|
if (status.repo.branchMismatch) addBlockedReason(status.sync, "branch_mismatch");
|
|
51506
|
-
if (
|
|
52684
|
+
if (normalizedSyncStatus === "conflict_risk") addBlockedReason(status.sync, "metadata_conflict");
|
|
51507
52685
|
status.sync.canApply = status.sync.status === "ready_to_fast_forward" && status.repo.worktree.isClean && Boolean(branch) && !status.sync.blockedReasons.includes("metadata_conflict");
|
|
51508
|
-
if (
|
|
52686
|
+
if (normalizedSyncStatus === "conflict_risk") {
|
|
51509
52687
|
status.reconcile.checked = true;
|
|
51510
52688
|
status.reconcile.status = "metadata_conflict";
|
|
51511
52689
|
status.reconcile.warnings = sync.warnings;
|
|
@@ -51515,7 +52693,7 @@ async function collabStatus(params) {
|
|
|
51515
52693
|
if (!status.repo.worktree.isClean) addBlockedReason(status.reconcile, "dirty_worktree");
|
|
51516
52694
|
if (!branch) addBlockedReason(status.reconcile, "detached_head");
|
|
51517
52695
|
if (status.repo.branchMismatch) addBlockedReason(status.reconcile, "branch_mismatch");
|
|
51518
|
-
} else if (
|
|
52696
|
+
} else if (normalizedSyncStatus === "base_unknown") {
|
|
51519
52697
|
try {
|
|
51520
52698
|
const preflightResp = await params.api.preflightAppReconcile(binding.currentAppId, {
|
|
51521
52699
|
localHeadCommitHash: headCommitHash,
|
|
@@ -51563,6 +52741,8 @@ async function collabStatus(params) {
|
|
|
51563
52741
|
status.recommendedAction = "reconcile";
|
|
51564
52742
|
} else if ((status.remote.incomingOpenMergeRequestCount ?? 0) > 0) {
|
|
51565
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";
|
|
51566
52746
|
} else {
|
|
51567
52747
|
status.recommendedAction = "no_action";
|
|
51568
52748
|
}
|
|
@@ -51570,7 +52750,11 @@ async function collabStatus(params) {
|
|
|
51570
52750
|
}
|
|
51571
52751
|
async function collabSyncUpstream(params) {
|
|
51572
52752
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51573
|
-
const binding = await
|
|
52753
|
+
const binding = await ensureActiveLaneBinding({
|
|
52754
|
+
repoRoot,
|
|
52755
|
+
api: params.api,
|
|
52756
|
+
operation: "`remix collab sync-upstream`"
|
|
52757
|
+
});
|
|
51574
52758
|
if (!binding) {
|
|
51575
52759
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
51576
52760
|
exitCode: 2,
|
|
@@ -51702,6 +52886,7 @@ var ERROR_CODES = {
|
|
|
51702
52886
|
DIRTY_WORKTREE: "DIRTY_WORKTREE",
|
|
51703
52887
|
DETACHED_HEAD: "DETACHED_HEAD",
|
|
51704
52888
|
PREFERRED_BRANCH_MISMATCH: "PREFERRED_BRANCH_MISMATCH",
|
|
52889
|
+
FAMILY_SELECTION_AMBIGUOUS: "FAMILY_SELECTION_AMBIGUOUS",
|
|
51705
52890
|
MISSING_HEAD: "MISSING_HEAD",
|
|
51706
52891
|
REPO_LOCK_HELD: "REPO_LOCK_HELD",
|
|
51707
52892
|
REPO_LOCK_TIMEOUT: "REPO_LOCK_TIMEOUT",
|
|
@@ -51828,7 +53013,7 @@ function normalizeByMessage(err) {
|
|
|
51828
53013
|
category: "local_state"
|
|
51829
53014
|
});
|
|
51830
53015
|
}
|
|
51831
|
-
if (code === ERROR_CODES.PREFERRED_BRANCH_MISMATCH || message.includes("preferred branch")) {
|
|
53016
|
+
if (code === ERROR_CODES.PREFERRED_BRANCH_MISMATCH || message.includes("preferred branch") || message.includes("bound branch")) {
|
|
51832
53017
|
return makeNormalized({
|
|
51833
53018
|
code: ERROR_CODES.PREFERRED_BRANCH_MISMATCH,
|
|
51834
53019
|
message,
|
|
@@ -51836,6 +53021,14 @@ function normalizeByMessage(err) {
|
|
|
51836
53021
|
category: "local_state"
|
|
51837
53022
|
});
|
|
51838
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
|
+
}
|
|
51839
53032
|
if (message.includes("Failed to resolve local HEAD")) {
|
|
51840
53033
|
return makeNormalized({
|
|
51841
53034
|
code: ERROR_CODES.MISSING_HEAD,
|
|
@@ -52232,7 +53425,9 @@ var initDataSchema = external_exports.object({
|
|
|
52232
53425
|
dashboardUrl: external_exports.string().url(),
|
|
52233
53426
|
upstreamAppId: external_exports.string(),
|
|
52234
53427
|
bindingPath: external_exports.string(),
|
|
52235
|
-
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()
|
|
52236
53431
|
});
|
|
52237
53432
|
var listDataSchema = external_exports.object({
|
|
52238
53433
|
apps: genericArraySchema,
|
|
@@ -52360,6 +53555,7 @@ var accessDebugSuccessSchema = makeSuccessSchema(accessDebugDataSchema);
|
|
|
52360
53555
|
var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema);
|
|
52361
53556
|
function getRiskLevel(status) {
|
|
52362
53557
|
if (status.recommendedAction === "reconcile") return "high";
|
|
53558
|
+
if (status.recommendedAction === "choose_family") return "medium";
|
|
52363
53559
|
if (status.recommendedAction === "sync" || status.remote.incomingOpenMergeRequestCount) return "medium";
|
|
52364
53560
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
52365
53561
|
return "low";
|
|
@@ -52367,7 +53563,7 @@ function getRiskLevel(status) {
|
|
|
52367
53563
|
function getRecommendedNextActions(status) {
|
|
52368
53564
|
if (status.repo.branchMismatch) {
|
|
52369
53565
|
return [
|
|
52370
|
-
`Switch to the
|
|
53566
|
+
`Switch to the bound branch (${status.binding.branchName ?? "configured in the binding"}) before using Remix mutation tools, or rerun with allowBranchMismatch=true if this deviation is intentional.`
|
|
52371
53567
|
];
|
|
52372
53568
|
}
|
|
52373
53569
|
switch (status.recommendedAction) {
|
|
@@ -52379,6 +53575,10 @@ function getRecommendedNextActions(status) {
|
|
|
52379
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."];
|
|
52380
53576
|
case "review_queue":
|
|
52381
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
|
+
];
|
|
52382
53582
|
default:
|
|
52383
53583
|
return [];
|
|
52384
53584
|
}
|
|
@@ -55329,7 +56529,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
55329
56529
|
// package.json
|
|
55330
56530
|
var package_default = {
|
|
55331
56531
|
name: "@remixhq/claude-plugin",
|
|
55332
|
-
version: "0.1.
|
|
56532
|
+
version: "0.1.17",
|
|
55333
56533
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
55334
56534
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
55335
56535
|
license: "MIT",
|
|
@@ -55360,8 +56560,8 @@ var package_default = {
|
|
|
55360
56560
|
prepack: "npm run build"
|
|
55361
56561
|
},
|
|
55362
56562
|
dependencies: {
|
|
55363
|
-
"@remixhq/core": "^0.1.
|
|
55364
|
-
"@remixhq/mcp": "^0.1.
|
|
56563
|
+
"@remixhq/core": "^0.1.12",
|
|
56564
|
+
"@remixhq/mcp": "^0.1.12"
|
|
55365
56565
|
},
|
|
55366
56566
|
devDependencies: {
|
|
55367
56567
|
"@types/node": "^25.4.0",
|