@remixhq/claude-plugin 0.1.17 → 0.1.18

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "remix",
3
3
  "description": "Remix collaboration workflows for Claude Code",
4
- "version": "0.1.17",
4
+ "version": "0.1.18",
5
5
  "author": {
6
6
  "name": "Remix"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: remix-collab
3
- description: Specialized Claude agent for Remix repository collaboration, merge request review, sync, reconcile, and change-step recording workflows.
3
+ description: Specialized Claude agent for Remix repository collaboration, merge request review, sync, reconcile, and queued finalize-turn workflows.
4
4
  ---
5
5
 
6
6
  You are the Remix collaboration specialist.
@@ -32,19 +32,24 @@ Operating rules:
32
32
  9. Clearly explain local mutation risk before using tools that can modify the local repo.
33
33
  10. In a bound repo, Remix MCP tools are the required workflow layer for ordinary collaboration work.
34
34
  11. In a bound repo, exactly one final `remix_collab_finalize_turn` is required before the final user-facing response.
35
- 12. The final recording call must use the exact user prompt and your final assistant response.
36
- 13. Do not finish the turn before recording. Do not make additional repo mutations after the final turn-recording call unless you intend to record again.
37
- 14. Do not duplicate core business logic in reasoning. Use the MCP tools to inspect and execute the workflow.
35
+ 12. `remix_collab_finalize_turn` is queued only. A remote change step does not exist yet until the finalize queue drains successfully.
36
+ 13. The final recording call must use the exact user prompt and your final assistant response.
37
+ 14. If `remix_collab_status` reports `await_finalize`, use `remix_collab_drain_finalize_queue`, then re-check status before merge-related or recovery flows that depend on a remote recorded turn.
38
+ 15. Do not finish the turn before recording. Do not make additional repo mutations after the final turn-recording call unless you intend to record again.
39
+ 16. Do not duplicate core business logic in reasoning. Use the MCP tools to inspect and execute the workflow.
38
40
 
39
41
  When appropriate:
40
42
 
41
43
  - use `remix_collab_init` to bind the current repo
42
44
  - use `remix_collab_remix` to start from an existing app lineage
43
45
  - use `remix_collab_checkout` to continue work on an existing app id without creating a fork
46
+ - when the user asks for an app's dashboard URL and an `appId` is known, answer with `https://dashboard.remix.one/apps/<appId>` without requiring an additional tool call
44
47
  - when helping the user choose an app, prefer scoped or membership-oriented discovery first: use `organizationId` / `projectId` when known, or use `ownership` with `accessScope="explicit_member"` when the user means “apps I can work on”
45
48
  - reserve `accessScope="all_readable"` for explicit public or broad readable discovery, not as the default work-oriented app picker
46
49
  - use memory summary/search/timeline tools before repo inspection when historical context or reasoning is needed
47
50
  - use the explicit change-step diff tool only after you already know which `changeStepId` matters
48
51
  - use `remix_collab_finalize_turn` as the final turn recorder
52
+ - treat `remix_collab_finalize_turn` as local capture plus queueing, not immediate remote materialization
53
+ - use `remix_collab_drain_finalize_queue` and `remix_collab_status` when the workflow is blocked on `await_finalize`
49
54
  - use `remix_collab_review_queue` for reviewable merge requests, `remix_collab_my_merge_requests` for authored requests, and `remix_collab_list_app_merge_requests` for app-scoped MR flows with required `queue` set to `app_reviewable`, `app_outgoing`, or `app_related_visible`
50
55
  - use merge request tools for review and approval flows
@@ -685,6 +685,12 @@ function normalizeStringArray(value) {
685
685
  )
686
686
  );
687
687
  }
