@remixhq/claude-plugin 0.1.12 → 0.1.15
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/agents/remix-collab.md +7 -6
- package/dist/hook-post-collab.cjs +49 -11
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-pre-git.cjs +1 -1
- package/dist/hook-pre-git.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +139 -29
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +37 -9
- 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 +2118 -239
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/access-troubleshooting/SKILL.md +35 -0
- package/skills/app-ops-triage/SKILL.md +32 -0
- package/skills/historical-memory-routing/SKILL.md +2 -0
- package/skills/identity-and-scope-routing/SKILL.md +35 -0
- package/skills/init-or-remix/SKILL.md +9 -4
- package/skills/review-merge-request/SKILL.md +1 -1
- package/skills/safe-collab-workflow/SKILL.md +15 -21
- package/skills/submit-change-step/SKILL.md +11 -19
- package/skills/sync-and-reconcile/SKILL.md +3 -1
package/dist/mcp-server.cjs
CHANGED
|
@@ -21513,7 +21513,7 @@ var RemixError = class extends Error {
|
|
|
21513
21513
|
}
|
|
21514
21514
|
};
|
|
21515
21515
|
|
|
21516
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
21516
|
+
// node_modules/@remixhq/core/dist/chunk-B5S3PUIR.js
|
|
21517
21517
|
async function readJsonSafe(res) {
|
|
21518
21518
|
const ct = res.headers.get("content-type") ?? "";
|
|
21519
21519
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -21627,11 +21627,33 @@ function createApiClient(config2, opts) {
|
|
|
21627
21627
|
const qs = new URLSearchParams();
|
|
21628
21628
|
if (params?.projectId) qs.set("projectId", params.projectId);
|
|
21629
21629
|
if (params?.organizationId) qs.set("organizationId", params.organizationId);
|
|
21630
|
+
if (params?.ownership) qs.set("ownership", params.ownership);
|
|
21631
|
+
if (params?.accessScope) qs.set("accessScope", params.accessScope);
|
|
21632
|
+
if (params?.createdBy) qs.set("createdBy", params.createdBy);
|
|
21630
21633
|
if (params?.forked) qs.set("forked", params.forked);
|
|
21634
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21635
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21631
21636
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21632
21637
|
return request(`/v1/apps${suffix}`, { method: "GET" });
|
|
21633
21638
|
},
|
|
21634
21639
|
getApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}`, { method: "GET" }),
|
|
21640
|
+
getAppContext: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/context`, { method: "GET" }),
|
|
21641
|
+
getAppOverview: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/overview`, { method: "GET" }),
|
|
21642
|
+
listAppTimeline: (appId, params) => {
|
|
21643
|
+
const qs = new URLSearchParams();
|
|
21644
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21645
|
+
if (params?.cursor) qs.set("cursor", params.cursor);
|
|
21646
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21647
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/timeline${suffix}`, { method: "GET" });
|
|
21648
|
+
},
|
|
21649
|
+
getAppTimelineEvent: (appId, eventId) => request(`/v1/apps/${encodeURIComponent(appId)}/timeline/${encodeURIComponent(eventId)}`, { method: "GET" }),
|
|
21650
|
+
listAppEditQueue: (appId, params) => {
|
|
21651
|
+
const qs = new URLSearchParams();
|
|
21652
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21653
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21654
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21655
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/edit-queue${suffix}`, { method: "GET" });
|
|
21656
|
+
},
|
|
21635
21657
|
getMergeRequest: (mrId) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}`, { method: "GET" }),
|
|
21636
21658
|
presignImportUpload: (payload) => request("/v1/apps/import/upload/presign", { method: "POST", body: JSON.stringify(payload) }),
|
|
21637
21659
|
importFromUpload: (payload) => request("/v1/apps/import/upload", { method: "POST", body: JSON.stringify(payload) }),
|
|
@@ -21713,6 +21735,8 @@ function createApiClient(config2, opts) {
|
|
|
21713
21735
|
qs.set("status", params.status);
|
|
21714
21736
|
}
|
|
21715
21737
|
if (params?.kind) qs.set("kind", params.kind);
|
|
21738
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21739
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21716
21740
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21717
21741
|
return request(`/v1/merge-requests${suffix}`, { method: "GET" });
|
|
21718
21742
|
},
|
|
@@ -21731,24 +21755,60 @@ function createApiClient(config2, opts) {
|
|
|
21731
21755
|
method: "POST",
|
|
21732
21756
|
body: JSON.stringify(payload)
|
|
21733
21757
|
}),
|
|
21734
|
-
listOrganizationMembers: (orgId) =>
|
|
21758
|
+
listOrganizationMembers: (orgId, params) => {
|
|
21759
|
+
const qs = new URLSearchParams();
|
|
21760
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21761
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21762
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21763
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/members${suffix}`, { method: "GET" });
|
|
21764
|
+
},
|
|
21735
21765
|
updateOrganizationMember: (orgId, userId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/members/${encodeURIComponent(userId)}`, {
|
|
21736
21766
|
method: "PATCH",
|
|
21737
21767
|
body: JSON.stringify(payload)
|
|
21738
21768
|
}),
|
|
21739
|
-
listProjectMembers: (projectId) =>
|
|
21769
|
+
listProjectMembers: (projectId, params) => {
|
|
21770
|
+
const qs = new URLSearchParams();
|
|
21771
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21772
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21773
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21774
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/members${suffix}`, { method: "GET" });
|
|
21775
|
+
},
|
|
21740
21776
|
updateProjectMember: (projectId, userId, payload) => request(`/v1/projects/${encodeURIComponent(projectId)}/members/${encodeURIComponent(userId)}`, {
|
|
21741
21777
|
method: "PATCH",
|
|
21742
21778
|
body: JSON.stringify(payload)
|
|
21743
21779
|
}),
|
|
21744
|
-
listAppMembers: (appId) =>
|
|
21780
|
+
listAppMembers: (appId, params) => {
|
|
21781
|
+
const qs = new URLSearchParams();
|
|
21782
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21783
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21784
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21785
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/members${suffix}`, { method: "GET" });
|
|
21786
|
+
},
|
|
21745
21787
|
updateAppMember: (appId, userId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/members/${encodeURIComponent(userId)}`, {
|
|
21746
21788
|
method: "PATCH",
|
|
21747
21789
|
body: JSON.stringify(payload)
|
|
21748
21790
|
}),
|
|
21749
|
-
listOrganizationInvites: (orgId) =>
|
|
21750
|
-
|
|
21751
|
-
|
|
21791
|
+
listOrganizationInvites: (orgId, params) => {
|
|
21792
|
+
const qs = new URLSearchParams();
|
|
21793
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21794
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21795
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21796
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations${suffix}`, { method: "GET" });
|
|
21797
|
+
},
|
|
21798
|
+
listProjectInvites: (projectId, params) => {
|
|
21799
|
+
const qs = new URLSearchParams();
|
|
21800
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21801
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21802
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21803
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/invitations${suffix}`, { method: "GET" });
|
|
21804
|
+
},
|
|
21805
|
+
listAppInvites: (appId, params) => {
|
|
21806
|
+
const qs = new URLSearchParams();
|
|
21807
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21808
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21809
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21810
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/invitations${suffix}`, { method: "GET" });
|
|
21811
|
+
},
|
|
21752
21812
|
resendOrganizationInvite: (orgId, inviteId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
|
|
21753
21813
|
method: "POST",
|
|
21754
21814
|
body: JSON.stringify(payload ?? {})
|
|
@@ -21770,6 +21830,7 @@ function createApiClient(config2, opts) {
|
|
|
21770
21830
|
revokeAppInvite: (appId, inviteId) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations/${encodeURIComponent(inviteId)}`, {
|
|
21771
21831
|
method: "DELETE"
|
|
21772
21832
|
}),
|
|
21833
|
+
acceptInvitation: (payload) => request("/v1/invitations/accept", { method: "POST", body: JSON.stringify(payload) }),
|
|
21773
21834
|
syncUpstreamApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sync-upstream`, {
|
|
21774
21835
|
method: "POST",
|
|
21775
21836
|
body: JSON.stringify({})
|
|
@@ -21805,7 +21866,31 @@ function createApiClient(config2, opts) {
|
|
|
21805
21866
|
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download?${qs.toString()}`,
|
|
21806
21867
|
{ method: "GET" }
|
|
21807
21868
|
);
|
|
21808
|
-
}
|
|
21869
|
+
},
|
|
21870
|
+
listAgentRuns: (appId, params) => {
|
|
21871
|
+
const qs = new URLSearchParams();
|
|
21872
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21873
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21874
|
+
if (params?.status) qs.set("status", params.status);
|
|
21875
|
+
if (params?.currentPhase) qs.set("currentPhase", params.currentPhase);
|
|
21876
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21877
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21878
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21879
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs${suffix}`, { method: "GET" });
|
|
21880
|
+
},
|
|
21881
|
+
getAgentRun: (appId, runId) => request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}`, { method: "GET" }),
|
|
21882
|
+
listAgentRunEvents: (appId, runId, params) => {
|
|
21883
|
+
const qs = new URLSearchParams();
|
|
21884
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21885
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21886
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21887
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21888
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21889
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}/events${suffix}`, {
|
|
21890
|
+
method: "GET"
|
|
21891
|
+
});
|
|
21892
|
+
},
|
|
21893
|
+
getSandboxStatus: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sandbox/status`, { method: "GET" })
|
|
21809
21894
|
};
|
|
21810
21895
|
}
|
|
21811
21896
|
|
|
@@ -41707,7 +41792,7 @@ var REMIX_ERROR_CODES = {
|
|
|
41707
41792
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
41708
41793
|
var import_path11 = __toESM(require("path"), 1);
|
|
41709
41794
|
|
|
41710
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41795
|
+
// node_modules/@remixhq/core/dist/chunk-GEHSFPCD.js
|
|
41711
41796
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
41712
41797
|
var import_path2 = __toESM(require("path"), 1);
|
|
41713
41798
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
@@ -41785,7 +41870,7 @@ async function writeCollabBinding(repoRoot, binding) {
|
|
|
41785
41870
|
return filePath;
|
|
41786
41871
|
}
|
|
41787
41872
|
|
|
41788
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41873
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
41789
41874
|
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
41790
41875
|
var import_crypto = require("crypto");
|
|
41791
41876
|
var import_os2 = __toESM(require("os"), 1);
|
|
@@ -48566,7 +48651,7 @@ var {
|
|
|
48566
48651
|
getCancelSignal: getCancelSignal2
|
|
48567
48652
|
} = getIpcExport();
|
|
48568
48653
|
|
|
48569
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
48654
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
48570
48655
|
var GIT_REMOTE_PROTOCOL_RE = /^(https?|ssh):\/\//i;
|
|
48571
48656
|
var SCP_LIKE_GIT_REMOTE_RE = /^(?<user>[^@\s]+)@(?<host>[^:\s]+):(?<path>[^\\\s]+)$/;
|
|
48572
48657
|
var CANONICAL_GIT_REMOTE_RE = /^(?<host>(?:localhost|[a-z0-9.-]+))\/(?<path>[^\\\s]+)$/i;
|
|
@@ -48813,6 +48898,13 @@ async function listUntrackedFiles(cwd) {
|
|
|
48813
48898
|
return [];
|
|
48814
48899
|
}
|
|
48815
48900
|
}
|
|
48901
|
+
async function getWorkspaceDiff(cwd) {
|
|
48902
|
+
const snapshot = await getWorkspaceSnapshot(cwd);
|
|
48903
|
+
return {
|
|
48904
|
+
diff: snapshot.diff,
|
|
48905
|
+
includedUntrackedPaths: snapshot.includedUntrackedPaths
|
|
48906
|
+
};
|
|
48907
|
+
}
|
|
48816
48908
|
async function getWorkspaceSnapshot(cwd) {
|
|
48817
48909
|
const headCommitHash = await getHeadCommitHash(cwd);
|
|
48818
48910
|
if (!headCommitHash) {
|
|
@@ -49252,6 +49344,26 @@ function unwrapResponseObject(resp, label) {
|
|
|
49252
49344
|
}
|
|
49253
49345
|
return obj;
|
|
49254
49346
|
}
|
|
49347
|
+
var DEFAULT_PAGINATION_LIMIT = 25;
|
|
49348
|
+
var MAX_PAGINATION_LIMIT = 50;
|
|
49349
|
+
function normalizePagination(params) {
|
|
49350
|
+
const rawLimit = typeof params?.limit === "number" && Number.isFinite(params.limit) ? Math.trunc(params.limit) : DEFAULT_PAGINATION_LIMIT;
|
|
49351
|
+
const rawOffset = typeof params?.offset === "number" && Number.isFinite(params.offset) ? Math.trunc(params.offset) : 0;
|
|
49352
|
+
return {
|
|
49353
|
+
limit: Math.max(1, Math.min(MAX_PAGINATION_LIMIT, rawLimit)),
|
|
49354
|
+
offset: Math.max(0, rawOffset)
|
|
49355
|
+
};
|
|
49356
|
+
}
|
|
49357
|
+
function paginateOverfetchedItems(items, params) {
|
|
49358
|
+
const pagination = normalizePagination(params);
|
|
49359
|
+
return {
|
|
49360
|
+
items: items.slice(0, pagination.limit),
|
|
49361
|
+
pagination: {
|
|
49362
|
+
...pagination,
|
|
49363
|
+
hasMore: items.length > pagination.limit
|
|
49364
|
+
}
|
|
49365
|
+
};
|
|
49366
|
+
}
|
|
49255
49367
|
function unwrapMergeRequest(resp) {
|
|
49256
49368
|
return unwrapResponseObject(resp, "merge request");
|
|
49257
49369
|
}
|
|
@@ -50201,6 +50313,7 @@ async function collabAdd(params) {
|
|
|
50201
50313
|
}
|
|
50202
50314
|
const { backupPath } = await writeTempUnifiedDiffBackup(diff, "remix-add");
|
|
50203
50315
|
try {
|
|
50316
|
+
await pollAppReady(params.api, binding.currentAppId);
|
|
50204
50317
|
if (submissionSnapshot) {
|
|
50205
50318
|
await assertRepoSnapshotUnchanged(repoRoot, submissionSnapshot, {
|
|
50206
50319
|
operation: "`remix collab add` auto-sync",
|
|
@@ -50345,6 +50458,105 @@ async function collabRecordTurn(params) {
|
|
|
50345
50458
|
});
|
|
50346
50459
|
return unwrapResponseObject(resp, "collab turn");
|
|
50347
50460
|
}
|
|
50461
|
+
function collectWarnings(value) {
|
|
50462
|
+
if (!Array.isArray(value)) return [];
|
|
50463
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
50464
|
+
}
|
|
50465
|
+
async function collabFinalizeTurn(params) {
|
|
50466
|
+
const repoRoot = await findGitRoot(params.cwd);
|
|
50467
|
+
const binding = await readCollabBinding(repoRoot);
|
|
50468
|
+
if (!binding) {
|
|
50469
|
+
throw new RemixError("Repository is not bound to Remix.", {
|
|
50470
|
+
exitCode: 2,
|
|
50471
|
+
hint: "Run `remix collab init` first."
|
|
50472
|
+
});
|
|
50473
|
+
}
|
|
50474
|
+
const prompt = params.prompt.trim();
|
|
50475
|
+
const assistantResponse = params.assistantResponse.trim();
|
|
50476
|
+
if (!prompt) throw new RemixError("Prompt is required.", { exitCode: 2 });
|
|
50477
|
+
if (!assistantResponse) throw new RemixError("Assistant response is required.", { exitCode: 2 });
|
|
50478
|
+
const diffSource = params.diffSource ?? (params.diff ? "external" : "worktree");
|
|
50479
|
+
const externalDiff = params.diff?.trim() ?? "";
|
|
50480
|
+
const workspaceDiff = diffSource === "worktree" ? await getWorkspaceDiff(repoRoot) : null;
|
|
50481
|
+
const hasChangedTurn = diffSource === "external" ? externalDiff.length > 0 : Boolean(workspaceDiff?.diff.trim());
|
|
50482
|
+
const currentHeadCommitHash = await getHeadCommitHash(repoRoot);
|
|
50483
|
+
const idempotencyKey = params.idempotencyKey?.trim() || buildDeterministicIdempotencyKey({
|
|
50484
|
+
kind: "collab_finalize_turn_v1",
|
|
50485
|
+
appId: binding.currentAppId,
|
|
50486
|
+
upstreamAppId: binding.upstreamAppId,
|
|
50487
|
+
headCommitHash: currentHeadCommitHash,
|
|
50488
|
+
modeHint: hasChangedTurn ? "changed_turn" : "no_diff_turn",
|
|
50489
|
+
prompt,
|
|
50490
|
+
assistantResponse,
|
|
50491
|
+
externalDiff: diffSource === "external" ? externalDiff : null
|
|
50492
|
+
});
|
|
50493
|
+
if (diffSource === "external" && !hasChangedTurn) {
|
|
50494
|
+
throw new RemixError("External diff is empty.", {
|
|
50495
|
+
exitCode: 2,
|
|
50496
|
+
hint: "Pass a non-empty diff when using external diff submission, or omit the external diff so finalize-turn can inspect the live worktree."
|
|
50497
|
+
});
|
|
50498
|
+
}
|
|
50499
|
+
if (hasChangedTurn) {
|
|
50500
|
+
const localHeadBefore = currentHeadCommitHash;
|
|
50501
|
+
const capturedUntrackedPathsCandidate = diffSource === "worktree" ? await listUntrackedFiles(repoRoot) : [];
|
|
50502
|
+
const changeStep = await collabAdd({
|
|
50503
|
+
api: params.api,
|
|
50504
|
+
cwd: repoRoot,
|
|
50505
|
+
prompt,
|
|
50506
|
+
assistantResponse,
|
|
50507
|
+
diff: diffSource === "external" ? externalDiff : null,
|
|
50508
|
+
diffSource,
|
|
50509
|
+
sync: params.sync,
|
|
50510
|
+
allowBranchMismatch: params.allowBranchMismatch,
|
|
50511
|
+
idempotencyKey,
|
|
50512
|
+
actor: params.actor
|
|
50513
|
+
});
|
|
50514
|
+
const localHeadAfter = await getHeadCommitHash(repoRoot);
|
|
50515
|
+
const warnings = [
|
|
50516
|
+
...collectWarnings(changeStep.warnings),
|
|
50517
|
+
...diffSource === "external" && params.sync !== false ? [
|
|
50518
|
+
"Automatic local discard+sync was skipped because the diff came from an external source and may not match the current worktree."
|
|
50519
|
+
] : []
|
|
50520
|
+
];
|
|
50521
|
+
const autoSyncRequested = params.sync !== false;
|
|
50522
|
+
const autoSyncEligible = diffSource === "worktree";
|
|
50523
|
+
return {
|
|
50524
|
+
mode: "changed_turn",
|
|
50525
|
+
idempotencyKey,
|
|
50526
|
+
changeStep,
|
|
50527
|
+
collabTurn: null,
|
|
50528
|
+
autoSync: {
|
|
50529
|
+
requested: autoSyncRequested,
|
|
50530
|
+
eligible: autoSyncEligible,
|
|
50531
|
+
attempted: autoSyncRequested && autoSyncEligible,
|
|
50532
|
+
applied: autoSyncRequested && autoSyncEligible,
|
|
50533
|
+
trackedChangesDiscarded: autoSyncRequested && autoSyncEligible,
|
|
50534
|
+
capturedUntrackedPathsCandidate,
|
|
50535
|
+
localHeadBefore,
|
|
50536
|
+
localHeadAfter,
|
|
50537
|
+
localRepoMutated: autoSyncRequested && autoSyncEligible && localHeadBefore !== localHeadAfter
|
|
50538
|
+
},
|
|
50539
|
+
warnings
|
|
50540
|
+
};
|
|
50541
|
+
}
|
|
50542
|
+
const collabTurn = await collabRecordTurn({
|
|
50543
|
+
api: params.api,
|
|
50544
|
+
cwd: repoRoot,
|
|
50545
|
+
prompt,
|
|
50546
|
+
assistantResponse,
|
|
50547
|
+
allowBranchMismatch: params.allowBranchMismatch,
|
|
50548
|
+
idempotencyKey,
|
|
50549
|
+
actor: params.actor
|
|
50550
|
+
});
|
|
50551
|
+
return {
|
|
50552
|
+
mode: "no_diff_turn",
|
|
50553
|
+
idempotencyKey,
|
|
50554
|
+
changeStep: null,
|
|
50555
|
+
collabTurn,
|
|
50556
|
+
autoSync: null,
|
|
50557
|
+
warnings: []
|
|
50558
|
+
};
|
|
50559
|
+
}
|
|
50348
50560
|
async function collabApprove(params) {
|
|
50349
50561
|
if (params.mode === "sync-target-repo") {
|
|
50350
50562
|
if (!params.cwd?.trim()) {
|
|
@@ -50602,17 +50814,22 @@ async function collabListMergeRequests(params) {
|
|
|
50602
50814
|
appId: params.appId,
|
|
50603
50815
|
queue: params.queue
|
|
50604
50816
|
});
|
|
50817
|
+
const pageRequest = normalizePagination(params);
|
|
50605
50818
|
const resp = await params.api.listMergeRequests({
|
|
50606
50819
|
queue: params.queue,
|
|
50607
50820
|
appId,
|
|
50608
50821
|
status: params.status,
|
|
50609
|
-
kind: params.kind ?? "merge"
|
|
50822
|
+
kind: params.kind ?? "merge",
|
|
50823
|
+
limit: pageRequest.limit + 1,
|
|
50824
|
+
offset: pageRequest.offset
|
|
50610
50825
|
});
|
|
50611
50826
|
const mergeRequests = unwrapResponseObject(resp, "merge requests");
|
|
50827
|
+
const page = paginateOverfetchedItems(mergeRequests, params);
|
|
50612
50828
|
return {
|
|
50613
50829
|
queue: params.queue,
|
|
50614
50830
|
appId: appId ?? null,
|
|
50615
|
-
mergeRequests
|
|
50831
|
+
mergeRequests: page.items,
|
|
50832
|
+
pagination: page.pagination
|
|
50616
50833
|
};
|
|
50617
50834
|
}
|
|
50618
50835
|
async function resolveScopeTarget(params) {
|
|
@@ -50651,12 +50868,24 @@ async function collabListMembers(params) {
|
|
|
50651
50868
|
scope: params.scope,
|
|
50652
50869
|
targetId: params.targetId
|
|
50653
50870
|
});
|
|
50654
|
-
const
|
|
50871
|
+
const pageRequest = normalizePagination(params);
|
|
50872
|
+
const resp = params.scope === "organization" ? await params.api.listOrganizationMembers(targetId, {
|
|
50873
|
+
limit: pageRequest.limit + 1,
|
|
50874
|
+
offset: pageRequest.offset
|
|
50875
|
+
}) : params.scope === "project" ? await params.api.listProjectMembers(targetId, {
|
|
50876
|
+
limit: pageRequest.limit + 1,
|
|
50877
|
+
offset: pageRequest.offset
|
|
50878
|
+
}) : await params.api.listAppMembers(targetId, {
|
|
50879
|
+
limit: pageRequest.limit + 1,
|
|
50880
|
+
offset: pageRequest.offset
|
|
50881
|
+
});
|
|
50655
50882
|
const members = params.scope === "organization" ? unwrapResponseObject(resp, "members") : params.scope === "project" ? unwrapResponseObject(resp, "members") : unwrapResponseObject(resp, "members");
|
|
50883
|
+
const page = paginateOverfetchedItems(members, params);
|
|
50656
50884
|
return {
|
|
50657
50885
|
scopeType: params.scope,
|
|
50658
50886
|
targetId,
|
|
50659
|
-
members
|
|
50887
|
+
members: page.items,
|
|
50888
|
+
pagination: page.pagination
|
|
50660
50889
|
};
|
|
50661
50890
|
}
|
|
50662
50891
|
async function collabUpdateMemberRole(params) {
|
|
@@ -50850,6 +51079,23 @@ async function collabInvite(params) {
|
|
|
50850
51079
|
targetId
|
|
50851
51080
|
};
|
|
50852
51081
|
}
|
|
51082
|
+
async function collabList(params) {
|
|
51083
|
+
const pageRequest = normalizePagination(params);
|
|
51084
|
+
const resp = await params.api.listApps({
|
|
51085
|
+
ownership: params.ownership ?? "all",
|
|
51086
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
51087
|
+
createdBy: params.createdBy,
|
|
51088
|
+
forked: params.forked ?? "all",
|
|
51089
|
+
limit: pageRequest.limit + 1,
|
|
51090
|
+
offset: pageRequest.offset
|
|
51091
|
+
});
|
|
51092
|
+
const apps = unwrapResponseObject(resp, "apps");
|
|
51093
|
+
const page = paginateOverfetchedItems(apps, params);
|
|
51094
|
+
return {
|
|
51095
|
+
apps: page.items,
|
|
51096
|
+
pagination: page.pagination
|
|
51097
|
+
};
|
|
51098
|
+
}
|
|
50853
51099
|
async function collabReconcile(params) {
|
|
50854
51100
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50855
51101
|
const binding = await readCollabBinding(repoRoot);
|
|
@@ -51465,6 +51711,8 @@ var ERROR_CODES = {
|
|
|
51465
51711
|
METADATA_CONFLICT: "METADATA_CONFLICT",
|
|
51466
51712
|
DESTRUCTIVE_OPERATION_BLOCKED: "DESTRUCTIVE_OPERATION_BLOCKED",
|
|
51467
51713
|
CONFIG_INVALID: "CONFIG_INVALID",
|
|
51714
|
+
ACCESS_DENIED: "ACCESS_DENIED",
|
|
51715
|
+
RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND",
|
|
51468
51716
|
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
51469
51717
|
};
|
|
51470
51718
|
var RemixMcpError = class extends Error {
|
|
@@ -51480,6 +51728,15 @@ function toStringOrNull(value) {
|
|
|
51480
51728
|
const trimmed = value.trim();
|
|
51481
51729
|
return trimmed.length > 0 ? trimmed : null;
|
|
51482
51730
|
}
|
|
51731
|
+
function parseJsonObject(value) {
|
|
51732
|
+
if (!value) return null;
|
|
51733
|
+
try {
|
|
51734
|
+
const parsed = JSON.parse(value);
|
|
51735
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
51736
|
+
} catch {
|
|
51737
|
+
return null;
|
|
51738
|
+
}
|
|
51739
|
+
}
|
|
51483
51740
|
function makeNormalized(params) {
|
|
51484
51741
|
return {
|
|
51485
51742
|
code: params.code,
|
|
@@ -51493,6 +51750,8 @@ function normalizeByMessage(err) {
|
|
|
51493
51750
|
const code = toStringOrNull(err.code);
|
|
51494
51751
|
const message = toStringOrNull(err.message) ?? "Unexpected error.";
|
|
51495
51752
|
const hint = toStringOrNull(err.hint);
|
|
51753
|
+
const hintBody = parseJsonObject(hint);
|
|
51754
|
+
const statusCode = typeof hintBody?.statusCode === "number" ? hintBody.statusCode : typeof hintBody?.statusCode === "string" ? Number(hintBody.statusCode) : null;
|
|
51496
51755
|
if (code === ERROR_CODES.REPO_LOCK_HELD) {
|
|
51497
51756
|
return makeNormalized({
|
|
51498
51757
|
code: ERROR_CODES.REPO_LOCK_HELD,
|
|
@@ -51593,6 +51852,22 @@ function normalizeByMessage(err) {
|
|
|
51593
51852
|
category: "remote_state"
|
|
51594
51853
|
});
|
|
51595
51854
|
}
|
|
51855
|
+
if (statusCode === 403) {
|
|
51856
|
+
return makeNormalized({
|
|
51857
|
+
code: ERROR_CODES.ACCESS_DENIED,
|
|
51858
|
+
message,
|
|
51859
|
+
hint,
|
|
51860
|
+
category: "remote_state"
|
|
51861
|
+
});
|
|
51862
|
+
}
|
|
51863
|
+
if (statusCode === 404) {
|
|
51864
|
+
return makeNormalized({
|
|
51865
|
+
code: ERROR_CODES.RESOURCE_NOT_FOUND,
|
|
51866
|
+
message,
|
|
51867
|
+
hint,
|
|
51868
|
+
category: "remote_state"
|
|
51869
|
+
});
|
|
51870
|
+
}
|
|
51596
51871
|
if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
|
|
51597
51872
|
return makeNormalized({
|
|
51598
51873
|
code: ERROR_CODES.REMOTE_ERROR,
|
|
@@ -51770,6 +52045,11 @@ function makeErrorResult(envelope) {
|
|
|
51770
52045
|
}
|
|
51771
52046
|
var genericRecordSchema = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
51772
52047
|
var genericArraySchema = external_exports.array(genericRecordSchema);
|
|
52048
|
+
var paginationSchema = external_exports.object({
|
|
52049
|
+
limit: external_exports.number().int().positive(),
|
|
52050
|
+
offset: external_exports.number().int().nonnegative(),
|
|
52051
|
+
hasMore: external_exports.boolean()
|
|
52052
|
+
});
|
|
51773
52053
|
var mergeRequestQueueSchema = external_exports.enum([
|
|
51774
52054
|
"reviewable",
|
|
51775
52055
|
"created_by_me",
|
|
@@ -51791,7 +52071,12 @@ var initInputSchema = {
|
|
|
51791
52071
|
var listInputSchema = {
|
|
51792
52072
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51793
52073
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51794
|
-
|
|
52074
|
+
ownership: external_exports.enum(["mine", "shared", "all"]).optional(),
|
|
52075
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]).optional(),
|
|
52076
|
+
createdBy: external_exports.string().trim().min(1).optional(),
|
|
52077
|
+
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
52078
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52079
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51795
52080
|
};
|
|
51796
52081
|
var remixInputSchema = {
|
|
51797
52082
|
...commonRequestFieldsSchema,
|
|
@@ -51820,6 +52105,16 @@ var recordTurnInputSchema = {
|
|
|
51820
52105
|
allowBranchMismatch: external_exports.boolean().optional(),
|
|
51821
52106
|
idempotencyKey: external_exports.string().trim().min(1).optional()
|
|
51822
52107
|
};
|
|
52108
|
+
var finalizeTurnInputSchema = {
|
|
52109
|
+
...commonRequestFieldsSchema,
|
|
52110
|
+
prompt: external_exports.string().trim().min(1),
|
|
52111
|
+
assistantResponse: external_exports.string().trim().min(1),
|
|
52112
|
+
diffSource: external_exports.enum(["worktree", "external"]).optional(),
|
|
52113
|
+
externalDiff: external_exports.string().optional(),
|
|
52114
|
+
sync: external_exports.boolean().optional(),
|
|
52115
|
+
allowBranchMismatch: external_exports.boolean().optional(),
|
|
52116
|
+
idempotencyKey: external_exports.string().trim().min(1).optional()
|
|
52117
|
+
};
|
|
51823
52118
|
var previewInputSchema = {
|
|
51824
52119
|
...commonRequestFieldsSchema
|
|
51825
52120
|
};
|
|
@@ -51835,20 +52130,26 @@ var reviewQueueInputSchema = {
|
|
|
51835
52130
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51836
52131
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51837
52132
|
status: external_exports.string().trim().min(1).optional(),
|
|
51838
|
-
kind: external_exports.enum(["merge", "sync", "all"]).optional()
|
|
52133
|
+
kind: external_exports.enum(["merge", "sync", "all"]).optional(),
|
|
52134
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52135
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51839
52136
|
};
|
|
51840
52137
|
var myMergeRequestsInputSchema = {
|
|
51841
52138
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51842
52139
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51843
52140
|
status: external_exports.string().trim().min(1).optional(),
|
|
51844
|
-
kind: external_exports.enum(["merge", "sync", "all"]).optional()
|
|
52141
|
+
kind: external_exports.enum(["merge", "sync", "all"]).optional(),
|
|
52142
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52143
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51845
52144
|
};
|
|
51846
52145
|
var appMergeRequestsInputSchema = {
|
|
51847
52146
|
...commonRequestFieldsSchema,
|
|
51848
52147
|
queue: appScopedMergeRequestQueueSchema,
|
|
51849
52148
|
appId: external_exports.string().trim().min(1).optional(),
|
|
51850
52149
|
status: external_exports.string().trim().min(1).optional(),
|
|
51851
|
-
kind: external_exports.enum(["merge", "sync", "all"]).optional()
|
|
52150
|
+
kind: external_exports.enum(["merge", "sync", "all"]).optional(),
|
|
52151
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52152
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51852
52153
|
};
|
|
51853
52154
|
var viewMergeRequestInputSchema = {
|
|
51854
52155
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
@@ -51879,6 +52180,38 @@ var inviteInputSchema = {
|
|
|
51879
52180
|
var listMembersInputSchema = {
|
|
51880
52181
|
...commonRequestFieldsSchema,
|
|
51881
52182
|
scope: memberScopeSchema,
|
|
52183
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52184
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52185
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
52186
|
+
};
|
|
52187
|
+
var listInvitesInputSchema = {
|
|
52188
|
+
...commonRequestFieldsSchema,
|
|
52189
|
+
scope: memberScopeSchema.optional(),
|
|
52190
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52191
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52192
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
52193
|
+
};
|
|
52194
|
+
var resendInviteInputSchema = {
|
|
52195
|
+
...commonRequestFieldsSchema,
|
|
52196
|
+
scope: memberScopeSchema.optional(),
|
|
52197
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52198
|
+
inviteId: external_exports.string().trim().min(1),
|
|
52199
|
+
ttlDays: external_exports.number().int().positive().max(30).optional()
|
|
52200
|
+
};
|
|
52201
|
+
var revokeInviteInputSchema = {
|
|
52202
|
+
...commonRequestFieldsSchema,
|
|
52203
|
+
scope: memberScopeSchema.optional(),
|
|
52204
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52205
|
+
inviteId: external_exports.string().trim().min(1),
|
|
52206
|
+
confirm: external_exports.boolean()
|
|
52207
|
+
};
|
|
52208
|
+
var acceptInvitationInputSchema = {
|
|
52209
|
+
requestId: external_exports.string().trim().min(1).optional(),
|
|
52210
|
+
token: external_exports.string().trim().min(20)
|
|
52211
|
+
};
|
|
52212
|
+
var accessDebugInputSchema = {
|
|
52213
|
+
...commonRequestFieldsSchema,
|
|
52214
|
+
scope: memberScopeSchema.optional(),
|
|
51882
52215
|
targetId: external_exports.string().trim().min(1).optional()
|
|
51883
52216
|
};
|
|
51884
52217
|
var updateMemberRoleInputSchema = {
|
|
@@ -51902,7 +52235,8 @@ var initDataSchema = external_exports.object({
|
|
|
51902
52235
|
repoRoot: external_exports.string()
|
|
51903
52236
|
});
|
|
51904
52237
|
var listDataSchema = external_exports.object({
|
|
51905
|
-
apps: genericArraySchema
|
|
52238
|
+
apps: genericArraySchema,
|
|
52239
|
+
pagination: paginationSchema
|
|
51906
52240
|
});
|
|
51907
52241
|
var remixDataSchema = external_exports.object({
|
|
51908
52242
|
appId: external_exports.string(),
|
|
@@ -51925,12 +52259,21 @@ var addDataSchema = external_exports.object({
|
|
|
51925
52259
|
autoSync: genericRecordSchema
|
|
51926
52260
|
});
|
|
51927
52261
|
var recordTurnDataSchema = genericRecordSchema;
|
|
52262
|
+
var finalizeTurnDataSchema = external_exports.object({
|
|
52263
|
+
mode: external_exports.enum(["changed_turn", "no_diff_turn"]),
|
|
52264
|
+
idempotencyKey: external_exports.string().min(1),
|
|
52265
|
+
changeStep: genericRecordSchema.nullable(),
|
|
52266
|
+
collabTurn: genericRecordSchema.nullable(),
|
|
52267
|
+
autoSync: genericRecordSchema.nullable(),
|
|
52268
|
+
warnings: external_exports.array(external_exports.string())
|
|
52269
|
+
});
|
|
51928
52270
|
var syncDataSchema = genericRecordSchema;
|
|
51929
52271
|
var requestMergeDataSchema = genericRecordSchema;
|
|
51930
52272
|
var mergeRequestQueueDataSchema = external_exports.object({
|
|
51931
52273
|
queue: mergeRequestQueueSchema,
|
|
51932
52274
|
appId: external_exports.string().nullable(),
|
|
51933
|
-
mergeRequests: external_exports.array(genericRecordSchema)
|
|
52275
|
+
mergeRequests: external_exports.array(genericRecordSchema),
|
|
52276
|
+
pagination: paginationSchema
|
|
51934
52277
|
});
|
|
51935
52278
|
var viewMergeRequestDataSchema = genericRecordSchema;
|
|
51936
52279
|
var approveDataSchema = genericRecordSchema;
|
|
@@ -51942,7 +52285,49 @@ var memberRecordSchema = genericRecordSchema;
|
|
|
51942
52285
|
var listMembersDataSchema = external_exports.object({
|
|
51943
52286
|
scopeType: memberScopeSchema,
|
|
51944
52287
|
targetId: external_exports.string(),
|
|
51945
|
-
members: external_exports.array(memberRecordSchema)
|
|
52288
|
+
members: external_exports.array(memberRecordSchema),
|
|
52289
|
+
pagination: paginationSchema
|
|
52290
|
+
});
|
|
52291
|
+
var listInvitesDataSchema = external_exports.object({
|
|
52292
|
+
scopeType: memberScopeSchema,
|
|
52293
|
+
targetId: external_exports.string(),
|
|
52294
|
+
invites: external_exports.array(genericRecordSchema),
|
|
52295
|
+
pagination: paginationSchema
|
|
52296
|
+
});
|
|
52297
|
+
var resendInviteDataSchema = genericRecordSchema;
|
|
52298
|
+
var revokeInviteDataSchema = external_exports.object({
|
|
52299
|
+
scopeType: memberScopeSchema,
|
|
52300
|
+
targetId: external_exports.string(),
|
|
52301
|
+
inviteId: external_exports.string(),
|
|
52302
|
+
revoked: external_exports.boolean()
|
|
52303
|
+
});
|
|
52304
|
+
var acceptInvitationDataSchema = genericRecordSchema;
|
|
52305
|
+
var accessDebugDataSchema = external_exports.object({
|
|
52306
|
+
viewer: genericRecordSchema,
|
|
52307
|
+
scope: external_exports.object({
|
|
52308
|
+
scopeType: memberScopeSchema,
|
|
52309
|
+
targetId: external_exports.string()
|
|
52310
|
+
}),
|
|
52311
|
+
entities: external_exports.object({
|
|
52312
|
+
organization: genericRecordSchema.nullable(),
|
|
52313
|
+
project: genericRecordSchema.nullable(),
|
|
52314
|
+
app: genericRecordSchema.nullable()
|
|
52315
|
+
}),
|
|
52316
|
+
binding: external_exports.object({
|
|
52317
|
+
repoRoot: external_exports.string().nullable(),
|
|
52318
|
+
binding: genericRecordSchema.nullable()
|
|
52319
|
+
}),
|
|
52320
|
+
access: external_exports.object({
|
|
52321
|
+
appContext: genericRecordSchema.nullable(),
|
|
52322
|
+
viewerMember: genericRecordSchema.nullable(),
|
|
52323
|
+
viewerProjectMember: genericRecordSchema.nullable(),
|
|
52324
|
+
inviteForViewerEmail: genericRecordSchema.nullable(),
|
|
52325
|
+
effectiveAppAccess: genericRecordSchema.nullable()
|
|
52326
|
+
}),
|
|
52327
|
+
members: external_exports.array(genericRecordSchema),
|
|
52328
|
+
membersPageInfo: paginationSchema,
|
|
52329
|
+
invites: external_exports.array(genericRecordSchema),
|
|
52330
|
+
invitesPageInfo: paginationSchema
|
|
51946
52331
|
});
|
|
51947
52332
|
var updateMemberRoleDataSchema = external_exports.object({
|
|
51948
52333
|
scopeType: memberScopeSchema,
|
|
@@ -51956,6 +52341,7 @@ var remixSuccessSchema = makeSuccessSchema(remixDataSchema);
|
|
|
51956
52341
|
var checkoutSuccessSchema = makeSuccessSchema(checkoutDataSchema);
|
|
51957
52342
|
var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
51958
52343
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
52344
|
+
var finalizeTurnSuccessSchema = makeSuccessSchema(finalizeTurnDataSchema);
|
|
51959
52345
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
51960
52346
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
51961
52347
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
@@ -51966,14 +52352,12 @@ var syncUpstreamSuccessSchema = makeSuccessSchema(syncUpstreamDataSchema);
|
|
|
51966
52352
|
var reconcileSuccessSchema = makeSuccessSchema(reconcileDataSchema);
|
|
51967
52353
|
var inviteSuccessSchema = makeSuccessSchema(inviteDataSchema);
|
|
51968
52354
|
var listMembersSuccessSchema = makeSuccessSchema(listMembersDataSchema);
|
|
52355
|
+
var listInvitesSuccessSchema = makeSuccessSchema(listInvitesDataSchema);
|
|
52356
|
+
var resendInviteSuccessSchema = makeSuccessSchema(resendInviteDataSchema);
|
|
52357
|
+
var revokeInviteSuccessSchema = makeSuccessSchema(revokeInviteDataSchema);
|
|
52358
|
+
var acceptInvitationSuccessSchema = makeSuccessSchema(acceptInvitationDataSchema);
|
|
52359
|
+
var accessDebugSuccessSchema = makeSuccessSchema(accessDebugDataSchema);
|
|
51969
52360
|
var updateMemberRoleSuccessSchema = makeSuccessSchema(updateMemberRoleDataSchema);
|
|
51970
|
-
function unwrapResponseObject2(resp, label) {
|
|
51971
|
-
const obj = resp?.responseObject;
|
|
51972
|
-
if (obj === void 0 || obj === null) {
|
|
51973
|
-
throw new Error(typeof resp?.message === "string" && resp.message.trim() ? resp.message : `Missing ${label} response`);
|
|
51974
|
-
}
|
|
51975
|
-
return obj;
|
|
51976
|
-
}
|
|
51977
52361
|
function getRiskLevel(status) {
|
|
51978
52362
|
if (status.recommendedAction === "reconcile") return "high";
|
|
51979
52363
|
if (status.recommendedAction === "sync" || status.remote.incomingOpenMergeRequestCount) return "medium";
|
|
@@ -51999,12 +52383,12 @@ function getRecommendedNextActions(status) {
|
|
|
51999
52383
|
return [];
|
|
52000
52384
|
}
|
|
52001
52385
|
}
|
|
52002
|
-
function
|
|
52386
|
+
function collectWarnings2(value) {
|
|
52003
52387
|
if (!value || !Array.isArray(value)) return [];
|
|
52004
52388
|
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
52005
52389
|
}
|
|
52006
52390
|
function collectResultWarnings(value) {
|
|
52007
|
-
return
|
|
52391
|
+
return collectWarnings2(value.warnings);
|
|
52008
52392
|
}
|
|
52009
52393
|
function truncateText(value, maxChars) {
|
|
52010
52394
|
if (value.length <= maxChars) {
|
|
@@ -52060,13 +52444,20 @@ async function initCollab(params) {
|
|
|
52060
52444
|
};
|
|
52061
52445
|
}
|
|
52062
52446
|
async function listApps(params) {
|
|
52063
|
-
const api = await
|
|
52064
|
-
const
|
|
52065
|
-
|
|
52447
|
+
const api = await createCollabApiClient();
|
|
52448
|
+
const result = await collabList({
|
|
52449
|
+
api,
|
|
52450
|
+
ownership: params.ownership,
|
|
52451
|
+
accessScope: params.accessScope,
|
|
52452
|
+
createdBy: params.createdBy,
|
|
52453
|
+
forked: params.forked,
|
|
52454
|
+
limit: params.limit,
|
|
52455
|
+
offset: params.offset
|
|
52456
|
+
});
|
|
52066
52457
|
return {
|
|
52067
|
-
data:
|
|
52458
|
+
data: result,
|
|
52068
52459
|
warnings: [],
|
|
52069
|
-
recommendedNextActions: [],
|
|
52460
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52070
52461
|
logContext: {}
|
|
52071
52462
|
};
|
|
52072
52463
|
}
|
|
@@ -52107,70 +52498,28 @@ async function checkoutCollab(params) {
|
|
|
52107
52498
|
}
|
|
52108
52499
|
};
|
|
52109
52500
|
}
|
|
52110
|
-
async function
|
|
52501
|
+
async function finalizeCollabTurn(params) {
|
|
52111
52502
|
const api = await createCollabApiClient();
|
|
52112
52503
|
const repoRoot = await findGitRoot(params.cwd);
|
|
52113
|
-
const
|
|
52114
|
-
const untrackedBefore = params.diffSource === "worktree" ? await listUntrackedFiles(repoRoot) : [];
|
|
52115
|
-
const changeStep = await collabAdd({
|
|
52504
|
+
const result = await collabFinalizeTurn({
|
|
52116
52505
|
api,
|
|
52117
52506
|
cwd: params.cwd,
|
|
52118
52507
|
prompt: params.prompt,
|
|
52119
|
-
assistantResponse: params.assistantResponse
|
|
52508
|
+
assistantResponse: params.assistantResponse,
|
|
52120
52509
|
diff: params.externalDiff ?? null,
|
|
52121
52510
|
diffSource: params.diffSource,
|
|
52122
|
-
|
|
52123
|
-
idempotencyKey: params.idempotencyKey ?? null,
|
|
52124
|
-
actor: params.agent
|
|
52125
|
-
});
|
|
52126
|
-
const postHead = await getHeadCommitHash(repoRoot);
|
|
52127
|
-
const autoSyncEligible = params.diffSource === "worktree";
|
|
52128
|
-
const localRepoMutated = autoSyncEligible && preHead !== postHead;
|
|
52129
|
-
return {
|
|
52130
|
-
data: {
|
|
52131
|
-
changeStep,
|
|
52132
|
-
autoSync: {
|
|
52133
|
-
requested: true,
|
|
52134
|
-
eligible: autoSyncEligible,
|
|
52135
|
-
attempted: autoSyncEligible,
|
|
52136
|
-
applied: autoSyncEligible,
|
|
52137
|
-
trackedChangesDiscarded: autoSyncEligible,
|
|
52138
|
-
capturedUntrackedPathsCandidate: untrackedBefore,
|
|
52139
|
-
localHeadBefore: preHead,
|
|
52140
|
-
localHeadAfter: postHead,
|
|
52141
|
-
localRepoMutated
|
|
52142
|
-
}
|
|
52143
|
-
},
|
|
52144
|
-
warnings: [
|
|
52145
|
-
...collectResultWarnings(changeStep),
|
|
52146
|
-
...params.diffSource === "external" ? [
|
|
52147
|
-
"Automatic local discard+sync was skipped because the diff came from an external source and may not match the current worktree."
|
|
52148
|
-
] : []
|
|
52149
|
-
],
|
|
52150
|
-
recommendedNextActions: [],
|
|
52151
|
-
logContext: {
|
|
52152
|
-
repoRoot
|
|
52153
|
-
}
|
|
52154
|
-
};
|
|
52155
|
-
}
|
|
52156
|
-
async function recordCollabTurn(params) {
|
|
52157
|
-
const api = await createCollabApiClient();
|
|
52158
|
-
const result = await collabRecordTurn({
|
|
52159
|
-
api,
|
|
52160
|
-
cwd: params.cwd,
|
|
52161
|
-
prompt: params.prompt,
|
|
52162
|
-
assistantResponse: params.assistantResponse,
|
|
52511
|
+
sync: params.sync,
|
|
52163
52512
|
allowBranchMismatch: params.allowBranchMismatch ?? false,
|
|
52164
52513
|
idempotencyKey: params.idempotencyKey ?? null,
|
|
52165
52514
|
actor: params.agent
|
|
52166
52515
|
});
|
|
52167
52516
|
return {
|
|
52168
52517
|
data: result,
|
|
52169
|
-
warnings:
|
|
52518
|
+
warnings: result.warnings,
|
|
52170
52519
|
recommendedNextActions: [],
|
|
52171
52520
|
logContext: {
|
|
52172
|
-
repoRoot
|
|
52173
|
-
appId: result.appId
|
|
52521
|
+
repoRoot,
|
|
52522
|
+
appId: result.changeStep?.appId ?? result.collabTurn?.appId ?? null
|
|
52174
52523
|
}
|
|
52175
52524
|
};
|
|
52176
52525
|
}
|
|
@@ -52212,16 +52561,19 @@ async function reviewQueue(params) {
|
|
|
52212
52561
|
api,
|
|
52213
52562
|
queue: "reviewable",
|
|
52214
52563
|
status: params.status ?? "open",
|
|
52215
|
-
kind: params.kind ?? "merge"
|
|
52564
|
+
kind: params.kind ?? "merge",
|
|
52565
|
+
limit: params.limit,
|
|
52566
|
+
offset: params.offset
|
|
52216
52567
|
});
|
|
52217
52568
|
return {
|
|
52218
52569
|
data: {
|
|
52219
52570
|
queue: result.queue,
|
|
52220
52571
|
appId: result.appId,
|
|
52221
|
-
mergeRequests: result.mergeRequests
|
|
52572
|
+
mergeRequests: result.mergeRequests,
|
|
52573
|
+
pagination: result.pagination
|
|
52222
52574
|
},
|
|
52223
52575
|
warnings: [],
|
|
52224
|
-
recommendedNextActions: [],
|
|
52576
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52225
52577
|
logContext: {}
|
|
52226
52578
|
};
|
|
52227
52579
|
}
|
|
@@ -52231,16 +52583,19 @@ async function myMergeRequests(params) {
|
|
|
52231
52583
|
api,
|
|
52232
52584
|
queue: "created_by_me",
|
|
52233
52585
|
status: params.status ?? "open",
|
|
52234
|
-
kind: params.kind ?? "merge"
|
|
52586
|
+
kind: params.kind ?? "merge",
|
|
52587
|
+
limit: params.limit,
|
|
52588
|
+
offset: params.offset
|
|
52235
52589
|
});
|
|
52236
52590
|
return {
|
|
52237
52591
|
data: {
|
|
52238
52592
|
queue: result.queue,
|
|
52239
52593
|
appId: result.appId,
|
|
52240
|
-
mergeRequests: result.mergeRequests
|
|
52594
|
+
mergeRequests: result.mergeRequests,
|
|
52595
|
+
pagination: result.pagination
|
|
52241
52596
|
},
|
|
52242
52597
|
warnings: [],
|
|
52243
|
-
recommendedNextActions: [],
|
|
52598
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52244
52599
|
logContext: {}
|
|
52245
52600
|
};
|
|
52246
52601
|
}
|
|
@@ -52252,16 +52607,19 @@ async function listAppMergeRequests(params) {
|
|
|
52252
52607
|
appId: params.appId,
|
|
52253
52608
|
queue: params.queue,
|
|
52254
52609
|
status: params.status ?? "open",
|
|
52255
|
-
kind: params.kind ?? "merge"
|
|
52610
|
+
kind: params.kind ?? "merge",
|
|
52611
|
+
limit: params.limit,
|
|
52612
|
+
offset: params.offset
|
|
52256
52613
|
});
|
|
52257
52614
|
return {
|
|
52258
52615
|
data: {
|
|
52259
52616
|
queue: result.queue,
|
|
52260
52617
|
appId: result.appId,
|
|
52261
|
-
mergeRequests: result.mergeRequests
|
|
52618
|
+
mergeRequests: result.mergeRequests,
|
|
52619
|
+
pagination: result.pagination
|
|
52262
52620
|
},
|
|
52263
52621
|
warnings: [],
|
|
52264
|
-
recommendedNextActions: [],
|
|
52622
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52265
52623
|
logContext: {
|
|
52266
52624
|
appId: result.appId
|
|
52267
52625
|
}
|
|
@@ -52354,7 +52712,7 @@ async function reconcile(params) {
|
|
|
52354
52712
|
});
|
|
52355
52713
|
return {
|
|
52356
52714
|
data: result,
|
|
52357
|
-
warnings:
|
|
52715
|
+
warnings: collectWarnings2(result.warnings),
|
|
52358
52716
|
recommendedNextActions: params.dryRun ? ["Run remix_collab_reconcile_apply with confirm=true only if the preview is acceptable. Do not replace this with raw git history-rewrite commands."] : [],
|
|
52359
52717
|
risks: params.dryRun ? ["Reconcile apply rewrites local history and creates a backup branch."] : [],
|
|
52360
52718
|
logContext: {
|
|
@@ -52386,12 +52744,14 @@ async function listMembers(params) {
|
|
|
52386
52744
|
api,
|
|
52387
52745
|
cwd: params.cwd,
|
|
52388
52746
|
scope: params.scope,
|
|
52389
|
-
targetId: params.targetId ?? null
|
|
52747
|
+
targetId: params.targetId ?? null,
|
|
52748
|
+
limit: params.limit,
|
|
52749
|
+
offset: params.offset
|
|
52390
52750
|
});
|
|
52391
52751
|
return {
|
|
52392
52752
|
data: result,
|
|
52393
52753
|
warnings: [],
|
|
52394
|
-
recommendedNextActions: [],
|
|
52754
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52395
52755
|
logContext: {}
|
|
52396
52756
|
};
|
|
52397
52757
|
}
|
|
@@ -52412,35 +52772,517 @@ async function updateMemberRole(params) {
|
|
|
52412
52772
|
logContext: {}
|
|
52413
52773
|
};
|
|
52414
52774
|
}
|
|
52415
|
-
function
|
|
52416
|
-
|
|
52417
|
-
|
|
52418
|
-
|
|
52419
|
-
|
|
52420
|
-
|
|
52421
|
-
|
|
52775
|
+
function unwrapResponseObject2(resp, label) {
|
|
52776
|
+
const obj = resp?.responseObject;
|
|
52777
|
+
if (obj === void 0 || obj === null) {
|
|
52778
|
+
throw new Error(typeof resp?.message === "string" && resp.message.trim() ? resp.message : `Missing ${label} response`);
|
|
52779
|
+
}
|
|
52780
|
+
return obj;
|
|
52781
|
+
}
|
|
52782
|
+
async function maybeFindGitRoot(cwd) {
|
|
52783
|
+
try {
|
|
52784
|
+
return await findGitRoot(cwd);
|
|
52785
|
+
} catch {
|
|
52786
|
+
return null;
|
|
52422
52787
|
}
|
|
52788
|
+
}
|
|
52789
|
+
async function loadBindingContext(cwd) {
|
|
52790
|
+
if (!cwd) return { repoRoot: null, binding: null };
|
|
52791
|
+
const repoRoot = await maybeFindGitRoot(cwd);
|
|
52792
|
+
if (!repoRoot) return { repoRoot: null, binding: null };
|
|
52793
|
+
const binding = await readCollabBinding(repoRoot);
|
|
52423
52794
|
return {
|
|
52424
|
-
|
|
52425
|
-
|
|
52426
|
-
idempotentHint: false,
|
|
52427
|
-
openWorldHint: false
|
|
52795
|
+
repoRoot,
|
|
52796
|
+
binding
|
|
52428
52797
|
};
|
|
52429
52798
|
}
|
|
52430
|
-
function
|
|
52431
|
-
|
|
52432
|
-
|
|
52433
|
-
|
|
52434
|
-
|
|
52435
|
-
|
|
52436
|
-
|
|
52437
|
-
|
|
52438
|
-
|
|
52799
|
+
function makeNotBoundError(message = "Repository is not bound to Remix.", hint) {
|
|
52800
|
+
const error2 = new Error(message);
|
|
52801
|
+
error2.hint = hint ?? "Run `remix_collab_init` in this repository, or pass the explicit id for a direct read.";
|
|
52802
|
+
return error2;
|
|
52803
|
+
}
|
|
52804
|
+
function parseJsonObject2(value) {
|
|
52805
|
+
if (!value) return null;
|
|
52806
|
+
try {
|
|
52807
|
+
const parsed = JSON.parse(value);
|
|
52808
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
52809
|
+
} catch {
|
|
52810
|
+
return null;
|
|
52811
|
+
}
|
|
52812
|
+
}
|
|
52813
|
+
function getBackendStatusCode(error2) {
|
|
52814
|
+
if (!error2 || typeof error2 !== "object") return null;
|
|
52815
|
+
const hint = "hint" in error2 && typeof error2.hint === "string" ? error2.hint : null;
|
|
52816
|
+
const body = parseJsonObject2(hint);
|
|
52817
|
+
if (typeof body?.statusCode === "number") return body.statusCode;
|
|
52818
|
+
if (typeof body?.statusCode === "string") {
|
|
52819
|
+
const parsed = Number(body.statusCode);
|
|
52820
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
52821
|
+
}
|
|
52822
|
+
return null;
|
|
52823
|
+
}
|
|
52824
|
+
function isBackendForbidden(error2) {
|
|
52825
|
+
return getBackendStatusCode(error2) === 403;
|
|
52826
|
+
}
|
|
52827
|
+
function isBackendNotFound(error2) {
|
|
52828
|
+
return getBackendStatusCode(error2) === 404;
|
|
52829
|
+
}
|
|
52830
|
+
function createAccessDeniedError(message, hint) {
|
|
52831
|
+
return new RemixMcpError({
|
|
52832
|
+
code: ERROR_CODES.ACCESS_DENIED,
|
|
52833
|
+
message,
|
|
52834
|
+
hint: hint ?? null,
|
|
52835
|
+
retryable: false,
|
|
52836
|
+
category: "remote_state"
|
|
52837
|
+
});
|
|
52838
|
+
}
|
|
52839
|
+
var MEMBERSHIP_PAGE_SIZE = 100;
|
|
52840
|
+
function normalizePagination2(params) {
|
|
52841
|
+
const rawLimit = typeof params?.limit === "number" ? Math.trunc(params.limit) : 25;
|
|
52842
|
+
const rawOffset = typeof params?.offset === "number" ? Math.trunc(params.offset) : 0;
|
|
52843
|
+
return {
|
|
52844
|
+
limit: Math.max(1, Math.min(50, rawLimit)),
|
|
52845
|
+
offset: Math.max(0, rawOffset)
|
|
52846
|
+
};
|
|
52847
|
+
}
|
|
52848
|
+
async function resolveScopeTarget2(api, params) {
|
|
52849
|
+
const explicitTargetId = params.targetId?.trim();
|
|
52850
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
52851
|
+
if (explicitTargetId) {
|
|
52852
|
+
return {
|
|
52853
|
+
scopeType: params.scope,
|
|
52854
|
+
targetId: explicitTargetId,
|
|
52855
|
+
repoRoot: bindingContext.repoRoot
|
|
52856
|
+
};
|
|
52857
|
+
}
|
|
52858
|
+
if (!bindingContext.binding) {
|
|
52859
|
+
throw makeNotBoundError("Scope target was not provided and the current repository is not bound to Remix.");
|
|
52860
|
+
}
|
|
52861
|
+
if (params.scope === "app") {
|
|
52862
|
+
return {
|
|
52863
|
+
scopeType: "app",
|
|
52864
|
+
targetId: bindingContext.binding.currentAppId,
|
|
52865
|
+
repoRoot: bindingContext.repoRoot
|
|
52866
|
+
};
|
|
52867
|
+
}
|
|
52868
|
+
const appContext = unwrapResponseObject2(
|
|
52869
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
52870
|
+
"bound app context"
|
|
52871
|
+
);
|
|
52872
|
+
if (params.scope === "project") {
|
|
52873
|
+
if (!appContext.readableScopes.project) {
|
|
52874
|
+
throw createAccessDeniedError(
|
|
52875
|
+
"The bound app's project is not readable to the current user.",
|
|
52876
|
+
"Use `scope=app` for app-level diagnostics, or pass an explicit readable project id."
|
|
52877
|
+
);
|
|
52878
|
+
}
|
|
52879
|
+
return {
|
|
52880
|
+
scopeType: "project",
|
|
52881
|
+
targetId: appContext.projectId,
|
|
52882
|
+
repoRoot: bindingContext.repoRoot
|
|
52883
|
+
};
|
|
52884
|
+
}
|
|
52885
|
+
if (!appContext.readableScopes.organization) {
|
|
52886
|
+
throw createAccessDeniedError(
|
|
52887
|
+
"The bound app's organization is not readable to the current user.",
|
|
52888
|
+
"Use `scope=app` or `scope=project` for narrower diagnostics, or pass an explicit readable organization id."
|
|
52889
|
+
);
|
|
52890
|
+
}
|
|
52891
|
+
return {
|
|
52892
|
+
scopeType: "organization",
|
|
52893
|
+
targetId: appContext.organizationId,
|
|
52894
|
+
repoRoot: bindingContext.repoRoot
|
|
52895
|
+
};
|
|
52896
|
+
}
|
|
52897
|
+
async function getScopeEntity(api, scopeType, targetId) {
|
|
52898
|
+
if (scopeType === "organization") {
|
|
52899
|
+
return {
|
|
52900
|
+
organization: unwrapResponseObject2(await api.getOrganization(targetId), "organization"),
|
|
52901
|
+
project: null,
|
|
52902
|
+
app: null
|
|
52903
|
+
};
|
|
52904
|
+
}
|
|
52905
|
+
if (scopeType === "project") {
|
|
52906
|
+
const project2 = unwrapResponseObject2(await api.getProject(targetId), "project");
|
|
52907
|
+
const organizationId2 = typeof project2.organizationId === "string" ? project2.organizationId : null;
|
|
52908
|
+
return {
|
|
52909
|
+
organization: organizationId2 == null ? null : unwrapResponseObject2(await api.getOrganization(organizationId2), "organization"),
|
|
52910
|
+
project: project2,
|
|
52911
|
+
app: null
|
|
52912
|
+
};
|
|
52913
|
+
}
|
|
52914
|
+
const app = unwrapResponseObject2(await api.getApp(targetId), "app");
|
|
52915
|
+
const projectId = typeof app.projectId === "string" ? app.projectId : null;
|
|
52916
|
+
const project = projectId == null ? null : unwrapResponseObject2(await api.getProject(projectId), "project");
|
|
52917
|
+
const organizationId = typeof project?.organizationId === "string" ? project.organizationId : null;
|
|
52918
|
+
return {
|
|
52919
|
+
organization: organizationId == null ? null : unwrapResponseObject2(await api.getOrganization(organizationId), "organization"),
|
|
52920
|
+
project,
|
|
52921
|
+
app
|
|
52922
|
+
};
|
|
52923
|
+
}
|
|
52924
|
+
function mapProjectRoleToAppRole(role) {
|
|
52925
|
+
switch (role) {
|
|
52926
|
+
case "owner":
|
|
52927
|
+
case "maintainer":
|
|
52928
|
+
return "maintainer";
|
|
52929
|
+
case "editor":
|
|
52930
|
+
return "editor";
|
|
52931
|
+
case "viewer":
|
|
52932
|
+
return "viewer";
|
|
52933
|
+
default:
|
|
52934
|
+
return null;
|
|
52935
|
+
}
|
|
52936
|
+
}
|
|
52937
|
+
function strongestRole(...roles) {
|
|
52938
|
+
if (roles.includes("owner")) return "owner";
|
|
52939
|
+
if (roles.includes("maintainer")) return "maintainer";
|
|
52940
|
+
if (roles.includes("editor")) return "editor";
|
|
52941
|
+
if (roles.includes("viewer")) return "viewer";
|
|
52942
|
+
return null;
|
|
52943
|
+
}
|
|
52944
|
+
function resolveAppAccessSource(params) {
|
|
52945
|
+
if (params.directAppRole && params.inheritedProjectRole) return "both";
|
|
52946
|
+
if (params.directAppRole) return "direct_app_membership";
|
|
52947
|
+
if (params.inheritedProjectRole) return "project_membership";
|
|
52948
|
+
return "none";
|
|
52949
|
+
}
|
|
52950
|
+
function buildEffectiveAppAccess(params) {
|
|
52951
|
+
const directAppRole = params.directAppRole ?? null;
|
|
52952
|
+
const inheritedProjectRole = mapProjectRoleToAppRole(params.projectRole);
|
|
52953
|
+
const effectiveRole = strongestRole(directAppRole, inheritedProjectRole);
|
|
52954
|
+
return {
|
|
52955
|
+
effectiveRole,
|
|
52956
|
+
directAppRole,
|
|
52957
|
+
projectRole: params.projectRole,
|
|
52958
|
+
inheritedProjectRole,
|
|
52959
|
+
accessSource: resolveAppAccessSource({ directAppRole, inheritedProjectRole }),
|
|
52960
|
+
canReadWorkflow: effectiveRole !== null,
|
|
52961
|
+
canEdit: effectiveRole === "owner" || effectiveRole === "maintainer" || effectiveRole === "editor",
|
|
52962
|
+
canManage: effectiveRole === "owner" || effectiveRole === "maintainer",
|
|
52963
|
+
isOwner: directAppRole === "owner"
|
|
52964
|
+
};
|
|
52965
|
+
}
|
|
52966
|
+
async function listMembersForScope(api, scopeType, targetId, params) {
|
|
52967
|
+
if (scopeType === "organization") {
|
|
52968
|
+
return unwrapResponseObject2(await api.listOrganizationMembers(targetId, params), "organization members");
|
|
52969
|
+
}
|
|
52970
|
+
if (scopeType === "project") {
|
|
52971
|
+
return unwrapResponseObject2(await api.listProjectMembers(targetId, params), "project members");
|
|
52972
|
+
}
|
|
52973
|
+
return unwrapResponseObject2(await api.listAppMembers(targetId, params), "app members");
|
|
52974
|
+
}
|
|
52975
|
+
async function loadFirstPageSample(fetchPage) {
|
|
52976
|
+
const items = await fetchPage(MEMBERSHIP_PAGE_SIZE, 0);
|
|
52977
|
+
const hasMore = items.length < MEMBERSHIP_PAGE_SIZE ? false : (await fetchPage(1, MEMBERSHIP_PAGE_SIZE)).length > 0;
|
|
52978
|
+
return {
|
|
52979
|
+
items,
|
|
52980
|
+
pageInfo: {
|
|
52981
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
52982
|
+
offset: 0,
|
|
52983
|
+
hasMore
|
|
52984
|
+
}
|
|
52985
|
+
};
|
|
52986
|
+
}
|
|
52987
|
+
function emptyFirstPageSample() {
|
|
52988
|
+
return {
|
|
52989
|
+
items: [],
|
|
52990
|
+
pageInfo: {
|
|
52991
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
52992
|
+
offset: 0,
|
|
52993
|
+
hasMore: false
|
|
52994
|
+
}
|
|
52995
|
+
};
|
|
52996
|
+
}
|
|
52997
|
+
async function listInvitesForScope(api, scopeType, targetId, params) {
|
|
52998
|
+
if (scopeType === "organization") {
|
|
52999
|
+
return unwrapResponseObject2(
|
|
53000
|
+
await api.listOrganizationInvites(targetId, params),
|
|
53001
|
+
"organization invites"
|
|
53002
|
+
);
|
|
53003
|
+
}
|
|
53004
|
+
if (scopeType === "project") {
|
|
53005
|
+
return unwrapResponseObject2(
|
|
53006
|
+
await api.listProjectInvites(targetId, params),
|
|
53007
|
+
"project invites"
|
|
53008
|
+
);
|
|
53009
|
+
}
|
|
53010
|
+
return unwrapResponseObject2(await api.listAppInvites(targetId, params), "app invites");
|
|
53011
|
+
}
|
|
53012
|
+
function getSelfMember(meId, members) {
|
|
53013
|
+
return meId == null ? null : members.find((member) => member.userId === meId || member.user_id === meId) ?? null;
|
|
53014
|
+
}
|
|
53015
|
+
async function findPendingInviteForEmailForScope(api, scopeType, targetId, email2) {
|
|
53016
|
+
if (email2 == null) return null;
|
|
53017
|
+
let offset = 0;
|
|
53018
|
+
for (; ; ) {
|
|
53019
|
+
const invites = await listInvitesForScope(api, scopeType, targetId, {
|
|
53020
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
53021
|
+
offset
|
|
53022
|
+
});
|
|
53023
|
+
const match = invites.find((invite) => invite.email.toLowerCase() === email2 && invite.state === "pending") ?? null;
|
|
53024
|
+
if (match) return match;
|
|
53025
|
+
if (invites.length < MEMBERSHIP_PAGE_SIZE) return null;
|
|
53026
|
+
offset += MEMBERSHIP_PAGE_SIZE;
|
|
53027
|
+
}
|
|
53028
|
+
}
|
|
53029
|
+
async function findSelfMemberForScope(api, scopeType, targetId, meId) {
|
|
53030
|
+
if (meId == null) return null;
|
|
53031
|
+
let offset = 0;
|
|
53032
|
+
for (; ; ) {
|
|
53033
|
+
const members = scopeType === "organization" ? unwrapResponseObject2(
|
|
53034
|
+
await api.listOrganizationMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53035
|
+
"organization members"
|
|
53036
|
+
) : scopeType === "project" ? unwrapResponseObject2(
|
|
53037
|
+
await api.listProjectMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53038
|
+
"project members"
|
|
53039
|
+
) : unwrapResponseObject2(
|
|
53040
|
+
await api.listAppMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53041
|
+
"app members"
|
|
53042
|
+
);
|
|
53043
|
+
const match = getSelfMember(meId, members);
|
|
53044
|
+
if (match) return match;
|
|
53045
|
+
if (members.length < MEMBERSHIP_PAGE_SIZE) return null;
|
|
53046
|
+
offset += MEMBERSHIP_PAGE_SIZE;
|
|
53047
|
+
}
|
|
53048
|
+
}
|
|
53049
|
+
async function listInvites(params) {
|
|
53050
|
+
const api = await createApiClient2();
|
|
53051
|
+
const target = await resolveScopeTarget2(api, {
|
|
53052
|
+
scope: params.scope ?? "project",
|
|
53053
|
+
targetId: params.targetId,
|
|
53054
|
+
cwd: params.cwd
|
|
53055
|
+
});
|
|
53056
|
+
const pagination = normalizePagination2(params);
|
|
53057
|
+
const invites = await listInvitesForScope(api, target.scopeType, target.targetId, {
|
|
53058
|
+
limit: pagination.limit + 1,
|
|
53059
|
+
offset: pagination.offset
|
|
53060
|
+
});
|
|
53061
|
+
return {
|
|
53062
|
+
data: {
|
|
53063
|
+
scopeType: target.scopeType,
|
|
53064
|
+
targetId: target.targetId,
|
|
53065
|
+
invites: invites.slice(0, pagination.limit),
|
|
53066
|
+
pagination: {
|
|
53067
|
+
...pagination,
|
|
53068
|
+
hasMore: invites.length > pagination.limit
|
|
53069
|
+
}
|
|
53070
|
+
},
|
|
53071
|
+
warnings: [],
|
|
53072
|
+
recommendedNextActions: invites.length > pagination.limit ? [`Pass offset=${pagination.offset + pagination.limit} to load the next page.`] : invites.length > 0 ? ["Use `remix_collab_resend_invite` or `remix_collab_revoke_invite` for lifecycle actions on a selected invite id."] : ["Use `remix_collab_invite` if you need to create a new invitation for this scope."],
|
|
53073
|
+
logContext: {
|
|
53074
|
+
repoRoot: target.repoRoot
|
|
53075
|
+
}
|
|
53076
|
+
};
|
|
53077
|
+
}
|
|
53078
|
+
async function resendInvite(params) {
|
|
53079
|
+
const api = await createApiClient2();
|
|
53080
|
+
const target = await resolveScopeTarget2(api, {
|
|
53081
|
+
scope: params.scope ?? "project",
|
|
53082
|
+
targetId: params.targetId,
|
|
53083
|
+
cwd: params.cwd
|
|
53084
|
+
});
|
|
53085
|
+
const response = target.scopeType === "organization" ? await api.resendOrganizationInvite(target.targetId, params.inviteId, { ttlDays: params.ttlDays }) : target.scopeType === "project" ? await api.resendProjectInvite(target.targetId, params.inviteId, { ttlDays: params.ttlDays }) : await api.resendAppInvite(target.targetId, params.inviteId, { ttlDays: params.ttlDays });
|
|
53086
|
+
return {
|
|
53087
|
+
data: unwrapResponseObject2(response, "resent invite"),
|
|
53088
|
+
warnings: [],
|
|
53089
|
+
recommendedNextActions: ["Use `remix_collab_list_invites` to confirm the refreshed expiry and delivery state."],
|
|
53090
|
+
logContext: {
|
|
53091
|
+
repoRoot: target.repoRoot
|
|
53092
|
+
}
|
|
53093
|
+
};
|
|
53094
|
+
}
|
|
53095
|
+
async function revokeInvite(params) {
|
|
53096
|
+
const api = await createApiClient2();
|
|
53097
|
+
const target = await resolveScopeTarget2(api, {
|
|
53098
|
+
scope: params.scope ?? "project",
|
|
53099
|
+
targetId: params.targetId,
|
|
53100
|
+
cwd: params.cwd
|
|
53101
|
+
});
|
|
53102
|
+
if (target.scopeType === "organization") {
|
|
53103
|
+
await api.revokeOrganizationInvite(target.targetId, params.inviteId);
|
|
53104
|
+
} else if (target.scopeType === "project") {
|
|
53105
|
+
await api.revokeProjectInvite(target.targetId, params.inviteId);
|
|
53106
|
+
} else {
|
|
53107
|
+
await api.revokeAppInvite(target.targetId, params.inviteId);
|
|
53108
|
+
}
|
|
53109
|
+
return {
|
|
53110
|
+
data: {
|
|
53111
|
+
scopeType: target.scopeType,
|
|
53112
|
+
targetId: target.targetId,
|
|
53113
|
+
inviteId: params.inviteId,
|
|
53114
|
+
revoked: true
|
|
53115
|
+
},
|
|
53116
|
+
warnings: [],
|
|
53117
|
+
recommendedNextActions: ["Use `remix_collab_list_invites` to confirm the invite state is now `revoked`."],
|
|
53118
|
+
logContext: {
|
|
53119
|
+
repoRoot: target.repoRoot
|
|
53120
|
+
}
|
|
53121
|
+
};
|
|
53122
|
+
}
|
|
53123
|
+
async function acceptInvitation(params) {
|
|
53124
|
+
const api = await createApiClient2();
|
|
53125
|
+
const result = unwrapResponseObject2(await api.acceptInvitation({ token: params.token }), "accepted invitation");
|
|
53126
|
+
return {
|
|
53127
|
+
data: result,
|
|
53128
|
+
warnings: [],
|
|
53129
|
+
recommendedNextActions: result.redirectPath ? [`The invitation is accepted. Use the returned redirect metadata to continue with the newly granted Remix scope.`] : [],
|
|
53130
|
+
logContext: {}
|
|
53131
|
+
};
|
|
53132
|
+
}
|
|
53133
|
+
async function accessDebug(params) {
|
|
53134
|
+
const api = await createApiClient2();
|
|
53135
|
+
const target = await resolveScopeTarget2(api, {
|
|
53136
|
+
scope: params.scope ?? "project",
|
|
53137
|
+
targetId: params.targetId,
|
|
53138
|
+
cwd: params.cwd
|
|
53139
|
+
});
|
|
53140
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53141
|
+
const viewer = unwrapResponseObject2(await api.getMe(), "current user");
|
|
53142
|
+
const viewerId = typeof viewer.id === "string" ? viewer.id : null;
|
|
53143
|
+
const viewerEmail = typeof viewer.email === "string" ? viewer.email.toLowerCase() : null;
|
|
53144
|
+
const warnings = [...bindingContext.binding ? [] : ["No local Remix binding was detected for the provided cwd."]];
|
|
53145
|
+
let entities;
|
|
53146
|
+
let appContext = null;
|
|
53147
|
+
let membersPage = emptyFirstPageSample();
|
|
53148
|
+
let invitesPage = emptyFirstPageSample();
|
|
53149
|
+
let viewerMember = null;
|
|
53150
|
+
let viewerProjectMember = null;
|
|
53151
|
+
let inviteForViewerEmail = null;
|
|
53152
|
+
let effectiveAppAccess = null;
|
|
53153
|
+
if (target.scopeType !== "app") {
|
|
53154
|
+
[entities, membersPage, invitesPage] = await Promise.all([
|
|
53155
|
+
getScopeEntity(api, target.scopeType, target.targetId),
|
|
53156
|
+
loadFirstPageSample((limit, offset) => listMembersForScope(api, target.scopeType, target.targetId, { limit, offset })),
|
|
53157
|
+
loadFirstPageSample((limit, offset) => listInvitesForScope(api, target.scopeType, target.targetId, { limit, offset }))
|
|
53158
|
+
]);
|
|
53159
|
+
viewerMember = await findSelfMemberForScope(api, target.scopeType, target.targetId, viewerId);
|
|
53160
|
+
inviteForViewerEmail = await findPendingInviteForEmailForScope(api, target.scopeType, target.targetId, viewerEmail);
|
|
53161
|
+
} else {
|
|
53162
|
+
const [app, loadedAppContext] = await Promise.all([
|
|
53163
|
+
unwrapResponseObject2(await api.getApp(target.targetId), "app"),
|
|
53164
|
+
unwrapResponseObject2(await api.getAppContext(target.targetId), "app context")
|
|
53165
|
+
]);
|
|
53166
|
+
appContext = loadedAppContext;
|
|
53167
|
+
entities = {
|
|
53168
|
+
organization: null,
|
|
53169
|
+
project: null,
|
|
53170
|
+
app
|
|
53171
|
+
};
|
|
53172
|
+
if (appContext.readableScopes.project) {
|
|
53173
|
+
try {
|
|
53174
|
+
entities.project = unwrapResponseObject2(await api.getProject(appContext.projectId), "project");
|
|
53175
|
+
} catch (error2) {
|
|
53176
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53177
|
+
warnings.push("The app is readable, but its project/workspace metadata is not currently readable to the current user.");
|
|
53178
|
+
}
|
|
53179
|
+
} else {
|
|
53180
|
+
warnings.push("The app is readable, but its project/workspace is not readable to the current user.");
|
|
53181
|
+
}
|
|
53182
|
+
if (appContext.readableScopes.organization) {
|
|
53183
|
+
try {
|
|
53184
|
+
entities.organization = unwrapResponseObject2(await api.getOrganization(appContext.organizationId), "organization");
|
|
53185
|
+
} catch (error2) {
|
|
53186
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53187
|
+
warnings.push("The app is readable, but its organization metadata is not currently readable to the current user.");
|
|
53188
|
+
}
|
|
53189
|
+
} else {
|
|
53190
|
+
warnings.push("The app's organization is not readable to the current user.");
|
|
53191
|
+
}
|
|
53192
|
+
effectiveAppAccess = {
|
|
53193
|
+
...buildEffectiveAppAccess({
|
|
53194
|
+
directAppRole: appContext.roles.appRole,
|
|
53195
|
+
projectRole: appContext.roles.projectRole
|
|
53196
|
+
}),
|
|
53197
|
+
accessPath: appContext.accessPath,
|
|
53198
|
+
readableScopes: appContext.readableScopes,
|
|
53199
|
+
visibility: appContext.visibility,
|
|
53200
|
+
organizationRole: appContext.roles.organizationRole ?? null
|
|
53201
|
+
};
|
|
53202
|
+
if (appContext.capabilities.canReadWorkflow) {
|
|
53203
|
+
membersPage = await loadFirstPageSample((limit, offset) => listMembersForScope(api, "app", target.targetId, { limit, offset }));
|
|
53204
|
+
viewerMember = await findSelfMemberForScope(api, "app", target.targetId, viewerId);
|
|
53205
|
+
if (appContext.readableScopes.project) {
|
|
53206
|
+
viewerProjectMember = await findSelfMemberForScope(api, "project", appContext.projectId, viewerId);
|
|
53207
|
+
}
|
|
53208
|
+
try {
|
|
53209
|
+
invitesPage = await loadFirstPageSample((limit, offset) => listInvitesForScope(api, "app", target.targetId, { limit, offset }));
|
|
53210
|
+
inviteForViewerEmail = await findPendingInviteForEmailForScope(api, "app", target.targetId, viewerEmail);
|
|
53211
|
+
} catch (error2) {
|
|
53212
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53213
|
+
warnings.push("App invite data is not readable to the current user, so invite diagnostics are partial.");
|
|
53214
|
+
}
|
|
53215
|
+
} else {
|
|
53216
|
+
warnings.push("The current viewer can read the app, but cannot read workflow-scoped app membership data.");
|
|
53217
|
+
}
|
|
53218
|
+
}
|
|
53219
|
+
if (membersPage.pageInfo.hasMore) {
|
|
53220
|
+
warnings.push("The `members` array is a first-page sample only; use the scope member list tool to inspect the remaining entries.");
|
|
53221
|
+
}
|
|
53222
|
+
if (invitesPage.pageInfo.hasMore) {
|
|
53223
|
+
warnings.push("The `invites` array is a first-page sample only; use the invite list tool with pagination to inspect the remaining entries.");
|
|
53224
|
+
}
|
|
53225
|
+
return {
|
|
53226
|
+
data: {
|
|
53227
|
+
viewer,
|
|
53228
|
+
scope: {
|
|
53229
|
+
scopeType: target.scopeType,
|
|
53230
|
+
targetId: target.targetId
|
|
53231
|
+
},
|
|
53232
|
+
entities,
|
|
53233
|
+
binding: {
|
|
53234
|
+
repoRoot: bindingContext.repoRoot,
|
|
53235
|
+
binding: bindingContext.binding
|
|
53236
|
+
},
|
|
53237
|
+
access: {
|
|
53238
|
+
appContext,
|
|
53239
|
+
viewerMember,
|
|
53240
|
+
viewerProjectMember,
|
|
53241
|
+
inviteForViewerEmail,
|
|
53242
|
+
effectiveAppAccess: effectiveAppAccess ?? null
|
|
53243
|
+
},
|
|
53244
|
+
members: membersPage.items,
|
|
53245
|
+
membersPageInfo: membersPage.pageInfo,
|
|
53246
|
+
invites: invitesPage.items,
|
|
53247
|
+
invitesPageInfo: invitesPage.pageInfo
|
|
53248
|
+
},
|
|
53249
|
+
warnings,
|
|
53250
|
+
recommendedNextActions: inviteForViewerEmail ? ["A pending invite exists for the current viewer email. Use `remix_collab_accept_invitation` if the viewer should accept it."] : target.scopeType === "app" ? ["Use `access.appContext` and `access.effectiveAppAccess` together to explain app-level visibility versus workspace-level visibility."] : ["Use the member and invite lists above to explain missing access, role mismatches, or stale invite state."],
|
|
53251
|
+
logContext: {
|
|
53252
|
+
repoRoot: target.repoRoot,
|
|
53253
|
+
appId: entities.app?.id ?? bindingContext.binding?.currentAppId ?? null
|
|
53254
|
+
}
|
|
53255
|
+
};
|
|
53256
|
+
}
|
|
53257
|
+
function getAnnotations(access, options) {
|
|
53258
|
+
if (access === "read") {
|
|
53259
|
+
return {
|
|
53260
|
+
readOnlyHint: true,
|
|
53261
|
+
idempotentHint: true,
|
|
53262
|
+
openWorldHint: false
|
|
53263
|
+
};
|
|
53264
|
+
}
|
|
53265
|
+
return {
|
|
53266
|
+
readOnlyHint: false,
|
|
53267
|
+
destructiveHint: access === "local_write",
|
|
53268
|
+
idempotentHint: options?.idempotent ?? false,
|
|
53269
|
+
openWorldHint: false
|
|
53270
|
+
};
|
|
53271
|
+
}
|
|
53272
|
+
function buildSuccessEnvelope(tool, requestId, result) {
|
|
53273
|
+
return {
|
|
53274
|
+
schemaVersion: SCHEMA_VERSION,
|
|
53275
|
+
ok: true,
|
|
53276
|
+
tool,
|
|
53277
|
+
requestId: requestId ?? null,
|
|
53278
|
+
data: result.data,
|
|
53279
|
+
warnings: result.warnings ?? [],
|
|
53280
|
+
risks: result.risks ?? [],
|
|
52439
53281
|
recommendedNextActions: result.recommendedNextActions ?? []
|
|
52440
53282
|
};
|
|
52441
53283
|
}
|
|
52442
53284
|
function deriveErrorRisks(tool, normalized) {
|
|
52443
|
-
if ((tool
|
|
53285
|
+
if (isFinalizeTurnLocalSyncFailure(tool, normalized)) {
|
|
52444
53286
|
return ["The change step succeeded remotely, but the local repository may need manual recovery or a follow-up sync."];
|
|
52445
53287
|
}
|
|
52446
53288
|
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
@@ -52454,9 +53296,16 @@ function deriveErrorRisks(tool, normalized) {
|
|
|
52454
53296
|
}
|
|
52455
53297
|
return [];
|
|
52456
53298
|
}
|
|
53299
|
+
function isFinalizeTurnLocalSyncFailure(tool, normalized) {
|
|
53300
|
+
return tool === "remix_collab_finalize_turn" && normalized.message === "Change step succeeded remotely, but automatic local sync failed.";
|
|
53301
|
+
}
|
|
52457
53302
|
function buildErrorEnvelope(tool, requestId, error2) {
|
|
52458
53303
|
const normalized = normalizeToolError(error2);
|
|
52459
|
-
const recommendedNextActions =
|
|
53304
|
+
const recommendedNextActions = isFinalizeTurnLocalSyncFailure(tool, normalized) ? [
|
|
53305
|
+
"Run `remix_collab_status` to confirm the bound repo state before attempting recovery.",
|
|
53306
|
+
"Run `remix_collab_sync_preview` next, then `remix_collab_sync_apply` with `confirm=true` if the preview looks correct.",
|
|
53307
|
+
"Inspect `error.hint` for any preserved diff backup path before retrying local recovery, and do not rerun `remix_collab_finalize_turn` immediately."
|
|
53308
|
+
] : normalized.code === "AUTH_REQUIRED" ? ["Set COMERGE_ACCESS_TOKEN, then retry the tool call."] : normalized.code === "REPO_LOCK_TIMEOUT" ? ["Wait for the active Remix mutation to finish, then retry the tool call."] : normalized.code === "REPO_STATE_CHANGED_DURING_OPERATION" ? ["Review local repository changes, then rerun the tool once the worktree is stable."] : normalized.code === "PREFERRED_BRANCH_MISMATCH" ? ["Switch to the repository's preferred Remix branch, or rerun with allowBranchMismatch=true if intentional."] : [];
|
|
52460
53309
|
return {
|
|
52461
53310
|
schemaVersion: SCHEMA_VERSION,
|
|
52462
53311
|
ok: false,
|
|
@@ -52477,7 +53326,7 @@ function registerTool(server, context, params) {
|
|
|
52477
53326
|
description: params.description,
|
|
52478
53327
|
inputSchema: params.inputSchema,
|
|
52479
53328
|
outputSchema: params.outputSchema,
|
|
52480
|
-
annotations: getAnnotations(params.access)
|
|
53329
|
+
annotations: params.annotations ?? getAnnotations(params.access)
|
|
52481
53330
|
},
|
|
52482
53331
|
async (rawArgs) => {
|
|
52483
53332
|
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
@@ -52551,13 +53400,20 @@ function registerCollabTools(server, context) {
|
|
|
52551
53400
|
});
|
|
52552
53401
|
registerTool(server, context, {
|
|
52553
53402
|
name: "remix_collab_list",
|
|
52554
|
-
description: "List Remix apps visible to the current authenticated user.",
|
|
53403
|
+
description: "List Remix apps visible to the current authenticated user. Defaults to membership-oriented discovery; pass accessScope=all_readable explicitly for broader readable discovery.",
|
|
52555
53404
|
access: "read",
|
|
52556
53405
|
inputSchema: listInputSchema,
|
|
52557
53406
|
outputSchema: listSuccessSchema,
|
|
52558
53407
|
run: async (args) => {
|
|
52559
53408
|
const input = external_exports.object(listInputSchema).parse(args);
|
|
52560
|
-
return listApps({
|
|
53409
|
+
return listApps({
|
|
53410
|
+
ownership: input.ownership,
|
|
53411
|
+
accessScope: input.accessScope,
|
|
53412
|
+
createdBy: input.createdBy,
|
|
53413
|
+
forked: input.forked,
|
|
53414
|
+
limit: input.limit,
|
|
53415
|
+
offset: input.offset
|
|
53416
|
+
});
|
|
52561
53417
|
}
|
|
52562
53418
|
});
|
|
52563
53419
|
registerTool(server, context, {
|
|
@@ -52594,89 +53450,25 @@ function registerCollabTools(server, context) {
|
|
|
52594
53450
|
}
|
|
52595
53451
|
});
|
|
52596
53452
|
registerTool(server, context, {
|
|
52597
|
-
name: "
|
|
52598
|
-
description: "
|
|
52599
|
-
access: "local_write",
|
|
52600
|
-
inputSchema: addInputSchema,
|
|
52601
|
-
outputSchema: addSuccessSchema,
|
|
52602
|
-
run: async (args) => {
|
|
52603
|
-
const input = external_exports.object(addInputSchema).parse(args);
|
|
52604
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52605
|
-
const diffSource = input.diffSource ?? "worktree";
|
|
52606
|
-
if (diffSource === "external") {
|
|
52607
|
-
const externalDiff = input.externalDiff ?? "";
|
|
52608
|
-
assertDiffWithinLimit(context.policy, externalDiff);
|
|
52609
|
-
}
|
|
52610
|
-
return addCollabStep({
|
|
52611
|
-
cwd,
|
|
52612
|
-
prompt: input.prompt,
|
|
52613
|
-
assistantResponse: input.assistantResponse,
|
|
52614
|
-
diffSource,
|
|
52615
|
-
externalDiff: input.externalDiff,
|
|
52616
|
-
allowBranchMismatch: input.allowBranchMismatch ?? false,
|
|
52617
|
-
idempotencyKey: input.idempotencyKey,
|
|
52618
|
-
agent: context.agentMetadata
|
|
52619
|
-
});
|
|
52620
|
-
}
|
|
52621
|
-
});
|
|
52622
|
-
registerTool(server, context, {
|
|
52623
|
-
name: "remix_collab_add_change_step",
|
|
52624
|
-
description: "Alias of remix_collab_add with a more explicit name: record a code-diff change step for the current bound repository.",
|
|
53453
|
+
name: "remix_collab_finalize_turn",
|
|
53454
|
+
description: "Primary turn recorder for the current bound repository. Call this exactly once before the final response; it records a changed turn when the worktree has a diff, records a no-diff turn when it does not, and can accept an explicit external diff when needed.",
|
|
52625
53455
|
access: "local_write",
|
|
52626
|
-
inputSchema:
|
|
52627
|
-
outputSchema:
|
|
53456
|
+
inputSchema: finalizeTurnInputSchema,
|
|
53457
|
+
outputSchema: finalizeTurnSuccessSchema,
|
|
53458
|
+
annotations: getAnnotations("local_write", { idempotent: true }),
|
|
52628
53459
|
run: async (args) => {
|
|
52629
|
-
const input = external_exports.object(
|
|
53460
|
+
const input = external_exports.object(finalizeTurnInputSchema).parse(args);
|
|
52630
53461
|
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52631
|
-
|
|
52632
|
-
|
|
52633
|
-
const externalDiff = input.externalDiff ?? "";
|
|
52634
|
-
assertDiffWithinLimit(context.policy, externalDiff);
|
|
53462
|
+
if ((input.diffSource ?? "worktree") === "external" || typeof input.externalDiff === "string") {
|
|
53463
|
+
assertDiffWithinLimit(context.policy, input.externalDiff ?? "");
|
|
52635
53464
|
}
|
|
52636
|
-
return
|
|
53465
|
+
return finalizeCollabTurn({
|
|
52637
53466
|
cwd,
|
|
52638
53467
|
prompt: input.prompt,
|
|
52639
53468
|
assistantResponse: input.assistantResponse,
|
|
52640
|
-
diffSource,
|
|
53469
|
+
diffSource: input.diffSource,
|
|
52641
53470
|
externalDiff: input.externalDiff,
|
|
52642
|
-
|
|
52643
|
-
idempotencyKey: input.idempotencyKey,
|
|
52644
|
-
agent: context.agentMetadata
|
|
52645
|
-
});
|
|
52646
|
-
}
|
|
52647
|
-
});
|
|
52648
|
-
registerTool(server, context, {
|
|
52649
|
-
name: "remix_collab_record_turn",
|
|
52650
|
-
description: "Record one no-diff collaboration turn for the current bound repository after a completed assistant response. This is for prompt/response history only and will fail if the worktree has code changes.",
|
|
52651
|
-
access: "remote_write",
|
|
52652
|
-
inputSchema: recordTurnInputSchema,
|
|
52653
|
-
outputSchema: recordTurnSuccessSchema,
|
|
52654
|
-
run: async (args) => {
|
|
52655
|
-
const input = external_exports.object(recordTurnInputSchema).parse(args);
|
|
52656
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52657
|
-
return recordCollabTurn({
|
|
52658
|
-
cwd,
|
|
52659
|
-
prompt: input.prompt,
|
|
52660
|
-
assistantResponse: input.assistantResponse,
|
|
52661
|
-
allowBranchMismatch: input.allowBranchMismatch ?? false,
|
|
52662
|
-
idempotencyKey: input.idempotencyKey,
|
|
52663
|
-
agent: context.agentMetadata
|
|
52664
|
-
});
|
|
52665
|
-
}
|
|
52666
|
-
});
|
|
52667
|
-
registerTool(server, context, {
|
|
52668
|
-
name: "remix_collab_record_no_diff_turn",
|
|
52669
|
-
description: "Alias of remix_collab_record_turn with a more explicit name: record a prompt/response turn only when the worktree has no code diff.",
|
|
52670
|
-
access: "remote_write",
|
|
52671
|
-
inputSchema: recordTurnInputSchema,
|
|
52672
|
-
outputSchema: recordTurnSuccessSchema,
|
|
52673
|
-
run: async (args) => {
|
|
52674
|
-
const input = external_exports.object(recordTurnInputSchema).parse(args);
|
|
52675
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52676
|
-
return recordCollabTurn({
|
|
52677
|
-
cwd,
|
|
52678
|
-
prompt: input.prompt,
|
|
52679
|
-
assistantResponse: input.assistantResponse,
|
|
53471
|
+
sync: input.sync,
|
|
52680
53472
|
allowBranchMismatch: input.allowBranchMismatch ?? false,
|
|
52681
53473
|
idempotencyKey: input.idempotencyKey,
|
|
52682
53474
|
agent: context.agentMetadata
|
|
@@ -52728,7 +53520,12 @@ function registerCollabTools(server, context) {
|
|
|
52728
53520
|
outputSchema: mergeRequestQueueSuccessSchema,
|
|
52729
53521
|
run: async (args) => {
|
|
52730
53522
|
const input = external_exports.object(reviewQueueInputSchema).parse(args);
|
|
52731
|
-
return reviewQueue({
|
|
53523
|
+
return reviewQueue({
|
|
53524
|
+
status: input.status,
|
|
53525
|
+
kind: input.kind,
|
|
53526
|
+
limit: input.limit,
|
|
53527
|
+
offset: input.offset
|
|
53528
|
+
});
|
|
52732
53529
|
}
|
|
52733
53530
|
});
|
|
52734
53531
|
registerTool(server, context, {
|
|
@@ -52739,7 +53536,12 @@ function registerCollabTools(server, context) {
|
|
|
52739
53536
|
outputSchema: mergeRequestQueueSuccessSchema,
|
|
52740
53537
|
run: async (args) => {
|
|
52741
53538
|
const input = external_exports.object(myMergeRequestsInputSchema).parse(args);
|
|
52742
|
-
return myMergeRequests({
|
|
53539
|
+
return myMergeRequests({
|
|
53540
|
+
status: input.status,
|
|
53541
|
+
kind: input.kind,
|
|
53542
|
+
limit: input.limit,
|
|
53543
|
+
offset: input.offset
|
|
53544
|
+
});
|
|
52743
53545
|
}
|
|
52744
53546
|
});
|
|
52745
53547
|
registerTool(server, context, {
|
|
@@ -52756,7 +53558,9 @@ function registerCollabTools(server, context) {
|
|
|
52756
53558
|
appId: input.appId,
|
|
52757
53559
|
queue: input.queue,
|
|
52758
53560
|
status: input.status,
|
|
52759
|
-
kind: input.kind
|
|
53561
|
+
kind: input.kind,
|
|
53562
|
+
limit: input.limit,
|
|
53563
|
+
offset: input.offset
|
|
52760
53564
|
});
|
|
52761
53565
|
}
|
|
52762
53566
|
});
|
|
@@ -52890,33 +53694,680 @@ function registerCollabTools(server, context) {
|
|
|
52890
53694
|
return listMembers({
|
|
52891
53695
|
cwd,
|
|
52892
53696
|
scope: input.scope,
|
|
52893
|
-
targetId: input.targetId
|
|
53697
|
+
targetId: input.targetId,
|
|
53698
|
+
limit: input.limit,
|
|
53699
|
+
offset: input.offset
|
|
52894
53700
|
});
|
|
52895
53701
|
}
|
|
52896
53702
|
});
|
|
52897
53703
|
registerTool(server, context, {
|
|
52898
|
-
name: "
|
|
52899
|
-
description: "
|
|
53704
|
+
name: "remix_collab_list_invites",
|
|
53705
|
+
description: "List invitations for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
53706
|
+
access: "read",
|
|
53707
|
+
inputSchema: listInvitesInputSchema,
|
|
53708
|
+
outputSchema: listInvitesSuccessSchema,
|
|
53709
|
+
run: async (args) => {
|
|
53710
|
+
const input = external_exports.object(listInvitesInputSchema).parse(args);
|
|
53711
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53712
|
+
return listInvites({
|
|
53713
|
+
cwd,
|
|
53714
|
+
scope: input.scope ?? "project",
|
|
53715
|
+
targetId: input.targetId,
|
|
53716
|
+
limit: input.limit,
|
|
53717
|
+
offset: input.offset
|
|
53718
|
+
});
|
|
53719
|
+
}
|
|
53720
|
+
});
|
|
53721
|
+
registerTool(server, context, {
|
|
53722
|
+
name: "remix_collab_resend_invite",
|
|
53723
|
+
description: "Resend an existing invitation for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
52900
53724
|
access: "remote_write",
|
|
52901
|
-
inputSchema:
|
|
52902
|
-
outputSchema:
|
|
53725
|
+
inputSchema: resendInviteInputSchema,
|
|
53726
|
+
outputSchema: resendInviteSuccessSchema,
|
|
52903
53727
|
run: async (args) => {
|
|
52904
|
-
const input = external_exports.object(
|
|
52905
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52906
|
-
return
|
|
53728
|
+
const input = external_exports.object(resendInviteInputSchema).parse(args);
|
|
53729
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53730
|
+
return resendInvite({
|
|
52907
53731
|
cwd,
|
|
52908
|
-
scope: input.scope,
|
|
53732
|
+
scope: input.scope ?? "project",
|
|
52909
53733
|
targetId: input.targetId,
|
|
52910
|
-
|
|
52911
|
-
|
|
53734
|
+
inviteId: input.inviteId,
|
|
53735
|
+
ttlDays: input.ttlDays
|
|
52912
53736
|
});
|
|
52913
53737
|
}
|
|
52914
53738
|
});
|
|
52915
|
-
|
|
53739
|
+
registerTool(server, context, {
|
|
53740
|
+
name: "remix_collab_revoke_invite",
|
|
53741
|
+
description: "Revoke an existing invitation for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
53742
|
+
access: "remote_write",
|
|
53743
|
+
inputSchema: revokeInviteInputSchema,
|
|
53744
|
+
outputSchema: revokeInviteSuccessSchema,
|
|
53745
|
+
run: async (args) => {
|
|
53746
|
+
const input = external_exports.object(revokeInviteInputSchema).parse(args);
|
|
53747
|
+
assertConfirm(input.confirm, "remix_collab_revoke_invite");
|
|
53748
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53749
|
+
return revokeInvite({
|
|
53750
|
+
cwd,
|
|
53751
|
+
scope: input.scope ?? "project",
|
|
53752
|
+
targetId: input.targetId,
|
|
53753
|
+
inviteId: input.inviteId
|
|
53754
|
+
});
|
|
53755
|
+
}
|
|
53756
|
+
});
|
|
53757
|
+
registerTool(server, context, {
|
|
53758
|
+
name: "remix_collab_accept_invitation",
|
|
53759
|
+
description: "Accept an invitation token for the currently authenticated Remix user.",
|
|
53760
|
+
access: "remote_write",
|
|
53761
|
+
inputSchema: acceptInvitationInputSchema,
|
|
53762
|
+
outputSchema: acceptInvitationSuccessSchema,
|
|
53763
|
+
annotations: getAnnotations("remote_write", { idempotent: true }),
|
|
53764
|
+
run: async (args) => {
|
|
53765
|
+
const input = external_exports.object(acceptInvitationInputSchema).parse(args);
|
|
53766
|
+
return acceptInvitation({
|
|
53767
|
+
token: input.token
|
|
53768
|
+
});
|
|
53769
|
+
}
|
|
53770
|
+
});
|
|
53771
|
+
registerTool(server, context, {
|
|
53772
|
+
name: "remix_access_debug",
|
|
53773
|
+
description: "Explain why the current user does or does not have access to an organization, project, or app by composing binding, membership, invite, and scope context.",
|
|
53774
|
+
access: "read",
|
|
53775
|
+
inputSchema: accessDebugInputSchema,
|
|
53776
|
+
outputSchema: accessDebugSuccessSchema,
|
|
53777
|
+
run: async (args) => {
|
|
53778
|
+
const input = external_exports.object(accessDebugInputSchema).parse(args);
|
|
53779
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53780
|
+
return accessDebug({
|
|
53781
|
+
cwd,
|
|
53782
|
+
scope: input.scope ?? "project",
|
|
53783
|
+
targetId: input.targetId
|
|
53784
|
+
});
|
|
53785
|
+
}
|
|
53786
|
+
});
|
|
53787
|
+
registerTool(server, context, {
|
|
53788
|
+
name: "remix_collab_update_member_role",
|
|
53789
|
+
description: "Update an organization, project, or app member role, using the current repository binding unless targetId is provided.",
|
|
53790
|
+
access: "remote_write",
|
|
53791
|
+
inputSchema: updateMemberRoleInputSchema,
|
|
53792
|
+
outputSchema: updateMemberRoleSuccessSchema,
|
|
53793
|
+
run: async (args) => {
|
|
53794
|
+
const input = external_exports.object(updateMemberRoleInputSchema).parse(args);
|
|
53795
|
+
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
53796
|
+
return updateMemberRole({
|
|
53797
|
+
cwd,
|
|
53798
|
+
scope: input.scope,
|
|
53799
|
+
targetId: input.targetId,
|
|
53800
|
+
userId: input.userId,
|
|
53801
|
+
role: input.role
|
|
53802
|
+
});
|
|
53803
|
+
}
|
|
53804
|
+
});
|
|
53805
|
+
}
|
|
52916
53806
|
var genericRecordSchema2 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
52917
53807
|
var genericArraySchema2 = external_exports.array(genericRecordSchema2);
|
|
53808
|
+
var paginationSchema2 = external_exports.object({
|
|
53809
|
+
limit: external_exports.number().int().positive(),
|
|
53810
|
+
offset: external_exports.number().int().nonnegative(),
|
|
53811
|
+
hasMore: external_exports.boolean()
|
|
53812
|
+
});
|
|
53813
|
+
var whoamiInputSchema = {
|
|
53814
|
+
...commonRequestFieldsSchema
|
|
53815
|
+
};
|
|
53816
|
+
var directoryOrganizationInputSchema = {
|
|
53817
|
+
...commonRequestFieldsSchema,
|
|
53818
|
+
organizationId: external_exports.string().trim().min(1).optional()
|
|
53819
|
+
};
|
|
53820
|
+
var directoryListProjectsInputSchema = {
|
|
53821
|
+
...commonRequestFieldsSchema,
|
|
53822
|
+
organizationId: external_exports.string().trim().min(1).optional(),
|
|
53823
|
+
clientAppId: external_exports.string().trim().min(1).optional()
|
|
53824
|
+
};
|
|
53825
|
+
var directoryProjectInputSchema = {
|
|
53826
|
+
...commonRequestFieldsSchema,
|
|
53827
|
+
projectId: external_exports.string().trim().min(1).optional()
|
|
53828
|
+
};
|
|
53829
|
+
var directoryListAppsInputSchema = {
|
|
53830
|
+
...commonRequestFieldsSchema,
|
|
53831
|
+
projectId: external_exports.string().trim().min(1).optional(),
|
|
53832
|
+
organizationId: external_exports.string().trim().min(1).optional(),
|
|
53833
|
+
ownership: external_exports.enum(["mine", "shared", "all"]).optional(),
|
|
53834
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]).optional(),
|
|
53835
|
+
createdBy: external_exports.string().trim().min(1).optional(),
|
|
53836
|
+
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
53837
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
53838
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
53839
|
+
};
|
|
53840
|
+
var directoryAppInputSchema = {
|
|
53841
|
+
...commonRequestFieldsSchema,
|
|
53842
|
+
appId: external_exports.string().trim().min(1).optional()
|
|
53843
|
+
};
|
|
53844
|
+
var whoamiDataSchema = external_exports.object({
|
|
53845
|
+
id: external_exports.string().nullable(),
|
|
53846
|
+
name: external_exports.string().nullable(),
|
|
53847
|
+
email: external_exports.string().nullable(),
|
|
53848
|
+
organizationId: external_exports.string().nullable(),
|
|
53849
|
+
roles: genericRecordSchema2,
|
|
53850
|
+
binding: genericRecordSchema2.nullable()
|
|
53851
|
+
});
|
|
53852
|
+
var listOrganizationsDataSchema = external_exports.object({
|
|
53853
|
+
organizations: genericArraySchema2
|
|
53854
|
+
});
|
|
53855
|
+
var getOrganizationDataSchema = external_exports.object({
|
|
53856
|
+
organization: genericRecordSchema2
|
|
53857
|
+
});
|
|
53858
|
+
var listProjectsDataSchema = external_exports.object({
|
|
53859
|
+
organizationId: external_exports.string().nullable(),
|
|
53860
|
+
projects: genericArraySchema2
|
|
53861
|
+
});
|
|
53862
|
+
var getProjectDataSchema = external_exports.object({
|
|
53863
|
+
project: genericRecordSchema2
|
|
53864
|
+
});
|
|
53865
|
+
var listAppsDataSchema = external_exports.object({
|
|
53866
|
+
apps: genericArraySchema2,
|
|
53867
|
+
pagination: paginationSchema2,
|
|
53868
|
+
filters: external_exports.object({
|
|
53869
|
+
projectId: external_exports.string().nullable(),
|
|
53870
|
+
organizationId: external_exports.string().nullable(),
|
|
53871
|
+
ownership: external_exports.enum(["mine", "shared", "all"]),
|
|
53872
|
+
accessScope: external_exports.enum(["all_readable", "explicit_member"]),
|
|
53873
|
+
createdBy: external_exports.string().nullable(),
|
|
53874
|
+
forked: external_exports.enum(["only", "exclude", "all"])
|
|
53875
|
+
})
|
|
53876
|
+
});
|
|
53877
|
+
var getAppDataSchema = external_exports.object({
|
|
53878
|
+
app: genericRecordSchema2
|
|
53879
|
+
});
|
|
53880
|
+
var whoamiSuccessSchema = makeSuccessSchema(whoamiDataSchema);
|
|
53881
|
+
var listOrganizationsSuccessSchema = makeSuccessSchema(listOrganizationsDataSchema);
|
|
53882
|
+
var getOrganizationSuccessSchema = makeSuccessSchema(getOrganizationDataSchema);
|
|
53883
|
+
var listProjectsSuccessSchema = makeSuccessSchema(listProjectsDataSchema);
|
|
53884
|
+
var getProjectSuccessSchema = makeSuccessSchema(getProjectDataSchema);
|
|
53885
|
+
var listAppsSuccessSchema = makeSuccessSchema(listAppsDataSchema);
|
|
53886
|
+
var getAppSuccessSchema = makeSuccessSchema(getAppDataSchema);
|
|
53887
|
+
function normalizePagination22(params) {
|
|
53888
|
+
const rawLimit = typeof params?.limit === "number" ? Math.trunc(params.limit) : 25;
|
|
53889
|
+
const rawOffset = typeof params?.offset === "number" ? Math.trunc(params.offset) : 0;
|
|
53890
|
+
return {
|
|
53891
|
+
limit: Math.max(1, Math.min(50, rawLimit)),
|
|
53892
|
+
offset: Math.max(0, rawOffset)
|
|
53893
|
+
};
|
|
53894
|
+
}
|
|
53895
|
+
async function resolveOrganizationId(api, params) {
|
|
53896
|
+
const explicitId = params.organizationId?.trim();
|
|
53897
|
+
if (explicitId) return explicitId;
|
|
53898
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53899
|
+
if (!bindingContext.binding) {
|
|
53900
|
+
throw makeNotBoundError("Organization id was not provided and the current repository is not bound to Remix.");
|
|
53901
|
+
}
|
|
53902
|
+
const appContext = unwrapResponseObject2(
|
|
53903
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
53904
|
+
"bound app context"
|
|
53905
|
+
);
|
|
53906
|
+
if (!appContext.readableScopes.organization) {
|
|
53907
|
+
throw createAccessDeniedError(
|
|
53908
|
+
"The bound app's organization is not readable to the current user.",
|
|
53909
|
+
"Use an explicit organization id you can access, or inspect the bound app with `remix_directory_get_app` / `remix_access_debug` for app-level context."
|
|
53910
|
+
);
|
|
53911
|
+
}
|
|
53912
|
+
return appContext.organizationId;
|
|
53913
|
+
}
|
|
53914
|
+
async function resolveProjectId(api, params) {
|
|
53915
|
+
const explicitId = params.projectId?.trim();
|
|
53916
|
+
if (explicitId) {
|
|
53917
|
+
const bindingContext2 = await loadBindingContext(params.cwd);
|
|
53918
|
+
return { projectId: explicitId, repoRoot: bindingContext2.repoRoot };
|
|
53919
|
+
}
|
|
53920
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53921
|
+
if (!bindingContext.binding) {
|
|
53922
|
+
throw makeNotBoundError("Project id was not provided and the current repository is not bound to Remix.");
|
|
53923
|
+
}
|
|
53924
|
+
const appContext = unwrapResponseObject2(
|
|
53925
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
53926
|
+
"bound app context"
|
|
53927
|
+
);
|
|
53928
|
+
if (!appContext.readableScopes.project) {
|
|
53929
|
+
throw createAccessDeniedError(
|
|
53930
|
+
"The bound app's project is not readable to the current user.",
|
|
53931
|
+
"Use `remix_directory_get_app` or `remix_access_debug` for app-level diagnostics, or pass an explicit project id you can access."
|
|
53932
|
+
);
|
|
53933
|
+
}
|
|
53934
|
+
return {
|
|
53935
|
+
projectId: appContext.projectId,
|
|
53936
|
+
repoRoot: bindingContext.repoRoot
|
|
53937
|
+
};
|
|
53938
|
+
}
|
|
53939
|
+
async function resolveAppId(params) {
|
|
53940
|
+
const explicitId = params.appId?.trim();
|
|
53941
|
+
if (explicitId) {
|
|
53942
|
+
const bindingContext2 = await loadBindingContext(params.cwd);
|
|
53943
|
+
return { appId: explicitId, repoRoot: bindingContext2.repoRoot };
|
|
53944
|
+
}
|
|
53945
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53946
|
+
if (!bindingContext.binding) {
|
|
53947
|
+
throw makeNotBoundError("App id was not provided and the current repository is not bound to Remix.");
|
|
53948
|
+
}
|
|
53949
|
+
return {
|
|
53950
|
+
appId: bindingContext.binding.currentAppId,
|
|
53951
|
+
repoRoot: bindingContext.repoRoot
|
|
53952
|
+
};
|
|
53953
|
+
}
|
|
53954
|
+
function toEffectiveAppRole(role) {
|
|
53955
|
+
switch (role) {
|
|
53956
|
+
case "owner":
|
|
53957
|
+
case "maintainer":
|
|
53958
|
+
case "editor":
|
|
53959
|
+
case "viewer":
|
|
53960
|
+
return role;
|
|
53961
|
+
default:
|
|
53962
|
+
return null;
|
|
53963
|
+
}
|
|
53964
|
+
}
|
|
53965
|
+
function resolveAppAccessSource2(params) {
|
|
53966
|
+
if (params.directAppRole && params.inheritedProjectRole) return "both";
|
|
53967
|
+
if (params.directAppRole) return "direct_app_membership";
|
|
53968
|
+
if (params.inheritedProjectRole) return "project_membership";
|
|
53969
|
+
return "none";
|
|
53970
|
+
}
|
|
53971
|
+
function emptySelfRoles() {
|
|
53972
|
+
return {
|
|
53973
|
+
organizationRole: null,
|
|
53974
|
+
projectRole: null,
|
|
53975
|
+
appRole: null,
|
|
53976
|
+
directAppRole: null,
|
|
53977
|
+
inheritedProjectRole: null,
|
|
53978
|
+
appAccessSource: "none"
|
|
53979
|
+
};
|
|
53980
|
+
}
|
|
53981
|
+
function resolveSelfRolesFromAppContext(appContext) {
|
|
53982
|
+
if (!appContext) return emptySelfRoles();
|
|
53983
|
+
const directAppRole = toEffectiveAppRole(appContext.roles.appRole);
|
|
53984
|
+
const inheritedProjectRole = toEffectiveAppRole(appContext.roles.inheritedProjectRole);
|
|
53985
|
+
return {
|
|
53986
|
+
organizationRole: appContext.roles.organizationRole ?? null,
|
|
53987
|
+
projectRole: appContext.roles.projectRole ?? null,
|
|
53988
|
+
appRole: toEffectiveAppRole(appContext.roles.effectiveAppRole),
|
|
53989
|
+
directAppRole,
|
|
53990
|
+
inheritedProjectRole,
|
|
53991
|
+
appAccessSource: resolveAppAccessSource2({ directAppRole, inheritedProjectRole })
|
|
53992
|
+
};
|
|
53993
|
+
}
|
|
53994
|
+
async function whoAmI(params) {
|
|
53995
|
+
const api = await createApiClient2();
|
|
53996
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53997
|
+
const me = unwrapResponseObject2(await api.getMe(), "current user");
|
|
53998
|
+
const warnings = bindingContext.binding ? [] : ["No local Remix binding was detected for the provided cwd."];
|
|
53999
|
+
let boundAppContext = null;
|
|
54000
|
+
let boundProject = null;
|
|
54001
|
+
let boundApp = null;
|
|
54002
|
+
if (bindingContext.binding) {
|
|
54003
|
+
try {
|
|
54004
|
+
boundAppContext = unwrapResponseObject2(
|
|
54005
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
54006
|
+
"bound app context"
|
|
54007
|
+
);
|
|
54008
|
+
} catch (error2) {
|
|
54009
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
54010
|
+
warnings.push(
|
|
54011
|
+
"The bound app context could not be loaded. The local binding may be stale, or the current user may no longer be able to read that app."
|
|
54012
|
+
);
|
|
54013
|
+
}
|
|
54014
|
+
try {
|
|
54015
|
+
boundApp = unwrapResponseObject2(await api.getApp(bindingContext.binding.currentAppId), "app");
|
|
54016
|
+
} catch (error2) {
|
|
54017
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
54018
|
+
warnings.push("The bound app metadata could not be loaded for the current user.");
|
|
54019
|
+
}
|
|
54020
|
+
if (boundAppContext?.readableScopes.project) {
|
|
54021
|
+
try {
|
|
54022
|
+
boundProject = unwrapResponseObject2(await api.getProject(boundAppContext.projectId), "project");
|
|
54023
|
+
} catch (error2) {
|
|
54024
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
54025
|
+
warnings.push("The bound app is readable, but its project metadata is not currently readable to the current user.");
|
|
54026
|
+
}
|
|
54027
|
+
} else if (boundAppContext) {
|
|
54028
|
+
warnings.push("The bound app is readable, but its project/workspace is not readable to the current user.");
|
|
54029
|
+
}
|
|
54030
|
+
}
|
|
54031
|
+
const roles = resolveSelfRolesFromAppContext(boundAppContext);
|
|
54032
|
+
return {
|
|
54033
|
+
data: {
|
|
54034
|
+
id: me.id ?? null,
|
|
54035
|
+
name: me.name ?? null,
|
|
54036
|
+
email: me.email ?? null,
|
|
54037
|
+
organizationId: me.organizationId ?? null,
|
|
54038
|
+
roles,
|
|
54039
|
+
binding: bindingContext.binding == null ? null : {
|
|
54040
|
+
repoRoot: bindingContext.repoRoot,
|
|
54041
|
+
...bindingContext.binding,
|
|
54042
|
+
projectId: boundAppContext?.projectId ?? bindingContext.binding.projectId,
|
|
54043
|
+
organizationId: boundAppContext?.organizationId ?? null,
|
|
54044
|
+
visibility: boundAppContext?.visibility ?? null,
|
|
54045
|
+
accessPath: boundAppContext?.accessPath ?? null,
|
|
54046
|
+
readableScopes: boundAppContext?.readableScopes ?? null,
|
|
54047
|
+
projectName: boundProject?.name ?? null,
|
|
54048
|
+
appName: boundApp?.name ?? null
|
|
54049
|
+
}
|
|
54050
|
+
},
|
|
54051
|
+
warnings,
|
|
54052
|
+
recommendedNextActions: bindingContext.binding ? ["Use `remix_access_debug` next when you need to explain repository binding or membership issues in this workspace."] : ["Use `remix_directory_list_organizations` to inspect visible tenancy context, or run `remix_collab_init` in a repository to create a local binding."],
|
|
54053
|
+
logContext: {
|
|
54054
|
+
repoRoot: bindingContext.repoRoot,
|
|
54055
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54056
|
+
}
|
|
54057
|
+
};
|
|
54058
|
+
}
|
|
54059
|
+
async function listOrganizations() {
|
|
54060
|
+
const api = await createApiClient2();
|
|
54061
|
+
const organizations = unwrapResponseObject2(await api.listOrganizations(), "organizations");
|
|
54062
|
+
return {
|
|
54063
|
+
data: { organizations },
|
|
54064
|
+
warnings: [],
|
|
54065
|
+
recommendedNextActions: organizations.length ? ["Use `remix_directory_get_organization` for one organization, or `remix_directory_list_projects` to inspect projects under a chosen organization."] : [],
|
|
54066
|
+
logContext: {}
|
|
54067
|
+
};
|
|
54068
|
+
}
|
|
54069
|
+
async function getOrganization(params) {
|
|
54070
|
+
const api = await createApiClient2();
|
|
54071
|
+
const organizationId = await resolveOrganizationId(api, params);
|
|
54072
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54073
|
+
const organization = unwrapResponseObject2(await api.getOrganization(organizationId), "organization");
|
|
54074
|
+
return {
|
|
54075
|
+
data: { organization },
|
|
54076
|
+
warnings: [],
|
|
54077
|
+
recommendedNextActions: ["Use `remix_directory_list_projects` with this organization id to inspect its project directory."],
|
|
54078
|
+
logContext: {
|
|
54079
|
+
repoRoot: bindingContext.repoRoot
|
|
54080
|
+
}
|
|
54081
|
+
};
|
|
54082
|
+
}
|
|
54083
|
+
async function listProjects(params) {
|
|
54084
|
+
const api = await createApiClient2();
|
|
54085
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54086
|
+
const organizationId = params.organizationId !== void 0 ? await resolveOrganizationId(api, { organizationId: params.organizationId, cwd: params.cwd }) : null;
|
|
54087
|
+
const projects = unwrapResponseObject2(
|
|
54088
|
+
await api.listProjects({
|
|
54089
|
+
organizationId: organizationId ?? void 0,
|
|
54090
|
+
clientAppId: params.clientAppId
|
|
54091
|
+
}),
|
|
54092
|
+
"projects"
|
|
54093
|
+
);
|
|
54094
|
+
return {
|
|
54095
|
+
data: {
|
|
54096
|
+
projects,
|
|
54097
|
+
organizationId
|
|
54098
|
+
},
|
|
54099
|
+
warnings: [],
|
|
54100
|
+
recommendedNextActions: projects.length ? ["Use `remix_directory_get_project` for one project, or `remix_directory_list_apps` to inspect apps under a chosen project or organization."] : [],
|
|
54101
|
+
logContext: {
|
|
54102
|
+
repoRoot: bindingContext.repoRoot,
|
|
54103
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54104
|
+
}
|
|
54105
|
+
};
|
|
54106
|
+
}
|
|
54107
|
+
async function getProject(params) {
|
|
54108
|
+
const api = await createApiClient2();
|
|
54109
|
+
const target = await resolveProjectId(api, params);
|
|
54110
|
+
const project = unwrapResponseObject2(await api.getProject(target.projectId), "project");
|
|
54111
|
+
return {
|
|
54112
|
+
data: { project },
|
|
54113
|
+
warnings: [],
|
|
54114
|
+
recommendedNextActions: ["Use `remix_directory_list_apps` with this project id to inspect apps under the project."],
|
|
54115
|
+
logContext: {
|
|
54116
|
+
repoRoot: target.repoRoot
|
|
54117
|
+
}
|
|
54118
|
+
};
|
|
54119
|
+
}
|
|
54120
|
+
async function listApps2(params) {
|
|
54121
|
+
const api = await createApiClient2();
|
|
54122
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54123
|
+
const pagination = normalizePagination22(params);
|
|
54124
|
+
const apps = unwrapResponseObject2(
|
|
54125
|
+
await api.listApps({
|
|
54126
|
+
projectId: params.projectId,
|
|
54127
|
+
organizationId: params.organizationId,
|
|
54128
|
+
ownership: params.ownership ?? "all",
|
|
54129
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
54130
|
+
createdBy: params.createdBy,
|
|
54131
|
+
forked: params.forked,
|
|
54132
|
+
limit: pagination.limit + 1,
|
|
54133
|
+
offset: pagination.offset
|
|
54134
|
+
}),
|
|
54135
|
+
"apps"
|
|
54136
|
+
);
|
|
54137
|
+
return {
|
|
54138
|
+
data: {
|
|
54139
|
+
apps: apps.slice(0, pagination.limit),
|
|
54140
|
+
pagination: {
|
|
54141
|
+
...pagination,
|
|
54142
|
+
hasMore: apps.length > pagination.limit
|
|
54143
|
+
},
|
|
54144
|
+
filters: {
|
|
54145
|
+
projectId: params.projectId ?? null,
|
|
54146
|
+
organizationId: params.organizationId ?? null,
|
|
54147
|
+
ownership: params.ownership ?? "all",
|
|
54148
|
+
accessScope: params.accessScope ?? "explicit_member",
|
|
54149
|
+
createdBy: params.createdBy ?? null,
|
|
54150
|
+
forked: params.forked ?? "all"
|
|
54151
|
+
}
|
|
54152
|
+
},
|
|
54153
|
+
warnings: [],
|
|
54154
|
+
recommendedNextActions: apps.length > pagination.limit ? [`Pass offset=${pagination.offset + pagination.limit} to load the next page.`] : ["Use `remix_directory_get_app` for one app, or `remix_context_get_app_overview` for operational context on a chosen app."],
|
|
54155
|
+
logContext: {
|
|
54156
|
+
repoRoot: bindingContext.repoRoot,
|
|
54157
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54158
|
+
}
|
|
54159
|
+
};
|
|
54160
|
+
}
|
|
54161
|
+
async function getApp(params) {
|
|
54162
|
+
const api = await createApiClient2();
|
|
54163
|
+
const target = await resolveAppId(params);
|
|
54164
|
+
const app = unwrapResponseObject2(await api.getApp(target.appId), "app");
|
|
54165
|
+
return {
|
|
54166
|
+
data: { app },
|
|
54167
|
+
warnings: [],
|
|
54168
|
+
recommendedNextActions: ["Use `remix_context_get_app_overview` for status and capability context, or `remix_ops_list_timeline` for bounded historical activity."],
|
|
54169
|
+
logContext: {
|
|
54170
|
+
repoRoot: target.repoRoot,
|
|
54171
|
+
appId: target.appId
|
|
54172
|
+
}
|
|
54173
|
+
};
|
|
54174
|
+
}
|
|
54175
|
+
function getAnnotations2(access) {
|
|
54176
|
+
return {
|
|
54177
|
+
readOnlyHint: access === "read",
|
|
54178
|
+
destructiveHint: false,
|
|
54179
|
+
idempotentHint: true,
|
|
54180
|
+
openWorldHint: false
|
|
54181
|
+
};
|
|
54182
|
+
}
|
|
54183
|
+
function buildSuccessEnvelope2(tool, requestId, result) {
|
|
54184
|
+
return {
|
|
54185
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54186
|
+
ok: true,
|
|
54187
|
+
tool,
|
|
54188
|
+
requestId: requestId ?? null,
|
|
54189
|
+
data: result.data,
|
|
54190
|
+
warnings: result.warnings ?? [],
|
|
54191
|
+
risks: result.risks ?? [],
|
|
54192
|
+
recommendedNextActions: result.recommendedNextActions ?? []
|
|
54193
|
+
};
|
|
54194
|
+
}
|
|
54195
|
+
function deriveErrorRisks2(normalized) {
|
|
54196
|
+
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
54197
|
+
return ["A policy guard blocked a disallowed operation."];
|
|
54198
|
+
}
|
|
54199
|
+
return [];
|
|
54200
|
+
}
|
|
54201
|
+
function buildErrorEnvelope2(tool, requestId, error2) {
|
|
54202
|
+
const normalized = normalizeToolError(error2);
|
|
54203
|
+
return {
|
|
54204
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54205
|
+
ok: false,
|
|
54206
|
+
tool,
|
|
54207
|
+
requestId: requestId ?? null,
|
|
54208
|
+
error: normalized,
|
|
54209
|
+
warnings: [],
|
|
54210
|
+
risks: deriveErrorRisks2(normalized),
|
|
54211
|
+
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
54212
|
+
};
|
|
54213
|
+
}
|
|
54214
|
+
function registerTool2(server, context, params) {
|
|
54215
|
+
const errorSchema = makeErrorSchema();
|
|
54216
|
+
server.registerTool(
|
|
54217
|
+
params.name,
|
|
54218
|
+
{
|
|
54219
|
+
title: params.name,
|
|
54220
|
+
description: params.description,
|
|
54221
|
+
inputSchema: params.inputSchema,
|
|
54222
|
+
outputSchema: params.outputSchema,
|
|
54223
|
+
annotations: getAnnotations2(params.access)
|
|
54224
|
+
},
|
|
54225
|
+
async (rawArgs) => {
|
|
54226
|
+
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
54227
|
+
const startedAt = Date.now();
|
|
54228
|
+
try {
|
|
54229
|
+
assertToolAccess(context.policy, params.access);
|
|
54230
|
+
const result = await params.run(rawArgs);
|
|
54231
|
+
const envelope = buildSuccessEnvelope2(params.name, requestId, result);
|
|
54232
|
+
params.outputSchema.parse(envelope);
|
|
54233
|
+
context.logger.log({
|
|
54234
|
+
level: "info",
|
|
54235
|
+
message: "tool_completed",
|
|
54236
|
+
tool: params.name,
|
|
54237
|
+
requestId: envelope.requestId,
|
|
54238
|
+
durationMs: Date.now() - startedAt,
|
|
54239
|
+
result: "success",
|
|
54240
|
+
repoRoot: result.logContext?.repoRoot ?? null,
|
|
54241
|
+
appId: result.logContext?.appId ?? null,
|
|
54242
|
+
mrId: result.logContext?.mrId ?? null
|
|
54243
|
+
});
|
|
54244
|
+
return makeSuccessResult2(envelope);
|
|
54245
|
+
} catch (error2) {
|
|
54246
|
+
const envelope = buildErrorEnvelope2(params.name, requestId, error2);
|
|
54247
|
+
errorSchema.parse(envelope);
|
|
54248
|
+
context.logger.log({
|
|
54249
|
+
level: "error",
|
|
54250
|
+
message: "tool_failed",
|
|
54251
|
+
tool: params.name,
|
|
54252
|
+
requestId: envelope.requestId,
|
|
54253
|
+
durationMs: Date.now() - startedAt,
|
|
54254
|
+
result: "error",
|
|
54255
|
+
errorCode: envelope.error.code
|
|
54256
|
+
});
|
|
54257
|
+
return makeErrorResult(envelope);
|
|
54258
|
+
}
|
|
54259
|
+
}
|
|
54260
|
+
);
|
|
54261
|
+
}
|
|
54262
|
+
function registerIdentityTools(server, context) {
|
|
54263
|
+
registerTool2(server, context, {
|
|
54264
|
+
name: "remix_identity_whoami",
|
|
54265
|
+
description: "Show the authenticated Remix user and, when cwd is provided, the current local binding and any immediately derivable roles for that bound workspace.",
|
|
54266
|
+
access: "read",
|
|
54267
|
+
inputSchema: whoamiInputSchema,
|
|
54268
|
+
outputSchema: whoamiSuccessSchema,
|
|
54269
|
+
run: async (args) => {
|
|
54270
|
+
const input = external_exports.object(whoamiInputSchema).parse(args);
|
|
54271
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54272
|
+
return whoAmI({ cwd });
|
|
54273
|
+
}
|
|
54274
|
+
});
|
|
54275
|
+
registerTool2(server, context, {
|
|
54276
|
+
name: "remix_directory_list_organizations",
|
|
54277
|
+
description: "List organizations visible to the authenticated Remix user.",
|
|
54278
|
+
access: "read",
|
|
54279
|
+
inputSchema: whoamiInputSchema,
|
|
54280
|
+
outputSchema: listOrganizationsSuccessSchema,
|
|
54281
|
+
run: async () => listOrganizations()
|
|
54282
|
+
});
|
|
54283
|
+
registerTool2(server, context, {
|
|
54284
|
+
name: "remix_directory_get_organization",
|
|
54285
|
+
description: "Fetch one organization by id, or infer the bound repository's organization from cwd when possible.",
|
|
54286
|
+
access: "read",
|
|
54287
|
+
inputSchema: directoryOrganizationInputSchema,
|
|
54288
|
+
outputSchema: getOrganizationSuccessSchema,
|
|
54289
|
+
run: async (args) => {
|
|
54290
|
+
const input = external_exports.object(directoryOrganizationInputSchema).parse(args);
|
|
54291
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54292
|
+
return getOrganization({
|
|
54293
|
+
organizationId: input.organizationId,
|
|
54294
|
+
cwd
|
|
54295
|
+
});
|
|
54296
|
+
}
|
|
54297
|
+
});
|
|
54298
|
+
registerTool2(server, context, {
|
|
54299
|
+
name: "remix_directory_list_projects",
|
|
54300
|
+
description: "List projects visible to the authenticated user, optionally narrowed to one organization or client app.",
|
|
54301
|
+
access: "read",
|
|
54302
|
+
inputSchema: directoryListProjectsInputSchema,
|
|
54303
|
+
outputSchema: listProjectsSuccessSchema,
|
|
54304
|
+
run: async (args) => {
|
|
54305
|
+
const input = external_exports.object(directoryListProjectsInputSchema).parse(args);
|
|
54306
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54307
|
+
return listProjects({
|
|
54308
|
+
organizationId: input.organizationId,
|
|
54309
|
+
clientAppId: input.clientAppId,
|
|
54310
|
+
cwd
|
|
54311
|
+
});
|
|
54312
|
+
}
|
|
54313
|
+
});
|
|
54314
|
+
registerTool2(server, context, {
|
|
54315
|
+
name: "remix_directory_get_project",
|
|
54316
|
+
description: "Fetch one project by id, or infer the bound repository's project from cwd when possible.",
|
|
54317
|
+
access: "read",
|
|
54318
|
+
inputSchema: directoryProjectInputSchema,
|
|
54319
|
+
outputSchema: getProjectSuccessSchema,
|
|
54320
|
+
run: async (args) => {
|
|
54321
|
+
const input = external_exports.object(directoryProjectInputSchema).parse(args);
|
|
54322
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54323
|
+
return getProject({
|
|
54324
|
+
projectId: input.projectId,
|
|
54325
|
+
cwd
|
|
54326
|
+
});
|
|
54327
|
+
}
|
|
54328
|
+
});
|
|
54329
|
+
registerTool2(server, context, {
|
|
54330
|
+
name: "remix_directory_list_apps",
|
|
54331
|
+
description: "List apps visible to the authenticated user, with optional organization, project, ownership, and access-scope filters. Defaults to membership-oriented discovery unless accessScope=all_readable is passed explicitly.",
|
|
54332
|
+
access: "read",
|
|
54333
|
+
inputSchema: directoryListAppsInputSchema,
|
|
54334
|
+
outputSchema: listAppsSuccessSchema,
|
|
54335
|
+
run: async (args) => {
|
|
54336
|
+
const input = external_exports.object(directoryListAppsInputSchema).parse(args);
|
|
54337
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54338
|
+
return listApps2({
|
|
54339
|
+
projectId: input.projectId,
|
|
54340
|
+
organizationId: input.organizationId,
|
|
54341
|
+
ownership: input.ownership,
|
|
54342
|
+
accessScope: input.accessScope,
|
|
54343
|
+
createdBy: input.createdBy,
|
|
54344
|
+
forked: input.forked,
|
|
54345
|
+
limit: input.limit,
|
|
54346
|
+
offset: input.offset,
|
|
54347
|
+
cwd
|
|
54348
|
+
});
|
|
54349
|
+
}
|
|
54350
|
+
});
|
|
54351
|
+
registerTool2(server, context, {
|
|
54352
|
+
name: "remix_directory_get_app",
|
|
54353
|
+
description: "Fetch one app by id, or infer the bound repository's current app from cwd when possible.",
|
|
54354
|
+
access: "read",
|
|
54355
|
+
inputSchema: directoryAppInputSchema,
|
|
54356
|
+
outputSchema: getAppSuccessSchema,
|
|
54357
|
+
run: async (args) => {
|
|
54358
|
+
const input = external_exports.object(directoryAppInputSchema).parse(args);
|
|
54359
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54360
|
+
return getApp({
|
|
54361
|
+
appId: input.appId,
|
|
54362
|
+
cwd
|
|
54363
|
+
});
|
|
54364
|
+
}
|
|
54365
|
+
});
|
|
54366
|
+
}
|
|
54367
|
+
var genericRecordSchema3 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
54368
|
+
var genericArraySchema3 = external_exports.array(genericRecordSchema3);
|
|
52918
54369
|
var memoryKindSchema = external_exports.enum(["collab_turn", "change_step", "merge_request", "reconcile"]);
|
|
52919
|
-
var
|
|
54370
|
+
var paginationSchema3 = external_exports.object({
|
|
52920
54371
|
limit: external_exports.number().int().nonnegative(),
|
|
52921
54372
|
offset: external_exports.number().int().nonnegative(),
|
|
52922
54373
|
hasMore: external_exports.boolean()
|
|
@@ -52949,14 +54400,14 @@ var changeStepDiffInputSchema = {
|
|
|
52949
54400
|
appId: external_exports.string().trim().min(1).optional(),
|
|
52950
54401
|
changeStepId: external_exports.string().trim().min(1)
|
|
52951
54402
|
};
|
|
52952
|
-
var memorySummaryDataSchema =
|
|
54403
|
+
var memorySummaryDataSchema = genericRecordSchema3;
|
|
52953
54404
|
var memorySearchDataSchema = external_exports.object({
|
|
52954
|
-
items:
|
|
52955
|
-
pagination:
|
|
54405
|
+
items: genericArraySchema3,
|
|
54406
|
+
pagination: paginationSchema3
|
|
52956
54407
|
});
|
|
52957
54408
|
var memoryTimelineDataSchema = external_exports.object({
|
|
52958
|
-
items:
|
|
52959
|
-
pagination:
|
|
54409
|
+
items: genericArraySchema3,
|
|
54410
|
+
pagination: paginationSchema3
|
|
52960
54411
|
});
|
|
52961
54412
|
var changeStepDiffDataSchema = external_exports.object({
|
|
52962
54413
|
changeStepId: external_exports.string(),
|
|
@@ -53044,12 +54495,12 @@ function unwrapResponseObject22(resp, label) {
|
|
|
53044
54495
|
}
|
|
53045
54496
|
return obj;
|
|
53046
54497
|
}
|
|
53047
|
-
function
|
|
54498
|
+
function makeNotBoundError2() {
|
|
53048
54499
|
const error2 = new Error("Repository is not bound to Remix.");
|
|
53049
54500
|
error2.hint = "Run `remix_collab_init` in this repository, or pass `appId` explicitly for a direct memory read.";
|
|
53050
54501
|
return error2;
|
|
53051
54502
|
}
|
|
53052
|
-
async function
|
|
54503
|
+
async function maybeFindGitRoot2(cwd) {
|
|
53053
54504
|
try {
|
|
53054
54505
|
return await findGitRoot(cwd);
|
|
53055
54506
|
} catch {
|
|
@@ -53061,13 +54512,13 @@ async function resolveMemoryTarget(params) {
|
|
|
53061
54512
|
if (explicitAppId) {
|
|
53062
54513
|
return {
|
|
53063
54514
|
appId: explicitAppId,
|
|
53064
|
-
repoRoot: await
|
|
54515
|
+
repoRoot: await maybeFindGitRoot2(params.cwd)
|
|
53065
54516
|
};
|
|
53066
54517
|
}
|
|
53067
54518
|
const repoRoot = await findGitRoot(params.cwd);
|
|
53068
54519
|
const binding = await readCollabBinding(repoRoot);
|
|
53069
54520
|
if (!binding) {
|
|
53070
|
-
throw
|
|
54521
|
+
throw makeNotBoundError2();
|
|
53071
54522
|
}
|
|
53072
54523
|
return {
|
|
53073
54524
|
appId: binding.currentAppId,
|
|
@@ -53135,7 +54586,7 @@ async function getChangeStepDiff(params) {
|
|
|
53135
54586
|
logContext: target
|
|
53136
54587
|
};
|
|
53137
54588
|
}
|
|
53138
|
-
function
|
|
54589
|
+
function getAnnotations3(access) {
|
|
53139
54590
|
return {
|
|
53140
54591
|
readOnlyHint: access === "read",
|
|
53141
54592
|
destructiveHint: false,
|
|
@@ -53143,7 +54594,7 @@ function getAnnotations2(access) {
|
|
|
53143
54594
|
openWorldHint: false
|
|
53144
54595
|
};
|
|
53145
54596
|
}
|
|
53146
|
-
function
|
|
54597
|
+
function buildSuccessEnvelope3(tool, requestId, result) {
|
|
53147
54598
|
return {
|
|
53148
54599
|
schemaVersion: SCHEMA_VERSION,
|
|
53149
54600
|
ok: true,
|
|
@@ -53155,7 +54606,7 @@ function buildSuccessEnvelope2(tool, requestId, result) {
|
|
|
53155
54606
|
recommendedNextActions: result.recommendedNextActions ?? []
|
|
53156
54607
|
};
|
|
53157
54608
|
}
|
|
53158
|
-
function
|
|
54609
|
+
function buildErrorEnvelope3(tool, requestId, error2) {
|
|
53159
54610
|
const normalized = normalizeToolError(error2);
|
|
53160
54611
|
return {
|
|
53161
54612
|
schemaVersion: SCHEMA_VERSION,
|
|
@@ -53164,17 +54615,17 @@ function buildErrorEnvelope2(tool, requestId, error2) {
|
|
|
53164
54615
|
requestId: requestId ?? null,
|
|
53165
54616
|
error: normalized,
|
|
53166
54617
|
warnings: [],
|
|
53167
|
-
risks:
|
|
54618
|
+
risks: deriveErrorRisks3(normalized),
|
|
53168
54619
|
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
53169
54620
|
};
|
|
53170
54621
|
}
|
|
53171
|
-
function
|
|
54622
|
+
function deriveErrorRisks3(normalized) {
|
|
53172
54623
|
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
53173
54624
|
return ["A policy guard blocked a disallowed operation."];
|
|
53174
54625
|
}
|
|
53175
54626
|
return [];
|
|
53176
54627
|
}
|
|
53177
|
-
function
|
|
54628
|
+
function registerTool3(server, context, params) {
|
|
53178
54629
|
const errorSchema = makeErrorSchema();
|
|
53179
54630
|
server.registerTool(
|
|
53180
54631
|
params.name,
|
|
@@ -53183,7 +54634,7 @@ function registerTool2(server, context, params) {
|
|
|
53183
54634
|
description: params.description,
|
|
53184
54635
|
inputSchema: params.inputSchema,
|
|
53185
54636
|
outputSchema: params.outputSchema,
|
|
53186
|
-
annotations:
|
|
54637
|
+
annotations: getAnnotations3(params.access)
|
|
53187
54638
|
},
|
|
53188
54639
|
async (rawArgs) => {
|
|
53189
54640
|
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
@@ -53191,7 +54642,7 @@ function registerTool2(server, context, params) {
|
|
|
53191
54642
|
try {
|
|
53192
54643
|
assertToolAccess(context.policy, params.access);
|
|
53193
54644
|
const result = await params.run(rawArgs);
|
|
53194
|
-
const envelope =
|
|
54645
|
+
const envelope = buildSuccessEnvelope3(params.name, requestId, result);
|
|
53195
54646
|
params.outputSchema.parse(envelope);
|
|
53196
54647
|
context.logger.log({
|
|
53197
54648
|
level: "info",
|
|
@@ -53207,7 +54658,7 @@ function registerTool2(server, context, params) {
|
|
|
53207
54658
|
});
|
|
53208
54659
|
return makeSuccessResult2(envelope);
|
|
53209
54660
|
} catch (error2) {
|
|
53210
|
-
const envelope =
|
|
54661
|
+
const envelope = buildErrorEnvelope3(params.name, requestId, error2);
|
|
53211
54662
|
errorSchema.parse(envelope);
|
|
53212
54663
|
context.logger.log({
|
|
53213
54664
|
level: "error",
|
|
@@ -53224,7 +54675,7 @@ function registerTool2(server, context, params) {
|
|
|
53224
54675
|
);
|
|
53225
54676
|
}
|
|
53226
54677
|
function registerMemoryTools(server, context) {
|
|
53227
|
-
|
|
54678
|
+
registerTool3(server, context, {
|
|
53228
54679
|
name: "remix_collab_memory_summary",
|
|
53229
54680
|
description: "First read for a bound app's current collaboration state, recent reasoning context, and merge or reconcile history before deeper inspection or any raw git history lookup.",
|
|
53230
54681
|
access: "read",
|
|
@@ -53239,7 +54690,7 @@ function registerMemoryTools(server, context) {
|
|
|
53239
54690
|
});
|
|
53240
54691
|
}
|
|
53241
54692
|
});
|
|
53242
|
-
|
|
54693
|
+
registerTool3(server, context, {
|
|
53243
54694
|
name: "remix_collab_memory_search",
|
|
53244
54695
|
description: "Default tool for why/history/failed-attempt/user-intent questions. Search prompts, diffs, merge activity, reconciles, and other historical context before using raw git for exact repository facts.",
|
|
53245
54696
|
access: "read",
|
|
@@ -53260,7 +54711,7 @@ function registerMemoryTools(server, context) {
|
|
|
53260
54711
|
});
|
|
53261
54712
|
}
|
|
53262
54713
|
});
|
|
53263
|
-
|
|
54714
|
+
registerTool3(server, context, {
|
|
53264
54715
|
name: "remix_collab_memory_timeline",
|
|
53265
54716
|
description: "Chronological view of collaboration memory for understanding what happened and in what order, with optional filters for bounded historical inspection before any exact-facts raw git follow-up.",
|
|
53266
54717
|
access: "read",
|
|
@@ -53280,7 +54731,7 @@ function registerMemoryTools(server, context) {
|
|
|
53280
54731
|
});
|
|
53281
54732
|
}
|
|
53282
54733
|
});
|
|
53283
|
-
|
|
54734
|
+
registerTool3(server, context, {
|
|
53284
54735
|
name: "remix_collab_memory_change_step_diff",
|
|
53285
54736
|
description: "Second-hop expansion tool that fetches the full stored diff for a specific change step after memory search, timeline, or review work has identified the relevant `changeStepId`, keeping historical inspection inside Remix before raw git fallback.",
|
|
53286
54737
|
access: "read",
|
|
@@ -53297,13 +54748,441 @@ function registerMemoryTools(server, context) {
|
|
|
53297
54748
|
}
|
|
53298
54749
|
});
|
|
53299
54750
|
}
|
|
54751
|
+
var genericRecordSchema4 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
54752
|
+
var appScopedInputSchema = {
|
|
54753
|
+
...commonRequestFieldsSchema,
|
|
54754
|
+
appId: external_exports.string().trim().min(1).optional()
|
|
54755
|
+
};
|
|
54756
|
+
var editQueueInputSchema = {
|
|
54757
|
+
...appScopedInputSchema,
|
|
54758
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54759
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
54760
|
+
};
|
|
54761
|
+
var bundleInputSchema = {
|
|
54762
|
+
...appScopedInputSchema,
|
|
54763
|
+
bundleId: external_exports.string().trim().min(1)
|
|
54764
|
+
};
|
|
54765
|
+
var timelineInputSchema = {
|
|
54766
|
+
...appScopedInputSchema,
|
|
54767
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54768
|
+
cursor: external_exports.string().trim().min(1).optional()
|
|
54769
|
+
};
|
|
54770
|
+
var agentRunsInputSchema = {
|
|
54771
|
+
...appScopedInputSchema,
|
|
54772
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54773
|
+
offset: external_exports.number().int().nonnegative().optional(),
|
|
54774
|
+
status: external_exports.string().trim().min(1).optional(),
|
|
54775
|
+
currentPhase: external_exports.string().trim().min(1).optional(),
|
|
54776
|
+
createdAfter: external_exports.string().datetime().optional(),
|
|
54777
|
+
createdBefore: external_exports.string().datetime().optional()
|
|
54778
|
+
};
|
|
54779
|
+
var agentRunInputSchema = {
|
|
54780
|
+
...appScopedInputSchema,
|
|
54781
|
+
runId: external_exports.string().trim().min(1)
|
|
54782
|
+
};
|
|
54783
|
+
var agentRunEventsInputSchema = {
|
|
54784
|
+
...appScopedInputSchema,
|
|
54785
|
+
runId: external_exports.string().trim().min(1),
|
|
54786
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54787
|
+
offset: external_exports.number().int().nonnegative().optional(),
|
|
54788
|
+
createdAfter: external_exports.string().datetime().optional(),
|
|
54789
|
+
createdBefore: external_exports.string().datetime().optional()
|
|
54790
|
+
};
|
|
54791
|
+
var appOverviewSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54792
|
+
var editQueueSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54793
|
+
var bundleSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54794
|
+
var timelineSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54795
|
+
var agentRunsSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54796
|
+
var agentRunSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54797
|
+
var agentRunEventsSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54798
|
+
var sandboxStatusSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54799
|
+
async function resolveAppTarget(_api, params) {
|
|
54800
|
+
const explicitAppId = params.appId?.trim();
|
|
54801
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54802
|
+
if (explicitAppId) {
|
|
54803
|
+
return {
|
|
54804
|
+
appId: explicitAppId,
|
|
54805
|
+
repoRoot: bindingContext.repoRoot
|
|
54806
|
+
};
|
|
54807
|
+
}
|
|
54808
|
+
if (!bindingContext.binding) {
|
|
54809
|
+
throw makeNotBoundError("App id was not provided and the current repository is not bound to Remix.");
|
|
54810
|
+
}
|
|
54811
|
+
return {
|
|
54812
|
+
appId: bindingContext.binding.currentAppId,
|
|
54813
|
+
repoRoot: bindingContext.repoRoot
|
|
54814
|
+
};
|
|
54815
|
+
}
|
|
54816
|
+
async function getAppOverview(params) {
|
|
54817
|
+
const api = await createApiClient2();
|
|
54818
|
+
const target = await resolveAppTarget(api, params);
|
|
54819
|
+
const data = unwrapResponseObject2(await api.getAppOverview(target.appId), "app overview");
|
|
54820
|
+
return {
|
|
54821
|
+
data,
|
|
54822
|
+
warnings: [],
|
|
54823
|
+
recommendedNextActions: [
|
|
54824
|
+
"Use `remix_ops_list_timeline`, `remix_ops_list_agent_runs`, `remix_ops_get_edit_queue`, or `remix_ops_get_sandbox_status` for the next operational drill-down on this app."
|
|
54825
|
+
],
|
|
54826
|
+
logContext: target
|
|
54827
|
+
};
|
|
54828
|
+
}
|
|
54829
|
+
async function getEditQueue(params) {
|
|
54830
|
+
const api = await createApiClient2();
|
|
54831
|
+
const target = await resolveAppTarget(api, params);
|
|
54832
|
+
const data = unwrapResponseObject2(
|
|
54833
|
+
await api.listAppEditQueue(target.appId, {
|
|
54834
|
+
limit: params.limit,
|
|
54835
|
+
offset: params.offset
|
|
54836
|
+
}),
|
|
54837
|
+
"edit queue"
|
|
54838
|
+
);
|
|
54839
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54840
|
+
return {
|
|
54841
|
+
data,
|
|
54842
|
+
warnings: [],
|
|
54843
|
+
recommendedNextActions: pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number" ? [`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next edit queue page.`] : [],
|
|
54844
|
+
logContext: target
|
|
54845
|
+
};
|
|
54846
|
+
}
|
|
54847
|
+
async function getBundle(params) {
|
|
54848
|
+
const api = await createApiClient2();
|
|
54849
|
+
const target = await resolveAppTarget(api, params);
|
|
54850
|
+
const data = unwrapResponseObject2(await api.getBundle(target.appId, params.bundleId), "bundle");
|
|
54851
|
+
return {
|
|
54852
|
+
data,
|
|
54853
|
+
warnings: [],
|
|
54854
|
+
recommendedNextActions: ["Use the bundle download-url client methods only when you need the actual artifact, not just metadata inspection."],
|
|
54855
|
+
logContext: target
|
|
54856
|
+
};
|
|
54857
|
+
}
|
|
54858
|
+
async function listTimeline(params) {
|
|
54859
|
+
const api = await createApiClient2();
|
|
54860
|
+
const target = await resolveAppTarget(api, params);
|
|
54861
|
+
const data = unwrapResponseObject2(
|
|
54862
|
+
await api.listAppTimeline(target.appId, {
|
|
54863
|
+
limit: params.limit,
|
|
54864
|
+
cursor: params.cursor
|
|
54865
|
+
}),
|
|
54866
|
+
"app timeline"
|
|
54867
|
+
);
|
|
54868
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54869
|
+
return {
|
|
54870
|
+
data,
|
|
54871
|
+
warnings: [],
|
|
54872
|
+
recommendedNextActions: pageInfo?.hasMore === true && typeof pageInfo.nextCursor === "string" ? [`Pass cursor=${pageInfo.nextCursor} to load the next timeline page.`] : [],
|
|
54873
|
+
logContext: target
|
|
54874
|
+
};
|
|
54875
|
+
}
|
|
54876
|
+
async function listAgentRuns(params) {
|
|
54877
|
+
const api = await createApiClient2();
|
|
54878
|
+
const target = await resolveAppTarget(api, params);
|
|
54879
|
+
const data = unwrapResponseObject2(
|
|
54880
|
+
await api.listAgentRuns(target.appId, {
|
|
54881
|
+
limit: params.limit,
|
|
54882
|
+
offset: params.offset,
|
|
54883
|
+
status: params.status,
|
|
54884
|
+
currentPhase: params.currentPhase,
|
|
54885
|
+
createdAfter: params.createdAfter,
|
|
54886
|
+
createdBefore: params.createdBefore
|
|
54887
|
+
}),
|
|
54888
|
+
"agent runs"
|
|
54889
|
+
);
|
|
54890
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54891
|
+
const items = Array.isArray(data.items) ? data.items : [];
|
|
54892
|
+
const firstRunId = items.length > 0 && items[0] && typeof items[0] === "object" && typeof items[0].id === "string" ? items[0].id : null;
|
|
54893
|
+
const recommendedNextActions = [];
|
|
54894
|
+
if (firstRunId) {
|
|
54895
|
+
recommendedNextActions.push(
|
|
54896
|
+
`Use \`remix_ops_get_agent_run\` with \`runId=${firstRunId}\` for the top listed run, then \`remix_ops_list_agent_run_events\` if you need its event stream.`
|
|
54897
|
+
);
|
|
54898
|
+
}
|
|
54899
|
+
if (pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number") {
|
|
54900
|
+
recommendedNextActions.push(`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next agent-runs page.`);
|
|
54901
|
+
}
|
|
54902
|
+
return {
|
|
54903
|
+
data,
|
|
54904
|
+
warnings: [],
|
|
54905
|
+
recommendedNextActions,
|
|
54906
|
+
logContext: target
|
|
54907
|
+
};
|
|
54908
|
+
}
|
|
54909
|
+
async function getAgentRun(params) {
|
|
54910
|
+
const api = await createApiClient2();
|
|
54911
|
+
const target = await resolveAppTarget(api, params);
|
|
54912
|
+
const data = unwrapResponseObject2(await api.getAgentRun(target.appId, params.runId), "agent run");
|
|
54913
|
+
return {
|
|
54914
|
+
data,
|
|
54915
|
+
warnings: [],
|
|
54916
|
+
recommendedNextActions: [`Use \`remix_ops_list_agent_run_events\` with \`runId=${params.runId}\` for the event stream behind this run.`],
|
|
54917
|
+
logContext: target
|
|
54918
|
+
};
|
|
54919
|
+
}
|
|
54920
|
+
async function listAgentRunEvents(params) {
|
|
54921
|
+
const api = await createApiClient2();
|
|
54922
|
+
const target = await resolveAppTarget(api, params);
|
|
54923
|
+
const data = unwrapResponseObject2(
|
|
54924
|
+
await api.listAgentRunEvents(target.appId, params.runId, {
|
|
54925
|
+
limit: params.limit,
|
|
54926
|
+
offset: params.offset,
|
|
54927
|
+
createdAfter: params.createdAfter,
|
|
54928
|
+
createdBefore: params.createdBefore
|
|
54929
|
+
}),
|
|
54930
|
+
"agent run events"
|
|
54931
|
+
);
|
|
54932
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54933
|
+
return {
|
|
54934
|
+
data,
|
|
54935
|
+
warnings: [],
|
|
54936
|
+
recommendedNextActions: pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number" ? [`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next event page.`] : [],
|
|
54937
|
+
logContext: target
|
|
54938
|
+
};
|
|
54939
|
+
}
|
|
54940
|
+
async function getSandboxStatus(params) {
|
|
54941
|
+
const api = await createApiClient2();
|
|
54942
|
+
const target = await resolveAppTarget(api, params);
|
|
54943
|
+
const data = unwrapResponseObject2(await api.getSandboxStatus(target.appId), "sandbox status");
|
|
54944
|
+
return {
|
|
54945
|
+
data,
|
|
54946
|
+
warnings: [],
|
|
54947
|
+
recommendedNextActions: ["Use the sandbox metadata here to decide whether a resume is plausible before attempting any write-side sandbox action."],
|
|
54948
|
+
logContext: target
|
|
54949
|
+
};
|
|
54950
|
+
}
|
|
54951
|
+
function getAnnotations4(access) {
|
|
54952
|
+
return {
|
|
54953
|
+
readOnlyHint: access === "read",
|
|
54954
|
+
destructiveHint: false,
|
|
54955
|
+
idempotentHint: true,
|
|
54956
|
+
openWorldHint: false
|
|
54957
|
+
};
|
|
54958
|
+
}
|
|
54959
|
+
function buildSuccessEnvelope4(tool, requestId, result) {
|
|
54960
|
+
return {
|
|
54961
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54962
|
+
ok: true,
|
|
54963
|
+
tool,
|
|
54964
|
+
requestId: requestId ?? null,
|
|
54965
|
+
data: result.data,
|
|
54966
|
+
warnings: result.warnings ?? [],
|
|
54967
|
+
risks: result.risks ?? [],
|
|
54968
|
+
recommendedNextActions: result.recommendedNextActions ?? []
|
|
54969
|
+
};
|
|
54970
|
+
}
|
|
54971
|
+
function deriveErrorRisks4(normalized) {
|
|
54972
|
+
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
54973
|
+
return ["A policy guard blocked a disallowed operation."];
|
|
54974
|
+
}
|
|
54975
|
+
return [];
|
|
54976
|
+
}
|
|
54977
|
+
function buildErrorEnvelope4(tool, requestId, error2) {
|
|
54978
|
+
const normalized = normalizeToolError(error2);
|
|
54979
|
+
return {
|
|
54980
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54981
|
+
ok: false,
|
|
54982
|
+
tool,
|
|
54983
|
+
requestId: requestId ?? null,
|
|
54984
|
+
error: normalized,
|
|
54985
|
+
warnings: [],
|
|
54986
|
+
risks: deriveErrorRisks4(normalized),
|
|
54987
|
+
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
54988
|
+
};
|
|
54989
|
+
}
|
|
54990
|
+
function registerTool4(server, context, params) {
|
|
54991
|
+
const errorSchema = makeErrorSchema();
|
|
54992
|
+
server.registerTool(
|
|
54993
|
+
params.name,
|
|
54994
|
+
{
|
|
54995
|
+
title: params.name,
|
|
54996
|
+
description: params.description,
|
|
54997
|
+
inputSchema: params.inputSchema,
|
|
54998
|
+
outputSchema: params.outputSchema,
|
|
54999
|
+
annotations: getAnnotations4(params.access)
|
|
55000
|
+
},
|
|
55001
|
+
async (rawArgs) => {
|
|
55002
|
+
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
55003
|
+
const startedAt = Date.now();
|
|
55004
|
+
try {
|
|
55005
|
+
assertToolAccess(context.policy, params.access);
|
|
55006
|
+
const result = await params.run(rawArgs);
|
|
55007
|
+
const envelope = buildSuccessEnvelope4(params.name, requestId, result);
|
|
55008
|
+
params.outputSchema.parse(envelope);
|
|
55009
|
+
context.logger.log({
|
|
55010
|
+
level: "info",
|
|
55011
|
+
message: "tool_completed",
|
|
55012
|
+
tool: params.name,
|
|
55013
|
+
requestId: envelope.requestId,
|
|
55014
|
+
durationMs: Date.now() - startedAt,
|
|
55015
|
+
result: "success",
|
|
55016
|
+
repoRoot: result.logContext?.repoRoot ?? null,
|
|
55017
|
+
appId: result.logContext?.appId ?? null,
|
|
55018
|
+
mrId: result.logContext?.mrId ?? null
|
|
55019
|
+
});
|
|
55020
|
+
return makeSuccessResult2(envelope);
|
|
55021
|
+
} catch (error2) {
|
|
55022
|
+
const envelope = buildErrorEnvelope4(params.name, requestId, error2);
|
|
55023
|
+
errorSchema.parse(envelope);
|
|
55024
|
+
context.logger.log({
|
|
55025
|
+
level: "error",
|
|
55026
|
+
message: "tool_failed",
|
|
55027
|
+
tool: params.name,
|
|
55028
|
+
requestId: envelope.requestId,
|
|
55029
|
+
durationMs: Date.now() - startedAt,
|
|
55030
|
+
result: "error",
|
|
55031
|
+
errorCode: envelope.error.code
|
|
55032
|
+
});
|
|
55033
|
+
return makeErrorResult(envelope);
|
|
55034
|
+
}
|
|
55035
|
+
}
|
|
55036
|
+
);
|
|
55037
|
+
}
|
|
55038
|
+
function registerOpsTools(server, context) {
|
|
55039
|
+
registerTool4(server, context, {
|
|
55040
|
+
name: "remix_context_get_app_overview",
|
|
55041
|
+
description: "Read the current app's overview, capabilities, and workflow readiness without mutating state.",
|
|
55042
|
+
access: "read",
|
|
55043
|
+
inputSchema: appScopedInputSchema,
|
|
55044
|
+
outputSchema: appOverviewSuccessSchema,
|
|
55045
|
+
run: async (args) => {
|
|
55046
|
+
const input = external_exports.object(appScopedInputSchema).parse(args);
|
|
55047
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55048
|
+
return getAppOverview({
|
|
55049
|
+
appId: input.appId,
|
|
55050
|
+
cwd
|
|
55051
|
+
});
|
|
55052
|
+
}
|
|
55053
|
+
});
|
|
55054
|
+
registerTool4(server, context, {
|
|
55055
|
+
name: "remix_ops_get_edit_queue",
|
|
55056
|
+
description: "Inspect the pending edit queue for one app with bounded pagination.",
|
|
55057
|
+
access: "read",
|
|
55058
|
+
inputSchema: editQueueInputSchema,
|
|
55059
|
+
outputSchema: editQueueSuccessSchema,
|
|
55060
|
+
run: async (args) => {
|
|
55061
|
+
const input = external_exports.object(editQueueInputSchema).parse(args);
|
|
55062
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55063
|
+
return getEditQueue({
|
|
55064
|
+
appId: input.appId,
|
|
55065
|
+
cwd,
|
|
55066
|
+
limit: input.limit,
|
|
55067
|
+
offset: input.offset
|
|
55068
|
+
});
|
|
55069
|
+
}
|
|
55070
|
+
});
|
|
55071
|
+
registerTool4(server, context, {
|
|
55072
|
+
name: "remix_ops_get_bundle",
|
|
55073
|
+
description: "Inspect one app bundle by id without downloading the artifact payload.",
|
|
55074
|
+
access: "read",
|
|
55075
|
+
inputSchema: bundleInputSchema,
|
|
55076
|
+
outputSchema: bundleSuccessSchema,
|
|
55077
|
+
run: async (args) => {
|
|
55078
|
+
const input = external_exports.object(bundleInputSchema).parse(args);
|
|
55079
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55080
|
+
return getBundle({
|
|
55081
|
+
appId: input.appId,
|
|
55082
|
+
cwd,
|
|
55083
|
+
bundleId: input.bundleId
|
|
55084
|
+
});
|
|
55085
|
+
}
|
|
55086
|
+
});
|
|
55087
|
+
registerTool4(server, context, {
|
|
55088
|
+
name: "remix_ops_list_timeline",
|
|
55089
|
+
description: "List bounded timeline events for one app using the backend cursor pagination model.",
|
|
55090
|
+
access: "read",
|
|
55091
|
+
inputSchema: timelineInputSchema,
|
|
55092
|
+
outputSchema: timelineSuccessSchema,
|
|
55093
|
+
run: async (args) => {
|
|
55094
|
+
const input = external_exports.object(timelineInputSchema).parse(args);
|
|
55095
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55096
|
+
return listTimeline({
|
|
55097
|
+
appId: input.appId,
|
|
55098
|
+
cwd,
|
|
55099
|
+
limit: input.limit,
|
|
55100
|
+
cursor: input.cursor
|
|
55101
|
+
});
|
|
55102
|
+
}
|
|
55103
|
+
});
|
|
55104
|
+
registerTool4(server, context, {
|
|
55105
|
+
name: "remix_ops_get_agent_run",
|
|
55106
|
+
description: "Fetch one stored agent run for an app, including status, phase, and summary metadata.",
|
|
55107
|
+
access: "read",
|
|
55108
|
+
inputSchema: agentRunInputSchema,
|
|
55109
|
+
outputSchema: agentRunSuccessSchema,
|
|
55110
|
+
run: async (args) => {
|
|
55111
|
+
const input = external_exports.object(agentRunInputSchema).parse(args);
|
|
55112
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55113
|
+
return getAgentRun({
|
|
55114
|
+
appId: input.appId,
|
|
55115
|
+
cwd,
|
|
55116
|
+
runId: input.runId
|
|
55117
|
+
});
|
|
55118
|
+
}
|
|
55119
|
+
});
|
|
55120
|
+
registerTool4(server, context, {
|
|
55121
|
+
name: "remix_ops_list_agent_runs",
|
|
55122
|
+
description: "List paginated agent runs for one app so run ids can be discovered before deeper inspection.",
|
|
55123
|
+
access: "read",
|
|
55124
|
+
inputSchema: agentRunsInputSchema,
|
|
55125
|
+
outputSchema: agentRunsSuccessSchema,
|
|
55126
|
+
run: async (args) => {
|
|
55127
|
+
const input = external_exports.object(agentRunsInputSchema).parse(args);
|
|
55128
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55129
|
+
return listAgentRuns({
|
|
55130
|
+
appId: input.appId,
|
|
55131
|
+
cwd,
|
|
55132
|
+
limit: input.limit,
|
|
55133
|
+
offset: input.offset,
|
|
55134
|
+
status: input.status,
|
|
55135
|
+
currentPhase: input.currentPhase,
|
|
55136
|
+
createdAfter: input.createdAfter,
|
|
55137
|
+
createdBefore: input.createdBefore
|
|
55138
|
+
});
|
|
55139
|
+
}
|
|
55140
|
+
});
|
|
55141
|
+
registerTool4(server, context, {
|
|
55142
|
+
name: "remix_ops_list_agent_run_events",
|
|
55143
|
+
description: "List paginated agent-run events for one stored run, with optional time bounds.",
|
|
55144
|
+
access: "read",
|
|
55145
|
+
inputSchema: agentRunEventsInputSchema,
|
|
55146
|
+
outputSchema: agentRunEventsSuccessSchema,
|
|
55147
|
+
run: async (args) => {
|
|
55148
|
+
const input = external_exports.object(agentRunEventsInputSchema).parse(args);
|
|
55149
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55150
|
+
return listAgentRunEvents({
|
|
55151
|
+
appId: input.appId,
|
|
55152
|
+
cwd,
|
|
55153
|
+
runId: input.runId,
|
|
55154
|
+
limit: input.limit,
|
|
55155
|
+
offset: input.offset,
|
|
55156
|
+
createdAfter: input.createdAfter,
|
|
55157
|
+
createdBefore: input.createdBefore
|
|
55158
|
+
});
|
|
55159
|
+
}
|
|
55160
|
+
});
|
|
55161
|
+
registerTool4(server, context, {
|
|
55162
|
+
name: "remix_ops_get_sandbox_status",
|
|
55163
|
+
description: "Read safe sandbox metadata and the latest migration status for one app without exposing execution handles or secrets.",
|
|
55164
|
+
access: "read",
|
|
55165
|
+
inputSchema: appScopedInputSchema,
|
|
55166
|
+
outputSchema: sandboxStatusSuccessSchema,
|
|
55167
|
+
run: async (args) => {
|
|
55168
|
+
const input = external_exports.object(appScopedInputSchema).parse(args);
|
|
55169
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55170
|
+
return getSandboxStatus({
|
|
55171
|
+
appId: input.appId,
|
|
55172
|
+
cwd
|
|
55173
|
+
});
|
|
55174
|
+
}
|
|
55175
|
+
});
|
|
55176
|
+
}
|
|
53300
55177
|
function createRemixMcpServer(params) {
|
|
53301
55178
|
const context = createServerContext({ version: params.version });
|
|
53302
55179
|
const server = new McpServer({
|
|
53303
55180
|
name: context.serverName,
|
|
53304
55181
|
version: context.version
|
|
53305
55182
|
});
|
|
55183
|
+
registerIdentityTools(server, context);
|
|
53306
55184
|
registerCollabTools(server, context);
|
|
55185
|
+
registerOpsTools(server, context);
|
|
53307
55186
|
registerMemoryTools(server, context);
|
|
53308
55187
|
return { server, context };
|
|
53309
55188
|
}
|
|
@@ -53450,7 +55329,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
53450
55329
|
// package.json
|
|
53451
55330
|
var package_default = {
|
|
53452
55331
|
name: "@remixhq/claude-plugin",
|
|
53453
|
-
version: "0.1.
|
|
55332
|
+
version: "0.1.15",
|
|
53454
55333
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
53455
55334
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
53456
55335
|
license: "MIT",
|
|
@@ -53481,8 +55360,8 @@ var package_default = {
|
|
|
53481
55360
|
prepack: "npm run build"
|
|
53482
55361
|
},
|
|
53483
55362
|
dependencies: {
|
|
53484
|
-
"@remixhq/core": "^0.1.
|
|
53485
|
-
"@remixhq/mcp": "^0.1.
|
|
55363
|
+
"@remixhq/core": "^0.1.10",
|
|
55364
|
+
"@remixhq/mcp": "^0.1.10"
|
|
53486
55365
|
},
|
|
53487
55366
|
devDependencies: {
|
|
53488
55367
|
"@types/node": "^25.4.0",
|
|
@@ -53575,7 +55454,7 @@ var outputSchema = external_exports.object({
|
|
|
53575
55454
|
toolName: external_exports.string().nullable(),
|
|
53576
55455
|
repoRoot: external_exports.string().nullable(),
|
|
53577
55456
|
message: external_exports.string().nullable(),
|
|
53578
|
-
fields: external_exports.record(external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]))
|
|
55457
|
+
fields: external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]))
|
|
53579
55458
|
})
|
|
53580
55459
|
),
|
|
53581
55460
|
pendingStates: external_exports.array(
|