@remixhq/claude-plugin 0.1.23 → 0.1.25
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 +261 -183
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +310 -228
- 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 +209 -73
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/submit-change-step/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@remixhq/claude-plugin",
|
|
6
|
-
version: "0.1.
|
|
6
|
+
version: "0.1.25",
|
|
7
7
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
8
8
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
9
9
|
license: "MIT",
|
|
@@ -41,8 +41,8 @@ var package_default = {
|
|
|
41
41
|
prepack: "npm run build"
|
|
42
42
|
},
|
|
43
43
|
dependencies: {
|
|
44
|
-
"@remixhq/core": "^0.1.
|
|
45
|
-
"@remixhq/mcp": "^0.1.
|
|
44
|
+
"@remixhq/core": "^0.1.20",
|
|
45
|
+
"@remixhq/mcp": "^0.1.20"
|
|
46
46
|
},
|
|
47
47
|
devDependencies: {
|
|
48
48
|
"@types/node": "^25.4.0",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json","../src/metadata.ts"],"sourcesContent":["{\n \"name\": \"@remixhq/claude-plugin\",\n \"version\": \"0.1.
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/metadata.ts"],"sourcesContent":["{\n \"name\": \"@remixhq/claude-plugin\",\n \"version\": \"0.1.25\",\n \"description\": \"Claude Code plugin for Remix collaboration workflows\",\n \"homepage\": \"https://github.com/RemixDotOne/remix-claude-plugin\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/RemixDotOne/remix-claude-plugin.git\"\n },\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=20\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\",\n \".claude-plugin/plugin.json\",\n \".mcp.json\",\n \"skills\",\n \"hooks\",\n \"agents\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"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);\\\"\",\n \"dev\": \"tsx src/mcp-server.ts\",\n \"typecheck\": \"tsc -p tsconfig.json --noEmit\",\n \"test\": \"node --import tsx --test 'src/**/*.test.ts'\",\n \"prepack\": \"npm run build\"\n },\n \"dependencies\": {\n \"@remixhq/core\": \"^0.1.20\",\n \"@remixhq/mcp\": \"^0.1.20\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.4.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.9.3\"\n }\n}\n","import pkg from \"../package.json\";\n\nexport const pluginMetadata = {\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n pluginId: \"remix\",\n agentName: \"remix-collab\",\n};\n"],"mappings":";;;AAAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,UAAY;AAAA,EACZ,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,EACR,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,QAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,WAAa;AAAA,IACb,KAAO;AAAA,IACP,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,SAAW;AAAA,EACb;AAAA,EACA,cAAgB;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,EAClB;AAAA,EACA,iBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,EAChB;AACF;;;AC/CO,IAAM,iBAAiB;AAAA,EAC5B,MAAM,gBAAI;AAAA,EACV,SAAS,gBAAI;AAAA,EACb,aAAa,gBAAI;AAAA,EACjB,UAAU;AAAA,EACV,WAAW;AACb;","names":[]}
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -22359,6 +22359,15 @@ function shouldRequireRemoteLaneForCurrentBranch(params) {
|
|
|
22359
22359
|
if (params.currentBranch === defaultBranch) return false;
|
|
22360
22360
|
return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
|
|
22361
22361
|
}
|
|
22362
|
+
function resolveLaneLookupProjectId(params) {
|
|
22363
|
+
const currentBranch = normalizeBranchName2(params.currentBranch);
|
|
22364
|
+
const defaultBranch = normalizeBranchName2(params.defaultBranch);
|
|
22365
|
+
const localProjectId = params.localBinding.projectId ?? null;
|
|
22366
|
+
if (currentBranch && currentBranch !== defaultBranch && localProjectId) {
|
|
22367
|
+
return localProjectId;
|
|
22368
|
+
}
|
|
22369
|
+
return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
|
|
22370
|
+
}
|
|
22362
22371
|
async function persistResolvedLane(repoRoot, binding) {
|
|
22363
22372
|
await writeCollabBinding(repoRoot, {
|
|
22364
22373
|
projectId: binding.projectId,
|
|
@@ -22437,7 +22446,14 @@ async function resolveActiveLaneBindingUncached(params, state) {
|
|
|
22437
22446
|
};
|
|
22438
22447
|
}
|
|
22439
22448
|
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
22440
|
-
projectId:
|
|
22449
|
+
projectId: resolveLaneLookupProjectId({
|
|
22450
|
+
explicitRootProjectId: state.explicitRootBinding?.projectId,
|
|
22451
|
+
localBinding,
|
|
22452
|
+
currentBranch,
|
|
22453
|
+
defaultBranch: state.defaultBranch,
|
|
22454
|
+
requireRemoteLane,
|
|
22455
|
+
fallbackProjectId: state.projectId
|
|
22456
|
+
}),
|
|
22441
22457
|
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
22442
22458
|
remoteUrl: state.remoteUrl ?? void 0,
|
|
22443
22459
|
defaultBranch: state.defaultBranch ?? void 0,
|
|
@@ -23288,6 +23304,59 @@ function buildWorkspaceMetadata(params) {
|
|
|
23288
23304
|
}
|
|
23289
23305
|
return metadata;
|
|
23290
23306
|
}
|
|
23307
|
+
async function findExistingChangeStepByIdempotency(params) {
|
|
23308
|
+
const idempotencyKey = params.idempotencyKey?.trim();
|
|
23309
|
+
if (!idempotencyKey) return null;
|
|
23310
|
+
const resp = await params.api.listChangeSteps(params.appId, { limit: 1, idempotencyKey });
|
|
23311
|
+
const responseObject = unwrapResponseObject(
|
|
23312
|
+
resp,
|
|
23313
|
+
"change step list"
|
|
23314
|
+
);
|
|
23315
|
+
const steps = Array.isArray(responseObject) ? responseObject : Array.isArray(responseObject.items) ? responseObject.items : [];
|
|
23316
|
+
return steps.find((step) => step.idempotencyKey === idempotencyKey) ?? null;
|
|
23317
|
+
}
|
|
23318
|
+
async function writeBaselineFromSucceededChangeStep(params) {
|
|
23319
|
+
const nextServerHeadHash = typeof params.changeStep.headCommitHash === "string" ? params.changeStep.headCommitHash.trim() : "";
|
|
23320
|
+
if (!nextServerHeadHash) {
|
|
23321
|
+
throw buildFinalizeCliError({
|
|
23322
|
+
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
23323
|
+
exitCode: 1,
|
|
23324
|
+
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
23325
|
+
disposition: "terminal",
|
|
23326
|
+
reason: "missing_head_commit_hash"
|
|
23327
|
+
});
|
|
23328
|
+
}
|
|
23329
|
+
let nextServerRevisionId = typeof params.changeStep.resultRevisionId === "string" ? params.changeStep.resultRevisionId.trim() : "";
|
|
23330
|
+
let nextServerTreeHash = null;
|
|
23331
|
+
if (!nextServerRevisionId) {
|
|
23332
|
+
const freshHeadResp = await params.api.getAppHead(params.job.currentAppId);
|
|
23333
|
+
const freshHead = unwrapResponseObject(freshHeadResp, "app head");
|
|
23334
|
+
if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
|
|
23335
|
+
throw buildFinalizeCliError({
|
|
23336
|
+
message: "Backend returned a succeeded change step without a matching result revision.",
|
|
23337
|
+
exitCode: 1,
|
|
23338
|
+
hint: "The local baseline was not advanced because the post-step revision could not be verified. Restart the backend/CLI and retry after checking `remix collab status`.",
|
|
23339
|
+
disposition: "terminal",
|
|
23340
|
+
reason: "missing_result_revision_id"
|
|
23341
|
+
});
|
|
23342
|
+
}
|
|
23343
|
+
nextServerRevisionId = freshHead.headRevisionId;
|
|
23344
|
+
nextServerTreeHash = freshHead.treeHash ?? null;
|
|
23345
|
+
}
|
|
23346
|
+
await writeLocalBaseline({
|
|
23347
|
+
repoRoot: params.job.repoRoot,
|
|
23348
|
+
repoFingerprint: params.job.repoFingerprint,
|
|
23349
|
+
laneId: params.job.laneId,
|
|
23350
|
+
currentAppId: params.job.currentAppId,
|
|
23351
|
+
branchName: params.job.branchName,
|
|
23352
|
+
lastSnapshotId: params.snapshot.id,
|
|
23353
|
+
lastSnapshotHash: params.snapshot.snapshotHash,
|
|
23354
|
+
lastServerRevisionId: nextServerRevisionId,
|
|
23355
|
+
lastServerTreeHash: nextServerTreeHash,
|
|
23356
|
+
lastServerHeadHash: nextServerHeadHash,
|
|
23357
|
+
lastSeenLocalCommitHash: params.snapshot.localCommitHash
|
|
23358
|
+
});
|
|
23359
|
+
}
|
|
23291
23360
|
async function harvestPreTurnEvents(repoRoot, fromCommit, toCommit) {
|
|
23292
23361
|
if (!toCommit) return null;
|
|
23293
23362
|
try {
|
|
@@ -23473,6 +23542,34 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23473
23542
|
});
|
|
23474
23543
|
}
|
|
23475
23544
|
const replayNeeded = appHead.headCommitHash !== submissionBaseHeadHash || baselineDrifted;
|
|
23545
|
+
if (replayNeeded) {
|
|
23546
|
+
const existingChangeStep = await findExistingChangeStepByIdempotency({
|
|
23547
|
+
api: params.api,
|
|
23548
|
+
appId: job.currentAppId,
|
|
23549
|
+
idempotencyKey: job.idempotencyKey
|
|
23550
|
+
});
|
|
23551
|
+
if (existingChangeStep) {
|
|
23552
|
+
const changeStep2 = existingChangeStep.status === "succeeded" ? existingChangeStep : await pollChangeStep(params.api, job.currentAppId, existingChangeStep.id);
|
|
23553
|
+
invalidateAppHeadCache(job.currentAppId);
|
|
23554
|
+
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
23555
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep: changeStep2 });
|
|
23556
|
+
await updatePendingFinalizeJob(job.id, {
|
|
23557
|
+
status: "completed",
|
|
23558
|
+
metadata: { changeStepId: String(changeStep2.id ?? "") }
|
|
23559
|
+
});
|
|
23560
|
+
return {
|
|
23561
|
+
mode: "changed_turn",
|
|
23562
|
+
idempotencyKey: job.idempotencyKey ?? "",
|
|
23563
|
+
queued: false,
|
|
23564
|
+
jobId: job.id,
|
|
23565
|
+
repoState,
|
|
23566
|
+
changeStep: changeStep2,
|
|
23567
|
+
collabTurn: null,
|
|
23568
|
+
autoSync: null,
|
|
23569
|
+
warnings: []
|
|
23570
|
+
};
|
|
23571
|
+
}
|
|
23572
|
+
}
|
|
23476
23573
|
if (replayNeeded) {
|
|
23477
23574
|
try {
|
|
23478
23575
|
const replayResp = await params.api.startChangeStepReplay(job.currentAppId, {
|
|
@@ -23570,46 +23667,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
23570
23667
|
const changeStep = await pollChangeStep(params.api, job.currentAppId, String(createdStep.id));
|
|
23571
23668
|
invalidateAppHeadCache(job.currentAppId);
|
|
23572
23669
|
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
23573
|
-
|
|
23574
|
-
if (!nextServerHeadHash) {
|
|
23575
|
-
throw buildFinalizeCliError({
|
|
23576
|
-
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
23577
|
-
exitCode: 1,
|
|
23578
|
-
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
23579
|
-
disposition: "terminal",
|
|
23580
|
-
reason: "missing_head_commit_hash"
|
|
23581
|
-
});
|
|
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
|
-
}
|
|
23600
|
-
await writeLocalBaseline({
|
|
23601
|
-
repoRoot: job.repoRoot,
|
|
23602
|
-
repoFingerprint: job.repoFingerprint,
|
|
23603
|
-
laneId: job.laneId,
|
|
23604
|
-
currentAppId: job.currentAppId,
|
|
23605
|
-
branchName: job.branchName,
|
|
23606
|
-
lastSnapshotId: snapshot.id,
|
|
23607
|
-
lastSnapshotHash: snapshot.snapshotHash,
|
|
23608
|
-
lastServerRevisionId: nextServerRevisionId,
|
|
23609
|
-
lastServerTreeHash: nextServerTreeHash,
|
|
23610
|
-
lastServerHeadHash: nextServerHeadHash,
|
|
23611
|
-
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
23612
|
-
});
|
|
23670
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep });
|
|
23613
23671
|
await updatePendingFinalizeJob(job.id, {
|
|
23614
23672
|
status: "completed",
|
|
23615
23673
|
metadata: { changeStepId: String(changeStep.id ?? "") }
|
|
@@ -24751,27 +24809,21 @@ async function trySeedEquivalentBranchBaseline(params) {
|
|
|
24751
24809
|
branchName: params.branchName,
|
|
24752
24810
|
persistBlobs: false
|
|
24753
24811
|
});
|
|
24754
|
-
if (inspection.snapshotHash !== defaultBaseline.lastSnapshotHash) {
|
|
24812
|
+
if (inspection.snapshotHash !== defaultBaseline.lastSnapshotHash && inspection.localCommitHash !== defaultBaseline.lastSeenLocalCommitHash) {
|
|
24755
24813
|
return null;
|
|
24756
24814
|
}
|
|
24757
|
-
const snapshot = await captureLocalSnapshot({
|
|
24758
|
-
repoRoot: params.repoRoot,
|
|
24759
|
-
repoFingerprint: params.repoFingerprint,
|
|
24760
|
-
laneId: params.laneId,
|
|
24761
|
-
branchName: params.branchName
|
|
24762
|
-
});
|
|
24763
24815
|
await writeLocalBaseline({
|
|
24764
24816
|
repoRoot: params.repoRoot,
|
|
24765
24817
|
repoFingerprint: params.repoFingerprint,
|
|
24766
24818
|
laneId: params.laneId,
|
|
24767
24819
|
currentAppId: params.currentAppId,
|
|
24768
24820
|
branchName: params.branchName,
|
|
24769
|
-
lastSnapshotId:
|
|
24770
|
-
lastSnapshotHash:
|
|
24821
|
+
lastSnapshotId: defaultBaseline.lastSnapshotId,
|
|
24822
|
+
lastSnapshotHash: defaultBaseline.lastSnapshotHash,
|
|
24771
24823
|
lastServerRevisionId: params.appHeadRevisionId,
|
|
24772
24824
|
lastServerTreeHash: params.appTreeHash,
|
|
24773
24825
|
lastServerHeadHash: params.appHeadHash,
|
|
24774
|
-
lastSeenLocalCommitHash:
|
|
24826
|
+
lastSeenLocalCommitHash: inspection.localCommitHash
|
|
24775
24827
|
});
|
|
24776
24828
|
return "seeded";
|
|
24777
24829
|
}
|
|
@@ -24820,6 +24872,21 @@ async function resolveInitBaselineStatus(params) {
|
|
|
24820
24872
|
});
|
|
24821
24873
|
const delta = unwrapResponseObject(deltaResp, "app delta");
|
|
24822
24874
|
if (delta.status === "up_to_date" || delta.status === "delta_ready") {
|
|
24875
|
+
const equivalentBaseline = await trySeedEquivalentBranchBaseline({
|
|
24876
|
+
repoRoot: params.repoRoot,
|
|
24877
|
+
repoFingerprint: params.repoFingerprint,
|
|
24878
|
+
laneId: params.laneId,
|
|
24879
|
+
currentAppId: params.currentAppId,
|
|
24880
|
+
upstreamAppId: params.upstreamAppId ?? null,
|
|
24881
|
+
branchName: params.branchName,
|
|
24882
|
+
defaultBranch: params.defaultBranch,
|
|
24883
|
+
appHeadHash: appHead.headCommitHash,
|
|
24884
|
+
appHeadRevisionId: appHead.headRevisionId ?? null,
|
|
24885
|
+
appTreeHash: appHead.treeHash ?? null
|
|
24886
|
+
});
|
|
24887
|
+
if (equivalentBaseline) {
|
|
24888
|
+
return equivalentBaseline;
|
|
24889
|
+
}
|
|
24823
24890
|
return "requires_sync";
|
|
24824
24891
|
}
|
|
24825
24892
|
if (delta.status === "content_equivalent") {
|
|
@@ -24936,6 +25003,7 @@ async function collabInit(params) {
|
|
|
24936
25003
|
upstreamAppId: existingBinding.upstreamAppId ?? existingBinding.currentAppId,
|
|
24937
25004
|
dashboardUrl: buildDashboardAppUrl(existingBinding.currentAppId),
|
|
24938
25005
|
bindingPath: getCollabBindingPath(repoRoot),
|
|
25006
|
+
repoFingerprint: existingBinding.repoFingerprint ?? repoFingerprint,
|
|
24939
25007
|
bindingMode: existingBinding.bindingMode,
|
|
24940
25008
|
createdCanonicalFamily: false,
|
|
24941
25009
|
remoteUrl: existingBinding.remoteUrl ?? remoteUrl,
|
|
@@ -24952,6 +25020,7 @@ async function collabInit(params) {
|
|
|
24952
25020
|
upstreamAppId: "",
|
|
24953
25021
|
dashboardUrl: "",
|
|
24954
25022
|
bindingPath: getCollabBindingPath(repoRoot),
|
|
25023
|
+
repoFingerprint,
|
|
24955
25024
|
bindingMode: "lane",
|
|
24956
25025
|
createdCanonicalFamily: false,
|
|
24957
25026
|
remoteUrl,
|
|
@@ -25052,6 +25121,7 @@ async function collabInit(params) {
|
|
|
25052
25121
|
upstreamAppId: boundUpstreamAppId2,
|
|
25053
25122
|
bindingPath: import_path11.default.join(repoRoot, ".remix", "config.json"),
|
|
25054
25123
|
repoRoot,
|
|
25124
|
+
repoFingerprint,
|
|
25055
25125
|
bindingMode: defaultBranch && branchName !== defaultBranch ? "lane" : "explicit_root",
|
|
25056
25126
|
createdCanonicalFamily: false,
|
|
25057
25127
|
baselineStatus: await resolveInitBaselineStatus({
|
|
@@ -25164,6 +25234,7 @@ async function collabInit(params) {
|
|
|
25164
25234
|
upstreamAppId: boundUpstreamAppId2,
|
|
25165
25235
|
bindingPath: bindingPath2,
|
|
25166
25236
|
repoRoot,
|
|
25237
|
+
repoFingerprint,
|
|
25167
25238
|
bindingMode: "lane",
|
|
25168
25239
|
createdCanonicalFamily: false,
|
|
25169
25240
|
baselineStatus: await resolveInitBaselineStatus({
|
|
@@ -25294,6 +25365,7 @@ async function collabInit(params) {
|
|
|
25294
25365
|
upstreamAppId: boundUpstreamAppId2,
|
|
25295
25366
|
bindingPath: bindingPath2,
|
|
25296
25367
|
repoRoot,
|
|
25368
|
+
repoFingerprint,
|
|
25297
25369
|
bindingMode: "lane",
|
|
25298
25370
|
createdCanonicalFamily: false,
|
|
25299
25371
|
baselineStatus: await resolveInitBaselineStatus({
|
|
@@ -25514,6 +25586,7 @@ async function collabInit(params) {
|
|
|
25514
25586
|
upstreamAppId: boundUpstreamAppId2,
|
|
25515
25587
|
dashboardUrl: buildDashboardAppUrl(boundCurrentAppId2),
|
|
25516
25588
|
bindingPath: bindingPath2,
|
|
25589
|
+
repoFingerprint,
|
|
25517
25590
|
bindingMode: bindingMode2,
|
|
25518
25591
|
createdCanonicalFamily: Boolean(params.forceNew),
|
|
25519
25592
|
remoteUrl,
|
|
@@ -25696,6 +25769,7 @@ async function collabInit(params) {
|
|
|
25696
25769
|
upstreamAppId: boundUpstreamAppId,
|
|
25697
25770
|
bindingPath,
|
|
25698
25771
|
repoRoot,
|
|
25772
|
+
repoFingerprint,
|
|
25699
25773
|
bindingMode,
|
|
25700
25774
|
createdCanonicalFamily: Boolean(params.forceNew),
|
|
25701
25775
|
baselineStatus,
|
|
@@ -35127,7 +35201,7 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
35127
35201
|
}
|
|
35128
35202
|
};
|
|
35129
35203
|
|
|
35130
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
35204
|
+
// node_modules/@remixhq/core/dist/chunk-C2FOZ3O7.js
|
|
35131
35205
|
async function readJsonSafe(res) {
|
|
35132
35206
|
const ct = res.headers.get("content-type") ?? "";
|
|
35133
35207
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -35321,6 +35395,14 @@ function createApiClient(config2, opts) {
|
|
|
35321
35395
|
method: "POST",
|
|
35322
35396
|
body: JSON.stringify(payload)
|
|
35323
35397
|
}),
|
|
35398
|
+
listChangeSteps: (appId, params) => {
|
|
35399
|
+
const qs = new URLSearchParams();
|
|
35400
|
+
if (params?.limit !== void 0) qs.set("limit", String(params.limit));
|
|
35401
|
+
if (params?.offset !== void 0) qs.set("offset", String(params.offset));
|
|
35402
|
+
if (params?.idempotencyKey) qs.set("idempotencyKey", params.idempotencyKey);
|
|
35403
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
35404
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/change-steps${suffix}`, { method: "GET" });
|
|
35405
|
+
},
|
|
35324
35406
|
createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
|
|
35325
35407
|
method: "POST",
|
|
35326
35408
|
body: JSON.stringify(payload)
|
|
@@ -55767,7 +55849,9 @@ async function resolveConfig(_opts) {
|
|
|
55767
55849
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
55768
55850
|
var import_path15 = __toESM(require("path"), 1);
|
|
55769
55851
|
var import_child_process = require("child_process");
|
|
55852
|
+
var import_crypto9 = require("crypto");
|
|
55770
55853
|
var import_fs3 = require("fs");
|
|
55854
|
+
var import_os8 = __toESM(require("os"), 1);
|
|
55771
55855
|
var import_path16 = __toESM(require("path"), 1);
|
|
55772
55856
|
async function createRemixTokenProvider(config2) {
|
|
55773
55857
|
const resolvedConfig = config2 ?? await resolveConfig();
|
|
@@ -55997,6 +56081,15 @@ function normalizeByMessage(err) {
|
|
|
55997
56081
|
category: "remote_state"
|
|
55998
56082
|
});
|
|
55999
56083
|
}
|
|
56084
|
+
if (statusCode === 409) {
|
|
56085
|
+
return makeNormalized({
|
|
56086
|
+
code: ERROR_CODES.REMOTE_ERROR,
|
|
56087
|
+
message,
|
|
56088
|
+
hint,
|
|
56089
|
+
retryable: true,
|
|
56090
|
+
category: "remote_state"
|
|
56091
|
+
});
|
|
56092
|
+
}
|
|
56000
56093
|
if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
|
|
56001
56094
|
return makeNormalized({
|
|
56002
56095
|
code: ERROR_CODES.REMOTE_ERROR,
|
|
@@ -56160,7 +56253,6 @@ function makeSuccessResult2(envelope) {
|
|
|
56160
56253
|
function makeErrorResult(envelope) {
|
|
56161
56254
|
return {
|
|
56162
56255
|
content: [{ type: "text", text: toJsonText(envelope) }],
|
|
56163
|
-
structuredContent: envelope,
|
|
56164
56256
|
isError: true
|
|
56165
56257
|
};
|
|
56166
56258
|
}
|
|
@@ -57411,11 +57503,30 @@ async function accessDebug(params) {
|
|
|
57411
57503
|
}
|
|
57412
57504
|
};
|
|
57413
57505
|
}
|
|
57414
|
-
var
|
|
57415
|
-
|
|
57416
|
-
|
|
57506
|
+
var LEGACY_MARKER_REL_PATH = import_path16.default.join(".remix", ".history-imported");
|
|
57507
|
+
function collabStateRoot() {
|
|
57508
|
+
const configured = process.env.REMIX_COLLAB_STATE_ROOT?.trim();
|
|
57509
|
+
return configured || import_path16.default.join(import_os8.default.homedir(), ".remix", "collab-state");
|
|
57510
|
+
}
|
|
57511
|
+
function sha256Hex3(value) {
|
|
57512
|
+
return (0, import_crypto9.createHash)("sha256").update(value).digest("hex");
|
|
57513
|
+
}
|
|
57514
|
+
function autoSpawnMarkerPath(repoRoot, repoFingerprint) {
|
|
57515
|
+
const identityKey = typeof repoFingerprint === "string" && repoFingerprint.trim() ? `repoFingerprint:${repoFingerprint.trim()}` : `repoRoot:${repoRoot}`;
|
|
57516
|
+
return import_path16.default.join(collabStateRoot(), "history-import", sha256Hex3(identityKey), "history-imported.json");
|
|
57517
|
+
}
|
|
57518
|
+
function fallbackRepoRootMarkerPath(repoRoot) {
|
|
57519
|
+
return autoSpawnMarkerPath(repoRoot, null);
|
|
57520
|
+
}
|
|
57521
|
+
function legacyLocalRepoRootMarkerPath(repoRoot) {
|
|
57522
|
+
return import_path16.default.join(collabStateRoot(), "history-import", sha256Hex3(repoRoot), "history-imported.json");
|
|
57523
|
+
}
|
|
57524
|
+
function legacyAutoSpawnMarkerPath(repoRoot) {
|
|
57525
|
+
return import_path16.default.join(repoRoot, LEGACY_MARKER_REL_PATH);
|
|
57526
|
+
}
|
|
57527
|
+
function shouldAutoSpawnHistoryImport(repoRoot, repoFingerprint) {
|
|
57417
57528
|
try {
|
|
57418
|
-
return !(0, import_fs3.existsSync)(
|
|
57529
|
+
return !(0, import_fs3.existsSync)(autoSpawnMarkerPath(repoRoot, repoFingerprint)) && !(0, import_fs3.existsSync)(fallbackRepoRootMarkerPath(repoRoot)) && !(0, import_fs3.existsSync)(legacyLocalRepoRootMarkerPath(repoRoot)) && !(0, import_fs3.existsSync)(legacyAutoSpawnMarkerPath(repoRoot));
|
|
57419
57530
|
} catch {
|
|
57420
57531
|
return false;
|
|
57421
57532
|
}
|
|
@@ -57424,14 +57535,6 @@ function isAutoSpawnEligibleBindingMode(bindingMode) {
|
|
|
57424
57535
|
return bindingMode === "explicit_root";
|
|
57425
57536
|
}
|
|
57426
57537
|
function spawnHistoryImportDetached(repoRoot, options) {
|
|
57427
|
-
const remixDir = import_path16.default.join(repoRoot, ".remix");
|
|
57428
|
-
try {
|
|
57429
|
-
(0, import_fs3.mkdirSync)(remixDir, { recursive: true });
|
|
57430
|
-
} catch {
|
|
57431
|
-
}
|
|
57432
|
-
const logPath = import_path16.default.join(repoRoot, LOG_REL_PATH);
|
|
57433
|
-
const out = (0, import_fs3.openSync)(logPath, "a");
|
|
57434
|
-
const err = (0, import_fs3.openSync)(logPath, "a");
|
|
57435
57538
|
const child = (0, import_child_process.spawn)(
|
|
57436
57539
|
"remix",
|
|
57437
57540
|
[
|
|
@@ -57448,12 +57551,12 @@ function spawnHistoryImportDetached(repoRoot, options) {
|
|
|
57448
57551
|
],
|
|
57449
57552
|
{
|
|
57450
57553
|
detached: true,
|
|
57451
|
-
stdio:
|
|
57554
|
+
stdio: "ignore",
|
|
57452
57555
|
env: { ...process.env, REMIX_HISTORY_AUTO_SPAWN: "1" }
|
|
57453
57556
|
}
|
|
57454
57557
|
);
|
|
57455
57558
|
child.unref();
|
|
57456
|
-
return { pid: child.pid
|
|
57559
|
+
return { pid: child.pid };
|
|
57457
57560
|
}
|
|
57458
57561
|
function getAnnotations(access, options) {
|
|
57459
57562
|
if (access === "read") {
|
|
@@ -57508,6 +57611,24 @@ function buildErrorEnvelope(tool, requestId, error2) {
|
|
|
57508
57611
|
recommendedNextActions
|
|
57509
57612
|
};
|
|
57510
57613
|
}
|
|
57614
|
+
function buildOutputValidationErrorEnvelope(tool, requestId, error2) {
|
|
57615
|
+
return {
|
|
57616
|
+
schemaVersion: SCHEMA_VERSION,
|
|
57617
|
+
ok: false,
|
|
57618
|
+
tool,
|
|
57619
|
+
requestId: requestId ?? null,
|
|
57620
|
+
error: {
|
|
57621
|
+
code: ERROR_CODES.INTERNAL_ERROR,
|
|
57622
|
+
message: "Tool output failed validation against its declared MCP schema.",
|
|
57623
|
+
hint: error2.issues.map((issue2) => `${issue2.path.join(".") || "output"}: ${issue2.message}`).join("; "),
|
|
57624
|
+
retryable: false,
|
|
57625
|
+
category: "internal"
|
|
57626
|
+
},
|
|
57627
|
+
warnings: [],
|
|
57628
|
+
risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
|
|
57629
|
+
recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
|
|
57630
|
+
};
|
|
57631
|
+
}
|
|
57511
57632
|
function registerTool(server, context, params) {
|
|
57512
57633
|
const errorSchema = makeErrorSchema();
|
|
57513
57634
|
server.registerTool(
|
|
@@ -57526,7 +57647,20 @@ function registerTool(server, context, params) {
|
|
|
57526
57647
|
assertToolAccess(context.policy, params.access);
|
|
57527
57648
|
const result = await params.run(rawArgs);
|
|
57528
57649
|
const envelope = buildSuccessEnvelope(params.name, requestId, result);
|
|
57529
|
-
params.outputSchema.
|
|
57650
|
+
const parsedEnvelope = params.outputSchema.safeParse(envelope);
|
|
57651
|
+
if (!parsedEnvelope.success) {
|
|
57652
|
+
const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
|
|
57653
|
+
context.logger.log({
|
|
57654
|
+
level: "error",
|
|
57655
|
+
message: "tool_output_validation_failed",
|
|
57656
|
+
tool: params.name,
|
|
57657
|
+
requestId: errorEnvelope.requestId,
|
|
57658
|
+
durationMs: Date.now() - startedAt,
|
|
57659
|
+
result: "error",
|
|
57660
|
+
errorCode: errorEnvelope.error.code
|
|
57661
|
+
});
|
|
57662
|
+
return makeErrorResult(errorEnvelope);
|
|
57663
|
+
}
|
|
57530
57664
|
context.logger.log({
|
|
57531
57665
|
level: "info",
|
|
57532
57666
|
message: "tool_completed",
|
|
@@ -57590,12 +57724,14 @@ function registerCollabTools(server, context) {
|
|
|
57590
57724
|
try {
|
|
57591
57725
|
const repoRoot = result && typeof result === "object" && "data" in result && result.data && typeof result.data.repoRoot === "string" ? result.data.repoRoot : null;
|
|
57592
57726
|
const bindingMode = result && typeof result === "object" && "data" in result && result.data && typeof result.data.bindingMode === "string" ? result.data.bindingMode : null;
|
|
57593
|
-
|
|
57727
|
+
const resultData = result && typeof result === "object" && "data" in result && result.data && typeof result.data === "object" ? result.data : null;
|
|
57728
|
+
const repoFingerprint = typeof resultData?.repoFingerprint === "string" ? resultData.repoFingerprint : null;
|
|
57729
|
+
if (repoRoot && isAutoSpawnEligibleBindingMode(bindingMode) && shouldAutoSpawnHistoryImport(repoRoot, repoFingerprint)) {
|
|
57594
57730
|
const cutoffAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
57595
57731
|
const spawned = spawnHistoryImportDetached(repoRoot, { cutoffAt });
|
|
57596
57732
|
context.logger.log({
|
|
57597
57733
|
level: "info",
|
|
57598
|
-
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"}
|
|
57734
|
+
message: `history_import_auto_spawned pid=${spawned.pid ?? "?"} cutoffAt=${cutoffAt}`,
|
|
57599
57735
|
tool: "remix_collab_init",
|
|
57600
57736
|
repoRoot
|
|
57601
57737
|
});
|
|
@@ -59629,7 +59765,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
59629
59765
|
// package.json
|
|
59630
59766
|
var package_default = {
|
|
59631
59767
|
name: "@remixhq/claude-plugin",
|
|
59632
|
-
version: "0.1.
|
|
59768
|
+
version: "0.1.25",
|
|
59633
59769
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
59634
59770
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
59635
59771
|
license: "MIT",
|
|
@@ -59667,8 +59803,8 @@ var package_default = {
|
|
|
59667
59803
|
prepack: "npm run build"
|
|
59668
59804
|
},
|
|
59669
59805
|
dependencies: {
|
|
59670
|
-
"@remixhq/core": "^0.1.
|
|
59671
|
-
"@remixhq/mcp": "^0.1.
|
|
59806
|
+
"@remixhq/core": "^0.1.20",
|
|
59807
|
+
"@remixhq/mcp": "^0.1.20"
|
|
59672
59808
|
},
|
|
59673
59809
|
devDependencies: {
|
|
59674
59810
|
"@types/node": "^25.4.0",
|