@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/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.23",
6
+ version: "0.1.24",
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.18",
45
- "@remixhq/mcp": "^0.1.18"
44
+ "@remixhq/core": "^0.1.19",
45
+ "@remixhq/mcp": "^0.1.19"
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.23\",\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.18\",\n \"@remixhq/mcp\": \"^0.1.18\"\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":[]}
1
+ {"version":3,"sources":["../package.json","../src/metadata.ts"],"sourcesContent":["{\n \"name\": \"@remixhq/claude-plugin\",\n \"version\": \"0.1.24\",\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.19\",\n \"@remixhq/mcp\": \"^0.1.19\"\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":[]}
@@ -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: state.explicitRootBinding?.projectId ?? (requireRemoteLane ? void 0 : localBinding.projectId ?? state.projectId ?? void 0),
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
- const nextServerHeadHash = typeof changeStep.headCommitHash === "string" ? changeStep.headCommitHash.trim() : "";
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: snapshot.id,
24770
- lastSnapshotHash: snapshot.snapshotHash,
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: snapshot.localCommitHash
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") {
@@ -35127,7 +35194,7 @@ var EMPTY_COMPLETION_RESULT = {
35127
35194
  }
35128
35195
  };
35129
35196
 
35130
- // node_modules/@remixhq/core/dist/chunk-RCNOSZP6.js
35197
+ // node_modules/@remixhq/core/dist/chunk-C2FOZ3O7.js
35131
35198
  async function readJsonSafe(res) {
35132
35199
  const ct = res.headers.get("content-type") ?? "";
35133
35200
  if (!ct.toLowerCase().includes("application/json")) return null;
@@ -35321,6 +35388,14 @@ function createApiClient(config2, opts) {
35321
35388
  method: "POST",
35322
35389
  body: JSON.stringify(payload)
35323
35390
  }),
35391
+ listChangeSteps: (appId, params) => {
35392
+ const qs = new URLSearchParams();
35393
+ if (params?.limit !== void 0) qs.set("limit", String(params.limit));
35394
+ if (params?.offset !== void 0) qs.set("offset", String(params.offset));
35395
+ if (params?.idempotencyKey) qs.set("idempotencyKey", params.idempotencyKey);
35396
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
35397
+ return request(`/v1/apps/${encodeURIComponent(appId)}/change-steps${suffix}`, { method: "GET" });
35398
+ },
35324
35399
  createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
35325
35400
  method: "POST",
35326
35401
  body: JSON.stringify(payload)
@@ -55997,6 +56072,15 @@ function normalizeByMessage(err) {
55997
56072
  category: "remote_state"
55998
56073
  });
55999
56074
  }
56075
+ if (statusCode === 409) {
56076
+ return makeNormalized({
56077
+ code: ERROR_CODES.REMOTE_ERROR,
56078
+ message,
56079
+ hint,
56080
+ retryable: true,
56081
+ category: "remote_state"
56082
+ });
56083
+ }
56000
56084
  if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
56001
56085
  return makeNormalized({
56002
56086
  code: ERROR_CODES.REMOTE_ERROR,
@@ -56160,7 +56244,6 @@ function makeSuccessResult2(envelope) {
56160
56244
  function makeErrorResult(envelope) {
56161
56245
  return {
56162
56246
  content: [{ type: "text", text: toJsonText(envelope) }],
56163
- structuredContent: envelope,
56164
56247
  isError: true
56165
56248
  };
56166
56249
  }
@@ -57508,6 +57591,24 @@ function buildErrorEnvelope(tool, requestId, error2) {
57508
57591
  recommendedNextActions
57509
57592
  };
57510
57593
  }
57594
+ function buildOutputValidationErrorEnvelope(tool, requestId, error2) {
57595
+ return {
57596
+ schemaVersion: SCHEMA_VERSION,
57597
+ ok: false,
57598
+ tool,
57599
+ requestId: requestId ?? null,
57600
+ error: {
57601
+ code: ERROR_CODES.INTERNAL_ERROR,
57602
+ message: "Tool output failed validation against its declared MCP schema.",
57603
+ hint: error2.issues.map((issue2) => `${issue2.path.join(".") || "output"}: ${issue2.message}`).join("; "),
57604
+ retryable: false,
57605
+ category: "internal"
57606
+ },
57607
+ warnings: [],
57608
+ risks: ["The MCP server returned an output shape that did not match the tool descriptor."],
57609
+ recommendedNextActions: ["Report this MCP schema mismatch with the tool name and error hint."]
57610
+ };
57611
+ }
57511
57612
  function registerTool(server, context, params) {
57512
57613
  const errorSchema = makeErrorSchema();
57513
57614
  server.registerTool(
@@ -57526,7 +57627,20 @@ function registerTool(server, context, params) {
57526
57627
  assertToolAccess(context.policy, params.access);
57527
57628
  const result = await params.run(rawArgs);
57528
57629
  const envelope = buildSuccessEnvelope(params.name, requestId, result);
57529
- params.outputSchema.parse(envelope);
57630
+ const parsedEnvelope = params.outputSchema.safeParse(envelope);
57631
+ if (!parsedEnvelope.success) {
57632
+ const errorEnvelope = buildOutputValidationErrorEnvelope(params.name, requestId, parsedEnvelope.error);
57633
+ context.logger.log({
57634
+ level: "error",
57635
+ message: "tool_output_validation_failed",
57636
+ tool: params.name,
57637
+ requestId: errorEnvelope.requestId,
57638
+ durationMs: Date.now() - startedAt,
57639
+ result: "error",
57640
+ errorCode: errorEnvelope.error.code
57641
+ });
57642
+ return makeErrorResult(errorEnvelope);
57643
+ }
57530
57644
  context.logger.log({
57531
57645
  level: "info",
57532
57646
  message: "tool_completed",
@@ -59629,7 +59743,7 @@ async function listPendingTurnStateSummaries() {
59629
59743
  // package.json
59630
59744
  var package_default = {
59631
59745
  name: "@remixhq/claude-plugin",
59632
- version: "0.1.23",
59746
+ version: "0.1.24",
59633
59747
  description: "Claude Code plugin for Remix collaboration workflows",
59634
59748
  homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
59635
59749
  license: "MIT",
@@ -59667,8 +59781,8 @@ var package_default = {
59667
59781
  prepack: "npm run build"
59668
59782
  },
59669
59783
  dependencies: {
59670
- "@remixhq/core": "^0.1.18",
59671
- "@remixhq/mcp": "^0.1.18"
59784
+ "@remixhq/core": "^0.1.19",
59785
+ "@remixhq/mcp": "^0.1.19"
59672
59786
  },
59673
59787
  devDependencies: {
59674
59788
  "@types/node": "^25.4.0",