@remixhq/claude-plugin 0.1.22 → 0.1.23
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 +1 -1
- package/dist/hook-post-collab.cjs +5 -5
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-pre-git.cjs +2 -2
- package/dist/hook-pre-git.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +449 -65
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +925 -487
- 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 +361 -486
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/safe-collab-workflow/SKILL.md +3 -3
- package/skills/submit-change-step/SKILL.md +6 -5
- package/skills/sync-and-reconcile/SKILL.md +1 -1
package/dist/mcp-server.cjs
CHANGED
|
@@ -36,8 +36,8 @@ var require_windows = __commonJS({
|
|
|
36
36
|
"use strict";
|
|
37
37
|
module2.exports = isexe;
|
|
38
38
|
isexe.sync = sync;
|
|
39
|
-
var
|
|
40
|
-
function checkPathExt(
|
|
39
|
+
var fs16 = require("fs");
|
|
40
|
+
function checkPathExt(path16, options) {
|
|
41
41
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
42
42
|
if (!pathext) {
|
|
43
43
|
return true;
|
|
@@ -48,25 +48,25 @@ var require_windows = __commonJS({
|
|
|
48
48
|
}
|
|
49
49
|
for (var i2 = 0; i2 < pathext.length; i2++) {
|
|
50
50
|
var p = pathext[i2].toLowerCase();
|
|
51
|
-
if (p &&
|
|
51
|
+
if (p && path16.substr(-p.length).toLowerCase() === p) {
|
|
52
52
|
return true;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
return false;
|
|
56
56
|
}
|
|
57
|
-
function checkStat(stat,
|
|
57
|
+
function checkStat(stat, path16, options) {
|
|
58
58
|
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
59
59
|
return false;
|
|
60
60
|
}
|
|
61
|
-
return checkPathExt(
|
|
61
|
+
return checkPathExt(path16, options);
|
|
62
62
|
}
|
|
63
|
-
function isexe(
|
|
64
|
-
|
|
65
|
-
cb(er, er ? false : checkStat(stat,
|
|
63
|
+
function isexe(path16, options, cb) {
|
|
64
|
+
fs16.stat(path16, function(er, stat) {
|
|
65
|
+
cb(er, er ? false : checkStat(stat, path16, options));
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
|
-
function sync(
|
|
69
|
-
return checkStat(
|
|
68
|
+
function sync(path16, options) {
|
|
69
|
+
return checkStat(fs16.statSync(path16), path16, options);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
});
|
|
@@ -77,14 +77,14 @@ var require_mode = __commonJS({
|
|
|
77
77
|
"use strict";
|
|
78
78
|
module2.exports = isexe;
|
|
79
79
|
isexe.sync = sync;
|
|
80
|
-
var
|
|
81
|
-
function isexe(
|
|
82
|
-
|
|
80
|
+
var fs16 = require("fs");
|
|
81
|
+
function isexe(path16, options, cb) {
|
|
82
|
+
fs16.stat(path16, function(er, stat) {
|
|
83
83
|
cb(er, er ? false : checkStat(stat, options));
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
|
-
function sync(
|
|
87
|
-
return checkStat(
|
|
86
|
+
function sync(path16, options) {
|
|
87
|
+
return checkStat(fs16.statSync(path16), options);
|
|
88
88
|
}
|
|
89
89
|
function checkStat(stat, options) {
|
|
90
90
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -109,7 +109,7 @@ var require_mode = __commonJS({
|
|
|
109
109
|
var require_isexe = __commonJS({
|
|
110
110
|
"node_modules/isexe/index.js"(exports2, module2) {
|
|
111
111
|
"use strict";
|
|
112
|
-
var
|
|
112
|
+
var fs16 = require("fs");
|
|
113
113
|
var core;
|
|
114
114
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
115
115
|
core = require_windows();
|
|
@@ -118,7 +118,7 @@ var require_isexe = __commonJS({
|
|
|
118
118
|
}
|
|
119
119
|
module2.exports = isexe;
|
|
120
120
|
isexe.sync = sync;
|
|
121
|
-
function isexe(
|
|
121
|
+
function isexe(path16, options, cb) {
|
|
122
122
|
if (typeof options === "function") {
|
|
123
123
|
cb = options;
|
|
124
124
|
options = {};
|
|
@@ -128,7 +128,7 @@ var require_isexe = __commonJS({
|
|
|
128
128
|
throw new TypeError("callback not provided");
|
|
129
129
|
}
|
|
130
130
|
return new Promise(function(resolve, reject) {
|
|
131
|
-
isexe(
|
|
131
|
+
isexe(path16, options || {}, function(er, is) {
|
|
132
132
|
if (er) {
|
|
133
133
|
reject(er);
|
|
134
134
|
} else {
|
|
@@ -137,7 +137,7 @@ var require_isexe = __commonJS({
|
|
|
137
137
|
});
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
-
core(
|
|
140
|
+
core(path16, options || {}, function(er, is) {
|
|
141
141
|
if (er) {
|
|
142
142
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
143
143
|
er = null;
|
|
@@ -147,9 +147,9 @@ var require_isexe = __commonJS({
|
|
|
147
147
|
cb(er, is);
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
|
-
function sync(
|
|
150
|
+
function sync(path16, options) {
|
|
151
151
|
try {
|
|
152
|
-
return core.sync(
|
|
152
|
+
return core.sync(path16, options || {});
|
|
153
153
|
} catch (er) {
|
|
154
154
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
155
155
|
return false;
|
|
@@ -166,7 +166,7 @@ var require_which = __commonJS({
|
|
|
166
166
|
"node_modules/which/which.js"(exports2, module2) {
|
|
167
167
|
"use strict";
|
|
168
168
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
169
|
-
var
|
|
169
|
+
var path16 = require("path");
|
|
170
170
|
var COLON = isWindows ? ";" : ":";
|
|
171
171
|
var isexe = require_isexe();
|
|
172
172
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -204,7 +204,7 @@ var require_which = __commonJS({
|
|
|
204
204
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
205
205
|
const ppRaw = pathEnv[i2];
|
|
206
206
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
207
|
-
const pCmd =
|
|
207
|
+
const pCmd = path16.join(pathPart, cmd);
|
|
208
208
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
209
209
|
resolve(subStep(p, i2, 0));
|
|
210
210
|
});
|
|
@@ -231,7 +231,7 @@ var require_which = __commonJS({
|
|
|
231
231
|
for (let i2 = 0; i2 < pathEnv.length; i2++) {
|
|
232
232
|
const ppRaw = pathEnv[i2];
|
|
233
233
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
234
|
-
const pCmd =
|
|
234
|
+
const pCmd = path16.join(pathPart, cmd);
|
|
235
235
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
236
236
|
for (let j = 0; j < pathExt.length; j++) {
|
|
237
237
|
const cur = p + pathExt[j];
|
|
@@ -279,7 +279,7 @@ var require_path_key = __commonJS({
|
|
|
279
279
|
var require_resolveCommand = __commonJS({
|
|
280
280
|
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
|
|
281
281
|
"use strict";
|
|
282
|
-
var
|
|
282
|
+
var path16 = require("path");
|
|
283
283
|
var which = require_which();
|
|
284
284
|
var getPathKey = require_path_key();
|
|
285
285
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -297,7 +297,7 @@ var require_resolveCommand = __commonJS({
|
|
|
297
297
|
try {
|
|
298
298
|
resolved = which.sync(parsed.command, {
|
|
299
299
|
path: env[getPathKey({ env })],
|
|
300
|
-
pathExt: withoutPathExt ?
|
|
300
|
+
pathExt: withoutPathExt ? path16.delimiter : void 0
|
|
301
301
|
});
|
|
302
302
|
} catch (e) {
|
|
303
303
|
} finally {
|
|
@@ -306,7 +306,7 @@ var require_resolveCommand = __commonJS({
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
if (resolved) {
|
|
309
|
-
resolved =
|
|
309
|
+
resolved = path16.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
310
310
|
}
|
|
311
311
|
return resolved;
|
|
312
312
|
}
|
|
@@ -360,8 +360,8 @@ var require_shebang_command = __commonJS({
|
|
|
360
360
|
if (!match) {
|
|
361
361
|
return null;
|
|
362
362
|
}
|
|
363
|
-
const [
|
|
364
|
-
const binary =
|
|
363
|
+
const [path16, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
364
|
+
const binary = path16.split("/").pop();
|
|
365
365
|
if (binary === "env") {
|
|
366
366
|
return argument;
|
|
367
367
|
}
|
|
@@ -374,16 +374,16 @@ var require_shebang_command = __commonJS({
|
|
|
374
374
|
var require_readShebang = __commonJS({
|
|
375
375
|
"node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) {
|
|
376
376
|
"use strict";
|
|
377
|
-
var
|
|
377
|
+
var fs16 = require("fs");
|
|
378
378
|
var shebangCommand = require_shebang_command();
|
|
379
379
|
function readShebang(command) {
|
|
380
380
|
const size = 150;
|
|
381
381
|
const buffer = Buffer.alloc(size);
|
|
382
382
|
let fd;
|
|
383
383
|
try {
|
|
384
|
-
fd =
|
|
385
|
-
|
|
386
|
-
|
|
384
|
+
fd = fs16.openSync(command, "r");
|
|
385
|
+
fs16.readSync(fd, buffer, 0, size, 0);
|
|
386
|
+
fs16.closeSync(fd);
|
|
387
387
|
} catch (e) {
|
|
388
388
|
}
|
|
389
389
|
return shebangCommand(buffer.toString());
|
|
@@ -396,7 +396,7 @@ var require_readShebang = __commonJS({
|
|
|
396
396
|
var require_parse = __commonJS({
|
|
397
397
|
"node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
|
|
398
398
|
"use strict";
|
|
399
|
-
var
|
|
399
|
+
var path16 = require("path");
|
|
400
400
|
var resolveCommand = require_resolveCommand();
|
|
401
401
|
var escape2 = require_escape();
|
|
402
402
|
var readShebang = require_readShebang();
|
|
@@ -421,7 +421,7 @@ var require_parse = __commonJS({
|
|
|
421
421
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
422
422
|
if (parsed.options.forceShell || needsShell) {
|
|
423
423
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
424
|
-
parsed.command =
|
|
424
|
+
parsed.command = path16.normalize(parsed.command);
|
|
425
425
|
parsed.command = escape2.command(parsed.command);
|
|
426
426
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
427
427
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -3724,8 +3724,8 @@ var require_utils = __commonJS({
|
|
|
3724
3724
|
}
|
|
3725
3725
|
return ind;
|
|
3726
3726
|
}
|
|
3727
|
-
function removeDotSegments(
|
|
3728
|
-
let input =
|
|
3727
|
+
function removeDotSegments(path16) {
|
|
3728
|
+
let input = path16;
|
|
3729
3729
|
const output = [];
|
|
3730
3730
|
let nextSlash = -1;
|
|
3731
3731
|
let len = 0;
|
|
@@ -3924,8 +3924,8 @@ var require_schemes = __commonJS({
|
|
|
3924
3924
|
wsComponent.secure = void 0;
|
|
3925
3925
|
}
|
|
3926
3926
|
if (wsComponent.resourceName) {
|
|
3927
|
-
const [
|
|
3928
|
-
wsComponent.path =
|
|
3927
|
+
const [path16, query] = wsComponent.resourceName.split("?");
|
|
3928
|
+
wsComponent.path = path16 && path16 !== "/" ? path16 : void 0;
|
|
3929
3929
|
wsComponent.query = query;
|
|
3930
3930
|
wsComponent.resourceName = void 0;
|
|
3931
3931
|
}
|
|
@@ -7287,12 +7287,12 @@ var require_dist = __commonJS({
|
|
|
7287
7287
|
throw new Error(`Unknown format "${name}"`);
|
|
7288
7288
|
return f;
|
|
7289
7289
|
};
|
|
7290
|
-
function addFormats(ajv, list,
|
|
7290
|
+
function addFormats(ajv, list, fs16, exportName) {
|
|
7291
7291
|
var _a;
|
|
7292
7292
|
var _b;
|
|
7293
7293
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
7294
7294
|
for (const f of list)
|
|
7295
|
-
ajv.addFormat(f,
|
|
7295
|
+
ajv.addFormat(f, fs16[f]);
|
|
7296
7296
|
}
|
|
7297
7297
|
module2.exports = exports2 = formatsPlugin;
|
|
7298
7298
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -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, path16) {
|
|
7502
|
+
if (!path16)
|
|
7503
7503
|
return obj;
|
|
7504
|
-
return
|
|
7504
|
+
return path16.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(path16, 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(path16);
|
|
7829
7829
|
return iss;
|
|
7830
7830
|
});
|
|
7831
7831
|
}
|
|
@@ -13430,21 +13430,27 @@ var REMIX_ERROR_CODES = {
|
|
|
13430
13430
|
PREFERRED_BRANCH_MISMATCH: "PREFERRED_BRANCH_MISMATCH"
|
|
13431
13431
|
};
|
|
13432
13432
|
|
|
13433
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
13433
|
+
// node_modules/@remixhq/core/dist/chunk-7XJGOKEO.js
|
|
13434
13434
|
var RemixError = class extends Error {
|
|
13435
13435
|
code;
|
|
13436
13436
|
exitCode;
|
|
13437
13437
|
hint;
|
|
13438
|
+
// HTTP status code when this error originates from an API response.
|
|
13439
|
+
// null for non-HTTP errors (validation, local IO, programming bugs).
|
|
13440
|
+
// Callers use this to distinguish transient (5xx) from permanent (4xx)
|
|
13441
|
+
// API failures without resorting to error-message string matching.
|
|
13442
|
+
statusCode;
|
|
13438
13443
|
constructor(message, opts) {
|
|
13439
13444
|
super(message);
|
|
13440
13445
|
this.name = "RemixError";
|
|
13441
13446
|
this.code = opts?.code ?? null;
|
|
13442
13447
|
this.exitCode = opts?.exitCode ?? 1;
|
|
13443
13448
|
this.hint = opts?.hint ?? null;
|
|
13449
|
+
this.statusCode = opts?.statusCode ?? null;
|
|
13444
13450
|
}
|
|
13445
13451
|
};
|
|
13446
13452
|
|
|
13447
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
13453
|
+
// node_modules/@remixhq/core/dist/chunk-S4ECO35X.js
|
|
13448
13454
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
13449
13455
|
var import_crypto = require("crypto");
|
|
13450
13456
|
var import_os = __toESM(require("os"), 1);
|
|
@@ -17831,13 +17837,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
|
|
|
17831
17837
|
}
|
|
17832
17838
|
};
|
|
17833
17839
|
var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
17834
|
-
for (const { path:
|
|
17835
|
-
const pathString = typeof
|
|
17840
|
+
for (const { path: path16, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
|
|
17841
|
+
const pathString = typeof path16 === "string" ? path16 : path16.toString();
|
|
17836
17842
|
if (append || outputFiles.has(pathString)) {
|
|
17837
|
-
(0, import_node_fs4.appendFileSync)(
|
|
17843
|
+
(0, import_node_fs4.appendFileSync)(path16, serializedResult);
|
|
17838
17844
|
} else {
|
|
17839
17845
|
outputFiles.add(pathString);
|
|
17840
|
-
(0, import_node_fs4.writeFileSync)(
|
|
17846
|
+
(0, import_node_fs4.writeFileSync)(path16, serializedResult);
|
|
17841
17847
|
}
|
|
17842
17848
|
}
|
|
17843
17849
|
};
|
|
@@ -20225,7 +20231,7 @@ var {
|
|
|
20225
20231
|
getCancelSignal: getCancelSignal2
|
|
20226
20232
|
} = getIpcExport();
|
|
20227
20233
|
|
|
20228
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
20234
|
+
// node_modules/@remixhq/core/dist/chunk-S4ECO35X.js
|
|
20229
20235
|
var GIT_REMOTE_PROTOCOL_RE = /^(https?|ssh):\/\//i;
|
|
20230
20236
|
var SCP_LIKE_GIT_REMOTE_RE = /^(?<user>[^@\s]+)@(?<host>[^:\s]+):(?<path>[^\\\s]+)$/;
|
|
20231
20237
|
var CANONICAL_GIT_REMOTE_RE = /^(?<host>(?:localhost|[a-z0-9.-]+))\/(?<path>[^\\\s]+)$/i;
|
|
@@ -20691,7 +20697,7 @@ function summarizeUnifiedDiff(diff) {
|
|
|
20691
20697
|
return { changedFilesCount, insertions, deletions };
|
|
20692
20698
|
}
|
|
20693
20699
|
|
|
20694
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
20700
|
+
// node_modules/@remixhq/core/dist/chunk-DBVN42RF.js
|
|
20695
20701
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
20696
20702
|
var import_path2 = __toESM(require("path"), 1);
|
|
20697
20703
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
@@ -21044,14 +21050,11 @@ var import_crypto8 = __toESM(require("crypto"), 1);
|
|
|
21044
21050
|
var import_fs = __toESM(require("fs"), 1);
|
|
21045
21051
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
21046
21052
|
var import_stream3 = require("stream");
|
|
21047
|
-
var import_crypto9 = require("crypto");
|
|
21048
21053
|
var import_promises23 = __toESM(require("fs/promises"), 1);
|
|
21054
|
+
var import_os6 = __toESM(require("os"), 1);
|
|
21049
21055
|
var import_path12 = __toESM(require("path"), 1);
|
|
21050
21056
|
var import_promises24 = __toESM(require("fs/promises"), 1);
|
|
21051
|
-
var import_os6 = __toESM(require("os"), 1);
|
|
21052
21057
|
var import_path13 = __toESM(require("path"), 1);
|
|
21053
|
-
var import_promises25 = __toESM(require("fs/promises"), 1);
|
|
21054
|
-
var import_path14 = __toESM(require("path"), 1);
|
|
21055
21058
|
var APP_DELTA_CACHE_TTL_MS = 5e3;
|
|
21056
21059
|
var appDeltaCache = /* @__PURE__ */ new Map();
|
|
21057
21060
|
var cacheClock = () => Date.now();
|
|
@@ -21060,6 +21063,8 @@ function buildAppDeltaCacheKey(appId, payload) {
|
|
|
21060
21063
|
appId,
|
|
21061
21064
|
payload.baseHeadHash,
|
|
21062
21065
|
payload.targetHeadHash ?? "",
|
|
21066
|
+
payload.baseRevisionId ?? "",
|
|
21067
|
+
payload.targetRevisionId ?? "",
|
|
21063
21068
|
payload.localSnapshotHash ?? "",
|
|
21064
21069
|
payload.repoFingerprint ?? "",
|
|
21065
21070
|
payload.remoteUrl ?? "",
|
|
@@ -21188,9 +21193,6 @@ function getAsyncJobDir(jobId) {
|
|
|
21188
21193
|
function getAsyncJobFilePath(jobId) {
|
|
21189
21194
|
return import_path5.default.join(getAsyncJobDir(jobId), "job.json");
|
|
21190
21195
|
}
|
|
21191
|
-
function getAsyncJobBundlePath(jobId) {
|
|
21192
|
-
return import_path5.default.join(getAsyncJobDir(jobId), "bundle.bundle");
|
|
21193
|
-
}
|
|
21194
21196
|
function getLogsRoot() {
|
|
21195
21197
|
return import_path5.default.join(getCollabStateRoot(), "logs");
|
|
21196
21198
|
}
|
|
@@ -21459,11 +21461,11 @@ async function readLocalBaseline(params) {
|
|
|
21459
21461
|
const raw = await import_promises16.default.readFile(getBaselinePath(params), "utf8");
|
|
21460
21462
|
const parsed = JSON.parse(raw);
|
|
21461
21463
|
if (!parsed || typeof parsed !== "object") return null;
|
|
21462
|
-
if (parsed.schemaVersion
|
|
21464
|
+
if (![1, 2].includes(Number(parsed.schemaVersion)) || typeof parsed.key !== "string" || typeof parsed.repoRoot !== "string") {
|
|
21463
21465
|
return null;
|
|
21464
21466
|
}
|
|
21465
21467
|
return {
|
|
21466
|
-
schemaVersion: 1,
|
|
21468
|
+
schemaVersion: Number(parsed.schemaVersion) === 2 ? 2 : 1,
|
|
21467
21469
|
key: parsed.key,
|
|
21468
21470
|
repoRoot: parsed.repoRoot,
|
|
21469
21471
|
repoFingerprint: parsed.repoFingerprint ?? null,
|
|
@@ -21472,6 +21474,8 @@ async function readLocalBaseline(params) {
|
|
|
21472
21474
|
branchName: parsed.branchName ?? null,
|
|
21473
21475
|
lastSnapshotId: parsed.lastSnapshotId ?? null,
|
|
21474
21476
|
lastSnapshotHash: parsed.lastSnapshotHash ?? null,
|
|
21477
|
+
lastServerRevisionId: parsed.lastServerRevisionId ?? null,
|
|
21478
|
+
lastServerTreeHash: parsed.lastServerTreeHash ?? null,
|
|
21475
21479
|
lastServerHeadHash: parsed.lastServerHeadHash ?? null,
|
|
21476
21480
|
lastSeenLocalCommitHash: parsed.lastSeenLocalCommitHash ?? null,
|
|
21477
21481
|
updatedAt: String(parsed.updatedAt ?? "")
|
|
@@ -21483,7 +21487,7 @@ async function readLocalBaseline(params) {
|
|
|
21483
21487
|
async function writeLocalBaseline(baseline) {
|
|
21484
21488
|
const key = buildLaneStateKey(baseline);
|
|
21485
21489
|
const normalized = {
|
|
21486
|
-
schemaVersion:
|
|
21490
|
+
schemaVersion: 2,
|
|
21487
21491
|
key,
|
|
21488
21492
|
repoRoot: baseline.repoRoot,
|
|
21489
21493
|
repoFingerprint: baseline.repoFingerprint ?? null,
|
|
@@ -21492,6 +21496,8 @@ async function writeLocalBaseline(baseline) {
|
|
|
21492
21496
|
branchName: baseline.branchName ?? null,
|
|
21493
21497
|
lastSnapshotId: baseline.lastSnapshotId ?? null,
|
|
21494
21498
|
lastSnapshotHash: baseline.lastSnapshotHash ?? null,
|
|
21499
|
+
lastServerRevisionId: baseline.lastServerRevisionId ?? null,
|
|
21500
|
+
lastServerTreeHash: baseline.lastServerTreeHash ?? null,
|
|
21495
21501
|
lastServerHeadHash: baseline.lastServerHeadHash ?? null,
|
|
21496
21502
|
lastSeenLocalCommitHash: baseline.lastSeenLocalCommitHash ?? null,
|
|
21497
21503
|
updatedAt: baseline.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -21833,6 +21839,7 @@ function normalizeJob2(input) {
|
|
|
21833
21839
|
prompt: input.prompt,
|
|
21834
21840
|
assistantResponse: input.assistantResponse,
|
|
21835
21841
|
baselineSnapshotId: input.baselineSnapshotId ?? null,
|
|
21842
|
+
baselineServerRevisionId: input.baselineServerRevisionId ?? null,
|
|
21836
21843
|
baselineServerHeadHash: input.baselineServerHeadHash ?? null,
|
|
21837
21844
|
currentSnapshotId: input.currentSnapshotId,
|
|
21838
21845
|
capturedAt: input.capturedAt ?? now,
|
|
@@ -21862,6 +21869,7 @@ async function readPendingFinalizeJob(jobId) {
|
|
|
21862
21869
|
prompt: String(parsed.prompt ?? ""),
|
|
21863
21870
|
assistantResponse: String(parsed.assistantResponse ?? ""),
|
|
21864
21871
|
baselineSnapshotId: parsed.baselineSnapshotId ?? null,
|
|
21872
|
+
baselineServerRevisionId: parsed.baselineServerRevisionId ?? null,
|
|
21865
21873
|
baselineServerHeadHash: parsed.baselineServerHeadHash ?? null,
|
|
21866
21874
|
currentSnapshotId: String(parsed.currentSnapshotId ?? ""),
|
|
21867
21875
|
capturedAt: parsed.capturedAt,
|
|
@@ -22588,6 +22596,8 @@ function buildBaseState() {
|
|
|
22588
22596
|
branchName: null,
|
|
22589
22597
|
localCommitHash: null,
|
|
22590
22598
|
currentSnapshotHash: null,
|
|
22599
|
+
currentServerRevisionId: null,
|
|
22600
|
+
currentServerTreeHash: null,
|
|
22591
22601
|
currentServerHeadHash: null,
|
|
22592
22602
|
currentServerHeadCommitId: null,
|
|
22593
22603
|
worktreeClean: false,
|
|
@@ -22621,6 +22631,8 @@ function buildBaseState() {
|
|
|
22621
22631
|
baseline: {
|
|
22622
22632
|
lastSnapshotId: null,
|
|
22623
22633
|
lastSnapshotHash: null,
|
|
22634
|
+
lastServerRevisionId: null,
|
|
22635
|
+
lastServerTreeHash: null,
|
|
22624
22636
|
lastServerHeadHash: null,
|
|
22625
22637
|
lastSeenLocalCommitHash: null
|
|
22626
22638
|
}
|
|
@@ -22747,6 +22759,8 @@ async function collabDetectRepoState(params) {
|
|
|
22747
22759
|
summarizeAsyncJobs({ repoRoot, branchName: binding.branchName ?? null })
|
|
22748
22760
|
]);
|
|
22749
22761
|
const appHead = unwrapResponseObject(headResp, "app head");
|
|
22762
|
+
detected.currentServerRevisionId = appHead.headRevisionId ?? null;
|
|
22763
|
+
detected.currentServerTreeHash = appHead.treeHash ?? null;
|
|
22750
22764
|
detected.currentServerHeadHash = appHead.headCommitHash;
|
|
22751
22765
|
detected.currentServerHeadCommitId = appHead.headCommitId;
|
|
22752
22766
|
detected.currentSnapshotHash = inspection.snapshotHash;
|
|
@@ -22755,6 +22769,8 @@ async function collabDetectRepoState(params) {
|
|
|
22755
22769
|
detected.baseline = {
|
|
22756
22770
|
lastSnapshotId: baseline?.lastSnapshotId ?? null,
|
|
22757
22771
|
lastSnapshotHash: baseline?.lastSnapshotHash ?? null,
|
|
22772
|
+
lastServerRevisionId: baseline?.lastServerRevisionId ?? null,
|
|
22773
|
+
lastServerTreeHash: baseline?.lastServerTreeHash ?? null,
|
|
22758
22774
|
lastServerHeadHash: baseline?.lastServerHeadHash ?? null,
|
|
22759
22775
|
lastSeenLocalCommitHash: baseline?.lastSeenLocalCommitHash ?? null
|
|
22760
22776
|
};
|
|
@@ -22764,6 +22780,7 @@ async function collabDetectRepoState(params) {
|
|
|
22764
22780
|
const bootstrapResp = await params.api.getAppDelta(binding.currentAppId, {
|
|
22765
22781
|
baseHeadHash: localCommitHash,
|
|
22766
22782
|
targetHeadHash: appHead.headCommitHash,
|
|
22783
|
+
targetRevisionId: appHead.headRevisionId,
|
|
22767
22784
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
22768
22785
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
22769
22786
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -22786,7 +22803,7 @@ async function collabDetectRepoState(params) {
|
|
|
22786
22803
|
}
|
|
22787
22804
|
}
|
|
22788
22805
|
detected.repoState = "external_local_base_changed";
|
|
22789
|
-
detected.hint = "No local Remix baseline exists for this lane yet. Run `remix collab
|
|
22806
|
+
detected.hint = "No local Remix revision baseline exists for this lane yet. Run `remix collab init` or sync this lane to seed the baseline.";
|
|
22790
22807
|
return detected;
|
|
22791
22808
|
}
|
|
22792
22809
|
const localHeadMovedSinceBaseline = Boolean(baseline.lastSeenLocalCommitHash) && localCommitHash !== baseline.lastSeenLocalCommitHash;
|
|
@@ -22805,7 +22822,30 @@ async function collabDetectRepoState(params) {
|
|
|
22805
22822
|
return detected;
|
|
22806
22823
|
}
|
|
22807
22824
|
const localChanged = inspection.snapshotHash !== baseline.lastSnapshotHash;
|
|
22808
|
-
const
|
|
22825
|
+
const serverHeadChanged = appHead.headCommitHash !== baseline.lastServerHeadHash;
|
|
22826
|
+
const revisionChanged = Boolean(
|
|
22827
|
+
baseline.lastServerRevisionId && (appHead.headRevisionId ?? null) !== baseline.lastServerRevisionId
|
|
22828
|
+
);
|
|
22829
|
+
const equivalentRevisionDrift = revisionChanged && !serverHeadChanged;
|
|
22830
|
+
if (equivalentRevisionDrift) {
|
|
22831
|
+
await writeLocalBaseline({
|
|
22832
|
+
repoRoot,
|
|
22833
|
+
repoFingerprint: binding.repoFingerprint,
|
|
22834
|
+
laneId: binding.laneId,
|
|
22835
|
+
currentAppId: binding.currentAppId,
|
|
22836
|
+
branchName: binding.branchName,
|
|
22837
|
+
lastSnapshotId: baseline.lastSnapshotId,
|
|
22838
|
+
lastSnapshotHash: baseline.lastSnapshotHash,
|
|
22839
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
22840
|
+
lastServerTreeHash: appHead.treeHash ?? baseline.lastServerTreeHash ?? null,
|
|
22841
|
+
lastServerHeadHash: appHead.headCommitHash,
|
|
22842
|
+
lastSeenLocalCommitHash: baseline.lastSeenLocalCommitHash
|
|
22843
|
+
});
|
|
22844
|
+
detected.baseline.lastServerRevisionId = appHead.headRevisionId ?? null;
|
|
22845
|
+
detected.baseline.lastServerTreeHash = appHead.treeHash ?? baseline.lastServerTreeHash ?? null;
|
|
22846
|
+
detected.baseline.lastServerHeadHash = appHead.headCommitHash;
|
|
22847
|
+
}
|
|
22848
|
+
const serverChanged = serverHeadChanged;
|
|
22809
22849
|
if (!localChanged && !serverChanged) {
|
|
22810
22850
|
detected.repoState = "idle";
|
|
22811
22851
|
return detected;
|
|
@@ -23229,6 +23269,7 @@ function buildWorkspaceMetadata(params) {
|
|
|
23229
23269
|
recordingMode: "boundary_delta",
|
|
23230
23270
|
baselineSnapshotId: params.baselineSnapshotId,
|
|
23231
23271
|
currentSnapshotId: params.currentSnapshotId,
|
|
23272
|
+
baselineServerRevisionId: params.baselineServerRevisionId ?? null,
|
|
23232
23273
|
baselineServerHeadHash: params.baselineServerHeadHash,
|
|
23233
23274
|
currentSnapshotHash: params.currentSnapshotHash,
|
|
23234
23275
|
localCommitHash: params.localCommitHash,
|
|
@@ -23307,12 +23348,12 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23307
23348
|
throw buildFinalizeCliError({
|
|
23308
23349
|
message: "Local baseline is missing for this queued finalize job.",
|
|
23309
23350
|
exitCode: 2,
|
|
23310
|
-
hint: "Run `remix collab
|
|
23351
|
+
hint: "Run `remix collab init` to seed this checkout's revision baseline.",
|
|
23311
23352
|
disposition: "terminal",
|
|
23312
23353
|
reason: "baseline_missing"
|
|
23313
23354
|
});
|
|
23314
23355
|
}
|
|
23315
|
-
const baselineDrifted = baseline.lastSnapshotId !== job.baselineSnapshotId || baseline.lastServerHeadHash !== job.baselineServerHeadHash;
|
|
23356
|
+
const baselineDrifted = baseline.lastSnapshotId !== job.baselineSnapshotId || (job.baselineServerRevisionId ? baseline.lastServerRevisionId !== job.baselineServerRevisionId : false) || baseline.lastServerHeadHash !== job.baselineServerHeadHash;
|
|
23316
23357
|
const appHead = unwrapResponseObject(appHeadResp, "app head");
|
|
23317
23358
|
const remoteUrl = readMetadataString(job, "remoteUrl");
|
|
23318
23359
|
const defaultBranch = readMetadataString(job, "defaultBranch");
|
|
@@ -23335,12 +23376,13 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23335
23376
|
throw buildFinalizeCliError({
|
|
23336
23377
|
message: "Finalize queue baseline drifted before this job was processed.",
|
|
23337
23378
|
exitCode: 1,
|
|
23338
|
-
hint: "Process queued finalize jobs in capture order, or
|
|
23379
|
+
hint: "Process queued finalize jobs in capture order, or run `remix collab init` to refresh the revision baseline before retrying.",
|
|
23339
23380
|
disposition: "terminal",
|
|
23340
23381
|
reason: "baseline_drifted"
|
|
23341
23382
|
});
|
|
23342
23383
|
}
|
|
23343
|
-
|
|
23384
|
+
const serverStillAtBaseline = job.baselineServerRevisionId ? appHead.headRevisionId === job.baselineServerRevisionId : appHead.headCommitHash === job.baselineServerHeadHash;
|
|
23385
|
+
if (!serverStillAtBaseline) {
|
|
23344
23386
|
throw buildFinalizeCliError({
|
|
23345
23387
|
message: "Server lane changed before a no-diff turn could be recorded.",
|
|
23346
23388
|
exitCode: 2,
|
|
@@ -23362,6 +23404,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23362
23404
|
defaultBranch,
|
|
23363
23405
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23364
23406
|
currentSnapshotId: job.currentSnapshotId,
|
|
23407
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23365
23408
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23366
23409
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23367
23410
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23382,6 +23425,8 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23382
23425
|
branchName: job.branchName,
|
|
23383
23426
|
lastSnapshotId: snapshot.id,
|
|
23384
23427
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
23428
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
23429
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
23385
23430
|
lastServerHeadHash: appHead.headCommitHash,
|
|
23386
23431
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23387
23432
|
});
|
|
@@ -23402,14 +23447,14 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23402
23447
|
};
|
|
23403
23448
|
}
|
|
23404
23449
|
const localBaselineAdvanced = baseline.lastSnapshotId !== job.baselineSnapshotId;
|
|
23405
|
-
const serverHeadAdvanced = appHead.headCommitHash !== job.baselineServerHeadHash;
|
|
23450
|
+
const serverHeadAdvanced = job.baselineServerRevisionId ? appHead.headRevisionId !== job.baselineServerRevisionId : appHead.headCommitHash !== job.baselineServerHeadHash;
|
|
23406
23451
|
if (baselineDrifted) {
|
|
23407
23452
|
const consistentAdvance = localBaselineAdvanced && serverHeadAdvanced;
|
|
23408
23453
|
if (!consistentAdvance) {
|
|
23409
23454
|
throw buildFinalizeCliError({
|
|
23410
23455
|
message: `Finalize queue baseline advanced inconsistently before this job was processed (localBaselineAdvanced=${localBaselineAdvanced}, serverHeadAdvanced=${serverHeadAdvanced}, jobBaselineSnapshotId=${job.baselineSnapshotId ?? "null"}, liveBaselineSnapshotId=${baseline.lastSnapshotId ?? "null"}, jobBaselineServerHeadHash=${job.baselineServerHeadHash ?? "null"}, liveBaselineServerHeadHash=${baseline.lastServerHeadHash ?? "null"}, currentAppHeadHash=${appHead.headCommitHash}). This indicates local Remix state diverged from the backend in a way that should not be reachable in normal operation; please report this as a bug.`,
|
|
23411
23456
|
exitCode: 1,
|
|
23412
|
-
hint: "Run `remix collab status` to inspect, then
|
|
23457
|
+
hint: "Run `remix collab status` to inspect, then sync or reconcile before retrying.",
|
|
23413
23458
|
disposition: "terminal",
|
|
23414
23459
|
reason: "baseline_drifted"
|
|
23415
23460
|
});
|
|
@@ -23417,6 +23462,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23417
23462
|
}
|
|
23418
23463
|
let submissionDiff = diffResult.diff;
|
|
23419
23464
|
let submissionBaseHeadHash = job.baselineServerHeadHash;
|
|
23465
|
+
let submissionBaseRevisionId = job.baselineServerRevisionId;
|
|
23420
23466
|
let replayedFromBaseHash = null;
|
|
23421
23467
|
if (!submissionBaseHeadHash) {
|
|
23422
23468
|
throw buildFinalizeCliError({
|
|
@@ -23434,7 +23480,9 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23434
23480
|
assistantResponse: job.assistantResponse,
|
|
23435
23481
|
diff: diffResult.diff,
|
|
23436
23482
|
baseCommitHash: submissionBaseHeadHash,
|
|
23483
|
+
baseRevisionId: job.baselineServerRevisionId,
|
|
23437
23484
|
targetHeadCommitHash: appHead.headCommitHash,
|
|
23485
|
+
targetRevisionId: appHead.headRevisionId,
|
|
23438
23486
|
expectedPaths: diffResult.changedPaths,
|
|
23439
23487
|
actor,
|
|
23440
23488
|
workspaceMetadata: buildWorkspaceMetadata({
|
|
@@ -23444,6 +23492,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23444
23492
|
defaultBranch,
|
|
23445
23493
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23446
23494
|
currentSnapshotId: job.currentSnapshotId,
|
|
23495
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23447
23496
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23448
23497
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23449
23498
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23469,6 +23518,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23469
23518
|
submissionDiff = replayDiff.diff;
|
|
23470
23519
|
replayedFromBaseHash = submissionBaseHeadHash;
|
|
23471
23520
|
submissionBaseHeadHash = appHead.headCommitHash;
|
|
23521
|
+
submissionBaseRevisionId = appHead.headRevisionId;
|
|
23472
23522
|
} catch (error2) {
|
|
23473
23523
|
if (error2 instanceof RemixError && error2.finalizeDisposition === void 0) {
|
|
23474
23524
|
const detail = error2.hint ? `${error2.message} (${error2.hint})` : error2.message;
|
|
@@ -23490,6 +23540,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23490
23540
|
assistantResponse: job.assistantResponse,
|
|
23491
23541
|
diff: submissionDiff,
|
|
23492
23542
|
baseCommitHash: submissionBaseHeadHash,
|
|
23543
|
+
baseRevisionId: submissionBaseRevisionId,
|
|
23493
23544
|
headCommitHash: submissionBaseHeadHash,
|
|
23494
23545
|
changedFilesCount: diffResult.stats.changedFilesCount,
|
|
23495
23546
|
insertions: diffResult.stats.insertions,
|
|
@@ -23502,6 +23553,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23502
23553
|
defaultBranch,
|
|
23503
23554
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23504
23555
|
currentSnapshotId: job.currentSnapshotId,
|
|
23556
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23505
23557
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23506
23558
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23507
23559
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23523,11 +23575,28 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23523
23575
|
throw buildFinalizeCliError({
|
|
23524
23576
|
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
23525
23577
|
exitCode: 1,
|
|
23526
|
-
hint: "This is a backend invariant violation; retry will not help.
|
|
23578
|
+
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
23527
23579
|
disposition: "terminal",
|
|
23528
23580
|
reason: "missing_head_commit_hash"
|
|
23529
23581
|
});
|
|
23530
23582
|
}
|
|
23583
|
+
let nextServerRevisionId = typeof changeStep.resultRevisionId === "string" ? changeStep.resultRevisionId.trim() : "";
|
|
23584
|
+
let nextServerTreeHash = null;
|
|
23585
|
+
if (!nextServerRevisionId) {
|
|
23586
|
+
const freshHeadResp = await params.api.getAppHead(job.currentAppId);
|
|
23587
|
+
const freshHead = unwrapResponseObject(freshHeadResp, "app head");
|
|
23588
|
+
if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
|
|
23589
|
+
throw buildFinalizeCliError({
|
|
23590
|
+
message: "Backend returned a succeeded change step without a matching result revision.",
|
|
23591
|
+
exitCode: 1,
|
|
23592
|
+
hint: "The local baseline was not advanced because the post-step revision could not be verified. Restart the backend/CLI and retry after checking `remix collab status`.",
|
|
23593
|
+
disposition: "terminal",
|
|
23594
|
+
reason: "missing_result_revision_id"
|
|
23595
|
+
});
|
|
23596
|
+
}
|
|
23597
|
+
nextServerRevisionId = freshHead.headRevisionId;
|
|
23598
|
+
nextServerTreeHash = freshHead.treeHash ?? null;
|
|
23599
|
+
}
|
|
23531
23600
|
await writeLocalBaseline({
|
|
23532
23601
|
repoRoot: job.repoRoot,
|
|
23533
23602
|
repoFingerprint: job.repoFingerprint,
|
|
@@ -23536,6 +23605,8 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23536
23605
|
branchName: job.branchName,
|
|
23537
23606
|
lastSnapshotId: snapshot.id,
|
|
23538
23607
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
23608
|
+
lastServerRevisionId: nextServerRevisionId,
|
|
23609
|
+
lastServerTreeHash: nextServerTreeHash,
|
|
23539
23610
|
lastServerHeadHash: nextServerHeadHash,
|
|
23540
23611
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23541
23612
|
});
|
|
@@ -23596,9 +23667,10 @@ var FINALIZE_PREFLIGHT_FAILURE_CODES = [
|
|
|
23596
23667
|
// Server has commits we don't. Fix: `remix collab sync` (safe to
|
|
23597
23668
|
// auto-run for fast-forward; non-FF refused by the command itself).
|
|
23598
23669
|
"pull_required",
|
|
23599
|
-
//
|
|
23600
|
-
|
|
23601
|
-
|
|
23670
|
+
// Both local and server changed. Fix: inspect and apply reconcile.
|
|
23671
|
+
"reconcile_required",
|
|
23672
|
+
// Local revision baseline is missing. Fix: `remix collab init` or sync.
|
|
23673
|
+
"baseline_missing"
|
|
23602
23674
|
];
|
|
23603
23675
|
var CODE_SET = new Set(FINALIZE_PREFLIGHT_FAILURE_CODES);
|
|
23604
23676
|
var DEFAULT_ACQUIRE_TIMEOUT_MS = 15e3;
|
|
@@ -23818,7 +23890,7 @@ async function ensureWorkspaceMatchesBaseline(params) {
|
|
|
23818
23890
|
if (!baseline?.lastSnapshotHash || !baseline.lastServerHeadHash) {
|
|
23819
23891
|
throw new RemixError("Local Remix baseline is missing for this lane.", {
|
|
23820
23892
|
exitCode: 2,
|
|
23821
|
-
hint: "Run `remix collab
|
|
23893
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline before applying server changes."
|
|
23822
23894
|
});
|
|
23823
23895
|
}
|
|
23824
23896
|
const inspection = await inspectLocalSnapshot({
|
|
@@ -23890,11 +23962,12 @@ async function collabSync(params) {
|
|
|
23890
23962
|
const repoSnapshot = await captureRepoSnapshot(repoRoot, { includeWorkspaceDiffHash: true });
|
|
23891
23963
|
const bootstrapFromLocalHead = !detected.baseline.lastSnapshotHash || !detected.baseline.lastServerHeadHash;
|
|
23892
23964
|
let baselineServerHeadHash;
|
|
23965
|
+
let baselineServerRevisionId = null;
|
|
23893
23966
|
if (bootstrapFromLocalHead) {
|
|
23894
23967
|
if (!headCommitHash) {
|
|
23895
23968
|
throw new RemixError("Failed to resolve local HEAD commit for the initial sync bootstrap.", {
|
|
23896
23969
|
exitCode: 1,
|
|
23897
|
-
hint: "Retry after Git HEAD is available, or run `remix collab
|
|
23970
|
+
hint: "Retry after Git HEAD is available, or run `remix collab init` to seed this checkout's revision baseline."
|
|
23898
23971
|
});
|
|
23899
23972
|
}
|
|
23900
23973
|
baselineServerHeadHash = headCommitHash;
|
|
@@ -23909,13 +23982,15 @@ async function collabSync(params) {
|
|
|
23909
23982
|
if (!baseline.lastServerHeadHash) {
|
|
23910
23983
|
throw new RemixError("Local Remix baseline is missing the last acknowledged server head.", {
|
|
23911
23984
|
exitCode: 2,
|
|
23912
|
-
hint: "Run `remix collab
|
|
23985
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline before pulling server changes."
|
|
23913
23986
|
});
|
|
23914
23987
|
}
|
|
23915
23988
|
baselineServerHeadHash = baseline.lastServerHeadHash;
|
|
23989
|
+
baselineServerRevisionId = baseline.lastServerRevisionId;
|
|
23916
23990
|
}
|
|
23917
23991
|
const deltaResp = await params.api.getAppDelta(binding.currentAppId, {
|
|
23918
23992
|
baseHeadHash: baselineServerHeadHash,
|
|
23993
|
+
baseRevisionId: baselineServerRevisionId,
|
|
23919
23994
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
23920
23995
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
23921
23996
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -23939,13 +24014,54 @@ async function collabSync(params) {
|
|
|
23939
24014
|
applied: false,
|
|
23940
24015
|
dryRun: params.dryRun
|
|
23941
24016
|
};
|
|
23942
|
-
if (params.dryRun
|
|
24017
|
+
if (params.dryRun) {
|
|
23943
24018
|
return previewResult;
|
|
23944
24019
|
}
|
|
24020
|
+
if (delta.status === "up_to_date") {
|
|
24021
|
+
if (!bootstrapFromLocalHead) {
|
|
24022
|
+
return previewResult;
|
|
24023
|
+
}
|
|
24024
|
+
return withRepoMutationLock(
|
|
24025
|
+
{
|
|
24026
|
+
cwd: repoRoot,
|
|
24027
|
+
operation: "collabSync"
|
|
24028
|
+
},
|
|
24029
|
+
async ({ repoRoot: lockedRepoRoot, warnings }) => {
|
|
24030
|
+
await assertRepoSnapshotUnchanged(lockedRepoRoot, repoSnapshot, {
|
|
24031
|
+
operation: "`remix collab sync`",
|
|
24032
|
+
recoveryHint: "The repository changed before the first local Remix baseline could be created. Review the local changes and rerun `remix collab sync`."
|
|
24033
|
+
});
|
|
24034
|
+
const snapshot = await captureLocalSnapshot({
|
|
24035
|
+
repoRoot: lockedRepoRoot,
|
|
24036
|
+
repoFingerprint: binding.repoFingerprint,
|
|
24037
|
+
laneId: binding.laneId,
|
|
24038
|
+
branchName: binding.branchName
|
|
24039
|
+
});
|
|
24040
|
+
await writeLocalBaseline({
|
|
24041
|
+
repoRoot: lockedRepoRoot,
|
|
24042
|
+
repoFingerprint: binding.repoFingerprint,
|
|
24043
|
+
laneId: binding.laneId,
|
|
24044
|
+
currentAppId: binding.currentAppId,
|
|
24045
|
+
branchName: binding.branchName,
|
|
24046
|
+
lastSnapshotId: snapshot.id,
|
|
24047
|
+
lastSnapshotHash: snapshot.snapshotHash,
|
|
24048
|
+
lastServerRevisionId: delta.targetRevisionId ?? null,
|
|
24049
|
+
lastServerTreeHash: delta.targetTreeHash ?? null,
|
|
24050
|
+
lastServerHeadHash: delta.targetHeadHash,
|
|
24051
|
+
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24052
|
+
});
|
|
24053
|
+
return {
|
|
24054
|
+
...previewResult,
|
|
24055
|
+
localCommitHash: snapshot.localCommitHash,
|
|
24056
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
24057
|
+
};
|
|
24058
|
+
}
|
|
24059
|
+
);
|
|
24060
|
+
}
|
|
23945
24061
|
if (delta.status === "base_unknown") {
|
|
23946
24062
|
throw new RemixError("Direct pull is unavailable because Remix can no longer diff from the last acknowledged server head.", {
|
|
23947
24063
|
exitCode: 2,
|
|
23948
|
-
hint: "Run `remix collab reconcile --dry-run` to inspect recovery options before retrying. If this checkout has no local Remix baseline yet for this lane, `remix collab
|
|
24064
|
+
hint: "Run `remix collab reconcile --dry-run` to inspect recovery options before retrying. If this checkout has no local Remix baseline yet for this lane, run `remix collab init` to seed one."
|
|
23949
24065
|
});
|
|
23950
24066
|
}
|
|
23951
24067
|
if (delta.status !== "delta_ready") {
|
|
@@ -23989,6 +24105,8 @@ async function collabSync(params) {
|
|
|
23989
24105
|
branchName: binding.branchName,
|
|
23990
24106
|
lastSnapshotId: snapshot.id,
|
|
23991
24107
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24108
|
+
lastServerRevisionId: delta.targetRevisionId ?? null,
|
|
24109
|
+
lastServerTreeHash: delta.targetTreeHash ?? null,
|
|
23992
24110
|
lastServerHeadHash: delta.targetHeadHash,
|
|
23993
24111
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23994
24112
|
});
|
|
@@ -24274,6 +24392,8 @@ async function collabCheckout(params) {
|
|
|
24274
24392
|
branchName: branchNameForBaseline,
|
|
24275
24393
|
lastSnapshotId: snapshot.id,
|
|
24276
24394
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24395
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
24396
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
24277
24397
|
lastServerHeadHash: appHead.headCommitHash,
|
|
24278
24398
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24279
24399
|
});
|
|
@@ -24648,6 +24768,8 @@ async function trySeedEquivalentBranchBaseline(params) {
|
|
|
24648
24768
|
branchName: params.branchName,
|
|
24649
24769
|
lastSnapshotId: snapshot.id,
|
|
24650
24770
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24771
|
+
lastServerRevisionId: params.appHeadRevisionId,
|
|
24772
|
+
lastServerTreeHash: params.appTreeHash,
|
|
24651
24773
|
lastServerHeadHash: params.appHeadHash,
|
|
24652
24774
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24653
24775
|
});
|
|
@@ -24659,11 +24781,11 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24659
24781
|
laneId: params.laneId,
|
|
24660
24782
|
repoRoot: params.repoRoot
|
|
24661
24783
|
});
|
|
24662
|
-
if (baseline?.lastSnapshotHash && baseline.lastServerHeadHash) {
|
|
24784
|
+
if (baseline?.lastSnapshotHash && (baseline.lastServerRevisionId || baseline.lastServerHeadHash)) {
|
|
24663
24785
|
return "existing";
|
|
24664
24786
|
}
|
|
24665
24787
|
const localHeadCommitHash = await getHeadCommitHash(params.repoRoot);
|
|
24666
|
-
if (!localHeadCommitHash) return "
|
|
24788
|
+
if (!localHeadCommitHash) return "baseline_missing";
|
|
24667
24789
|
const appHead = unwrapResponseObject(
|
|
24668
24790
|
await params.api.getAppHead(params.currentAppId),
|
|
24669
24791
|
"app head"
|
|
@@ -24690,6 +24812,7 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24690
24812
|
const deltaResp = await params.api.getAppDelta(params.currentAppId, {
|
|
24691
24813
|
baseHeadHash: localHeadCommitHash,
|
|
24692
24814
|
targetHeadHash: appHead.headCommitHash,
|
|
24815
|
+
targetRevisionId: appHead.headRevisionId,
|
|
24693
24816
|
localSnapshotHash,
|
|
24694
24817
|
repoFingerprint: params.repoFingerprint,
|
|
24695
24818
|
remoteUrl: params.remoteUrl ?? void 0,
|
|
@@ -24719,7 +24842,9 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24719
24842
|
upstreamAppId: params.upstreamAppId ?? null,
|
|
24720
24843
|
branchName: params.branchName,
|
|
24721
24844
|
defaultBranch: params.defaultBranch,
|
|
24722
|
-
appHeadHash: appHead.headCommitHash
|
|
24845
|
+
appHeadHash: appHead.headCommitHash,
|
|
24846
|
+
appHeadRevisionId: appHead.headRevisionId ?? null,
|
|
24847
|
+
appTreeHash: appHead.treeHash ?? null
|
|
24723
24848
|
});
|
|
24724
24849
|
if (equivalentBaseline) {
|
|
24725
24850
|
return equivalentBaseline;
|
|
@@ -24727,7 +24852,7 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24727
24852
|
}
|
|
24728
24853
|
} catch {
|
|
24729
24854
|
}
|
|
24730
|
-
return "
|
|
24855
|
+
return "baseline_missing";
|
|
24731
24856
|
}
|
|
24732
24857
|
async function seedImportedInitBaseline(params) {
|
|
24733
24858
|
const appHead = unwrapResponseObject(
|
|
@@ -24748,6 +24873,8 @@ async function seedImportedInitBaseline(params) {
|
|
|
24748
24873
|
branchName: params.branchName,
|
|
24749
24874
|
lastSnapshotId: snapshot.id,
|
|
24750
24875
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24876
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
24877
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
24751
24878
|
lastServerHeadHash: appHead.headCommitHash,
|
|
24752
24879
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24753
24880
|
});
|
|
@@ -24761,7 +24888,6 @@ async function collabInit(params) {
|
|
|
24761
24888
|
},
|
|
24762
24889
|
async ({ repoRoot, warnings }) => {
|
|
24763
24890
|
await ensureGitInfoExcludeEntries(repoRoot, [".remix/"]);
|
|
24764
|
-
await ensureCleanWorktree(repoRoot, "`remix collab init`");
|
|
24765
24891
|
if (params.path?.trim()) {
|
|
24766
24892
|
throw new RemixError("`remix collab init --path` is not supported.", {
|
|
24767
24893
|
exitCode: 2,
|
|
@@ -24769,6 +24895,10 @@ async function collabInit(params) {
|
|
|
24769
24895
|
});
|
|
24770
24896
|
}
|
|
24771
24897
|
const localBindingState = await readCollabBindingState(repoRoot, { persist: true });
|
|
24898
|
+
const hasExistingBinding = localBindingState != null && Object.keys(localBindingState.branchBindings ?? {}).length > 0;
|
|
24899
|
+
if (params.forceNew || !hasExistingBinding) {
|
|
24900
|
+
await ensureCleanWorktree(repoRoot, "`remix collab init`");
|
|
24901
|
+
}
|
|
24772
24902
|
const persistedRemoteUrl = normalizeGitRemote(localBindingState?.remoteUrl ?? null);
|
|
24773
24903
|
const currentBranch = await getCurrentBranch(repoRoot);
|
|
24774
24904
|
const defaultBranch = localBindingState?.defaultBranch ?? await getDefaultBranch(repoRoot) ?? currentBranch;
|
|
@@ -25620,248 +25750,6 @@ function hasPendingFinalize(summary) {
|
|
|
25620
25750
|
function buildPendingFinalizeHint() {
|
|
25621
25751
|
return "Drain or await the local finalize queue first, then retry after the queued Remix turn finishes recording remotely.";
|
|
25622
25752
|
}
|
|
25623
|
-
async function collabReAnchor(params) {
|
|
25624
|
-
const repoRoot = await findGitRoot(params.cwd);
|
|
25625
|
-
const binding = await ensureActiveLaneBinding({
|
|
25626
|
-
repoRoot,
|
|
25627
|
-
api: params.api,
|
|
25628
|
-
operation: "`remix collab re-anchor`"
|
|
25629
|
-
});
|
|
25630
|
-
if (!binding) {
|
|
25631
|
-
throw new RemixError("Repository is not bound to Remix.", {
|
|
25632
|
-
exitCode: 2,
|
|
25633
|
-
hint: "Run `remix collab init` first."
|
|
25634
|
-
});
|
|
25635
|
-
}
|
|
25636
|
-
const detected = await collabDetectRepoState({
|
|
25637
|
-
api: params.api,
|
|
25638
|
-
cwd: repoRoot,
|
|
25639
|
-
allowBranchMismatch: params.allowBranchMismatch
|
|
25640
|
-
});
|
|
25641
|
-
if (detected.status === "metadata_conflict" || detected.status === "branch_mismatch") {
|
|
25642
|
-
throw new RemixError("Repository must be realigned before seeding a fresh local Remix baseline.", {
|
|
25643
|
-
exitCode: 2,
|
|
25644
|
-
hint: detected.hint
|
|
25645
|
-
});
|
|
25646
|
-
}
|
|
25647
|
-
if (detected.status !== "ready" || !detected.binding) {
|
|
25648
|
-
throw new RemixError(detected.hint || "Repository is not ready for re-anchor.", {
|
|
25649
|
-
exitCode: 2,
|
|
25650
|
-
hint: detected.hint
|
|
25651
|
-
});
|
|
25652
|
-
}
|
|
25653
|
-
if (detected.repoState === "server_only_changed") {
|
|
25654
|
-
throw new RemixError("This checkout is already on a server-known base and only needs a local pull.", {
|
|
25655
|
-
exitCode: 2,
|
|
25656
|
-
hint: "Run `remix collab sync` instead of `remix collab re-anchor`."
|
|
25657
|
-
});
|
|
25658
|
-
}
|
|
25659
|
-
if (detected.repoState === "both_changed") {
|
|
25660
|
-
throw new RemixError("Both the local workspace and the server lane changed since the last agreed baseline.", {
|
|
25661
|
-
exitCode: 2,
|
|
25662
|
-
hint: "Run `remix collab reconcile` to replay the local boundary onto the newer server head."
|
|
25663
|
-
});
|
|
25664
|
-
}
|
|
25665
|
-
if (detected.repoState === "local_only_changed") {
|
|
25666
|
-
if (hasPendingFinalize(detected.pendingFinalize)) {
|
|
25667
|
-
throw new RemixError("Re-anchor is not needed while queued Remix turn recording is still processing.", {
|
|
25668
|
-
exitCode: 2,
|
|
25669
|
-
hint: buildPendingFinalizeHint()
|
|
25670
|
-
});
|
|
25671
|
-
}
|
|
25672
|
-
throw new RemixError("Re-anchor is not the right command for local content changes.", {
|
|
25673
|
-
exitCode: 2,
|
|
25674
|
-
hint: "Remix is source-blind: any local content change since the last recorded turn \u2014 including manual commits, pulls, merges, and rebases \u2014 is recorded with `remix collab finalize-turn`. Use `remix collab re-anchor` only when no local Remix baseline exists yet for this lane (status reports `re_anchor`)."
|
|
25675
|
-
});
|
|
25676
|
-
}
|
|
25677
|
-
if (detected.repoState === "idle") {
|
|
25678
|
-
throw new RemixError("This checkout is already aligned with Remix.", {
|
|
25679
|
-
exitCode: 2,
|
|
25680
|
-
hint: "No re-anchor step is needed. Re-anchor only applies when no local Remix baseline exists yet for this lane."
|
|
25681
|
-
});
|
|
25682
|
-
}
|
|
25683
|
-
await ensureCleanWorktree(repoRoot, "`remix collab re-anchor`");
|
|
25684
|
-
const branch = await requireCurrentBranch(repoRoot);
|
|
25685
|
-
const headCommitHash = await getHeadCommitHash(repoRoot);
|
|
25686
|
-
if (!headCommitHash) {
|
|
25687
|
-
throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
|
|
25688
|
-
}
|
|
25689
|
-
if (params.asyncSubmit && !params.dryRun) {
|
|
25690
|
-
const pending = await findPendingAsyncJob({
|
|
25691
|
-
repoRoot,
|
|
25692
|
-
branchName: binding.branchName ?? branch,
|
|
25693
|
-
kind: "re_anchor"
|
|
25694
|
-
});
|
|
25695
|
-
if (pending) {
|
|
25696
|
-
return {
|
|
25697
|
-
status: "queued",
|
|
25698
|
-
queued: true,
|
|
25699
|
-
jobId: pending.id,
|
|
25700
|
-
repoRoot,
|
|
25701
|
-
branch,
|
|
25702
|
-
currentAppId: binding.currentAppId,
|
|
25703
|
-
dryRun: false,
|
|
25704
|
-
applied: false
|
|
25705
|
-
};
|
|
25706
|
-
}
|
|
25707
|
-
}
|
|
25708
|
-
const preflightResp = await params.api.preflightAppReconcile(binding.currentAppId, {
|
|
25709
|
-
localHeadCommitHash: headCommitHash,
|
|
25710
|
-
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
25711
|
-
remoteUrl: binding.remoteUrl ?? void 0,
|
|
25712
|
-
defaultBranch: binding.defaultBranch ?? void 0
|
|
25713
|
-
});
|
|
25714
|
-
const preflight = unwrapResponseObject(preflightResp, "reconcile preflight");
|
|
25715
|
-
if (preflight.status === "metadata_conflict") {
|
|
25716
|
-
throw new RemixError("Local repository metadata conflicts with the bound Remix app.", {
|
|
25717
|
-
exitCode: 2,
|
|
25718
|
-
hint: preflight.warnings.join("\n") || "Run the command from the correct bound repository."
|
|
25719
|
-
});
|
|
25720
|
-
}
|
|
25721
|
-
const preview = {
|
|
25722
|
-
status: preflight.status === "up_to_date" ? "reanchored" : "re_anchor_required",
|
|
25723
|
-
repoRoot,
|
|
25724
|
-
branch,
|
|
25725
|
-
currentAppId: binding.currentAppId,
|
|
25726
|
-
localHeadCommitHash: headCommitHash,
|
|
25727
|
-
targetHeadCommitHash: preflight.targetHeadCommitHash,
|
|
25728
|
-
targetHeadCommitId: preflight.targetHeadCommitId,
|
|
25729
|
-
warnings: preflight.warnings,
|
|
25730
|
-
applied: false,
|
|
25731
|
-
dryRun: params.dryRun === true
|
|
25732
|
-
};
|
|
25733
|
-
if (params.dryRun) {
|
|
25734
|
-
return preview;
|
|
25735
|
-
}
|
|
25736
|
-
let anchoredServerHeadHash = preflight.targetHeadCommitHash;
|
|
25737
|
-
if (params.asyncSubmit && preflight.status === "ready_to_reconcile") {
|
|
25738
|
-
const failed = await findFailedAsyncJob({
|
|
25739
|
-
repoRoot,
|
|
25740
|
-
branchName: binding.branchName ?? branch,
|
|
25741
|
-
kind: "re_anchor"
|
|
25742
|
-
});
|
|
25743
|
-
if (failed) {
|
|
25744
|
-
await deleteAsyncJob(failed.id);
|
|
25745
|
-
}
|
|
25746
|
-
const { bundlePath: tmpBundlePath, headCommitHash: bundledHeadCommitHash } = await createGitBundle(
|
|
25747
|
-
repoRoot,
|
|
25748
|
-
"re-anchor.bundle"
|
|
25749
|
-
);
|
|
25750
|
-
const tmpBundleDir = import_path12.default.dirname(tmpBundlePath);
|
|
25751
|
-
try {
|
|
25752
|
-
const jobId = (0, import_crypto9.randomUUID)();
|
|
25753
|
-
const durableBundlePath = getAsyncJobBundlePath(jobId);
|
|
25754
|
-
await import_promises23.default.mkdir(getAsyncJobDir(jobId), { recursive: true });
|
|
25755
|
-
try {
|
|
25756
|
-
await import_promises23.default.rename(tmpBundlePath, durableBundlePath);
|
|
25757
|
-
} catch (error2) {
|
|
25758
|
-
if (error2?.code !== "EXDEV") throw error2;
|
|
25759
|
-
await import_promises23.default.copyFile(tmpBundlePath, durableBundlePath);
|
|
25760
|
-
await import_promises23.default.unlink(tmpBundlePath).catch(() => void 0);
|
|
25761
|
-
}
|
|
25762
|
-
const bundleSha = await sha256FileHex(durableBundlePath);
|
|
25763
|
-
const job = await enqueueAsyncJob({
|
|
25764
|
-
id: jobId,
|
|
25765
|
-
kind: "re_anchor",
|
|
25766
|
-
status: "queued",
|
|
25767
|
-
repoRoot,
|
|
25768
|
-
repoFingerprint: binding.repoFingerprint,
|
|
25769
|
-
branchName: binding.branchName ?? branch,
|
|
25770
|
-
laneId: binding.laneId,
|
|
25771
|
-
retryCount: 0,
|
|
25772
|
-
error: null,
|
|
25773
|
-
idempotencyKey: null,
|
|
25774
|
-
payload: {
|
|
25775
|
-
bundlePath: durableBundlePath,
|
|
25776
|
-
bundleSha256: bundleSha,
|
|
25777
|
-
localHeadCommitHash: bundledHeadCommitHash,
|
|
25778
|
-
targetHeadCommitHash: preflight.targetHeadCommitHash,
|
|
25779
|
-
appId: binding.currentAppId
|
|
25780
|
-
}
|
|
25781
|
-
});
|
|
25782
|
-
await logDrainerEvent(job.id, "submitted", { kind: "re_anchor" });
|
|
25783
|
-
return {
|
|
25784
|
-
status: "queued",
|
|
25785
|
-
queued: true,
|
|
25786
|
-
jobId: job.id,
|
|
25787
|
-
repoRoot,
|
|
25788
|
-
branch,
|
|
25789
|
-
currentAppId: binding.currentAppId,
|
|
25790
|
-
localHeadCommitHash: bundledHeadCommitHash,
|
|
25791
|
-
targetHeadCommitHash: preflight.targetHeadCommitHash,
|
|
25792
|
-
warnings: preflight.warnings,
|
|
25793
|
-
dryRun: false,
|
|
25794
|
-
applied: false
|
|
25795
|
-
};
|
|
25796
|
-
} finally {
|
|
25797
|
-
await import_promises23.default.rm(tmpBundleDir, { recursive: true, force: true }).catch(() => void 0);
|
|
25798
|
-
}
|
|
25799
|
-
}
|
|
25800
|
-
if (preflight.status === "ready_to_reconcile") {
|
|
25801
|
-
const { bundlePath, headCommitHash: bundledHeadCommitHash } = await createGitBundle(repoRoot, "re-anchor.bundle");
|
|
25802
|
-
const bundleTempDir = import_path12.default.dirname(bundlePath);
|
|
25803
|
-
try {
|
|
25804
|
-
const bundleStat = await import_promises23.default.stat(bundlePath);
|
|
25805
|
-
const checksumSha256 = await sha256FileHex(bundlePath);
|
|
25806
|
-
const presignResp = await params.api.presignImportUploadFirstParty({
|
|
25807
|
-
file: {
|
|
25808
|
-
name: import_path12.default.basename(bundlePath),
|
|
25809
|
-
mimeType: "application/x-git-bundle",
|
|
25810
|
-
size: bundleStat.size,
|
|
25811
|
-
checksumSha256
|
|
25812
|
-
}
|
|
25813
|
-
});
|
|
25814
|
-
const uploadTarget = unwrapResponseObject(presignResp, "import upload target");
|
|
25815
|
-
await uploadPresigned({
|
|
25816
|
-
uploadUrl: String(uploadTarget.uploadUrl),
|
|
25817
|
-
filePath: bundlePath,
|
|
25818
|
-
headers: uploadTarget.headers ?? {}
|
|
25819
|
-
});
|
|
25820
|
-
const startResp = await params.api.startAppReconcile(binding.currentAppId, {
|
|
25821
|
-
uploadId: String(uploadTarget.uploadId),
|
|
25822
|
-
localHeadCommitHash: bundledHeadCommitHash,
|
|
25823
|
-
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
25824
|
-
remoteUrl: binding.remoteUrl ?? void 0,
|
|
25825
|
-
defaultBranch: binding.defaultBranch ?? void 0,
|
|
25826
|
-
idempotencyKey: buildDeterministicIdempotencyKey({
|
|
25827
|
-
kind: "collab_re_anchor_v1",
|
|
25828
|
-
appId: binding.currentAppId,
|
|
25829
|
-
localHeadCommitHash: bundledHeadCommitHash,
|
|
25830
|
-
targetHeadCommitHash: preflight.targetHeadCommitHash
|
|
25831
|
-
})
|
|
25832
|
-
});
|
|
25833
|
-
const started = unwrapResponseObject(startResp, "reconcile");
|
|
25834
|
-
const reconcile2 = await pollReconcile(params.api, binding.currentAppId, started.id);
|
|
25835
|
-
anchoredServerHeadHash = reconcile2.reconciledHeadCommitHash ?? reconcile2.targetHeadCommitHash ?? preflight.targetHeadCommitHash;
|
|
25836
|
-
} finally {
|
|
25837
|
-
await import_promises23.default.rm(bundleTempDir, { recursive: true, force: true });
|
|
25838
|
-
}
|
|
25839
|
-
}
|
|
25840
|
-
const snapshot = await captureLocalSnapshot({
|
|
25841
|
-
repoRoot,
|
|
25842
|
-
repoFingerprint: binding.repoFingerprint,
|
|
25843
|
-
laneId: binding.laneId,
|
|
25844
|
-
branchName: binding.branchName
|
|
25845
|
-
});
|
|
25846
|
-
await writeLocalBaseline({
|
|
25847
|
-
repoRoot,
|
|
25848
|
-
repoFingerprint: binding.repoFingerprint,
|
|
25849
|
-
laneId: binding.laneId,
|
|
25850
|
-
currentAppId: binding.currentAppId,
|
|
25851
|
-
branchName: binding.branchName,
|
|
25852
|
-
lastSnapshotId: snapshot.id,
|
|
25853
|
-
lastSnapshotHash: snapshot.snapshotHash,
|
|
25854
|
-
lastServerHeadHash: anchoredServerHeadHash,
|
|
25855
|
-
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
25856
|
-
});
|
|
25857
|
-
return {
|
|
25858
|
-
...preview,
|
|
25859
|
-
status: "reanchored",
|
|
25860
|
-
targetHeadCommitHash: anchoredServerHeadHash,
|
|
25861
|
-
applied: true,
|
|
25862
|
-
dryRun: false
|
|
25863
|
-
};
|
|
25864
|
-
}
|
|
25865
25753
|
async function reconcileBothChanged(params) {
|
|
25866
25754
|
const repoRoot = await findGitRoot(params.cwd);
|
|
25867
25755
|
const binding = await ensureActiveLaneBinding({
|
|
@@ -25884,7 +25772,7 @@ async function reconcileBothChanged(params) {
|
|
|
25884
25772
|
if (!baseline?.lastSnapshotId || !baseline.lastServerHeadHash) {
|
|
25885
25773
|
throw new RemixError("Local Remix baseline is missing for this lane.", {
|
|
25886
25774
|
exitCode: 2,
|
|
25887
|
-
hint: "Run `remix collab
|
|
25775
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline first."
|
|
25888
25776
|
});
|
|
25889
25777
|
}
|
|
25890
25778
|
const currentSnapshot = await captureLocalSnapshot({
|
|
@@ -25907,6 +25795,7 @@ async function reconcileBothChanged(params) {
|
|
|
25907
25795
|
params.api.getAppHead(binding.currentAppId),
|
|
25908
25796
|
params.api.getAppDelta(binding.currentAppId, {
|
|
25909
25797
|
baseHeadHash: baseline.lastServerHeadHash,
|
|
25798
|
+
baseRevisionId: baseline.lastServerRevisionId,
|
|
25910
25799
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
25911
25800
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
25912
25801
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -25924,7 +25813,7 @@ async function reconcileBothChanged(params) {
|
|
|
25924
25813
|
if (delta.status === "base_unknown") {
|
|
25925
25814
|
throw new RemixError("Reconcile cannot pull the newer server state from the last acknowledged baseline.", {
|
|
25926
25815
|
exitCode: 2,
|
|
25927
|
-
hint: "Run `remix collab
|
|
25816
|
+
hint: "Run `remix collab init` to seed a fresh revision baseline for this checkout before retrying."
|
|
25928
25817
|
});
|
|
25929
25818
|
}
|
|
25930
25819
|
if (delta.status !== "delta_ready" && delta.status !== "up_to_date") {
|
|
@@ -25955,7 +25844,9 @@ async function reconcileBothChanged(params) {
|
|
|
25955
25844
|
assistantResponse: "Replay the local boundary delta onto the latest server head without recording a new change step.",
|
|
25956
25845
|
diff: diffResult.diff,
|
|
25957
25846
|
baseCommitHash: baseline.lastServerHeadHash,
|
|
25847
|
+
baseRevisionId: baseline.lastServerRevisionId,
|
|
25958
25848
|
targetHeadCommitHash: appHead.headCommitHash,
|
|
25849
|
+
targetRevisionId: appHead.headRevisionId,
|
|
25959
25850
|
expectedPaths: diffResult.changedPaths,
|
|
25960
25851
|
workspaceMetadata: {
|
|
25961
25852
|
recordingMode: "boundary_delta",
|
|
@@ -25963,6 +25854,7 @@ async function reconcileBothChanged(params) {
|
|
|
25963
25854
|
branch,
|
|
25964
25855
|
baselineSnapshotId: baseline.lastSnapshotId,
|
|
25965
25856
|
currentSnapshotId: currentSnapshot.id,
|
|
25857
|
+
baselineServerRevisionId: baseline.lastServerRevisionId,
|
|
25966
25858
|
baselineServerHeadHash: baseline.lastServerHeadHash,
|
|
25967
25859
|
currentSnapshotHash: currentSnapshot.snapshotHash,
|
|
25968
25860
|
localCommitHash: currentSnapshot.localCommitHash,
|
|
@@ -25981,12 +25873,12 @@ async function reconcileBothChanged(params) {
|
|
|
25981
25873
|
const replay = await pollChangeStepReplay(params.api, binding.currentAppId, String(replayStart.id));
|
|
25982
25874
|
const replayDiffResp = await params.api.getChangeStepReplayDiff(binding.currentAppId, replay.id);
|
|
25983
25875
|
const replayDiff = unwrapResponseObject(replayDiffResp, "change step replay diff");
|
|
25984
|
-
const tempRoot = await
|
|
25876
|
+
const tempRoot = await import_promises23.default.mkdtemp(import_path12.default.join(import_os6.default.tmpdir(), "remix-reconcile-"));
|
|
25985
25877
|
let serverHeadSnapshot = null;
|
|
25986
25878
|
let mergedSnapshot = null;
|
|
25987
25879
|
try {
|
|
25988
|
-
const tempRepoRoot =
|
|
25989
|
-
await
|
|
25880
|
+
const tempRepoRoot = import_path12.default.join(tempRoot, "repo");
|
|
25881
|
+
await import_promises23.default.mkdir(tempRepoRoot, { recursive: true });
|
|
25990
25882
|
await execa("git", ["init"], { cwd: tempRepoRoot, stderr: "ignore" });
|
|
25991
25883
|
await materializeLocalSnapshot(baseline.lastSnapshotId, tempRepoRoot);
|
|
25992
25884
|
if (delta.status === "delta_ready" && delta.diff.trim()) {
|
|
@@ -26008,7 +25900,7 @@ async function reconcileBothChanged(params) {
|
|
|
26008
25900
|
branchName: binding.branchName
|
|
26009
25901
|
});
|
|
26010
25902
|
} finally {
|
|
26011
|
-
await
|
|
25903
|
+
await import_promises23.default.rm(tempRoot, { recursive: true, force: true }).catch(() => void 0);
|
|
26012
25904
|
}
|
|
26013
25905
|
if (!serverHeadSnapshot || !mergedSnapshot) {
|
|
26014
25906
|
throw new RemixError("Failed to materialize the reconciled local workspace.", { exitCode: 1 });
|
|
@@ -26045,6 +25937,8 @@ async function reconcileBothChanged(params) {
|
|
|
26045
25937
|
branchName: binding.branchName,
|
|
26046
25938
|
lastSnapshotId: serverHeadSnapshot.id,
|
|
26047
25939
|
lastSnapshotHash: serverHeadSnapshot.snapshotHash,
|
|
25940
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
25941
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
26048
25942
|
lastServerHeadHash: appHead.headCommitHash,
|
|
26049
25943
|
lastSeenLocalCommitHash: restoredSnapshot.localCommitHash
|
|
26050
25944
|
});
|
|
@@ -26080,7 +25974,10 @@ async function collabReconcile(params) {
|
|
|
26080
25974
|
return reconcileBothChanged(params);
|
|
26081
25975
|
}
|
|
26082
25976
|
if (detected.repoState === "external_local_base_changed") {
|
|
26083
|
-
|
|
25977
|
+
throw new RemixError("This checkout needs a local Remix revision baseline before reconciliation.", {
|
|
25978
|
+
exitCode: 2,
|
|
25979
|
+
hint: detected.hint || "Run `remix collab init` or `remix collab sync` to seed the baseline."
|
|
25980
|
+
});
|
|
26084
25981
|
}
|
|
26085
25982
|
if (detected.repoState === "local_only_changed") {
|
|
26086
25983
|
if (hasPendingFinalize(detected.pendingFinalize)) {
|
|
@@ -26187,6 +26084,8 @@ async function collabRemix(params) {
|
|
|
26187
26084
|
branchName: branchNameForBaseline,
|
|
26188
26085
|
lastSnapshotId: snapshot.id,
|
|
26189
26086
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
26087
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
26088
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
26190
26089
|
lastServerHeadHash: appHead.headCommitHash,
|
|
26191
26090
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
26192
26091
|
});
|
|
@@ -26307,11 +26206,15 @@ function createBaseStatus() {
|
|
|
26307
26206
|
baseline: {
|
|
26308
26207
|
lastSnapshotId: null,
|
|
26309
26208
|
lastSnapshotHash: null,
|
|
26209
|
+
lastServerRevisionId: null,
|
|
26210
|
+
lastServerTreeHash: null,
|
|
26310
26211
|
lastServerHeadHash: null,
|
|
26311
26212
|
lastSeenLocalCommitHash: null
|
|
26312
26213
|
},
|
|
26313
26214
|
current: {
|
|
26314
26215
|
snapshotHash: null,
|
|
26216
|
+
serverRevisionId: null,
|
|
26217
|
+
serverTreeHash: null,
|
|
26315
26218
|
serverHeadHash: null,
|
|
26316
26219
|
serverHeadCommitId: null,
|
|
26317
26220
|
localCommitHash: null
|
|
@@ -26398,6 +26301,8 @@ async function collabStatus(params) {
|
|
|
26398
26301
|
status.alignment.baseline = detected.baseline;
|
|
26399
26302
|
status.alignment.current = {
|
|
26400
26303
|
snapshotHash: detected.currentSnapshotHash,
|
|
26304
|
+
serverRevisionId: detected.currentServerRevisionId,
|
|
26305
|
+
serverTreeHash: detected.currentServerTreeHash,
|
|
26401
26306
|
serverHeadHash: detected.currentServerHeadHash,
|
|
26402
26307
|
serverHeadCommitId: detected.currentServerHeadCommitId,
|
|
26403
26308
|
localCommitHash: detected.localCommitHash
|
|
@@ -26461,7 +26366,7 @@ async function collabStatus(params) {
|
|
|
26461
26366
|
status.reconcile.canApply = !status.repo.branchMismatch;
|
|
26462
26367
|
status.recommendedAction = "reconcile";
|
|
26463
26368
|
} else if (detected.repoState === "external_local_base_changed") {
|
|
26464
|
-
status.recommendedAction = "
|
|
26369
|
+
status.recommendedAction = "init";
|
|
26465
26370
|
addBlockedReason(status.sync, "baseline_missing");
|
|
26466
26371
|
addBlockedReason(status.reconcile, "baseline_missing");
|
|
26467
26372
|
} else if (detected.repoState === "local_only_changed") {
|
|
@@ -26714,10 +26619,10 @@ async function processInitJob(job, api) {
|
|
|
26714
26619
|
try {
|
|
26715
26620
|
await updateAsyncJob(job.id, { status: "submitting", error: null });
|
|
26716
26621
|
await logDrainerEvent(job.id, "claimed", { kind: "init" });
|
|
26717
|
-
const bundleStat = await
|
|
26622
|
+
const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
|
|
26718
26623
|
const presignResp = await api.presignImportUploadFirstParty({
|
|
26719
26624
|
file: {
|
|
26720
|
-
name:
|
|
26625
|
+
name: import_path13.default.basename(job.payload.bundlePath),
|
|
26721
26626
|
mimeType: "application/x-git-bundle",
|
|
26722
26627
|
size: bundleStat.size,
|
|
26723
26628
|
checksumSha256: job.payload.bundleSha256
|
|
@@ -26734,7 +26639,7 @@ async function processInitJob(job, api) {
|
|
|
26734
26639
|
await updateAsyncJob(job.id, { status: "server_processing" });
|
|
26735
26640
|
const importResp = await api.importFromUploadFirstParty({
|
|
26736
26641
|
uploadId: String(presign.uploadId),
|
|
26737
|
-
appName: job.payload.appName?.trim() ||
|
|
26642
|
+
appName: job.payload.appName?.trim() || import_path13.default.basename(job.repoRoot),
|
|
26738
26643
|
platform: "generic",
|
|
26739
26644
|
isPublic: false,
|
|
26740
26645
|
branch: job.payload.defaultBranch && job.branchName && job.branchName !== job.payload.defaultBranch ? job.payload.defaultBranch : job.branchName ?? void 0,
|
|
@@ -26928,7 +26833,7 @@ async function processInitPostJob(job, api) {
|
|
|
26928
26833
|
if (outcome.status === "failed") {
|
|
26929
26834
|
const bindingPath = getCollabBindingPath(job.repoRoot);
|
|
26930
26835
|
try {
|
|
26931
|
-
await
|
|
26836
|
+
await import_promises24.default.unlink(bindingPath);
|
|
26932
26837
|
await logDrainerEvent(job.id, "binding_cleared", {
|
|
26933
26838
|
kind: "init_post",
|
|
26934
26839
|
appId: job.payload.appId,
|
|
@@ -26969,10 +26874,10 @@ async function processReAnchorJob(job, api) {
|
|
|
26969
26874
|
}
|
|
26970
26875
|
let anchoredServerHeadHash = preflight.targetHeadCommitHash;
|
|
26971
26876
|
if (preflight.status === "ready_to_reconcile") {
|
|
26972
|
-
const bundleStat = await
|
|
26877
|
+
const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
|
|
26973
26878
|
const presignResp = await api.presignImportUploadFirstParty({
|
|
26974
26879
|
file: {
|
|
26975
|
-
name:
|
|
26880
|
+
name: import_path13.default.basename(job.payload.bundlePath),
|
|
26976
26881
|
mimeType: "application/x-git-bundle",
|
|
26977
26882
|
size: bundleStat.size,
|
|
26978
26883
|
checksumSha256: job.payload.bundleSha256
|
|
@@ -27076,9 +26981,9 @@ async function collabReAnchorProcess(jobId, opts) {
|
|
|
27076
26981
|
}
|
|
27077
26982
|
async function acquireDrainerPidLock() {
|
|
27078
26983
|
const pidPath = getDrainerPidPath();
|
|
27079
|
-
await
|
|
26984
|
+
await import_promises24.default.mkdir(import_path13.default.dirname(pidPath), { recursive: true });
|
|
27080
26985
|
try {
|
|
27081
|
-
const existing = await
|
|
26986
|
+
const existing = await import_promises24.default.readFile(pidPath, "utf8").catch(() => "");
|
|
27082
26987
|
const existingPid = parseInt(existing.trim(), 10);
|
|
27083
26988
|
if (Number.isFinite(existingPid) && existingPid > 0 && existingPid !== process.pid) {
|
|
27084
26989
|
try {
|
|
@@ -27088,13 +26993,13 @@ async function acquireDrainerPidLock() {
|
|
|
27088
26993
|
if (error2?.code !== "ESRCH") return null;
|
|
27089
26994
|
}
|
|
27090
26995
|
}
|
|
27091
|
-
await
|
|
26996
|
+
await import_promises24.default.writeFile(pidPath, String(process.pid), "utf8");
|
|
27092
26997
|
return {
|
|
27093
26998
|
release: async () => {
|
|
27094
26999
|
try {
|
|
27095
|
-
const current = (await
|
|
27000
|
+
const current = (await import_promises24.default.readFile(pidPath, "utf8")).trim();
|
|
27096
27001
|
if (current === String(process.pid)) {
|
|
27097
|
-
await
|
|
27002
|
+
await import_promises24.default.unlink(pidPath).catch(() => void 0);
|
|
27098
27003
|
}
|
|
27099
27004
|
} catch {
|
|
27100
27005
|
}
|
|
@@ -27609,8 +27514,8 @@ function getErrorMap() {
|
|
|
27609
27514
|
|
|
27610
27515
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
27611
27516
|
var makeIssue = (params) => {
|
|
27612
|
-
const { data, path:
|
|
27613
|
-
const fullPath = [...
|
|
27517
|
+
const { data, path: path16, errorMaps, issueData } = params;
|
|
27518
|
+
const fullPath = [...path16, ...issueData.path || []];
|
|
27614
27519
|
const fullIssue = {
|
|
27615
27520
|
...issueData,
|
|
27616
27521
|
path: fullPath
|
|
@@ -27726,11 +27631,11 @@ var errorUtil;
|
|
|
27726
27631
|
|
|
27727
27632
|
// node_modules/zod/v3/types.js
|
|
27728
27633
|
var ParseInputLazyPath = class {
|
|
27729
|
-
constructor(parent, value,
|
|
27634
|
+
constructor(parent, value, path16, key) {
|
|
27730
27635
|
this._cachedPath = [];
|
|
27731
27636
|
this.parent = parent;
|
|
27732
27637
|
this.data = value;
|
|
27733
|
-
this._path =
|
|
27638
|
+
this._path = path16;
|
|
27734
27639
|
this._key = key;
|
|
27735
27640
|
}
|
|
27736
27641
|
get path() {
|
|
@@ -35222,7 +35127,7 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
35222
35127
|
}
|
|
35223
35128
|
};
|
|
35224
35129
|
|
|
35225
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
35130
|
+
// node_modules/@remixhq/core/dist/chunk-RCNOSZP6.js
|
|
35226
35131
|
async function readJsonSafe(res) {
|
|
35227
35132
|
const ct = res.headers.get("content-type") ?? "";
|
|
35228
35133
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -35235,8 +35140,13 @@ async function readJsonSafe(res) {
|
|
|
35235
35140
|
function createApiClient(config2, opts) {
|
|
35236
35141
|
const apiKey = (opts?.apiKey ?? "").trim();
|
|
35237
35142
|
const tokenProvider = opts?.tokenProvider;
|
|
35143
|
+
const defaultTimeoutMs = typeof opts?.defaultRequestTimeoutMs === "number" && opts.defaultRequestTimeoutMs > 0 ? opts.defaultRequestTimeoutMs : null;
|
|
35238
35144
|
const CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
35239
|
-
|
|
35145
|
+
function makeTimeoutSignal(timeoutMs) {
|
|
35146
|
+
const ms = typeof timeoutMs === "number" && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs;
|
|
35147
|
+
return ms != null ? AbortSignal.timeout(ms) : void 0;
|
|
35148
|
+
}
|
|
35149
|
+
async function request(path16, init, opts2) {
|
|
35240
35150
|
if (!tokenProvider) {
|
|
35241
35151
|
throw new RemixError("API client is missing a token provider.", {
|
|
35242
35152
|
exitCode: 1,
|
|
@@ -35244,9 +35154,10 @@ function createApiClient(config2, opts) {
|
|
|
35244
35154
|
});
|
|
35245
35155
|
}
|
|
35246
35156
|
const auth = await tokenProvider();
|
|
35247
|
-
const url = new URL(
|
|
35157
|
+
const url = new URL(path16, config2.apiUrl).toString();
|
|
35248
35158
|
const doFetch = async (bearer) => fetch(url, {
|
|
35249
35159
|
...init,
|
|
35160
|
+
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
35250
35161
|
headers: {
|
|
35251
35162
|
Accept: "application/json",
|
|
35252
35163
|
"Content-Type": "application/json",
|
|
@@ -35263,12 +35174,16 @@ function createApiClient(config2, opts) {
|
|
|
35263
35174
|
if (!res.ok) {
|
|
35264
35175
|
const body = await readJsonSafe(res);
|
|
35265
35176
|
const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
|
|
35266
|
-
throw new RemixError(msg, {
|
|
35177
|
+
throw new RemixError(msg, {
|
|
35178
|
+
exitCode: 1,
|
|
35179
|
+
hint: body ? JSON.stringify(body, null, 2) : null,
|
|
35180
|
+
statusCode: res.status
|
|
35181
|
+
});
|
|
35267
35182
|
}
|
|
35268
35183
|
const json = await readJsonSafe(res);
|
|
35269
35184
|
return json ?? null;
|
|
35270
35185
|
}
|
|
35271
|
-
async function requestBinary(
|
|
35186
|
+
async function requestBinary(path16, init, opts2) {
|
|
35272
35187
|
if (!tokenProvider) {
|
|
35273
35188
|
throw new RemixError("API client is missing a token provider.", {
|
|
35274
35189
|
exitCode: 1,
|
|
@@ -35276,9 +35191,10 @@ function createApiClient(config2, opts) {
|
|
|
35276
35191
|
});
|
|
35277
35192
|
}
|
|
35278
35193
|
const auth = await tokenProvider();
|
|
35279
|
-
const url = new URL(
|
|
35194
|
+
const url = new URL(path16, config2.apiUrl).toString();
|
|
35280
35195
|
const doFetch = async (bearer) => fetch(url, {
|
|
35281
35196
|
...init,
|
|
35197
|
+
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
35282
35198
|
headers: {
|
|
35283
35199
|
Accept: "*/*",
|
|
35284
35200
|
...init?.headers ?? {},
|
|
@@ -35294,7 +35210,11 @@ function createApiClient(config2, opts) {
|
|
|
35294
35210
|
if (!res.ok) {
|
|
35295
35211
|
const body = await readJsonSafe(res);
|
|
35296
35212
|
const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
|
|
35297
|
-
throw new RemixError(msg, {
|
|
35213
|
+
throw new RemixError(msg, {
|
|
35214
|
+
exitCode: 1,
|
|
35215
|
+
hint: body ? JSON.stringify(body, null, 2) : null,
|
|
35216
|
+
statusCode: res.status
|
|
35217
|
+
});
|
|
35298
35218
|
}
|
|
35299
35219
|
const contentDisposition = res.headers.get("content-disposition") ?? "";
|
|
35300
35220
|
const fileNameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);
|
|
@@ -35648,10 +35568,10 @@ function createApiClient(config2, opts) {
|
|
|
35648
35568
|
};
|
|
35649
35569
|
}
|
|
35650
35570
|
|
|
35651
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
35652
|
-
var
|
|
35571
|
+
// node_modules/@remixhq/core/dist/chunk-XETDXVGM.js
|
|
35572
|
+
var import_promises25 = __toESM(require("fs/promises"), 1);
|
|
35653
35573
|
var import_os7 = __toESM(require("os"), 1);
|
|
35654
|
-
var
|
|
35574
|
+
var import_path14 = __toESM(require("path"), 1);
|
|
35655
35575
|
|
|
35656
35576
|
// node_modules/tslib/tslib.es6.mjs
|
|
35657
35577
|
function __rest(s, e) {
|
|
@@ -44754,8 +44674,8 @@ var IcebergError = class extends Error {
|
|
|
44754
44674
|
return this.status === 419;
|
|
44755
44675
|
}
|
|
44756
44676
|
};
|
|
44757
|
-
function buildUrl(baseUrl,
|
|
44758
|
-
const url = new URL(
|
|
44677
|
+
function buildUrl(baseUrl, path16, query) {
|
|
44678
|
+
const url = new URL(path16, baseUrl);
|
|
44759
44679
|
if (query) {
|
|
44760
44680
|
for (const [key, value] of Object.entries(query)) {
|
|
44761
44681
|
if (value !== void 0) {
|
|
@@ -44785,12 +44705,12 @@ function createFetchClient(options) {
|
|
|
44785
44705
|
return {
|
|
44786
44706
|
async request({
|
|
44787
44707
|
method,
|
|
44788
|
-
path:
|
|
44708
|
+
path: path16,
|
|
44789
44709
|
query,
|
|
44790
44710
|
body,
|
|
44791
44711
|
headers
|
|
44792
44712
|
}) {
|
|
44793
|
-
const url = buildUrl(options.baseUrl,
|
|
44713
|
+
const url = buildUrl(options.baseUrl, path16, query);
|
|
44794
44714
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
44795
44715
|
const res = await fetchFn(url, {
|
|
44796
44716
|
method,
|
|
@@ -45628,7 +45548,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45628
45548
|
* @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
|
|
45629
45549
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
45630
45550
|
*/
|
|
45631
|
-
async uploadOrUpdate(method,
|
|
45551
|
+
async uploadOrUpdate(method, path16, fileBody, fileOptions) {
|
|
45632
45552
|
var _this = this;
|
|
45633
45553
|
return _this.handleOperation(async () => {
|
|
45634
45554
|
let body;
|
|
@@ -45652,7 +45572,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45652
45572
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
45653
45573
|
}
|
|
45654
45574
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
|
|
45655
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
45575
|
+
const cleanPath = _this._removeEmptyFolders(path16);
|
|
45656
45576
|
const _path = _this._getFinalPath(cleanPath);
|
|
45657
45577
|
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 } : {}));
|
|
45658
45578
|
return {
|
|
@@ -45713,8 +45633,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45713
45633
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45714
45634
|
* - 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.
|
|
45715
45635
|
*/
|
|
45716
|
-
async upload(
|
|
45717
|
-
return this.uploadOrUpdate("POST",
|
|
45636
|
+
async upload(path16, fileBody, fileOptions) {
|
|
45637
|
+
return this.uploadOrUpdate("POST", path16, fileBody, fileOptions);
|
|
45718
45638
|
}
|
|
45719
45639
|
/**
|
|
45720
45640
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -45753,9 +45673,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45753
45673
|
* - `objects` table permissions: none
|
|
45754
45674
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45755
45675
|
*/
|
|
45756
|
-
async uploadToSignedUrl(
|
|
45676
|
+
async uploadToSignedUrl(path16, token, fileBody, fileOptions) {
|
|
45757
45677
|
var _this3 = this;
|
|
45758
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
45678
|
+
const cleanPath = _this3._removeEmptyFolders(path16);
|
|
45759
45679
|
const _path = _this3._getFinalPath(cleanPath);
|
|
45760
45680
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
45761
45681
|
url.searchParams.set("token", token);
|
|
@@ -45817,10 +45737,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45817
45737
|
* - `objects` table permissions: `insert`
|
|
45818
45738
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45819
45739
|
*/
|
|
45820
|
-
async createSignedUploadUrl(
|
|
45740
|
+
async createSignedUploadUrl(path16, options) {
|
|
45821
45741
|
var _this4 = this;
|
|
45822
45742
|
return _this4.handleOperation(async () => {
|
|
45823
|
-
let _path = _this4._getFinalPath(
|
|
45743
|
+
let _path = _this4._getFinalPath(path16);
|
|
45824
45744
|
const headers = _objectSpread22({}, _this4.headers);
|
|
45825
45745
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
45826
45746
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -45829,7 +45749,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45829
45749
|
if (!token) throw new StorageError("No token returned by API");
|
|
45830
45750
|
return {
|
|
45831
45751
|
signedUrl: url.toString(),
|
|
45832
|
-
path:
|
|
45752
|
+
path: path16,
|
|
45833
45753
|
token
|
|
45834
45754
|
};
|
|
45835
45755
|
});
|
|
@@ -45885,8 +45805,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45885
45805
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45886
45806
|
* - 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.
|
|
45887
45807
|
*/
|
|
45888
|
-
async update(
|
|
45889
|
-
return this.uploadOrUpdate("PUT",
|
|
45808
|
+
async update(path16, fileBody, fileOptions) {
|
|
45809
|
+
return this.uploadOrUpdate("PUT", path16, fileBody, fileOptions);
|
|
45890
45810
|
}
|
|
45891
45811
|
/**
|
|
45892
45812
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -46034,10 +45954,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46034
45954
|
* - `objects` table permissions: `select`
|
|
46035
45955
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46036
45956
|
*/
|
|
46037
|
-
async createSignedUrl(
|
|
45957
|
+
async createSignedUrl(path16, expiresIn, options) {
|
|
46038
45958
|
var _this8 = this;
|
|
46039
45959
|
return _this8.handleOperation(async () => {
|
|
46040
|
-
let _path = _this8._getFinalPath(
|
|
45960
|
+
let _path = _this8._getFinalPath(path16);
|
|
46041
45961
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
46042
45962
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
46043
45963
|
const query = new URLSearchParams();
|
|
@@ -46171,13 +46091,13 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46171
46091
|
* - `objects` table permissions: `select`
|
|
46172
46092
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46173
46093
|
*/
|
|
46174
|
-
download(
|
|
46094
|
+
download(path16, options, parameters) {
|
|
46175
46095
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0 ? "render/image/authenticated" : "object";
|
|
46176
46096
|
const query = new URLSearchParams();
|
|
46177
46097
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
46178
46098
|
if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
|
|
46179
46099
|
const queryString = query.toString();
|
|
46180
|
-
const _path = this._getFinalPath(
|
|
46100
|
+
const _path = this._getFinalPath(path16);
|
|
46181
46101
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
|
|
46182
46102
|
headers: this.headers,
|
|
46183
46103
|
noResolveJson: true
|
|
@@ -46207,9 +46127,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46207
46127
|
* }
|
|
46208
46128
|
* ```
|
|
46209
46129
|
*/
|
|
46210
|
-
async info(
|
|
46130
|
+
async info(path16) {
|
|
46211
46131
|
var _this10 = this;
|
|
46212
|
-
const _path = _this10._getFinalPath(
|
|
46132
|
+
const _path = _this10._getFinalPath(path16);
|
|
46213
46133
|
return _this10.handleOperation(async () => {
|
|
46214
46134
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
46215
46135
|
});
|
|
@@ -46229,9 +46149,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46229
46149
|
* .exists('folder/avatar1.png')
|
|
46230
46150
|
* ```
|
|
46231
46151
|
*/
|
|
46232
|
-
async exists(
|
|
46152
|
+
async exists(path16) {
|
|
46233
46153
|
var _this11 = this;
|
|
46234
|
-
const _path = _this11._getFinalPath(
|
|
46154
|
+
const _path = _this11._getFinalPath(path16);
|
|
46235
46155
|
try {
|
|
46236
46156
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
46237
46157
|
return {
|
|
@@ -46309,8 +46229,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46309
46229
|
* - `objects` table permissions: none
|
|
46310
46230
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46311
46231
|
*/
|
|
46312
|
-
getPublicUrl(
|
|
46313
|
-
const _path = this._getFinalPath(
|
|
46232
|
+
getPublicUrl(path16, options) {
|
|
46233
|
+
const _path = this._getFinalPath(path16);
|
|
46314
46234
|
const query = new URLSearchParams();
|
|
46315
46235
|
if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
|
|
46316
46236
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
@@ -46447,10 +46367,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46447
46367
|
* - `objects` table permissions: `select`
|
|
46448
46368
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46449
46369
|
*/
|
|
46450
|
-
async list(
|
|
46370
|
+
async list(path16, options, parameters) {
|
|
46451
46371
|
var _this13 = this;
|
|
46452
46372
|
return _this13.handleOperation(async () => {
|
|
46453
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
46373
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path16 || "" });
|
|
46454
46374
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
46455
46375
|
});
|
|
46456
46376
|
}
|
|
@@ -46514,11 +46434,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46514
46434
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
46515
46435
|
return btoa(data);
|
|
46516
46436
|
}
|
|
46517
|
-
_getFinalPath(
|
|
46518
|
-
return `${this.bucketId}/${
|
|
46437
|
+
_getFinalPath(path16) {
|
|
46438
|
+
return `${this.bucketId}/${path16.replace(/^\/+/, "")}`;
|
|
46519
46439
|
}
|
|
46520
|
-
_removeEmptyFolders(
|
|
46521
|
-
return
|
|
46440
|
+
_removeEmptyFolders(path16) {
|
|
46441
|
+
return path16.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
46522
46442
|
}
|
|
46523
46443
|
/** Modifies the `query`, appending values the from `transform` */
|
|
46524
46444
|
applyTransformOptsToQuery(query, transform2) {
|
|
@@ -55593,7 +55513,7 @@ function shouldShowDeprecationWarning() {
|
|
|
55593
55513
|
}
|
|
55594
55514
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
55595
55515
|
|
|
55596
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
55516
|
+
// node_modules/@remixhq/core/dist/chunk-XETDXVGM.js
|
|
55597
55517
|
var storedSessionSchema = external_exports.object({
|
|
55598
55518
|
access_token: external_exports.string().min(1),
|
|
55599
55519
|
refresh_token: external_exports.string().min(1),
|
|
@@ -55607,7 +55527,7 @@ var storedSessionSchema = external_exports.object({
|
|
|
55607
55527
|
function xdgConfigHome() {
|
|
55608
55528
|
const value = process.env.XDG_CONFIG_HOME;
|
|
55609
55529
|
if (typeof value === "string" && value.trim()) return value;
|
|
55610
|
-
return
|
|
55530
|
+
return import_path14.default.join(import_os7.default.homedir(), ".config");
|
|
55611
55531
|
}
|
|
55612
55532
|
async function maybeLoadKeytar() {
|
|
55613
55533
|
try {
|
|
@@ -55625,22 +55545,22 @@ async function maybeLoadKeytar() {
|
|
|
55625
55545
|
return null;
|
|
55626
55546
|
}
|
|
55627
55547
|
async function ensurePathPermissions(filePath) {
|
|
55628
|
-
const dir =
|
|
55629
|
-
await
|
|
55548
|
+
const dir = import_path14.default.dirname(filePath);
|
|
55549
|
+
await import_promises25.default.mkdir(dir, { recursive: true });
|
|
55630
55550
|
try {
|
|
55631
|
-
await
|
|
55551
|
+
await import_promises25.default.chmod(dir, 448);
|
|
55632
55552
|
} catch {
|
|
55633
55553
|
}
|
|
55634
55554
|
try {
|
|
55635
|
-
await
|
|
55555
|
+
await import_promises25.default.chmod(filePath, 384);
|
|
55636
55556
|
} catch {
|
|
55637
55557
|
}
|
|
55638
55558
|
}
|
|
55639
55559
|
async function writeJsonAtomic2(filePath, value) {
|
|
55640
|
-
await
|
|
55560
|
+
await import_promises25.default.mkdir(import_path14.default.dirname(filePath), { recursive: true });
|
|
55641
55561
|
const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
55642
|
-
await
|
|
55643
|
-
await
|
|
55562
|
+
await import_promises25.default.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
55563
|
+
await import_promises25.default.rename(tmpPath, filePath);
|
|
55644
55564
|
}
|
|
55645
55565
|
async function writeSessionFileFallback(filePath, session) {
|
|
55646
55566
|
await writeJsonAtomic2(filePath, session);
|
|
@@ -55649,7 +55569,7 @@ async function writeSessionFileFallback(filePath, session) {
|
|
|
55649
55569
|
function createLocalSessionStore(params) {
|
|
55650
55570
|
const service = params?.service?.trim() || "remix-cli";
|
|
55651
55571
|
const account = params?.account?.trim() || "default";
|
|
55652
|
-
const filePath = params?.filePath?.trim() ||
|
|
55572
|
+
const filePath = params?.filePath?.trim() || import_path14.default.join(xdgConfigHome(), "remix", "session.json");
|
|
55653
55573
|
async function readKeytar() {
|
|
55654
55574
|
const keytar = await maybeLoadKeytar();
|
|
55655
55575
|
if (!keytar) return null;
|
|
@@ -55663,7 +55583,7 @@ function createLocalSessionStore(params) {
|
|
|
55663
55583
|
}
|
|
55664
55584
|
}
|
|
55665
55585
|
async function readFile() {
|
|
55666
|
-
const raw = await
|
|
55586
|
+
const raw = await import_promises25.default.readFile(filePath, "utf8").catch(() => null);
|
|
55667
55587
|
if (!raw) return null;
|
|
55668
55588
|
try {
|
|
55669
55589
|
const parsed = storedSessionSchema.safeParse(JSON.parse(raw));
|
|
@@ -55807,7 +55727,7 @@ function createSupabaseAuthHelpers(config2) {
|
|
|
55807
55727
|
};
|
|
55808
55728
|
}
|
|
55809
55729
|
|
|
55810
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
55730
|
+
// node_modules/@remixhq/core/dist/chunk-XCZRNB35.js
|
|
55811
55731
|
var DEFAULT_API_URL = "https://api.remix.one";
|
|
55812
55732
|
var DEFAULT_SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
|
|
55813
55733
|
var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
|
|
@@ -55845,10 +55765,10 @@ async function resolveConfig(_opts) {
|
|
|
55845
55765
|
}
|
|
55846
55766
|
|
|
55847
55767
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
55848
|
-
var
|
|
55768
|
+
var import_path15 = __toESM(require("path"), 1);
|
|
55849
55769
|
var import_child_process = require("child_process");
|
|
55850
55770
|
var import_fs3 = require("fs");
|
|
55851
|
-
var
|
|
55771
|
+
var import_path16 = __toESM(require("path"), 1);
|
|
55852
55772
|
async function createRemixTokenProvider(config2) {
|
|
55853
55773
|
const resolvedConfig = config2 ?? await resolveConfig();
|
|
55854
55774
|
const sessionStore = createLocalSessionStore();
|
|
@@ -56141,12 +56061,12 @@ function parsePositiveIntEnv(name, fallback) {
|
|
|
56141
56061
|
}
|
|
56142
56062
|
function parseAllowedRoots(raw) {
|
|
56143
56063
|
if (!raw) return null;
|
|
56144
|
-
const roots = raw.split(
|
|
56064
|
+
const roots = raw.split(import_path15.default.delimiter).map((entry) => entry.trim()).filter(Boolean).map((entry) => import_path15.default.resolve(entry));
|
|
56145
56065
|
return roots.length > 0 ? roots : null;
|
|
56146
56066
|
}
|
|
56147
56067
|
function isWithinRoot(root, candidate) {
|
|
56148
|
-
const relative =
|
|
56149
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
56068
|
+
const relative = import_path15.default.relative(root, candidate);
|
|
56069
|
+
return relative === "" || !relative.startsWith("..") && !import_path15.default.isAbsolute(relative);
|
|
56150
56070
|
}
|
|
56151
56071
|
function loadPolicy() {
|
|
56152
56072
|
return {
|
|
@@ -56158,7 +56078,7 @@ function loadPolicy() {
|
|
|
56158
56078
|
};
|
|
56159
56079
|
}
|
|
56160
56080
|
function resolvePolicyCwd(policy, cwd) {
|
|
56161
|
-
const resolved =
|
|
56081
|
+
const resolved = import_path15.default.resolve(cwd?.trim() || process.cwd());
|
|
56162
56082
|
if (!policy.allowedRepoRoots) return resolved;
|
|
56163
56083
|
if (policy.allowedRepoRoots.some((root) => isWithinRoot(root, resolved))) return resolved;
|
|
56164
56084
|
throw createPolicyError("Requested working directory is outside the allowed repository roots.", resolved);
|
|
@@ -56317,9 +56237,6 @@ var applyInputSchema = {
|
|
|
56317
56237
|
confirm: external_exports.boolean(),
|
|
56318
56238
|
allowBranchMismatch: external_exports.boolean().optional()
|
|
56319
56239
|
};
|
|
56320
|
-
var reAnchorInputSchema = {
|
|
56321
|
-
...applyInputSchema
|
|
56322
|
-
};
|
|
56323
56240
|
var requestMergeInputSchema = {
|
|
56324
56241
|
...commonRequestFieldsSchema
|
|
56325
56242
|
};
|
|
@@ -56432,7 +56349,7 @@ var initSyncDataSchema = external_exports.object({
|
|
|
56432
56349
|
repoRoot: external_exports.string(),
|
|
56433
56350
|
bindingMode: external_exports.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
56434
56351
|
createdCanonicalFamily: external_exports.boolean().optional(),
|
|
56435
|
-
baselineStatus: external_exports.enum(["seeded", "existing", "
|
|
56352
|
+
baselineStatus: external_exports.enum(["seeded", "existing", "baseline_missing", "requires_sync"]).optional()
|
|
56436
56353
|
});
|
|
56437
56354
|
var initQueuedDataSchema = external_exports.object({
|
|
56438
56355
|
queued: external_exports.literal(true),
|
|
@@ -56480,7 +56397,6 @@ var drainFinalizeQueueDataSchema = external_exports.object({
|
|
|
56480
56397
|
results: external_exports.array(genericRecordSchema)
|
|
56481
56398
|
});
|
|
56482
56399
|
var syncDataSchema = genericRecordSchema;
|
|
56483
|
-
var reAnchorDataSchema = genericRecordSchema;
|
|
56484
56400
|
var requestMergeDataSchema = genericRecordSchema;
|
|
56485
56401
|
var mergeRequestQueueDataSchema = external_exports.object({
|
|
56486
56402
|
queue: mergeRequestQueueSchema,
|
|
@@ -56556,7 +56472,6 @@ var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
|
56556
56472
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
56557
56473
|
var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
|
|
56558
56474
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
56559
|
-
var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
|
|
56560
56475
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
56561
56476
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
56562
56477
|
var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
|
|
@@ -56575,7 +56490,7 @@ var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema
|
|
|
56575
56490
|
function getRiskLevel(status) {
|
|
56576
56491
|
if (status.recommendedAction === "reconcile") return "high";
|
|
56577
56492
|
if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
|
|
56578
|
-
if (status.recommendedAction === "pull" || status.
|
|
56493
|
+
if (status.recommendedAction === "pull" || status.remote.incomingOpenMergeRequestCount) {
|
|
56579
56494
|
return "medium";
|
|
56580
56495
|
}
|
|
56581
56496
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
@@ -56592,10 +56507,6 @@ function getRecommendedNextActions(status) {
|
|
|
56592
56507
|
return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
|
|
56593
56508
|
case "pull":
|
|
56594
56509
|
return ["Run remix_collab_sync_preview, then remix_collab_sync_apply if the preview is acceptable. This pulls the server delta into the local working tree without rewriting local git history."];
|
|
56595
|
-
case "re_anchor":
|
|
56596
|
-
return [
|
|
56597
|
-
"Run remix_collab_re_anchor_preview, then remix_collab_re_anchor_apply. This seeds a local Remix baseline. It is required because no local baseline exists for this lane yet (fresh clone, deleted .remix/ state, or first init didn't seed) \u2014 not because of any specific git operation. After it succeeds, automatic hook recording can capture completed turns."
|
|
56598
|
-
];
|
|
56599
56510
|
case "record":
|
|
56600
56511
|
return [
|
|
56601
56512
|
"No MCP recording tool is required. Automatic hook finalization will capture the local boundary at the end of the completed turn; this covers agent edits, manual user edits, git commit, git pull, git merge, git rebase, and git reset."
|
|
@@ -56680,8 +56591,8 @@ async function initCollab(params) {
|
|
|
56680
56591
|
return {
|
|
56681
56592
|
data: syncResult,
|
|
56682
56593
|
warnings: collectResultWarnings(result),
|
|
56683
|
-
recommendedNextActions: syncResult.baselineStatus === "
|
|
56684
|
-
"This checkout has no local Remix baseline yet. Run
|
|
56594
|
+
recommendedNextActions: syncResult.baselineStatus === "baseline_missing" ? [
|
|
56595
|
+
"This checkout has no local Remix revision baseline yet. Run remix_collab_init or remix_collab_sync_preview/apply to seed one. After it succeeds, automatic hook recording can capture completed turns."
|
|
56685
56596
|
] : syncResult.baselineStatus === "requires_sync" ? [
|
|
56686
56597
|
"Run remix_collab_sync_preview, then remix_collab_sync_apply to pull the server delta and create the first local baseline for this checkout."
|
|
56687
56598
|
] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
|
|
@@ -56784,26 +56695,6 @@ async function syncCollab(params) {
|
|
|
56784
56695
|
}
|
|
56785
56696
|
};
|
|
56786
56697
|
}
|
|
56787
|
-
async function reAnchor(params) {
|
|
56788
|
-
const api = await createCollabApiClient();
|
|
56789
|
-
const result = await collabReAnchor({
|
|
56790
|
-
api,
|
|
56791
|
-
cwd: params.cwd,
|
|
56792
|
-
dryRun: params.dryRun,
|
|
56793
|
-
allowBranchMismatch: params.allowBranchMismatch ?? false
|
|
56794
|
-
});
|
|
56795
|
-
return {
|
|
56796
|
-
data: result,
|
|
56797
|
-
warnings: collectWarnings(result.warnings),
|
|
56798
|
-
recommendedNextActions: params.dryRun ? [
|
|
56799
|
-
"Run remix_collab_re_anchor_apply with confirm=true to seed a local Remix baseline for this checkout. Re-anchor is for missing-baseline cases only and does not replace automatic hook recording for ordinary local content changes."
|
|
56800
|
-
] : [],
|
|
56801
|
-
logContext: {
|
|
56802
|
-
repoRoot: result.repoRoot,
|
|
56803
|
-
appId: result.currentAppId
|
|
56804
|
-
}
|
|
56805
|
-
};
|
|
56806
|
-
}
|
|
56807
56698
|
async function requestMerge(params) {
|
|
56808
56699
|
const api = await createCollabApiClient();
|
|
56809
56700
|
const drainWarnings = await drainBeforeMutation(api);
|
|
@@ -57520,22 +57411,25 @@ async function accessDebug(params) {
|
|
|
57520
57411
|
}
|
|
57521
57412
|
};
|
|
57522
57413
|
}
|
|
57523
|
-
var MARKER_REL_PATH =
|
|
57524
|
-
var LOG_REL_PATH =
|
|
57414
|
+
var MARKER_REL_PATH = import_path16.default.join(".remix", ".history-imported");
|
|
57415
|
+
var LOG_REL_PATH = import_path16.default.join(".remix", "history-import.log");
|
|
57525
57416
|
function shouldAutoSpawnHistoryImport(repoRoot) {
|
|
57526
57417
|
try {
|
|
57527
|
-
return !(0, import_fs3.existsSync)(
|
|
57418
|
+
return !(0, import_fs3.existsSync)(import_path16.default.join(repoRoot, MARKER_REL_PATH));
|
|
57528
57419
|
} catch {
|
|
57529
57420
|
return false;
|
|
57530
57421
|
}
|
|
57531
57422
|
}
|
|
57532
|
-
function
|
|
57533
|
-
|
|
57423
|
+
function isAutoSpawnEligibleBindingMode(bindingMode) {
|
|
57424
|
+
return bindingMode === "explicit_root";
|
|
57425
|
+
}
|
|
57426
|
+
function spawnHistoryImportDetached(repoRoot, options) {
|
|
57427
|
+
const remixDir = import_path16.default.join(repoRoot, ".remix");
|
|
57534
57428
|
try {
|
|
57535
57429
|
(0, import_fs3.mkdirSync)(remixDir, { recursive: true });
|
|
57536
57430
|
} catch {
|
|
57537
57431
|
}
|
|
57538
|
-
const logPath =
|
|
57432
|
+
const logPath = import_path16.default.join(repoRoot, LOG_REL_PATH);
|
|
57539
57433
|
const out = (0, import_fs3.openSync)(logPath, "a");
|
|
57540
57434
|
const err = (0, import_fs3.openSync)(logPath, "a");
|
|
57541
57435
|
const child = (0, import_child_process.spawn)(
|
|
@@ -57545,6 +57439,8 @@ function spawnHistoryImportDetached(repoRoot) {
|
|
|
57545
57439
|
"import",
|
|
57546
57440
|
"--repo",
|
|
57547
57441
|
repoRoot,
|
|
57442
|
+
"--before",
|
|
57443
|
+
options.cutoffAt,
|
|
57548
57444
|
// Include prompt text for parity with the CLI auto-spawn path:
|
|
57549
57445
|
// first-time UX is a lot worse if the dashboard renders every
|
|
57550
57446
|
// historical row as "(prompt not uploaded)".
|
|
@@ -57693,11 +57589,13 @@ function registerCollabTools(server, context) {
|
|
|
57693
57589
|
});
|
|
57694
57590
|
try {
|
|
57695
57591
|
const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
|
|
57696
|
-
|
|
57697
|
-
|
|
57592
|
+
const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
|
|
57593
|
+
if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot)) {
|
|
57594
|
+
const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
57595
|
+
const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
|
|
57698
57596
|
context.logger.log({
|
|
57699
57597
|
level: "info",
|
|
57700
|
-
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath}`,
|
|
57598
|
+
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath} cutoffAt=${cutoffAt}`,
|
|
57701
57599
|
tool: "remix_collab_init",
|
|
57702
57600
|
repoRoot
|
|
57703
57601
|
});
|
|
@@ -57801,31 +57699,6 @@ function registerCollabTools(server, context) {
|
|
|
57801
57699
|
return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
57802
57700
|
}
|
|
57803
57701
|
});
|
|
57804
|
-
registerTool(server, context, {
|
|
57805
|
-
name: "remix_collab_re_anchor_preview",
|
|
57806
|
-
description: "Preview whether this checkout needs a fresh local Remix baseline. Use only when status reports `re_anchor` (no local baseline exists for this lane yet \u2014 fresh clone, deleted `.remix/` state, or first init didn't seed). Re-anchor does not replace automatic hook recording; ordinary local content changes (including merges, pulls, and rebases) are captured at the completed-turn boundary, not by re-anchor.",
|
|
57807
|
-
access: "read",
|
|
57808
|
-
inputSchema: previewInputSchema,
|
|
57809
|
-
outputSchema: reAnchorSuccessSchema,
|
|
57810
|
-
run: async (args) => {
|
|
57811
|
-
const input = external_exports.object(previewInputSchema).parse(args);
|
|
57812
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
57813
|
-
return reAnchor({ cwd, dryRun: true });
|
|
57814
|
-
}
|
|
57815
|
-
});
|
|
57816
|
-
registerTool(server, context, {
|
|
57817
|
-
name: "remix_collab_re_anchor_apply",
|
|
57818
|
-
description: "Establish a local Remix baseline for the current checkout against the existing app head, without rewriting the local checkout afterward. Required only when status reports `re_anchor` (missing local baseline). It does not replace automatic hook recording \u2014 local commits, pulls, merges, and rebases are still captured at the completed-turn boundary.",
|
|
57819
|
-
access: "local_write",
|
|
57820
|
-
inputSchema: reAnchorInputSchema,
|
|
57821
|
-
outputSchema: reAnchorSuccessSchema,
|
|
57822
|
-
run: async (args) => {
|
|
57823
|
-
const input = external_exports.object(reAnchorInputSchema).parse(args);
|
|
57824
|
-
assertConfirm(input.confirm, "remix_collab_re_anchor_apply");
|
|
57825
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
57826
|
-
return reAnchor({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
57827
|
-
}
|
|
57828
|
-
});
|
|
57829
57702
|
registerTool(server, context, {
|
|
57830
57703
|
name: "remix_collab_request_merge",
|
|
57831
57704
|
description: "Open a prompt-backed Remix merge request from the current bound repository to its upstream app instead of merging locally with raw git.",
|
|
@@ -59590,6 +59463,7 @@ function createRemixMcpServer(params) {
|
|
|
59590
59463
|
}
|
|
59591
59464
|
|
|
59592
59465
|
// src/hook-auth.ts
|
|
59466
|
+
var HOOK_API_REQUEST_TIMEOUT_MS = 6e4;
|
|
59593
59467
|
async function createHookCollabApiClient() {
|
|
59594
59468
|
const config2 = await resolveConfig();
|
|
59595
59469
|
const sessionStore = createLocalSessionStore();
|
|
@@ -59602,18 +59476,19 @@ async function createHookCollabApiClient() {
|
|
|
59602
59476
|
}
|
|
59603
59477
|
});
|
|
59604
59478
|
return createApiClient(config2, {
|
|
59605
|
-
tokenProvider
|
|
59479
|
+
tokenProvider,
|
|
59480
|
+
defaultRequestTimeoutMs: HOOK_API_REQUEST_TIMEOUT_MS
|
|
59606
59481
|
});
|
|
59607
59482
|
}
|
|
59608
59483
|
|
|
59609
59484
|
// src/hook-diagnostics.ts
|
|
59610
59485
|
var import_node_crypto2 = require("crypto");
|
|
59611
|
-
var
|
|
59486
|
+
var import_promises27 = __toESM(require("fs/promises"), 1);
|
|
59612
59487
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
59613
59488
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
59614
59489
|
|
|
59615
59490
|
// src/hook-state.ts
|
|
59616
|
-
var
|
|
59491
|
+
var import_promises26 = __toESM(require("fs/promises"), 1);
|
|
59617
59492
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
59618
59493
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
59619
59494
|
var import_node_crypto = require("crypto");
|
|
@@ -59718,7 +59593,7 @@ function getPendingTurnStateRootPath() {
|
|
|
59718
59593
|
return stateRoot();
|
|
59719
59594
|
}
|
|
59720
59595
|
async function loadPendingTurnState(sessionId) {
|
|
59721
|
-
const raw = await
|
|
59596
|
+
const raw = await import_promises26.default.readFile(statePath(sessionId), "utf8").catch(() => null);
|
|
59722
59597
|
if (!raw) return null;
|
|
59723
59598
|
try {
|
|
59724
59599
|
const parsed = JSON.parse(raw);
|
|
@@ -59745,7 +59620,7 @@ async function loadPendingTurnState(sessionId) {
|
|
|
59745
59620
|
}
|
|
59746
59621
|
async function listPendingTurnStateSummaries() {
|
|
59747
59622
|
const root = stateRoot();
|
|
59748
|
-
const entries = await
|
|
59623
|
+
const entries = await import_promises26.default.readdir(root, { withFileTypes: true }).catch(() => []);
|
|
59749
59624
|
const sessionIds = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((a2, b) => a2.localeCompare(b));
|
|
59750
59625
|
const states = await Promise.all(sessionIds.map((sessionId) => loadPendingTurnState(sessionId)));
|
|
59751
59626
|
return states.filter((state) => state !== null).sort((a2, b) => b.submittedAt.localeCompare(a2.submittedAt)).map((state) => summarizePendingTurnState(state));
|
|
@@ -59754,7 +59629,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
59754
59629
|
// package.json
|
|
59755
59630
|
var package_default = {
|
|
59756
59631
|
name: "@remixhq/claude-plugin",
|
|
59757
|
-
version: "0.1.
|
|
59632
|
+
version: "0.1.23",
|
|
59758
59633
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
59759
59634
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
59760
59635
|
license: "MIT",
|
|
@@ -59792,8 +59667,8 @@ var package_default = {
|
|
|
59792
59667
|
prepack: "npm run build"
|
|
59793
59668
|
},
|
|
59794
59669
|
dependencies: {
|
|
59795
|
-
"@remixhq/core": "^0.1.
|
|
59796
|
-
"@remixhq/mcp": "^0.1.
|
|
59670
|
+
"@remixhq/core": "^0.1.18",
|
|
59671
|
+
"@remixhq/mcp": "^0.1.18"
|
|
59797
59672
|
},
|
|
59798
59673
|
devDependencies: {
|
|
59799
59674
|
"@types/node": "^25.4.0",
|
|
@@ -59835,7 +59710,7 @@ function clampEventLimit(limit) {
|
|
|
59835
59710
|
return Math.max(1, Math.min(MAX_EVENT_LIMIT, Math.trunc(limit)));
|
|
59836
59711
|
}
|
|
59837
59712
|
async function readEventsFromFile(filePath) {
|
|
59838
|
-
const raw = await
|
|
59713
|
+
const raw = await import_promises27.default.readFile(filePath, "utf8").catch(() => null);
|
|
59839
59714
|
if (!raw) return [];
|
|
59840
59715
|
return raw.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
|
|
59841
59716
|
try {
|