@remixhq/claude-plugin 0.1.21 → 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;
@@ -25285,7 +25415,7 @@ async function collabInit(params) {
25285
25415
  operation: "`remix collab init`",
25286
25416
  recoveryHint: "The repository changed before the Remix binding was written. Review the local changes and rerun `remix collab init`."
25287
25417
  });
25288
- const bindingMode2 = params.forceNew && (!defaultBranch || branchName === defaultBranch) ? "explicit_root" : "lane";
25418
+ const bindingMode2 = defaultBranch && branchName !== defaultBranch ? "lane" : "explicit_root";
25289
25419
  let bindingPath2;
25290
25420
  if (params.forceNew && defaultBranch && canonicalLane2) {
25291
25421
  const canonicalBinding = branchBindingFromLane(canonicalLane2, "explicit_root", {
@@ -25327,7 +25457,15 @@ async function collabInit(params) {
25327
25457
  defaultBranch: canonicalLane2.defaultBranch ?? defaultBranch,
25328
25458
  laneId: canonicalLane2.laneId ?? null,
25329
25459
  branchName: defaultBranch,
25330
- bindingMode: params.forceNew ? "explicit_root" : "lane"
25460
+ // This branch is reached only when the CURRENT branch is
25461
+ // not the default branch — so the binding being written
25462
+ // here is for the DEFAULT branch (the canonical/main app).
25463
+ // It must always be `explicit_root` regardless of
25464
+ // `forceNew`; the previous `forceNew ? ... : "lane"`
25465
+ // produced a `lane`-marked default-branch binding for
25466
+ // every plain init, which silently disabled the
25467
+ // history-import auto-spawn.
25468
+ bindingMode: "explicit_root"
25331
25469
  });
25332
25470
  }
25333
25471
  bindingPath2 = await writeCollabBinding(repoRoot, {
@@ -25479,7 +25617,7 @@ async function collabInit(params) {
25479
25617
  operation: "`remix collab init`",
25480
25618
  recoveryHint: "The repository changed before the Remix binding was written. Review the local changes and rerun `remix collab init`."
25481
25619
  });
25482
- const bindingMode = params.forceNew && (!defaultBranch || branchName === defaultBranch) ? "explicit_root" : "lane";
25620
+ const bindingMode = defaultBranch && branchName !== defaultBranch ? "lane" : "explicit_root";
25483
25621
  let bindingPath;
25484
25622
  if (params.forceNew && defaultBranch && canonicalLane) {
25485
25623
  const canonicalBinding = branchBindingFromLane(canonicalLane, "explicit_root", {
@@ -25521,7 +25659,12 @@ async function collabInit(params) {
25521
25659
  defaultBranch: canonicalLane.defaultBranch ?? defaultBranch,
25522
25660
  laneId: canonicalLane.laneId ?? null,
25523
25661
  branchName: defaultBranch,
25524
- bindingMode: params.forceNew ? "explicit_root" : "lane"
25662
+ // Same reasoning as the queued-path default-branch write
25663
+ // above: this is the canonical/main-app binding for the
25664
+ // default branch and must be `explicit_root`, otherwise the
25665
+ // history-import auto-spawn (gated on explicit_root) will
25666
+ // silently no-op for every plain init.
25667
+ bindingMode: "explicit_root"
25525
25668
  });
25526
25669
  }
25527
25670
  bindingPath = await writeCollabBinding(repoRoot, {
@@ -25607,248 +25750,6 @@ function hasPendingFinalize(summary) {
25607
25750
  function buildPendingFinalizeHint() {
25608
25751
  return "Drain or await the local finalize queue first, then retry after the queued Remix turn finishes recording remotely.";
25609
25752
  }
25610
- async function collabReAnchor(params) {
25611
- const repoRoot = await findGitRoot(params.cwd);
25612
- const binding = await ensureActiveLaneBinding({
25613
- repoRoot,
25614
- api: params.api,
25615
- operation: "`remix collab re-anchor`"
25616
- });
25617
- if (!binding) {
25618
- throw new RemixError("Repository is not bound to Remix.", {
25619
- exitCode: 2,
25620
- hint: "Run `remix collab init` first."
25621
- });
25622
- }
25623
- const detected = await collabDetectRepoState({
25624
- api: params.api,
25625
- cwd: repoRoot,
25626
- allowBranchMismatch: params.allowBranchMismatch
25627
- });
25628
- if (detected.status === "metadata_conflict" || detected.status === "branch_mismatch") {
25629
- throw new RemixError("Repository must be realigned before seeding a fresh local Remix baseline.", {
25630
- exitCode: 2,
25631
- hint: detected.hint
25632
- });
25633
- }
25634
- if (detected.status !== "ready" || !detected.binding) {
25635
- throw new RemixError(detected.hint || "Repository is not ready for re-anchor.", {
25636
- exitCode: 2,
25637
- hint: detected.hint
25638
- });
25639
- }
25640
- if (detected.repoState === "server_only_changed") {
25641
- throw new RemixError("This checkout is already on a server-known base and only needs a local pull.", {
25642
- exitCode: 2,
25643
- hint: "Run `remix collab sync` instead of `remix collab re-anchor`."
25644
- });
25645
- }
25646
- if (detected.repoState === "both_changed") {
25647
- throw new RemixError("Both the local workspace and the server lane changed since the last agreed baseline.", {
25648
- exitCode: 2,
25649
- hint: "Run `remix collab reconcile` to replay the local boundary onto the newer server head."
25650
- });
25651
- }
25652
- if (detected.repoState === "local_only_changed") {
25653
- if (hasPendingFinalize(detected.pendingFinalize)) {
25654
- throw new RemixError("Re-anchor is not needed while queued Remix turn recording is still processing.", {
25655
- exitCode: 2,
25656
- hint: buildPendingFinalizeHint()
25657
- });
25658
- }
25659
- throw new RemixError("Re-anchor is not the right command for local content changes.", {
25660
- exitCode: 2,
25661
- 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`)."
25662
- });
25663
- }
25664
- if (detected.repoState === "idle") {
25665
- throw new RemixError("This checkout is already aligned with Remix.", {
25666
- exitCode: 2,
25667
- hint: "No re-anchor step is needed. Re-anchor only applies when no local Remix baseline exists yet for this lane."
25668
- });
25669
- }
25670
- await ensureCleanWorktree(repoRoot, "`remix collab re-anchor`");
25671
- const branch = await requireCurrentBranch(repoRoot);
25672
- const headCommitHash = await getHeadCommitHash(repoRoot);
25673
- if (!headCommitHash) {
25674
- throw new RemixError("Failed to resolve local HEAD commit.", { exitCode: 1 });
25675
- }
25676
- if (params.asyncSubmit && !params.dryRun) {
25677
- const pending = await findPendingAsyncJob({
25678
- repoRoot,
25679
- branchName: binding.branchName ?? branch,
25680
- kind: "re_anchor"
25681
- });
25682
- if (pending) {
25683
- return {
25684
- status: "queued",
25685
- queued: true,
25686
- jobId: pending.id,
25687
- repoRoot,
25688
- branch,
25689
- currentAppId: binding.currentAppId,
25690
- dryRun: false,
25691
- applied: false
25692
- };
25693
- }
25694
- }
25695
- const preflightResp = await params.api.preflightAppReconcile(binding.currentAppId, {
25696
- localHeadCommitHash: headCommitHash,
25697
- repoFingerprint: binding.repoFingerprint ?? void 0,
25698
- remoteUrl: binding.remoteUrl ?? void 0,
25699
- defaultBranch: binding.defaultBranch ?? void 0
25700
- });
25701
- const preflight = unwrapResponseObject(preflightResp, "reconcile preflight");
25702
- if (preflight.status === "metadata_conflict") {
25703
- throw new RemixError("Local repository metadata conflicts with the bound Remix app.", {
25704
- exitCode: 2,
25705
- hint: preflight.warnings.join("\n") || "Run the command from the correct bound repository."
25706
- });
25707
- }
25708
- const preview = {
25709
- status: preflight.status === "up_to_date" ? "reanchored" : "re_anchor_required",
25710
- repoRoot,
25711
- branch,
25712
- currentAppId: binding.currentAppId,
25713
- localHeadCommitHash: headCommitHash,
25714
- targetHeadCommitHash: preflight.targetHeadCommitHash,
25715
- targetHeadCommitId: preflight.targetHeadCommitId,
25716
- warnings: preflight.warnings,
25717
- applied: false,
25718
- dryRun: params.dryRun === true
25719
- };
25720
- if (params.dryRun) {
25721
- return preview;
25722
- }
25723
- let anchoredServerHeadHash = preflight.targetHeadCommitHash;
25724
- if (params.asyncSubmit && preflight.status === "ready_to_reconcile") {
25725
- const failed = await findFailedAsyncJob({
25726
- repoRoot,
25727
- branchName: binding.branchName ?? branch,
25728
- kind: "re_anchor"
25729
- });
25730
- if (failed) {
25731
- await deleteAsyncJob(failed.id);
25732
- }
25733
- const { bundlePath: tmpBundlePath, headCommitHash: bundledHeadCommitHash } = await createGitBundle(
25734
- repoRoot,
25735
- "re-anchor.bundle"
25736
- );
25737
- const tmpBundleDir = import_path12.default.dirname(tmpBundlePath);
25738
- try {
25739
- const jobId = (0, import_crypto9.randomUUID)();
25740
- const durableBundlePath = getAsyncJobBundlePath(jobId);
25741
- await import_promises23.default.mkdir(getAsyncJobDir(jobId), { recursive: true });
25742
- try {
25743
- await import_promises23.default.rename(tmpBundlePath, durableBundlePath);
25744
- } catch (error2) {
25745
- if (error2?.code !== "EXDEV") throw error2;
25746
- await import_promises23.default.copyFile(tmpBundlePath, durableBundlePath);
25747
- await import_promises23.default.unlink(tmpBundlePath).catch(() => void 0);
25748
- }
25749
- const bundleSha = await sha256FileHex(durableBundlePath);
25750
- const job = await enqueueAsyncJob({
25751
- id: jobId,
25752
- kind: "re_anchor",
25753
- status: "queued",
25754
- repoRoot,
25755
- repoFingerprint: binding.repoFingerprint,
25756
- branchName: binding.branchName ?? branch,
25757
- laneId: binding.laneId,
25758
- retryCount: 0,
25759
- error: null,
25760
- idempotencyKey: null,
25761
- payload: {
25762
- bundlePath: durableBundlePath,
25763
- bundleSha256: bundleSha,
25764
- localHeadCommitHash: bundledHeadCommitHash,
25765
- targetHeadCommitHash: preflight.targetHeadCommitHash,
25766
- appId: binding.currentAppId
25767
- }
25768
- });
25769
- await logDrainerEvent(job.id, "submitted", { kind: "re_anchor" });
25770
- return {
25771
- status: "queued",
25772
- queued: true,
25773
- jobId: job.id,
25774
- repoRoot,
25775
- branch,
25776
- currentAppId: binding.currentAppId,
25777
- localHeadCommitHash: bundledHeadCommitHash,
25778
- targetHeadCommitHash: preflight.targetHeadCommitHash,
25779
- warnings: preflight.warnings,
25780
- dryRun: false,
25781
- applied: false
25782
- };
25783
- } finally {
25784
- await import_promises23.default.rm(tmpBundleDir, { recursive: true, force: true }).catch(() => void 0);
25785
- }
25786
- }
25787
- if (preflight.status === "ready_to_reconcile") {
25788
- const { bundlePath, headCommitHash: bundledHeadCommitHash } = await createGitBundle(repoRoot, "re-anchor.bundle");
25789
- const bundleTempDir = import_path12.default.dirname(bundlePath);
25790
- try {
25791
- const bundleStat = await import_promises23.default.stat(bundlePath);
25792
- const checksumSha256 = await sha256FileHex(bundlePath);
25793
- const presignResp = await params.api.presignImportUploadFirstParty({
25794
- file: {
25795
- name: import_path12.default.basename(bundlePath),
25796
- mimeType: "application/x-git-bundle",
25797
- size: bundleStat.size,
25798
- checksumSha256
25799
- }
25800
- });
25801
- const uploadTarget = unwrapResponseObject(presignResp, "import upload target");
25802
- await uploadPresigned({
25803
- uploadUrl: String(uploadTarget.uploadUrl),
25804
- filePath: bundlePath,
25805
- headers: uploadTarget.headers ?? {}
25806
- });
25807
- const startResp = await params.api.startAppReconcile(binding.currentAppId, {
25808
- uploadId: String(uploadTarget.uploadId),
25809
- localHeadCommitHash: bundledHeadCommitHash,
25810
- repoFingerprint: binding.repoFingerprint ?? void 0,
25811
- remoteUrl: binding.remoteUrl ?? void 0,
25812
- defaultBranch: binding.defaultBranch ?? void 0,
25813
- idempotencyKey: buildDeterministicIdempotencyKey({
25814
- kind: "collab_re_anchor_v1",
25815
- appId: binding.currentAppId,
25816
- localHeadCommitHash: bundledHeadCommitHash,
25817
- targetHeadCommitHash: preflight.targetHeadCommitHash
25818
- })
25819
- });
25820
- const started = unwrapResponseObject(startResp, "reconcile");
25821
- const reconcile2 = await pollReconcile(params.api, binding.currentAppId, started.id);
25822
- anchoredServerHeadHash = reconcile2.reconciledHeadCommitHash ?? reconcile2.targetHeadCommitHash ?? preflight.targetHeadCommitHash;
25823
- } finally {
25824
- await import_promises23.default.rm(bundleTempDir, { recursive: true, force: true });
25825
- }
25826
- }
25827
- const snapshot = await captureLocalSnapshot({
25828
- repoRoot,
25829
- repoFingerprint: binding.repoFingerprint,
25830
- laneId: binding.laneId,
25831
- branchName: binding.branchName
25832
- });
25833
- await writeLocalBaseline({
25834
- repoRoot,
25835
- repoFingerprint: binding.repoFingerprint,
25836
- laneId: binding.laneId,
25837
- currentAppId: binding.currentAppId,
25838
- branchName: binding.branchName,
25839
- lastSnapshotId: snapshot.id,
25840
- lastSnapshotHash: snapshot.snapshotHash,
25841
- lastServerHeadHash: anchoredServerHeadHash,
25842
- lastSeenLocalCommitHash: snapshot.localCommitHash
25843
- });
25844
- return {
25845
- ...preview,
25846
- status: "reanchored",
25847
- targetHeadCommitHash: anchoredServerHeadHash,
25848
- applied: true,
25849
- dryRun: false
25850
- };
25851
- }
25852
25753
  async function reconcileBothChanged(params) {
25853
25754
  const repoRoot = await findGitRoot(params.cwd);
25854
25755
  const binding = await ensureActiveLaneBinding({
@@ -25871,7 +25772,7 @@ async function reconcileBothChanged(params) {
25871
25772
  if (!baseline?.lastSnapshotId || !baseline.lastServerHeadHash) {
25872
25773
  throw new RemixError("Local Remix baseline is missing for this lane.", {
25873
25774
  exitCode: 2,
25874
- 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."
25875
25776
  });
25876
25777
  }
25877
25778
  const currentSnapshot = await captureLocalSnapshot({
@@ -25894,6 +25795,7 @@ async function reconcileBothChanged(params) {
25894
25795
  params.api.getAppHead(binding.currentAppId),
25895
25796
  params.api.getAppDelta(binding.currentAppId, {
25896
25797
  baseHeadHash: baseline.lastServerHeadHash,
25798
+ baseRevisionId: baseline.lastServerRevisionId,
25897
25799
  repoFingerprint: binding.repoFingerprint ?? void 0,
25898
25800
  remoteUrl: binding.remoteUrl ?? void 0,
25899
25801
  defaultBranch: binding.defaultBranch ?? void 0
@@ -25911,7 +25813,7 @@ async function reconcileBothChanged(params) {
25911
25813
  if (delta.status === "base_unknown") {
25912
25814
  throw new RemixError("Reconcile cannot pull the newer server state from the last acknowledged baseline.", {
25913
25815
  exitCode: 2,
25914
- 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."
25915
25817
  });
25916
25818
  }
25917
25819
  if (delta.status !== "delta_ready" && delta.status !== "up_to_date") {
@@ -25942,7 +25844,9 @@ async function reconcileBothChanged(params) {
25942
25844
  assistantResponse: "Replay the local boundary delta onto the latest server head without recording a new change step.",
25943
25845
  diff: diffResult.diff,
25944
25846
  baseCommitHash: baseline.lastServerHeadHash,
25847
+ baseRevisionId: baseline.lastServerRevisionId,
25945
25848
  targetHeadCommitHash: appHead.headCommitHash,
25849
+ targetRevisionId: appHead.headRevisionId,
25946
25850
  expectedPaths: diffResult.changedPaths,
25947
25851
  workspaceMetadata: {
25948
25852
  recordingMode: "boundary_delta",
@@ -25950,6 +25854,7 @@ async function reconcileBothChanged(params) {
25950
25854
  branch,
25951
25855
  baselineSnapshotId: baseline.lastSnapshotId,
25952
25856
  currentSnapshotId: currentSnapshot.id,
25857
+ baselineServerRevisionId: baseline.lastServerRevisionId,
25953
25858
  baselineServerHeadHash: baseline.lastServerHeadHash,
25954
25859
  currentSnapshotHash: currentSnapshot.snapshotHash,
25955
25860
  localCommitHash: currentSnapshot.localCommitHash,
@@ -25968,12 +25873,12 @@ async function reconcileBothChanged(params) {
25968
25873
  const replay = await pollChangeStepReplay(params.api, binding.currentAppId, String(replayStart.id));
25969
25874
  const replayDiffResp = await params.api.getChangeStepReplayDiff(binding.currentAppId, replay.id);
25970
25875
  const replayDiff = unwrapResponseObject(replayDiffResp, "change step replay diff");
25971
- 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-"));
25972
25877
  let serverHeadSnapshot = null;
25973
25878
  let mergedSnapshot = null;
25974
25879
  try {
25975
- const tempRepoRoot = import_path13.default.join(tempRoot, "repo");
25976
- 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 });
25977
25882
  await execa("git", ["init"], { cwd: tempRepoRoot, stderr: "ignore" });
25978
25883
  await materializeLocalSnapshot(baseline.lastSnapshotId, tempRepoRoot);
25979
25884
  if (delta.status === "delta_ready" && delta.diff.trim()) {
@@ -25995,7 +25900,7 @@ async function reconcileBothChanged(params) {
25995
25900
  branchName: binding.branchName
25996
25901
  });
25997
25902
  } finally {
25998
- 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);
25999
25904
  }
26000
25905
  if (!serverHeadSnapshot || !mergedSnapshot) {
26001
25906
  throw new RemixError("Failed to materialize the reconciled local workspace.", { exitCode: 1 });
@@ -26032,6 +25937,8 @@ async function reconcileBothChanged(params) {
26032
25937
  branchName: binding.branchName,
26033
25938
  lastSnapshotId: serverHeadSnapshot.id,
26034
25939
  lastSnapshotHash: serverHeadSnapshot.snapshotHash,
25940
+ lastServerRevisionId: appHead.headRevisionId ?? null,
25941
+ lastServerTreeHash: appHead.treeHash ?? null,
26035
25942
  lastServerHeadHash: appHead.headCommitHash,
26036
25943
  lastSeenLocalCommitHash: restoredSnapshot.localCommitHash
26037
25944
  });
@@ -26067,7 +25974,10 @@ async function collabReconcile(params) {
26067
25974
  return reconcileBothChanged(params);
26068
25975
  }
26069
25976
  if (detected.repoState === "external_local_base_changed") {
26070
- 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
+ });
26071
25981
  }
26072
25982
  if (detected.repoState === "local_only_changed") {
26073
25983
  if (hasPendingFinalize(detected.pendingFinalize)) {
@@ -26174,6 +26084,8 @@ async function collabRemix(params) {
26174
26084
  branchName: branchNameForBaseline,
26175
26085
  lastSnapshotId: snapshot.id,
26176
26086
  lastSnapshotHash: snapshot.snapshotHash,
26087
+ lastServerRevisionId: appHead.headRevisionId ?? null,
26088
+ lastServerTreeHash: appHead.treeHash ?? null,
26177
26089
  lastServerHeadHash: appHead.headCommitHash,
26178
26090
  lastSeenLocalCommitHash: snapshot.localCommitHash
26179
26091
  });
@@ -26294,11 +26206,15 @@ function createBaseStatus() {
26294
26206
  baseline: {
26295
26207
  lastSnapshotId: null,
26296
26208
  lastSnapshotHash: null,
26209
+ lastServerRevisionId: null,
26210
+ lastServerTreeHash: null,
26297
26211
  lastServerHeadHash: null,
26298
26212
  lastSeenLocalCommitHash: null
26299
26213
  },
26300
26214
  current: {
26301
26215
  snapshotHash: null,
26216
+ serverRevisionId: null,
26217
+ serverTreeHash: null,
26302
26218
  serverHeadHash: null,
26303
26219
  serverHeadCommitId: null,
26304
26220
  localCommitHash: null
@@ -26385,6 +26301,8 @@ async function collabStatus(params) {
26385
26301
  status.alignment.baseline = detected.baseline;
26386
26302
  status.alignment.current = {
26387
26303
  snapshotHash: detected.currentSnapshotHash,
26304
+ serverRevisionId: detected.currentServerRevisionId,
26305
+ serverTreeHash: detected.currentServerTreeHash,
26388
26306
  serverHeadHash: detected.currentServerHeadHash,
26389
26307
  serverHeadCommitId: detected.currentServerHeadCommitId,
26390
26308
  localCommitHash: detected.localCommitHash
@@ -26448,7 +26366,7 @@ async function collabStatus(params) {
26448
26366
  status.reconcile.canApply = !status.repo.branchMismatch;
26449
26367
  status.recommendedAction = "reconcile";
26450
26368
  } else if (detected.repoState === "external_local_base_changed") {
26451
- status.recommendedAction = "re_anchor";
26369
+ status.recommendedAction = "init";
26452
26370
  addBlockedReason(status.sync, "baseline_missing");
26453
26371
  addBlockedReason(status.reconcile, "baseline_missing");
26454
26372
  } else if (detected.repoState === "local_only_changed") {
@@ -26701,10 +26619,10 @@ async function processInitJob(job, api) {
26701
26619
  try {
26702
26620
  await updateAsyncJob(job.id, { status: "submitting", error: null });
26703
26621
  await logDrainerEvent(job.id, "claimed", { kind: "init" });
26704
- const bundleStat = await import_promises25.default.stat(job.payload.bundlePath);
26622
+ const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
26705
26623
  const presignResp = await api.presignImportUploadFirstParty({
26706
26624
  file: {
26707
- name: import_path14.default.basename(job.payload.bundlePath),
26625
+ name: import_path13.default.basename(job.payload.bundlePath),
26708
26626
  mimeType: "application/x-git-bundle",
26709
26627
  size: bundleStat.size,
26710
26628
  checksumSha256: job.payload.bundleSha256
@@ -26721,7 +26639,7 @@ async function processInitJob(job, api) {
26721
26639
  await updateAsyncJob(job.id, { status: "server_processing" });
26722
26640
  const importResp = await api.importFromUploadFirstParty({
26723
26641
  uploadId: String(presign.uploadId),
26724
- appName: job.payload.appName?.trim() || import_path14.default.basename(job.repoRoot),
26642
+ appName: job.payload.appName?.trim() || import_path13.default.basename(job.repoRoot),
26725
26643
  platform: "generic",
26726
26644
  isPublic: false,
26727
26645
  branch: job.payload.defaultBranch && job.branchName && job.branchName !== job.payload.defaultBranch ? job.payload.defaultBranch : job.branchName ?? void 0,
@@ -26796,7 +26714,7 @@ async function processInitJob(job, api) {
26796
26714
  boundProjectId = String(readyApp.projectId ?? boundProjectId);
26797
26715
  boundThreadId = readyApp.threadId ? String(readyApp.threadId) : boundThreadId;
26798
26716
  }
26799
- const bindingMode = job.payload.forceNew && (!defaultBranch || branchName === defaultBranch) ? "explicit_root" : "lane";
26717
+ const bindingMode = defaultBranch && branchName !== defaultBranch ? "lane" : "explicit_root";
26800
26718
  if (job.payload.forceNew && defaultBranch && canonicalLane) {
26801
26719
  const canonicalBinding = branchBindingFromLane(canonicalLane, "explicit_root", {
26802
26720
  projectId: canonicalLane.projectId ?? boundProjectId,
@@ -26835,7 +26753,12 @@ async function processInitJob(job, api) {
26835
26753
  defaultBranch: canonicalLane.defaultBranch ?? defaultBranch,
26836
26754
  laneId: canonicalLane.laneId ?? null,
26837
26755
  branchName: defaultBranch,
26838
- bindingMode: job.payload.forceNew ? "explicit_root" : "lane"
26756
+ // This branch is reached only when the current branch is NOT
26757
+ // the default branch — so the binding being written here is
26758
+ // for the DEFAULT branch (the canonical/main app). It must
26759
+ // always be `explicit_root` so the history-import auto-spawn
26760
+ // can fire on first-ever inits (see autoSpawnHistoryImport.ts).
26761
+ bindingMode: "explicit_root"
26839
26762
  });
26840
26763
  }
26841
26764
  await writeCollabBinding(repoRoot, {
@@ -26910,7 +26833,7 @@ async function processInitPostJob(job, api) {
26910
26833
  if (outcome.status === "failed") {
26911
26834
  const bindingPath = getCollabBindingPath(job.repoRoot);
26912
26835
  try {
26913
- await import_promises25.default.unlink(bindingPath);
26836
+ await import_promises24.default.unlink(bindingPath);
26914
26837
  await logDrainerEvent(job.id, "binding_cleared", {
26915
26838
  kind: "init_post",
26916
26839
  appId: job.payload.appId,
@@ -26951,10 +26874,10 @@ async function processReAnchorJob(job, api) {
26951
26874
  }
26952
26875
  let anchoredServerHeadHash = preflight.targetHeadCommitHash;
26953
26876
  if (preflight.status === "ready_to_reconcile") {
26954
- const bundleStat = await import_promises25.default.stat(job.payload.bundlePath);
26877
+ const bundleStat = await import_promises24.default.stat(job.payload.bundlePath);
26955
26878
  const presignResp = await api.presignImportUploadFirstParty({
26956
26879
  file: {
26957
- name: import_path14.default.basename(job.payload.bundlePath),
26880
+ name: import_path13.default.basename(job.payload.bundlePath),
26958
26881
  mimeType: "application/x-git-bundle",
26959
26882
  size: bundleStat.size,
26960
26883
  checksumSha256: job.payload.bundleSha256
@@ -27058,9 +26981,9 @@ async function collabReAnchorProcess(jobId, opts) {
27058
26981
  }
27059
26982
  async function acquireDrainerPidLock() {
27060
26983
  const pidPath = getDrainerPidPath();
27061
- 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 });
27062
26985
  try {
27063
- const existing = await import_promises25.default.readFile(pidPath, "utf8").catch(() => "");
26986
+ const existing = await import_promises24.default.readFile(pidPath, "utf8").catch(() => "");
27064
26987
  const existingPid = parseInt(existing.trim(), 10);
27065
26988
  if (Number.isFinite(existingPid) && existingPid > 0 && existingPid !== process.pid) {
27066
26989
  try {
@@ -27070,13 +26993,13 @@ async function acquireDrainerPidLock() {
27070
26993
  if (error2?.code !== "ESRCH") return null;
27071
26994
  }
27072
26995
  }
27073
- await import_promises25.default.writeFile(pidPath, String(process.pid), "utf8");
26996
+ await import_promises24.default.writeFile(pidPath, String(process.pid), "utf8");
27074
26997
  return {
27075
26998
  release: async () => {
27076
26999
  try {
27077
- const current = (await import_promises25.default.readFile(pidPath, "utf8")).trim();
27000
+ const current = (await import_promises24.default.readFile(pidPath, "utf8")).trim();
27078
27001
  if (current === String(process.pid)) {
27079
- await import_promises25.default.unlink(pidPath).catch(() => void 0);
27002
+ await import_promises24.default.unlink(pidPath).catch(() => void 0);
27080
27003
  }
27081
27004
  } catch {
27082
27005
  }
@@ -27591,8 +27514,8 @@ function getErrorMap() {
27591
27514
 
27592
27515
  // node_modules/zod/v3/helpers/parseUtil.js
27593
27516
  var makeIssue = (params) => {
27594
- const { data, path: path17, errorMaps, issueData } = params;
27595
- const fullPath = [...path17, ...issueData.path || []];
27517
+ const { data, path: path16, errorMaps, issueData } = params;
27518
+ const fullPath = [...path16, ...issueData.path || []];
27596
27519
  const fullIssue = {
27597
27520
  ...issueData,
27598
27521
  path: fullPath
@@ -27708,11 +27631,11 @@ var errorUtil;
27708
27631
 
27709
27632
  // node_modules/zod/v3/types.js
27710
27633
  var ParseInputLazyPath = class {
27711
- constructor(parent, value, path17, key) {
27634
+ constructor(parent, value, path16, key) {
27712
27635
  this._cachedPath = [];
27713
27636
  this.parent = parent;
27714
27637
  this.data = value;
27715
- this._path = path17;
27638
+ this._path = path16;
27716
27639
  this._key = key;
27717
27640
  }
27718
27641
  get path() {
@@ -35204,7 +35127,7 @@ var EMPTY_COMPLETION_RESULT = {
35204
35127
  }
35205
35128
  };
35206
35129
 
35207
- // node_modules/@remixhq/core/dist/chunk-US5SM7ZC.js
35130
+ // node_modules/@remixhq/core/dist/chunk-RCNOSZP6.js
35208
35131
  async function readJsonSafe(res) {
35209
35132
  const ct = res.headers.get("content-type") ?? "";
35210
35133
  if (!ct.toLowerCase().includes("application/json")) return null;
@@ -35217,8 +35140,13 @@ async function readJsonSafe(res) {
35217
35140
  function createApiClient(config2, opts) {
35218
35141
  const apiKey = (opts?.apiKey ?? "").trim();
35219
35142
  const tokenProvider = opts?.tokenProvider;
35143
+ const defaultTimeoutMs = typeof opts?.defaultRequestTimeoutMs === "number" && opts.defaultRequestTimeoutMs > 0 ? opts.defaultRequestTimeoutMs : null;
35220
35144
  const CLIENT_KEY_HEADER = "x-comerge-api-key";
35221
- 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) {
35222
35150
  if (!tokenProvider) {
35223
35151
  throw new RemixError("API client is missing a token provider.", {
35224
35152
  exitCode: 1,
@@ -35226,9 +35154,10 @@ function createApiClient(config2, opts) {
35226
35154
  });
35227
35155
  }
35228
35156
  const auth = await tokenProvider();
35229
- const url = new URL(path17, config2.apiUrl).toString();
35157
+ const url = new URL(path16, config2.apiUrl).toString();
35230
35158
  const doFetch = async (bearer) => fetch(url, {
35231
35159
  ...init,
35160
+ signal: makeTimeoutSignal(opts2?.timeoutMs),
35232
35161
  headers: {
35233
35162
  Accept: "application/json",
35234
35163
  "Content-Type": "application/json",
@@ -35245,12 +35174,16 @@ function createApiClient(config2, opts) {
35245
35174
  if (!res.ok) {
35246
35175
  const body = await readJsonSafe(res);
35247
35176
  const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
35248
- 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
+ });
35249
35182
  }
35250
35183
  const json = await readJsonSafe(res);
35251
35184
  return json ?? null;
35252
35185
  }
35253
- async function requestBinary(path17, init) {
35186
+ async function requestBinary(path16, init, opts2) {
35254
35187
  if (!tokenProvider) {
35255
35188
  throw new RemixError("API client is missing a token provider.", {
35256
35189
  exitCode: 1,
@@ -35258,9 +35191,10 @@ function createApiClient(config2, opts) {
35258
35191
  });
35259
35192
  }
35260
35193
  const auth = await tokenProvider();
35261
- const url = new URL(path17, config2.apiUrl).toString();
35194
+ const url = new URL(path16, config2.apiUrl).toString();
35262
35195
  const doFetch = async (bearer) => fetch(url, {
35263
35196
  ...init,
35197
+ signal: makeTimeoutSignal(opts2?.timeoutMs),
35264
35198
  headers: {
35265
35199
  Accept: "*/*",
35266
35200
  ...init?.headers ?? {},
@@ -35276,7 +35210,11 @@ function createApiClient(config2, opts) {
35276
35210
  if (!res.ok) {
35277
35211
  const body = await readJsonSafe(res);
35278
35212
  const msg = (body && typeof body === "object" && body && "message" in body && typeof body.message === "string" ? body.message : null) ?? `Request failed (status ${res.status})`;
35279
- 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
+ });
35280
35218
  }
35281
35219
  const contentDisposition = res.headers.get("content-disposition") ?? "";
35282
35220
  const fileNameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);
@@ -35630,10 +35568,10 @@ function createApiClient(config2, opts) {
35630
35568
  };
35631
35569
  }
35632
35570
 
35633
- // node_modules/@remixhq/core/dist/chunk-P6JHXOV4.js
35634
- 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);
35635
35573
  var import_os7 = __toESM(require("os"), 1);
35636
- var import_path15 = __toESM(require("path"), 1);
35574
+ var import_path14 = __toESM(require("path"), 1);
35637
35575
 
35638
35576
  // node_modules/tslib/tslib.es6.mjs
35639
35577
  function __rest(s, e) {
@@ -44736,8 +44674,8 @@ var IcebergError = class extends Error {
44736
44674
  return this.status === 419;
44737
44675
  }
44738
44676
  };
44739
- function buildUrl(baseUrl, path17, query) {
44740
- const url = new URL(path17, baseUrl);
44677
+ function buildUrl(baseUrl, path16, query) {
44678
+ const url = new URL(path16, baseUrl);
44741
44679
  if (query) {
44742
44680
  for (const [key, value] of Object.entries(query)) {
44743
44681
  if (value !== void 0) {
@@ -44767,12 +44705,12 @@ function createFetchClient(options) {
44767
44705
  return {
44768
44706
  async request({
44769
44707
  method,
44770
- path: path17,
44708
+ path: path16,
44771
44709
  query,
44772
44710
  body,
44773
44711
  headers
44774
44712
  }) {
44775
- const url = buildUrl(options.baseUrl, path17, query);
44713
+ const url = buildUrl(options.baseUrl, path16, query);
44776
44714
  const authHeaders = await buildAuthHeaders(options.auth);
44777
44715
  const res = await fetchFn(url, {
44778
44716
  method,
@@ -45610,7 +45548,7 @@ var StorageFileApi = class extends BaseApiClient {
45610
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.
45611
45549
  * @param fileBody The body of the file to be stored in the bucket.
45612
45550
  */
45613
- async uploadOrUpdate(method, path17, fileBody, fileOptions) {
45551
+ async uploadOrUpdate(method, path16, fileBody, fileOptions) {
45614
45552
  var _this = this;
45615
45553
  return _this.handleOperation(async () => {
45616
45554
  let body;
@@ -45634,7 +45572,7 @@ var StorageFileApi = class extends BaseApiClient {
45634
45572
  if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
45635
45573
  }
45636
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);
45637
- const cleanPath = _this._removeEmptyFolders(path17);
45575
+ const cleanPath = _this._removeEmptyFolders(path16);
45638
45576
  const _path = _this._getFinalPath(cleanPath);
45639
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 } : {}));
45640
45578
  return {
@@ -45695,8 +45633,8 @@ var StorageFileApi = class extends BaseApiClient {
45695
45633
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
45696
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.
45697
45635
  */
45698
- async upload(path17, fileBody, fileOptions) {
45699
- return this.uploadOrUpdate("POST", path17, fileBody, fileOptions);
45636
+ async upload(path16, fileBody, fileOptions) {
45637
+ return this.uploadOrUpdate("POST", path16, fileBody, fileOptions);
45700
45638
  }
45701
45639
  /**
45702
45640
  * Upload a file with a token generated from `createSignedUploadUrl`.
@@ -45735,9 +45673,9 @@ var StorageFileApi = class extends BaseApiClient {
45735
45673
  * - `objects` table permissions: none
45736
45674
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
45737
45675
  */
45738
- async uploadToSignedUrl(path17, token, fileBody, fileOptions) {
45676
+ async uploadToSignedUrl(path16, token, fileBody, fileOptions) {
45739
45677
  var _this3 = this;
45740
- const cleanPath = _this3._removeEmptyFolders(path17);
45678
+ const cleanPath = _this3._removeEmptyFolders(path16);
45741
45679
  const _path = _this3._getFinalPath(cleanPath);
45742
45680
  const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
45743
45681
  url.searchParams.set("token", token);
@@ -45799,10 +45737,10 @@ var StorageFileApi = class extends BaseApiClient {
45799
45737
  * - `objects` table permissions: `insert`
45800
45738
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
45801
45739
  */
45802
- async createSignedUploadUrl(path17, options) {
45740
+ async createSignedUploadUrl(path16, options) {
45803
45741
  var _this4 = this;
45804
45742
  return _this4.handleOperation(async () => {
45805
- let _path = _this4._getFinalPath(path17);
45743
+ let _path = _this4._getFinalPath(path16);
45806
45744
  const headers = _objectSpread22({}, _this4.headers);
45807
45745
  if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
45808
45746
  const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
@@ -45811,7 +45749,7 @@ var StorageFileApi = class extends BaseApiClient {
45811
45749
  if (!token) throw new StorageError("No token returned by API");
45812
45750
  return {
45813
45751
  signedUrl: url.toString(),
45814
- path: path17,
45752
+ path: path16,
45815
45753
  token
45816
45754
  };
45817
45755
  });
@@ -45867,8 +45805,8 @@ var StorageFileApi = class extends BaseApiClient {
45867
45805
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
45868
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.
45869
45807
  */
45870
- async update(path17, fileBody, fileOptions) {
45871
- return this.uploadOrUpdate("PUT", path17, fileBody, fileOptions);
45808
+ async update(path16, fileBody, fileOptions) {
45809
+ return this.uploadOrUpdate("PUT", path16, fileBody, fileOptions);
45872
45810
  }
45873
45811
  /**
45874
45812
  * Moves an existing file to a new path in the same bucket.
@@ -46016,10 +45954,10 @@ var StorageFileApi = class extends BaseApiClient {
46016
45954
  * - `objects` table permissions: `select`
46017
45955
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
46018
45956
  */
46019
- async createSignedUrl(path17, expiresIn, options) {
45957
+ async createSignedUrl(path16, expiresIn, options) {
46020
45958
  var _this8 = this;
46021
45959
  return _this8.handleOperation(async () => {
46022
- let _path = _this8._getFinalPath(path17);
45960
+ let _path = _this8._getFinalPath(path16);
46023
45961
  const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
46024
45962
  let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
46025
45963
  const query = new URLSearchParams();
@@ -46153,13 +46091,13 @@ var StorageFileApi = class extends BaseApiClient {
46153
46091
  * - `objects` table permissions: `select`
46154
46092
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
46155
46093
  */
46156
- download(path17, options, parameters) {
46094
+ download(path16, options, parameters) {
46157
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";
46158
46096
  const query = new URLSearchParams();
46159
46097
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
46160
46098
  if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
46161
46099
  const queryString = query.toString();
46162
- const _path = this._getFinalPath(path17);
46100
+ const _path = this._getFinalPath(path16);
46163
46101
  const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
46164
46102
  headers: this.headers,
46165
46103
  noResolveJson: true
@@ -46189,9 +46127,9 @@ var StorageFileApi = class extends BaseApiClient {
46189
46127
  * }
46190
46128
  * ```
46191
46129
  */
46192
- async info(path17) {
46130
+ async info(path16) {
46193
46131
  var _this10 = this;
46194
- const _path = _this10._getFinalPath(path17);
46132
+ const _path = _this10._getFinalPath(path16);
46195
46133
  return _this10.handleOperation(async () => {
46196
46134
  return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
46197
46135
  });
@@ -46211,9 +46149,9 @@ var StorageFileApi = class extends BaseApiClient {
46211
46149
  * .exists('folder/avatar1.png')
46212
46150
  * ```
46213
46151
  */
46214
- async exists(path17) {
46152
+ async exists(path16) {
46215
46153
  var _this11 = this;
46216
- const _path = _this11._getFinalPath(path17);
46154
+ const _path = _this11._getFinalPath(path16);
46217
46155
  try {
46218
46156
  await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
46219
46157
  return {
@@ -46291,8 +46229,8 @@ var StorageFileApi = class extends BaseApiClient {
46291
46229
  * - `objects` table permissions: none
46292
46230
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
46293
46231
  */
46294
- getPublicUrl(path17, options) {
46295
- const _path = this._getFinalPath(path17);
46232
+ getPublicUrl(path16, options) {
46233
+ const _path = this._getFinalPath(path16);
46296
46234
  const query = new URLSearchParams();
46297
46235
  if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
46298
46236
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
@@ -46429,10 +46367,10 @@ var StorageFileApi = class extends BaseApiClient {
46429
46367
  * - `objects` table permissions: `select`
46430
46368
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
46431
46369
  */
46432
- async list(path17, options, parameters) {
46370
+ async list(path16, options, parameters) {
46433
46371
  var _this13 = this;
46434
46372
  return _this13.handleOperation(async () => {
46435
- const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path17 || "" });
46373
+ const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path16 || "" });
46436
46374
  return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
46437
46375
  });
46438
46376
  }
@@ -46496,11 +46434,11 @@ var StorageFileApi = class extends BaseApiClient {
46496
46434
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
46497
46435
  return btoa(data);
46498
46436
  }
46499
- _getFinalPath(path17) {
46500
- return `${this.bucketId}/${path17.replace(/^\/+/, "")}`;
46437
+ _getFinalPath(path16) {
46438
+ return `${this.bucketId}/${path16.replace(/^\/+/, "")}`;
46501
46439
  }
46502
- _removeEmptyFolders(path17) {
46503
- return path17.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
46440
+ _removeEmptyFolders(path16) {
46441
+ return path16.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
46504
46442
  }
46505
46443
  /** Modifies the `query`, appending values the from `transform` */
46506
46444
  applyTransformOptsToQuery(query, transform2) {
@@ -55575,7 +55513,7 @@ function shouldShowDeprecationWarning() {
55575
55513
  }
55576
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");
55577
55515
 
55578
- // node_modules/@remixhq/core/dist/chunk-P6JHXOV4.js
55516
+ // node_modules/@remixhq/core/dist/chunk-XETDXVGM.js
55579
55517
  var storedSessionSchema = external_exports.object({
55580
55518
  access_token: external_exports.string().min(1),
55581
55519
  refresh_token: external_exports.string().min(1),
@@ -55589,7 +55527,7 @@ var storedSessionSchema = external_exports.object({
55589
55527
  function xdgConfigHome() {
55590
55528
  const value = process.env.XDG_CONFIG_HOME;
55591
55529
  if (typeof value === "string" && value.trim()) return value;
55592
- return import_path15.default.join(import_os7.default.homedir(), ".config");
55530
+ return import_path14.default.join(import_os7.default.homedir(), ".config");
55593
55531
  }
55594
55532
  async function maybeLoadKeytar() {
55595
55533
  try {
@@ -55607,22 +55545,22 @@ async function maybeLoadKeytar() {
55607
55545
  return null;
55608
55546
  }
55609
55547
  async function ensurePathPermissions(filePath) {
55610
- const dir = import_path15.default.dirname(filePath);
55611
- 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 });
55612
55550
  try {
55613
- await import_promises26.default.chmod(dir, 448);
55551
+ await import_promises25.default.chmod(dir, 448);
55614
55552
  } catch {
55615
55553
  }
55616
55554
  try {
55617
- await import_promises26.default.chmod(filePath, 384);
55555
+ await import_promises25.default.chmod(filePath, 384);
55618
55556
  } catch {
55619
55557
  }
55620
55558
  }
55621
55559
  async function writeJsonAtomic2(filePath, value) {
55622
- 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 });
55623
55561
  const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
55624
- await import_promises26.default.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf8");
55625
- 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);
55626
55564
  }
55627
55565
  async function writeSessionFileFallback(filePath, session) {
55628
55566
  await writeJsonAtomic2(filePath, session);
@@ -55631,7 +55569,7 @@ async function writeSessionFileFallback(filePath, session) {
55631
55569
  function createLocalSessionStore(params) {
55632
55570
  const service = params?.service?.trim() || "remix-cli";
55633
55571
  const account = params?.account?.trim() || "default";
55634
- 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");
55635
55573
  async function readKeytar() {
55636
55574
  const keytar = await maybeLoadKeytar();
55637
55575
  if (!keytar) return null;
@@ -55645,7 +55583,7 @@ function createLocalSessionStore(params) {
55645
55583
  }
55646
55584
  }
55647
55585
  async function readFile() {
55648
- const raw = await import_promises26.default.readFile(filePath, "utf8").catch(() => null);
55586
+ const raw = await import_promises25.default.readFile(filePath, "utf8").catch(() => null);
55649
55587
  if (!raw) return null;
55650
55588
  try {
55651
55589
  const parsed = storedSessionSchema.safeParse(JSON.parse(raw));
@@ -55789,7 +55727,7 @@ function createSupabaseAuthHelpers(config2) {
55789
55727
  };
55790
55728
  }
55791
55729
 
55792
- // node_modules/@remixhq/core/dist/chunk-VM3CGCNX.js
55730
+ // node_modules/@remixhq/core/dist/chunk-XCZRNB35.js
55793
55731
  var DEFAULT_API_URL = "https://api.remix.one";
55794
55732
  var DEFAULT_SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
55795
55733
  var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
@@ -55827,10 +55765,10 @@ async function resolveConfig(_opts) {
55827
55765
  }
55828
55766
 
55829
55767
  // node_modules/@remixhq/mcp/dist/index.js
55830
- var import_path16 = __toESM(require("path"), 1);
55768
+ var import_path15 = __toESM(require("path"), 1);
55831
55769
  var import_child_process = require("child_process");
55832
55770
  var import_fs3 = require("fs");
55833
- var import_path17 = __toESM(require("path"), 1);
55771
+ var import_path16 = __toESM(require("path"), 1);
55834
55772
  async function createRemixTokenProvider(config2) {
55835
55773
  const resolvedConfig = config2 ?? await resolveConfig();
55836
55774
  const sessionStore = createLocalSessionStore();
@@ -56123,12 +56061,12 @@ function parsePositiveIntEnv(name, fallback) {
56123
56061
  }
56124
56062
  function parseAllowedRoots(raw) {
56125
56063
  if (!raw) return null;
56126
- 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));
56127
56065
  return roots.length > 0 ? roots : null;
56128
56066
  }
56129
56067
  function isWithinRoot(root, candidate) {
56130
- const relative = import_path16.default.relative(root, candidate);
56131
- 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);
56132
56070
  }
56133
56071
  function loadPolicy() {
56134
56072
  return {
@@ -56140,7 +56078,7 @@ function loadPolicy() {
56140
56078
  };
56141
56079
  }
56142
56080
  function resolvePolicyCwd(policy, cwd) {
56143
- const resolved = import_path16.default.resolve(cwd?.trim() || process.cwd());
56081
+ const resolved = import_path15.default.resolve(cwd?.trim() || process.cwd());
56144
56082
  if (!policy.allowedRepoRoots) return resolved;
56145
56083
  if (policy.allowedRepoRoots.some((root) => isWithinRoot(root, resolved))) return resolved;
56146
56084
  throw createPolicyError("Requested working directory is outside the allowed repository roots.", resolved);
@@ -56299,9 +56237,6 @@ var applyInputSchema = {
56299
56237
  confirm: external_exports.boolean(),
56300
56238
  allowBranchMismatch: external_exports.boolean().optional()
56301
56239
  };
56302
- var reAnchorInputSchema = {
56303
- ...applyInputSchema
56304
- };
56305
56240
  var requestMergeInputSchema = {
56306
56241
  ...commonRequestFieldsSchema
56307
56242
  };
@@ -56414,7 +56349,7 @@ var initSyncDataSchema = external_exports.object({
56414
56349
  repoRoot: external_exports.string(),
56415
56350
  bindingMode: external_exports.enum(["legacy", "lane", "explicit_root"]).optional(),
56416
56351
  createdCanonicalFamily: external_exports.boolean().optional(),
56417
- baselineStatus: external_exports.enum(["seeded", "existing", "requires_re_anchor", "requires_sync"]).optional()
56352
+ baselineStatus: external_exports.enum(["seeded", "existing", "baseline_missing", "requires_sync"]).optional()
56418
56353
  });
56419
56354
  var initQueuedDataSchema = external_exports.object({
56420
56355
  queued: external_exports.literal(true),
@@ -56462,7 +56397,6 @@ var drainFinalizeQueueDataSchema = external_exports.object({
56462
56397
  results: external_exports.array(genericRecordSchema)
56463
56398
  });
56464
56399
  var syncDataSchema = genericRecordSchema;
56465
- var reAnchorDataSchema = genericRecordSchema;
56466
56400
  var requestMergeDataSchema = genericRecordSchema;
56467
56401
  var mergeRequestQueueDataSchema = external_exports.object({
56468
56402
  queue: mergeRequestQueueSchema,
@@ -56538,7 +56472,6 @@ var addSuccessSchema = makeSuccessSchema(addDataSchema);
56538
56472
  var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
56539
56473
  var drainFinalizeQueueSuccessSchema = makeSuccessSchema(drainFinalizeQueueDataSchema);
56540
56474
  var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
56541
- var reAnchorSuccessSchema = makeSuccessSchema(reAnchorDataSchema);
56542
56475
  var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
56543
56476
  var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
56544
56477
  var viewMergeRequestSuccessSchema = makeSuccessSchema(viewMergeRequestDataSchema);
@@ -56557,7 +56490,7 @@ var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema
56557
56490
  function getRiskLevel(status) {
56558
56491
  if (status.recommendedAction === "reconcile") return "high";
56559
56492
  if (status.recommendedAction === "choose_family" || status.recommendedAction === "await_finalize") return "medium";
56560
- if (status.recommendedAction === "pull" || status.recommendedAction === "re_anchor" || status.remote.incomingOpenMergeRequestCount) {
56493
+ if (status.recommendedAction === "pull" || status.remote.incomingOpenMergeRequestCount) {
56561
56494
  return "medium";
56562
56495
  }
56563
56496
  if (status.repo.branchMismatch || !status.repo.isGitRepo || !status.binding.isBound || !status.repo.worktree.isClean) return "medium";
@@ -56574,10 +56507,6 @@ function getRecommendedNextActions(status) {
56574
56507
  return ["Run remix_collab_init to bind the repository to Remix before using any Remix collaboration mutation flow."];
56575
56508
  case "pull":
56576
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."];
56577
- case "re_anchor":
56578
- return [
56579
- "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."
56580
- ];
56581
56510
  case "record":
56582
56511
  return [
56583
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."
@@ -56662,8 +56591,8 @@ async function initCollab(params) {
56662
56591
  return {
56663
56592
  data: syncResult,
56664
56593
  warnings: collectResultWarnings(result),
56665
- recommendedNextActions: syncResult.baselineStatus === "requires_re_anchor" ? [
56666
- "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."
56667
56596
  ] : syncResult.baselineStatus === "requires_sync" ? [
56668
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."
56669
56598
  ] : ["Run remix_collab_status to inspect sync, reconcile, and merge-request readiness before mutating bound-repo state."],
@@ -56766,26 +56695,6 @@ async function syncCollab(params) {
56766
56695
  }
56767
56696
  };
56768
56697
  }
56769
- async function reAnchor(params) {
56770
- const api = await createCollabApiClient();
56771
- const result = await collabReAnchor({
56772
- api,
56773
- cwd: params.cwd,
56774
- dryRun: params.dryRun,
56775
- allowBranchMismatch: params.allowBranchMismatch ?? false
56776
- });
56777
- return {
56778
- data: result,
56779
- warnings: collectWarnings(result.warnings),
56780
- recommendedNextActions: params.dryRun ? [
56781
- "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."
56782
- ] : [],
56783
- logContext: {
56784
- repoRoot: result.repoRoot,
56785
- appId: result.currentAppId
56786
- }
56787
- };
56788
- }
56789
56698
  async function requestMerge(params) {
56790
56699
  const api = await createCollabApiClient();
56791
56700
  const drainWarnings = await drainBeforeMutation(api);
@@ -57502,22 +57411,25 @@ async function accessDebug(params) {
57502
57411
  }
57503
57412
  };
57504
57413
  }
57505
- var MARKER_REL_PATH = import_path17.default.join(".remix", ".history-imported");
57506
- 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");
57507
57416
  function shouldAutoSpawnHistoryImport(repoRoot) {
57508
57417
  try {
57509
- 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));
57510
57419
  } catch {
57511
57420
  return false;
57512
57421
  }
57513
57422
  }
57514
- function spawnHistoryImportDetached(repoRoot) {
57515
- 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");
57516
57428
  try {
57517
57429
  (0, import_fs3.mkdirSync)(remixDir, { recursive: true });
57518
57430
  } catch {
57519
57431
  }
57520
- const logPath = import_path17.default.join(repoRoot, LOG_REL_PATH);
57432
+ const logPath = import_path16.default.join(repoRoot, LOG_REL_PATH);
57521
57433
  const out = (0, import_fs3.openSync)(logPath, "a");
57522
57434
  const err = (0, import_fs3.openSync)(logPath, "a");
57523
57435
  const child = (0, import_child_process.spawn)(
@@ -57527,6 +57439,8 @@ function spawnHistoryImportDetached(repoRoot) {
57527
57439
  "import",
57528
57440
  "--repo",
57529
57441
  repoRoot,
57442
+ "--before",
57443
+ options.cutoffAt,
57530
57444
  // Include prompt text for parity with the CLI auto-spawn path:
57531
57445
  // first-time UX is a lot worse if the dashboard renders every
57532
57446
  // historical row as "(prompt not uploaded)".
@@ -57675,11 +57589,13 @@ function registerCollabTools(server, context) {
57675
57589
  });
57676
57590
  try {
57677
57591
  const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
57678
- if (repoRoot && shouldAutoSpawnHistoryImport(repoRoot)) {
57679
- 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 });
57680
57596
  context.logger.log({
57681
57597
  level: "info",
57682
- 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}`,
57683
57599
  tool: "remix_collab_init",
57684
57600
  repoRoot
57685
57601
  });
@@ -57783,31 +57699,6 @@ function registerCollabTools(server, context) {
57783
57699
  return syncCollab({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
57784
57700
  }
57785
57701
  });
57786
- registerTool(server, context, {
57787
- name: "remix_collab_re_anchor_preview",
57788
- 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.",
57789
- access: "read",
57790
- inputSchema: previewInputSchema,
57791
- outputSchema: reAnchorSuccessSchema,
57792
- run: async (args) => {
57793
- const input = external_exports.object(previewInputSchema).parse(args);
57794
- const cwd = resolvePolicyCwd(context.policy, input.cwd);
57795
- return reAnchor({ cwd, dryRun: true });
57796
- }
57797
- });
57798
- registerTool(server, context, {
57799
- name: "remix_collab_re_anchor_apply",
57800
- 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.",
57801
- access: "local_write",
57802
- inputSchema: reAnchorInputSchema,
57803
- outputSchema: reAnchorSuccessSchema,
57804
- run: async (args) => {
57805
- const input = external_exports.object(reAnchorInputSchema).parse(args);
57806
- assertConfirm(input.confirm, "remix_collab_re_anchor_apply");
57807
- const cwd = resolvePolicyCwd(context.policy, input.cwd);
57808
- return reAnchor({ cwd, dryRun: false, allowBranchMismatch: input.allowBranchMismatch ?? false });
57809
- }
57810
- });
57811
57702
  registerTool(server, context, {
57812
57703
  name: "remix_collab_request_merge",
57813
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.",
@@ -59572,6 +59463,7 @@ function createRemixMcpServer(params) {
59572
59463
  }
59573
59464
 
59574
59465
  // src/hook-auth.ts
59466
+ var HOOK_API_REQUEST_TIMEOUT_MS = 6e4;
59575
59467
  async function createHookCollabApiClient() {
59576
59468
  const config2 = await resolveConfig();
59577
59469
  const sessionStore = createLocalSessionStore();
@@ -59584,18 +59476,19 @@ async function createHookCollabApiClient() {
59584
59476
  }
59585
59477
  });
59586
59478
  return createApiClient(config2, {
59587
- tokenProvider
59479
+ tokenProvider,
59480
+ defaultRequestTimeoutMs: HOOK_API_REQUEST_TIMEOUT_MS
59588
59481
  });
59589
59482
  }
59590
59483
 
59591
59484
  // src/hook-diagnostics.ts
59592
59485
  var import_node_crypto2 = require("crypto");
59593
- var import_promises28 = __toESM(require("fs/promises"), 1);
59486
+ var import_promises27 = __toESM(require("fs/promises"), 1);
59594
59487
  var import_node_os5 = __toESM(require("os"), 1);
59595
59488
  var import_node_path7 = __toESM(require("path"), 1);
59596
59489
 
59597
59490
  // src/hook-state.ts
59598
- var import_promises27 = __toESM(require("fs/promises"), 1);
59491
+ var import_promises26 = __toESM(require("fs/promises"), 1);
59599
59492
  var import_node_os4 = __toESM(require("os"), 1);
59600
59493
  var import_node_path6 = __toESM(require("path"), 1);
59601
59494
  var import_node_crypto = require("crypto");
@@ -59700,7 +59593,7 @@ function getPendingTurnStateRootPath() {
59700
59593
  return stateRoot();
59701
59594
  }
59702
59595
  async function loadPendingTurnState(sessionId) {
59703
- 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);
59704
59597
  if (!raw) return null;
59705
59598
  try {
59706
59599
  const parsed = JSON.parse(raw);
@@ -59727,7 +59620,7 @@ async function loadPendingTurnState(sessionId) {
59727
59620
  }
59728
59621
  async function listPendingTurnStateSummaries() {
59729
59622
  const root = stateRoot();
59730
- const entries = await import_promises27.default.readdir(root, { withFileTypes: true }).catch(() => []);
59623
+ const entries = await import_promises26.default.readdir(root, { withFileTypes: true }).catch(() => []);
59731
59624
  const sessionIds = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((a2, b) => a2.localeCompare(b));
59732
59625
  const states = await Promise.all(sessionIds.map((sessionId) => loadPendingTurnState(sessionId)));
59733
59626
  return states.filter((state) => state !== null).sort((a2, b) => b.submittedAt.localeCompare(a2.submittedAt)).map((state) => summarizePendingTurnState(state));
@@ -59736,7 +59629,7 @@ async function listPendingTurnStateSummaries() {
59736
59629
  // package.json
59737
59630
  var package_default = {
59738
59631
  name: "@remixhq/claude-plugin",
59739
- version: "0.1.21",
59632
+ version: "0.1.23",
59740
59633
  description: "Claude Code plugin for Remix collaboration workflows",
59741
59634
  homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
59742
59635
  license: "MIT",
@@ -59770,12 +59663,12 @@ var package_default = {
59770
59663
  postbuild: `node -e "const fs=require('node:fs'); for (const p of ['dist/mcp-server.cjs','dist/hook-pre-git.cjs','dist/hook-user-prompt.cjs','dist/hook-post-collab.cjs','dist/hook-stop-collab.cjs']) fs.chmodSync(p, 0o755);"`,
59771
59664
  dev: "tsx src/mcp-server.ts",
59772
59665
  typecheck: "tsc -p tsconfig.json --noEmit",
59773
- test: "node --import tsx --test src/**/*.test.ts",
59666
+ test: "node --import tsx --test 'src/**/*.test.ts'",
59774
59667
  prepack: "npm run build"
59775
59668
  },
59776
59669
  dependencies: {
59777
- "@remixhq/core": "^0.1.15",
59778
- "@remixhq/mcp": "^0.1.16"
59670
+ "@remixhq/core": "^0.1.18",
59671
+ "@remixhq/mcp": "^0.1.18"
59779
59672
  },
59780
59673
  devDependencies: {
59781
59674
  "@types/node": "^25.4.0",
@@ -59817,7 +59710,7 @@ function clampEventLimit(limit) {
59817
59710
  return Math.max(1, Math.min(MAX_EVENT_LIMIT, Math.trunc(limit)));
59818
59711
  }
59819
59712
  async function readEventsFromFile(filePath) {
59820
- const raw = await import_promises28.default.readFile(filePath, "utf8").catch(() => null);
59713
+ const raw = await import_promises27.default.readFile(filePath, "utf8").catch(() => null);
59821
59714
  if (!raw) return [];
59822
59715
  return raw.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
59823
59716
  try {