688
+ function normalizeManualRecordingScope(value) {
689
+ if (value === "full_turn") {
690
+ return "full_turn";
691
+ }
692
+ return null;
693
+ }
688
694
  function normalizeTouchedRepo(value, repoRoot) {
689
695
  if (!value || typeof value !== "object") return null;
690
696
  const parsed = value;
@@ -703,7 +709,7 @@ function normalizeTouchedRepo(value, repoRoot) {
703
709
  manuallyRecorded: Boolean(parsed.manuallyRecorded),
704
710
  manuallyRecordedAt: normalizeString(parsed.manuallyRecordedAt),
705
711
  manuallyRecordedByTool: normalizeString(parsed.manuallyRecordedByTool),
706
- manualRecordingScope: parsed.manualRecordingScope === "change_step" || parsed.manualRecordingScope === "full_turn" ? parsed.manualRecordingScope : null,
712
+ manualRecordingScope: normalizeManualRecordingScope(parsed.manualRecordingScope),
707
713
  manualRemoteChangeRecordedAt: normalizeString(parsed.manualRemoteChangeRecordedAt),
708
714
  stopAttempted: Boolean(parsed.stopAttempted),
709
715
  stopRecorded: Boolean(parsed.stopRecorded),
@@ -855,7 +861,7 @@ async function markPendingTurnConsultedMemory(sessionId) {
855
861
  // package.json
856
862
  var package_default = {
857
863
  name: "@remixhq/claude-plugin",
858
- version: "0.1.17",
864
+ version: "0.1.18",
859
865
  description: "Claude Code plugin for Remix collaboration workflows",
860
866
  homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
861
867
  license: "MIT",
@@ -886,8 +892,8 @@ var package_default = {
886
892
  prepack: "npm run build"
887
893
  },
888
894
  dependencies: {
889
- "@remixhq/core": "^0.1.12",
890
- "@remixhq/mcp": "^0.1.12"
895
+ "@remixhq/core": "^0.1.13",
896
+ "@remixhq/mcp": "^0.1.13"
891
897
  },
892
898
  devDependencies: {
893
899
  "@types/node": "^25.4.0",
@@ -7751,7 +7757,7 @@ var {
7751
7757
  getCancelSignal: getCancelSignal2
7752
7758
  } = getIpcExport();
7753
7759
 
7754
- // node_modules/@remixhq/core/dist/chunk-RREREIGW.js
7760
+ // node_modules/@remixhq/core/dist/chunk-WT6VRLXU.js
7755
7761
  async function runGit(args, cwd) {
7756
7762
  const res = await execa("git", args, { cwd, stderr: "ignore" });
7757
7763
  return String(res.stdout || "").trim();
@@ -7765,7 +7771,7 @@ async function getCurrentBranch(cwd) {
7765
7771
  }
7766
7772
  }
7767
7773
 
7768
- // node_modules/@remixhq/core/dist/chunk-IXWQWFYT.js
7774
+ // node_modules/@remixhq/core/dist/chunk-YCFLOHJV.js
7769
7775
  var import_promises14 = __toESM(require("fs/promises"), 1);
7770
7776
  var import_path = __toESM(require("path"), 1);
7771
7777
  var import_promises15 = __toESM(require("fs/promises"), 1);
@@ -8028,11 +8034,6 @@ function extractToolInput(payload) {
8028
8034
  function extractToolResponse(payload) {
8029
8035
  return getNestedRecord(payload.tool_response) ?? getNestedRecord(payload.toolResponse);
8030
8036
  }
8031
- function extractToolStructuredData(payload) {
8032
- const toolResponse = extractToolResponse(payload);
8033
- const structuredContent = getNestedRecord(toolResponse?.structuredContent) ?? getNestedRecord(payload.structuredContent);
8034
- return getNestedRecord(toolResponse?.data) ?? getNestedRecord(structuredContent?.data) ?? structuredContent;
8035
- }
8036
8037
  function extractToolName(payload) {
8037
8038
  return extractString(payload, ["tool_name", "toolName"]);
8038
8039
  }
@@ -8046,26 +8047,6 @@ function normalizeHookToolName(toolName) {
8046
8047
  }
8047
8048
  return trimmed;
8048
8049
  }
8049
- function extractAssistantResponse(payload) {
8050
- const candidateKeys = [
8051
- "last_assistant_message",
8052
- "lastAssistantMessage",
8053
- "assistant_response",
8054
- "assistantResponse",
8055
- "assistant_message",
8056
- "assistantMessage",
8057
- "response",
8058
- "message"
8059
- ];
8060
- return extractString(payload, candidateKeys) ?? extractString(extractToolResponse(payload) ?? {}, candidateKeys) ?? extractString(extractToolStructuredData(payload) ?? {}, candidateKeys) ?? extractString(extractToolInput(payload), candidateKeys);
8061
- }
8062
- function extractFinalizeTurnMode(payload) {
8063
- const mode = extractString(extractToolStructuredData(payload) ?? {}, ["mode"]) ?? extractString(extractToolResponse(payload) ?? {}, ["mode"]) ?? extractString(payload, ["mode"]);
8064
- if (mode === "changed_turn" || mode === "no_diff_turn") {
8065
- return mode;
8066
- }
8067
- return null;
8068
- }
8069
8050
  function extractString(input, keys) {
8070
8051
  for (const key of keys) {
8071
8052
  const value = input[key];
@@ -8117,9 +8098,6 @@ function didToolSucceed(payload) {
8117
8098
  const hookEventName = extractString(payload, ["hook_event_name", "hookEventName"]);
8118
8099
  return hookEventName === "PostToolUse";
8119
8100
  }
8120
- function isRemoteChangeRecordedButLocalSyncFailed(payload) {
8121
- return extractToolErrorMessage(payload) === "Change step succeeded remotely, but automatic local sync failed.";
8122
- }
8123
8101
  function collectStringPathValue(value) {
8124
8102
  if (typeof value === "string" && value.trim()) return [value.trim()];
8125
8103
  if (Array.isArray(value)) {
@@ -8184,7 +8162,7 @@ async function resolveBoundRepoFromToolCwd(payload) {
8184
8162
 
8185
8163
  // src/hook-post-collab.ts
8186
8164
  function isRepoMutationToolName(toolName) {
8187
- return /remix_collab_(add|add_change_step|sync_apply|approve_and_sync_target|sync_upstream|reconcile_apply)$/i.test(toolName);
8165
+ return /remix_collab_(sync_apply|approve_and_sync_target|sync_upstream|reconcile_apply)$/i.test(toolName);
8188
8166
  }
8189
8167
  function isMemoryToolName(toolName) {
8190
8168
  return /remix_collab_memory_(summary|search|timeline|change_step_diff)$/i.test(toolName);
@@ -8198,31 +8176,12 @@ function isStructuredLocalReadToolName(toolName) {
8198
8176
  function isShellToolName(toolName) {
8199
8177
  return /^Bash$/i.test(toolName);
8200
8178
  }
8201
- function isRemoteChangeRecordingToolName(toolName) {
8202
- return /remix_collab_(add|add_change_step)$/i.test(toolName);
8203
- }
8204
- function hasManualFullTurnPayload(payload) {
8205
- const toolInput = extractToolInput(payload);
8206
- return Boolean(extractString(toolInput, ["prompt"]) && extractAssistantResponse(payload));
8207
- }
8208
- function getManualRecordingScope(payload, toolName) {
8179
+ function getManualRecordingScope(toolName) {
8209
8180
  if (/remix_collab_finalize_turn$/i.test(toolName)) {
8210
8181
  return "full_turn";
8211
8182
  }
8212
- if (/remix_collab_(add|add_change_step)$/i.test(toolName)) {
8213
- return hasManualFullTurnPayload(payload) ? "full_turn" : "change_step";
8214
- }
8215
- if (/remix_collab_(record_turn|record_no_diff_turn)$/i.test(toolName)) {
8216
- return "full_turn";
8217
- }
8218
8183
  return null;
8219
8184
  }
8220
- function didFinalizeTurnRecordRemoteChange(payload, toolName) {
8221
- if (!/remix_collab_finalize_turn$/i.test(toolName)) {
8222
- return false;
8223
- }
8224
- return extractFinalizeTurnMode(payload) === "changed_turn";
8225
- }
8226
8185
  function isLikelyMutatingShellCommand(command) {
8227
8186
  const normalized = command.trim().toLowerCase();
8228
8187
  if (!normalized) return false;
@@ -8288,7 +8247,6 @@ async function runHookPostCollab(payload) {
8288
8247
  return;
8289
8248
  }
8290
8249
  const toolSucceeded = didToolSucceed(payload);
8291
- const remoteChangeRecordedButSyncFailed = (isRemoteChangeRecordingToolName(toolName) || /remix_collab_finalize_turn$/i.test(toolName)) && isRemoteChangeRecordedButLocalSyncFailed(payload);
8292
8250
  await appendHookDiagnosticsEvent({
8293
8251
  hook: "PostToolUse",
8294
8252
  sessionId,
@@ -8297,7 +8255,6 @@ async function runHookPostCollab(payload) {
8297
8255
  toolName,
8298
8256
  fields: {
8299
8257
  toolSucceeded,
8300
- remoteChangeRecordedButSyncFailed,
8301
8258
  isMemoryTool: isMemoryToolName(toolName),
8302
8259
  isRepoMutationTool: isRepoMutationToolName(toolName),
8303
8260
  isShellTool: isShellToolName(toolName),
@@ -8305,7 +8262,7 @@ async function runHookPostCollab(payload) {
8305
8262
  isStructuredLocalReadTool: isStructuredLocalReadToolName(toolName)
8306
8263
  }
8307
8264
  });
8308
- if (!toolSucceeded && !remoteChangeRecordedButSyncFailed) {
8265
+ if (!toolSucceeded) {
8309
8266
  await appendHookDiagnosticsEvent({
8310
8267
  hook: "PostToolUse",
8311
8268
  sessionId,
@@ -8326,7 +8283,7 @@ async function runHookPostCollab(payload) {
8326
8283
  toolName
8327
8284
  });
8328
8285
  }
8329
- const manualRecordingScope = getManualRecordingScope(payload, toolName);
8286
+ const manualRecordingScope = getManualRecordingScope(toolName);
8330
8287
  if (isRepoMutationToolName(toolName) || manualRecordingScope) {
8331
8288
  const targetRepo = await resolveBoundRepoFromToolCwd(payload);
8332
8289
  if (targetRepo) {
@@ -8345,7 +8302,7 @@ async function runHookPostCollab(payload) {
8345
8302
  await markTouchedRepoManuallyRecorded(sessionId, targetRepo.repoRoot, {
8346
8303
  toolName,
8347
8304
  scope: manualRecordingScope,
8348
- remoteChangeRecorded: toolSucceeded ? isRemoteChangeRecordingToolName(toolName) || didFinalizeTurnRecordRemoteChange(payload, toolName) : remoteChangeRecordedButSyncFailed
8305
+ remoteChangeRecorded: false
8349
8306
  });
8350
8307
  }
8351
8308
  await appendHookDiagnosticsEvent({
@@ -8357,8 +8314,7 @@ async function runHookPostCollab(payload) {
8357
8314
  repoRoot: targetRepo.repoRoot,
8358
8315
  fields: {
8359
8316
  hasObservedWrite: isRepoMutationToolName(toolName),
8360
- manualRecordingScope,
8361
- remoteChangeRecordedButSyncFailed
8317
+ manualRecordingScope
8362
8318
  }
8363
8319
  });
8364
8320
  } else {