@remixhq/claude-plugin 0.1.22 → 0.1.24
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 +536 -86
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +1047 -514
- 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 +508 -519
- 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,
|
|
@@ -22351,6 +22359,15 @@ function shouldRequireRemoteLaneForCurrentBranch(params) {
|
|
|
22351
22359
|
if (params.currentBranch === defaultBranch) return false;
|
|
22352
22360
|
return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
|
|
22353
22361
|
}
|
|
22362
|
+
function resolveLaneLookupProjectId(params) {
|
|
22363
|
+
const currentBranch = normalizeBranchName2(params.currentBranch);
|
|
22364
|
+
const defaultBranch = normalizeBranchName2(params.defaultBranch);
|
|
22365
|
+
const localProjectId = params.localBinding.projectId ?? null;
|
|
22366
|
+
if (currentBranch && currentBranch !== defaultBranch && localProjectId) {
|
|
22367
|
+
return localProjectId;
|
|
22368
|
+
}
|
|
22369
|
+
return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
|
|
22370
|
+
}
|
|
22354
22371
|
async function persistResolvedLane(repoRoot, binding) {
|
|
22355
22372
|
await writeCollabBinding(repoRoot, {
|
|
22356
22373
|
projectId: binding.projectId,
|
|
@@ -22429,7 +22446,14 @@ async function resolveActiveLaneBindingUncached(params, state) {
|
|
|
22429
22446
|
};
|
|
22430
22447
|
}
|
|
22431
22448
|
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
22432
|
-
projectId:
|
|
22449
|
+
projectId: resolveLaneLookupProjectId({
|
|
22450
|
+
explicitRootProjectId: state.explicitRootBinding?.projectId,
|
|
22451
|
+
localBinding,
|
|
22452
|
+
currentBranch,
|
|
22453
|
+
defaultBranch: state.defaultBranch,
|
|
22454
|
+
requireRemoteLane,
|
|
22455
|
+
fallbackProjectId: state.projectId
|
|
22456
|
+
}),
|
|
22433
22457
|
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
22434
22458
|
remoteUrl: state.remoteUrl ?? void 0,
|
|
22435
22459
|
defaultBranch: state.defaultBranch ?? void 0,
|
|
@@ -22588,6 +22612,8 @@ function buildBaseState() {
|
|
|
22588
22612
|
branchName: null,
|
|
22589
22613
|
localCommitHash: null,
|
|
22590
22614
|
currentSnapshotHash: null,
|
|
22615
|
+
currentServerRevisionId: null,
|
|
22616
|
+
currentServerTreeHash: null,
|
|
22591
22617
|
currentServerHeadHash: null,
|
|
22592
22618
|
currentServerHeadCommitId: null,
|
|
22593
22619
|
worktreeClean: false,
|
|
@@ -22621,6 +22647,8 @@ function buildBaseState() {
|
|
|
22621
22647
|
baseline: {
|
|
22622
22648
|
lastSnapshotId: null,
|
|
22623
22649
|
lastSnapshotHash: null,
|
|
22650
|
+
lastServerRevisionId: null,
|
|
22651
|
+
lastServerTreeHash: null,
|
|
22624
22652
|
lastServerHeadHash: null,
|
|
22625
22653
|
lastSeenLocalCommitHash: null
|
|
22626
22654
|
}
|
|
@@ -22747,6 +22775,8 @@ async function collabDetectRepoState(params) {
|
|
|
22747
22775
|
summarizeAsyncJobs({ repoRoot, branchName: binding.branchName ?? null })
|
|
22748
22776
|
]);
|
|
22749
22777
|
const appHead = unwrapResponseObject(headResp, "app head");
|
|
22778
|
+
detected.currentServerRevisionId = appHead.headRevisionId ?? null;
|
|
22779
|
+
detected.currentServerTreeHash = appHead.treeHash ?? null;
|
|
22750
22780
|
detected.currentServerHeadHash = appHead.headCommitHash;
|
|
22751
22781
|
detected.currentServerHeadCommitId = appHead.headCommitId;
|
|
22752
22782
|
detected.currentSnapshotHash = inspection.snapshotHash;
|
|
@@ -22755,6 +22785,8 @@ async function collabDetectRepoState(params) {
|
|
|
22755
22785
|
detected.baseline = {
|
|
22756
22786
|
lastSnapshotId: baseline?.lastSnapshotId ?? null,
|
|
22757
22787
|
lastSnapshotHash: baseline?.lastSnapshotHash ?? null,
|
|
22788
|
+
lastServerRevisionId: baseline?.lastServerRevisionId ?? null,
|
|
22789
|
+
lastServerTreeHash: baseline?.lastServerTreeHash ?? null,
|
|
22758
22790
|
lastServerHeadHash: baseline?.lastServerHeadHash ?? null,
|
|
22759
22791
|
lastSeenLocalCommitHash: baseline?.lastSeenLocalCommitHash ?? null
|
|
22760
22792
|
};
|
|
@@ -22764,6 +22796,7 @@ async function collabDetectRepoState(params) {
|
|
|
22764
22796
|
const bootstrapResp = await params.api.getAppDelta(binding.currentAppId, {
|
|
22765
22797
|
baseHeadHash: localCommitHash,
|
|
22766
22798
|
targetHeadHash: appHead.headCommitHash,
|
|
22799
|
+
targetRevisionId: appHead.headRevisionId,
|
|
22767
22800
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
22768
22801
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
22769
22802
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -22786,7 +22819,7 @@ async function collabDetectRepoState(params) {
|
|
|
22786
22819
|
}
|
|
22787
22820
|
}
|
|
22788
22821
|
detected.repoState = "external_local_base_changed";
|
|
22789
|
-
detected.hint = "No local Remix baseline exists for this lane yet. Run `remix collab
|
|
22822
|
+
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
22823
|
return detected;
|
|
22791
22824
|
}
|
|
22792
22825
|
const localHeadMovedSinceBaseline = Boolean(baseline.lastSeenLocalCommitHash) && localCommitHash !== baseline.lastSeenLocalCommitHash;
|
|
@@ -22805,7 +22838,30 @@ async function collabDetectRepoState(params) {
|
|
|
22805
22838
|
return detected;
|
|
22806
22839
|
}
|
|
22807
22840
|
const localChanged = inspection.snapshotHash !== baseline.lastSnapshotHash;
|
|
22808
|
-
const
|
|
22841
|
+
const serverHeadChanged = appHead.headCommitHash !== baseline.lastServerHeadHash;
|
|
22842
|
+
const revisionChanged = Boolean(
|
|
22843
|
+
baseline.lastServerRevisionId && (appHead.headRevisionId ?? null) !== baseline.lastServerRevisionId
|
|
22844
|
+
);
|
|
22845
|
+
const equivalentRevisionDrift = revisionChanged && !serverHeadChanged;
|
|
22846
|
+
if (equivalentRevisionDrift) {
|
|
22847
|
+
await writeLocalBaseline({
|
|
22848
|
+
repoRoot,
|
|
22849
|
+
repoFingerprint: binding.repoFingerprint,
|
|
22850
|
+
laneId: binding.laneId,
|
|
22851
|
+
currentAppId: binding.currentAppId,
|
|
22852
|
+
branchName: binding.branchName,
|
|
22853
|
+
lastSnapshotId: baseline.lastSnapshotId,
|
|
22854
|
+
lastSnapshotHash: baseline.lastSnapshotHash,
|
|
22855
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
22856
|
+
lastServerTreeHash: appHead.treeHash ?? baseline.lastServerTreeHash ?? null,
|
|
22857
|
+
lastServerHeadHash: appHead.headCommitHash,
|
|
22858
|
+
lastSeenLocalCommitHash: baseline.lastSeenLocalCommitHash
|
|
22859
|
+
});
|
|
22860
|
+
detected.baseline.lastServerRevisionId = appHead.headRevisionId ?? null;
|
|
22861
|
+
detected.baseline.lastServerTreeHash = appHead.treeHash ?? baseline.lastServerTreeHash ?? null;
|
|
22862
|
+
detected.baseline.lastServerHeadHash = appHead.headCommitHash;
|
|
22863
|
+
}
|
|
22864
|
+
const serverChanged = serverHeadChanged;
|
|
22809
22865
|
if (!localChanged && !serverChanged) {
|
|
22810
22866
|
detected.repoState = "idle";
|
|
22811
22867
|
return detected;
|
|
@@ -23229,6 +23285,7 @@ function buildWorkspaceMetadata(params) {
|
|
|
23229
23285
|
recordingMode: "boundary_delta",
|
|
23230
23286
|
baselineSnapshotId: params.baselineSnapshotId,
|
|
23231
23287
|
currentSnapshotId: params.currentSnapshotId,
|
|
23288
|
+
baselineServerRevisionId: params.baselineServerRevisionId ?? null,
|
|
23232
23289
|
baselineServerHeadHash: params.baselineServerHeadHash,
|
|
23233
23290
|
currentSnapshotHash: params.currentSnapshotHash,
|
|
23234
23291
|
localCommitHash: params.localCommitHash,
|
|
@@ -23247,6 +23304,59 @@ function buildWorkspaceMetadata(params) {
|
|
|
23247
23304
|
}
|
|
23248
23305
|
return metadata;
|
|
23249
23306
|
}
|
|
23307
|
+
async function findExistingChangeStepByIdempotency(params) {
|
|
23308
|
+
const idempotencyKey = params.idempotencyKey?.trim();
|
|
23309
|
+
if (!idempotencyKey) return null;
|
|
23310
|
+
const resp = await params.api.listChangeSteps(params.appId, { limit: 1, idempotencyKey });
|
|
23311
|
+
const responseObject = unwrapResponseObject(
|
|
23312
|
+
resp,
|
|
23313
|
+
"change step list"
|
|
23314
|
+
);
|
|
23315
|
+
const steps = Array.isArray(responseObject) ? responseObject : Array.isArray(responseObject.items) ? responseObject.items : [];
|
|
23316
|
+
return steps.find((step) => step.idempotencyKey === idempotencyKey) ?? null;
|
|
23317
|
+
}
|
|
23318
|
+
async function writeBaselineFromSucceededChangeStep(params) {
|
|
23319
|
+
const nextServerHeadHash = typeof params.changeStep.headCommitHash === "string" ? params.changeStep.headCommitHash.trim() : "";
|
|
23320
|
+
if (!nextServerHeadHash) {
|
|
23321
|
+
throw buildFinalizeCliError({
|
|
23322
|
+
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
23323
|
+
exitCode: 1,
|
|
23324
|
+
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
23325
|
+
disposition: "terminal",
|
|
23326
|
+
reason: "missing_head_commit_hash"
|
|
23327
|
+
});
|
|
23328
|
+
}
|
|
23329
|
+
let nextServerRevisionId = typeof params.changeStep.resultRevisionId === "string" ? params.changeStep.resultRevisionId.trim() : "";
|
|
23330
|
+
let nextServerTreeHash = null;
|
|
23331
|
+
if (!nextServerRevisionId) {
|
|
23332
|
+
const freshHeadResp = await params.api.getAppHead(params.job.currentAppId);
|
|
23333
|
+
const freshHead = unwrapResponseObject(freshHeadResp, "app head");
|
|
23334
|
+
if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
|
|
23335
|
+
throw buildFinalizeCliError({
|
|
23336
|
+
message: "Backend returned a succeeded change step without a matching result revision.",
|
|
23337
|
+
exitCode: 1,
|
|
23338
|
+
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`.",
|
|
23339
|
+
disposition: "terminal",
|
|
23340
|
+
reason: "missing_result_revision_id"
|
|
23341
|
+
});
|
|
23342
|
+
}
|
|
23343
|
+
nextServerRevisionId = freshHead.headRevisionId;
|
|
23344
|
+
nextServerTreeHash = freshHead.treeHash ?? null;
|
|
23345
|
+
}
|
|
23346
|
+
await writeLocalBaseline({
|
|
23347
|
+
repoRoot: params.job.repoRoot,
|
|
23348
|
+
repoFingerprint: params.job.repoFingerprint,
|
|
23349
|
+
laneId: params.job.laneId,
|
|
23350
|
+
currentAppId: params.job.currentAppId,
|
|
23351
|
+
branchName: params.job.branchName,
|
|
23352
|
+
lastSnapshotId: params.snapshot.id,
|
|
23353
|
+
lastSnapshotHash: params.snapshot.snapshotHash,
|
|
23354
|
+
lastServerRevisionId: nextServerRevisionId,
|
|
23355
|
+
lastServerTreeHash: nextServerTreeHash,
|
|
23356
|
+
lastServerHeadHash: nextServerHeadHash,
|
|
23357
|
+
lastSeenLocalCommitHash: params.snapshot.localCommitHash
|
|
23358
|
+
});
|
|
23359
|
+
}
|
|
23250
23360
|
async function harvestPreTurnEvents(repoRoot, fromCommit, toCommit) {
|
|
23251
23361
|
if (!toCommit) return null;
|
|
23252
23362
|
try {
|
|
@@ -23307,12 +23417,12 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23307
23417
|
throw buildFinalizeCliError({
|
|
23308
23418
|
message: "Local baseline is missing for this queued finalize job.",
|
|
23309
23419
|
exitCode: 2,
|
|
23310
|
-
hint: "Run `remix collab
|
|
23420
|
+
hint: "Run `remix collab init` to seed this checkout's revision baseline.",
|
|
23311
23421
|
disposition: "terminal",
|
|
23312
23422
|
reason: "baseline_missing"
|
|
23313
23423
|
});
|
|
23314
23424
|
}
|
|
23315
|
-
const baselineDrifted = baseline.lastSnapshotId !== job.baselineSnapshotId || baseline.lastServerHeadHash !== job.baselineServerHeadHash;
|
|
23425
|
+
const baselineDrifted = baseline.lastSnapshotId !== job.baselineSnapshotId || (job.baselineServerRevisionId ? baseline.lastServerRevisionId !== job.baselineServerRevisionId : false) || baseline.lastServerHeadHash !== job.baselineServerHeadHash;
|
|
23316
23426
|
const appHead = unwrapResponseObject(appHeadResp, "app head");
|
|
23317
23427
|
const remoteUrl = readMetadataString(job, "remoteUrl");
|
|
23318
23428
|
const defaultBranch = readMetadataString(job, "defaultBranch");
|
|
@@ -23335,12 +23445,13 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23335
23445
|
throw buildFinalizeCliError({
|
|
23336
23446
|
message: "Finalize queue baseline drifted before this job was processed.",
|
|
23337
23447
|
exitCode: 1,
|
|
23338
|
-
hint: "Process queued finalize jobs in capture order, or
|
|
23448
|
+
hint: "Process queued finalize jobs in capture order, or run `remix collab init` to refresh the revision baseline before retrying.",
|
|
23339
23449
|
disposition: "terminal",
|
|
23340
23450
|
reason: "baseline_drifted"
|
|
23341
23451
|
});
|
|
23342
23452
|
}
|
|
23343
|
-
|
|
23453
|
+
const serverStillAtBaseline = job.baselineServerRevisionId ? appHead.headRevisionId === job.baselineServerRevisionId : appHead.headCommitHash === job.baselineServerHeadHash;
|
|
23454
|
+
if (!serverStillAtBaseline) {
|
|
23344
23455
|
throw buildFinalizeCliError({
|
|
23345
23456
|
message: "Server lane changed before a no-diff turn could be recorded.",
|
|
23346
23457
|
exitCode: 2,
|
|
@@ -23362,6 +23473,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23362
23473
|
defaultBranch,
|
|
23363
23474
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23364
23475
|
currentSnapshotId: job.currentSnapshotId,
|
|
23476
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23365
23477
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23366
23478
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23367
23479
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23382,6 +23494,8 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23382
23494
|
branchName: job.branchName,
|
|
23383
23495
|
lastSnapshotId: snapshot.id,
|
|
23384
23496
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
23497
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
23498
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
23385
23499
|
lastServerHeadHash: appHead.headCommitHash,
|
|
23386
23500
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23387
23501
|
});
|
|
@@ -23402,14 +23516,14 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23402
23516
|
};
|
|
23403
23517
|
}
|
|
23404
23518
|
const localBaselineAdvanced = baseline.lastSnapshotId !== job.baselineSnapshotId;
|
|
23405
|
-
const serverHeadAdvanced = appHead.headCommitHash !== job.baselineServerHeadHash;
|
|
23519
|
+
const serverHeadAdvanced = job.baselineServerRevisionId ? appHead.headRevisionId !== job.baselineServerRevisionId : appHead.headCommitHash !== job.baselineServerHeadHash;
|
|
23406
23520
|
if (baselineDrifted) {
|
|
23407
23521
|
const consistentAdvance = localBaselineAdvanced && serverHeadAdvanced;
|
|
23408
23522
|
if (!consistentAdvance) {
|
|
23409
23523
|
throw buildFinalizeCliError({
|
|
23410
23524
|
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
23525
|
exitCode: 1,
|
|
23412
|
-
hint: "Run `remix collab status` to inspect, then
|
|
23526
|
+
hint: "Run `remix collab status` to inspect, then sync or reconcile before retrying.",
|
|
23413
23527
|
disposition: "terminal",
|
|
23414
23528
|
reason: "baseline_drifted"
|
|
23415
23529
|
});
|
|
@@ -23417,6 +23531,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23417
23531
|
}
|
|
23418
23532
|
let submissionDiff = diffResult.diff;
|
|
23419
23533
|
let submissionBaseHeadHash = job.baselineServerHeadHash;
|
|
23534
|
+
let submissionBaseRevisionId = job.baselineServerRevisionId;
|
|
23420
23535
|
let replayedFromBaseHash = null;
|
|
23421
23536
|
if (!submissionBaseHeadHash) {
|
|
23422
23537
|
throw buildFinalizeCliError({
|
|
@@ -23427,6 +23542,34 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23427
23542
|
});
|
|
23428
23543
|
}
|
|
23429
23544
|
const replayNeeded = appHead.headCommitHash !== submissionBaseHeadHash || baselineDrifted;
|
|
23545
|
+
if (replayNeeded) {
|
|
23546
|
+
const existingChangeStep = await findExistingChangeStepByIdempotency({
|
|
23547
|
+
api: params.api,
|
|
23548
|
+
appId: job.currentAppId,
|
|
23549
|
+
idempotencyKey: job.idempotencyKey
|
|
23550
|
+
});
|
|
23551
|
+
if (existingChangeStep) {
|
|
23552
|
+
const changeStep2 = existingChangeStep.status === "succeeded" ? existingChangeStep : await pollChangeStep(params.api, job.currentAppId, existingChangeStep.id);
|
|
23553
|
+
invalidateAppHeadCache(job.currentAppId);
|
|
23554
|
+
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
23555
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep: changeStep2 });
|
|
23556
|
+
await updatePendingFinalizeJob(job.id, {
|
|
23557
|
+
status: "completed",
|
|
23558
|
+
metadata: { changeStepId: String(changeStep2.id ?? "") }
|
|
23559
|
+
});
|
|
23560
|
+
return {
|
|
23561
|
+
mode: "changed_turn",
|
|
23562
|
+
idempotencyKey: job.idempotencyKey ?? "",
|
|
23563
|
+
queued: false,
|
|
23564
|
+
jobId: job.id,
|
|
23565
|
+
repoState,
|
|
23566
|
+
changeStep: changeStep2,
|
|
23567
|
+
collabTurn: null,
|
|
23568
|
+
autoSync: null,
|
|
23569
|
+
warnings: []
|
|
23570
|
+
};
|
|
23571
|
+
}
|
|
23572
|
+
}
|
|
23430
23573
|
if (replayNeeded) {
|
|
23431
23574
|
try {
|
|
23432
23575
|
const replayResp = await params.api.startChangeStepReplay(job.currentAppId, {
|
|
@@ -23434,7 +23577,9 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23434
23577
|
assistantResponse: job.assistantResponse,
|
|
23435
23578
|
diff: diffResult.diff,
|
|
23436
23579
|
baseCommitHash: submissionBaseHeadHash,
|
|
23580
|
+
baseRevisionId: job.baselineServerRevisionId,
|
|
23437
23581
|
targetHeadCommitHash: appHead.headCommitHash,
|
|
23582
|
+
targetRevisionId: appHead.headRevisionId,
|
|
23438
23583
|
expectedPaths: diffResult.changedPaths,
|
|
23439
23584
|
actor,
|
|
23440
23585
|
workspaceMetadata: buildWorkspaceMetadata({
|
|
@@ -23444,6 +23589,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23444
23589
|
defaultBranch,
|
|
23445
23590
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23446
23591
|
currentSnapshotId: job.currentSnapshotId,
|
|
23592
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23447
23593
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23448
23594
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23449
23595
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23469,6 +23615,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23469
23615
|
submissionDiff = replayDiff.diff;
|
|
23470
23616
|
replayedFromBaseHash = submissionBaseHeadHash;
|
|
23471
23617
|
submissionBaseHeadHash = appHead.headCommitHash;
|
|
23618
|
+
submissionBaseRevisionId = appHead.headRevisionId;
|
|
23472
23619
|
} catch (error2) {
|
|
23473
23620
|
if (error2 instanceof RemixError && error2.finalizeDisposition === void 0) {
|
|
23474
23621
|
const detail = error2.hint ? `${error2.message} (${error2.hint})` : error2.message;
|
|
@@ -23490,6 +23637,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23490
23637
|
assistantResponse: job.assistantResponse,
|
|
23491
23638
|
diff: submissionDiff,
|
|
23492
23639
|
baseCommitHash: submissionBaseHeadHash,
|
|
23640
|
+
baseRevisionId: submissionBaseRevisionId,
|
|
23493
23641
|
headCommitHash: submissionBaseHeadHash,
|
|
23494
23642
|
changedFilesCount: diffResult.stats.changedFilesCount,
|
|
23495
23643
|
insertions: diffResult.stats.insertions,
|
|
@@ -23502,6 +23650,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23502
23650
|
defaultBranch,
|
|
23503
23651
|
baselineSnapshotId: job.baselineSnapshotId,
|
|
23504
23652
|
currentSnapshotId: job.currentSnapshotId,
|
|
23653
|
+
baselineServerRevisionId: job.baselineServerRevisionId,
|
|
23505
23654
|
baselineServerHeadHash: job.baselineServerHeadHash,
|
|
23506
23655
|
currentSnapshotHash: snapshot.snapshotHash,
|
|
23507
23656
|
localCommitHash: snapshot.localCommitHash,
|
|
@@ -23518,27 +23667,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23518
23667
|
const changeStep = await pollChangeStep(params.api, job.currentAppId, String(createdStep.id));
|
|
23519
23668
|
invalidateAppHeadCache(job.currentAppId);
|
|
23520
23669
|
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
23521
|
-
|
|
23522
|
-
if (!nextServerHeadHash) {
|
|
23523
|
-
throw buildFinalizeCliError({
|
|
23524
|
-
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
23525
|
-
exitCode: 1,
|
|
23526
|
-
hint: "This is a backend invariant violation; retry will not help. Re-anchor and try again.",
|
|
23527
|
-
disposition: "terminal",
|
|
23528
|
-
reason: "missing_head_commit_hash"
|
|
23529
|
-
});
|
|
23530
|
-
}
|
|
23531
|
-
await writeLocalBaseline({
|
|
23532
|
-
repoRoot: job.repoRoot,
|
|
23533
|
-
repoFingerprint: job.repoFingerprint,
|
|
23534
|
-
laneId: job.laneId,
|
|
23535
|
-
currentAppId: job.currentAppId,
|
|
23536
|
-
branchName: job.branchName,
|
|
23537
|
-
lastSnapshotId: snapshot.id,
|
|
23538
|
-
lastSnapshotHash: snapshot.snapshotHash,
|
|
23539
|
-
lastServerHeadHash: nextServerHeadHash,
|
|
23540
|
-
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23541
|
-
});
|
|
23670
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep });
|
|
23542
23671
|
await updatePendingFinalizeJob(job.id, {
|
|
23543
23672
|
status: "completed",
|
|
23544
23673
|
metadata: { changeStepId: String(changeStep.id ?? "") }
|
|
@@ -23596,9 +23725,10 @@ var FINALIZE_PREFLIGHT_FAILURE_CODES = [
|
|
|
23596
23725
|
// Server has commits we don't. Fix: `remix collab sync` (safe to
|
|
23597
23726
|
// auto-run for fast-forward; non-FF refused by the command itself).
|
|
23598
23727
|
"pull_required",
|
|
23599
|
-
//
|
|
23600
|
-
|
|
23601
|
-
|
|
23728
|
+
// Both local and server changed. Fix: inspect and apply reconcile.
|
|
23729
|
+
"reconcile_required",
|
|
23730
|
+
// Local revision baseline is missing. Fix: `remix collab init` or sync.
|
|
23731
|
+
"baseline_missing"
|
|
23602
23732
|
];
|
|
23603
23733
|
var CODE_SET = new Set(FINALIZE_PREFLIGHT_FAILURE_CODES);
|
|
23604
23734
|
var DEFAULT_ACQUIRE_TIMEOUT_MS = 15e3;
|
|
@@ -23818,7 +23948,7 @@ async function ensureWorkspaceMatchesBaseline(params) {
|
|
|
23818
23948
|
if (!baseline?.lastSnapshotHash || !baseline.lastServerHeadHash) {
|
|
23819
23949
|
throw new RemixError("Local Remix baseline is missing for this lane.", {
|
|
23820
23950
|
exitCode: 2,
|
|
23821
|
-
hint: "Run `remix collab
|
|
23951
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline before applying server changes."
|
|
23822
23952
|
});
|
|
23823
23953
|
}
|
|
23824
23954
|
const inspection = await inspectLocalSnapshot({
|
|
@@ -23890,11 +24020,12 @@ async function collabSync(params) {
|
|
|
23890
24020
|
const repoSnapshot = await captureRepoSnapshot(repoRoot, { includeWorkspaceDiffHash: true });
|
|
23891
24021
|
const bootstrapFromLocalHead = !detected.baseline.lastSnapshotHash || !detected.baseline.lastServerHeadHash;
|
|
23892
24022
|
let baselineServerHeadHash;
|
|
24023
|
+
let baselineServerRevisionId = null;
|
|
23893
24024
|
if (bootstrapFromLocalHead) {
|
|
23894
24025
|
if (!headCommitHash) {
|
|
23895
24026
|
throw new RemixError("Failed to resolve local HEAD commit for the initial sync bootstrap.", {
|
|
23896
24027
|
exitCode: 1,
|
|
23897
|
-
hint: "Retry after Git HEAD is available, or run `remix collab
|
|
24028
|
+
hint: "Retry after Git HEAD is available, or run `remix collab init` to seed this checkout's revision baseline."
|
|
23898
24029
|
});
|
|
23899
24030
|
}
|
|
23900
24031
|
baselineServerHeadHash = headCommitHash;
|
|
@@ -23909,13 +24040,15 @@ async function collabSync(params) {
|
|
|
23909
24040
|
if (!baseline.lastServerHeadHash) {
|
|
23910
24041
|
throw new RemixError("Local Remix baseline is missing the last acknowledged server head.", {
|
|
23911
24042
|
exitCode: 2,
|
|
23912
|
-
hint: "Run `remix collab
|
|
24043
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline before pulling server changes."
|
|
23913
24044
|
});
|
|
23914
24045
|
}
|
|
23915
24046
|
baselineServerHeadHash = baseline.lastServerHeadHash;
|
|
24047
|
+
baselineServerRevisionId = baseline.lastServerRevisionId;
|
|
23916
24048
|
}
|
|
23917
24049
|
const deltaResp = await params.api.getAppDelta(binding.currentAppId, {
|
|
23918
24050
|
baseHeadHash: baselineServerHeadHash,
|
|
24051
|
+
baseRevisionId: baselineServerRevisionId,
|
|
23919
24052
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
23920
24053
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
23921
24054
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -23939,13 +24072,54 @@ async function collabSync(params) {
|
|
|
23939
24072
|
applied: false,
|
|
23940
24073
|
dryRun: params.dryRun
|
|
23941
24074
|
};
|
|
23942
|
-
if (params.dryRun
|
|
24075
|
+
if (params.dryRun) {
|
|
23943
24076
|
return previewResult;
|
|
23944
24077
|
}
|
|
24078
|
+
if (delta.status === "up_to_date") {
|
|
24079
|
+
if (!bootstrapFromLocalHead) {
|
|
24080
|
+
return previewResult;
|
|
24081
|
+
}
|
|
24082
|
+
return withRepoMutationLock(
|
|
24083
|
+
{
|
|
24084
|
+
cwd: repoRoot,
|
|
24085
|
+
operation: "collabSync"
|
|
24086
|
+
},
|
|
24087
|
+
async ({ repoRoot: lockedRepoRoot, warnings }) => {
|
|
24088
|
+
await assertRepoSnapshotUnchanged(lockedRepoRoot, repoSnapshot, {
|
|
24089
|
+
operation: "`remix collab sync`",
|
|
24090
|
+
recoveryHint: "The repository changed before the first local Remix baseline could be created. Review the local changes and rerun `remix collab sync`."
|
|
24091
|
+
});
|
|
24092
|
+
const snapshot = await captureLocalSnapshot({
|
|
24093
|
+
repoRoot: lockedRepoRoot,
|
|
24094
|
+
repoFingerprint: binding.repoFingerprint,
|
|
24095
|
+
laneId: binding.laneId,
|
|
24096
|
+
branchName: binding.branchName
|
|
24097
|
+
});
|
|
24098
|
+
await writeLocalBaseline({
|
|
24099
|
+
repoRoot: lockedRepoRoot,
|
|
24100
|
+
repoFingerprint: binding.repoFingerprint,
|
|
24101
|
+
laneId: binding.laneId,
|
|
24102
|
+
currentAppId: binding.currentAppId,
|
|
24103
|
+
branchName: binding.branchName,
|
|
24104
|
+
lastSnapshotId: snapshot.id,
|
|
24105
|
+
lastSnapshotHash: snapshot.snapshotHash,
|
|
24106
|
+
lastServerRevisionId: delta.targetRevisionId ?? null,
|
|
24107
|
+
lastServerTreeHash: delta.targetTreeHash ?? null,
|
|
24108
|
+
lastServerHeadHash: delta.targetHeadHash,
|
|
24109
|
+
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24110
|
+
});
|
|
24111
|
+
return {
|
|
24112
|
+
...previewResult,
|
|
24113
|
+
localCommitHash: snapshot.localCommitHash,
|
|
24114
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
24115
|
+
};
|
|
24116
|
+
}
|
|
24117
|
+
);
|
|
24118
|
+
}
|
|
23945
24119
|
if (delta.status === "base_unknown") {
|
|
23946
24120
|
throw new RemixError("Direct pull is unavailable because Remix can no longer diff from the last acknowledged server head.", {
|
|
23947
24121
|
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
|
|
24122
|
+
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
24123
|
});
|
|
23950
24124
|
}
|
|
23951
24125
|
if (delta.status !== "delta_ready") {
|
|
@@ -23989,6 +24163,8 @@ async function collabSync(params) {
|
|
|
23989
24163
|
branchName: binding.branchName,
|
|
23990
24164
|
lastSnapshotId: snapshot.id,
|
|
23991
24165
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24166
|
+
lastServerRevisionId: delta.targetRevisionId ?? null,
|
|
24167
|
+
lastServerTreeHash: delta.targetTreeHash ?? null,
|
|
23992
24168
|
lastServerHeadHash: delta.targetHeadHash,
|
|
23993
24169
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23994
24170
|
});
|
|
@@ -24274,6 +24450,8 @@ async function collabCheckout(params) {
|
|
|
24274
24450
|
branchName: branchNameForBaseline,
|
|
24275
24451
|
lastSnapshotId: snapshot.id,
|
|
24276
24452
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24453
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
24454
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
24277
24455
|
lastServerHeadHash: appHead.headCommitHash,
|
|
24278
24456
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24279
24457
|
});
|
|
@@ -24631,25 +24809,21 @@ async function trySeedEquivalentBranchBaseline(params) {
|
|
|
24631
24809
|
branchName: params.branchName,
|
|
24632
24810
|
persistBlobs: false
|
|
24633
24811
|
});
|
|
24634
|
-
if (inspection.snapshotHash !== defaultBaseline.lastSnapshotHash) {
|
|
24812
|
+
if (inspection.snapshotHash !== defaultBaseline.lastSnapshotHash && inspection.localCommitHash !== defaultBaseline.lastSeenLocalCommitHash) {
|
|
24635
24813
|
return null;
|
|
24636
24814
|
}
|
|
24637
|
-
const snapshot = await captureLocalSnapshot({
|
|
24638
|
-
repoRoot: params.repoRoot,
|
|
24639
|
-
repoFingerprint: params.repoFingerprint,
|
|
24640
|
-
laneId: params.laneId,
|
|
24641
|
-
branchName: params.branchName
|
|
24642
|
-
});
|
|
24643
24815
|
await writeLocalBaseline({
|
|
24644
24816
|
repoRoot: params.repoRoot,
|
|
24645
24817
|
repoFingerprint: params.repoFingerprint,
|
|
24646
24818
|
laneId: params.laneId,
|
|
24647
24819
|
currentAppId: params.currentAppId,
|
|
24648
24820
|
branchName: params.branchName,
|
|
24649
|
-
lastSnapshotId:
|
|
24650
|
-
lastSnapshotHash:
|
|
24821
|
+
lastSnapshotId: defaultBaseline.lastSnapshotId,
|
|
24822
|
+
lastSnapshotHash: defaultBaseline.lastSnapshotHash,
|
|
24823
|
+
lastServerRevisionId: params.appHeadRevisionId,
|
|
24824
|
+
lastServerTreeHash: params.appTreeHash,
|
|
24651
24825
|
lastServerHeadHash: params.appHeadHash,
|
|
24652
|
-
lastSeenLocalCommitHash:
|
|
24826
|
+
lastSeenLocalCommitHash: inspection.localCommitHash
|
|
24653
24827
|
});
|
|
24654
24828
|
return "seeded";
|
|
24655
24829
|
}
|
|
@@ -24659,11 +24833,11 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24659
24833
|
laneId: params.laneId,
|
|
24660
24834
|
repoRoot: params.repoRoot
|
|
24661
24835
|
});
|
|
24662
|
-
if (baseline?.lastSnapshotHash && baseline.lastServerHeadHash) {
|
|
24836
|
+
if (baseline?.lastSnapshotHash && (baseline.lastServerRevisionId || baseline.lastServerHeadHash)) {
|
|
24663
24837
|
return "existing";
|
|
24664
24838
|
}
|
|
24665
24839
|
const localHeadCommitHash = await getHeadCommitHash(params.repoRoot);
|
|
24666
|
-
if (!localHeadCommitHash) return "
|
|
24840
|
+
if (!localHeadCommitHash) return "baseline_missing";
|
|
24667
24841
|
const appHead = unwrapResponseObject(
|
|
24668
24842
|
await params.api.getAppHead(params.currentAppId),
|
|
24669
24843
|
"app head"
|
|
@@ -24690,6 +24864,7 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24690
24864
|
const deltaResp = await params.api.getAppDelta(params.currentAppId, {
|
|
24691
24865
|
baseHeadHash: localHeadCommitHash,
|
|
24692
24866
|
targetHeadHash: appHead.headCommitHash,
|
|
24867
|
+
targetRevisionId: appHead.headRevisionId,
|
|
24693
24868
|
localSnapshotHash,
|
|
24694
24869
|
repoFingerprint: params.repoFingerprint,
|
|
24695
24870
|
remoteUrl: params.remoteUrl ?? void 0,
|
|
@@ -24697,6 +24872,21 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24697
24872
|
});
|
|
24698
24873
|
const delta = unwrapResponseObject(deltaResp, "app delta");
|
|
24699
24874
|
if (delta.status === "up_to_date" || delta.status === "delta_ready") {
|
|
24875
|
+
const equivalentBaseline = await trySeedEquivalentBranchBaseline({
|
|
24876
|
+
repoRoot: params.repoRoot,
|
|
24877
|
+
repoFingerprint: params.repoFingerprint,
|
|
24878
|
+
laneId: params.laneId,
|
|
24879
|
+
currentAppId: params.currentAppId,
|
|
24880
|
+
upstreamAppId: params.upstreamAppId ?? null,
|
|
24881
|
+
branchName: params.branchName,
|
|
24882
|
+
defaultBranch: params.defaultBranch,
|
|
24883
|
+
appHeadHash: appHead.headCommitHash,
|
|
24884
|
+
appHeadRevisionId: appHead.headRevisionId ?? null,
|
|
24885
|
+
appTreeHash: appHead.treeHash ?? null
|
|
24886
|
+
});
|
|
24887
|
+
if (equivalentBaseline) {
|
|
24888
|
+
return equivalentBaseline;
|
|
24889
|
+
}
|
|
24700
24890
|
return "requires_sync";
|
|
24701
24891
|
}
|
|
24702
24892
|
if (delta.status === "content_equivalent") {
|
|
@@ -24719,7 +24909,9 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24719
24909
|
upstreamAppId: params.upstreamAppId ?? null,
|
|
24720
24910
|
branchName: params.branchName,
|
|
24721
24911
|
defaultBranch: params.defaultBranch,
|
|
24722
|
-
appHeadHash: appHead.headCommitHash
|
|
24912
|
+
appHeadHash: appHead.headCommitHash,
|
|
24913
|
+
appHeadRevisionId: appHead.headRevisionId ?? null,
|
|
24914
|
+
appTreeHash: appHead.treeHash ?? null
|
|
24723
24915
|
});
|
|
24724
24916
|
if (equivalentBaseline) {
|
|
24725
24917
|
return equivalentBaseline;
|
|
@@ -24727,7 +24919,7 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24727
24919
|
}
|
|
24728
24920
|
} catch {
|
|
24729
24921
|
}
|
|
24730
|
-
return "
|
|
24922
|
+
return "baseline_missing";
|
|
24731
24923
|
}
|
|
24732
24924
|
async function seedImportedInitBaseline(params) {
|
|
24733
24925
|
const appHead = unwrapResponseObject(
|
|
@@ -24748,6 +24940,8 @@ async function seedImportedInitBaseline(params) {
|
|
|
24748
24940
|
branchName: params.branchName,
|
|
24749
24941
|
lastSnapshotId: snapshot.id,
|
|
24750
24942
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
24943
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
24944
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
24751
24945
|
lastServerHeadHash: appHead.headCommitHash,
|
|
24752
24946
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
24753
24947
|
});
|
|
@@ -24761,7 +24955,6 @@ async function collabInit(params) {
|
|
|
24761
24955
|
},
|
|
24762
24956
|
async ({ repoRoot, warnings }) => {
|
|
24763
24957
|
await ensureGitInfoExcludeEntries(repoRoot, [".remix/"]);
|
|
24764
|
-
await ensureCleanWorktree(repoRoot, "`remix collab init`");
|
|
24765
24958
|
if (params.path?.trim()) {
|
|
24766
24959
|
throw new RemixError("`remix collab init --path` is not supported.", {
|
|
24767
24960
|
exitCode: 2,
|
|
@@ -24769,6 +24962,10 @@ async function collabInit(params) {
|
|
|
24769
24962
|
});
|
|
24770
24963
|
}
|
|
24771
24964
|
const localBindingState = await readCollabBindingState(repoRoot, { persist: true });
|
|
24965
|
+
const hasExistingBinding = localBindingState != null && Object.keys(localBindingState.branchBindings ?? {}).length > 0;
|
|
24966
|
+
if (params.forceNew || !hasExistingBinding) {
|
|
24967
|
+
await ensureCleanWorktree(repoRoot, "`remix collab init`");
|
|
24968
|
+
}
|
|
24772
24969
|
const persistedRemoteUrl = normalizeGitRemote(localBindingState?.remoteUrl ?? null);
|
|
24773
24970
|
const currentBranch = await getCurrentBranch(repoRoot);
|
|
24774
24971
|
const defaultBranch = localBindingState?.defaultBranch ?? await getDefaultBranch(repoRoot) ?? currentBranch;
|
|
@@ -25620,248 +25817,6 @@ function hasPendingFinalize(summary) {
|
|
|
25620
25817
|
function buildPendingFinalizeHint() {
|
|
25621
25818
|
return "Drain or await the local finalize queue first, then retry after the queued Remix turn finishes recording remotely.";
|
|
25622
25819
|
}
|
|
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
25820
|
async function reconcileBothChanged(params) {
|
|
25866
25821
|
const repoRoot = await findGitRoot(params.cwd);
|
|
25867
25822
|
const binding = await ensureActiveLaneBinding({
|
|
@@ -25884,7 +25839,7 @@ async function reconcileBothChanged(params) {
|
|
|
25884
25839
|
if (!baseline?.lastSnapshotId || !baseline.lastServerHeadHash) {
|
|
25885
25840
|
throw new RemixError("Local Remix baseline is missing for this lane.", {
|
|
25886
25841
|
exitCode: 2,
|
|
25887
|
-
hint: "Run `remix collab
|
|
25842
|
+
hint: "Run `remix collab init` or sync from a checkout with a valid revision baseline first."
|
|
25888
25843
|
});
|
|
25889
25844
|
}
|
|
25890
25845
|
const currentSnapshot = await captureLocalSnapshot({
|
|
@@ -25907,6 +25862,7 @@ async function reconcileBothChanged(params) {
|
|
|
25907
25862
|
params.api.getAppHead(binding.currentAppId),
|
|
25908
25863
|
params.api.getAppDelta(binding.currentAppId, {
|
|
25909
25864
|
baseHeadHash: baseline.lastServerHeadHash,
|
|
25865
|
+
baseRevisionId: baseline.lastServerRevisionId,
|
|
25910
25866
|
repoFingerprint: binding.repoFingerprint ?? void 0,
|
|
25911
25867
|
remoteUrl: binding.remoteUrl ?? void 0,
|
|
25912
25868
|
defaultBranch: binding.defaultBranch ?? void 0
|
|
@@ -25924,7 +25880,7 @@ async function reconcileBothChanged(params) {
|
|
|
25924
25880
|
if (delta.status === "base_unknown") {
|
|
25925
25881
|
throw new RemixError("Reconcile cannot pull the newer server state from the last acknowledged baseline.", {
|
|
25926
25882
|
exitCode: 2,
|
|
25927
|
-
hint: "Run `remix collab
|
|
25883
|
+
hint: "Run `remix collab init` to seed a fresh revision baseline for this checkout before retrying."
|
|
25928
25884
|
});
|
|
25929
25885
|
}
|
|
25930
25886
|
if (delta.status !== "delta_ready" && delta.status !== "up_to_date") {
|
|
@@ -25955,7 +25911,9 @@ async function reconcileBothChanged(params) {
|
|
|
25955
25911
|
assistantResponse: "Replay the local boundary delta onto the latest server head without recording a new change step.",
|
|
25956
25912
|
diff: diffResult.diff,
|
|
25957
25913
|
baseCommitHash: baseline.lastServerHeadHash,
|
|
25914
|
+
baseRevisionId: baseline.lastServerRevisionId,
|
|
25958
25915
|
targetHeadCommitHash: appHead.headCommitHash,
|
|
25916
|
+
targetRevisionId: appHead.headRevisionId,
|
|
25959
25917
|
expectedPaths: diffResult.changedPaths,
|
|
25960
25918
|
workspaceMetadata: {
|
|
25961
25919
|
recordingMode: "boundary_delta",
|
|
@@ -25963,6 +25921,7 @@ async function reconcileBothChanged(params) {
|
|
|
25963
25921
|
branch,
|
|
25964
25922
|
baselineSnapshotId: baseline.lastSnapshotId,
|
|
25965
25923
|
currentSnapshotId: currentSnapshot.id,
|
|
25924
|
+
baselineServerRevisionId: baseline.lastServerRevisionId,
|
|
25966
25925
|
baselineServerHeadHash: baseline.lastServerHeadHash,
|
|
25967
25926
|
currentSnapshotHash: currentSnapshot.snapshotHash,
|
|
25968
25927
|
localCommitHash: currentSnapshot.localCommitHash,
|
|
@@ -25981,12 +25940,12 @@ async function reconcileBothChanged(params) {
|
|
|
25981
25940
|
const replay = await pollChangeStepReplay(params.api, binding.currentAppId, String(replayStart.id));
|
|
25982
25941
|
const replayDiffResp = await params.api.getChangeStepReplayDiff(binding.currentAppId, replay.id);
|
|
25983
25942
|
const replayDiff = unwrapResponseObject(replayDiffResp, "change step replay diff");
|
|
25984
|
-
const tempRoot = await
|
|
25943
|
+
const tempRoot = await import_promises23.default.mkdtemp(import_path12.default.join(import_os6.default.tmpdir(), "remix-reconcile-"));
|
|
25985
25944
|
let serverHeadSnapshot = null;
|
|
25986
25945
|
let mergedSnapshot = null;
|
|
25987
25946
|
try {
|
|
25988
|
-
const tempRepoRoot =
|
|
25989
|
-
await
|
|
25947
|
+
const tempRepoRoot = import_path12.default.join(tempRoot, "repo");
|
|
25948
|
+
await import_promises23.default.mkdir(tempRepoRoot, { recursive: true });
|
|
25990
25949
|
await execa("git", ["init"], { cwd: tempRepoRoot, stderr: "ignore" });
|
|
25991
25950
|
await materializeLocalSnapshot(baseline.lastSnapshotId, tempRepoRoot);
|
|
25992
25951
|
if (delta.status === "delta_ready" && delta.diff.trim()) {
|
|
@@ -26008,7 +25967,7 @@ async function reconcileBothChanged(params) {
|
|
|
26008
25967
|
branchName: binding.branchName
|
|
26009
25968
|
});
|
|
26010
25969
|
} finally {
|
|
26011
|
-
await
|
|
25970
|
+
await import_promises23.default.rm(tempRoot, { recursive: true, force: true }).catch(() => void 0);
|
|
26012
25971
|
}
|
|
26013
25972
|
if (!serverHeadSnapshot || !mergedSnapshot) {
|
|
26014
25973
|
throw new RemixError("Failed to materialize the reconciled local workspace.", { exitCode: 1 });
|
|
@@ -26045,6 +26004,8 @@ async function reconcileBothChanged(params) {
|
|
|
26045
26004
|
branchName: binding.branchName,
|
|
26046
26005
|
lastSnapshotId: serverHeadSnapshot.id,
|
|
26047
26006
|
lastSnapshotHash: serverHeadSnapshot.snapshotHash,
|
|
26007
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
26008
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
26048
26009
|
lastServerHeadHash: appHead.headCommitHash,
|
|
26049
26010
|
lastSeenLocalCommitHash: restoredSnapshot.localCommitHash
|
|
26050
26011
|
});
|
|
@@ -26080,7 +26041,10 @@ async function collabReconcile(params) {
|
|
|
26080
26041
|
return reconcileBothChanged(params);
|
|
26081
26042
|
}
|
|
26082
26043
|
if (detected.repoState === "external_local_base_changed") {
|
|
26083
|
-
|
|
26044
|
+
throw new RemixError("This checkout needs a local Remix revision baseline before reconciliation.", {
|
|
26045
|
+
exitCode: 2,
|
|
26046
|
+
hint: detected.hint || "Run `remix collab init` or `remix collab sync` to seed the baseline."
|
|
26047
|
+
});
|
|
26084
26048
|
}
|
|
26085
26049
|
if (detected.repoState === "local_only_changed") {
|
|
26086
26050
|
if (hasPendingFinalize(detected.pendingFinalize)) {
|
|
@@ -26187,6 +26151,8 @@ async function collabRemix(params) {
|
|
|
26187
26151
|
branchName: branchNameForBaseline,
|
|
26188
26152
|
lastSnapshotId: snapshot.id,
|
|
26189
26153
|
lastSnapshotHash: snapshot.snapshotHash,
|
|
26154
|
+
lastServerRevisionId: appHead.headRevisionId ?? null,
|
|
26155
|
+
lastServerTreeHash: appHead.treeHash ?? null,
|
|
26190
26156
|
lastServerHeadHash: appHead.headCommitHash,
|
|
26191
26157
|
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
26192
26158
|
});
|
|
@@ -26307,11 +26273,15 @@ function createBaseStatus() {
|
|
|
26307
26273
|
baseline: {
|
|
26308
26274
|
lastSnapshotId: null,
|
|
26309
26275
|
lastSnapshotHash: null,
|
|
26276
|
+
lastServerRevisionId: null,
|
|
26277
|
+
lastServerTreeHash: null,
|
|
26310
26278
|
lastServerHeadHash: null,
|
|
26311
26279
|
lastSeenLocalCommitHash: null
|
|
26312
26280
|
},
|
|
26313
26281
|
current: {
|
|
26314
26282
|
snapshotHash: null,
|
|
26283
|
+
serverRevisionId: null,
|
|
26284
|
+
serverTreeHash: null,
|
|
26315
26285
|
serverHeadHash: null,
|
|
26316
26286
|
serverHeadCommitId: null,
|
|
26317
26287
|
localCommitHash: null
|
|
@@ -26398,6 +26368,8 @@ async function collabStatus(params) {
|
|
|
26398
26368
|
status.alignment.baseline = detected.baseline;
|
|
26399
26369
|
status.alignment.current = {
|
|
26400
26370
|
snapshotHash: detected.currentSnapshotHash,
|
|
26371
|
+
serverRevisionId: detected.currentServerRevisionId,
|
|
26372
|
+
serverTreeHash: detected.currentServerTreeHash,
|
|
26401
26373
|
serverHeadHash: detected.currentServerHeadHash,
|
|
26402
26374
|
serverHeadCommitId: detected.currentServerHeadCommitId,
|
|
26403
26375
|
localCommitHash: detected.localCommitHash
|
|
@@ -26461,7 +26433,7 @@ async function collabStatus(params) {
|
|
|
26461
26433
|
status.reconcile.canApply = !status.repo.branchMismatch;
|
|
26462
26434
|
status.recommendedAction = "reconcile";
|
|
26463
26435
|
} else if (detected.repoState === "external_local_base_changed") {
|
|
26464
|
-
status.recommendedAction = "
|
|
26436
|
+
status.recommendedAction = "init";
|
|
26465
26437
|
addBlockedReason(status.sync, "baseline_missing");
|
|
26466
26438
|
addBlockedReason(status.reconcile, "baseline_missing");
|
|
26467
26439
|
} else if (detected.repoState === "local_only_changed") {
|
|
@@ -26714,10 +26686,10 @@ async function processInitJob(job, api) {
|
|
|
26714
26686
|
try {
|
|
26715
26687
|
await updateAsyncJob(job.id, { status: "submitting", error: null });
|
|
26716
26688
|
await logDrainerEvent(job.id, "claimed", { kind: "init" });
|
|
26717
|
-
const bundleStat = await
|
|
26689
|
+
const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
|
|
26718
26690
|
const presignResp = await api.presignImportUploadFirstParty({
|
|
26719
26691
|
file: {
|
|
26720
|
-
name:
|
|
26692
|
+
name: import_path13.default.basename(job.payload.bundlePath),
|
|
26721
26693
|
mimeType: "application/x-git-bundle",
|
|
26722
26694
|
size: bundleStat.size,
|
|
26723
26695
|
checksumSha256: job.payload.bundleSha256
|
|
@@ -26734,7 +26706,7 @@ async function processInitJob(job, api) {
|
|
|
26734
26706
|
await updateAsyncJob(job.id, { status: "server_processing" });
|
|
26735
26707
|
const importResp = await api.importFromUploadFirstParty({
|
|
26736
26708
|
uploadId: String(presign.uploadId),
|
|
26737
|
-
appName: job.payload.appName?.trim() ||
|
|
26709
|
+
appName: job.payload.appName?.trim() || import_path13.default.basename(job.repoRoot),
|
|
26738
26710
|
platform: "generic",
|
|
26739
26711
|
isPublic: false,
|
|
26740
26712
|
branch: job.payload.defaultBranch && job.branchName && job.branchName !== job.payload.defaultBranch ? job.payload.defaultBranch : job.branchName ?? void 0,
|
|
@@ -26928,7 +26900,7 @@ async function processInitPostJob(job, api) {
|
|
|
26928
26900
|
if (outcome.status === "failed") {
|
|
26929
26901
|
const bindingPath = getCollabBindingPath(job.repoRoot);
|
|
26930
26902
|
try {
|
|
26931
|
-
await
|
|
26903
|
+
await import_promises24.default.unlink(bindingPath);
|
|
26932
26904
|
await logDrainerEvent(job.id, "binding_cleared", {
|
|
26933
26905
|
kind: "init_post",
|
|
26934
26906
|
appId: job.payload.appId,
|
|
@@ -26969,10 +26941,10 @@ async function processReAnchorJob(job, api) {
|
|
|
26969
26941
|
}
|
|
26970
26942
|
let anchoredServerHeadHash = preflight.targetHeadCommitHash;
|
|
26971
26943
|
if (preflight.status === "ready_to_reconcile") {
|
|
26972
|
-
const bundleStat = await
|
|
26944
|
+
const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
|
|
26973
26945
|
const presignResp = await api.presignImportUploadFirstParty({
|
|
26974
26946
|
file: {
|
|
26975
|
-
name:
|
|
26947
|
+
name: import_path13.default.basename(job.payload.bundlePath),
|
|
26976
26948
|
mimeType: "application/x-git-bundle",
|
|
26977
26949
|
size: bundleStat.size,
|
|
26978
26950
|
checksumSha256: job.payload.bundleSha256
|
|
@@ -27076,9 +27048,9 @@ async function collabReAnchorProcess(jobId, opts) {
|
|
|
27076
27048
|
}
|
|
27077
27049
|
async function acquireDrainerPidLock() {
|
|
27078
27050
|
const pidPath = getDrainerPidPath();
|
|
27079
|
-
await
|
|
27051
|
+
await import_promises24.default.mkdir(import_path13.default.dirname(pidPath), { recursive: true });
|
|
27080
27052
|
try {
|
|
27081
|
-
const existing = await
|
|
27053
|
+
const existing = await import_promises24.default.readFile(pidPath, "utf8").catch(() => "");
|
|
27082
27054
|
const existingPid = parseInt(existing.trim(), 10);
|
|
27083
27055
|
if (Number.isFinite(existingPid) && existingPid > 0 && existingPid !== process.pid) {
|
|
27084
27056
|
try {
|
|
@@ -27088,13 +27060,13 @@ async function acquireDrainerPidLock() {
|
|
|
27088
27060
|
if (error2?.code !== "ESRCH") return null;
|
|
27089
27061
|
}
|
|
27090
27062
|
}
|
|
27091
|
-
await
|
|
27063
|
+
await import_promises24.default.writeFile(pidPath, String(process.pid), "utf8");
|
|
27092
27064
|
return {
|
|
27093
27065
|
release: async () => {
|
|
27094
27066
|
try {
|
|
27095
|
-
const current = (await
|
|
27067
|
+
const current = (await import_promises24.default.readFile(pidPath, "utf8")).trim();
|
|
27096
27068
|
if (current === String(process.pid)) {
|
|
27097
|
-
await
|
|
27069
|
+
await import_promises24.default.unlink(pidPath).catch(() => void 0);
|
|
27098
27070
|
}
|
|
27099
27071
|
} catch {
|
|
27100
27072
|
}
|
|
@@ -27609,8 +27581,8 @@ function getErrorMap() {
|
|
|
27609
27581
|
|
|
27610
27582
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
27611
27583
|
var makeIssue = (params) => {
|
|
27612
|
-
const { data, path:
|
|
27613
|
-
const fullPath = [...
|
|
27584
|
+
const { data, path: path16, errorMaps, issueData } = params;
|
|
27585
|
+
const fullPath = [...path16, ...issueData.path || []];
|
|
27614
27586
|
const fullIssue = {
|
|
27615
27587
|
...issueData,
|
|
27616
27588
|
path: fullPath
|
|
@@ -27726,11 +27698,11 @@ var errorUtil;
|
|
|
27726
27698
|
|
|
27727
27699
|
// node_modules/zod/v3/types.js
|
|
27728
27700
|
var ParseInputLazyPath = class {
|
|
27729
|
-
constructor(parent, value,
|
|
27701
|
+
constructor(parent, value, path16, key) {
|
|
27730
27702
|
this._cachedPath = [];
|
|
27731
27703
|
this.parent = parent;
|
|
27732
27704
|
this.data = value;
|
|
27733
|
-
this._path =
|
|
27705
|
+
this._path = path16;
|
|
27734
27706
|
this._key = key;
|
|
27735
27707
|
}
|
|
27736
27708
|
get path() {
|
|
@@ -35222,7 +35194,7 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
35222
35194
|
}
|
|
35223
35195
|
};
|
|
35224
35196
|
|
|
35225
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
35197
|
+
// node_modules/@remixhq/core/dist/chunk-C2FOZ3O7.js
|
|
35226
35198
|
async function readJsonSafe(res) {
|
|
35227
35199
|
const ct = res.headers.get("content-type") ?? "";
|
|
35228
35200
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -35235,8 +35207,13 @@ async function readJsonSafe(res) {
|
|
|
35235
35207
|
function createApiClient(config2, opts) {
|
|
35236
35208
|
const apiKey = (opts?.apiKey ?? "").trim();
|
|
35237
35209
|
const tokenProvider = opts?.tokenProvider;
|
|
35210
|
+
const defaultTimeoutMs = typeof opts?.defaultRequestTimeoutMs === "number" && opts.defaultRequestTimeoutMs > 0 ? opts.defaultRequestTimeoutMs : null;
|
|
35238
35211
|
const CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
35239
|
-
|
|
35212
|
+
function makeTimeoutSignal(timeoutMs) {
|
|
35213
|
+
const ms = typeof timeoutMs === "number" && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs;
|
|
35214
|
+
return ms != null ? AbortSignal.timeout(ms) : void 0;
|
|
35215
|
+
}
|
|
35216
|
+
async function request(path16, init, opts2) {
|
|
35240
35217
|
if (!tokenProvider) {
|
|
35241
35218
|
throw new RemixError("API client is missing a token provider.", {
|
|
35242
35219
|
exitCode: 1,
|
|
@@ -35244,9 +35221,10 @@ function createApiClient(config2, opts) {
|
|
|
35244
35221
|
});
|
|
35245
35222
|
}
|
|
35246
35223
|
const auth = await tokenProvider();
|
|
35247
|
-
const url = new URL(
|
|
35224
|
+
const url = new URL(path16, config2.apiUrl).toString();
|
|
35248
35225
|
const doFetch = async (bearer) => fetch(url, {
|
|
35249
35226
|
...init,
|
|
35227
|
+
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
35250
35228
|
headers: {
|
|
35251
35229
|
Accept: "application/json",
|
|
35252
35230
|
"Content-Type": "application/json",
|
|
@@ -35263,12 +35241,16 @@ function createApiClient(config2, opts) {
|
|
|
35263
35241
|
if (!res.ok) {
|
|
35264
35242
|
const body = await readJsonSafe(res);
|
|
35265
35243
|
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, {
|
|
35244
|
+
throw new RemixError(msg, {
|
|
35245
|
+
exitCode: 1,
|
|
35246
|
+
hint: body ? JSON.stringify(body, null, 2) : null,
|
|
35247
|
+
statusCode: res.status
|
|
35248
|
+
});
|
|
35267
35249
|
}
|
|
35268
35250
|
const json = await readJsonSafe(res);
|
|
35269
35251
|
return json ?? null;
|
|
35270
35252
|
}
|
|
35271
|
-
async function requestBinary(
|
|
35253
|
+
async function requestBinary(path16, init, opts2) {
|
|
35272
35254
|
if (!tokenProvider) {
|
|
35273
35255
|
throw new RemixError("API client is missing a token provider.", {
|
|
35274
35256
|
exitCode: 1,
|
|
@@ -35276,9 +35258,10 @@ function createApiClient(config2, opts) {
|
|
|
35276
35258
|
});
|
|
35277
35259
|
}
|
|
35278
35260
|
const auth = await tokenProvider();
|
|
35279
|
-
const url = new URL(
|
|
35261
|
+
const url = new URL(path16, config2.apiUrl).toString();
|
|
35280
35262
|
const doFetch = async (bearer) => fetch(url, {
|
|
35281
35263
|
...init,
|
|
35264
|
+
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
35282
35265
|
headers: {
|
|
35283
35266
|
Accept: "*/*",
|
|
35284
35267
|
...init?.headers ?? {},
|
|
@@ -35294,7 +35277,11 @@ function createApiClient(config2, opts) {
|
|
|
35294
35277
|
if (!res.ok) {
|
|
35295
35278
|
const body = await readJsonSafe(res);
|
|
35296
35279
|
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, {
|
|
35280
|
+
throw new RemixError(msg, {
|
|
35281
|
+
exitCode: 1,
|
|
35282
|
+
hint: body ? JSON.stringify(body, null, 2) : null,
|
|
35283
|
+
statusCode: res.status
|
|
35284
|
+
});
|
|
35298
35285
|
}
|
|
35299
35286
|
const contentDisposition = res.headers.get("content-disposition") ?? "";
|
|
35300
35287
|
const fileNameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);
|
|
@@ -35401,6 +35388,14 @@ function createApiClient(config2, opts) {
|
|
|
35401
35388
|
method: "POST",
|
|
35402
35389
|
body: JSON.stringify(payload)
|
|
35403
35390
|
}),
|
|
35391
|
+
listChangeSteps: (appId, params) => {
|
|
35392
|
+
const qs = new URLSearchParams();
|
|
35393
|
+
if (params?.limit !== void 0) qs.set("limit", String(params.limit));
|
|
35394
|
+
if (params?.offset !== void 0) qs.set("offset", String(params.offset));
|
|
35395
|
+
if (params?.idempotencyKey) qs.set("idempotencyKey", params.idempotencyKey);
|
|
35396
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
35397
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/change-steps${suffix}`, { method: "GET" });
|
|
35398
|
+
},
|
|
35404
35399
|
createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
|
|
35405
35400
|
method: "POST",
|
|
35406
35401
|
body: JSON.stringify(payload)
|
|
@@ -35648,10 +35643,10 @@ function createApiClient(config2, opts) {
|
|
|
35648
35643
|
};
|
|
35649
35644
|
}
|
|
35650
35645
|
|
|
35651
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
35652
|
-
var
|
|
35646
|
+
// node_modules/@remixhq/core/dist/chunk-XETDXVGM.js
|
|
35647
|
+
var import_promises25 = __toESM(require("fs/promises"), 1);
|
|
35653
35648
|
var import_os7 = __toESM(require("os"), 1);
|
|
35654
|
-
var
|
|
35649
|
+
var import_path14 = __toESM(require("path"), 1);
|
|
35655
35650
|
|
|
35656
35651
|
// node_modules/tslib/tslib.es6.mjs
|
|
35657
35652
|
function __rest(s, e) {
|
|
@@ -44754,8 +44749,8 @@ var IcebergError = class extends Error {
|
|
|
44754
44749
|
return this.status === 419;
|
|
44755
44750
|
}
|
|
44756
44751
|
};
|
|
44757
|
-
function buildUrl(baseUrl,
|
|
44758
|
-
const url = new URL(
|
|
44752
|
+
function buildUrl(baseUrl, path16, query) {
|
|
44753
|
+
const url = new URL(path16, baseUrl);
|
|
44759
44754
|
if (query) {
|
|
44760
44755
|
for (const [key, value] of Object.entries(query)) {
|
|
44761
44756
|
if (value !== void 0) {
|
|
@@ -44785,12 +44780,12 @@ function createFetchClient(options) {
|
|
|
44785
44780
|
return {
|
|
44786
44781
|
async request({
|
|
44787
44782
|
method,
|
|
44788
|
-
path:
|
|
44783
|
+
path: path16,
|
|
44789
44784
|
query,
|
|
44790
44785
|
body,
|
|
44791
44786
|
headers
|
|
44792
44787
|
}) {
|
|
44793
|
-
const url = buildUrl(options.baseUrl,
|
|
44788
|
+
const url = buildUrl(options.baseUrl, path16, query);
|
|
44794
44789
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
44795
44790
|
const res = await fetchFn(url, {
|
|
44796
44791
|
method,
|
|
@@ -45628,7 +45623,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45628
45623
|
* @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
45624
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
45630
45625
|
*/
|
|
45631
|
-
async uploadOrUpdate(method,
|
|
45626
|
+
async uploadOrUpdate(method, path16, fileBody, fileOptions) {
|
|
45632
45627
|
var _this = this;
|
|
45633
45628
|
return _this.handleOperation(async () => {
|
|
45634
45629
|
let body;
|
|
@@ -45652,7 +45647,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45652
45647
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
45653
45648
|
}
|
|
45654
45649
|
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(
|
|
45650
|
+
const cleanPath = _this._removeEmptyFolders(path16);
|
|
45656
45651
|
const _path = _this._getFinalPath(cleanPath);
|
|
45657
45652
|
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
45653
|
return {
|
|
@@ -45713,8 +45708,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45713
45708
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45714
45709
|
* - 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
45710
|
*/
|
|
45716
|
-
async upload(
|
|
45717
|
-
return this.uploadOrUpdate("POST",
|
|
45711
|
+
async upload(path16, fileBody, fileOptions) {
|
|
45712
|
+
return this.uploadOrUpdate("POST", path16, fileBody, fileOptions);
|
|
45718
45713
|
}
|
|
45719
45714
|
/**
|
|
45720
45715
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -45753,9 +45748,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45753
45748
|
* - `objects` table permissions: none
|
|
45754
45749
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45755
45750
|
*/
|
|
45756
|
-
async uploadToSignedUrl(
|
|
45751
|
+
async uploadToSignedUrl(path16, token, fileBody, fileOptions) {
|
|
45757
45752
|
var _this3 = this;
|
|
45758
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
45753
|
+
const cleanPath = _this3._removeEmptyFolders(path16);
|
|
45759
45754
|
const _path = _this3._getFinalPath(cleanPath);
|
|
45760
45755
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
45761
45756
|
url.searchParams.set("token", token);
|
|
@@ -45817,10 +45812,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45817
45812
|
* - `objects` table permissions: `insert`
|
|
45818
45813
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45819
45814
|
*/
|
|
45820
|
-
async createSignedUploadUrl(
|
|
45815
|
+
async createSignedUploadUrl(path16, options) {
|
|
45821
45816
|
var _this4 = this;
|
|
45822
45817
|
return _this4.handleOperation(async () => {
|
|
45823
|
-
let _path = _this4._getFinalPath(
|
|
45818
|
+
let _path = _this4._getFinalPath(path16);
|
|
45824
45819
|
const headers = _objectSpread22({}, _this4.headers);
|
|
45825
45820
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
45826
45821
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -45829,7 +45824,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45829
45824
|
if (!token) throw new StorageError("No token returned by API");
|
|
45830
45825
|
return {
|
|
45831
45826
|
signedUrl: url.toString(),
|
|
45832
|
-
path:
|
|
45827
|
+
path: path16,
|
|
45833
45828
|
token
|
|
45834
45829
|
};
|
|
45835
45830
|
});
|
|
@@ -45885,8 +45880,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
45885
45880
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
45886
45881
|
* - 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
45882
|
*/
|
|
45888
|
-
async update(
|
|
45889
|
-
return this.uploadOrUpdate("PUT",
|
|
45883
|
+
async update(path16, fileBody, fileOptions) {
|
|
45884
|
+
return this.uploadOrUpdate("PUT", path16, fileBody, fileOptions);
|
|
45890
45885
|
}
|
|
45891
45886
|
/**
|
|
45892
45887
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -46034,10 +46029,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46034
46029
|
* - `objects` table permissions: `select`
|
|
46035
46030
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46036
46031
|
*/
|
|
46037
|
-
async createSignedUrl(
|
|
46032
|
+
async createSignedUrl(path16, expiresIn, options) {
|
|
46038
46033
|
var _this8 = this;
|
|
46039
46034
|
return _this8.handleOperation(async () => {
|
|
46040
|
-
let _path = _this8._getFinalPath(
|
|
46035
|
+
let _path = _this8._getFinalPath(path16);
|
|
46041
46036
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
46042
46037
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
46043
46038
|
const query = new URLSearchParams();
|
|
@@ -46171,13 +46166,13 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46171
46166
|
* - `objects` table permissions: `select`
|
|
46172
46167
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46173
46168
|
*/
|
|
46174
|
-
download(
|
|
46169
|
+
download(path16, options, parameters) {
|
|
46175
46170
|
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
46171
|
const query = new URLSearchParams();
|
|
46177
46172
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
46178
46173
|
if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
|
|
46179
46174
|
const queryString = query.toString();
|
|
46180
|
-
const _path = this._getFinalPath(
|
|
46175
|
+
const _path = this._getFinalPath(path16);
|
|
46181
46176
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
|
|
46182
46177
|
headers: this.headers,
|
|
46183
46178
|
noResolveJson: true
|
|
@@ -46207,9 +46202,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46207
46202
|
* }
|
|
46208
46203
|
* ```
|
|
46209
46204
|
*/
|
|
46210
|
-
async info(
|
|
46205
|
+
async info(path16) {
|
|
46211
46206
|
var _this10 = this;
|
|
46212
|
-
const _path = _this10._getFinalPath(
|
|
46207
|
+
const _path = _this10._getFinalPath(path16);
|
|
46213
46208
|
return _this10.handleOperation(async () => {
|
|
46214
46209
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
46215
46210
|
});
|
|
@@ -46229,9 +46224,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46229
46224
|
* .exists('folder/avatar1.png')
|
|
46230
46225
|
* ```
|
|
46231
46226
|
*/
|
|
46232
|
-
async exists(
|
|
46227
|
+
async exists(path16) {
|
|
46233
46228
|
var _this11 = this;
|
|
46234
|
-
const _path = _this11._getFinalPath(
|
|
46229
|
+
const _path = _this11._getFinalPath(path16);
|
|
46235
46230
|
try {
|
|
46236
46231
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
46237
46232
|
return {
|
|
@@ -46309,8 +46304,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46309
46304
|
* - `objects` table permissions: none
|
|
46310
46305
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46311
46306
|
*/
|
|
46312
|
-
getPublicUrl(
|
|
46313
|
-
const _path = this._getFinalPath(
|
|
46307
|
+
getPublicUrl(path16, options) {
|
|
46308
|
+
const _path = this._getFinalPath(path16);
|
|
46314
46309
|
const query = new URLSearchParams();
|
|
46315
46310
|
if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
|
|
46316
46311
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
@@ -46447,10 +46442,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46447
46442
|
* - `objects` table permissions: `select`
|
|
46448
46443
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
46449
46444
|
*/
|
|
46450
|
-
async list(
|
|
46445
|
+
async list(path16, options, parameters) {
|
|
46451
46446
|
var _this13 = this;
|
|
46452
46447
|
return _this13.handleOperation(async () => {
|
|
46453
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
46448
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path16 || "" });
|
|
46454
46449
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
46455
46450
|
});
|
|
46456
46451
|
}
|
|
@@ -46514,11 +46509,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
46514
46509
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
46515
46510
|
return btoa(data);
|
|
46516
46511
|
}
|
|
46517
|
-
_getFinalPath(
|
|
46518
|
-
return `${this.bucketId}/${
|
|
46512
|
+
_getFinalPath(path16) {
|
|
46513
|
+
return `${this.bucketId}/${path16.replace(/^\/+/, "")}`;
|
|
46519
46514
|
}
|
|
46520
|
-
_removeEmptyFolders(
|
|
46521
|
-
return
|
|
46515
|
+
_removeEmptyFolders(path16) {
|
|
46516
|
+
return path16.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
46522
46517
|
}
|
|
46523
46518
|
/** Modifies the `query`, appending values the from `transform` */
|
|
46524
46519
|
applyTransformOptsToQuery(query, transform2) {
|
|
@@ -55593,7 +55588,7 @@ function shouldShowDeprecationWarning() {
|
|
|
55593
55588
|
}
|
|
55594
55589
|
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
55590
|
|
|
55596
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
55591
|
+
// node_modules/@remixhq/core/dist/chunk-XETDXVGM.js
|
|
55597
55592
|
var storedSessionSchema = external_exports.object({
|
|
55598
55593
|
access_token: external_exports.string().min(1),
|
|
55599
55594
|
refresh_token: external_exports.string().min(1),
|
|
@@ -55607,7 +55602,7 @@ var storedSessionSchema = external_exports.object({
|
|
|
55607
55602
|
function xdgConfigHome() {
|
|
55608
55603
|
const value = process.env.XDG_CONFIG_HOME;
|
|
55609
55604
|
if (typeof value === "string" && value.trim()) return value;
|
|
55610
|
-
return
|
|
55605
|
+
return import_path14.default.join(import_os7.default.homedir(), ".config");
|
|
55611
55606
|
}
|
|
55612
55607
|
async function maybeLoadKeytar() {
|
|
55613
55608
|
try {
|
|
@@ -55625,22 +55620,22 @@ async function maybeLoadKeytar() {
|
|
|
55625
55620
|
return null;
|
|
55626
55621
|
}
|
|
55627
55622
|
async function ensurePathPermissions(filePath) {
|
|
55628
|
-
const dir =
|
|
55629
|
-
await
|
|
55623
|
+
const dir = import_path14.default.dirname(filePath);
|
|
55624
|
+
await import_promises25.default.mkdir(dir, { recursive: true });
|
|
55630
55625
|
try {
|
|
55631
|
-
await
|
|
55626
|
+
await import_promises25.default.chmod(dir, 448);
|
|
55632
55627
|
} catch {
|
|
55633
55628
|
}
|
|
55634
55629
|
try {
|
|
55635
|
-
await
|
|
55630
|
+
await import_promises25.default.chmod(filePath, 384);
|
|
55636
55631
|
} catch {
|
|
55637
55632
|
}
|
|
55638
55633
|
}
|
|
55639
55634
|
async function writeJsonAtomic2(filePath, value) {
|
|
55640
|
-
await
|
|
55635
|
+
await import_promises25.default.mkdir(import_path14.default.dirname(filePath), { recursive: true });
|
|
55641
55636
|
const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
55642
|
-
await
|
|
55643
|
-
await
|
|
55637
|
+
await import_promises25.default.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
55638
|
+
await import_promises25.default.rename(tmpPath, filePath);
|
|
55644
55639
|
}
|
|
55645
55640
|
async function writeSessionFileFallback(filePath, session) {
|
|
55646
55641
|
await writeJsonAtomic2(filePath, session);
|
|
@@ -55649,7 +55644,7 @@ async function writeSessionFileFallback(filePath, session) {
|
|
|
55649
55644
|
function createLocalSessionStore(params) {
|
|
55650
55645
|
const service = params?.service?.trim() || "remix-cli";
|
|
55651
55646
|
const account = params?.account?.trim() || "default";
|
|
55652
|
-
const filePath = params?.filePath?.trim() ||
|
|
55647
|
+
const filePath = params?.filePath?.trim() || import_path14.default.join(xdgConfigHome(), "remix", "session.json");
|
|
55653
55648
|
async function readKeytar() {
|
|
55654
55649
|
const keytar = await maybeLoadKeytar();
|
|
55655
55650
|
if (!keytar) return null;
|
|
@@ -55663,7 +55658,7 @@ function createLocalSessionStore(params) {
|
|
|
55663
55658
|
}
|
|
55664
55659
|
}
|
|
55665
55660
|
async function readFile() {
|
|
55666
|
-
const raw = await
|
|
55661
|
+
const raw = await import_promises25.default.readFile(filePath, "utf8").catch(() => null);
|
|
55667
55662
|
if (!raw) return null;
|
|
55668
55663
|
try {
|
|
55669
55664
|
const parsed = storedSessionSchema.safeParse(JSON.parse(raw));
|
|
@@ -55807,7 +55802,7 @@ function createSupabaseAuthHelpers(config2) {
|
|
|
55807
55802
|
};
|
|
55808
55803
|
}
|
|
55809
55804
|
|
|
55810
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
55805
|
+
// node_modules/@remixhq/core/dist/chunk-XCZRNB35.js
|
|
55811
55806
|
var DEFAULT_API_URL = "https://api.remix.one";
|
|
55812
55807
|
var DEFAULT_SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
|
|
55813
55808
|
var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
|
|
@@ -55845,10 +55840,10 @@ async function resolveConfig(_opts) {
|
|
|
55845
55840
|
}
|
|
55846
55841
|
|
|
55847
55842
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
55848
|
-
var
|
|
55843
|
+
var import_path15 = __toESM(require("path"), 1);
|
|
55849
55844
|
var import_child_process = require("child_process");
|
|
55850
55845
|
var import_fs3 = require("fs");
|
|
55851
|
-
var
|
|
55846
|
+
var import_path16 = __toESM(require("path"), 1);
|
|
55852
55847
|
async function createRemixTokenProvider(config2) {
|
|
55853
55848
|
const resolvedConfig = config2 ?? await resolveConfig();
|
|
55854
55849
|
const sessionStore = createLocalSessionStore();
|
|
@@ -56077,6 +56072,15 @@ function normalizeByMessage(err) {
|
|
|
56077
56072
|
category: "remote_state"
|
|
56078
56073
|
});
|
|
56079
56074
|
}
|
|
56075
|
+
if (statusCode === 409) {
|
|
56076
|
+
return makeNormalized({
|
|
56077
|
+
code: ERROR_CODES.REMOTE_ERROR,
|
|
56078
|
+
message,
|
|
56079
|
+
hint,
|
|
56080
|
+
retryable: true,
|
|
56081
|
+
category: "remote_state"
|
|
56082
|
+
});
|
|
56083
|
+
}
|
|
56080
56084
|
if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
|
|
56081
56085
|
return makeNormalized({
|
|
56082
56086
|
code: ERROR_CODES.REMOTE_ERROR,
|
|
@@ -56141,12 +56145,12 @@ function parsePositiveIntEnv(name, fallback) {
|
|
|
56141
56145
|
}
|
|
56142
56146
|
function parseAllowedRoots(raw) {
|
|
56143
56147
|
if (!raw) return null;
|
|
56144
|
-
const roots = raw.split(
|
|
56148
|
+
const roots = raw.split(import_path15.default.delimiter).map((entry) => entry.trim()).filter(Boolean).map((entry) => import_path15.default.resolve(entry));
|
|
56145
56149
|
return roots.length > 0 ? roots : null;
|
|
56146
56150
|
}
|
|
56147
56151
|
function isWithinRoot(root, candidate) {
|
|
56148
|
-
const relative =
|
|
56149
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
56152
|
+
const relative = import_path15.default.relative(root, candidate);
|
|
56153
|
+
return relative === "" || !relative.startsWith("..") && !import_path15.default.isAbsolute(relative);
|
|
56150
56154
|
}
|
|
56151
56155
|
function loadPolicy() {
|
|
56152
56156
|
return {
|
|
@@ -56158,7 +56162,7 @@ function loadPolicy() {
|
|
|
56158
56162
|
};
|
|
56159
56163
|
}
|
|
56160
56164
|
function resolvePolicyCwd(policy, cwd) {
|
|
56161
|
-
const resolved =
|
|
56165
|
+
const resolved = import_path15.default.resolve(cwd?.trim() || process.cwd());
|
|
56162
56166
|
if (!policy.allowedRepoRoots) return resolved;
|
|
56163
56167
|
if (policy.allowedRepoRoots.some((root) => isWithinRoot(root, resolved))) return resolved;
|
|
56164
56168
|
throw createPolicyError("Requested working directory is outside the allowed repository roots.", resolved);
|
|
@@ -56240,7 +56244,6 @@ function makeSuccessResult2(envelope) {
|
|
|
56240
56244
|
function makeErrorResult(envelope) {
|
|
56241
56245
|
return {
|
|
56242
56246
|
content: [{ type: "text", text: toJsonText(envelope) }],
|
|
56243
|
-
structuredContent: envelope,
|
|
56244
56247
|
isError: true
|
|
56245
56248
|
};
|
|
56246
56249
|
}
|
|
@@ -56317,9 +56320,6 @@ var applyInputSchema = {
|
|
|
56317
56320
|
confirm: external_exports.boolean(),
|
|
56318
56321
|
allowBranchMismatch: external_exports.boolean().optional()
|
|
56319
56322
|
};
|
|
56320
|
-
var reAnchorInputSchema = {
|
|
56321
|
-
...applyInputSchema
|
|
56322
|
-
};
|
|
56323
56323
|
var requestMergeInputSchema = {
|
|
56324
56324
|
...commonRequestFieldsSchema
|
|
56325
56325
|
};
|
|
@@ -56432,7 +56432,7 @@ var initSyncDataSchema = external_exports.object({
|
|
|
56432
56432
|
repoRoot: external_exports.string(),
|
|
56433
56433
|
bindingMode: external_exports.enum(["legacy", "lane", "explicit_root"]).optional(),
|
|
56434
56434
|
createdCanonicalFamily: external_exports.boolean().optional(),
|
|
56435
|
-
baselineStatus: external_exports.enum(["seeded", "existing", "
|
|
56435
|
+
baselineStatus: external_exports.enum(["seeded", "existing", "baseline_missing", "requires_sync"]).optional()
|
|
56436
56436
|
});
|
|
56437
56437
|
var initQueuedDataSchema = external_exports.object({
|
|
56438
56438
|
queued: external_exports.literal(true),
|
|
@@ -56480,7 +56480,6 @@ var drainFinalizeQueueDataSchema = external_exports.object({
|
|
|
56480
56480
|
results: external_exports.array(genericRecordSchema)
|
|
56481
56481
|
});
|
|
56482
56482
|
var syncDataSchema = genericRecordSchema;
|
|
56483
|
-
var reAnchorDataSchema = genericRecordSchema;
|
|
56484
56483
|
var requestMergeDataSchema = genericRecordSchema;
|
|
56485
56484
|
var mergeRequestQueueDataSchema = external_exports.object({
|
|
56486
56485
|
queue: mergeRequestQueueSchema,
|
|
@@ -56556,7 +56555,6 @@ var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
|
56556
56555
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
56557
56556
|
var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
|
|
56558
56557
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
56559
|
-
var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
|
|
56560
56558
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
56561
56559
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
56562
56560
|
var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
|
|
@@ -56575,7 +56573,7 @@ var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema
|
|
|
56575
56573
|
function getRiskLevel(status) {
|
|
56576
56574
|
if (status.recommendedAction === "reconcile") return "high";
|
|
56577
56575
|
if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
|
|
56578
|
-
if (status.recommendedAction === "pull" || status.
|
|
56576
|
+
if (status.recommendedAction === "pull" || status.remote.incomingOpenMergeRequestCount) {
|
|
56579
56577
|
return "medium";
|
|
56580
56578
|
}
|
|
56581
56579
|
if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
|
|
@@ -56592,10 +56590,6 @@ function getRecommendedNextActions(status) {
|
|
|
56592
56590
|
return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
|
|
56593
56591
|
case "pull":
|
|
56594
56592
|
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
56593
|
case "record":
|
|
56600
56594
|
return [
|
|
56601
56595
|
"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 +56674,8 @@ async function initCollab(params) {
|
|
|
56680
56674
|
return {
|
|
56681
56675
|
data: syncResult,
|
|
56682
56676
|
warnings: collectResultWarnings(result),
|
|
56683
|
-
recommendedNextActions: syncResult.baselineStatus === "
|
|
56684
|
-
"This checkout has no local Remix baseline yet. Run
|
|
56677
|
+
recommendedNextActions: syncResult.baselineStatus === "baseline_missing" ? [
|
|
56678
|
+
"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
56679
|
] : syncResult.baselineStatus === "requires_sync" ? [
|
|
56686
56680
|
"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
56681
|
] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
|
|
@@ -56784,26 +56778,6 @@ async function syncCollab(params) {
|
|
|
56784
56778
|
}
|
|
56785
56779
|
};
|
|
56786
56780
|
}
|
|
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
56781
|
async function requestMerge(params) {
|
|
56808
56782
|
const api = await createCollabApiClient();
|
|
56809
56783
|
const drainWarnings = await drainBeforeMutation(api);
|
|
@@ -57520,22 +57494,25 @@ async function accessDebug(params) {
|
|
|
57520
57494
|
}
|
|
57521
57495
|
};
|
|
57522
57496
|
}
|
|
57523
|
-
var MARKER_REL_PATH =
|
|
57524
|
-
var LOG_REL_PATH =
|
|
57497
|
+
var MARKER_REL_PATH = import_path16.default.join(".remix", ".history-imported");
|
|
57498
|
+
var LOG_REL_PATH = import_path16.default.join(".remix", "history-import.log");
|
|
57525
57499
|
function shouldAutoSpawnHistoryImport(repoRoot) {
|
|
57526
57500
|
try {
|
|
57527
|
-
return !(0, import_fs3.existsSync)(
|
|
57501
|
+
return !(0, import_fs3.existsSync)(import_path16.default.join(repoRoot, MARKER_REL_PATH));
|
|
57528
57502
|
} catch {
|
|
57529
57503
|
return false;
|
|
57530
57504
|
}
|
|
57531
57505
|
}
|
|
57532
|
-
function
|
|
57533
|
-
|
|
57506
|
+
function isAutoSpawnEligibleBindingMode(bindingMode) {
|
|
57507
|
+
return bindingMode === "explicit_root";
|
|
57508
|
+
}
|
|
57509
|
+
function spawnHistoryImportDetached(repoRoot, options) {
|
|
57510
|
+
const remixDir = import_path16.default.join(repoRoot, ".remix");
|
|
57534
57511
|
try {
|
|
57535
57512
|
(0, import_fs3.mkdirSync)(remixDir, { recursive: true });
|
|
57536
57513
|
} catch {
|
|
57537
57514
|
}
|
|
57538
|
-
const logPath =
|
|
57515
|
+
const logPath = import_path16.default.join(repoRoot, LOG_REL_PATH);
|
|
57539
57516
|
const out = (0, import_fs3.openSync)(logPath, "a");
|
|
57540
57517
|
const err = (0, import_fs3.openSync)(logPath, "a");
|
|
57541
57518
|
const child = (0, import_child_process.spawn)(
|
|
@@ -57545,6 +57522,8 @@ function spawnHistoryImportDetached(repoRoot) {
|
|
|
57545
57522
|
"import",
|
|
57546
57523
|
"--repo",
|
|
57547
57524
|
repoRoot,
|
|
57525
|
+
"--before",
|
|
57526
|
+
options.cutoffAt,
|
|
57548
57527
|
// Include prompt text for parity with the CLI auto-spawn path:
|
|
57549
57528
|
// first-time UX is a lot worse if the dashboard renders every
|
|
57550
57529
|
// historical row as "(prompt not uploaded)".
|
|
@@ -57612,6 +57591,24 @@ function buildErrorEnvelope(tool, requestId, error2) {
|
|
|
57612
57591
|
recommendedNextActions
|
|
57613
57592
|
};
|
|
57614
57593
|
}
|
|
57594
|
+
function buildOutputValidationErrorEnvelope(tool, requestId, error2) {
|
|
57595
|
+
return {
|
|
57596
|
+
schemaVersion: SCHEMA_VERSION,
|
|
57597
|
+
ok: false,
|
|
57598
|
+
tool,
|
|
57599
|
+
requestId: requestId ?? null,
|
|
57600
|
+
error: {
|
|
57601
|
+
code: ERROR_CODES.INTERNAL_ERROR,
|
|
57602
|
+
message: "Tool output failed validation against its declared MCP schema.",
|
|
57603
|
+
hint: error2.issues.map((issue2) => `${issue2.path.join(".") || "output"}: ${issue2.message}`).join("; "),
|
|
57604
|
+
retryable: false,
|
|
57605
|
+
category: "internal"
|
|
57606
|
+
},
|
|
57607
|
+
warnings: [],
|
|
57608
|
+
risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
|
|
57609
|
+
recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
|
|
57610
|
+
};
|
|
57611
|
+
}
|
|
57615
57612
|
function registerTool(server, context, params) {
|
|
57616
57613
|
const errorSchema = makeErrorSchema();
|
|
57617
57614
|
server.registerTool(
|
|
@@ -57630,7 +57627,20 @@ function registerTool(server, context, params) {
|
|
|
57630
57627
|
assertToolAccess(context.policy, params.access);
|
|
57631
57628
|
const result = await params.run(rawArgs);
|
|
57632
57629
|
const envelope = buildSuccessEnvelope(params.name, requestId, result);
|
|
57633
|
-
params.outputSchema.
|
|
57630
|
+
const parsedEnvelope = params.outputSchema.safeParse(envelope);
|
|
57631
|
+
if (!parsedEnvelope.success) {
|
|
57632
|
+
const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
|
|
57633
|
+
context.logger.log({
|
|
57634
|
+
level: "error",
|
|
57635
|
+
message: "tool_output_validation_failed",
|
|
57636
|
+
tool: params.name,
|
|
57637
|
+
requestId: errorEnvelope.requestId,
|
|
57638
|
+
durationMs: Date.now() - startedAt,
|
|
57639
|
+
result: "error",
|
|
57640
|
+
errorCode: errorEnvelope.error.code
|
|
57641
|
+
});
|
|
57642
|
+
return makeErrorResult(errorEnvelope);
|
|
57643
|
+
}
|
|
57634
57644
|
context.logger.log({
|
|
57635
57645
|
level: "info",
|
|
57636
57646
|
message: "tool_completed",
|
|
@@ -57693,11 +57703,13 @@ function registerCollabTools(server, context) {
|
|
|
57693
57703
|
});
|
|
57694
57704
|
try {
|
|
57695
57705
|
const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
|
|
57696
|
-
|
|
57697
|
-
|
|
57706
|
+
const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
|
|
57707
|
+
if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot)) {
|
|
57708
|
+
const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
57709
|
+
const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
|
|
57698
57710
|
context.logger.log({
|
|
57699
57711
|
level: "info",
|
|
57700
|
-
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath}`,
|
|
57712
|
+
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} log=${spawned.logPath} cutoffAt=${cutoffAt}`,
|
|
57701
57713
|
tool: "remix_collab_init",
|
|
57702
57714
|
repoRoot
|
|
57703
57715
|
});
|
|
@@ -57801,31 +57813,6 @@ function registerCollabTools(server, context) {
|
|
|
57801
57813
|
return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
|
|
57802
57814
|
}
|
|
57803
57815
|
});
|
|
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
57816
|
registerTool(server, context, {
|
|
57830
57817
|
name: "remix_collab_request_merge",
|
|
57831
57818
|
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 +59577,7 @@ function createRemixMcpServer(params) {
|
|
|
59590
59577
|
}
|
|
59591
59578
|
|
|
59592
59579
|
// src/hook-auth.ts
|
|
59580
|
+
var HOOK_API_REQUEST_TIMEOUT_MS = 6e4;
|
|
59593
59581
|
async function createHookCollabApiClient() {
|
|
59594
59582
|
const config2 = await resolveConfig();
|
|
59595
59583
|
const sessionStore = createLocalSessionStore();
|
|
@@ -59602,18 +59590,19 @@ async function createHookCollabApiClient() {
|
|
|
59602
59590
|
}
|
|
59603
59591
|
});
|
|
59604
59592
|
return createApiClient(config2, {
|
|
59605
|
-
tokenProvider
|
|
59593
|
+
tokenProvider,
|
|
59594
|
+
defaultRequestTimeoutMs: HOOK_API_REQUEST_TIMEOUT_MS
|
|
59606
59595
|
});
|
|
59607
59596
|
}
|
|
59608
59597
|
|
|
59609
59598
|
// src/hook-diagnostics.ts
|
|
59610
59599
|
var import_node_crypto2 = require("crypto");
|
|
59611
|
-
var
|
|
59600
|
+
var import_promises27 = __toESM(require("fs/promises"), 1);
|
|
59612
59601
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
59613
59602
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
59614
59603
|
|
|
59615
59604
|
// src/hook-state.ts
|
|
59616
|
-
var
|
|
59605
|
+
var import_promises26 = __toESM(require("fs/promises"), 1);
|
|
59617
59606
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
59618
59607
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
59619
59608
|
var import_node_crypto = require("crypto");
|
|
@@ -59718,7 +59707,7 @@ function getPendingTurnStateRootPath() {
|
|
|
59718
59707
|
return stateRoot();
|
|
59719
59708
|
}
|
|
59720
59709
|
async function loadPendingTurnState(sessionId) {
|
|
59721
|
-
const raw = await
|
|
59710
|
+
const raw = await import_promises26.default.readFile(statePath(sessionId), "utf8").catch(() => null);
|
|
59722
59711
|
if (!raw) return null;
|
|
59723
59712
|
try {
|
|
59724
59713
|
const parsed = JSON.parse(raw);
|
|
@@ -59745,7 +59734,7 @@ async function loadPendingTurnState(sessionId) {
|
|
|
59745
59734
|
}
|
|
59746
59735
|
async function listPendingTurnStateSummaries() {
|
|
59747
59736
|
const root = stateRoot();
|
|
59748
|
-
const entries = await
|
|
59737
|
+
const entries = await import_promises26.default.readdir(root, { withFileTypes: true }).catch(() => []);
|
|
59749
59738
|
const sessionIds = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((a2, b) => a2.localeCompare(b));
|
|
59750
59739
|
const states = await Promise.all(sessionIds.map((sessionId) => loadPendingTurnState(sessionId)));
|
|
59751
59740
|
return states.filter((state) => state !== null).sort((a2, b) => b.submittedAt.localeCompare(a2.submittedAt)).map((state) => summarizePendingTurnState(state));
|
|
@@ -59754,7 +59743,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
59754
59743
|
// package.json
|
|
59755
59744
|
var package_default = {
|
|
59756
59745
|
name: "@remixhq/claude-plugin",
|
|
59757
|
-
version: "0.1.
|
|
59746
|
+
version: "0.1.24",
|
|
59758
59747
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
59759
59748
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
59760
59749
|
license: "MIT",
|
|
@@ -59792,8 +59781,8 @@ var package_default = {
|
|
|
59792
59781
|
prepack: "npm run build"
|
|
59793
59782
|
},
|
|
59794
59783
|
dependencies: {
|
|
59795
|
-
"@remixhq/core": "^0.1.
|
|
59796
|
-
"@remixhq/mcp": "^0.1.
|
|
59784
|
+
"@remixhq/core": "^0.1.19",
|
|
59785
|
+
"@remixhq/mcp": "^0.1.19"
|
|
59797
59786
|
},
|
|
59798
59787
|
devDependencies: {
|
|
59799
59788
|
"@types/node": "^25.4.0",
|
|
@@ -59835,7 +59824,7 @@ function clampEventLimit(limit) {
|
|
|
59835
59824
|
return Math.max(1, Math.min(MAX_EVENT_LIMIT, Math.trunc(limit)));
|
|
59836
59825
|
}
|
|
59837
59826
|
async function readEventsFromFile(filePath) {
|
|
59838
|
-
const raw = await
|
|
59827
|
+
const raw = await import_promises27.default.readFile(filePath, "utf8").catch(() => null);
|
|
59839
59828
|
if (!raw) return [];
|
|
59840
59829
|
return raw.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
|
|
59841
59830
|
try {
|