@remixhq/claude-plugin 0.1.14 → 0.1.16
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 +10 -0
- package/dist/hook-post-collab.cjs +7508 -38
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +692 -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 +1183 -349
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/identity-and-scope-routing/SKILL.md +4 -0
- package/skills/init-or-remix/SKILL.md +8 -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)}` : "";
|
|
@@ -21627,6 +21639,9 @@ function createApiClient(config2, opts) {
|
|
|
21627
21639
|
const qs = new URLSearchParams();
|
|
21628
21640
|
if (params?.projectId) qs.set("projectId", params.projectId);
|
|
21629
21641
|
if (params?.organizationId) qs.set("organizationId", params.organizationId);
|
|
21642
|
+
if (params?.ownership) qs.set("ownership", params.ownership);
|
|
21643
|
+
if (params?.accessScope) qs.set("accessScope", params.accessScope);
|
|
21644
|
+
if (params?.createdBy) qs.set("createdBy", params.createdBy);
|
|
21630
21645
|
if (params?.forked) qs.set("forked", params.forked);
|
|
21631
21646
|
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21632
21647
|
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
@@ -21673,6 +21688,7 @@ function createApiClient(config2, opts) {
|
|
|
21673
21688
|
if (params?.offset !== void 0) qs.set("offset", String(params.offset));
|
|
21674
21689
|
if (params?.changeStepId) qs.set("changeStepId", params.changeStepId);
|
|
21675
21690
|
if (params?.threadId) qs.set("threadId", params.threadId);
|
|
21691
|
+
if (params?.collabLaneId) qs.set("collabLaneId", params.collabLaneId);
|
|
21676
21692
|
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21677
21693
|
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21678
21694
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
@@ -30782,8 +30798,8 @@ var IcebergError = class extends Error {
|
|
|
30782
30798
|
return this.status === 419;
|
|
30783
30799
|
}
|
|
30784
30800
|
};
|
|
30785
|
-
function buildUrl(baseUrl,
|
|
30786
|
-
const url = new URL(
|
|
30801
|
+
function buildUrl(baseUrl, path13, query) {
|
|
30802
|
+
const url = new URL(path13, baseUrl);
|
|
30787
30803
|
if (query) {
|
|
30788
30804
|
for (const [key, value] of Object.entries(query)) {
|
|
30789
30805
|
if (value !== void 0) {
|
|
@@ -30813,12 +30829,12 @@ function createFetchClient(options) {
|
|
|
30813
30829
|
return {
|
|
30814
30830
|
async request({
|
|
30815
30831
|
method,
|
|
30816
|
-
path:
|
|
30832
|
+
path: path13,
|
|
30817
30833
|
query,
|
|
30818
30834
|
body,
|
|
30819
30835
|
headers
|
|
30820
30836
|
}) {
|
|
30821
|
-
const url = buildUrl(options.baseUrl,
|
|
30837
|
+
const url = buildUrl(options.baseUrl, path13, query);
|
|
30822
30838
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
30823
30839
|
const res = await fetchFn(url, {
|
|
30824
30840
|
method,
|
|
@@ -31637,7 +31653,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31637
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.
|
|
31638
31654
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
31639
31655
|
*/
|
|
31640
|
-
async uploadOrUpdate(method,
|
|
31656
|
+
async uploadOrUpdate(method, path13, fileBody, fileOptions) {
|
|
31641
31657
|
var _this = this;
|
|
31642
31658
|
return _this.handleOperation(async () => {
|
|
31643
31659
|
let body;
|
|
@@ -31661,7 +31677,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31661
31677
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
31662
31678
|
}
|
|
31663
31679
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) headers = _objectSpread22(_objectSpread22({}, headers), fileOptions.headers);
|
|
31664
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
31680
|
+
const cleanPath = _this._removeEmptyFolders(path13);
|
|
31665
31681
|
const _path = _this._getFinalPath(cleanPath);
|
|
31666
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 } : {}));
|
|
31667
31683
|
return {
|
|
@@ -31722,8 +31738,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31722
31738
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31723
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.
|
|
31724
31740
|
*/
|
|
31725
|
-
async upload(
|
|
31726
|
-
return this.uploadOrUpdate("POST",
|
|
31741
|
+
async upload(path13, fileBody, fileOptions) {
|
|
31742
|
+
return this.uploadOrUpdate("POST", path13, fileBody, fileOptions);
|
|
31727
31743
|
}
|
|
31728
31744
|
/**
|
|
31729
31745
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -31762,9 +31778,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31762
31778
|
* - `objects` table permissions: none
|
|
31763
31779
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31764
31780
|
*/
|
|
31765
|
-
async uploadToSignedUrl(
|
|
31781
|
+
async uploadToSignedUrl(path13, token, fileBody, fileOptions) {
|
|
31766
31782
|
var _this3 = this;
|
|
31767
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
31783
|
+
const cleanPath = _this3._removeEmptyFolders(path13);
|
|
31768
31784
|
const _path = _this3._getFinalPath(cleanPath);
|
|
31769
31785
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
31770
31786
|
url.searchParams.set("token", token);
|
|
@@ -31826,10 +31842,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31826
31842
|
* - `objects` table permissions: `insert`
|
|
31827
31843
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31828
31844
|
*/
|
|
31829
|
-
async createSignedUploadUrl(
|
|
31845
|
+
async createSignedUploadUrl(path13, options) {
|
|
31830
31846
|
var _this4 = this;
|
|
31831
31847
|
return _this4.handleOperation(async () => {
|
|
31832
|
-
let _path = _this4._getFinalPath(
|
|
31848
|
+
let _path = _this4._getFinalPath(path13);
|
|
31833
31849
|
const headers = _objectSpread22({}, _this4.headers);
|
|
31834
31850
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
31835
31851
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -31838,7 +31854,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31838
31854
|
if (!token) throw new StorageError("No token returned by API");
|
|
31839
31855
|
return {
|
|
31840
31856
|
signedUrl: url.toString(),
|
|
31841
|
-
path:
|
|
31857
|
+
path: path13,
|
|
31842
31858
|
token
|
|
31843
31859
|
};
|
|
31844
31860
|
});
|
|
@@ -31894,8 +31910,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
31894
31910
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
31895
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.
|
|
31896
31912
|
*/
|
|
31897
|
-
async update(
|
|
31898
|
-
return this.uploadOrUpdate("PUT",
|
|
31913
|
+
async update(path13, fileBody, fileOptions) {
|
|
31914
|
+
return this.uploadOrUpdate("PUT", path13, fileBody, fileOptions);
|
|
31899
31915
|
}
|
|
31900
31916
|
/**
|
|
31901
31917
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -32042,10 +32058,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32042
32058
|
* - `objects` table permissions: `select`
|
|
32043
32059
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32044
32060
|
*/
|
|
32045
|
-
async createSignedUrl(
|
|
32061
|
+
async createSignedUrl(path13, expiresIn, options) {
|
|
32046
32062
|
var _this8 = this;
|
|
32047
32063
|
return _this8.handleOperation(async () => {
|
|
32048
|
-
let _path = _this8._getFinalPath(
|
|
32064
|
+
let _path = _this8._getFinalPath(path13);
|
|
32049
32065
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
32050
32066
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
32051
32067
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `&download=${options.download === true ? "" : options.download}` : "";
|
|
@@ -32172,11 +32188,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32172
32188
|
* - `objects` table permissions: `select`
|
|
32173
32189
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32174
32190
|
*/
|
|
32175
|
-
download(
|
|
32191
|
+
download(path13, options, parameters) {
|
|
32176
32192
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) !== "undefined" ? "render/image/authenticated" : "object";
|
|
32177
32193
|
const transformationQuery = this.transformOptsToQueryString((options === null || options === void 0 ? void 0 : options.transform) || {});
|
|
32178
32194
|
const queryString = transformationQuery ? `?${transformationQuery}` : "";
|
|
32179
|
-
const _path = this._getFinalPath(
|
|
32195
|
+
const _path = this._getFinalPath(path13);
|
|
32180
32196
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString}`, {
|
|
32181
32197
|
headers: this.headers,
|
|
32182
32198
|
noResolveJson: true
|
|
@@ -32206,9 +32222,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32206
32222
|
* }
|
|
32207
32223
|
* ```
|
|
32208
32224
|
*/
|
|
32209
|
-
async info(
|
|
32225
|
+
async info(path13) {
|
|
32210
32226
|
var _this10 = this;
|
|
32211
|
-
const _path = _this10._getFinalPath(
|
|
32227
|
+
const _path = _this10._getFinalPath(path13);
|
|
32212
32228
|
return _this10.handleOperation(async () => {
|
|
32213
32229
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
32214
32230
|
});
|
|
@@ -32228,9 +32244,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32228
32244
|
* .exists('folder/avatar1.png')
|
|
32229
32245
|
* ```
|
|
32230
32246
|
*/
|
|
32231
|
-
async exists(
|
|
32247
|
+
async exists(path13) {
|
|
32232
32248
|
var _this11 = this;
|
|
32233
|
-
const _path = _this11._getFinalPath(
|
|
32249
|
+
const _path = _this11._getFinalPath(path13);
|
|
32234
32250
|
try {
|
|
32235
32251
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
32236
32252
|
return {
|
|
@@ -32307,8 +32323,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32307
32323
|
* - `objects` table permissions: none
|
|
32308
32324
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32309
32325
|
*/
|
|
32310
|
-
getPublicUrl(
|
|
32311
|
-
const _path = this._getFinalPath(
|
|
32326
|
+
getPublicUrl(path13, options) {
|
|
32327
|
+
const _path = this._getFinalPath(path13);
|
|
32312
32328
|
const _queryString = [];
|
|
32313
32329
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `download=${options.download === true ? "" : options.download}` : "";
|
|
32314
32330
|
if (downloadQueryParam !== "") _queryString.push(downloadQueryParam);
|
|
@@ -32447,10 +32463,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32447
32463
|
* - `objects` table permissions: `select`
|
|
32448
32464
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
32449
32465
|
*/
|
|
32450
|
-
async list(
|
|
32466
|
+
async list(path13, options, parameters) {
|
|
32451
32467
|
var _this13 = this;
|
|
32452
32468
|
return _this13.handleOperation(async () => {
|
|
32453
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
32469
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path13 || "" });
|
|
32454
32470
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
32455
32471
|
});
|
|
32456
32472
|
}
|
|
@@ -32514,11 +32530,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
32514
32530
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
32515
32531
|
return btoa(data);
|
|
32516
32532
|
}
|
|
32517
|
-
_getFinalPath(
|
|
32518
|
-
return `${this.bucketId}/${
|
|
32533
|
+
_getFinalPath(path13) {
|
|
32534
|
+
return `${this.bucketId}/${path13.replace(/^\/+/, "")}`;
|
|
32519
32535
|
}
|
|
32520
|
-
_removeEmptyFolders(
|
|
32521
|
-
return
|
|
32536
|
+
_removeEmptyFolders(path13) {
|
|
32537
|
+
return path13.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
32522
32538
|
}
|
|
32523
32539
|
transformOptsToQueryString(transform2) {
|
|
32524
32540
|
const params = [];
|
|
@@ -41789,89 +41805,11 @@ var REMIX_ERROR_CODES = {
|
|
|
41789
41805
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
41790
41806
|
var import_path11 = __toESM(require("path"), 1);
|
|
41791
41807
|
|
|
41792
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41793
|
-
var
|
|
41794
|
-
var import_path2 = __toESM(require("path"), 1);
|
|
41795
|
-
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
41796
|
-
var import_path3 = __toESM(require("path"), 1);
|
|
41797
|
-
async function reserveDirectory(targetDir) {
|
|
41798
|
-
try {
|
|
41799
|
-
await import_promises3.default.mkdir(targetDir);
|
|
41800
|
-
return targetDir;
|
|
41801
|
-
} catch (error2) {
|
|
41802
|
-
if (error2?.code === "EEXIST") {
|
|
41803
|
-
throw new RemixError("Output directory already exists.", {
|
|
41804
|
-
exitCode: 2,
|
|
41805
|
-
hint: `Choose an empty destination path: ${targetDir}`
|
|
41806
|
-
});
|
|
41807
|
-
}
|
|
41808
|
-
throw error2;
|
|
41809
|
-
}
|
|
41810
|
-
}
|
|
41811
|
-
async function reserveAvailableDirPath(preferredDir) {
|
|
41812
|
-
const parent = import_path3.default.dirname(preferredDir);
|
|
41813
|
-
const base = import_path3.default.basename(preferredDir);
|
|
41814
|
-
for (let i2 = 1; i2 <= 1e3; i2 += 1) {
|
|
41815
|
-
const candidate = i2 === 1 ? preferredDir : import_path3.default.join(parent, `${base}-${i2}`);
|
|
41816
|
-
try {
|
|
41817
|
-
await import_promises3.default.mkdir(candidate);
|
|
41818
|
-
return candidate;
|
|
41819
|
-
} catch (error2) {
|
|
41820
|
-
if (error2?.code === "EEXIST") continue;
|
|
41821
|
-
throw error2;
|
|
41822
|
-
}
|
|
41823
|
-
}
|
|
41824
|
-
throw new RemixError("No available output directory name.", {
|
|
41825
|
-
exitCode: 2,
|
|
41826
|
-
hint: `Tried ${base} through ${base}-1000 under ${parent}.`
|
|
41827
|
-
});
|
|
41828
|
-
}
|
|
41829
|
-
async function writeJsonAtomic2(filePath, value) {
|
|
41830
|
-
const dir = import_path3.default.dirname(filePath);
|
|
41831
|
-
await import_promises3.default.mkdir(dir, { recursive: true });
|
|
41832
|
-
const tmp = `${filePath}.tmp-${Date.now()}`;
|
|
41833
|
-
await import_promises3.default.writeFile(tmp, `${JSON.stringify(value, null, 2)}
|
|
41834
|
-
`, "utf8");
|
|
41835
|
-
await import_promises3.default.rename(tmp, filePath);
|
|
41836
|
-
}
|
|
41837
|
-
function getCollabBindingPath(repoRoot) {
|
|
41838
|
-
return import_path2.default.join(repoRoot, ".remix", "config.json");
|
|
41839
|
-
}
|
|
41840
|
-
async function readCollabBinding(repoRoot) {
|
|
41841
|
-
try {
|
|
41842
|
-
const raw = await import_promises2.default.readFile(getCollabBindingPath(repoRoot), "utf8");
|
|
41843
|
-
const parsed = JSON.parse(raw);
|
|
41844
|
-
if (parsed?.schemaVersion !== 1) return null;
|
|
41845
|
-
if (!parsed.projectId || !parsed.currentAppId || !parsed.upstreamAppId) return null;
|
|
41846
|
-
return {
|
|
41847
|
-
schemaVersion: 1,
|
|
41848
|
-
projectId: parsed.projectId,
|
|
41849
|
-
currentAppId: parsed.currentAppId,
|
|
41850
|
-
upstreamAppId: parsed.upstreamAppId,
|
|
41851
|
-
threadId: parsed.threadId ?? null,
|
|
41852
|
-
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
41853
|
-
remoteUrl: parsed.remoteUrl ?? null,
|
|
41854
|
-
defaultBranch: parsed.defaultBranch ?? null,
|
|
41855
|
-
preferredBranch: parsed.preferredBranch ?? parsed.defaultBranch ?? null
|
|
41856
|
-
};
|
|
41857
|
-
} catch {
|
|
41858
|
-
return null;
|
|
41859
|
-
}
|
|
41860
|
-
}
|
|
41861
|
-
async function writeCollabBinding(repoRoot, binding) {
|
|
41862
|
-
const filePath = getCollabBindingPath(repoRoot);
|
|
41863
|
-
await writeJsonAtomic2(filePath, {
|
|
41864
|
-
schemaVersion: 1,
|
|
41865
|
-
...binding
|
|
41866
|
-
});
|
|
41867
|
-
return filePath;
|
|
41868
|
-
}
|
|
41869
|
-
|
|
41870
|
-
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
41871
|
-
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);
|
|
41872
41810
|
var import_crypto = require("crypto");
|
|
41873
41811
|
var import_os2 = __toESM(require("os"), 1);
|
|
41874
|
-
var
|
|
41812
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
41875
41813
|
|
|
41876
41814
|
// node_modules/is-plain-obj/index.js
|
|
41877
41815
|
function isPlainObject4(value) {
|
|
@@ -42803,7 +42741,7 @@ var npmRunPathEnv = ({ env = import_node_process6.default.env, ...options } = {}
|
|
|
42803
42741
|
};
|
|
42804
42742
|
|
|
42805
42743
|
// node_modules/execa/lib/terminate/kill.js
|
|
42806
|
-
var
|
|
42744
|
+
var import_promises2 = require("timers/promises");
|
|
42807
42745
|
|
|
42808
42746
|
// node_modules/execa/lib/return/final-error.js
|
|
42809
42747
|
var getFinalError = (originalError, message, isSync) => {
|
|
@@ -43310,7 +43248,7 @@ var killOnTimeout = async ({ kill, forceKillAfterDelay, context, controllerSigna
|
|
|
43310
43248
|
return;
|
|
43311
43249
|
}
|
|
43312
43250
|
try {
|
|
43313
|
-
await (0,
|
|
43251
|
+
await (0, import_promises2.setTimeout)(forceKillAfterDelay, void 0, { signal: controllerSignal });
|
|
43314
43252
|
if (kill("SIGKILL")) {
|
|
43315
43253
|
context.isForcefullyTerminated ??= true;
|
|
43316
43254
|
}
|
|
@@ -43341,7 +43279,7 @@ var terminateOnCancel = async (subprocess, cancelSignal, context, { signal }) =>
|
|
|
43341
43279
|
};
|
|
43342
43280
|
|
|
43343
43281
|
// node_modules/execa/lib/ipc/graceful.js
|
|
43344
|
-
var
|
|
43282
|
+
var import_promises4 = require("timers/promises");
|
|
43345
43283
|
|
|
43346
43284
|
// node_modules/execa/lib/ipc/send.js
|
|
43347
43285
|
var import_node_util5 = require("util");
|
|
@@ -43528,7 +43466,7 @@ var import_node_events4 = require("events");
|
|
|
43528
43466
|
|
|
43529
43467
|
// node_modules/execa/lib/ipc/incoming.js
|
|
43530
43468
|
var import_node_events3 = require("events");
|
|
43531
|
-
var
|
|
43469
|
+
var import_promises3 = require("timers/promises");
|
|
43532
43470
|
|
|
43533
43471
|
// node_modules/execa/lib/ipc/reference.js
|
|
43534
43472
|
var addReference = (channel, reference) => {
|
|
@@ -43575,7 +43513,7 @@ var onMessage = async ({ anyProcess, channel, isSubprocess, ipcEmitter }, wrappe
|
|
|
43575
43513
|
}
|
|
43576
43514
|
while (incomingMessages.length > 0) {
|
|
43577
43515
|
await waitForOutgoingMessages(anyProcess, ipcEmitter, wrappedMessage);
|
|
43578
|
-
await
|
|
43516
|
+
await import_promises3.scheduler.yield();
|
|
43579
43517
|
const message = await handleStrictRequest({
|
|
43580
43518
|
wrappedMessage: incomingMessages[0],
|
|
43581
43519
|
anyProcess,
|
|
@@ -43855,7 +43793,7 @@ var startIpc = async ({ anyProcess, channel, isSubprocess, ipc }) => {
|
|
|
43855
43793
|
return;
|
|
43856
43794
|
}
|
|
43857
43795
|
getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
43858
|
-
await
|
|
43796
|
+
await import_promises4.scheduler.yield();
|
|
43859
43797
|
};
|
|
43860
43798
|
var cancelListening = false;
|
|
43861
43799
|
var handleAbort = (wrappedMessage) => {
|
|
@@ -43928,7 +43866,7 @@ var getReason = ({ reason }) => {
|
|
|
43928
43866
|
};
|
|
43929
43867
|
|
|
43930
43868
|
// node_modules/execa/lib/terminate/timeout.js
|
|
43931
|
-
var
|
|
43869
|
+
var import_promises5 = require("timers/promises");
|
|
43932
43870
|
var validateTimeout = ({ timeout }) => {
|
|
43933
43871
|
if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) {
|
|
43934
43872
|
throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);
|
|
@@ -43936,7 +43874,7 @@ var validateTimeout = ({ timeout }) => {
|
|
|
43936
43874
|
};
|
|
43937
43875
|
var throwOnTimeout = (subprocess, timeout, context, controller) => timeout === 0 || timeout === void 0 ? [] : [killAfterTimeout(subprocess, timeout, context, controller)];
|
|
43938
43876
|
var killAfterTimeout = async (subprocess, timeout, context, { signal }) => {
|
|
43939
|
-
await (0,
|
|
43877
|
+
await (0, import_promises5.setTimeout)(timeout, void 0, { signal });
|
|
43940
43878
|
context.terminationReason ??= "timeout";
|
|
43941
43879
|
subprocess.kill();
|
|
43942
43880
|
throw new DiscardedError();
|
|
@@ -44193,7 +44131,7 @@ var CR_BINARY = CR.codePointAt(0);
|
|
|
44193
44131
|
|
|
44194
44132
|
// node_modules/get-stream/source/index.js
|
|
44195
44133
|
var import_node_events6 = require("events");
|
|
44196
|
-
var
|
|
44134
|
+
var import_promises6 = require("stream/promises");
|
|
44197
44135
|
|
|
44198
44136
|
// node_modules/is-stream/index.js
|
|
44199
44137
|
function isStream(stream, { checkOpen = true } = {}) {
|
|
@@ -44559,7 +44497,7 @@ var stringMethods = {
|
|
|
44559
44497
|
};
|
|
44560
44498
|
|
|
44561
44499
|
// node_modules/get-stream/source/index.js
|
|
44562
|
-
Object.assign(nodeImports, { on: import_node_events6.on, finished:
|
|
44500
|
+
Object.assign(nodeImports, { on: import_node_events6.on, finished: import_promises6.finished });
|
|
44563
44501
|
|
|
44564
44502
|
// node_modules/execa/lib/io/max-buffer.js
|
|
44565
44503
|
var handleMaxBuffer = ({ error: error2, stream, readableObjectMode, lines, encoding, fdNumber }) => {
|
|
@@ -46254,13 +46192,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
|
|
|
46254
46192
|
}
|
|
46255
46193
|
};
|
|
46256
46194
|
var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
46257
|
-
for (const { path:
|
|
46258
|
-
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();
|
|
46259
46197
|
if (append || outputFiles.has(pathString)) {
|
|
46260
|
-
(0, import_node_fs4.appendFileSync)(
|
|
46198
|
+
(0, import_node_fs4.appendFileSync)(path13, serializedResult);
|
|
46261
46199
|
} else {
|
|
46262
46200
|
outputFiles.add(pathString);
|
|
46263
|
-
(0, import_node_fs4.writeFileSync)(
|
|
46201
|
+
(0, import_node_fs4.writeFileSync)(path13, serializedResult);
|
|
46264
46202
|
}
|
|
46265
46203
|
}
|
|
46266
46204
|
};
|
|
@@ -46751,7 +46689,7 @@ var addPropertiesAsync = {
|
|
|
46751
46689
|
// node_modules/@sindresorhus/merge-streams/index.js
|
|
46752
46690
|
var import_node_events10 = require("events");
|
|
46753
46691
|
var import_node_stream4 = require("stream");
|
|
46754
|
-
var
|
|
46692
|
+
var import_promises7 = require("stream/promises");
|
|
46755
46693
|
function mergeStreams(streams) {
|
|
46756
46694
|
if (!Array.isArray(streams)) {
|
|
46757
46695
|
throw new TypeError(`Expected an array, got \`${typeof streams}\`.`);
|
|
@@ -46834,7 +46772,7 @@ var onMergedStreamFinished = async (passThroughStream, streams, unpipeEvent) =>
|
|
|
46834
46772
|
};
|
|
46835
46773
|
var onMergedStreamEnd = async (passThroughStream, { signal }) => {
|
|
46836
46774
|
try {
|
|
46837
|
-
await (0,
|
|
46775
|
+
await (0, import_promises7.finished)(passThroughStream, { signal, cleanup: true });
|
|
46838
46776
|
} catch (error2) {
|
|
46839
46777
|
errorOrAbortStream(passThroughStream, error2);
|
|
46840
46778
|
throw error2;
|
|
@@ -46901,7 +46839,7 @@ var afterMergedStreamFinished = async (onFinished, stream, { signal }) => {
|
|
|
46901
46839
|
};
|
|
46902
46840
|
var onInputStreamEnd = async ({ passThroughStream, stream, streams, ended, aborted: aborted3, controller: { signal } }) => {
|
|
46903
46841
|
try {
|
|
46904
|
-
await (0,
|
|
46842
|
+
await (0, import_promises7.finished)(stream, {
|
|
46905
46843
|
signal,
|
|
46906
46844
|
cleanup: true,
|
|
46907
46845
|
readable: true,
|
|
@@ -46966,7 +46904,7 @@ var PASSTHROUGH_LISTENERS_COUNT = 2;
|
|
|
46966
46904
|
var PASSTHROUGH_LISTENERS_PER_STREAM = 1;
|
|
46967
46905
|
|
|
46968
46906
|
// node_modules/execa/lib/io/pipeline.js
|
|
46969
|
-
var
|
|
46907
|
+
var import_promises8 = require("stream/promises");
|
|
46970
46908
|
var pipeStreams = (source, destination) => {
|
|
46971
46909
|
source.pipe(destination);
|
|
46972
46910
|
onSourceFinish(source, destination);
|
|
@@ -46977,7 +46915,7 @@ var onSourceFinish = async (source, destination) => {
|
|
|
46977
46915
|
return;
|
|
46978
46916
|
}
|
|
46979
46917
|
try {
|
|
46980
|
-
await (0,
|
|
46918
|
+
await (0, import_promises8.finished)(source, { cleanup: true, readable: true, writable: false });
|
|
46981
46919
|
} catch {
|
|
46982
46920
|
}
|
|
46983
46921
|
endDestinationStream(destination);
|
|
@@ -46992,7 +46930,7 @@ var onDestinationFinish = async (source, destination) => {
|
|
|
46992
46930
|
return;
|
|
46993
46931
|
}
|
|
46994
46932
|
try {
|
|
46995
|
-
await (0,
|
|
46933
|
+
await (0, import_promises8.finished)(destination, { cleanup: true, readable: false, writable: true });
|
|
46996
46934
|
} catch {
|
|
46997
46935
|
}
|
|
46998
46936
|
abortSourceStream(source);
|
|
@@ -47463,7 +47401,7 @@ var waitForBothSubprocesses = async (subprocessPromises) => {
|
|
|
47463
47401
|
};
|
|
47464
47402
|
|
|
47465
47403
|
// node_modules/execa/lib/pipe/streaming.js
|
|
47466
|
-
var
|
|
47404
|
+
var import_promises9 = require("stream/promises");
|
|
47467
47405
|
var pipeSubprocessStream = (sourceStream, destinationStream, maxListenersController) => {
|
|
47468
47406
|
const mergedStream = MERGED_STREAMS.has(destinationStream) ? pipeMoreSubprocessStream(sourceStream, destinationStream) : pipeFirstSubprocessStream(sourceStream, destinationStream);
|
|
47469
47407
|
incrementMaxListeners(sourceStream, SOURCE_LISTENERS_PER_PIPE, maxListenersController.signal);
|
|
@@ -47484,7 +47422,7 @@ var pipeMoreSubprocessStream = (sourceStream, destinationStream) => {
|
|
|
47484
47422
|
};
|
|
47485
47423
|
var cleanupMergedStreamsMap = async (destinationStream) => {
|
|
47486
47424
|
try {
|
|
47487
|
-
await (0,
|
|
47425
|
+
await (0, import_promises9.finished)(destinationStream, { cleanup: true, readable: false, writable: true });
|
|
47488
47426
|
} catch {
|
|
47489
47427
|
}
|
|
47490
47428
|
MERGED_STREAMS.delete(destinationStream);
|
|
@@ -47568,7 +47506,7 @@ var handlePipePromise = async ({
|
|
|
47568
47506
|
var getSubprocessPromises = (sourcePromise, destination) => Promise.allSettled([sourcePromise, destination]);
|
|
47569
47507
|
|
|
47570
47508
|
// node_modules/execa/lib/io/contents.js
|
|
47571
|
-
var
|
|
47509
|
+
var import_promises10 = require("timers/promises");
|
|
47572
47510
|
|
|
47573
47511
|
// node_modules/execa/lib/io/iterate.js
|
|
47574
47512
|
var import_node_events12 = require("events");
|
|
@@ -47720,7 +47658,7 @@ var logOutputAsync = async ({ stream, onStreamEnd, fdNumber, encoding, allMixed,
|
|
|
47720
47658
|
await logLines(linesIterable, stream, fdNumber, verboseInfo);
|
|
47721
47659
|
};
|
|
47722
47660
|
var resumeStream = async (stream) => {
|
|
47723
|
-
await (0,
|
|
47661
|
+
await (0, import_promises10.setImmediate)();
|
|
47724
47662
|
if (stream.readableFlowing === null) {
|
|
47725
47663
|
stream.resume();
|
|
47726
47664
|
}
|
|
@@ -47755,14 +47693,14 @@ var getBufferedData = async (streamPromise) => {
|
|
|
47755
47693
|
var handleBufferedData = ({ bufferedData }) => isArrayBuffer(bufferedData) ? new Uint8Array(bufferedData) : bufferedData;
|
|
47756
47694
|
|
|
47757
47695
|
// node_modules/execa/lib/resolve/wait-stream.js
|
|
47758
|
-
var
|
|
47696
|
+
var import_promises11 = require("stream/promises");
|
|
47759
47697
|
var waitForStream = async (stream, fdNumber, streamInfo, { isSameDirection, stopOnExit = false } = {}) => {
|
|
47760
47698
|
const state = handleStdinDestroy(stream, streamInfo);
|
|
47761
47699
|
const abortController = new AbortController();
|
|
47762
47700
|
try {
|
|
47763
47701
|
await Promise.race([
|
|
47764
47702
|
...stopOnExit ? [streamInfo.exitPromise] : [],
|
|
47765
|
-
(0,
|
|
47703
|
+
(0, import_promises11.finished)(stream, { cleanup: true, signal: abortController.signal })
|
|
47766
47704
|
]);
|
|
47767
47705
|
} catch (error2) {
|
|
47768
47706
|
if (!state.stdinCleanedUp) {
|
|
@@ -48076,7 +48014,7 @@ var import_node_stream6 = require("stream");
|
|
|
48076
48014
|
var import_node_util9 = require("util");
|
|
48077
48015
|
|
|
48078
48016
|
// node_modules/execa/lib/convert/shared.js
|
|
48079
|
-
var
|
|
48017
|
+
var import_promises12 = require("stream/promises");
|
|
48080
48018
|
var safeWaitForSubprocessStdin = async (subprocessStdin) => {
|
|
48081
48019
|
if (subprocessStdin === void 0) {
|
|
48082
48020
|
return;
|
|
@@ -48096,10 +48034,10 @@ var safeWaitForSubprocessStdout = async (subprocessStdout) => {
|
|
|
48096
48034
|
}
|
|
48097
48035
|
};
|
|
48098
48036
|
var waitForSubprocessStdin = async (subprocessStdin) => {
|
|
48099
|
-
await (0,
|
|
48037
|
+
await (0, import_promises12.finished)(subprocessStdin, { cleanup: true, readable: false, writable: true });
|
|
48100
48038
|
};
|
|
48101
48039
|
var waitForSubprocessStdout = async (subprocessStdout) => {
|
|
48102
|
-
await (0,
|
|
48040
|
+
await (0, import_promises12.finished)(subprocessStdout, { cleanup: true, readable: true, writable: false });
|
|
48103
48041
|
};
|
|
48104
48042
|
var waitForSubprocess = async (subprocess, error2) => {
|
|
48105
48043
|
await subprocess;
|
|
@@ -48648,7 +48586,7 @@ var {
|
|
|
48648
48586
|
getCancelSignal: getCancelSignal2
|
|
48649
48587
|
} = getIpcExport();
|
|
48650
48588
|
|
|
48651
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
48589
|
+
// node_modules/@remixhq/core/dist/chunk-RREREIGW.js
|
|
48652
48590
|
var GIT_REMOTE_PROTOCOL_RE = /^(https?|ssh):\/\//i;
|
|
48653
48591
|
var SCP_LIKE_GIT_REMOTE_RE = /^(?<user>[^@\s]+)@(?<host>[^:\s]+):(?<path>[^\\\s]+)$/;
|
|
48654
48592
|
var CANONICAL_GIT_REMOTE_RE = /^(?<host>(?:localhost|[a-z0-9.-]+))\/(?<path>[^\\\s]+)$/i;
|
|
@@ -48706,8 +48644,8 @@ function sanitizeRefFragment(value) {
|
|
|
48706
48644
|
return value.trim().replace(/[^A-Za-z0-9._/-]+/g, "-").replace(/\/{2,}/g, "/").replace(/^\/+|\/+$/g, "").replace(/^-+|-+$/g, "").slice(0, 120);
|
|
48707
48645
|
}
|
|
48708
48646
|
function normalizeRepoRelativePath(value) {
|
|
48709
|
-
const normalized =
|
|
48710
|
-
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)) {
|
|
48711
48649
|
throw new RemixError("Git returned an invalid repository-relative path.", {
|
|
48712
48650
|
exitCode: 1,
|
|
48713
48651
|
hint: `Path: ${value}`
|
|
@@ -48716,11 +48654,11 @@ function normalizeRepoRelativePath(value) {
|
|
|
48716
48654
|
return normalized;
|
|
48717
48655
|
}
|
|
48718
48656
|
function resolveRepoRelativePath(repoRoot, relativePath) {
|
|
48719
|
-
return
|
|
48657
|
+
return import_path2.default.resolve(repoRoot, ...relativePath.split("/"));
|
|
48720
48658
|
}
|
|
48721
48659
|
function isWithinRepoRoot(repoRoot, targetPath) {
|
|
48722
|
-
const relative =
|
|
48723
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
48660
|
+
const relative = import_path2.default.relative(repoRoot, targetPath);
|
|
48661
|
+
return relative === "" || !relative.startsWith("..") && !import_path2.default.isAbsolute(relative);
|
|
48724
48662
|
}
|
|
48725
48663
|
function sha256Hex(value) {
|
|
48726
48664
|
return (0, import_crypto.createHash)("sha256").update(value).digest("hex");
|
|
@@ -48730,7 +48668,7 @@ function resolveGitReportedPath(cwd, reportedPath) {
|
|
|
48730
48668
|
if (!value) {
|
|
48731
48669
|
throw new RemixError("Git returned an empty internal path.", { exitCode: 1 });
|
|
48732
48670
|
}
|
|
48733
|
-
return
|
|
48671
|
+
return import_path2.default.isAbsolute(value) ? value : import_path2.default.resolve(cwd, value);
|
|
48734
48672
|
}
|
|
48735
48673
|
function parseGitNameStatusZ(stdout) {
|
|
48736
48674
|
const tokens = stdout.split("\0");
|
|
@@ -48801,12 +48739,12 @@ function classifyGitApplyFailure(detail) {
|
|
|
48801
48739
|
return "unknown";
|
|
48802
48740
|
}
|
|
48803
48741
|
async function pruneEmptyParentDirectories(repoRoot, filePath) {
|
|
48804
|
-
let current =
|
|
48742
|
+
let current = import_path2.default.dirname(filePath);
|
|
48805
48743
|
while (current !== repoRoot && isWithinRepoRoot(repoRoot, current)) {
|
|
48806
|
-
const entries = await
|
|
48744
|
+
const entries = await import_promises13.default.readdir(current).catch(() => null);
|
|
48807
48745
|
if (!entries || entries.length > 0) return;
|
|
48808
|
-
await
|
|
48809
|
-
current =
|
|
48746
|
+
await import_promises13.default.rmdir(current).catch(() => void 0);
|
|
48747
|
+
current = import_path2.default.dirname(current);
|
|
48810
48748
|
}
|
|
48811
48749
|
}
|
|
48812
48750
|
async function findGitRoot(startDir) {
|
|
@@ -48908,8 +48846,8 @@ async function getWorkspaceSnapshot(cwd) {
|
|
|
48908
48846
|
throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
|
|
48909
48847
|
}
|
|
48910
48848
|
const includedUntrackedPaths = Array.from(new Set((await listUntrackedFiles(cwd)).map((entry) => normalizeRepoRelativePath(entry))));
|
|
48911
|
-
const tempDir = await
|
|
48912
|
-
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");
|
|
48913
48851
|
const env = { ...process.env, GIT_INDEX_FILE: tempIndexPath };
|
|
48914
48852
|
try {
|
|
48915
48853
|
try {
|
|
@@ -48932,14 +48870,14 @@ async function getWorkspaceSnapshot(cwd) {
|
|
|
48932
48870
|
});
|
|
48933
48871
|
}
|
|
48934
48872
|
} finally {
|
|
48935
|
-
await
|
|
48873
|
+
await import_promises13.default.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
|
|
48936
48874
|
}
|
|
48937
48875
|
}
|
|
48938
48876
|
async function writeTempUnifiedDiffBackup(diff, prefix = "remix-add-backup") {
|
|
48939
48877
|
const safePrefix = prefix.replace(/[^a-zA-Z0-9._-]+/g, "-") || "remix-add-backup";
|
|
48940
|
-
const tmpDir = await
|
|
48941
|
-
const backupPath =
|
|
48942
|
-
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");
|
|
48943
48881
|
return { backupPath, diffSha256: sha256Hex(diff) };
|
|
48944
48882
|
}
|
|
48945
48883
|
async function validateUnifiedDiff(cwd, diff) {
|
|
@@ -48956,7 +48894,7 @@ async function validateUnifiedDiff(cwd, diff) {
|
|
|
48956
48894
|
detail
|
|
48957
48895
|
};
|
|
48958
48896
|
} finally {
|
|
48959
|
-
await
|
|
48897
|
+
await import_promises13.default.rm(import_path2.default.dirname(backupPath), { recursive: true, force: true }).catch(() => void 0);
|
|
48960
48898
|
}
|
|
48961
48899
|
}
|
|
48962
48900
|
async function preserveWorkspaceChanges(cwd, prefix = "remix-add-preserve") {
|
|
@@ -48976,7 +48914,7 @@ async function preserveWorkspaceChanges(cwd, prefix = "remix-add-preserve") {
|
|
|
48976
48914
|
}
|
|
48977
48915
|
async function reapplyPreservedWorkspaceChanges(cwd, preserved, operation = "`remix collab add`") {
|
|
48978
48916
|
const patchFilePath = preserved.preservedDiffPath;
|
|
48979
|
-
const tempPatchHash = await
|
|
48917
|
+
const tempPatchHash = await import_promises13.default.readFile(patchFilePath, "utf8").then((content) => sha256Hex(content)).catch(() => null);
|
|
48980
48918
|
if (!tempPatchHash) {
|
|
48981
48919
|
return { status: "failed", detail: "Preserved diff artifact is missing." };
|
|
48982
48920
|
}
|
|
@@ -49016,8 +48954,8 @@ async function createGitBundle(cwd, bundleName = "repository.bundle") {
|
|
|
49016
48954
|
throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
|
|
49017
48955
|
}
|
|
49018
48956
|
const safeName = bundleName.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
49019
|
-
const tmpDir = await
|
|
49020
|
-
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);
|
|
49021
48959
|
const res = await runGitDetailed(["bundle", "create", bundlePath, "--all"], cwd);
|
|
49022
48960
|
if (res.exitCode !== 0) {
|
|
49023
48961
|
const detail = [res.stderr.trim(), res.stdout.trim()].filter(Boolean).join("\n\n");
|
|
@@ -49126,7 +49064,7 @@ async function discardCapturedUntrackedChanges(repoRoot, capturedPaths) {
|
|
|
49126
49064
|
hint: `Path: ${relativePath}`
|
|
49127
49065
|
});
|
|
49128
49066
|
}
|
|
49129
|
-
await
|
|
49067
|
+
await import_promises13.default.rm(absolutePath, { recursive: true, force: true }).catch((err) => {
|
|
49130
49068
|
throw new RemixError("Failed to remove a captured untracked path before syncing.", {
|
|
49131
49069
|
exitCode: 1,
|
|
49132
49070
|
hint: err instanceof Error ? `${relativePath}
|
|
@@ -49168,7 +49106,7 @@ async function importGitBundle(cwd, bundlePath, bundleRef) {
|
|
|
49168
49106
|
}
|
|
49169
49107
|
}
|
|
49170
49108
|
async function cloneGitBundleToDirectory(bundlePath, targetDir) {
|
|
49171
|
-
const parentDir =
|
|
49109
|
+
const parentDir = import_path2.default.dirname(targetDir);
|
|
49172
49110
|
const cloneRes = await runGitDetailed(["clone", bundlePath, targetDir], parentDir);
|
|
49173
49111
|
if (cloneRes.exitCode !== 0) {
|
|
49174
49112
|
const detail = [cloneRes.stderr.trim(), cloneRes.stdout.trim()].filter(Boolean).join("\n\n");
|
|
@@ -49188,10 +49126,10 @@ async function cloneGitBundleToDirectory(bundlePath, targetDir) {
|
|
|
49188
49126
|
}
|
|
49189
49127
|
async function ensureGitInfoExcludeEntries(cwd, entries) {
|
|
49190
49128
|
const excludePath = await getGitPath(cwd, "info/exclude");
|
|
49191
|
-
await
|
|
49129
|
+
await import_promises13.default.mkdir(import_path2.default.dirname(excludePath), { recursive: true });
|
|
49192
49130
|
let current = "";
|
|
49193
49131
|
try {
|
|
49194
|
-
current = await
|
|
49132
|
+
current = await import_promises13.default.readFile(excludePath, "utf8");
|
|
49195
49133
|
} catch {
|
|
49196
49134
|
}
|
|
49197
49135
|
const lines = new Set(current.split("\n").map((line) => line.trim()).filter(Boolean));
|
|
@@ -49203,7 +49141,7 @@ async function ensureGitInfoExcludeEntries(cwd, entries) {
|
|
|
49203
49141
|
changed = true;
|
|
49204
49142
|
}
|
|
49205
49143
|
if (!changed) return;
|
|
49206
|
-
await
|
|
49144
|
+
await import_promises13.default.writeFile(excludePath, `${Array.from(lines).join("\n")}
|
|
49207
49145
|
`, "utf8");
|
|
49208
49146
|
}
|
|
49209
49147
|
async function ensureCommitExists(cwd, commitHash) {
|
|
@@ -49264,7 +49202,7 @@ async function hardResetToCommit(cwd, commitHash, operation = "`remix collab rec
|
|
|
49264
49202
|
async function buildRepoFingerprint(params) {
|
|
49265
49203
|
const remote = normalizeGitRemote(params.remoteUrl);
|
|
49266
49204
|
const defaultBranch = params.defaultBranch?.trim().toLowerCase() || "";
|
|
49267
|
-
const payload = remote ? { remote, defaultBranch } : { local:
|
|
49205
|
+
const payload = remote ? { remote, defaultBranch } : { local: import_path2.default.resolve(params.gitRoot).toLowerCase(), defaultBranch };
|
|
49268
49206
|
return (0, import_crypto.createHash)("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
49269
49207
|
}
|
|
49270
49208
|
function summarizeUnifiedDiff(diff) {
|
|
@@ -49280,6 +49218,268 @@ function summarizeUnifiedDiff(diff) {
|
|
|
49280
49218
|
return { changedFilesCount, insertions, deletions };
|
|
49281
49219
|
}
|
|
49282
49220
|
|
|
49221
|
+
// node_modules/@remixhq/core/dist/chunk-4L3ZBZUQ.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
|
+
};
|
|
49277
|
+
}
|
|
49278
|
+
function normalizeBranchName(value) {
|
|
49279
|
+
const normalized = String(value ?? "").trim();
|
|
49280
|
+
return normalized || null;
|
|
49281
|
+
}
|
|
49282
|
+
function normalizeProjectId(value) {
|
|
49283
|
+
const normalized = String(value ?? "").trim();
|
|
49284
|
+
return normalized || null;
|
|
49285
|
+
}
|
|
49286
|
+
function normalizeBranchBinding(value) {
|
|
49287
|
+
if (!value?.currentAppId || !value?.upstreamAppId) return null;
|
|
49288
|
+
return {
|
|
49289
|
+
projectId: normalizeProjectId(value.projectId),
|
|
49290
|
+
currentAppId: value.currentAppId,
|
|
49291
|
+
upstreamAppId: value.upstreamAppId,
|
|
49292
|
+
threadId: value.threadId ?? null,
|
|
49293
|
+
laneId: value.laneId ?? null,
|
|
49294
|
+
bindingMode: value.bindingMode === "legacy" ? "legacy" : "lane"
|
|
49295
|
+
};
|
|
49296
|
+
}
|
|
49297
|
+
function buildResolvedBinding(params) {
|
|
49298
|
+
if (!params.binding) return null;
|
|
49299
|
+
return {
|
|
49300
|
+
schemaVersion: 3,
|
|
49301
|
+
projectId: params.binding.projectId ?? params.fallbackProjectId,
|
|
49302
|
+
currentAppId: params.binding.currentAppId,
|
|
49303
|
+
upstreamAppId: params.binding.upstreamAppId,
|
|
49304
|
+
threadId: params.binding.threadId,
|
|
49305
|
+
repoFingerprint: params.repoFingerprint,
|
|
49306
|
+
remoteUrl: params.remoteUrl,
|
|
49307
|
+
defaultBranch: params.defaultBranch,
|
|
49308
|
+
laneId: params.binding.laneId,
|
|
49309
|
+
branchName: params.branchName,
|
|
49310
|
+
bindingMode: params.binding.bindingMode
|
|
49311
|
+
};
|
|
49312
|
+
}
|
|
49313
|
+
function deriveFallbackProjectId(params) {
|
|
49314
|
+
const candidates = [
|
|
49315
|
+
params.currentBranch ? params.branchBindings[params.currentBranch]?.projectId ?? null : null,
|
|
49316
|
+
params.defaultBranch ? params.branchBindings[params.defaultBranch]?.projectId ?? null : null,
|
|
49317
|
+
...Object.values(params.branchBindings).map((binding) => binding.projectId),
|
|
49318
|
+
params.legacyProjectId
|
|
49319
|
+
];
|
|
49320
|
+
for (const candidate of candidates) {
|
|
49321
|
+
if (candidate) return candidate;
|
|
49322
|
+
}
|
|
49323
|
+
return null;
|
|
49324
|
+
}
|
|
49325
|
+
async function readCollabBindingState(repoRoot, options) {
|
|
49326
|
+
try {
|
|
49327
|
+
const persist = options?.persist === true;
|
|
49328
|
+
const filePath = getCollabBindingPath(repoRoot);
|
|
49329
|
+
const raw = await import_promises14.default.readFile(filePath, "utf8");
|
|
49330
|
+
const parsed = JSON.parse(raw);
|
|
49331
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
49332
|
+
const currentBranch = normalizeBranchName(await getCurrentBranch(repoRoot).catch(() => null));
|
|
49333
|
+
if (parsed.schemaVersion === 1) {
|
|
49334
|
+
if (!parsed.currentAppId || !parsed.upstreamAppId) return null;
|
|
49335
|
+
const projectId = normalizeProjectId(parsed.projectId);
|
|
49336
|
+
const preferredBranch = normalizeBranchName(parsed.preferredBranch ?? parsed.defaultBranch ?? null);
|
|
49337
|
+
const branchKey = preferredBranch ?? currentBranch ?? null;
|
|
49338
|
+
const branchBindings2 = branchKey ? {
|
|
49339
|
+
[branchKey]: {
|
|
49340
|
+
projectId,
|
|
49341
|
+
currentAppId: parsed.currentAppId,
|
|
49342
|
+
upstreamAppId: parsed.upstreamAppId,
|
|
49343
|
+
threadId: parsed.threadId ?? null,
|
|
49344
|
+
laneId: null,
|
|
49345
|
+
bindingMode: "legacy"
|
|
49346
|
+
}
|
|
49347
|
+
} : {};
|
|
49348
|
+
const migratedFile = buildBindingFileV3({
|
|
49349
|
+
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
49350
|
+
remoteUrl: parsed.remoteUrl ?? null,
|
|
49351
|
+
defaultBranch: parsed.defaultBranch ?? null,
|
|
49352
|
+
branchBindings: branchBindings2
|
|
49353
|
+
});
|
|
49354
|
+
if (persist) {
|
|
49355
|
+
try {
|
|
49356
|
+
await writeJsonAtomic2(filePath, migratedFile);
|
|
49357
|
+
} catch {
|
|
49358
|
+
}
|
|
49359
|
+
}
|
|
49360
|
+
return {
|
|
49361
|
+
schemaVersion: 3,
|
|
49362
|
+
projectId,
|
|
49363
|
+
repoFingerprint: migratedFile.repoFingerprint,
|
|
49364
|
+
remoteUrl: migratedFile.remoteUrl,
|
|
49365
|
+
defaultBranch: migratedFile.defaultBranch,
|
|
49366
|
+
currentBranch,
|
|
49367
|
+
branchBindings: migratedFile.branchBindings,
|
|
49368
|
+
binding: buildResolvedBinding({
|
|
49369
|
+
fallbackProjectId: projectId,
|
|
49370
|
+
repoFingerprint: migratedFile.repoFingerprint,
|
|
49371
|
+
remoteUrl: migratedFile.remoteUrl,
|
|
49372
|
+
defaultBranch: migratedFile.defaultBranch,
|
|
49373
|
+
branchName: branchKey,
|
|
49374
|
+
binding: branchKey ? migratedFile.branchBindings[branchKey] : null
|
|
49375
|
+
})
|
|
49376
|
+
};
|
|
49377
|
+
}
|
|
49378
|
+
if (parsed.schemaVersion !== 2 && parsed.schemaVersion !== 3) return null;
|
|
49379
|
+
const file = parsed;
|
|
49380
|
+
let shouldPersistNormalizedBranchBindings = false;
|
|
49381
|
+
const legacyProjectId = normalizeProjectId(file.projectId);
|
|
49382
|
+
const branchBindings = Object.fromEntries(
|
|
49383
|
+
Object.entries(file.branchBindings ?? {}).map(([branchName, branchBinding]) => {
|
|
49384
|
+
const normalized = normalizeBranchBinding(branchBinding);
|
|
49385
|
+
const rawProjectId = branchBinding && typeof branchBinding === "object" && "projectId" in branchBinding ? normalizeProjectId(branchBinding.projectId) : null;
|
|
49386
|
+
const rawBindingMode = branchBinding && typeof branchBinding === "object" && "bindingMode" in branchBinding ? branchBinding.bindingMode : null;
|
|
49387
|
+
const hasLegacyPreferredBranch = Boolean(branchBinding) && typeof branchBinding === "object" && "preferredBranch" in branchBinding;
|
|
49388
|
+
let normalizedWithProject = normalized;
|
|
49389
|
+
if (normalizedWithProject && !normalizedWithProject.projectId && legacyProjectId) {
|
|
49390
|
+
normalizedWithProject = {
|
|
49391
|
+
...normalizedWithProject,
|
|
49392
|
+
projectId: legacyProjectId
|
|
49393
|
+
};
|
|
49394
|
+
}
|
|
49395
|
+
if (normalizedWithProject && (rawBindingMode !== normalizedWithProject.bindingMode || hasLegacyPreferredBranch || rawProjectId !== normalizedWithProject.projectId)) {
|
|
49396
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49397
|
+
}
|
|
49398
|
+
return [branchName, normalizedWithProject];
|
|
49399
|
+
}).filter((entry) => Boolean(entry[1]))
|
|
49400
|
+
);
|
|
49401
|
+
const legacyExplicitBinding = normalizeBranchBinding(file.explicitBinding ?? null);
|
|
49402
|
+
const legacyExplicitBranch = currentBranch ?? normalizeBranchName(file.defaultBranch);
|
|
49403
|
+
if (legacyExplicitBinding && legacyExplicitBranch) {
|
|
49404
|
+
branchBindings[legacyExplicitBranch] = {
|
|
49405
|
+
...legacyExplicitBinding,
|
|
49406
|
+
projectId: legacyExplicitBinding.projectId ?? branchBindings[legacyExplicitBranch]?.projectId ?? legacyProjectId,
|
|
49407
|
+
bindingMode: "lane"
|
|
49408
|
+
};
|
|
49409
|
+
shouldPersistNormalizedBranchBindings = true;
|
|
49410
|
+
}
|
|
49411
|
+
if (persist && ("explicitBinding" in file || shouldPersistNormalizedBranchBindings || parsed.schemaVersion === 2)) {
|
|
49412
|
+
try {
|
|
49413
|
+
await writeJsonAtomic2(
|
|
49414
|
+
filePath,
|
|
49415
|
+
buildBindingFileV3({
|
|
49416
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49417
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49418
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49419
|
+
branchBindings
|
|
49420
|
+
})
|
|
49421
|
+
);
|
|
49422
|
+
} catch {
|
|
49423
|
+
}
|
|
49424
|
+
}
|
|
49425
|
+
const resolvedBranch = currentBranch ?? normalizeBranchName(file.defaultBranch);
|
|
49426
|
+
const fallbackProjectId = deriveFallbackProjectId({
|
|
49427
|
+
branchBindings,
|
|
49428
|
+
currentBranch: resolvedBranch,
|
|
49429
|
+
defaultBranch: normalizeBranchName(file.defaultBranch),
|
|
49430
|
+
legacyProjectId
|
|
49431
|
+
});
|
|
49432
|
+
return {
|
|
49433
|
+
schemaVersion: parsed.schemaVersion,
|
|
49434
|
+
projectId: fallbackProjectId,
|
|
49435
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49436
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49437
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49438
|
+
currentBranch,
|
|
49439
|
+
branchBindings,
|
|
49440
|
+
binding: buildResolvedBinding({
|
|
49441
|
+
fallbackProjectId,
|
|
49442
|
+
repoFingerprint: file.repoFingerprint ?? null,
|
|
49443
|
+
remoteUrl: file.remoteUrl ?? null,
|
|
49444
|
+
defaultBranch: file.defaultBranch ?? null,
|
|
49445
|
+
branchName: resolvedBranch,
|
|
49446
|
+
binding: resolvedBranch ? branchBindings[resolvedBranch] ?? null : null
|
|
49447
|
+
})
|
|
49448
|
+
};
|
|
49449
|
+
} catch {
|
|
49450
|
+
return null;
|
|
49451
|
+
}
|
|
49452
|
+
}
|
|
49453
|
+
async function readCollabBinding(repoRoot) {
|
|
49454
|
+
const state = await readCollabBindingState(repoRoot);
|
|
49455
|
+
return state?.binding ?? null;
|
|
49456
|
+
}
|
|
49457
|
+
async function writeCollabBinding(repoRoot, binding) {
|
|
49458
|
+
const filePath = getCollabBindingPath(repoRoot);
|
|
49459
|
+
const currentBranch = normalizeBranchName(await getCurrentBranch(repoRoot).catch(() => null));
|
|
49460
|
+
const branchName = normalizeBranchName(binding.branchName) ?? currentBranch ?? binding.defaultBranch ?? "main";
|
|
49461
|
+
const existing = await readCollabBindingState(repoRoot, { persist: true });
|
|
49462
|
+
const branchBindings = { ...existing?.branchBindings ?? {} };
|
|
49463
|
+
branchBindings[branchName] = {
|
|
49464
|
+
projectId: normalizeProjectId(binding.projectId) ?? branchBindings[branchName]?.projectId ?? existing?.projectId ?? null,
|
|
49465
|
+
currentAppId: binding.currentAppId,
|
|
49466
|
+
upstreamAppId: binding.upstreamAppId,
|
|
49467
|
+
threadId: binding.threadId ?? null,
|
|
49468
|
+
laneId: binding.laneId ?? null,
|
|
49469
|
+
bindingMode: binding.bindingMode ?? "lane"
|
|
49470
|
+
};
|
|
49471
|
+
await writeJsonAtomic2(
|
|
49472
|
+
filePath,
|
|
49473
|
+
buildBindingFileV3({
|
|
49474
|
+
repoFingerprint: binding.repoFingerprint ?? null,
|
|
49475
|
+
remoteUrl: binding.remoteUrl ?? null,
|
|
49476
|
+
defaultBranch: binding.defaultBranch ?? null,
|
|
49477
|
+
branchBindings
|
|
49478
|
+
})
|
|
49479
|
+
);
|
|
49480
|
+
return filePath;
|
|
49481
|
+
}
|
|
49482
|
+
|
|
49283
49483
|
// node_modules/@remixhq/core/dist/collab.js
|
|
49284
49484
|
var import_promises16 = __toESM(require("fs/promises"), 1);
|
|
49285
49485
|
var import_path5 = __toESM(require("path"), 1);
|
|
@@ -49306,29 +49506,29 @@ function describeBranch(value) {
|
|
|
49306
49506
|
const normalized = String(value ?? "").trim();
|
|
49307
49507
|
return normalized || "(detached)";
|
|
49308
49508
|
}
|
|
49309
|
-
function
|
|
49509
|
+
function isBoundBranchMatch(currentBranch, branchName) {
|
|
49310
49510
|
const current = String(currentBranch ?? "").trim();
|
|
49311
|
-
const
|
|
49312
|
-
if (!
|
|
49313
|
-
return current ===
|
|
49511
|
+
const expected = String(branchName ?? "").trim();
|
|
49512
|
+
if (!expected || !current) return true;
|
|
49513
|
+
return current === expected;
|
|
49314
49514
|
}
|
|
49315
|
-
function
|
|
49515
|
+
function buildBranchMismatchHint(params) {
|
|
49316
49516
|
const overrideFlag = params.overrideFlag?.trim() || "--allow-branch-mismatch";
|
|
49317
49517
|
return [
|
|
49318
49518
|
`Current branch: ${describeBranch(params.currentBranch)}`,
|
|
49319
|
-
`
|
|
49320
|
-
`Switch to ${describeBranch(params.
|
|
49519
|
+
`Bound branch: ${describeBranch(params.branchName)}`,
|
|
49520
|
+
`Switch to ${describeBranch(params.branchName)} or rerun with ${overrideFlag} if this is intentional.`
|
|
49321
49521
|
].join("\n");
|
|
49322
49522
|
}
|
|
49323
|
-
function
|
|
49523
|
+
function assertBoundBranchMatch(params) {
|
|
49324
49524
|
if (params.allowBranchMismatch) return;
|
|
49325
|
-
if (
|
|
49326
|
-
throw new RemixError(`Current branch does not match this checkout's Remix
|
|
49525
|
+
if (isBoundBranchMatch(params.currentBranch, params.branchName)) return;
|
|
49526
|
+
throw new RemixError(`Current branch does not match this checkout's bound Remix branch while running ${params.operation}.`, {
|
|
49327
49527
|
code: REMIX_ERROR_CODES.PREFERRED_BRANCH_MISMATCH,
|
|
49328
49528
|
exitCode: 2,
|
|
49329
|
-
hint:
|
|
49529
|
+
hint: buildBranchMismatchHint({
|
|
49330
49530
|
currentBranch: params.currentBranch,
|
|
49331
|
-
|
|
49531
|
+
branchName: params.branchName,
|
|
49332
49532
|
overrideFlag: params.overrideFlag
|
|
49333
49533
|
})
|
|
49334
49534
|
});
|
|
@@ -49389,6 +49589,52 @@ function sanitizeCheckoutDirName(value) {
|
|
|
49389
49589
|
function buildDashboardAppUrl(appId) {
|
|
49390
49590
|
return `https://dashboard.remix.one/apps/${encodeURIComponent(appId)}`;
|
|
49391
49591
|
}
|
|
49592
|
+
async function resolveProjectLaneIfAuthoritative(api, params) {
|
|
49593
|
+
const branchName = String(params.branchName ?? "").trim();
|
|
49594
|
+
if (!branchName) return null;
|
|
49595
|
+
if (!params.projectId && !params.repoFingerprint && !params.remoteUrl) return null;
|
|
49596
|
+
const readLane = async () => {
|
|
49597
|
+
const laneResp = await api.resolveProjectLaneBinding({
|
|
49598
|
+
projectId: params.projectId ?? void 0,
|
|
49599
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49600
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49601
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49602
|
+
branchName
|
|
49603
|
+
});
|
|
49604
|
+
return unwrapResponseObject(laneResp, "project lane binding");
|
|
49605
|
+
};
|
|
49606
|
+
let lane = await readLane();
|
|
49607
|
+
const shouldRepairResolvedLane = lane.status === "resolved" && Boolean(
|
|
49608
|
+
params.expectedUpstreamAppId && (!lane.upstreamAppId || lane.upstreamAppId !== params.expectedUpstreamAppId)
|
|
49609
|
+
);
|
|
49610
|
+
if (shouldRepairResolvedLane && params.createIfMissing && params.seedAppId) {
|
|
49611
|
+
const ensuredResp = await api.ensureProjectLaneBinding({
|
|
49612
|
+
projectId: params.projectId ?? void 0,
|
|
49613
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49614
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49615
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49616
|
+
branchName,
|
|
49617
|
+
seedAppId: params.seedAppId
|
|
49618
|
+
});
|
|
49619
|
+
lane = unwrapResponseObject(ensuredResp, "project lane binding");
|
|
49620
|
+
}
|
|
49621
|
+
if (lane.status !== "resolved" && params.createIfMissing && params.seedAppId) {
|
|
49622
|
+
const ensuredResp = await api.ensureProjectLaneBinding({
|
|
49623
|
+
projectId: params.projectId ?? void 0,
|
|
49624
|
+
repoFingerprint: params.repoFingerprint ?? void 0,
|
|
49625
|
+
remoteUrl: params.remoteUrl ?? void 0,
|
|
49626
|
+
defaultBranch: params.defaultBranch ?? void 0,
|
|
49627
|
+
branchName,
|
|
49628
|
+
seedAppId: params.seedAppId
|
|
49629
|
+
});
|
|
49630
|
+
lane = unwrapResponseObject(ensuredResp, "project lane binding");
|
|
49631
|
+
}
|
|
49632
|
+
if (lane.status !== "resolved") return null;
|
|
49633
|
+
if (params.projectId && lane.projectId && lane.projectId !== params.projectId) return null;
|
|
49634
|
+
if (params.currentAppId && lane.currentAppId && lane.currentAppId !== params.currentAppId) return null;
|
|
49635
|
+
if (params.expectedUpstreamAppId && lane.upstreamAppId && lane.upstreamAppId !== params.expectedUpstreamAppId) return null;
|
|
49636
|
+
return lane;
|
|
49637
|
+
}
|
|
49392
49638
|
async function pollAppReady(api, appId) {
|
|
49393
49639
|
const started = Date.now();
|
|
49394
49640
|
let delay = 2e3;
|
|
@@ -49532,6 +49778,273 @@ async function pollMergeRequestCompletion(api, mrId, params) {
|
|
|
49532
49778
|
}
|
|
49533
49779
|
throw new RemixError("Timed out waiting for merge approval to complete.", { exitCode: 1 });
|
|
49534
49780
|
}
|
|
49781
|
+
function normalizeBranchName2(value) {
|
|
49782
|
+
const normalized = String(value ?? "").trim();
|
|
49783
|
+
return normalized || null;
|
|
49784
|
+
}
|
|
49785
|
+
function buildBindingFromLane(state, lane) {
|
|
49786
|
+
if (!lane.currentAppId || !lane.upstreamAppId) return null;
|
|
49787
|
+
return {
|
|
49788
|
+
schemaVersion: 3,
|
|
49789
|
+
projectId: lane.projectId ?? state.projectId,
|
|
49790
|
+
currentAppId: lane.currentAppId,
|
|
49791
|
+
upstreamAppId: lane.upstreamAppId,
|
|
49792
|
+
threadId: lane.threadId ?? null,
|
|
49793
|
+
repoFingerprint: lane.repoFingerprint ?? state.repoFingerprint ?? null,
|
|
49794
|
+
remoteUrl: lane.remoteUrl ?? state.remoteUrl ?? null,
|
|
49795
|
+
defaultBranch: lane.defaultBranch ?? state.defaultBranch ?? null,
|
|
49796
|
+
laneId: lane.laneId ?? null,
|
|
49797
|
+
branchName: lane.branchName ?? state.currentBranch ?? null,
|
|
49798
|
+
bindingMode: "lane"
|
|
49799
|
+
};
|
|
49800
|
+
}
|
|
49801
|
+
function shouldPersistRemoteLaneMetadata(localBinding, lane) {
|
|
49802
|
+
return Boolean(
|
|
49803
|
+
!localBinding.laneId && lane.laneId || !localBinding.threadId && lane.threadId || !localBinding.repoFingerprint && lane.repoFingerprint || !localBinding.remoteUrl && lane.remoteUrl || !localBinding.defaultBranch && lane.defaultBranch || !localBinding.branchName && lane.branchName
|
|
49804
|
+
);
|
|
49805
|
+
}
|
|
49806
|
+
function shouldRequireRemoteLaneForCurrentBranch(params) {
|
|
49807
|
+
if (!params.currentBranch) return false;
|
|
49808
|
+
const defaultBranch = normalizeBranchName2(params.defaultBranch);
|
|
49809
|
+
if (params.currentBranch === defaultBranch) return false;
|
|
49810
|
+
return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
|
|
49811
|
+
}
|
|
49812
|
+
async function persistResolvedLane(repoRoot, binding) {
|
|
49813
|
+
await writeCollabBinding(repoRoot, {
|
|
49814
|
+
projectId: binding.projectId,
|
|
49815
|
+
currentAppId: binding.currentAppId,
|
|
49816
|
+
upstreamAppId: binding.upstreamAppId,
|
|
49817
|
+
threadId: binding.threadId,
|
|
49818
|
+
repoFingerprint: binding.repoFingerprint,
|
|
49819
|
+
remoteUrl: binding.remoteUrl,
|
|
49820
|
+
defaultBranch: binding.defaultBranch,
|
|
49821
|
+
laneId: binding.laneId,
|
|
49822
|
+
branchName: binding.branchName,
|
|
49823
|
+
bindingMode: binding.bindingMode
|
|
49824
|
+
});
|
|
49825
|
+
return readCollabBinding(repoRoot);
|
|
49826
|
+
}
|
|
49827
|
+
async function resolveActiveLaneBinding(params) {
|
|
49828
|
+
const state = await readCollabBindingState(params.repoRoot);
|
|
49829
|
+
if (!state) {
|
|
49830
|
+
return { status: "not_bound", currentBranch: null };
|
|
49831
|
+
}
|
|
49832
|
+
const currentBranch = normalizeBranchName2(state.currentBranch);
|
|
49833
|
+
const localBinding = state.binding;
|
|
49834
|
+
if (localBinding) {
|
|
49835
|
+
const requireRemoteLane = shouldRequireRemoteLaneForCurrentBranch({
|
|
49836
|
+
binding: localBinding,
|
|
49837
|
+
currentBranch,
|
|
49838
|
+
defaultBranch: state.defaultBranch
|
|
49839
|
+
});
|
|
49840
|
+
if (!params.api || !currentBranch) {
|
|
49841
|
+
return {
|
|
49842
|
+
status: "resolved",
|
|
49843
|
+
source: "local",
|
|
49844
|
+
binding: localBinding,
|
|
49845
|
+
currentBranch
|
|
49846
|
+
};
|
|
49847
|
+
}
|
|
49848
|
+
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
49849
|
+
projectId: localBinding.projectId ?? state.projectId ?? void 0,
|
|
49850
|
+
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
49851
|
+
remoteUrl: state.remoteUrl ?? void 0,
|
|
49852
|
+
defaultBranch: state.defaultBranch ?? void 0,
|
|
49853
|
+
branchName: currentBranch
|
|
49854
|
+
});
|
|
49855
|
+
const lane2 = unwrapResponseObject(laneResp2, "project lane binding");
|
|
49856
|
+
if (lane2.status === "resolved") {
|
|
49857
|
+
const resolvedBranch = normalizeBranchName2(lane2.branchName);
|
|
49858
|
+
const resolvedProjectId = lane2.projectId ?? state.projectId;
|
|
49859
|
+
const branchConflict = Boolean(resolvedBranch && localBinding.branchName && resolvedBranch !== localBinding.branchName);
|
|
49860
|
+
const appConflict = Boolean(lane2.currentAppId && lane2.currentAppId !== localBinding.currentAppId);
|
|
49861
|
+
const upstreamConflict = Boolean(lane2.upstreamAppId && lane2.upstreamAppId !== localBinding.upstreamAppId);
|
|
49862
|
+
const projectConflict = Boolean(resolvedProjectId && localBinding.projectId && resolvedProjectId !== localBinding.projectId);
|
|
49863
|
+
if (branchConflict || appConflict || upstreamConflict || projectConflict) {
|
|
49864
|
+
if (requireRemoteLane) {
|
|
49865
|
+
const binding = buildBindingFromLane(state, lane2);
|
|
49866
|
+
if (binding) {
|
|
49867
|
+
return {
|
|
49868
|
+
status: "resolved",
|
|
49869
|
+
source: "remote",
|
|
49870
|
+
binding,
|
|
49871
|
+
currentBranch
|
|
49872
|
+
};
|
|
49873
|
+
}
|
|
49874
|
+
}
|
|
49875
|
+
return {
|
|
49876
|
+
status: "binding_conflict",
|
|
49877
|
+
binding: localBinding,
|
|
49878
|
+
resolvedLane: lane2,
|
|
49879
|
+
currentBranch
|
|
49880
|
+
};
|
|
49881
|
+
}
|
|
49882
|
+
if (shouldPersistRemoteLaneMetadata(localBinding, lane2)) {
|
|
49883
|
+
const binding = buildBindingFromLane(state, lane2);
|
|
49884
|
+
if (binding) {
|
|
49885
|
+
return {
|
|
49886
|
+
status: "resolved",
|
|
49887
|
+
source: "remote",
|
|
49888
|
+
binding,
|
|
49889
|
+
currentBranch
|
|
49890
|
+
};
|
|
49891
|
+
}
|
|
49892
|
+
}
|
|
49893
|
+
}
|
|
49894
|
+
if (requireRemoteLane) {
|
|
49895
|
+
return {
|
|
49896
|
+
status: "missing_branch_binding",
|
|
49897
|
+
currentBranch,
|
|
49898
|
+
projectId: state.projectId,
|
|
49899
|
+
repoFingerprint: state.repoFingerprint,
|
|
49900
|
+
remoteUrl: state.remoteUrl,
|
|
49901
|
+
defaultBranch: state.defaultBranch,
|
|
49902
|
+
upstreamAppId: localBinding.upstreamAppId ?? null,
|
|
49903
|
+
threadId: localBinding.threadId ?? null
|
|
49904
|
+
};
|
|
49905
|
+
}
|
|
49906
|
+
return {
|
|
49907
|
+
status: "resolved",
|
|
49908
|
+
source: "local",
|
|
49909
|
+
binding: localBinding,
|
|
49910
|
+
currentBranch
|
|
49911
|
+
};
|
|
49912
|
+
}
|
|
49913
|
+
if (!params.api || !currentBranch) {
|
|
49914
|
+
return {
|
|
49915
|
+
status: "missing_branch_binding",
|
|
49916
|
+
currentBranch,
|
|
49917
|
+
projectId: state.projectId,
|
|
49918
|
+
repoFingerprint: state.repoFingerprint,
|
|
49919
|
+
remoteUrl: state.remoteUrl,
|
|
49920
|
+
defaultBranch: state.defaultBranch,
|
|
49921
|
+
upstreamAppId: null,
|
|
49922
|
+
threadId: null
|
|
49923
|
+
};
|
|
49924
|
+
}
|
|
49925
|
+
const laneResp = await params.api.resolveProjectLaneBinding({
|
|
49926
|
+
projectId: state.projectId ?? void 0,
|
|
49927
|
+
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
49928
|
+
remoteUrl: state.remoteUrl ?? void 0,
|
|
49929
|
+
defaultBranch: state.defaultBranch ?? void 0,
|
|
49930
|
+
branchName: currentBranch
|
|
49931
|
+
});
|
|
49932
|
+
const lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
49933
|
+
if (lane.status === "resolved") {
|
|
49934
|
+
const binding = buildBindingFromLane(state, lane);
|
|
49935
|
+
if (binding) {
|
|
49936
|
+
return {
|
|
49937
|
+
status: "resolved",
|
|
49938
|
+
source: "remote",
|
|
49939
|
+
binding,
|
|
49940
|
+
currentBranch
|
|
49941
|
+
};
|
|
49942
|
+
}
|
|
49943
|
+
}
|
|
49944
|
+
if (lane.status === "binding_not_found") {
|
|
49945
|
+
return { status: "not_bound", currentBranch };
|
|
49946
|
+
}
|
|
49947
|
+
return {
|
|
49948
|
+
status: "missing_branch_binding",
|
|
49949
|
+
currentBranch,
|
|
49950
|
+
projectId: lane.projectId ?? state.projectId,
|
|
49951
|
+
repoFingerprint: lane.repoFingerprint ?? state.repoFingerprint,
|
|
49952
|
+
remoteUrl: lane.remoteUrl ?? state.remoteUrl,
|
|
49953
|
+
defaultBranch: lane.defaultBranch ?? state.defaultBranch,
|
|
49954
|
+
upstreamAppId: lane.upstreamAppId ?? null,
|
|
49955
|
+
threadId: lane.threadId ?? null
|
|
49956
|
+
};
|
|
49957
|
+
}
|
|
49958
|
+
async function ensureActiveLaneBinding(params) {
|
|
49959
|
+
const resolved = await resolveActiveLaneBinding({
|
|
49960
|
+
repoRoot: params.repoRoot,
|
|
49961
|
+
api: params.api
|
|
49962
|
+
});
|
|
49963
|
+
if (resolved.status === "resolved") {
|
|
49964
|
+
if (resolved.source === "local") {
|
|
49965
|
+
return resolved.binding;
|
|
49966
|
+
}
|
|
49967
|
+
return persistResolvedLane(params.repoRoot, resolved.binding);
|
|
49968
|
+
}
|
|
49969
|
+
if (resolved.status === "binding_conflict") {
|
|
49970
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
49971
|
+
exitCode: 2,
|
|
49972
|
+
hint: `Local app ${resolved.binding.currentAppId}; server app ${resolved.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before running ${params.operation ?? "this command"}.`
|
|
49973
|
+
});
|
|
49974
|
+
}
|
|
49975
|
+
if (resolved.status === "not_bound") {
|
|
49976
|
+
return null;
|
|
49977
|
+
}
|
|
49978
|
+
if (!resolved.currentBranch) {
|
|
49979
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
49980
|
+
exitCode: 2,
|
|
49981
|
+
hint: `Switch to a named branch before running ${params.operation ?? "this command"}.`
|
|
49982
|
+
});
|
|
49983
|
+
}
|
|
49984
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
49985
|
+
exitCode: 2,
|
|
49986
|
+
hint: `Run \`remix collab init\` on branch ${resolved.currentBranch} before running ${params.operation ?? "this command"}.`
|
|
49987
|
+
});
|
|
49988
|
+
}
|
|
49989
|
+
async function provisionActiveLaneBinding(params) {
|
|
49990
|
+
const resolved = await resolveActiveLaneBinding(params);
|
|
49991
|
+
if (resolved.status === "resolved") {
|
|
49992
|
+
if (resolved.source === "local") {
|
|
49993
|
+
return { binding: resolved.binding, warnings: [] };
|
|
49994
|
+
}
|
|
49995
|
+
const persisted2 = await persistResolvedLane(params.repoRoot, resolved.binding);
|
|
49996
|
+
return { binding: persisted2, warnings: [] };
|
|
49997
|
+
}
|
|
49998
|
+
if (resolved.status === "binding_conflict") {
|
|
49999
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
50000
|
+
exitCode: 2,
|
|
50001
|
+
hint: `Local app ${resolved.binding.currentAppId}; server app ${resolved.resolvedLane.currentAppId ?? "(unknown)"}. Repair the branch binding before running ${params.operation}.`
|
|
50002
|
+
});
|
|
50003
|
+
}
|
|
50004
|
+
if (resolved.status === "not_bound") {
|
|
50005
|
+
return { binding: null, warnings: [] };
|
|
50006
|
+
}
|
|
50007
|
+
if (!resolved.currentBranch) {
|
|
50008
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50009
|
+
exitCode: 2,
|
|
50010
|
+
hint: `Switch to a named branch before running ${params.operation}.`
|
|
50011
|
+
});
|
|
50012
|
+
}
|
|
50013
|
+
let lane;
|
|
50014
|
+
try {
|
|
50015
|
+
const laneResp = await params.api.ensureProjectLaneBinding({
|
|
50016
|
+
projectId: resolved.projectId ?? void 0,
|
|
50017
|
+
repoFingerprint: resolved.repoFingerprint ?? void 0,
|
|
50018
|
+
remoteUrl: resolved.remoteUrl ?? void 0,
|
|
50019
|
+
defaultBranch: resolved.defaultBranch ?? void 0,
|
|
50020
|
+
branchName: resolved.currentBranch
|
|
50021
|
+
});
|
|
50022
|
+
lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
50023
|
+
} catch (error2) {
|
|
50024
|
+
throw new RemixError(`Failed to provision a Remix lane for branch ${resolved.currentBranch}.`, {
|
|
50025
|
+
exitCode: error2 instanceof RemixError ? error2.exitCode : 1,
|
|
50026
|
+
hint: formatCliErrorDetail(error2) || `Remix could not create or recover the branch lane required before ${params.operation}.`
|
|
50027
|
+
});
|
|
50028
|
+
}
|
|
50029
|
+
const state = await readCollabBindingState(params.repoRoot);
|
|
50030
|
+
if (!state) {
|
|
50031
|
+
return { binding: null, warnings: [] };
|
|
50032
|
+
}
|
|
50033
|
+
const binding = buildBindingFromLane(state, lane);
|
|
50034
|
+
if (!binding) {
|
|
50035
|
+
throw new RemixError(`Failed to provision a Remix lane for branch ${resolved.currentBranch}.`, {
|
|
50036
|
+
exitCode: 1,
|
|
50037
|
+
hint: "The server returned incomplete lane binding metadata."
|
|
50038
|
+
});
|
|
50039
|
+
}
|
|
50040
|
+
const persisted = await persistResolvedLane(params.repoRoot, binding);
|
|
50041
|
+
return {
|
|
50042
|
+
binding: persisted,
|
|
50043
|
+
warnings: [
|
|
50044
|
+
lane.created ? `Provisioned Remix lane for branch ${resolved.currentBranch}.` : `Recovered existing Remix lane binding for branch ${resolved.currentBranch}.`
|
|
50045
|
+
]
|
|
50046
|
+
};
|
|
50047
|
+
}
|
|
49535
50048
|
async function collabRecordingPreflight(params) {
|
|
49536
50049
|
let repoRoot;
|
|
49537
50050
|
try {
|
|
@@ -49543,7 +50056,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49543
50056
|
repoRoot: null,
|
|
49544
50057
|
appId: null,
|
|
49545
50058
|
currentBranch: null,
|
|
49546
|
-
|
|
50059
|
+
branchName: null,
|
|
49547
50060
|
headCommitHash: null,
|
|
49548
50061
|
worktreeClean: false,
|
|
49549
50062
|
syncStatus: null,
|
|
@@ -49555,14 +50068,14 @@ async function collabRecordingPreflight(params) {
|
|
|
49555
50068
|
hint: message
|
|
49556
50069
|
};
|
|
49557
50070
|
}
|
|
49558
|
-
const
|
|
49559
|
-
if (
|
|
50071
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot, api: params.api });
|
|
50072
|
+
if (bindingResolution.status === "not_bound") {
|
|
49560
50073
|
return {
|
|
49561
50074
|
status: "not_bound",
|
|
49562
50075
|
repoRoot,
|
|
49563
50076
|
appId: null,
|
|
49564
50077
|
currentBranch: null,
|
|
49565
|
-
|
|
50078
|
+
branchName: null,
|
|
49566
50079
|
headCommitHash: null,
|
|
49567
50080
|
worktreeClean: false,
|
|
49568
50081
|
syncStatus: null,
|
|
@@ -49574,19 +50087,56 @@ async function collabRecordingPreflight(params) {
|
|
|
49574
50087
|
hint: "Run `remix collab init` first."
|
|
49575
50088
|
};
|
|
49576
50089
|
}
|
|
50090
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
50091
|
+
return {
|
|
50092
|
+
status: "branch_binding_missing",
|
|
50093
|
+
repoRoot,
|
|
50094
|
+
appId: null,
|
|
50095
|
+
currentBranch: bindingResolution.currentBranch,
|
|
50096
|
+
branchName: bindingResolution.currentBranch,
|
|
50097
|
+
headCommitHash: null,
|
|
50098
|
+
worktreeClean: false,
|
|
50099
|
+
syncStatus: null,
|
|
50100
|
+
syncTargetCommitHash: null,
|
|
50101
|
+
syncTargetCommitId: null,
|
|
50102
|
+
reconcileTargetHeadCommitHash: null,
|
|
50103
|
+
reconcileTargetHeadCommitId: null,
|
|
50104
|
+
warnings: [],
|
|
50105
|
+
hint: `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`
|
|
50106
|
+
};
|
|
50107
|
+
}
|
|
50108
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
50109
|
+
return {
|
|
50110
|
+
status: "metadata_conflict",
|
|
50111
|
+
repoRoot,
|
|
50112
|
+
appId: bindingResolution.binding.currentAppId,
|
|
50113
|
+
currentBranch: bindingResolution.currentBranch,
|
|
50114
|
+
branchName: bindingResolution.binding.branchName,
|
|
50115
|
+
headCommitHash: null,
|
|
50116
|
+
worktreeClean: false,
|
|
50117
|
+
syncStatus: null,
|
|
50118
|
+
syncTargetCommitHash: null,
|
|
50119
|
+
syncTargetCommitId: null,
|
|
50120
|
+
reconcileTargetHeadCommitHash: null,
|
|
50121
|
+
reconcileTargetHeadCommitId: null,
|
|
50122
|
+
warnings: [],
|
|
50123
|
+
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.`
|
|
50124
|
+
};
|
|
50125
|
+
}
|
|
50126
|
+
const binding = bindingResolution.binding;
|
|
49577
50127
|
const [currentBranch, headCommitHash, worktreeStatus] = await Promise.all([
|
|
49578
50128
|
getCurrentBranch(repoRoot),
|
|
49579
50129
|
getHeadCommitHash(repoRoot),
|
|
49580
50130
|
getWorktreeStatus(repoRoot)
|
|
49581
50131
|
]);
|
|
49582
|
-
const
|
|
50132
|
+
const branchName = binding.branchName ?? null;
|
|
49583
50133
|
if (!headCommitHash) {
|
|
49584
50134
|
return {
|
|
49585
50135
|
status: "missing_head",
|
|
49586
50136
|
repoRoot,
|
|
49587
50137
|
appId: binding.currentAppId,
|
|
49588
50138
|
currentBranch,
|
|
49589
|
-
|
|
50139
|
+
branchName,
|
|
49590
50140
|
headCommitHash: null,
|
|
49591
50141
|
worktreeClean: worktreeStatus.isClean,
|
|
49592
50142
|
syncStatus: null,
|
|
@@ -49598,13 +50148,13 @@ async function collabRecordingPreflight(params) {
|
|
|
49598
50148
|
hint: "Failed to resolve local HEAD commit."
|
|
49599
50149
|
};
|
|
49600
50150
|
}
|
|
49601
|
-
if (!params.allowBranchMismatch && !
|
|
50151
|
+
if (!params.allowBranchMismatch && !isBoundBranchMatch(currentBranch, branchName)) {
|
|
49602
50152
|
return {
|
|
49603
50153
|
status: "branch_mismatch",
|
|
49604
50154
|
repoRoot,
|
|
49605
50155
|
appId: binding.currentAppId,
|
|
49606
50156
|
currentBranch,
|
|
49607
|
-
|
|
50157
|
+
branchName,
|
|
49608
50158
|
headCommitHash,
|
|
49609
50159
|
worktreeClean: worktreeStatus.isClean,
|
|
49610
50160
|
syncStatus: null,
|
|
@@ -49613,9 +50163,9 @@ async function collabRecordingPreflight(params) {
|
|
|
49613
50163
|
reconcileTargetHeadCommitHash: null,
|
|
49614
50164
|
reconcileTargetHeadCommitId: null,
|
|
49615
50165
|
warnings: [],
|
|
49616
|
-
hint:
|
|
50166
|
+
hint: buildBranchMismatchHint({
|
|
49617
50167
|
currentBranch,
|
|
49618
|
-
|
|
50168
|
+
branchName
|
|
49619
50169
|
})
|
|
49620
50170
|
};
|
|
49621
50171
|
}
|
|
@@ -49633,7 +50183,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49633
50183
|
repoRoot,
|
|
49634
50184
|
appId: binding.currentAppId,
|
|
49635
50185
|
currentBranch,
|
|
49636
|
-
|
|
50186
|
+
branchName,
|
|
49637
50187
|
headCommitHash,
|
|
49638
50188
|
worktreeClean: worktreeStatus.isClean,
|
|
49639
50189
|
syncStatus: sync.status,
|
|
@@ -49651,7 +50201,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49651
50201
|
repoRoot,
|
|
49652
50202
|
appId: binding.currentAppId,
|
|
49653
50203
|
currentBranch,
|
|
49654
|
-
|
|
50204
|
+
branchName,
|
|
49655
50205
|
headCommitHash,
|
|
49656
50206
|
worktreeClean: worktreeStatus.isClean,
|
|
49657
50207
|
syncStatus: sync.status,
|
|
@@ -49676,7 +50226,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49676
50226
|
repoRoot,
|
|
49677
50227
|
appId: binding.currentAppId,
|
|
49678
50228
|
currentBranch,
|
|
49679
|
-
|
|
50229
|
+
branchName,
|
|
49680
50230
|
headCommitHash,
|
|
49681
50231
|
worktreeClean: worktreeStatus.isClean,
|
|
49682
50232
|
syncStatus: sync.status,
|
|
@@ -49694,7 +50244,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49694
50244
|
repoRoot,
|
|
49695
50245
|
appId: binding.currentAppId,
|
|
49696
50246
|
currentBranch,
|
|
49697
|
-
|
|
50247
|
+
branchName,
|
|
49698
50248
|
headCommitHash,
|
|
49699
50249
|
worktreeClean: worktreeStatus.isClean,
|
|
49700
50250
|
syncStatus: sync.status,
|
|
@@ -49711,7 +50261,7 @@ async function collabRecordingPreflight(params) {
|
|
|
49711
50261
|
repoRoot,
|
|
49712
50262
|
appId: binding.currentAppId,
|
|
49713
50263
|
currentBranch,
|
|
49714
|
-
|
|
50264
|
+
branchName,
|
|
49715
50265
|
headCommitHash,
|
|
49716
50266
|
worktreeClean: worktreeStatus.isClean,
|
|
49717
50267
|
syncStatus: sync.status,
|
|
@@ -49933,7 +50483,11 @@ async function withRepoMutationLock(options, fn) {
|
|
|
49933
50483
|
}
|
|
49934
50484
|
async function collabSync(params) {
|
|
49935
50485
|
const repoRoot = await findGitRoot(params.cwd);
|
|
49936
|
-
const binding = await
|
|
50486
|
+
const binding = await ensureActiveLaneBinding({
|
|
50487
|
+
repoRoot,
|
|
50488
|
+
api: params.api,
|
|
50489
|
+
operation: "`remix collab sync`"
|
|
50490
|
+
});
|
|
49937
50491
|
if (!binding) {
|
|
49938
50492
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
49939
50493
|
exitCode: 2,
|
|
@@ -49942,9 +50496,9 @@ async function collabSync(params) {
|
|
|
49942
50496
|
}
|
|
49943
50497
|
await ensureCleanWorktree(repoRoot);
|
|
49944
50498
|
const branch = await requireCurrentBranch(repoRoot);
|
|
49945
|
-
|
|
50499
|
+
assertBoundBranchMatch({
|
|
49946
50500
|
currentBranch: branch,
|
|
49947
|
-
|
|
50501
|
+
branchName: binding.branchName,
|
|
49948
50502
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
49949
50503
|
operation: "`remix collab sync`"
|
|
49950
50504
|
});
|
|
@@ -50021,9 +50575,9 @@ async function collabSync(params) {
|
|
|
50021
50575
|
});
|
|
50022
50576
|
await ensureCleanWorktree(lockedRepoRoot);
|
|
50023
50577
|
const lockedBranch = await requireCurrentBranch(lockedRepoRoot);
|
|
50024
|
-
|
|
50578
|
+
assertBoundBranchMatch({
|
|
50025
50579
|
currentBranch: lockedBranch,
|
|
50026
|
-
|
|
50580
|
+
branchName: binding.branchName,
|
|
50027
50581
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50028
50582
|
operation: "`remix collab sync`"
|
|
50029
50583
|
});
|
|
@@ -50054,6 +50608,12 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50054
50608
|
hint: preflight.hint
|
|
50055
50609
|
});
|
|
50056
50610
|
}
|
|
50611
|
+
if (preflight.status === "branch_binding_missing") {
|
|
50612
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50613
|
+
exitCode: 2,
|
|
50614
|
+
hint: preflight.hint
|
|
50615
|
+
});
|
|
50616
|
+
}
|
|
50057
50617
|
if (preflight.status === "not_git_repo") {
|
|
50058
50618
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50059
50619
|
exitCode: 2,
|
|
@@ -50067,9 +50627,9 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50067
50627
|
});
|
|
50068
50628
|
}
|
|
50069
50629
|
if (preflight.status === "branch_mismatch") {
|
|
50070
|
-
|
|
50630
|
+
assertBoundBranchMatch({
|
|
50071
50631
|
currentBranch: preflight.currentBranch,
|
|
50072
|
-
|
|
50632
|
+
branchName: preflight.branchName,
|
|
50073
50633
|
allowBranchMismatch: false,
|
|
50074
50634
|
operation: "`remix collab add`"
|
|
50075
50635
|
});
|
|
@@ -50089,7 +50649,11 @@ function assertSupportedRecordingPreflight(preflight) {
|
|
|
50089
50649
|
}
|
|
50090
50650
|
async function collabAdd(params) {
|
|
50091
50651
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50092
|
-
const binding = await
|
|
50652
|
+
const binding = await ensureActiveLaneBinding({
|
|
50653
|
+
repoRoot,
|
|
50654
|
+
api: params.api,
|
|
50655
|
+
operation: "`remix collab add`"
|
|
50656
|
+
});
|
|
50093
50657
|
if (!binding) {
|
|
50094
50658
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50095
50659
|
exitCode: 2,
|
|
@@ -50110,9 +50674,9 @@ async function collabAdd(params) {
|
|
|
50110
50674
|
});
|
|
50111
50675
|
assertSupportedRecordingPreflight(preflight);
|
|
50112
50676
|
const branch = preflight.currentBranch;
|
|
50113
|
-
|
|
50677
|
+
assertBoundBranchMatch({
|
|
50114
50678
|
currentBranch: branch,
|
|
50115
|
-
|
|
50679
|
+
branchName: binding.branchName,
|
|
50116
50680
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50117
50681
|
operation: "`remix collab add`"
|
|
50118
50682
|
});
|
|
@@ -50285,6 +50849,7 @@ async function collabAdd(params) {
|
|
|
50285
50849
|
});
|
|
50286
50850
|
const resp = await params.api.createChangeStep(binding.currentAppId, {
|
|
50287
50851
|
threadId: binding.threadId ?? void 0,
|
|
50852
|
+
collabLaneId: binding.laneId ?? void 0,
|
|
50288
50853
|
prompt,
|
|
50289
50854
|
assistantResponse: assistantResponse ?? void 0,
|
|
50290
50855
|
diff,
|
|
@@ -50358,6 +50923,12 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50358
50923
|
hint: preflight.hint
|
|
50359
50924
|
});
|
|
50360
50925
|
}
|
|
50926
|
+
if (preflight.status === "branch_binding_missing") {
|
|
50927
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
50928
|
+
exitCode: 2,
|
|
50929
|
+
hint: preflight.hint
|
|
50930
|
+
});
|
|
50931
|
+
}
|
|
50361
50932
|
if (preflight.status === "not_git_repo") {
|
|
50362
50933
|
throw new RemixError(preflight.hint || "Not inside a git repository.", {
|
|
50363
50934
|
exitCode: 2,
|
|
@@ -50371,9 +50942,9 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50371
50942
|
});
|
|
50372
50943
|
}
|
|
50373
50944
|
if (preflight.status === "branch_mismatch") {
|
|
50374
|
-
|
|
50945
|
+
assertBoundBranchMatch({
|
|
50375
50946
|
currentBranch: preflight.currentBranch,
|
|
50376
|
-
|
|
50947
|
+
branchName: preflight.branchName,
|
|
50377
50948
|
allowBranchMismatch: false,
|
|
50378
50949
|
operation: "`remix collab record-turn`"
|
|
50379
50950
|
});
|
|
@@ -50393,7 +50964,11 @@ function assertSupportedRecordingPreflight2(preflight) {
|
|
|
50393
50964
|
}
|
|
50394
50965
|
async function collabRecordTurn(params) {
|
|
50395
50966
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50396
|
-
const binding = await
|
|
50967
|
+
const binding = await ensureActiveLaneBinding({
|
|
50968
|
+
repoRoot,
|
|
50969
|
+
api: params.api,
|
|
50970
|
+
operation: "`remix collab record-turn`"
|
|
50971
|
+
});
|
|
50397
50972
|
if (!binding) {
|
|
50398
50973
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50399
50974
|
exitCode: 2,
|
|
@@ -50425,9 +51000,9 @@ async function collabRecordTurn(params) {
|
|
|
50425
51000
|
});
|
|
50426
51001
|
}
|
|
50427
51002
|
const branch = await getCurrentBranch(repoRoot);
|
|
50428
|
-
|
|
51003
|
+
assertBoundBranchMatch({
|
|
50429
51004
|
currentBranch: branch,
|
|
50430
|
-
|
|
51005
|
+
branchName: binding.branchName,
|
|
50431
51006
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50432
51007
|
operation: "`remix collab record-turn`"
|
|
50433
51008
|
});
|
|
@@ -50441,6 +51016,7 @@ async function collabRecordTurn(params) {
|
|
|
50441
51016
|
});
|
|
50442
51017
|
const resp = await params.api.createCollabTurn(binding.currentAppId, {
|
|
50443
51018
|
threadId: binding.threadId ?? void 0,
|
|
51019
|
+
collabLaneId: binding.laneId ?? void 0,
|
|
50444
51020
|
prompt,
|
|
50445
51021
|
assistantResponse,
|
|
50446
51022
|
actor: params.actor,
|
|
@@ -50453,7 +51029,8 @@ async function collabRecordTurn(params) {
|
|
|
50453
51029
|
},
|
|
50454
51030
|
idempotencyKey
|
|
50455
51031
|
});
|
|
50456
|
-
|
|
51032
|
+
const turn = unwrapResponseObject(resp, "collab turn");
|
|
51033
|
+
return turn;
|
|
50457
51034
|
}
|
|
50458
51035
|
function collectWarnings(value) {
|
|
50459
51036
|
if (!Array.isArray(value)) return [];
|
|
@@ -50461,7 +51038,11 @@ function collectWarnings(value) {
|
|
|
50461
51038
|
}
|
|
50462
51039
|
async function collabFinalizeTurn(params) {
|
|
50463
51040
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50464
|
-
const binding = await
|
|
51041
|
+
const binding = await ensureActiveLaneBinding({
|
|
51042
|
+
repoRoot,
|
|
51043
|
+
api: params.api,
|
|
51044
|
+
operation: "`remix collab finalize-turn`"
|
|
51045
|
+
});
|
|
50465
51046
|
if (!binding) {
|
|
50466
51047
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50467
51048
|
exitCode: 2,
|
|
@@ -50567,7 +51148,11 @@ async function collabApprove(params) {
|
|
|
50567
51148
|
operation: "collabApproveSyncTarget"
|
|
50568
51149
|
},
|
|
50569
51150
|
async ({ repoRoot, warnings }) => {
|
|
50570
|
-
const binding = await
|
|
51151
|
+
const binding = await ensureActiveLaneBinding({
|
|
51152
|
+
repoRoot,
|
|
51153
|
+
api: params.api,
|
|
51154
|
+
operation: "`remix collab approve --sync-target-repo`"
|
|
51155
|
+
});
|
|
50571
51156
|
if (!binding) {
|
|
50572
51157
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50573
51158
|
exitCode: 2,
|
|
@@ -50576,9 +51161,9 @@ async function collabApprove(params) {
|
|
|
50576
51161
|
}
|
|
50577
51162
|
await ensureCleanWorktree(repoRoot, "`remix collab approve --sync-target-repo`");
|
|
50578
51163
|
const branch = await requireCurrentBranch(repoRoot);
|
|
50579
|
-
|
|
51164
|
+
assertBoundBranchMatch({
|
|
50580
51165
|
currentBranch: branch,
|
|
50581
|
-
|
|
51166
|
+
branchName: binding.branchName,
|
|
50582
51167
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
50583
51168
|
operation: "`remix collab approve --sync-target-repo`"
|
|
50584
51169
|
});
|
|
@@ -50656,10 +51241,6 @@ function isSubpath(parentPath, candidatePath) {
|
|
|
50656
51241
|
const relative = import_path8.default.relative(parentPath, candidatePath);
|
|
50657
51242
|
return relative === "" || !relative.startsWith("..") && !import_path8.default.isAbsolute(relative);
|
|
50658
51243
|
}
|
|
50659
|
-
function buildPreferredCheckoutBranch(appId) {
|
|
50660
|
-
const normalized = appId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
50661
|
-
return `remix/remix/${normalized || "app"}`;
|
|
50662
|
-
}
|
|
50663
51244
|
async function resolveCheckoutDestination(params) {
|
|
50664
51245
|
if (params.outputDir?.trim()) {
|
|
50665
51246
|
const preferredRepoRoot = import_path8.default.resolve(params.outputDir.trim());
|
|
@@ -50724,7 +51305,9 @@ async function materializeAppCheckout(params) {
|
|
|
50724
51305
|
const bundle = await params.api.downloadAppBundle(params.appId);
|
|
50725
51306
|
await import_promises19.default.writeFile(bundlePath, bundle.data);
|
|
50726
51307
|
await cloneGitBundleToDirectory(bundlePath, repoRoot);
|
|
50727
|
-
|
|
51308
|
+
if (params.expectedBranchName?.trim()) {
|
|
51309
|
+
await checkoutLocalBranch(repoRoot, params.expectedBranchName.trim());
|
|
51310
|
+
}
|
|
50728
51311
|
await ensureGitInfoExcludeEntries(repoRoot, [".remix/"]);
|
|
50729
51312
|
} catch (err) {
|
|
50730
51313
|
await import_promises19.default.rm(repoRoot, { recursive: true, force: true }).catch(() => {
|
|
@@ -50733,15 +51316,15 @@ async function materializeAppCheckout(params) {
|
|
|
50733
51316
|
} finally {
|
|
50734
51317
|
await import_promises19.default.rm(bundleTempDir, { recursive: true, force: true });
|
|
50735
51318
|
}
|
|
50736
|
-
const
|
|
50737
|
-
const
|
|
50738
|
-
const
|
|
51319
|
+
const branchName = await getCurrentBranch(repoRoot) ?? params.expectedBranchName?.trim() ?? null;
|
|
51320
|
+
const remoteUrl = normalizeGitRemote(params.expectedRemoteUrl ?? await getRemoteOriginUrl(repoRoot));
|
|
51321
|
+
const defaultBranch = params.expectedDefaultBranch?.trim() ?? await getDefaultBranch(repoRoot) ?? branchName ?? null;
|
|
50739
51322
|
const repoFingerprint = remoteUrl ? await buildRepoFingerprint({ gitRoot: repoRoot, remoteUrl, defaultBranch }) : null;
|
|
50740
51323
|
return {
|
|
50741
51324
|
repoRoot,
|
|
50742
51325
|
remoteUrl,
|
|
50743
51326
|
defaultBranch,
|
|
50744
|
-
|
|
51327
|
+
branchName,
|
|
50745
51328
|
repoFingerprint
|
|
50746
51329
|
};
|
|
50747
51330
|
}
|
|
@@ -50754,29 +51337,55 @@ async function collabCheckout(params) {
|
|
|
50754
51337
|
});
|
|
50755
51338
|
}
|
|
50756
51339
|
const app = await pollAppReady(params.api, appId);
|
|
51340
|
+
const collab = app.collab && typeof app.collab === "object" ? app.collab : null;
|
|
51341
|
+
const source = app.source && typeof app.source === "object" ? app.source : null;
|
|
51342
|
+
const authoritativeBranchName = typeof collab?.branchName === "string" && collab.branchName.trim() || typeof source?.branch === "string" && source.branch.trim() || typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
51343
|
+
const authoritativeRemoteUrl = typeof source?.remoteUrl === "string" && source.remoteUrl.trim() || null;
|
|
51344
|
+
const authoritativeDefaultBranch = typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
50757
51345
|
const checkout = await materializeAppCheckout({
|
|
50758
51346
|
api: params.api,
|
|
50759
51347
|
cwd: params.cwd,
|
|
50760
51348
|
appId: String(app.id),
|
|
50761
51349
|
outputDir: params.outputDir ?? null,
|
|
50762
|
-
defaultDirName: sanitizeCheckoutDirName(String(app.name || app.id))
|
|
51350
|
+
defaultDirName: sanitizeCheckoutDirName(String(app.name || app.id)),
|
|
51351
|
+
expectedBranchName: authoritativeBranchName,
|
|
51352
|
+
expectedRemoteUrl: authoritativeRemoteUrl,
|
|
51353
|
+
expectedDefaultBranch: authoritativeDefaultBranch
|
|
50763
51354
|
});
|
|
50764
51355
|
const upstreamAppId = String(app.forkedFromAppId ?? app.id);
|
|
50765
|
-
const
|
|
51356
|
+
const laneId = typeof collab?.laneId === "string" ? collab.laneId : null;
|
|
51357
|
+
const repoFingerprint = typeof source?.repoFingerprint === "string" ? source.repoFingerprint : checkout.repoFingerprint;
|
|
51358
|
+
const remoteUrl = typeof source?.remoteUrl === "string" ? source.remoteUrl : checkout.remoteUrl;
|
|
51359
|
+
const defaultBranch = typeof source?.defaultBranch === "string" ? source.defaultBranch : checkout.defaultBranch;
|
|
51360
|
+
const branchName = authoritativeBranchName ?? checkout.branchName;
|
|
51361
|
+
const authoritativeLane = await resolveProjectLaneIfAuthoritative(params.api, {
|
|
50766
51362
|
projectId: String(app.projectId),
|
|
51363
|
+
repoFingerprint,
|
|
51364
|
+
remoteUrl,
|
|
51365
|
+
defaultBranch,
|
|
51366
|
+
branchName,
|
|
50767
51367
|
currentAppId: String(app.id),
|
|
50768
|
-
upstreamAppId,
|
|
50769
|
-
|
|
50770
|
-
|
|
50771
|
-
|
|
50772
|
-
|
|
50773
|
-
|
|
51368
|
+
expectedUpstreamAppId: upstreamAppId,
|
|
51369
|
+
createIfMissing: true,
|
|
51370
|
+
seedAppId: String(app.id)
|
|
51371
|
+
});
|
|
51372
|
+
const bindingPath = await writeCollabBinding(checkout.repoRoot, {
|
|
51373
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
51374
|
+
currentAppId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
51375
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? upstreamAppId,
|
|
51376
|
+
threadId: authoritativeLane?.threadId ?? (app.threadId ? String(app.threadId) : null),
|
|
51377
|
+
repoFingerprint: authoritativeLane?.repoFingerprint ?? repoFingerprint,
|
|
51378
|
+
remoteUrl: authoritativeLane?.remoteUrl ?? remoteUrl,
|
|
51379
|
+
defaultBranch: authoritativeLane?.defaultBranch ?? defaultBranch,
|
|
51380
|
+
laneId: authoritativeLane?.laneId ?? laneId,
|
|
51381
|
+
branchName: authoritativeLane?.branchName ?? branchName,
|
|
51382
|
+
bindingMode: "lane"
|
|
50774
51383
|
});
|
|
50775
51384
|
return {
|
|
50776
|
-
appId: String(app.id),
|
|
50777
|
-
dashboardUrl: buildDashboardAppUrl(String(app.id)),
|
|
50778
|
-
projectId: String(app.projectId),
|
|
50779
|
-
upstreamAppId,
|
|
51385
|
+
appId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
51386
|
+
dashboardUrl: buildDashboardAppUrl(authoritativeLane?.currentAppId ?? String(app.id)),
|
|
51387
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
51388
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? upstreamAppId,
|
|
50780
51389
|
bindingPath,
|
|
50781
51390
|
repoRoot: checkout.repoRoot
|
|
50782
51391
|
};
|
|
@@ -50796,14 +51405,26 @@ async function resolveQueueAppId(params) {
|
|
|
50796
51405
|
});
|
|
50797
51406
|
}
|
|
50798
51407
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50799
|
-
const
|
|
50800
|
-
if (
|
|
51408
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot });
|
|
51409
|
+
if (bindingResolution.status === "not_bound") {
|
|
50801
51410
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
50802
51411
|
exitCode: 2,
|
|
50803
51412
|
hint: "Bind the repository first or pass `appId` explicitly for the app-scoped merge-request queue."
|
|
50804
51413
|
});
|
|
50805
51414
|
}
|
|
50806
|
-
|
|
51415
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
51416
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane.", {
|
|
51417
|
+
exitCode: 2,
|
|
51418
|
+
hint: `Switch back to a bound branch or create a lane by recording work on ${bindingResolution.currentBranch ?? "this branch"}.`
|
|
51419
|
+
});
|
|
51420
|
+
}
|
|
51421
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
51422
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
51423
|
+
exitCode: 2,
|
|
51424
|
+
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51425
|
+
});
|
|
51426
|
+
}
|
|
51427
|
+
return bindingResolution.binding.currentAppId;
|
|
50807
51428
|
}
|
|
50808
51429
|
async function collabListMergeRequests(params) {
|
|
50809
51430
|
const appId = await resolveQueueAppId({
|
|
@@ -50832,12 +51453,32 @@ async function collabListMergeRequests(params) {
|
|
|
50832
51453
|
async function resolveScopeTarget(params) {
|
|
50833
51454
|
if (params.targetId?.trim()) return params.targetId.trim();
|
|
50834
51455
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50835
|
-
const
|
|
50836
|
-
if (
|
|
51456
|
+
const bindingResolution = await resolveActiveLaneBinding({ repoRoot, api: params.api });
|
|
51457
|
+
if (bindingResolution.status === "not_bound") {
|
|
50837
51458
|
throw new RemixError("Repository is not bound to Remix and no explicit target id was provided.", { exitCode: 2 });
|
|
50838
51459
|
}
|
|
50839
|
-
if (
|
|
51460
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
51461
|
+
throw new RemixError("Current branch is not yet bound to a Remix lane and no explicit target id was provided.", {
|
|
51462
|
+
exitCode: 2
|
|
51463
|
+
});
|
|
51464
|
+
}
|
|
51465
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
51466
|
+
throw new RemixError("Current branch binding conflicts with the server-resolved Remix lane.", {
|
|
51467
|
+
exitCode: 2,
|
|
51468
|
+
hint: `Local app ${bindingResolution.binding.currentAppId}; server app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"}.`
|
|
51469
|
+
});
|
|
51470
|
+
}
|
|
51471
|
+
const binding = bindingResolution.binding;
|
|
51472
|
+
if (params.scope === "project") {
|
|
51473
|
+
if (!binding.projectId) {
|
|
51474
|
+
throw new RemixError("Could not resolve the project for the current repository binding.", { exitCode: 2 });
|
|
51475
|
+
}
|
|
51476
|
+
return binding.projectId;
|
|
51477
|
+
}
|
|
50840
51478
|
if (params.scope === "app") return binding.currentAppId;
|
|
51479
|
+
if (!binding.projectId) {
|
|
51480
|
+
throw new RemixError("Could not resolve the project for the current repository binding.", { exitCode: 2 });
|
|
51481
|
+
}
|
|
50841
51482
|
const project = unwrapResponseObject(await params.api.getProject(binding.projectId), "project");
|
|
50842
51483
|
const organizationId = typeof project.organizationId === "string" ? project.organizationId : null;
|
|
50843
51484
|
if (!organizationId) {
|
|
@@ -50959,13 +51600,28 @@ async function collabInit(params) {
|
|
|
50959
51600
|
const remoteUrl = normalizeGitRemote(await getRemoteOriginUrl(repoRoot));
|
|
50960
51601
|
const currentBranch = await getCurrentBranch(repoRoot);
|
|
50961
51602
|
const defaultBranch = await getDefaultBranch(repoRoot) ?? currentBranch;
|
|
50962
|
-
const
|
|
51603
|
+
const branchName = currentBranch ?? defaultBranch ?? null;
|
|
50963
51604
|
const repoFingerprint = await buildRepoFingerprint({ gitRoot: repoRoot, remoteUrl, defaultBranch });
|
|
50964
51605
|
const repoSnapshot = await captureRepoSnapshot(repoRoot);
|
|
51606
|
+
if (params.forceNew) {
|
|
51607
|
+
const bindingResp = await params.api.resolveProjectBinding({
|
|
51608
|
+
repoFingerprint,
|
|
51609
|
+
remoteUrl: remoteUrl ?? void 0,
|
|
51610
|
+
branchName: branchName ?? void 0
|
|
51611
|
+
});
|
|
51612
|
+
const existing = bindingResp?.responseObject;
|
|
51613
|
+
if (existing?.projectId && existing?.appId) {
|
|
51614
|
+
throw new RemixError("`remix collab init --force-new` is not allowed for repositories already known to Remix.", {
|
|
51615
|
+
exitCode: 2,
|
|
51616
|
+
hint: "This repository already resolves to an existing Remix lineage. Run `remix collab init` without `--force-new`, or use an explicit checkout/remix flow instead of creating a duplicate imported app."
|
|
51617
|
+
});
|
|
51618
|
+
}
|
|
51619
|
+
}
|
|
50965
51620
|
if (!params.forceNew) {
|
|
50966
51621
|
const bindingResp = await params.api.resolveProjectBinding({
|
|
50967
51622
|
repoFingerprint,
|
|
50968
|
-
remoteUrl: remoteUrl ?? void 0
|
|
51623
|
+
remoteUrl: remoteUrl ?? void 0,
|
|
51624
|
+
branchName: branchName ?? void 0
|
|
50969
51625
|
});
|
|
50970
51626
|
const existing = bindingResp?.responseObject;
|
|
50971
51627
|
if (existing?.projectId && existing?.appId) {
|
|
@@ -50973,25 +51629,55 @@ async function collabInit(params) {
|
|
|
50973
51629
|
operation: "`remix collab init`",
|
|
50974
51630
|
recoveryHint: "The repository changed while the local binding was being initialized. Review the local changes and rerun `remix collab init`."
|
|
50975
51631
|
});
|
|
51632
|
+
const initialProjectId = String(existing.projectId);
|
|
51633
|
+
const initialCurrentAppId = String(existing.appId);
|
|
51634
|
+
const initialUpstreamAppId = String(existing.upstreamAppId ?? existing.appId);
|
|
51635
|
+
const initialThreadId = existing.threadId ? String(existing.threadId) : null;
|
|
50976
51636
|
const bindingPath2 = await writeCollabBinding(repoRoot, {
|
|
50977
|
-
projectId:
|
|
50978
|
-
currentAppId:
|
|
50979
|
-
upstreamAppId:
|
|
50980
|
-
threadId:
|
|
51637
|
+
projectId: initialProjectId,
|
|
51638
|
+
currentAppId: initialCurrentAppId,
|
|
51639
|
+
upstreamAppId: initialUpstreamAppId,
|
|
51640
|
+
threadId: initialThreadId,
|
|
50981
51641
|
repoFingerprint,
|
|
50982
51642
|
remoteUrl,
|
|
50983
51643
|
defaultBranch: defaultBranch ?? null,
|
|
50984
|
-
|
|
51644
|
+
laneId: null,
|
|
51645
|
+
branchName,
|
|
51646
|
+
bindingMode: "lane"
|
|
50985
51647
|
});
|
|
51648
|
+
let boundProjectId2 = initialProjectId;
|
|
51649
|
+
let boundCurrentAppId2 = initialCurrentAppId;
|
|
51650
|
+
let boundUpstreamAppId2 = initialUpstreamAppId;
|
|
51651
|
+
let boundThreadId2 = initialThreadId;
|
|
51652
|
+
let finalWarnings = [...warnings];
|
|
51653
|
+
if (branchName) {
|
|
51654
|
+
const provisioned = await provisionActiveLaneBinding({
|
|
51655
|
+
repoRoot,
|
|
51656
|
+
api: params.api,
|
|
51657
|
+
operation: "`remix collab init`"
|
|
51658
|
+
});
|
|
51659
|
+
if (provisioned.binding) {
|
|
51660
|
+
boundProjectId2 = provisioned.binding.projectId ?? boundProjectId2;
|
|
51661
|
+
boundCurrentAppId2 = provisioned.binding.currentAppId;
|
|
51662
|
+
boundUpstreamAppId2 = provisioned.binding.upstreamAppId;
|
|
51663
|
+
boundThreadId2 = provisioned.binding.threadId;
|
|
51664
|
+
}
|
|
51665
|
+
finalWarnings = [...finalWarnings, ...provisioned.warnings];
|
|
51666
|
+
}
|
|
51667
|
+
if (boundCurrentAppId2) {
|
|
51668
|
+
const readyApp = await pollAppReady(params.api, boundCurrentAppId2);
|
|
51669
|
+
boundProjectId2 = String(readyApp.projectId ?? boundProjectId2);
|
|
51670
|
+
boundThreadId2 = readyApp.threadId ? String(readyApp.threadId) : boundThreadId2;
|
|
51671
|
+
}
|
|
50986
51672
|
return {
|
|
50987
51673
|
reused: true,
|
|
50988
|
-
projectId:
|
|
50989
|
-
appId:
|
|
50990
|
-
dashboardUrl: buildDashboardAppUrl(
|
|
50991
|
-
upstreamAppId:
|
|
51674
|
+
projectId: boundProjectId2,
|
|
51675
|
+
appId: boundCurrentAppId2,
|
|
51676
|
+
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId2),
|
|
51677
|
+
upstreamAppId: boundUpstreamAppId2,
|
|
50992
51678
|
bindingPath: bindingPath2,
|
|
50993
51679
|
repoRoot,
|
|
50994
|
-
...
|
|
51680
|
+
...finalWarnings.length > 0 ? { warnings: finalWarnings } : {}
|
|
50995
51681
|
};
|
|
50996
51682
|
}
|
|
50997
51683
|
}
|
|
@@ -51018,6 +51704,7 @@ async function collabInit(params) {
|
|
|
51018
51704
|
path: params.path?.trim() || void 0,
|
|
51019
51705
|
platform: "generic",
|
|
51020
51706
|
isPublic: false,
|
|
51707
|
+
branch: currentBranch ?? void 0,
|
|
51021
51708
|
remoteUrl: remoteUrl ?? void 0,
|
|
51022
51709
|
defaultBranch: defaultBranch ?? void 0,
|
|
51023
51710
|
repoFingerprint,
|
|
@@ -51025,31 +51712,65 @@ async function collabInit(params) {
|
|
|
51025
51712
|
});
|
|
51026
51713
|
const imported = unwrapResponseObject(importResp, "import");
|
|
51027
51714
|
const app = await pollAppReady(params.api, String(imported.appId));
|
|
51715
|
+
let boundProjectId = String(app.projectId);
|
|
51716
|
+
let boundCurrentAppId = String(app.id);
|
|
51717
|
+
let boundUpstreamAppId = String(app.id);
|
|
51718
|
+
let boundThreadId = app.threadId ? String(app.threadId) : null;
|
|
51719
|
+
let boundLaneId = null;
|
|
51720
|
+
if (branchName) {
|
|
51721
|
+
const laneResp = defaultBranch && branchName !== defaultBranch ? await params.api.bootstrapFreshProjectLane({
|
|
51722
|
+
projectId: boundProjectId,
|
|
51723
|
+
repoFingerprint,
|
|
51724
|
+
remoteUrl: remoteUrl ?? void 0,
|
|
51725
|
+
defaultBranch: defaultBranch ?? void 0,
|
|
51726
|
+
branchName,
|
|
51727
|
+
seedAppId: String(app.id)
|
|
51728
|
+
}) : await params.api.ensureProjectLaneBinding({
|
|
51729
|
+
projectId: boundProjectId,
|
|
51730
|
+
repoFingerprint,
|
|
51731
|
+
remoteUrl: remoteUrl ?? void 0,
|
|
51732
|
+
defaultBranch: defaultBranch ?? void 0,
|
|
51733
|
+
branchName,
|
|
51734
|
+
seedAppId: String(app.id)
|
|
51735
|
+
});
|
|
51736
|
+
const lane = unwrapResponseObject(laneResp, "project lane binding");
|
|
51737
|
+
boundProjectId = typeof lane.projectId === "string" && lane.projectId ? lane.projectId : boundProjectId;
|
|
51738
|
+
boundCurrentAppId = typeof lane.currentAppId === "string" && lane.currentAppId ? lane.currentAppId : boundCurrentAppId;
|
|
51739
|
+
boundUpstreamAppId = typeof lane.upstreamAppId === "string" && lane.upstreamAppId ? lane.upstreamAppId : boundUpstreamAppId;
|
|
51740
|
+
boundThreadId = typeof lane.threadId === "string" && lane.threadId ? lane.threadId : boundThreadId;
|
|
51741
|
+
boundLaneId = typeof lane.laneId === "string" && lane.laneId ? lane.laneId : null;
|
|
51742
|
+
}
|
|
51743
|
+
if (boundCurrentAppId) {
|
|
51744
|
+
const readyApp = await pollAppReady(params.api, boundCurrentAppId);
|
|
51745
|
+
boundProjectId = String(readyApp.projectId ?? boundProjectId);
|
|
51746
|
+
boundThreadId = readyApp.threadId ? String(readyApp.threadId) : boundThreadId;
|
|
51747
|
+
}
|
|
51028
51748
|
await assertRepoSnapshotUnchanged(repoRoot, repoSnapshot, {
|
|
51029
51749
|
operation: "`remix collab init`",
|
|
51030
51750
|
recoveryHint: "The repository changed before the Remix binding was written. Review the local changes and rerun `remix collab init`."
|
|
51031
51751
|
});
|
|
51032
51752
|
const bindingPath = await writeCollabBinding(repoRoot, {
|
|
51033
|
-
projectId:
|
|
51034
|
-
currentAppId:
|
|
51035
|
-
upstreamAppId:
|
|
51036
|
-
threadId:
|
|
51753
|
+
projectId: boundProjectId,
|
|
51754
|
+
currentAppId: boundCurrentAppId,
|
|
51755
|
+
upstreamAppId: boundUpstreamAppId,
|
|
51756
|
+
threadId: boundThreadId,
|
|
51037
51757
|
repoFingerprint,
|
|
51038
51758
|
remoteUrl,
|
|
51039
51759
|
defaultBranch: defaultBranch ?? null,
|
|
51040
|
-
|
|
51760
|
+
laneId: boundLaneId,
|
|
51761
|
+
branchName,
|
|
51762
|
+
bindingMode: "lane"
|
|
51041
51763
|
});
|
|
51042
51764
|
return {
|
|
51043
51765
|
reused: false,
|
|
51044
|
-
projectId:
|
|
51045
|
-
appId:
|
|
51046
|
-
dashboardUrl: buildDashboardAppUrl(
|
|
51047
|
-
upstreamAppId:
|
|
51766
|
+
projectId: boundProjectId,
|
|
51767
|
+
appId: boundCurrentAppId,
|
|
51768
|
+
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId),
|
|
51769
|
+
upstreamAppId: boundUpstreamAppId,
|
|
51048
51770
|
bindingPath,
|
|
51049
51771
|
repoRoot,
|
|
51050
51772
|
remoteUrl,
|
|
51051
51773
|
defaultBranch,
|
|
51052
|
-
preferredBranch,
|
|
51053
51774
|
...warnings.length > 0 ? { warnings } : {}
|
|
51054
51775
|
};
|
|
51055
51776
|
}
|
|
@@ -51079,6 +51800,9 @@ async function collabInvite(params) {
|
|
|
51079
51800
|
async function collabList(params) {
|
|
51080
51801
|
const pageRequest = normalizePagination(params);
|
|
51081
51802
|
const resp = await params.api.listApps({
|
|
51803
|
+
ownership: params.ownership ?? "all",
|
|
51804
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
51805
|
+
createdBy: params.createdBy,
|
|
51082
51806
|
forked: params.forked ?? "all",
|
|
51083
51807
|
limit: pageRequest.limit + 1,
|
|
51084
51808
|
offset: pageRequest.offset
|
|
@@ -51092,7 +51816,11 @@ async function collabList(params) {
|
|
|
51092
51816
|
}
|
|
51093
51817
|
async function collabReconcile(params) {
|
|
51094
51818
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51095
|
-
const binding = await
|
|
51819
|
+
const binding = await ensureActiveLaneBinding({
|
|
51820
|
+
repoRoot,
|
|
51821
|
+
api: params.api,
|
|
51822
|
+
operation: "`remix collab reconcile`"
|
|
51823
|
+
});
|
|
51096
51824
|
if (!binding) {
|
|
51097
51825
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
51098
51826
|
exitCode: 2,
|
|
@@ -51101,9 +51829,9 @@ async function collabReconcile(params) {
|
|
|
51101
51829
|
}
|
|
51102
51830
|
await ensureCleanWorktree(repoRoot, "`remix collab reconcile`");
|
|
51103
51831
|
const branch = await requireCurrentBranch(repoRoot);
|
|
51104
|
-
|
|
51832
|
+
assertBoundBranchMatch({
|
|
51105
51833
|
currentBranch: branch,
|
|
51106
|
-
|
|
51834
|
+
branchName: binding.branchName,
|
|
51107
51835
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
51108
51836
|
operation: "`remix collab reconcile`"
|
|
51109
51837
|
});
|
|
@@ -51212,9 +51940,9 @@ async function collabReconcile(params) {
|
|
|
51212
51940
|
});
|
|
51213
51941
|
await ensureCleanWorktree(lockedRepoRoot, "`remix collab reconcile`");
|
|
51214
51942
|
const lockedBranch = await requireCurrentBranch(lockedRepoRoot);
|
|
51215
|
-
|
|
51943
|
+
assertBoundBranchMatch({
|
|
51216
51944
|
currentBranch: lockedBranch,
|
|
51217
|
-
|
|
51945
|
+
branchName: binding.branchName,
|
|
51218
51946
|
allowBranchMismatch: params.allowBranchMismatch,
|
|
51219
51947
|
operation: "`remix collab reconcile`"
|
|
51220
51948
|
});
|
|
@@ -51269,38 +51997,76 @@ async function collabRemix(params) {
|
|
|
51269
51997
|
hint: "Pass the source app id to remix."
|
|
51270
51998
|
});
|
|
51271
51999
|
}
|
|
51272
|
-
const
|
|
52000
|
+
const sourceApp = await pollAppReady(params.api, sourceAppId);
|
|
52001
|
+
const sourceCollab = sourceApp.collab && typeof sourceApp.collab === "object" ? sourceApp.collab : null;
|
|
52002
|
+
const sourceSource = sourceApp.source && typeof sourceApp.source === "object" ? sourceApp.source : null;
|
|
52003
|
+
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;
|
|
52004
|
+
const forkResp = await params.api.forkApp(sourceAppId, {
|
|
52005
|
+
name: params.name?.trim() || void 0,
|
|
52006
|
+
platform: "generic",
|
|
52007
|
+
branchName: sourceBranchName
|
|
52008
|
+
});
|
|
51273
52009
|
const forked = unwrapResponseObject(forkResp, "fork");
|
|
51274
52010
|
const app = await pollAppReady(params.api, String(forked.id));
|
|
52011
|
+
const collab = app.collab && typeof app.collab === "object" ? app.collab : null;
|
|
52012
|
+
const source = app.source && typeof app.source === "object" ? app.source : null;
|
|
52013
|
+
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;
|
|
52014
|
+
const authoritativeRemoteUrl = typeof source?.remoteUrl === "string" && source.remoteUrl.trim() || null;
|
|
52015
|
+
const authoritativeDefaultBranch = typeof source?.defaultBranch === "string" && source.defaultBranch.trim() || null;
|
|
51275
52016
|
const checkout = await materializeAppCheckout({
|
|
51276
52017
|
api: params.api,
|
|
51277
52018
|
cwd: params.cwd,
|
|
51278
52019
|
appId: String(app.id),
|
|
51279
52020
|
outputDir: params.outputDir ?? null,
|
|
51280
|
-
defaultDirName: sanitizeCheckoutDirName(String(params.name?.trim() || app.name || app.id))
|
|
51281
|
-
|
|
51282
|
-
|
|
52021
|
+
defaultDirName: sanitizeCheckoutDirName(String(params.name?.trim() || app.name || app.id)),
|
|
52022
|
+
expectedBranchName: authoritativeBranchName,
|
|
52023
|
+
expectedRemoteUrl: authoritativeRemoteUrl,
|
|
52024
|
+
expectedDefaultBranch: authoritativeDefaultBranch
|
|
52025
|
+
});
|
|
52026
|
+
const laneId = typeof collab?.laneId === "string" ? collab.laneId : null;
|
|
52027
|
+
const repoFingerprint = typeof source?.repoFingerprint === "string" ? source.repoFingerprint : checkout.repoFingerprint;
|
|
52028
|
+
const remoteUrl = typeof source?.remoteUrl === "string" ? source.remoteUrl : checkout.remoteUrl;
|
|
52029
|
+
const defaultBranch = typeof source?.defaultBranch === "string" ? source.defaultBranch : checkout.defaultBranch;
|
|
52030
|
+
const branchName = authoritativeBranchName ?? checkout.branchName;
|
|
52031
|
+
const authoritativeLane = await resolveProjectLaneIfAuthoritative(params.api, {
|
|
51283
52032
|
projectId: String(app.projectId),
|
|
52033
|
+
repoFingerprint,
|
|
52034
|
+
remoteUrl,
|
|
52035
|
+
defaultBranch,
|
|
52036
|
+
branchName,
|
|
51284
52037
|
currentAppId: String(app.id),
|
|
51285
|
-
|
|
51286
|
-
|
|
51287
|
-
|
|
51288
|
-
|
|
51289
|
-
|
|
51290
|
-
|
|
52038
|
+
expectedUpstreamAppId: String(app.forkedFromAppId ?? sourceAppId),
|
|
52039
|
+
createIfMissing: true,
|
|
52040
|
+
seedAppId: String(app.id)
|
|
52041
|
+
});
|
|
52042
|
+
const bindingPath = await writeCollabBinding(checkout.repoRoot, {
|
|
52043
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
52044
|
+
currentAppId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
52045
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? String(app.forkedFromAppId ?? sourceAppId),
|
|
52046
|
+
threadId: authoritativeLane?.threadId ?? (app.threadId ? String(app.threadId) : null),
|
|
52047
|
+
repoFingerprint: authoritativeLane?.repoFingerprint ?? repoFingerprint,
|
|
52048
|
+
remoteUrl: authoritativeLane?.remoteUrl ?? remoteUrl,
|
|
52049
|
+
defaultBranch: authoritativeLane?.defaultBranch ?? defaultBranch,
|
|
52050
|
+
laneId: authoritativeLane?.laneId ?? laneId,
|
|
52051
|
+
branchName: authoritativeLane?.branchName ?? branchName,
|
|
52052
|
+
bindingMode: "lane"
|
|
51291
52053
|
});
|
|
51292
52054
|
return {
|
|
51293
|
-
appId: String(app.id),
|
|
51294
|
-
dashboardUrl: buildDashboardAppUrl(String(app.id)),
|
|
51295
|
-
projectId: String(app.projectId),
|
|
51296
|
-
upstreamAppId: String(app.forkedFromAppId ?? sourceAppId),
|
|
52055
|
+
appId: authoritativeLane?.currentAppId ?? String(app.id),
|
|
52056
|
+
dashboardUrl: buildDashboardAppUrl(authoritativeLane?.currentAppId ?? String(app.id)),
|
|
52057
|
+
projectId: authoritativeLane?.projectId ?? String(app.projectId),
|
|
52058
|
+
upstreamAppId: authoritativeLane?.upstreamAppId ?? String(app.forkedFromAppId ?? sourceAppId),
|
|
51297
52059
|
bindingPath,
|
|
51298
52060
|
repoRoot: checkout.repoRoot
|
|
51299
52061
|
};
|
|
51300
52062
|
}
|
|
51301
52063
|
async function collabRequestMerge(params) {
|
|
51302
52064
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51303
|
-
const binding = await
|
|
52065
|
+
const binding = await ensureActiveLaneBinding({
|
|
52066
|
+
repoRoot,
|
|
52067
|
+
api: params.api,
|
|
52068
|
+
operation: "`remix collab request-merge`"
|
|
52069
|
+
});
|
|
51304
52070
|
if (!binding) throw new RemixError("Repository is not bound to Remix.", { exitCode: 2 });
|
|
51305
52071
|
const resp = await params.api.openMergeRequest(binding.currentAppId);
|
|
51306
52072
|
return unwrapResponseObject(resp, "merge request");
|
|
@@ -51333,7 +52099,9 @@ function createBaseStatus() {
|
|
|
51333
52099
|
repoFingerprint: null,
|
|
51334
52100
|
remoteUrl: null,
|
|
51335
52101
|
defaultBranch: null,
|
|
51336
|
-
|
|
52102
|
+
laneId: null,
|
|
52103
|
+
branchName: null,
|
|
52104
|
+
bindingMode: null
|
|
51337
52105
|
},
|
|
51338
52106
|
remote: {
|
|
51339
52107
|
checked: false,
|
|
@@ -51397,12 +52165,13 @@ async function collabStatus(params) {
|
|
|
51397
52165
|
}
|
|
51398
52166
|
status.repo.isGitRepo = true;
|
|
51399
52167
|
status.repo.repoRoot = repoRoot;
|
|
51400
|
-
const [branch,
|
|
52168
|
+
const [branch, initialHeadCommitHash, worktreeStatus, bindingResolution] = await Promise.all([
|
|
51401
52169
|
getCurrentBranch(repoRoot),
|
|
51402
52170
|
getHeadCommitHash(repoRoot),
|
|
51403
52171
|
getWorktreeStatus(repoRoot),
|
|
51404
|
-
|
|
52172
|
+
resolveActiveLaneBinding({ repoRoot, api: params.api ?? void 0 })
|
|
51405
52173
|
]);
|
|
52174
|
+
let headCommitHash = initialHeadCommitHash;
|
|
51406
52175
|
status.repo.branch = branch;
|
|
51407
52176
|
status.repo.branchMismatch = false;
|
|
51408
52177
|
status.repo.headCommitHash = headCommitHash;
|
|
@@ -51416,13 +52185,36 @@ async function collabStatus(params) {
|
|
|
51416
52185
|
if (!status.repo.worktree.isClean) addWarning(status, "Working tree has local changes.");
|
|
51417
52186
|
if (!branch) addWarning(status, "Repository is in a detached HEAD state.");
|
|
51418
52187
|
if (!headCommitHash) addWarning(status, "Failed to resolve local HEAD commit.");
|
|
51419
|
-
if (
|
|
52188
|
+
if (bindingResolution.status === "not_bound") {
|
|
51420
52189
|
status.binding.path = null;
|
|
51421
52190
|
addBlockedReason(status.sync, "not_bound");
|
|
51422
52191
|
addBlockedReason(status.reconcile, "not_bound");
|
|
51423
52192
|
status.recommendedAction = "init";
|
|
51424
52193
|
return status;
|
|
51425
52194
|
}
|
|
52195
|
+
if (bindingResolution.status === "missing_branch_binding") {
|
|
52196
|
+
status.binding = {
|
|
52197
|
+
isBound: true,
|
|
52198
|
+
path: getCollabBindingPath(repoRoot),
|
|
52199
|
+
projectId: bindingResolution.projectId,
|
|
52200
|
+
currentAppId: null,
|
|
52201
|
+
upstreamAppId: bindingResolution.upstreamAppId,
|
|
52202
|
+
isRemix: null,
|
|
52203
|
+
threadId: bindingResolution.threadId,
|
|
52204
|
+
repoFingerprint: bindingResolution.repoFingerprint,
|
|
52205
|
+
remoteUrl: bindingResolution.remoteUrl,
|
|
52206
|
+
defaultBranch: bindingResolution.defaultBranch,
|
|
52207
|
+
laneId: null,
|
|
52208
|
+
branchName: bindingResolution.currentBranch,
|
|
52209
|
+
bindingMode: "lane"
|
|
52210
|
+
};
|
|
52211
|
+
addBlockedReason(status.sync, "branch_binding_missing");
|
|
52212
|
+
addBlockedReason(status.reconcile, "branch_binding_missing");
|
|
52213
|
+
addWarning(status, `Current branch ${bindingResolution.currentBranch ?? "(detached)"} is not yet bound to a Remix lane.`);
|
|
52214
|
+
status.recommendedAction = "no_action";
|
|
52215
|
+
return status;
|
|
52216
|
+
}
|
|
52217
|
+
const binding = bindingResolution.binding;
|
|
51426
52218
|
status.binding = {
|
|
51427
52219
|
isBound: true,
|
|
51428
52220
|
path: getCollabBindingPath(repoRoot),
|
|
@@ -51434,13 +52226,21 @@ async function collabStatus(params) {
|
|
|
51434
52226
|
repoFingerprint: binding.repoFingerprint,
|
|
51435
52227
|
remoteUrl: binding.remoteUrl,
|
|
51436
52228
|
defaultBranch: binding.defaultBranch,
|
|
51437
|
-
|
|
52229
|
+
laneId: binding.laneId,
|
|
52230
|
+
branchName: binding.branchName,
|
|
52231
|
+
bindingMode: binding.bindingMode
|
|
51438
52232
|
};
|
|
51439
|
-
status.repo.branchMismatch = !
|
|
52233
|
+
status.repo.branchMismatch = !isBoundBranchMatch(branch, binding.branchName);
|
|
51440
52234
|
if (status.repo.branchMismatch) {
|
|
51441
52235
|
addWarning(
|
|
51442
52236
|
status,
|
|
51443
|
-
`Current branch ${branch ?? "(detached)"} does not match
|
|
52237
|
+
`Current branch ${branch ?? "(detached)"} does not match bound branch ${binding.branchName ?? "(unset)"}.`
|
|
52238
|
+
);
|
|
52239
|
+
}
|
|
52240
|
+
if (bindingResolution.status === "binding_conflict") {
|
|
52241
|
+
addWarning(
|
|
52242
|
+
status,
|
|
52243
|
+
`Local binding app ${binding.currentAppId} conflicts with server-resolved app ${bindingResolution.resolvedLane.currentAppId ?? "(unknown)"} for branch ${bindingResolution.currentBranch ?? "(detached)"}.`
|
|
51444
52244
|
);
|
|
51445
52245
|
}
|
|
51446
52246
|
if (!params.api) {
|
|
@@ -51488,8 +52288,14 @@ async function collabStatus(params) {
|
|
|
51488
52288
|
const syncResp = syncResult.value;
|
|
51489
52289
|
if (syncResp) {
|
|
51490
52290
|
const sync = unwrapResponseObject(syncResp, "sync result");
|
|
52291
|
+
const latestHeadCommitHash = sync.targetCommitHash && sync.status !== "up_to_date" ? await getHeadCommitHash(repoRoot) : headCommitHash;
|
|
52292
|
+
if (latestHeadCommitHash) {
|
|
52293
|
+
headCommitHash = latestHeadCommitHash;
|
|
52294
|
+
status.repo.headCommitHash = latestHeadCommitHash;
|
|
52295
|
+
}
|
|
52296
|
+
const normalizedSyncStatus = headCommitHash && sync.targetCommitHash && headCommitHash === sync.targetCommitHash ? "up_to_date" : sync.status;
|
|
51491
52297
|
status.sync.checked = true;
|
|
51492
|
-
status.sync.status =
|
|
52298
|
+
status.sync.status = normalizedSyncStatus;
|
|
51493
52299
|
status.sync.warnings = sync.warnings;
|
|
51494
52300
|
status.sync.targetCommitHash = sync.targetCommitHash;
|
|
51495
52301
|
status.sync.targetCommitId = sync.targetCommitId;
|
|
@@ -51497,9 +52303,9 @@ async function collabStatus(params) {
|
|
|
51497
52303
|
if (!status.repo.worktree.isClean) addBlockedReason(status.sync, "dirty_worktree");
|
|
51498
52304
|
if (!branch) addBlockedReason(status.sync, "detached_head");
|
|
51499
52305
|
if (status.repo.branchMismatch) addBlockedReason(status.sync, "branch_mismatch");
|
|
51500
|
-
if (
|
|
52306
|
+
if (normalizedSyncStatus === "conflict_risk") addBlockedReason(status.sync, "metadata_conflict");
|
|
51501
52307
|
status.sync.canApply = status.sync.status === "ready_to_fast_forward" && status.repo.worktree.isClean && Boolean(branch) && !status.sync.blockedReasons.includes("metadata_conflict");
|
|
51502
|
-
if (
|
|
52308
|
+
if (normalizedSyncStatus === "conflict_risk") {
|
|
51503
52309
|
status.reconcile.checked = true;
|
|
51504
52310
|
status.reconcile.status = "metadata_conflict";
|
|
51505
52311
|
status.reconcile.warnings = sync.warnings;
|
|
@@ -51509,7 +52315,7 @@ async function collabStatus(params) {
|
|
|
51509
52315
|
if (!status.repo.worktree.isClean) addBlockedReason(status.reconcile, "dirty_worktree");
|
|
51510
52316
|
if (!branch) addBlockedReason(status.reconcile, "detached_head");
|
|
51511
52317
|
if (status.repo.branchMismatch) addBlockedReason(status.reconcile, "branch_mismatch");
|
|
51512
|
-
} else if (
|
|
52318
|
+
} else if (normalizedSyncStatus === "base_unknown") {
|
|
51513
52319
|
try {
|
|
51514
52320
|
const preflightResp = await params.api.preflightAppReconcile(binding.currentAppId, {
|
|
51515
52321
|
localHeadCommitHash: headCommitHash,
|
|
@@ -51564,7 +52370,11 @@ async function collabStatus(params) {
|
|
|
51564
52370
|
}
|
|
51565
52371
|
async function collabSyncUpstream(params) {
|
|
51566
52372
|
const repoRoot = await findGitRoot(params.cwd);
|
|
51567
|
-
const binding = await
|
|
52373
|
+
const binding = await ensureActiveLaneBinding({
|
|
52374
|
+
repoRoot,
|
|
52375
|
+
api: params.api,
|
|
52376
|
+
operation: "`remix collab sync-upstream`"
|
|
52377
|
+
});
|
|
51568
52378
|
if (!binding) {
|
|
51569
52379
|
throw new RemixError("Repository is not bound to Remix.", {
|
|
51570
52380
|
exitCode: 2,
|
|
@@ -51822,7 +52632,7 @@ function normalizeByMessage(err) {
|
|
|
51822
52632
|
category: "local_state"
|
|
51823
52633
|
});
|
|
51824
52634
|
}
|
|
51825
|
-
if (code === ERROR_CODES.PREFERRED_BRANCH_MISMATCH || message.includes("preferred branch")) {
|
|
52635
|
+
if (code === ERROR_CODES.PREFERRED_BRANCH_MISMATCH || message.includes("preferred branch") || message.includes("bound branch")) {
|
|
51826
52636
|
return makeNormalized({
|
|
51827
52637
|
code: ERROR_CODES.PREFERRED_BRANCH_MISMATCH,
|
|
51828
52638
|
message,
|
|
@@ -52065,6 +52875,9 @@ var initInputSchema = {
|
|
|
52065
52875
|
var listInputSchema = {
|
|
52066
52876
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
52067
52877
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
52878
|
+
ownership: external_exports.enum(["mine", "shared", "all"]).optional(),
|
|
52879
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]).optional(),
|
|
52880
|
+
createdBy: external_exports.string().trim().min(1).optional(),
|
|
52068
52881
|
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
52069
52882
|
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52070
52883
|
offset: external_exports.number().int().nonnegative().optional()
|
|
@@ -52358,7 +53171,7 @@ function getRiskLevel(status) {
|
|
|
52358
53171
|
function getRecommendedNextActions(status) {
|
|
52359
53172
|
if (status.repo.branchMismatch) {
|
|
52360
53173
|
return [
|
|
52361
|
-
`Switch to the
|
|
53174
|
+
`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.`
|
|
52362
53175
|
];
|
|
52363
53176
|
}
|
|
52364
53177
|
switch (status.recommendedAction) {
|
|
@@ -52438,6 +53251,9 @@ async function listApps(params) {
|
|
|
52438
53251
|
const api = await createCollabApiClient();
|
|
52439
53252
|
const result = await collabList({
|
|
52440
53253
|
api,
|
|
53254
|
+
ownership: params.ownership,
|
|
53255
|
+
accessScope: params.accessScope,
|
|
53256
|
+
createdBy: params.createdBy,
|
|
52441
53257
|
forked: params.forked,
|
|
52442
53258
|
limit: params.limit,
|
|
52443
53259
|
offset: params.offset
|
|
@@ -53388,13 +54204,16 @@ function registerCollabTools(server, context) {
|
|
|
53388
54204
|
});
|
|
53389
54205
|
registerTool(server, context, {
|
|
53390
54206
|
name: "remix_collab_list",
|
|
53391
|
-
description: "List Remix apps visible to the current authenticated user.",
|
|
54207
|
+
description: "List Remix apps visible to the current authenticated user. Defaults to membership-oriented discovery; pass accessScope=all_readable explicitly for broader readable discovery.",
|
|
53392
54208
|
access: "read",
|
|
53393
54209
|
inputSchema: listInputSchema,
|
|
53394
54210
|
outputSchema: listSuccessSchema,
|
|
53395
54211
|
run: async (args) => {
|
|
53396
54212
|
const input = external_exports.object(listInputSchema).parse(args);
|
|
53397
54213
|
return listApps({
|
|
54214
|
+
ownership: input.ownership,
|
|
54215
|
+
accessScope: input.accessScope,
|
|
54216
|
+
createdBy: input.createdBy,
|
|
53398
54217
|
forked: input.forked,
|
|
53399
54218
|
limit: input.limit,
|
|
53400
54219
|
offset: input.offset
|
|
@@ -53815,6 +54634,9 @@ var directoryListAppsInputSchema = {
|
|
|
53815
54634
|
...commonRequestFieldsSchema,
|
|
53816
54635
|
projectId: external_exports.string().trim().min(1).optional(),
|
|
53817
54636
|
organizationId: external_exports.string().trim().min(1).optional(),
|
|
54637
|
+
ownership: external_exports.enum(["mine", "shared", "all"]).optional(),
|
|
54638
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]).optional(),
|
|
54639
|
+
createdBy: external_exports.string().trim().min(1).optional(),
|
|
53818
54640
|
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
53819
54641
|
limit: external_exports.number().int().positive().max(50).optional(),
|
|
53820
54642
|
offset: external_exports.number().int().nonnegative().optional()
|
|
@@ -53850,6 +54672,9 @@ var listAppsDataSchema = external_exports.object({
|
|
|
53850
54672
|
filters: external_exports.object({
|
|
53851
54673
|
projectId: external_exports.string().nullable(),
|
|
53852
54674
|
organizationId: external_exports.string().nullable(),
|
|
54675
|
+
ownership: external_exports.enum(["mine", "shared", "all"]),
|
|
54676
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]),
|
|
54677
|
+
createdBy: external_exports.string().nullable(),
|
|
53853
54678
|
forked: external_exports.enum(["only", "exclude", "all"])
|
|
53854
54679
|
})
|
|
53855
54680
|
});
|
|
@@ -54104,6 +54929,9 @@ async function listApps2(params) {
|
|
|
54104
54929
|
await api.listApps({
|
|
54105
54930
|
projectId: params.projectId,
|
|
54106
54931
|
organizationId: params.organizationId,
|
|
54932
|
+
ownership: params.ownership ?? "all",
|
|
54933
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
54934
|
+
createdBy: params.createdBy,
|
|
54107
54935
|
forked: params.forked,
|
|
54108
54936
|
limit: pagination.limit + 1,
|
|
54109
54937
|
offset: pagination.offset
|
|
@@ -54120,6 +54948,9 @@ async function listApps2(params) {
|
|
|
54120
54948
|
filters: {
|
|
54121
54949
|
projectId: params.projectId ?? null,
|
|
54122
54950
|
organizationId: params.organizationId ?? null,
|
|
54951
|
+
ownership: params.ownership ?? "all",
|
|
54952
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
54953
|
+
createdBy: params.createdBy ?? null,
|
|
54123
54954
|
forked: params.forked ?? "all"
|
|
54124
54955
|
}
|
|
54125
54956
|
},
|
|
@@ -54301,7 +55132,7 @@ function registerIdentityTools(server, context) {
|
|
|
54301
55132
|
});
|
|
54302
55133
|
registerTool2(server, context, {
|
|
54303
55134
|
name: "remix_directory_list_apps",
|
|
54304
|
-
description: "List apps visible to the authenticated user, with optional organization
|
|
55135
|
+
description: "List apps visible to the authenticated user, with optional organization, project, ownership, and access-scope filters. Defaults to membership-oriented discovery unless accessScope=all_readable is passed explicitly.",
|
|
54305
55136
|
access: "read",
|
|
54306
55137
|
inputSchema: directoryListAppsInputSchema,
|
|
54307
55138
|
outputSchema: listAppsSuccessSchema,
|
|
@@ -54311,6 +55142,9 @@ function registerIdentityTools(server, context) {
|
|
|
54311
55142
|
return listApps2({
|
|
54312
55143
|
projectId: input.projectId,
|
|
54313
55144
|
organizationId: input.organizationId,
|
|
55145
|
+
ownership: input.ownership,
|
|
55146
|
+
accessScope: input.accessScope,
|
|
55147
|
+
createdBy: input.createdBy,
|
|
54314
55148
|
forked: input.forked,
|
|
54315
55149
|
limit: input.limit,
|
|
54316
55150
|
offset: input.offset,
|
|
@@ -55299,7 +56133,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
55299
56133
|
// package.json
|
|
55300
56134
|
var package_default = {
|
|
55301
56135
|
name: "@remixhq/claude-plugin",
|
|
55302
|
-
version: "0.1.
|
|
56136
|
+
version: "0.1.16",
|
|
55303
56137
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
55304
56138
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
55305
56139
|
license: "MIT",
|
|
@@ -55330,8 +56164,8 @@ var package_default = {
|
|
|
55330
56164
|
prepack: "npm run build"
|
|
55331
56165
|
},
|
|
55332
56166
|
dependencies: {
|
|
55333
|
-
"@remixhq/core": "^0.1.
|
|
55334
|
-
"@remixhq/mcp": "^0.1.
|
|
56167
|
+
"@remixhq/core": "^0.1.11",
|
|
56168
|
+
"@remixhq/mcp": "^0.1.11"
|
|
55335
56169
|
},
|
|
55336
56170
|
devDependencies: {
|
|
55337
56171
|
"@types/node": "^25.4.0",
|