@remixhq/claude-plugin 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8578,6 +8578,15 @@ function shouldRequireRemoteLaneForCurrentBranch(params) {
8578
8578
  if (params.currentBranch === defaultBranch) return false;
8579
8579
  return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
8580
8580
  }
8581
+ function resolveLaneLookupProjectId(params) {
8582
+ const currentBranch = normalizeBranchName2(params.currentBranch);
8583
+ const defaultBranch = normalizeBranchName2(params.defaultBranch);
8584
+ const localProjectId = params.localBinding.projectId ?? null;
8585
+ if (currentBranch && currentBranch !== defaultBranch && localProjectId) {
8586
+ return localProjectId;
8587
+ }
8588
+ return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
8589
+ }
8581
8590
  async function persistResolvedLane(repoRoot, binding) {
8582
8591
  await writeCollabBinding(repoRoot, {
8583
8592
  projectId: binding.projectId,
@@ -8656,7 +8665,14 @@ async function resolveActiveLaneBindingUncached(params, state) {
8656
8665
  };
8657
8666
  }
8658
8667
  const laneResp2 = await params.api.resolveProjectLaneBinding({
8659
- projectId: state.explicitRootBinding?.projectId ?? (requireRemoteLane ? void 0 : localBinding.projectId ?? state.projectId ?? void 0),
8668
+ projectId: resolveLaneLookupProjectId({
8669
+ explicitRootProjectId: state.explicitRootBinding?.projectId,
8670
+ localBinding,
8671
+ currentBranch,
8672
+ defaultBranch: state.defaultBranch,
8673
+ requireRemoteLane,
8674
+ fallbackProjectId: state.projectId
8675
+ }),
8660
8676
  repoFingerprint: state.repoFingerprint ?? void 0,
8661
8677
  remoteUrl: state.remoteUrl ?? void 0,
8662
8678
  defaultBranch: state.defaultBranch ?? void 0,
@@ -9507,6 +9523,59 @@ function buildWorkspaceMetadata(params) {
9507
9523
  }
9508
9524
  return metadata;
9509
9525
  }
9526
+ async function findExistingChangeStepByIdempotency(params) {
9527
+ const idempotencyKey = params.idempotencyKey?.trim();
9528
+ if (!idempotencyKey) return null;
9529
+ const resp = await params.api.listChangeSteps(params.appId, { limit: 1, idempotencyKey });
9530
+ const responseObject = unwrapResponseObject(
9531
+ resp,
9532
+ "change step list"
9533
+ );
9534
+ const steps = Array.isArray(responseObject) ? responseObject : Array.isArray(responseObject.items) ? responseObject.items : [];
9535
+ return steps.find((step) => step.idempotencyKey === idempotencyKey) ?? null;
9536
+ }
9537
+ async function writeBaselineFromSucceededChangeStep(params) {
9538
+ const nextServerHeadHash = typeof params.changeStep.headCommitHash === "string" ? params.changeStep.headCommitHash.trim() : "";
9539
+ if (!nextServerHeadHash) {
9540
+ throw buildFinalizeCliError({
9541
+ message: "Backend returned a succeeded change step without a head commit hash.",
9542
+ exitCode: 1,
9543
+ hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
9544
+ disposition: "terminal",
9545
+ reason: "missing_head_commit_hash"
9546
+ });
9547
+ }
9548
+ let nextServerRevisionId = typeof params.changeStep.resultRevisionId === "string" ? params.changeStep.resultRevisionId.trim() : "";
9549
+ let nextServerTreeHash = null;
9550
+ if (!nextServerRevisionId) {
9551
+ const freshHeadResp = await params.api.getAppHead(params.job.currentAppId);
9552
+ const freshHead = unwrapResponseObject(freshHeadResp, "app head");
9553
+ if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
9554
+ throw buildFinalizeCliError({
9555
+ message: "Backend returned a succeeded change step without a matching result revision.",
9556
+ exitCode: 1,
9557
+ 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`.",
9558
+ disposition: "terminal",
9559
+ reason: "missing_result_revision_id"
9560
+ });
9561
+ }
9562
+ nextServerRevisionId = freshHead.headRevisionId;
9563
+ nextServerTreeHash = freshHead.treeHash ?? null;
9564
+ }
9565
+ await writeLocalBaseline({
9566
+ repoRoot: params.job.repoRoot,
9567
+ repoFingerprint: params.job.repoFingerprint,
9568
+ laneId: params.job.laneId,
9569
+ currentAppId: params.job.currentAppId,
9570
+ branchName: params.job.branchName,
9571
+ lastSnapshotId: params.snapshot.id,
9572
+ lastSnapshotHash: params.snapshot.snapshotHash,
9573
+ lastServerRevisionId: nextServerRevisionId,
9574
+ lastServerTreeHash: nextServerTreeHash,
9575
+ lastServerHeadHash: nextServerHeadHash,
9576
+ lastSeenLocalCommitHash: params.snapshot.localCommitHash
9577
+ });
9578
+ }
9510
9579
  async function harvestPreTurnEvents(repoRoot, fromCommit, toCommit) {
9511
9580
  if (!toCommit) return null;
9512
9581
  try {
@@ -9692,6 +9761,34 @@ async function processClaimedPendingFinalizeJobInner(params) {
9692
9761
  });
9693
9762
  }
9694
9763
  const replayNeeded = appHead.headCommitHash !== submissionBaseHeadHash || baselineDrifted;
9764
+ if (replayNeeded) {
9765
+ const existingChangeStep = await findExistingChangeStepByIdempotency({
9766
+ api: params.api,
9767
+ appId: job.currentAppId,
9768
+ idempotencyKey: job.idempotencyKey
9769
+ });
9770
+ if (existingChangeStep) {
9771
+ const changeStep2 = existingChangeStep.status === "succeeded" ? existingChangeStep : await pollChangeStep(params.api, job.currentAppId, existingChangeStep.id);
9772
+ invalidateAppHeadCache(job.currentAppId);
9773
+ invalidateAppDeltaCacheForApp(job.currentAppId);
9774
+ await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep: changeStep2 });
9775
+ await updatePendingFinalizeJob(job.id, {
9776
+ status: "completed",
9777
+ metadata: { changeStepId: String(changeStep2.id ?? "") }
9778
+ });
9779
+ return {
9780
+ mode: "changed_turn",
9781
+ idempotencyKey: job.idempotencyKey ?? "",
9782
+ queued: false,
9783
+ jobId: job.id,
9784
+ repoState,
9785
+ changeStep: changeStep2,
9786
+ collabTurn: null,
9787
+ autoSync: null,
9788
+ warnings: []
9789
+ };
9790
+ }
9791
+ }
9695
9792
  if (replayNeeded) {
9696
9793
  try {
9697
9794
  const replayResp = await params.api.startChangeStepReplay(job.currentAppId, {
@@ -9789,46 +9886,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
9789
9886
  const changeStep = await pollChangeStep(params.api, job.currentAppId, String(createdStep.id));
9790
9887
  invalidateAppHeadCache(job.currentAppId);
9791
9888
  invalidateAppDeltaCacheForApp(job.currentAppId);
9792
- const nextServerHeadHash = typeof changeStep.headCommitHash === "string" ? changeStep.headCommitHash.trim() : "";
9793
- if (!nextServerHeadHash) {
9794
- throw buildFinalizeCliError({
9795
- message: "Backend returned a succeeded change step without a head commit hash.",
9796
- exitCode: 1,
9797
- hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
9798
- disposition: "terminal",
9799
- reason: "missing_head_commit_hash"
9800
- });
9801
- }
9802
- let nextServerRevisionId = typeof changeStep.resultRevisionId === "string" ? changeStep.resultRevisionId.trim() : "";
9803
- let nextServerTreeHash = null;
9804
- if (!nextServerRevisionId) {
9805
- const freshHeadResp = await params.api.getAppHead(job.currentAppId);
9806
- const freshHead = unwrapResponseObject(freshHeadResp, "app head");
9807
- if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
9808
- throw buildFinalizeCliError({
9809
- message: "Backend returned a succeeded change step without a matching result revision.",
9810
- exitCode: 1,
9811
- 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`.",
9812
- disposition: "terminal",
9813
- reason: "missing_result_revision_id"
9814
- });
9815
- }
9816
- nextServerRevisionId = freshHead.headRevisionId;
9817
- nextServerTreeHash = freshHead.treeHash ?? null;
9818
- }
9819
- await writeLocalBaseline({
9820
- repoRoot: job.repoRoot,
9821
- repoFingerprint: job.repoFingerprint,
9822
- laneId: job.laneId,
9823
- currentAppId: job.currentAppId,
9824
- branchName: job.branchName,
9825
- lastSnapshotId: snapshot.id,
9826
- lastSnapshotHash: snapshot.snapshotHash,
9827
- lastServerRevisionId: nextServerRevisionId,
9828
- lastServerTreeHash: nextServerTreeHash,
9829
- lastServerHeadHash: nextServerHeadHash,
9830
- lastSeenLocalCommitHash: snapshot.localCommitHash
9831
- });
9889
+ await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep });
9832
9890
  await updatePendingFinalizeJob(job.id, {
9833
9891
  status: "completed",
9834
9892
  metadata: { changeStepId: String(changeStep.id ?? "") }
@@ -10516,7 +10574,7 @@ async function clearPendingTurnState(sessionId) {
10516
10574
  // package.json
10517
10575
  var package_default = {
10518
10576
  name: "@remixhq/claude-plugin",
10519
- version: "0.1.23",
10577
+ version: "0.1.24",
10520
10578
  description: "Claude Code plugin for Remix collaboration workflows",
10521
10579
  homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
10522
10580
  license: "MIT",
@@ -10554,8 +10612,8 @@ var package_default = {
10554
10612
  prepack: "npm run build"
10555
10613
  },
10556
10614
  dependencies: {
10557
- "@remixhq/core": "^0.1.18",
10558
- "@remixhq/mcp": "^0.1.18"
10615
+ "@remixhq/core": "^0.1.19",
10616
+ "@remixhq/mcp": "^0.1.19"
10559
10617
  },
10560
10618
  devDependencies: {
10561
10619
  "@types/node": "^25.4.0",
@@ -10993,7 +11051,7 @@ var import_promises23 = __toESM(require("fs/promises"), 1);
10993
11051
  var import_node_path11 = __toESM(require("path"), 1);
10994
11052
  var import_node_crypto3 = require("crypto");
10995
11053
 
10996
- // node_modules/@remixhq/core/dist/chunk-RCNOSZP6.js
11054
+ // node_modules/@remixhq/core/dist/chunk-C2FOZ3O7.js
10997
11055
  async function readJsonSafe(res) {
10998
11056
  const ct = res.headers.get("content-type") ?? "";
10999
11057
  if (!ct.toLowerCase().includes("application/json")) return null;
@@ -11187,6 +11245,14 @@ function createApiClient(config, opts) {
11187
11245
  method: "POST",
11188
11246
  body: JSON.stringify(payload)
11189
11247
  }),
11248
+ listChangeSteps: (appId, params) => {
11249
+ const qs = new URLSearchParams();
11250
+ if (params?.limit !== void 0) qs.set("limit", String(params.limit));
11251
+ if (params?.offset !== void 0) qs.set("offset", String(params.offset));
11252
+ if (params?.idempotencyKey) qs.set("idempotencyKey", params.idempotencyKey);
11253
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
11254
+ return request(`/v1/apps/${encodeURIComponent(appId)}/change-steps${suffix}`, { method: "GET" });
11255
+ },
11190
11256
  createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
11191
11257
  method: "POST",
11192
11258
  body: JSON.stringify(payload)