@remixhq/claude-plugin 0.1.22 → 0.1.23

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