@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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/hook-post-collab.cjs +3 -3
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +111 -45
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +147 -52
- package/dist/hook-user-prompt.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +171 -57
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
|
@@ -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:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
10558
|
-
"@remixhq/mcp": "^0.1.
|
|
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-
|
|
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)
|