@remixhq/claude-plugin 0.1.12 → 0.1.14
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 +5 -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 +136 -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 +2087 -238
- 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 +31 -0
- package/skills/init-or-remix/SKILL.md +1 -1
- 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-XC2FV57P.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;
|
|
@@ -21628,10 +21628,29 @@ function createApiClient(config2, opts) {
|
|
|
21628
21628
|
if (params?.projectId) qs.set("projectId", params.projectId);
|
|
21629
21629
|
if (params?.organizationId) qs.set("organizationId", params.organizationId);
|
|
21630
21630
|
if (params?.forked) qs.set("forked", params.forked);
|
|
21631
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21632
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21631
21633
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21632
21634
|
return request(`/v1/apps${suffix}`, { method: "GET" });
|
|
21633
21635
|
},
|
|
21634
21636
|
getApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}`, { method: "GET" }),
|
|
21637
|
+
getAppContext: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/context`, { method: "GET" }),
|
|
21638
|
+
getAppOverview: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/overview`, { method: "GET" }),
|
|
21639
|
+
listAppTimeline: (appId, params) => {
|
|
21640
|
+
const qs = new URLSearchParams();
|
|
21641
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21642
|
+
if (params?.cursor) qs.set("cursor", params.cursor);
|
|
21643
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21644
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/timeline${suffix}`, { method: "GET" });
|
|
21645
|
+
},
|
|
21646
|
+
getAppTimelineEvent: (appId, eventId) => request(`/v1/apps/${encodeURIComponent(appId)}/timeline/${encodeURIComponent(eventId)}`, { method: "GET" }),
|
|
21647
|
+
listAppEditQueue: (appId, params) => {
|
|
21648
|
+
const qs = new URLSearchParams();
|
|
21649
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21650
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21651
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21652
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/edit-queue${suffix}`, { method: "GET" });
|
|
21653
|
+
},
|
|
21635
21654
|
getMergeRequest: (mrId) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}`, { method: "GET" }),
|
|
21636
21655
|
presignImportUpload: (payload) => request("/v1/apps/import/upload/presign", { method: "POST", body: JSON.stringify(payload) }),
|
|
21637
21656
|
importFromUpload: (payload) => request("/v1/apps/import/upload", { method: "POST", body: JSON.stringify(payload) }),
|
|
@@ -21713,6 +21732,8 @@ function createApiClient(config2, opts) {
|
|
|
21713
21732
|
qs.set("status", params.status);
|
|
21714
21733
|
}
|
|
21715
21734
|
if (params?.kind) qs.set("kind", params.kind);
|
|
21735
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21736
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21716
21737
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21717
21738
|
return request(`/v1/merge-requests${suffix}`, { method: "GET" });
|
|
21718
21739
|
},
|
|
@@ -21731,24 +21752,60 @@ function createApiClient(config2, opts) {
|
|
|
21731
21752
|
method: "POST",
|
|
21732
21753
|
body: JSON.stringify(payload)
|
|
21733
21754
|
}),
|
|
21734
|
-
listOrganizationMembers: (orgId) =>
|
|
21755
|
+
listOrganizationMembers: (orgId, params) => {
|
|
21756
|
+
const qs = new URLSearchParams();
|
|
21757
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21758
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21759
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21760
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/members${suffix}`, { method: "GET" });
|
|
21761
|
+
},
|
|
21735
21762
|
updateOrganizationMember: (orgId, userId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/members/${encodeURIComponent(userId)}`, {
|
|
21736
21763
|
method: "PATCH",
|
|
21737
21764
|
body: JSON.stringify(payload)
|
|
21738
21765
|
}),
|
|
21739
|
-
listProjectMembers: (projectId) =>
|
|
21766
|
+
listProjectMembers: (projectId, params) => {
|
|
21767
|
+
const qs = new URLSearchParams();
|
|
21768
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21769
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21770
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21771
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/members${suffix}`, { method: "GET" });
|
|
21772
|
+
},
|
|
21740
21773
|
updateProjectMember: (projectId, userId, payload) => request(`/v1/projects/${encodeURIComponent(projectId)}/members/${encodeURIComponent(userId)}`, {
|
|
21741
21774
|
method: "PATCH",
|
|
21742
21775
|
body: JSON.stringify(payload)
|
|
21743
21776
|
}),
|
|
21744
|
-
listAppMembers: (appId) =>
|
|
21777
|
+
listAppMembers: (appId, params) => {
|
|
21778
|
+
const qs = new URLSearchParams();
|
|
21779
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21780
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21781
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21782
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/members${suffix}`, { method: "GET" });
|
|
21783
|
+
},
|
|
21745
21784
|
updateAppMember: (appId, userId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/members/${encodeURIComponent(userId)}`, {
|
|
21746
21785
|
method: "PATCH",
|
|
21747
21786
|
body: JSON.stringify(payload)
|
|
21748
21787
|
}),
|
|
21749
|
-
listOrganizationInvites: (orgId) =>
|
|
21750
|
-
|
|
21751
|
-
|
|
21788
|
+
listOrganizationInvites: (orgId, params) => {
|
|
21789
|
+
const qs = new URLSearchParams();
|
|
21790
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21791
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21792
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21793
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations${suffix}`, { method: "GET" });
|
|
21794
|
+
},
|
|
21795
|
+
listProjectInvites: (projectId, params) => {
|
|
21796
|
+
const qs = new URLSearchParams();
|
|
21797
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21798
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21799
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21800
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/invitations${suffix}`, { method: "GET" });
|
|
21801
|
+
},
|
|
21802
|
+
listAppInvites: (appId, params) => {
|
|
21803
|
+
const qs = new URLSearchParams();
|
|
21804
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21805
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21806
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21807
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/invitations${suffix}`, { method: "GET" });
|
|
21808
|
+
},
|
|
21752
21809
|
resendOrganizationInvite: (orgId, inviteId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
|
|
21753
21810
|
method: "POST",
|
|
21754
21811
|
body: JSON.stringify(payload ?? {})
|
|
@@ -21770,6 +21827,7 @@ function createApiClient(config2, opts) {
|
|
|
21770
21827
|
revokeAppInvite: (appId, inviteId) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations/${encodeURIComponent(inviteId)}`, {
|
|
21771
21828
|
method: "DELETE"
|
|
21772
21829
|
}),
|
|
21830
|
+
acceptInvitation: (payload) => request("/v1/invitations/accept", { method: "POST", body: JSON.stringify(payload) }),
|
|
21773
21831
|
syncUpstreamApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sync-upstream`, {
|
|
21774
21832
|
method: "POST",
|
|
21775
21833
|
body: JSON.stringify({})
|
|
@@ -21805,7 +21863,31 @@ function createApiClient(config2, opts) {
|
|
|
21805
21863
|
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download?${qs.toString()}`,
|
|
21806
21864
|
{ method: "GET" }
|
|
21807
21865
|
);
|
|
21808
|
-
}
|
|
21866
|
+
},
|
|
21867
|
+
listAgentRuns: (appId, params) => {
|
|
21868
|
+
const qs = new URLSearchParams();
|
|
21869
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21870
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21871
|
+
if (params?.status) qs.set("status", params.status);
|
|
21872
|
+
if (params?.currentPhase) qs.set("currentPhase", params.currentPhase);
|
|
21873
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21874
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21875
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21876
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs${suffix}`, { method: "GET" });
|
|
21877
|
+
},
|
|
21878
|
+
getAgentRun: (appId, runId) => request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}`, { method: "GET" }),
|
|
21879
|
+
listAgentRunEvents: (appId, runId, params) => {
|
|
21880
|
+
const qs = new URLSearchParams();
|
|
21881
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
21882
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
21883
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
21884
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
21885
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
21886
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}/events${suffix}`, {
|
|
21887
|
+
method: "GET"
|
|
21888
|
+
});
|
|
21889
|
+
},
|
|
21890
|
+
getSandboxStatus: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sandbox/status`, { method: "GET" })
|
|
21809
21891
|
};
|
|
21810
21892
|
}
|
|
21811
21893
|
|
|
@@ -41707,7 +41789,7 @@ var REMIX_ERROR_CODES = {
|
|
|
41707
41789
|
// node_modules/@remixhq/mcp/dist/index.js
|
|
41708
41790
|
var import_path11 = __toESM(require("path"), 1);
|
|
41709
41791
|
|
|
41710
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41792
|
+
// node_modules/@remixhq/core/dist/chunk-GEHSFPCD.js
|
|
41711
41793
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
41712
41794
|
var import_path2 = __toESM(require("path"), 1);
|
|
41713
41795
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
@@ -41785,7 +41867,7 @@ async function writeCollabBinding(repoRoot, binding) {
|
|
|
41785
41867
|
return filePath;
|
|
41786
41868
|
}
|
|
41787
41869
|
|
|
41788
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
41870
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
41789
41871
|
var import_promises15 = __toESM(require("fs/promises"), 1);
|
|
41790
41872
|
var import_crypto = require("crypto");
|
|
41791
41873
|
var import_os2 = __toESM(require("os"), 1);
|
|
@@ -48566,7 +48648,7 @@ var {
|
|
|
48566
48648
|
getCancelSignal: getCancelSignal2
|
|
48567
48649
|
} = getIpcExport();
|
|
48568
48650
|
|
|
48569
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
48651
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
48570
48652
|
var GIT_REMOTE_PROTOCOL_RE = /^(https?|ssh):\/\//i;
|
|
48571
48653
|
var SCP_LIKE_GIT_REMOTE_RE = /^(?<user>[^@\s]+)@(?<host>[^:\s]+):(?<path>[^\\\s]+)$/;
|
|
48572
48654
|
var CANONICAL_GIT_REMOTE_RE = /^(?<host>(?:localhost|[a-z0-9.-]+))\/(?<path>[^\\\s]+)$/i;
|
|
@@ -48813,6 +48895,13 @@ async function listUntrackedFiles(cwd) {
|
|
|
48813
48895
|
return [];
|
|
48814
48896
|
}
|
|
48815
48897
|
}
|
|
48898
|
+
async function getWorkspaceDiff(cwd) {
|
|
48899
|
+
const snapshot = await getWorkspaceSnapshot(cwd);
|
|
48900
|
+
return {
|
|
48901
|
+
diff: snapshot.diff,
|
|
48902
|
+
includedUntrackedPaths: snapshot.includedUntrackedPaths
|
|
48903
|
+
};
|
|
48904
|
+
}
|
|
48816
48905
|
async function getWorkspaceSnapshot(cwd) {
|
|
48817
48906
|
const headCommitHash = await getHeadCommitHash(cwd);
|
|
48818
48907
|
if (!headCommitHash) {
|
|
@@ -49252,6 +49341,26 @@ function unwrapResponseObject(resp, label) {
|
|
|
49252
49341
|
}
|
|
49253
49342
|
return obj;
|
|
49254
49343
|
}
|
|
49344
|
+
var DEFAULT_PAGINATION_LIMIT = 25;
|
|
49345
|
+
var MAX_PAGINATION_LIMIT = 50;
|
|
49346
|
+
function normalizePagination(params) {
|
|
49347
|
+
const rawLimit = typeof params?.limit === "number" && Number.isFinite(params.limit) ? Math.trunc(params.limit) : DEFAULT_PAGINATION_LIMIT;
|
|
49348
|
+
const rawOffset = typeof params?.offset === "number" && Number.isFinite(params.offset) ? Math.trunc(params.offset) : 0;
|
|
49349
|
+
return {
|
|
49350
|
+
limit: Math.max(1, Math.min(MAX_PAGINATION_LIMIT, rawLimit)),
|
|
49351
|
+
offset: Math.max(0, rawOffset)
|
|
49352
|
+
};
|
|
49353
|
+
}
|
|
49354
|
+
function paginateOverfetchedItems(items, params) {
|
|
49355
|
+
const pagination = normalizePagination(params);
|
|
49356
|
+
return {
|
|
49357
|
+
items: items.slice(0, pagination.limit),
|
|
49358
|
+
pagination: {
|
|
49359
|
+
...pagination,
|
|
49360
|
+
hasMore: items.length > pagination.limit
|
|
49361
|
+
}
|
|
49362
|
+
};
|
|
49363
|
+
}
|
|
49255
49364
|
function unwrapMergeRequest(resp) {
|
|
49256
49365
|
return unwrapResponseObject(resp, "merge request");
|
|
49257
49366
|
}
|
|
@@ -50201,6 +50310,7 @@ async function collabAdd(params) {
|
|
|
50201
50310
|
}
|
|
50202
50311
|
const { backupPath } = await writeTempUnifiedDiffBackup(diff, "remix-add");
|
|
50203
50312
|
try {
|
|
50313
|
+
await pollAppReady(params.api, binding.currentAppId);
|
|
50204
50314
|
if (submissionSnapshot) {
|
|
50205
50315
|
await assertRepoSnapshotUnchanged(repoRoot, submissionSnapshot, {
|
|
50206
50316
|
operation: "`remix collab add` auto-sync",
|
|
@@ -50345,6 +50455,105 @@ async function collabRecordTurn(params) {
|
|
|
50345
50455
|
});
|
|
50346
50456
|
return unwrapResponseObject(resp, "collab turn");
|
|
50347
50457
|
}
|
|
50458
|
+
function collectWarnings(value) {
|
|
50459
|
+
if (!Array.isArray(value)) return [];
|
|
50460
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
50461
|
+
}
|
|
50462
|
+
async function collabFinalizeTurn(params) {
|
|
50463
|
+
const repoRoot = await findGitRoot(params.cwd);
|
|
50464
|
+
const binding = await readCollabBinding(repoRoot);
|
|
50465
|
+
if (!binding) {
|
|
50466
|
+
throw new RemixError("Repository is not bound to Remix.", {
|
|
50467
|
+
exitCode: 2,
|
|
50468
|
+
hint: "Run `remix collab init` first."
|
|
50469
|
+
});
|
|
50470
|
+
}
|
|
50471
|
+
const prompt = params.prompt.trim();
|
|
50472
|
+
const assistantResponse = params.assistantResponse.trim();
|
|
50473
|
+
if (!prompt) throw new RemixError("Prompt is required.", { exitCode: 2 });
|
|
50474
|
+
if (!assistantResponse) throw new RemixError("Assistant response is required.", { exitCode: 2 });
|
|
50475
|
+
const diffSource = params.diffSource ?? (params.diff ? "external" : "worktree");
|
|
50476
|
+
const externalDiff = params.diff?.trim() ?? "";
|
|
50477
|
+
const workspaceDiff = diffSource === "worktree" ? await getWorkspaceDiff(repoRoot) : null;
|
|
50478
|
+
const hasChangedTurn = diffSource === "external" ? externalDiff.length > 0 : Boolean(workspaceDiff?.diff.trim());
|
|
50479
|
+
const currentHeadCommitHash = await getHeadCommitHash(repoRoot);
|
|
50480
|
+
const idempotencyKey = params.idempotencyKey?.trim() || buildDeterministicIdempotencyKey({
|
|
50481
|
+
kind: "collab_finalize_turn_v1",
|
|
50482
|
+
appId: binding.currentAppId,
|
|
50483
|
+
upstreamAppId: binding.upstreamAppId,
|
|
50484
|
+
headCommitHash: currentHeadCommitHash,
|
|
50485
|
+
modeHint: hasChangedTurn ? "changed_turn" : "no_diff_turn",
|
|
50486
|
+
prompt,
|
|
50487
|
+
assistantResponse,
|
|
50488
|
+
externalDiff: diffSource === "external" ? externalDiff : null
|
|
50489
|
+
});
|
|
50490
|
+
if (diffSource === "external" && !hasChangedTurn) {
|
|
50491
|
+
throw new RemixError("External diff is empty.", {
|
|
50492
|
+
exitCode: 2,
|
|
50493
|
+
hint: "Pass a non-empty diff when using external diff submission, or omit the external diff so finalize-turn can inspect the live worktree."
|
|
50494
|
+
});
|
|
50495
|
+
}
|
|
50496
|
+
if (hasChangedTurn) {
|
|
50497
|
+
const localHeadBefore = currentHeadCommitHash;
|
|
50498
|
+
const capturedUntrackedPathsCandidate = diffSource === "worktree" ? await listUntrackedFiles(repoRoot) : [];
|
|
50499
|
+
const changeStep = await collabAdd({
|
|
50500
|
+
api: params.api,
|
|
50501
|
+
cwd: repoRoot,
|
|
50502
|
+
prompt,
|
|
50503
|
+
assistantResponse,
|
|
50504
|
+
diff: diffSource === "external" ? externalDiff : null,
|
|
50505
|
+
diffSource,
|
|
50506
|
+
sync: params.sync,
|
|
50507
|
+
allowBranchMismatch: params.allowBranchMismatch,
|
|
50508
|
+
idempotencyKey,
|
|
50509
|
+
actor: params.actor
|
|
50510
|
+
});
|
|
50511
|
+
const localHeadAfter = await getHeadCommitHash(repoRoot);
|
|
50512
|
+
const warnings = [
|
|
50513
|
+
...collectWarnings(changeStep.warnings),
|
|
50514
|
+
...diffSource === "external" && params.sync !== false ? [
|
|
50515
|
+
"Automatic local discard+sync was skipped because the diff came from an external source and may not match the current worktree."
|
|
50516
|
+
] : []
|
|
50517
|
+
];
|
|
50518
|
+
const autoSyncRequested = params.sync !== false;
|
|
50519
|
+
const autoSyncEligible = diffSource === "worktree";
|
|
50520
|
+
return {
|
|
50521
|
+
mode: "changed_turn",
|
|
50522
|
+
idempotencyKey,
|
|
50523
|
+
changeStep,
|
|
50524
|
+
collabTurn: null,
|
|
50525
|
+
autoSync: {
|
|
50526
|
+
requested: autoSyncRequested,
|
|
50527
|
+
eligible: autoSyncEligible,
|
|
50528
|
+
attempted: autoSyncRequested && autoSyncEligible,
|
|
50529
|
+
applied: autoSyncRequested && autoSyncEligible,
|
|
50530
|
+
trackedChangesDiscarded: autoSyncRequested && autoSyncEligible,
|
|
50531
|
+
capturedUntrackedPathsCandidate,
|
|
50532
|
+
localHeadBefore,
|
|
50533
|
+
localHeadAfter,
|
|
50534
|
+
localRepoMutated: autoSyncRequested && autoSyncEligible && localHeadBefore !== localHeadAfter
|
|
50535
|
+
},
|
|
50536
|
+
warnings
|
|
50537
|
+
};
|
|
50538
|
+
}
|
|
50539
|
+
const collabTurn = await collabRecordTurn({
|
|
50540
|
+
api: params.api,
|
|
50541
|
+
cwd: repoRoot,
|
|
50542
|
+
prompt,
|
|
50543
|
+
assistantResponse,
|
|
50544
|
+
allowBranchMismatch: params.allowBranchMismatch,
|
|
50545
|
+
idempotencyKey,
|
|
50546
|
+
actor: params.actor
|
|
50547
|
+
});
|
|
50548
|
+
return {
|
|
50549
|
+
mode: "no_diff_turn",
|
|
50550
|
+
idempotencyKey,
|
|
50551
|
+
changeStep: null,
|
|
50552
|
+
collabTurn,
|
|
50553
|
+
autoSync: null,
|
|
50554
|
+
warnings: []
|
|
50555
|
+
};
|
|
50556
|
+
}
|
|
50348
50557
|
async function collabApprove(params) {
|
|
50349
50558
|
if (params.mode === "sync-target-repo") {
|
|
50350
50559
|
if (!params.cwd?.trim()) {
|
|
@@ -50602,17 +50811,22 @@ async function collabListMergeRequests(params) {
|
|
|
50602
50811
|
appId: params.appId,
|
|
50603
50812
|
queue: params.queue
|
|
50604
50813
|
});
|
|
50814
|
+
const pageRequest = normalizePagination(params);
|
|
50605
50815
|
const resp = await params.api.listMergeRequests({
|
|
50606
50816
|
queue: params.queue,
|
|
50607
50817
|
appId,
|
|
50608
50818
|
status: params.status,
|
|
50609
|
-
kind: params.kind ?? "merge"
|
|
50819
|
+
kind: params.kind ?? "merge",
|
|
50820
|
+
limit: pageRequest.limit + 1,
|
|
50821
|
+
offset: pageRequest.offset
|
|
50610
50822
|
});
|
|
50611
50823
|
const mergeRequests = unwrapResponseObject(resp, "merge requests");
|
|
50824
|
+
const page = paginateOverfetchedItems(mergeRequests, params);
|
|
50612
50825
|
return {
|
|
50613
50826
|
queue: params.queue,
|
|
50614
50827
|
appId: appId ?? null,
|
|
50615
|
-
mergeRequests
|
|
50828
|
+
mergeRequests: page.items,
|
|
50829
|
+
pagination: page.pagination
|
|
50616
50830
|
};
|
|
50617
50831
|
}
|
|
50618
50832
|
async function resolveScopeTarget(params) {
|
|
@@ -50651,12 +50865,24 @@ async function collabListMembers(params) {
|
|
|
50651
50865
|
scope: params.scope,
|
|
50652
50866
|
targetId: params.targetId
|
|
50653
50867
|
});
|
|
50654
|
-
const
|
|
50868
|
+
const pageRequest = normalizePagination(params);
|
|
50869
|
+
const resp = params.scope === "organization" ? await params.api.listOrganizationMembers(targetId, {
|
|
50870
|
+
limit: pageRequest.limit + 1,
|
|
50871
|
+
offset: pageRequest.offset
|
|
50872
|
+
}) : params.scope === "project" ? await params.api.listProjectMembers(targetId, {
|
|
50873
|
+
limit: pageRequest.limit + 1,
|
|
50874
|
+
offset: pageRequest.offset
|
|
50875
|
+
}) : await params.api.listAppMembers(targetId, {
|
|
50876
|
+
limit: pageRequest.limit + 1,
|
|
50877
|
+
offset: pageRequest.offset
|
|
50878
|
+
});
|
|
50655
50879
|
const members = params.scope === "organization" ? unwrapResponseObject(resp, "members") : params.scope === "project" ? unwrapResponseObject(resp, "members") : unwrapResponseObject(resp, "members");
|
|
50880
|
+
const page = paginateOverfetchedItems(members, params);
|
|
50656
50881
|
return {
|
|
50657
50882
|
scopeType: params.scope,
|
|
50658
50883
|
targetId,
|
|
50659
|
-
members
|
|
50884
|
+
members: page.items,
|
|
50885
|
+
pagination: page.pagination
|
|
50660
50886
|
};
|
|
50661
50887
|
}
|
|
50662
50888
|
async function collabUpdateMemberRole(params) {
|
|
@@ -50850,6 +51076,20 @@ async function collabInvite(params) {
|
|
|
50850
51076
|
targetId
|
|
50851
51077
|
};
|
|
50852
51078
|
}
|
|
51079
|
+
async function collabList(params) {
|
|
51080
|
+
const pageRequest = normalizePagination(params);
|
|
51081
|
+
const resp = await params.api.listApps({
|
|
51082
|
+
forked: params.forked ?? "all",
|
|
51083
|
+
limit: pageRequest.limit + 1,
|
|
51084
|
+
offset: pageRequest.offset
|
|
51085
|
+
});
|
|
51086
|
+
const apps = unwrapResponseObject(resp, "apps");
|
|
51087
|
+
const page = paginateOverfetchedItems(apps, params);
|
|
51088
|
+
return {
|
|
51089
|
+
apps: page.items,
|
|
51090
|
+
pagination: page.pagination
|
|
51091
|
+
};
|
|
51092
|
+
}
|
|
50853
51093
|
async function collabReconcile(params) {
|
|
50854
51094
|
const repoRoot = await findGitRoot(params.cwd);
|
|
50855
51095
|
const binding = await readCollabBinding(repoRoot);
|
|
@@ -51465,6 +51705,8 @@ var ERROR_CODES = {
|
|
|
51465
51705
|
METADATA_CONFLICT: "METADATA_CONFLICT",
|
|
51466
51706
|
DESTRUCTIVE_OPERATION_BLOCKED: "DESTRUCTIVE_OPERATION_BLOCKED",
|
|
51467
51707
|
CONFIG_INVALID: "CONFIG_INVALID",
|
|
51708
|
+
ACCESS_DENIED: "ACCESS_DENIED",
|
|
51709
|
+
RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND",
|
|
51468
51710
|
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
51469
51711
|
};
|
|
51470
51712
|
var RemixMcpError = class extends Error {
|
|
@@ -51480,6 +51722,15 @@ function toStringOrNull(value) {
|
|
|
51480
51722
|
const trimmed = value.trim();
|
|
51481
51723
|
return trimmed.length > 0 ? trimmed : null;
|
|
51482
51724
|
}
|
|
51725
|
+
function parseJsonObject(value) {
|
|
51726
|
+
if (!value) return null;
|
|
51727
|
+
try {
|
|
51728
|
+
const parsed = JSON.parse(value);
|
|
51729
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
51730
|
+
} catch {
|
|
51731
|
+
return null;
|
|
51732
|
+
}
|
|
51733
|
+
}
|
|
51483
51734
|
function makeNormalized(params) {
|
|
51484
51735
|
return {
|
|
51485
51736
|
code: params.code,
|
|
@@ -51493,6 +51744,8 @@ function normalizeByMessage(err) {
|
|
|
51493
51744
|
const code = toStringOrNull(err.code);
|
|
51494
51745
|
const message = toStringOrNull(err.message) ?? "Unexpected error.";
|
|
51495
51746
|
const hint = toStringOrNull(err.hint);
|
|
51747
|
+
const hintBody = parseJsonObject(hint);
|
|
51748
|
+
const statusCode = typeof hintBody?.statusCode === "number" ? hintBody.statusCode : typeof hintBody?.statusCode === "string" ? Number(hintBody.statusCode) : null;
|
|
51496
51749
|
if (code === ERROR_CODES.REPO_LOCK_HELD) {
|
|
51497
51750
|
return makeNormalized({
|
|
51498
51751
|
code: ERROR_CODES.REPO_LOCK_HELD,
|
|
@@ -51593,6 +51846,22 @@ function normalizeByMessage(err) {
|
|
|
51593
51846
|
category: "remote_state"
|
|
51594
51847
|
});
|
|
51595
51848
|
}
|
|
51849
|
+
if (statusCode === 403) {
|
|
51850
|
+
return makeNormalized({
|
|
51851
|
+
code: ERROR_CODES.ACCESS_DENIED,
|
|
51852
|
+
message,
|
|
51853
|
+
hint,
|
|
51854
|
+
category: "remote_state"
|
|
51855
|
+
});
|
|
51856
|
+
}
|
|
51857
|
+
if (statusCode === 404) {
|
|
51858
|
+
return makeNormalized({
|
|
51859
|
+
code: ERROR_CODES.RESOURCE_NOT_FOUND,
|
|
51860
|
+
message,
|
|
51861
|
+
hint,
|
|
51862
|
+
category: "remote_state"
|
|
51863
|
+
});
|
|
51864
|
+
}
|
|
51596
51865
|
if (message.includes("Timed out") || message.includes("failed") || message.includes("error state")) {
|
|
51597
51866
|
return makeNormalized({
|
|
51598
51867
|
code: ERROR_CODES.REMOTE_ERROR,
|
|
@@ -51770,6 +52039,11 @@ function makeErrorResult(envelope) {
|
|
|
51770
52039
|
}
|
|
51771
52040
|
var genericRecordSchema = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
51772
52041
|
var genericArraySchema = external_exports.array(genericRecordSchema);
|
|
52042
|
+
var paginationSchema = external_exports.object({
|
|
52043
|
+
limit: external_exports.number().int().positive(),
|
|
52044
|
+
offset: external_exports.number().int().nonnegative(),
|
|
52045
|
+
hasMore: external_exports.boolean()
|
|
52046
|
+
});
|
|
51773
52047
|
var mergeRequestQueueSchema = external_exports.enum([
|
|
51774
52048
|
"reviewable",
|
|
51775
52049
|
"created_by_me",
|
|
@@ -51791,7 +52065,9 @@ var initInputSchema = {
|
|
|
51791
52065
|
var listInputSchema = {
|
|
51792
52066
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51793
52067
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51794
|
-
forked: external_exports.enum(["only", "exclude", "all"]).optional()
|
|
52068
|
+
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
52069
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52070
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51795
52071
|
};
|
|
51796
52072
|
var remixInputSchema = {
|
|
51797
52073
|
...commonRequestFieldsSchema,
|
|
@@ -51820,6 +52096,16 @@ var recordTurnInputSchema = {
|
|
|
51820
52096
|
allowBranchMismatch: external_exports.boolean().optional(),
|
|
51821
52097
|
idempotencyKey: external_exports.string().trim().min(1).optional()
|
|
51822
52098
|
};
|
|
52099
|
+
var finalizeTurnInputSchema = {
|
|
52100
|
+
...commonRequestFieldsSchema,
|
|
52101
|
+
prompt: external_exports.string().trim().min(1),
|
|
52102
|
+
assistantResponse: external_exports.string().trim().min(1),
|
|
52103
|
+
diffSource: external_exports.enum(["worktree", "external"]).optional(),
|
|
52104
|
+
externalDiff: external_exports.string().optional(),
|
|
52105
|
+
sync: external_exports.boolean().optional(),
|
|
52106
|
+
allowBranchMismatch: external_exports.boolean().optional(),
|
|
52107
|
+
idempotencyKey: external_exports.string().trim().min(1).optional()
|
|
52108
|
+
};
|
|
51823
52109
|
var previewInputSchema = {
|
|
51824
52110
|
...commonRequestFieldsSchema
|
|
51825
52111
|
};
|
|
@@ -51835,20 +52121,26 @@ var reviewQueueInputSchema = {
|
|
|
51835
52121
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51836
52122
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51837
52123
|
status: external_exports.string().trim().min(1).optional(),
|
|
51838
|
-
kind: external_exports.enum(["merge", "sync", "all"]).optional()
|
|
52124
|
+
kind: external_exports.enum(["merge", "sync", "all"]).optional(),
|
|
52125
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52126
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51839
52127
|
};
|
|
51840
52128
|
var myMergeRequestsInputSchema = {
|
|
51841
52129
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
51842
52130
|
outputMode: external_exports.enum(["summary", "full"]).optional(),
|
|
51843
52131
|
status: external_exports.string().trim().min(1).optional(),
|
|
51844
|
-
kind: external_exports.enum(["merge", "sync", "all"]).optional()
|
|
52132
|
+
kind: external_exports.enum(["merge", "sync", "all"]).optional(),
|
|
52133
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52134
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
51845
52135
|
};
|
|
51846
52136
|
var appMergeRequestsInputSchema = {
|
|
51847
52137
|
...commonRequestFieldsSchema,
|
|
51848
52138
|
queue: appScopedMergeRequestQueueSchema,
|
|
51849
52139
|
appId: external_exports.string().trim().min(1).optional(),
|
|
51850
52140
|
status: external_exports.string().trim().min(1).optional(),
|
|
51851
|
-
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()
|
|
51852
52144
|
};
|
|
51853
52145
|
var viewMergeRequestInputSchema = {
|
|
51854
52146
|
requestId: external_exports.string().trim().min(1).optional(),
|
|
@@ -51879,6 +52171,38 @@ var inviteInputSchema = {
|
|
|
51879
52171
|
var listMembersInputSchema = {
|
|
51880
52172
|
...commonRequestFieldsSchema,
|
|
51881
52173
|
scope: memberScopeSchema,
|
|
52174
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52175
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52176
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
52177
|
+
};
|
|
52178
|
+
var listInvitesInputSchema = {
|
|
52179
|
+
...commonRequestFieldsSchema,
|
|
52180
|
+
scope: memberScopeSchema.optional(),
|
|
52181
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52182
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
52183
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
52184
|
+
};
|
|
52185
|
+
var resendInviteInputSchema = {
|
|
52186
|
+
...commonRequestFieldsSchema,
|
|
52187
|
+
scope: memberScopeSchema.optional(),
|
|
52188
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52189
|
+
inviteId: external_exports.string().trim().min(1),
|
|
52190
|
+
ttlDays: external_exports.number().int().positive().max(30).optional()
|
|
52191
|
+
};
|
|
52192
|
+
var revokeInviteInputSchema = {
|
|
52193
|
+
...commonRequestFieldsSchema,
|
|
52194
|
+
scope: memberScopeSchema.optional(),
|
|
52195
|
+
targetId: external_exports.string().trim().min(1).optional(),
|
|
52196
|
+
inviteId: external_exports.string().trim().min(1),
|
|
52197
|
+
confirm: external_exports.boolean()
|
|
52198
|
+
};
|
|
52199
|
+
var acceptInvitationInputSchema = {
|
|
52200
|
+
requestId: external_exports.string().trim().min(1).optional(),
|
|
52201
|
+
token: external_exports.string().trim().min(20)
|
|
52202
|
+
};
|
|
52203
|
+
var accessDebugInputSchema = {
|
|
52204
|
+
...commonRequestFieldsSchema,
|
|
52205
|
+
scope: memberScopeSchema.optional(),
|
|
51882
52206
|
targetId: external_exports.string().trim().min(1).optional()
|
|
51883
52207
|
};
|
|
51884
52208
|
var updateMemberRoleInputSchema = {
|
|
@@ -51902,7 +52226,8 @@ var initDataSchema = external_exports.object({
|
|
|
51902
52226
|
repoRoot: external_exports.string()
|
|
51903
52227
|
});
|
|
51904
52228
|
var listDataSchema = external_exports.object({
|
|
51905
|
-
apps: genericArraySchema
|
|
52229
|
+
apps: genericArraySchema,
|
|
52230
|
+
pagination: paginationSchema
|
|
51906
52231
|
});
|
|
51907
52232
|
var remixDataSchema = external_exports.object({
|
|
51908
52233
|
appId: external_exports.string(),
|
|
@@ -51925,12 +52250,21 @@ var addDataSchema = external_exports.object({
|
|
|
51925
52250
|
autoSync: genericRecordSchema
|
|
51926
52251
|
});
|
|
51927
52252
|
var recordTurnDataSchema = genericRecordSchema;
|
|
52253
|
+
var finalizeTurnDataSchema = external_exports.object({
|
|
52254
|
+
mode: external_exports.enum(["changed_turn", "no_diff_turn"]),
|
|
52255
|
+
idempotencyKey: external_exports.string().min(1),
|
|
52256
|
+
changeStep: genericRecordSchema.nullable(),
|
|
52257
|
+
collabTurn: genericRecordSchema.nullable(),
|
|
52258
|
+
autoSync: genericRecordSchema.nullable(),
|
|
52259
|
+
warnings: external_exports.array(external_exports.string())
|
|
52260
|
+
});
|
|
51928
52261
|
var syncDataSchema = genericRecordSchema;
|
|
51929
52262
|
var requestMergeDataSchema = genericRecordSchema;
|
|
51930
52263
|
var mergeRequestQueueDataSchema = external_exports.object({
|
|
51931
52264
|
queue: mergeRequestQueueSchema,
|
|
51932
52265
|
appId: external_exports.string().nullable(),
|
|
51933
|
-
mergeRequests: external_exports.array(genericRecordSchema)
|
|
52266
|
+
mergeRequests: external_exports.array(genericRecordSchema),
|
|
52267
|
+
pagination: paginationSchema
|
|
51934
52268
|
});
|
|
51935
52269
|
var viewMergeRequestDataSchema = genericRecordSchema;
|
|
51936
52270
|
var approveDataSchema = genericRecordSchema;
|
|
@@ -51942,7 +52276,49 @@ var memberRecordSchema = genericRecordSchema;
|
|
|
51942
52276
|
var listMembersDataSchema = external_exports.object({
|
|
51943
52277
|
scopeType: memberScopeSchema,
|
|
51944
52278
|
targetId: external_exports.string(),
|
|
51945
|
-
members: external_exports.array(memberRecordSchema)
|
|
52279
|
+
members: external_exports.array(memberRecordSchema),
|
|
52280
|
+
pagination: paginationSchema
|
|
52281
|
+
});
|
|
52282
|
+
var listInvitesDataSchema = external_exports.object({
|
|
52283
|
+
scopeType: memberScopeSchema,
|
|
52284
|
+
targetId: external_exports.string(),
|
|
52285
|
+
invites: external_exports.array(genericRecordSchema),
|
|
52286
|
+
pagination: paginationSchema
|
|
52287
|
+
});
|
|
52288
|
+
var resendInviteDataSchema = genericRecordSchema;
|
|
52289
|
+
var revokeInviteDataSchema = external_exports.object({
|
|
52290
|
+
scopeType: memberScopeSchema,
|
|
52291
|
+
targetId: external_exports.string(),
|
|
52292
|
+
inviteId: external_exports.string(),
|
|
52293
|
+
revoked: external_exports.boolean()
|
|
52294
|
+
});
|
|
52295
|
+
var acceptInvitationDataSchema = genericRecordSchema;
|
|
52296
|
+
var accessDebugDataSchema = external_exports.object({
|
|
52297
|
+
viewer: genericRecordSchema,
|
|
52298
|
+
scope: external_exports.object({
|
|
52299
|
+
scopeType: memberScopeSchema,
|
|
52300
|
+
targetId: external_exports.string()
|
|
52301
|
+
}),
|
|
52302
|
+
entities: external_exports.object({
|
|
52303
|
+
organization: genericRecordSchema.nullable(),
|
|
52304
|
+
project: genericRecordSchema.nullable(),
|
|
52305
|
+
app: genericRecordSchema.nullable()
|
|
52306
|
+
}),
|
|
52307
|
+
binding: external_exports.object({
|
|
52308
|
+
repoRoot: external_exports.string().nullable(),
|
|
52309
|
+
binding: genericRecordSchema.nullable()
|
|
52310
|
+
}),
|
|
52311
|
+
access: external_exports.object({
|
|
52312
|
+
appContext: genericRecordSchema.nullable(),
|
|
52313
|
+
viewerMember: genericRecordSchema.nullable(),
|
|
52314
|
+
viewerProjectMember: genericRecordSchema.nullable(),
|
|
52315
|
+
inviteForViewerEmail: genericRecordSchema.nullable(),
|
|
52316
|
+
effectiveAppAccess: genericRecordSchema.nullable()
|
|
52317
|
+
}),
|
|
52318
|
+
members: external_exports.array(genericRecordSchema),
|
|
52319
|
+
membersPageInfo: paginationSchema,
|
|
52320
|
+
invites: external_exports.array(genericRecordSchema),
|
|
52321
|
+
invitesPageInfo: paginationSchema
|
|
51946
52322
|
});
|
|
51947
52323
|
var updateMemberRoleDataSchema = external_exports.object({
|
|
51948
52324
|
scopeType: memberScopeSchema,
|
|
@@ -51956,6 +52332,7 @@ var remixSuccessSchema = makeSuccessSchema(remixDataSchema);
|
|
|
51956
52332
|
var checkoutSuccessSchema = makeSuccessSchema(checkoutDataSchema);
|
|
51957
52333
|
var addSuccessSchema = makeSuccessSchema(addDataSchema);
|
|
51958
52334
|
var recordTurnSuccessSchema = makeSuccessSchema(recordTurnDataSchema);
|
|
52335
|
+
var finalizeTurnSuccessSchema = makeSuccessSchema(finalizeTurnDataSchema);
|
|
51959
52336
|
var syncSuccessSchema = makeSuccessSchema(syncDataSchema);
|
|
51960
52337
|
var requestMergeSuccessSchema = makeSuccessSchema(requestMergeDataSchema);
|
|
51961
52338
|
var mergeRequestQueueSuccessSchema = makeSuccessSchema(mergeRequestQueueDataSchema);
|
|
@@ -51966,14 +52343,12 @@ var syncUpstreamSuccessSchema = makeSuccessSchema(syncUpstreamDataSchema);
|
|
|
51966
52343
|
var reconcileSuccessSchema = makeSuccessSchema(reconcileDataSchema);
|
|
51967
52344
|
var inviteSuccessSchema = makeSuccessSchema(inviteDataSchema);
|
|
51968
52345
|
var listMembersSuccessSchema = makeSuccessSchema(listMembersDataSchema);
|
|
52346
|
+
var listInvitesSuccessSchema = makeSuccessSchema(listInvitesDataSchema);
|
|
52347
|
+
var resendInviteSuccessSchema = makeSuccessSchema(resendInviteDataSchema);
|
|
52348
|
+
var revokeInviteSuccessSchema = makeSuccessSchema(revokeInviteDataSchema);
|
|
52349
|
+
var acceptInvitationSuccessSchema = makeSuccessSchema(acceptInvitationDataSchema);
|
|
52350
|
+
var accessDebugSuccessSchema = makeSuccessSchema(accessDebugDataSchema);
|
|
51969
52351
|
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
52352
|
function getRiskLevel(status) {
|
|
51978
52353
|
if (status.recommendedAction === "reconcile") return "high";
|
|
51979
52354
|
if (status.recommendedAction === "sync" || status.remote.incomingOpenMergeRequestCount) return "medium";
|
|
@@ -51999,12 +52374,12 @@ function getRecommendedNextActions(status) {
|
|
|
51999
52374
|
return [];
|
|
52000
52375
|
}
|
|
52001
52376
|
}
|
|
52002
|
-
function
|
|
52377
|
+
function collectWarnings2(value) {
|
|
52003
52378
|
if (!value || !Array.isArray(value)) return [];
|
|
52004
52379
|
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
52005
52380
|
}
|
|
52006
52381
|
function collectResultWarnings(value) {
|
|
52007
|
-
return
|
|
52382
|
+
return collectWarnings2(value.warnings);
|
|
52008
52383
|
}
|
|
52009
52384
|
function truncateText(value, maxChars) {
|
|
52010
52385
|
if (value.length <= maxChars) {
|
|
@@ -52060,13 +52435,17 @@ async function initCollab(params) {
|
|
|
52060
52435
|
};
|
|
52061
52436
|
}
|
|
52062
52437
|
async function listApps(params) {
|
|
52063
|
-
const api = await
|
|
52064
|
-
const
|
|
52065
|
-
|
|
52438
|
+
const api = await createCollabApiClient();
|
|
52439
|
+
const result = await collabList({
|
|
52440
|
+
api,
|
|
52441
|
+
forked: params.forked,
|
|
52442
|
+
limit: params.limit,
|
|
52443
|
+
offset: params.offset
|
|
52444
|
+
});
|
|
52066
52445
|
return {
|
|
52067
|
-
data:
|
|
52446
|
+
data: result,
|
|
52068
52447
|
warnings: [],
|
|
52069
|
-
recommendedNextActions: [],
|
|
52448
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52070
52449
|
logContext: {}
|
|
52071
52450
|
};
|
|
52072
52451
|
}
|
|
@@ -52107,70 +52486,28 @@ async function checkoutCollab(params) {
|
|
|
52107
52486
|
}
|
|
52108
52487
|
};
|
|
52109
52488
|
}
|
|
52110
|
-
async function
|
|
52489
|
+
async function finalizeCollabTurn(params) {
|
|
52111
52490
|
const api = await createCollabApiClient();
|
|
52112
52491
|
const repoRoot = await findGitRoot(params.cwd);
|
|
52113
|
-
const
|
|
52114
|
-
const untrackedBefore = params.diffSource === "worktree" ? await listUntrackedFiles(repoRoot) : [];
|
|
52115
|
-
const changeStep = await collabAdd({
|
|
52492
|
+
const result = await collabFinalizeTurn({
|
|
52116
52493
|
api,
|
|
52117
52494
|
cwd: params.cwd,
|
|
52118
52495
|
prompt: params.prompt,
|
|
52119
|
-
assistantResponse: params.assistantResponse
|
|
52496
|
+
assistantResponse: params.assistantResponse,
|
|
52120
52497
|
diff: params.externalDiff ?? null,
|
|
52121
52498
|
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,
|
|
52499
|
+
sync: params.sync,
|
|
52163
52500
|
allowBranchMismatch: params.allowBranchMismatch ?? false,
|
|
52164
52501
|
idempotencyKey: params.idempotencyKey ?? null,
|
|
52165
52502
|
actor: params.agent
|
|
52166
52503
|
});
|
|
52167
52504
|
return {
|
|
52168
52505
|
data: result,
|
|
52169
|
-
warnings:
|
|
52506
|
+
warnings: result.warnings,
|
|
52170
52507
|
recommendedNextActions: [],
|
|
52171
52508
|
logContext: {
|
|
52172
|
-
repoRoot
|
|
52173
|
-
appId: result.appId
|
|
52509
|
+
repoRoot,
|
|
52510
|
+
appId: result.changeStep?.appId ?? result.collabTurn?.appId ?? null
|
|
52174
52511
|
}
|
|
52175
52512
|
};
|
|
52176
52513
|
}
|
|
@@ -52212,16 +52549,19 @@ async function reviewQueue(params) {
|
|
|
52212
52549
|
api,
|
|
52213
52550
|
queue: "reviewable",
|
|
52214
52551
|
status: params.status ?? "open",
|
|
52215
|
-
kind: params.kind ?? "merge"
|
|
52552
|
+
kind: params.kind ?? "merge",
|
|
52553
|
+
limit: params.limit,
|
|
52554
|
+
offset: params.offset
|
|
52216
52555
|
});
|
|
52217
52556
|
return {
|
|
52218
52557
|
data: {
|
|
52219
52558
|
queue: result.queue,
|
|
52220
52559
|
appId: result.appId,
|
|
52221
|
-
mergeRequests: result.mergeRequests
|
|
52560
|
+
mergeRequests: result.mergeRequests,
|
|
52561
|
+
pagination: result.pagination
|
|
52222
52562
|
},
|
|
52223
52563
|
warnings: [],
|
|
52224
|
-
recommendedNextActions: [],
|
|
52564
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52225
52565
|
logContext: {}
|
|
52226
52566
|
};
|
|
52227
52567
|
}
|
|
@@ -52231,16 +52571,19 @@ async function myMergeRequests(params) {
|
|
|
52231
52571
|
api,
|
|
52232
52572
|
queue: "created_by_me",
|
|
52233
52573
|
status: params.status ?? "open",
|
|
52234
|
-
kind: params.kind ?? "merge"
|
|
52574
|
+
kind: params.kind ?? "merge",
|
|
52575
|
+
limit: params.limit,
|
|
52576
|
+
offset: params.offset
|
|
52235
52577
|
});
|
|
52236
52578
|
return {
|
|
52237
52579
|
data: {
|
|
52238
52580
|
queue: result.queue,
|
|
52239
52581
|
appId: result.appId,
|
|
52240
|
-
mergeRequests: result.mergeRequests
|
|
52582
|
+
mergeRequests: result.mergeRequests,
|
|
52583
|
+
pagination: result.pagination
|
|
52241
52584
|
},
|
|
52242
52585
|
warnings: [],
|
|
52243
|
-
recommendedNextActions: [],
|
|
52586
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52244
52587
|
logContext: {}
|
|
52245
52588
|
};
|
|
52246
52589
|
}
|
|
@@ -52252,16 +52595,19 @@ async function listAppMergeRequests(params) {
|
|
|
52252
52595
|
appId: params.appId,
|
|
52253
52596
|
queue: params.queue,
|
|
52254
52597
|
status: params.status ?? "open",
|
|
52255
|
-
kind: params.kind ?? "merge"
|
|
52598
|
+
kind: params.kind ?? "merge",
|
|
52599
|
+
limit: params.limit,
|
|
52600
|
+
offset: params.offset
|
|
52256
52601
|
});
|
|
52257
52602
|
return {
|
|
52258
52603
|
data: {
|
|
52259
52604
|
queue: result.queue,
|
|
52260
52605
|
appId: result.appId,
|
|
52261
|
-
mergeRequests: result.mergeRequests
|
|
52606
|
+
mergeRequests: result.mergeRequests,
|
|
52607
|
+
pagination: result.pagination
|
|
52262
52608
|
},
|
|
52263
52609
|
warnings: [],
|
|
52264
|
-
recommendedNextActions: [],
|
|
52610
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52265
52611
|
logContext: {
|
|
52266
52612
|
appId: result.appId
|
|
52267
52613
|
}
|
|
@@ -52354,7 +52700,7 @@ async function reconcile(params) {
|
|
|
52354
52700
|
});
|
|
52355
52701
|
return {
|
|
52356
52702
|
data: result,
|
|
52357
|
-
warnings:
|
|
52703
|
+
warnings: collectWarnings2(result.warnings),
|
|
52358
52704
|
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
52705
|
risks: params.dryRun ? ["Reconcile apply rewrites local history and creates a backup branch."] : [],
|
|
52360
52706
|
logContext: {
|
|
@@ -52386,12 +52732,14 @@ async function listMembers(params) {
|
|
|
52386
52732
|
api,
|
|
52387
52733
|
cwd: params.cwd,
|
|
52388
52734
|
scope: params.scope,
|
|
52389
|
-
targetId: params.targetId ?? null
|
|
52735
|
+
targetId: params.targetId ?? null,
|
|
52736
|
+
limit: params.limit,
|
|
52737
|
+
offset: params.offset
|
|
52390
52738
|
});
|
|
52391
52739
|
return {
|
|
52392
52740
|
data: result,
|
|
52393
52741
|
warnings: [],
|
|
52394
|
-
recommendedNextActions: [],
|
|
52742
|
+
recommendedNextActions: result.pagination.hasMore ? [`Pass offset=${result.pagination.offset + result.pagination.limit} to load the next page.`] : [],
|
|
52395
52743
|
logContext: {}
|
|
52396
52744
|
};
|
|
52397
52745
|
}
|
|
@@ -52412,35 +52760,517 @@ async function updateMemberRole(params) {
|
|
|
52412
52760
|
logContext: {}
|
|
52413
52761
|
};
|
|
52414
52762
|
}
|
|
52415
|
-
function
|
|
52416
|
-
|
|
52417
|
-
|
|
52418
|
-
|
|
52419
|
-
|
|
52420
|
-
|
|
52421
|
-
|
|
52763
|
+
function unwrapResponseObject2(resp, label) {
|
|
52764
|
+
const obj = resp?.responseObject;
|
|
52765
|
+
if (obj === void 0 || obj === null) {
|
|
52766
|
+
throw new Error(typeof resp?.message === "string" && resp.message.trim() ? resp.message : `Missing ${label} response`);
|
|
52767
|
+
}
|
|
52768
|
+
return obj;
|
|
52769
|
+
}
|
|
52770
|
+
async function maybeFindGitRoot(cwd) {
|
|
52771
|
+
try {
|
|
52772
|
+
return await findGitRoot(cwd);
|
|
52773
|
+
} catch {
|
|
52774
|
+
return null;
|
|
52422
52775
|
}
|
|
52776
|
+
}
|
|
52777
|
+
async function loadBindingContext(cwd) {
|
|
52778
|
+
if (!cwd) return { repoRoot: null, binding: null };
|
|
52779
|
+
const repoRoot = await maybeFindGitRoot(cwd);
|
|
52780
|
+
if (!repoRoot) return { repoRoot: null, binding: null };
|
|
52781
|
+
const binding = await readCollabBinding(repoRoot);
|
|
52423
52782
|
return {
|
|
52424
|
-
|
|
52425
|
-
|
|
52426
|
-
idempotentHint: false,
|
|
52427
|
-
openWorldHint: false
|
|
52783
|
+
repoRoot,
|
|
52784
|
+
binding
|
|
52428
52785
|
};
|
|
52429
52786
|
}
|
|
52430
|
-
function
|
|
52431
|
-
|
|
52432
|
-
|
|
52433
|
-
|
|
52434
|
-
|
|
52435
|
-
|
|
52436
|
-
|
|
52437
|
-
|
|
52787
|
+
function makeNotBoundError(message = "Repository is not bound to Remix.", hint) {
|
|
52788
|
+
const error2 = new Error(message);
|
|
52789
|
+
error2.hint = hint ?? "Run `remix_collab_init` in this repository, or pass the explicit id for a direct read.";
|
|
52790
|
+
return error2;
|
|
52791
|
+
}
|
|
52792
|
+
function parseJsonObject2(value) {
|
|
52793
|
+
if (!value) return null;
|
|
52794
|
+
try {
|
|
52795
|
+
const parsed = JSON.parse(value);
|
|
52796
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
52797
|
+
} catch {
|
|
52798
|
+
return null;
|
|
52799
|
+
}
|
|
52800
|
+
}
|
|
52801
|
+
function getBackendStatusCode(error2) {
|
|
52802
|
+
if (!error2 || typeof error2 !== "object") return null;
|
|
52803
|
+
const hint = "hint" in error2 && typeof error2.hint === "string" ? error2.hint : null;
|
|
52804
|
+
const body = parseJsonObject2(hint);
|
|
52805
|
+
if (typeof body?.statusCode === "number") return body.statusCode;
|
|
52806
|
+
if (typeof body?.statusCode === "string") {
|
|
52807
|
+
const parsed = Number(body.statusCode);
|
|
52808
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
52809
|
+
}
|
|
52810
|
+
return null;
|
|
52811
|
+
}
|
|
52812
|
+
function isBackendForbidden(error2) {
|
|
52813
|
+
return getBackendStatusCode(error2) === 403;
|
|
52814
|
+
}
|
|
52815
|
+
function isBackendNotFound(error2) {
|
|
52816
|
+
return getBackendStatusCode(error2) === 404;
|
|
52817
|
+
}
|
|
52818
|
+
function createAccessDeniedError(message, hint) {
|
|
52819
|
+
return new RemixMcpError({
|
|
52820
|
+
code: ERROR_CODES.ACCESS_DENIED,
|
|
52821
|
+
message,
|
|
52822
|
+
hint: hint ?? null,
|
|
52823
|
+
retryable: false,
|
|
52824
|
+
category: "remote_state"
|
|
52825
|
+
});
|
|
52826
|
+
}
|
|
52827
|
+
var MEMBERSHIP_PAGE_SIZE = 100;
|
|
52828
|
+
function normalizePagination2(params) {
|
|
52829
|
+
const rawLimit = typeof params?.limit === "number" ? Math.trunc(params.limit) : 25;
|
|
52830
|
+
const rawOffset = typeof params?.offset === "number" ? Math.trunc(params.offset) : 0;
|
|
52831
|
+
return {
|
|
52832
|
+
limit: Math.max(1, Math.min(50, rawLimit)),
|
|
52833
|
+
offset: Math.max(0, rawOffset)
|
|
52834
|
+
};
|
|
52835
|
+
}
|
|
52836
|
+
async function resolveScopeTarget2(api, params) {
|
|
52837
|
+
const explicitTargetId = params.targetId?.trim();
|
|
52838
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
52839
|
+
if (explicitTargetId) {
|
|
52840
|
+
return {
|
|
52841
|
+
scopeType: params.scope,
|
|
52842
|
+
targetId: explicitTargetId,
|
|
52843
|
+
repoRoot: bindingContext.repoRoot
|
|
52844
|
+
};
|
|
52845
|
+
}
|
|
52846
|
+
if (!bindingContext.binding) {
|
|
52847
|
+
throw makeNotBoundError("Scope target was not provided and the current repository is not bound to Remix.");
|
|
52848
|
+
}
|
|
52849
|
+
if (params.scope === "app") {
|
|
52850
|
+
return {
|
|
52851
|
+
scopeType: "app",
|
|
52852
|
+
targetId: bindingContext.binding.currentAppId,
|
|
52853
|
+
repoRoot: bindingContext.repoRoot
|
|
52854
|
+
};
|
|
52855
|
+
}
|
|
52856
|
+
const appContext = unwrapResponseObject2(
|
|
52857
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
52858
|
+
"bound app context"
|
|
52859
|
+
);
|
|
52860
|
+
if (params.scope === "project") {
|
|
52861
|
+
if (!appContext.readableScopes.project) {
|
|
52862
|
+
throw createAccessDeniedError(
|
|
52863
|
+
"The bound app's project is not readable to the current user.",
|
|
52864
|
+
"Use `scope=app` for app-level diagnostics, or pass an explicit readable project id."
|
|
52865
|
+
);
|
|
52866
|
+
}
|
|
52867
|
+
return {
|
|
52868
|
+
scopeType: "project",
|
|
52869
|
+
targetId: appContext.projectId,
|
|
52870
|
+
repoRoot: bindingContext.repoRoot
|
|
52871
|
+
};
|
|
52872
|
+
}
|
|
52873
|
+
if (!appContext.readableScopes.organization) {
|
|
52874
|
+
throw createAccessDeniedError(
|
|
52875
|
+
"The bound app's organization is not readable to the current user.",
|
|
52876
|
+
"Use `scope=app` or `scope=project` for narrower diagnostics, or pass an explicit readable organization id."
|
|
52877
|
+
);
|
|
52878
|
+
}
|
|
52879
|
+
return {
|
|
52880
|
+
scopeType: "organization",
|
|
52881
|
+
targetId: appContext.organizationId,
|
|
52882
|
+
repoRoot: bindingContext.repoRoot
|
|
52883
|
+
};
|
|
52884
|
+
}
|
|
52885
|
+
async function getScopeEntity(api, scopeType, targetId) {
|
|
52886
|
+
if (scopeType === "organization") {
|
|
52887
|
+
return {
|
|
52888
|
+
organization: unwrapResponseObject2(await api.getOrganization(targetId), "organization"),
|
|
52889
|
+
project: null,
|
|
52890
|
+
app: null
|
|
52891
|
+
};
|
|
52892
|
+
}
|
|
52893
|
+
if (scopeType === "project") {
|
|
52894
|
+
const project2 = unwrapResponseObject2(await api.getProject(targetId), "project");
|
|
52895
|
+
const organizationId2 = typeof project2.organizationId === "string" ? project2.organizationId : null;
|
|
52896
|
+
return {
|
|
52897
|
+
organization: organizationId2 == null ? null : unwrapResponseObject2(await api.getOrganization(organizationId2), "organization"),
|
|
52898
|
+
project: project2,
|
|
52899
|
+
app: null
|
|
52900
|
+
};
|
|
52901
|
+
}
|
|
52902
|
+
const app = unwrapResponseObject2(await api.getApp(targetId), "app");
|
|
52903
|
+
const projectId = typeof app.projectId === "string" ? app.projectId : null;
|
|
52904
|
+
const project = projectId == null ? null : unwrapResponseObject2(await api.getProject(projectId), "project");
|
|
52905
|
+
const organizationId = typeof project?.organizationId === "string" ? project.organizationId : null;
|
|
52906
|
+
return {
|
|
52907
|
+
organization: organizationId == null ? null : unwrapResponseObject2(await api.getOrganization(organizationId), "organization"),
|
|
52908
|
+
project,
|
|
52909
|
+
app
|
|
52910
|
+
};
|
|
52911
|
+
}
|
|
52912
|
+
function mapProjectRoleToAppRole(role) {
|
|
52913
|
+
switch (role) {
|
|
52914
|
+
case "owner":
|
|
52915
|
+
case "maintainer":
|
|
52916
|
+
return "maintainer";
|
|
52917
|
+
case "editor":
|
|
52918
|
+
return "editor";
|
|
52919
|
+
case "viewer":
|
|
52920
|
+
return "viewer";
|
|
52921
|
+
default:
|
|
52922
|
+
return null;
|
|
52923
|
+
}
|
|
52924
|
+
}
|
|
52925
|
+
function strongestRole(...roles) {
|
|
52926
|
+
if (roles.includes("owner")) return "owner";
|
|
52927
|
+
if (roles.includes("maintainer")) return "maintainer";
|
|
52928
|
+
if (roles.includes("editor")) return "editor";
|
|
52929
|
+
if (roles.includes("viewer")) return "viewer";
|
|
52930
|
+
return null;
|
|
52931
|
+
}
|
|
52932
|
+
function resolveAppAccessSource(params) {
|
|
52933
|
+
if (params.directAppRole && params.inheritedProjectRole) return "both";
|
|
52934
|
+
if (params.directAppRole) return "direct_app_membership";
|
|
52935
|
+
if (params.inheritedProjectRole) return "project_membership";
|
|
52936
|
+
return "none";
|
|
52937
|
+
}
|
|
52938
|
+
function buildEffectiveAppAccess(params) {
|
|
52939
|
+
const directAppRole = params.directAppRole ?? null;
|
|
52940
|
+
const inheritedProjectRole = mapProjectRoleToAppRole(params.projectRole);
|
|
52941
|
+
const effectiveRole = strongestRole(directAppRole, inheritedProjectRole);
|
|
52942
|
+
return {
|
|
52943
|
+
effectiveRole,
|
|
52944
|
+
directAppRole,
|
|
52945
|
+
projectRole: params.projectRole,
|
|
52946
|
+
inheritedProjectRole,
|
|
52947
|
+
accessSource: resolveAppAccessSource({ directAppRole, inheritedProjectRole }),
|
|
52948
|
+
canReadWorkflow: effectiveRole !== null,
|
|
52949
|
+
canEdit: effectiveRole === "owner" || effectiveRole === "maintainer" || effectiveRole === "editor",
|
|
52950
|
+
canManage: effectiveRole === "owner" || effectiveRole === "maintainer",
|
|
52951
|
+
isOwner: directAppRole === "owner"
|
|
52952
|
+
};
|
|
52953
|
+
}
|
|
52954
|
+
async function listMembersForScope(api, scopeType, targetId, params) {
|
|
52955
|
+
if (scopeType === "organization") {
|
|
52956
|
+
return unwrapResponseObject2(await api.listOrganizationMembers(targetId, params), "organization members");
|
|
52957
|
+
}
|
|
52958
|
+
if (scopeType === "project") {
|
|
52959
|
+
return unwrapResponseObject2(await api.listProjectMembers(targetId, params), "project members");
|
|
52960
|
+
}
|
|
52961
|
+
return unwrapResponseObject2(await api.listAppMembers(targetId, params), "app members");
|
|
52962
|
+
}
|
|
52963
|
+
async function loadFirstPageSample(fetchPage) {
|
|
52964
|
+
const items = await fetchPage(MEMBERSHIP_PAGE_SIZE, 0);
|
|
52965
|
+
const hasMore = items.length < MEMBERSHIP_PAGE_SIZE ? false : (await fetchPage(1, MEMBERSHIP_PAGE_SIZE)).length > 0;
|
|
52966
|
+
return {
|
|
52967
|
+
items,
|
|
52968
|
+
pageInfo: {
|
|
52969
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
52970
|
+
offset: 0,
|
|
52971
|
+
hasMore
|
|
52972
|
+
}
|
|
52973
|
+
};
|
|
52974
|
+
}
|
|
52975
|
+
function emptyFirstPageSample() {
|
|
52976
|
+
return {
|
|
52977
|
+
items: [],
|
|
52978
|
+
pageInfo: {
|
|
52979
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
52980
|
+
offset: 0,
|
|
52981
|
+
hasMore: false
|
|
52982
|
+
}
|
|
52983
|
+
};
|
|
52984
|
+
}
|
|
52985
|
+
async function listInvitesForScope(api, scopeType, targetId, params) {
|
|
52986
|
+
if (scopeType === "organization") {
|
|
52987
|
+
return unwrapResponseObject2(
|
|
52988
|
+
await api.listOrganizationInvites(targetId, params),
|
|
52989
|
+
"organization invites"
|
|
52990
|
+
);
|
|
52991
|
+
}
|
|
52992
|
+
if (scopeType === "project") {
|
|
52993
|
+
return unwrapResponseObject2(
|
|
52994
|
+
await api.listProjectInvites(targetId, params),
|
|
52995
|
+
"project invites"
|
|
52996
|
+
);
|
|
52997
|
+
}
|
|
52998
|
+
return unwrapResponseObject2(await api.listAppInvites(targetId, params), "app invites");
|
|
52999
|
+
}
|
|
53000
|
+
function getSelfMember(meId, members) {
|
|
53001
|
+
return meId == null ? null : members.find((member) => member.userId === meId || member.user_id === meId) ?? null;
|
|
53002
|
+
}
|
|
53003
|
+
async function findPendingInviteForEmailForScope(api, scopeType, targetId, email2) {
|
|
53004
|
+
if (email2 == null) return null;
|
|
53005
|
+
let offset = 0;
|
|
53006
|
+
for (; ; ) {
|
|
53007
|
+
const invites = await listInvitesForScope(api, scopeType, targetId, {
|
|
53008
|
+
limit: MEMBERSHIP_PAGE_SIZE,
|
|
53009
|
+
offset
|
|
53010
|
+
});
|
|
53011
|
+
const match = invites.find((invite) => invite.email.toLowerCase() === email2 && invite.state === "pending") ?? null;
|
|
53012
|
+
if (match) return match;
|
|
53013
|
+
if (invites.length < MEMBERSHIP_PAGE_SIZE) return null;
|
|
53014
|
+
offset += MEMBERSHIP_PAGE_SIZE;
|
|
53015
|
+
}
|
|
53016
|
+
}
|
|
53017
|
+
async function findSelfMemberForScope(api, scopeType, targetId, meId) {
|
|
53018
|
+
if (meId == null) return null;
|
|
53019
|
+
let offset = 0;
|
|
53020
|
+
for (; ; ) {
|
|
53021
|
+
const members = scopeType === "organization" ? unwrapResponseObject2(
|
|
53022
|
+
await api.listOrganizationMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53023
|
+
"organization members"
|
|
53024
|
+
) : scopeType === "project" ? unwrapResponseObject2(
|
|
53025
|
+
await api.listProjectMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53026
|
+
"project members"
|
|
53027
|
+
) : unwrapResponseObject2(
|
|
53028
|
+
await api.listAppMembers(targetId, { limit: MEMBERSHIP_PAGE_SIZE, offset }),
|
|
53029
|
+
"app members"
|
|
53030
|
+
);
|
|
53031
|
+
const match = getSelfMember(meId, members);
|
|
53032
|
+
if (match) return match;
|
|
53033
|
+
if (members.length < MEMBERSHIP_PAGE_SIZE) return null;
|
|
53034
|
+
offset += MEMBERSHIP_PAGE_SIZE;
|
|
53035
|
+
}
|
|
53036
|
+
}
|
|
53037
|
+
async function listInvites(params) {
|
|
53038
|
+
const api = await createApiClient2();
|
|
53039
|
+
const target = await resolveScopeTarget2(api, {
|
|
53040
|
+
scope: params.scope ?? "project",
|
|
53041
|
+
targetId: params.targetId,
|
|
53042
|
+
cwd: params.cwd
|
|
53043
|
+
});
|
|
53044
|
+
const pagination = normalizePagination2(params);
|
|
53045
|
+
const invites = await listInvitesForScope(api, target.scopeType, target.targetId, {
|
|
53046
|
+
limit: pagination.limit + 1,
|
|
53047
|
+
offset: pagination.offset
|
|
53048
|
+
});
|
|
53049
|
+
return {
|
|
53050
|
+
data: {
|
|
53051
|
+
scopeType: target.scopeType,
|
|
53052
|
+
targetId: target.targetId,
|
|
53053
|
+
invites: invites.slice(0, pagination.limit),
|
|
53054
|
+
pagination: {
|
|
53055
|
+
...pagination,
|
|
53056
|
+
hasMore: invites.length > pagination.limit
|
|
53057
|
+
}
|
|
53058
|
+
},
|
|
53059
|
+
warnings: [],
|
|
53060
|
+
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."],
|
|
53061
|
+
logContext: {
|
|
53062
|
+
repoRoot: target.repoRoot
|
|
53063
|
+
}
|
|
53064
|
+
};
|
|
53065
|
+
}
|
|
53066
|
+
async function resendInvite(params) {
|
|
53067
|
+
const api = await createApiClient2();
|
|
53068
|
+
const target = await resolveScopeTarget2(api, {
|
|
53069
|
+
scope: params.scope ?? "project",
|
|
53070
|
+
targetId: params.targetId,
|
|
53071
|
+
cwd: params.cwd
|
|
53072
|
+
});
|
|
53073
|
+
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 });
|
|
53074
|
+
return {
|
|
53075
|
+
data: unwrapResponseObject2(response, "resent invite"),
|
|
53076
|
+
warnings: [],
|
|
53077
|
+
recommendedNextActions: ["Use `remix_collab_list_invites` to confirm the refreshed expiry and delivery state."],
|
|
53078
|
+
logContext: {
|
|
53079
|
+
repoRoot: target.repoRoot
|
|
53080
|
+
}
|
|
53081
|
+
};
|
|
53082
|
+
}
|
|
53083
|
+
async function revokeInvite(params) {
|
|
53084
|
+
const api = await createApiClient2();
|
|
53085
|
+
const target = await resolveScopeTarget2(api, {
|
|
53086
|
+
scope: params.scope ?? "project",
|
|
53087
|
+
targetId: params.targetId,
|
|
53088
|
+
cwd: params.cwd
|
|
53089
|
+
});
|
|
53090
|
+
if (target.scopeType === "organization") {
|
|
53091
|
+
await api.revokeOrganizationInvite(target.targetId, params.inviteId);
|
|
53092
|
+
} else if (target.scopeType === "project") {
|
|
53093
|
+
await api.revokeProjectInvite(target.targetId, params.inviteId);
|
|
53094
|
+
} else {
|
|
53095
|
+
await api.revokeAppInvite(target.targetId, params.inviteId);
|
|
53096
|
+
}
|
|
53097
|
+
return {
|
|
53098
|
+
data: {
|
|
53099
|
+
scopeType: target.scopeType,
|
|
53100
|
+
targetId: target.targetId,
|
|
53101
|
+
inviteId: params.inviteId,
|
|
53102
|
+
revoked: true
|
|
53103
|
+
},
|
|
53104
|
+
warnings: [],
|
|
53105
|
+
recommendedNextActions: ["Use `remix_collab_list_invites` to confirm the invite state is now `revoked`."],
|
|
53106
|
+
logContext: {
|
|
53107
|
+
repoRoot: target.repoRoot
|
|
53108
|
+
}
|
|
53109
|
+
};
|
|
53110
|
+
}
|
|
53111
|
+
async function acceptInvitation(params) {
|
|
53112
|
+
const api = await createApiClient2();
|
|
53113
|
+
const result = unwrapResponseObject2(await api.acceptInvitation({ token: params.token }), "accepted invitation");
|
|
53114
|
+
return {
|
|
53115
|
+
data: result,
|
|
53116
|
+
warnings: [],
|
|
53117
|
+
recommendedNextActions: result.redirectPath ? [`The invitation is accepted. Use the returned redirect metadata to continue with the newly granted Remix scope.`] : [],
|
|
53118
|
+
logContext: {}
|
|
53119
|
+
};
|
|
53120
|
+
}
|
|
53121
|
+
async function accessDebug(params) {
|
|
53122
|
+
const api = await createApiClient2();
|
|
53123
|
+
const target = await resolveScopeTarget2(api, {
|
|
53124
|
+
scope: params.scope ?? "project",
|
|
53125
|
+
targetId: params.targetId,
|
|
53126
|
+
cwd: params.cwd
|
|
53127
|
+
});
|
|
53128
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53129
|
+
const viewer = unwrapResponseObject2(await api.getMe(), "current user");
|
|
53130
|
+
const viewerId = typeof viewer.id === "string" ? viewer.id : null;
|
|
53131
|
+
const viewerEmail = typeof viewer.email === "string" ? viewer.email.toLowerCase() : null;
|
|
53132
|
+
const warnings = [...bindingContext.binding ? [] : ["No local Remix binding was detected for the provided cwd."]];
|
|
53133
|
+
let entities;
|
|
53134
|
+
let appContext = null;
|
|
53135
|
+
let membersPage = emptyFirstPageSample();
|
|
53136
|
+
let invitesPage = emptyFirstPageSample();
|
|
53137
|
+
let viewerMember = null;
|
|
53138
|
+
let viewerProjectMember = null;
|
|
53139
|
+
let inviteForViewerEmail = null;
|
|
53140
|
+
let effectiveAppAccess = null;
|
|
53141
|
+
if (target.scopeType !== "app") {
|
|
53142
|
+
[entities, membersPage, invitesPage] = await Promise.all([
|
|
53143
|
+
getScopeEntity(api, target.scopeType, target.targetId),
|
|
53144
|
+
loadFirstPageSample((limit, offset) => listMembersForScope(api, target.scopeType, target.targetId, { limit, offset })),
|
|
53145
|
+
loadFirstPageSample((limit, offset) => listInvitesForScope(api, target.scopeType, target.targetId, { limit, offset }))
|
|
53146
|
+
]);
|
|
53147
|
+
viewerMember = await findSelfMemberForScope(api, target.scopeType, target.targetId, viewerId);
|
|
53148
|
+
inviteForViewerEmail = await findPendingInviteForEmailForScope(api, target.scopeType, target.targetId, viewerEmail);
|
|
53149
|
+
} else {
|
|
53150
|
+
const [app, loadedAppContext] = await Promise.all([
|
|
53151
|
+
unwrapResponseObject2(await api.getApp(target.targetId), "app"),
|
|
53152
|
+
unwrapResponseObject2(await api.getAppContext(target.targetId), "app context")
|
|
53153
|
+
]);
|
|
53154
|
+
appContext = loadedAppContext;
|
|
53155
|
+
entities = {
|
|
53156
|
+
organization: null,
|
|
53157
|
+
project: null,
|
|
53158
|
+
app
|
|
53159
|
+
};
|
|
53160
|
+
if (appContext.readableScopes.project) {
|
|
53161
|
+
try {
|
|
53162
|
+
entities.project = unwrapResponseObject2(await api.getProject(appContext.projectId), "project");
|
|
53163
|
+
} catch (error2) {
|
|
53164
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53165
|
+
warnings.push("The app is readable, but its project/workspace metadata is not currently readable to the current user.");
|
|
53166
|
+
}
|
|
53167
|
+
} else {
|
|
53168
|
+
warnings.push("The app is readable, but its project/workspace is not readable to the current user.");
|
|
53169
|
+
}
|
|
53170
|
+
if (appContext.readableScopes.organization) {
|
|
53171
|
+
try {
|
|
53172
|
+
entities.organization = unwrapResponseObject2(await api.getOrganization(appContext.organizationId), "organization");
|
|
53173
|
+
} catch (error2) {
|
|
53174
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53175
|
+
warnings.push("The app is readable, but its organization metadata is not currently readable to the current user.");
|
|
53176
|
+
}
|
|
53177
|
+
} else {
|
|
53178
|
+
warnings.push("The app's organization is not readable to the current user.");
|
|
53179
|
+
}
|
|
53180
|
+
effectiveAppAccess = {
|
|
53181
|
+
...buildEffectiveAppAccess({
|
|
53182
|
+
directAppRole: appContext.roles.appRole,
|
|
53183
|
+
projectRole: appContext.roles.projectRole
|
|
53184
|
+
}),
|
|
53185
|
+
accessPath: appContext.accessPath,
|
|
53186
|
+
readableScopes: appContext.readableScopes,
|
|
53187
|
+
visibility: appContext.visibility,
|
|
53188
|
+
organizationRole: appContext.roles.organizationRole ?? null
|
|
53189
|
+
};
|
|
53190
|
+
if (appContext.capabilities.canReadWorkflow) {
|
|
53191
|
+
membersPage = await loadFirstPageSample((limit, offset) => listMembersForScope(api, "app", target.targetId, { limit, offset }));
|
|
53192
|
+
viewerMember = await findSelfMemberForScope(api, "app", target.targetId, viewerId);
|
|
53193
|
+
if (appContext.readableScopes.project) {
|
|
53194
|
+
viewerProjectMember = await findSelfMemberForScope(api, "project", appContext.projectId, viewerId);
|
|
53195
|
+
}
|
|
53196
|
+
try {
|
|
53197
|
+
invitesPage = await loadFirstPageSample((limit, offset) => listInvitesForScope(api, "app", target.targetId, { limit, offset }));
|
|
53198
|
+
inviteForViewerEmail = await findPendingInviteForEmailForScope(api, "app", target.targetId, viewerEmail);
|
|
53199
|
+
} catch (error2) {
|
|
53200
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53201
|
+
warnings.push("App invite data is not readable to the current user, so invite diagnostics are partial.");
|
|
53202
|
+
}
|
|
53203
|
+
} else {
|
|
53204
|
+
warnings.push("The current viewer can read the app, but cannot read workflow-scoped app membership data.");
|
|
53205
|
+
}
|
|
53206
|
+
}
|
|
53207
|
+
if (membersPage.pageInfo.hasMore) {
|
|
53208
|
+
warnings.push("The `members` array is a first-page sample only; use the scope member list tool to inspect the remaining entries.");
|
|
53209
|
+
}
|
|
53210
|
+
if (invitesPage.pageInfo.hasMore) {
|
|
53211
|
+
warnings.push("The `invites` array is a first-page sample only; use the invite list tool with pagination to inspect the remaining entries.");
|
|
53212
|
+
}
|
|
53213
|
+
return {
|
|
53214
|
+
data: {
|
|
53215
|
+
viewer,
|
|
53216
|
+
scope: {
|
|
53217
|
+
scopeType: target.scopeType,
|
|
53218
|
+
targetId: target.targetId
|
|
53219
|
+
},
|
|
53220
|
+
entities,
|
|
53221
|
+
binding: {
|
|
53222
|
+
repoRoot: bindingContext.repoRoot,
|
|
53223
|
+
binding: bindingContext.binding
|
|
53224
|
+
},
|
|
53225
|
+
access: {
|
|
53226
|
+
appContext,
|
|
53227
|
+
viewerMember,
|
|
53228
|
+
viewerProjectMember,
|
|
53229
|
+
inviteForViewerEmail,
|
|
53230
|
+
effectiveAppAccess: effectiveAppAccess ?? null
|
|
53231
|
+
},
|
|
53232
|
+
members: membersPage.items,
|
|
53233
|
+
membersPageInfo: membersPage.pageInfo,
|
|
53234
|
+
invites: invitesPage.items,
|
|
53235
|
+
invitesPageInfo: invitesPage.pageInfo
|
|
53236
|
+
},
|
|
53237
|
+
warnings,
|
|
53238
|
+
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."],
|
|
53239
|
+
logContext: {
|
|
53240
|
+
repoRoot: target.repoRoot,
|
|
53241
|
+
appId: entities.app?.id ?? bindingContext.binding?.currentAppId ?? null
|
|
53242
|
+
}
|
|
53243
|
+
};
|
|
53244
|
+
}
|
|
53245
|
+
function getAnnotations(access, options) {
|
|
53246
|
+
if (access === "read") {
|
|
53247
|
+
return {
|
|
53248
|
+
readOnlyHint: true,
|
|
53249
|
+
idempotentHint: true,
|
|
53250
|
+
openWorldHint: false
|
|
53251
|
+
};
|
|
53252
|
+
}
|
|
53253
|
+
return {
|
|
53254
|
+
readOnlyHint: false,
|
|
53255
|
+
destructiveHint: access === "local_write",
|
|
53256
|
+
idempotentHint: options?.idempotent ?? false,
|
|
53257
|
+
openWorldHint: false
|
|
53258
|
+
};
|
|
53259
|
+
}
|
|
53260
|
+
function buildSuccessEnvelope(tool, requestId, result) {
|
|
53261
|
+
return {
|
|
53262
|
+
schemaVersion: SCHEMA_VERSION,
|
|
53263
|
+
ok: true,
|
|
53264
|
+
tool,
|
|
53265
|
+
requestId: requestId ?? null,
|
|
53266
|
+
data: result.data,
|
|
53267
|
+
warnings: result.warnings ?? [],
|
|
52438
53268
|
risks: result.risks ?? [],
|
|
52439
53269
|
recommendedNextActions: result.recommendedNextActions ?? []
|
|
52440
53270
|
};
|
|
52441
53271
|
}
|
|
52442
53272
|
function deriveErrorRisks(tool, normalized) {
|
|
52443
|
-
if ((tool
|
|
53273
|
+
if (isFinalizeTurnLocalSyncFailure(tool, normalized)) {
|
|
52444
53274
|
return ["The change step succeeded remotely, but the local repository may need manual recovery or a follow-up sync."];
|
|
52445
53275
|
}
|
|
52446
53276
|
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
@@ -52454,9 +53284,16 @@ function deriveErrorRisks(tool, normalized) {
|
|
|
52454
53284
|
}
|
|
52455
53285
|
return [];
|
|
52456
53286
|
}
|
|
53287
|
+
function isFinalizeTurnLocalSyncFailure(tool, normalized) {
|
|
53288
|
+
return tool === "remix_collab_finalize_turn" && normalized.message === "Change step succeeded remotely, but automatic local sync failed.";
|
|
53289
|
+
}
|
|
52457
53290
|
function buildErrorEnvelope(tool, requestId, error2) {
|
|
52458
53291
|
const normalized = normalizeToolError(error2);
|
|
52459
|
-
const recommendedNextActions =
|
|
53292
|
+
const recommendedNextActions = isFinalizeTurnLocalSyncFailure(tool, normalized) ? [
|
|
53293
|
+
"Run `remix_collab_status` to confirm the bound repo state before attempting recovery.",
|
|
53294
|
+
"Run `remix_collab_sync_preview` next, then `remix_collab_sync_apply` with `confirm=true` if the preview looks correct.",
|
|
53295
|
+
"Inspect `error.hint` for any preserved diff backup path before retrying local recovery, and do not rerun `remix_collab_finalize_turn` immediately."
|
|
53296
|
+
] : 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
53297
|
return {
|
|
52461
53298
|
schemaVersion: SCHEMA_VERSION,
|
|
52462
53299
|
ok: false,
|
|
@@ -52477,7 +53314,7 @@ function registerTool(server, context, params) {
|
|
|
52477
53314
|
description: params.description,
|
|
52478
53315
|
inputSchema: params.inputSchema,
|
|
52479
53316
|
outputSchema: params.outputSchema,
|
|
52480
|
-
annotations: getAnnotations(params.access)
|
|
53317
|
+
annotations: params.annotations ?? getAnnotations(params.access)
|
|
52481
53318
|
},
|
|
52482
53319
|
async (rawArgs) => {
|
|
52483
53320
|
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
@@ -52557,7 +53394,11 @@ function registerCollabTools(server, context) {
|
|
|
52557
53394
|
outputSchema: listSuccessSchema,
|
|
52558
53395
|
run: async (args) => {
|
|
52559
53396
|
const input = external_exports.object(listInputSchema).parse(args);
|
|
52560
|
-
return listApps({
|
|
53397
|
+
return listApps({
|
|
53398
|
+
forked: input.forked,
|
|
53399
|
+
limit: input.limit,
|
|
53400
|
+
offset: input.offset
|
|
53401
|
+
});
|
|
52561
53402
|
}
|
|
52562
53403
|
});
|
|
52563
53404
|
registerTool(server, context, {
|
|
@@ -52594,89 +53435,25 @@ function registerCollabTools(server, context) {
|
|
|
52594
53435
|
}
|
|
52595
53436
|
});
|
|
52596
53437
|
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.",
|
|
53438
|
+
name: "remix_collab_finalize_turn",
|
|
53439
|
+
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
53440
|
access: "local_write",
|
|
52626
|
-
inputSchema:
|
|
52627
|
-
outputSchema:
|
|
53441
|
+
inputSchema: finalizeTurnInputSchema,
|
|
53442
|
+
outputSchema: finalizeTurnSuccessSchema,
|
|
53443
|
+
annotations: getAnnotations("local_write", { idempotent: true }),
|
|
52628
53444
|
run: async (args) => {
|
|
52629
|
-
const input = external_exports.object(
|
|
53445
|
+
const input = external_exports.object(finalizeTurnInputSchema).parse(args);
|
|
52630
53446
|
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52631
|
-
|
|
52632
|
-
|
|
52633
|
-
const externalDiff = input.externalDiff ?? "";
|
|
52634
|
-
assertDiffWithinLimit(context.policy, externalDiff);
|
|
53447
|
+
if ((input.diffSource ?? "worktree") === "external" || typeof input.externalDiff === "string") {
|
|
53448
|
+
assertDiffWithinLimit(context.policy, input.externalDiff ?? "");
|
|
52635
53449
|
}
|
|
52636
|
-
return
|
|
53450
|
+
return finalizeCollabTurn({
|
|
52637
53451
|
cwd,
|
|
52638
53452
|
prompt: input.prompt,
|
|
52639
53453
|
assistantResponse: input.assistantResponse,
|
|
52640
|
-
diffSource,
|
|
53454
|
+
diffSource: input.diffSource,
|
|
52641
53455
|
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,
|
|
53456
|
+
sync: input.sync,
|
|
52680
53457
|
allowBranchMismatch: input.allowBranchMismatch ?? false,
|
|
52681
53458
|
idempotencyKey: input.idempotencyKey,
|
|
52682
53459
|
agent: context.agentMetadata
|
|
@@ -52728,7 +53505,12 @@ function registerCollabTools(server, context) {
|
|
|
52728
53505
|
outputSchema: mergeRequestQueueSuccessSchema,
|
|
52729
53506
|
run: async (args) => {
|
|
52730
53507
|
const input = external_exports.object(reviewQueueInputSchema).parse(args);
|
|
52731
|
-
return reviewQueue({
|
|
53508
|
+
return reviewQueue({
|
|
53509
|
+
status: input.status,
|
|
53510
|
+
kind: input.kind,
|
|
53511
|
+
limit: input.limit,
|
|
53512
|
+
offset: input.offset
|
|
53513
|
+
});
|
|
52732
53514
|
}
|
|
52733
53515
|
});
|
|
52734
53516
|
registerTool(server, context, {
|
|
@@ -52739,7 +53521,12 @@ function registerCollabTools(server, context) {
|
|
|
52739
53521
|
outputSchema: mergeRequestQueueSuccessSchema,
|
|
52740
53522
|
run: async (args) => {
|
|
52741
53523
|
const input = external_exports.object(myMergeRequestsInputSchema).parse(args);
|
|
52742
|
-
return myMergeRequests({
|
|
53524
|
+
return myMergeRequests({
|
|
53525
|
+
status: input.status,
|
|
53526
|
+
kind: input.kind,
|
|
53527
|
+
limit: input.limit,
|
|
53528
|
+
offset: input.offset
|
|
53529
|
+
});
|
|
52743
53530
|
}
|
|
52744
53531
|
});
|
|
52745
53532
|
registerTool(server, context, {
|
|
@@ -52756,7 +53543,9 @@ function registerCollabTools(server, context) {
|
|
|
52756
53543
|
appId: input.appId,
|
|
52757
53544
|
queue: input.queue,
|
|
52758
53545
|
status: input.status,
|
|
52759
|
-
kind: input.kind
|
|
53546
|
+
kind: input.kind,
|
|
53547
|
+
limit: input.limit,
|
|
53548
|
+
offset: input.offset
|
|
52760
53549
|
});
|
|
52761
53550
|
}
|
|
52762
53551
|
});
|
|
@@ -52890,33 +53679,665 @@ function registerCollabTools(server, context) {
|
|
|
52890
53679
|
return listMembers({
|
|
52891
53680
|
cwd,
|
|
52892
53681
|
scope: input.scope,
|
|
52893
|
-
targetId: input.targetId
|
|
53682
|
+
targetId: input.targetId,
|
|
53683
|
+
limit: input.limit,
|
|
53684
|
+
offset: input.offset
|
|
52894
53685
|
});
|
|
52895
53686
|
}
|
|
52896
53687
|
});
|
|
52897
53688
|
registerTool(server, context, {
|
|
52898
|
-
name: "
|
|
52899
|
-
description: "
|
|
53689
|
+
name: "remix_collab_list_invites",
|
|
53690
|
+
description: "List invitations for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
53691
|
+
access: "read",
|
|
53692
|
+
inputSchema: listInvitesInputSchema,
|
|
53693
|
+
outputSchema: listInvitesSuccessSchema,
|
|
53694
|
+
run: async (args) => {
|
|
53695
|
+
const input = external_exports.object(listInvitesInputSchema).parse(args);
|
|
53696
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53697
|
+
return listInvites({
|
|
53698
|
+
cwd,
|
|
53699
|
+
scope: input.scope ?? "project",
|
|
53700
|
+
targetId: input.targetId,
|
|
53701
|
+
limit: input.limit,
|
|
53702
|
+
offset: input.offset
|
|
53703
|
+
});
|
|
53704
|
+
}
|
|
53705
|
+
});
|
|
53706
|
+
registerTool(server, context, {
|
|
53707
|
+
name: "remix_collab_resend_invite",
|
|
53708
|
+
description: "Resend an existing invitation for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
52900
53709
|
access: "remote_write",
|
|
52901
|
-
inputSchema:
|
|
52902
|
-
outputSchema:
|
|
53710
|
+
inputSchema: resendInviteInputSchema,
|
|
53711
|
+
outputSchema: resendInviteSuccessSchema,
|
|
52903
53712
|
run: async (args) => {
|
|
52904
|
-
const input = external_exports.object(
|
|
52905
|
-
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
52906
|
-
return
|
|
53713
|
+
const input = external_exports.object(resendInviteInputSchema).parse(args);
|
|
53714
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53715
|
+
return resendInvite({
|
|
52907
53716
|
cwd,
|
|
52908
|
-
scope: input.scope,
|
|
53717
|
+
scope: input.scope ?? "project",
|
|
52909
53718
|
targetId: input.targetId,
|
|
52910
|
-
|
|
52911
|
-
|
|
53719
|
+
inviteId: input.inviteId,
|
|
53720
|
+
ttlDays: input.ttlDays
|
|
52912
53721
|
});
|
|
52913
53722
|
}
|
|
52914
53723
|
});
|
|
52915
|
-
|
|
52916
|
-
|
|
53724
|
+
registerTool(server, context, {
|
|
53725
|
+
name: "remix_collab_revoke_invite",
|
|
53726
|
+
description: "Revoke an existing invitation for an organization, project, or app, using the current repository binding unless targetId is provided.",
|
|
53727
|
+
access: "remote_write",
|
|
53728
|
+
inputSchema: revokeInviteInputSchema,
|
|
53729
|
+
outputSchema: revokeInviteSuccessSchema,
|
|
53730
|
+
run: async (args) => {
|
|
53731
|
+
const input = external_exports.object(revokeInviteInputSchema).parse(args);
|
|
53732
|
+
assertConfirm(input.confirm, "remix_collab_revoke_invite");
|
|
53733
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53734
|
+
return revokeInvite({
|
|
53735
|
+
cwd,
|
|
53736
|
+
scope: input.scope ?? "project",
|
|
53737
|
+
targetId: input.targetId,
|
|
53738
|
+
inviteId: input.inviteId
|
|
53739
|
+
});
|
|
53740
|
+
}
|
|
53741
|
+
});
|
|
53742
|
+
registerTool(server, context, {
|
|
53743
|
+
name: "remix_collab_accept_invitation",
|
|
53744
|
+
description: "Accept an invitation token for the currently authenticated Remix user.",
|
|
53745
|
+
access: "remote_write",
|
|
53746
|
+
inputSchema: acceptInvitationInputSchema,
|
|
53747
|
+
outputSchema: acceptInvitationSuccessSchema,
|
|
53748
|
+
annotations: getAnnotations("remote_write", { idempotent: true }),
|
|
53749
|
+
run: async (args) => {
|
|
53750
|
+
const input = external_exports.object(acceptInvitationInputSchema).parse(args);
|
|
53751
|
+
return acceptInvitation({
|
|
53752
|
+
token: input.token
|
|
53753
|
+
});
|
|
53754
|
+
}
|
|
53755
|
+
});
|
|
53756
|
+
registerTool(server, context, {
|
|
53757
|
+
name: "remix_access_debug",
|
|
53758
|
+
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.",
|
|
53759
|
+
access: "read",
|
|
53760
|
+
inputSchema: accessDebugInputSchema,
|
|
53761
|
+
outputSchema: accessDebugSuccessSchema,
|
|
53762
|
+
run: async (args) => {
|
|
53763
|
+
const input = external_exports.object(accessDebugInputSchema).parse(args);
|
|
53764
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
53765
|
+
return accessDebug({
|
|
53766
|
+
cwd,
|
|
53767
|
+
scope: input.scope ?? "project",
|
|
53768
|
+
targetId: input.targetId
|
|
53769
|
+
});
|
|
53770
|
+
}
|
|
53771
|
+
});
|
|
53772
|
+
registerTool(server, context, {
|
|
53773
|
+
name: "remix_collab_update_member_role",
|
|
53774
|
+
description: "Update an organization, project, or app member role, using the current repository binding unless targetId is provided.",
|
|
53775
|
+
access: "remote_write",
|
|
53776
|
+
inputSchema: updateMemberRoleInputSchema,
|
|
53777
|
+
outputSchema: updateMemberRoleSuccessSchema,
|
|
53778
|
+
run: async (args) => {
|
|
53779
|
+
const input = external_exports.object(updateMemberRoleInputSchema).parse(args);
|
|
53780
|
+
const cwd = resolvePolicyCwd(context.policy, input.cwd);
|
|
53781
|
+
return updateMemberRole({
|
|
53782
|
+
cwd,
|
|
53783
|
+
scope: input.scope,
|
|
53784
|
+
targetId: input.targetId,
|
|
53785
|
+
userId: input.userId,
|
|
53786
|
+
role: input.role
|
|
53787
|
+
});
|
|
53788
|
+
}
|
|
53789
|
+
});
|
|
53790
|
+
}
|
|
53791
|
+
var genericRecordSchema2 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
52917
53792
|
var genericArraySchema2 = external_exports.array(genericRecordSchema2);
|
|
53793
|
+
var paginationSchema2 = external_exports.object({
|
|
53794
|
+
limit: external_exports.number().int().positive(),
|
|
53795
|
+
offset: external_exports.number().int().nonnegative(),
|
|
53796
|
+
hasMore: external_exports.boolean()
|
|
53797
|
+
});
|
|
53798
|
+
var whoamiInputSchema = {
|
|
53799
|
+
...commonRequestFieldsSchema
|
|
53800
|
+
};
|
|
53801
|
+
var directoryOrganizationInputSchema = {
|
|
53802
|
+
...commonRequestFieldsSchema,
|
|
53803
|
+
organizationId: external_exports.string().trim().min(1).optional()
|
|
53804
|
+
};
|
|
53805
|
+
var directoryListProjectsInputSchema = {
|
|
53806
|
+
...commonRequestFieldsSchema,
|
|
53807
|
+
organizationId: external_exports.string().trim().min(1).optional(),
|
|
53808
|
+
clientAppId: external_exports.string().trim().min(1).optional()
|
|
53809
|
+
};
|
|
53810
|
+
var directoryProjectInputSchema = {
|
|
53811
|
+
...commonRequestFieldsSchema,
|
|
53812
|
+
projectId: external_exports.string().trim().min(1).optional()
|
|
53813
|
+
};
|
|
53814
|
+
var directoryListAppsInputSchema = {
|
|
53815
|
+
...commonRequestFieldsSchema,
|
|
53816
|
+
projectId: external_exports.string().trim().min(1).optional(),
|
|
53817
|
+
organizationId: external_exports.string().trim().min(1).optional(),
|
|
53818
|
+
forked: external_exports.enum(["only", "exclude", "all"]).optional(),
|
|
53819
|
+
limit: external_exports.number().int().positive().max(50).optional(),
|
|
53820
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
53821
|
+
};
|
|
53822
|
+
var directoryAppInputSchema = {
|
|
53823
|
+
...commonRequestFieldsSchema,
|
|
53824
|
+
appId: external_exports.string().trim().min(1).optional()
|
|
53825
|
+
};
|
|
53826
|
+
var whoamiDataSchema = external_exports.object({
|
|
53827
|
+
id: external_exports.string().nullable(),
|
|
53828
|
+
name: external_exports.string().nullable(),
|
|
53829
|
+
email: external_exports.string().nullable(),
|
|
53830
|
+
organizationId: external_exports.string().nullable(),
|
|
53831
|
+
roles: genericRecordSchema2,
|
|
53832
|
+
binding: genericRecordSchema2.nullable()
|
|
53833
|
+
});
|
|
53834
|
+
var listOrganizationsDataSchema = external_exports.object({
|
|
53835
|
+
organizations: genericArraySchema2
|
|
53836
|
+
});
|
|
53837
|
+
var getOrganizationDataSchema = external_exports.object({
|
|
53838
|
+
organization: genericRecordSchema2
|
|
53839
|
+
});
|
|
53840
|
+
var listProjectsDataSchema = external_exports.object({
|
|
53841
|
+
organizationId: external_exports.string().nullable(),
|
|
53842
|
+
projects: genericArraySchema2
|
|
53843
|
+
});
|
|
53844
|
+
var getProjectDataSchema = external_exports.object({
|
|
53845
|
+
project: genericRecordSchema2
|
|
53846
|
+
});
|
|
53847
|
+
var listAppsDataSchema = external_exports.object({
|
|
53848
|
+
apps: genericArraySchema2,
|
|
53849
|
+
pagination: paginationSchema2,
|
|
53850
|
+
filters: external_exports.object({
|
|
53851
|
+
projectId: external_exports.string().nullable(),
|
|
53852
|
+
organizationId: external_exports.string().nullable(),
|
|
53853
|
+
forked: external_exports.enum(["only", "exclude", "all"])
|
|
53854
|
+
})
|
|
53855
|
+
});
|
|
53856
|
+
var getAppDataSchema = external_exports.object({
|
|
53857
|
+
app: genericRecordSchema2
|
|
53858
|
+
});
|
|
53859
|
+
var whoamiSuccessSchema = makeSuccessSchema(whoamiDataSchema);
|
|
53860
|
+
var listOrganizationsSuccessSchema = makeSuccessSchema(listOrganizationsDataSchema);
|
|
53861
|
+
var getOrganizationSuccessSchema = makeSuccessSchema(getOrganizationDataSchema);
|
|
53862
|
+
var listProjectsSuccessSchema = makeSuccessSchema(listProjectsDataSchema);
|
|
53863
|
+
var getProjectSuccessSchema = makeSuccessSchema(getProjectDataSchema);
|
|
53864
|
+
var listAppsSuccessSchema = makeSuccessSchema(listAppsDataSchema);
|
|
53865
|
+
var getAppSuccessSchema = makeSuccessSchema(getAppDataSchema);
|
|
53866
|
+
function normalizePagination22(params) {
|
|
53867
|
+
const rawLimit = typeof params?.limit === "number" ? Math.trunc(params.limit) : 25;
|
|
53868
|
+
const rawOffset = typeof params?.offset === "number" ? Math.trunc(params.offset) : 0;
|
|
53869
|
+
return {
|
|
53870
|
+
limit: Math.max(1, Math.min(50, rawLimit)),
|
|
53871
|
+
offset: Math.max(0, rawOffset)
|
|
53872
|
+
};
|
|
53873
|
+
}
|
|
53874
|
+
async function resolveOrganizationId(api, params) {
|
|
53875
|
+
const explicitId = params.organizationId?.trim();
|
|
53876
|
+
if (explicitId) return explicitId;
|
|
53877
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53878
|
+
if (!bindingContext.binding) {
|
|
53879
|
+
throw makeNotBoundError("Organization id was not provided and the current repository is not bound to Remix.");
|
|
53880
|
+
}
|
|
53881
|
+
const appContext = unwrapResponseObject2(
|
|
53882
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
53883
|
+
"bound app context"
|
|
53884
|
+
);
|
|
53885
|
+
if (!appContext.readableScopes.organization) {
|
|
53886
|
+
throw createAccessDeniedError(
|
|
53887
|
+
"The bound app's organization is not readable to the current user.",
|
|
53888
|
+
"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."
|
|
53889
|
+
);
|
|
53890
|
+
}
|
|
53891
|
+
return appContext.organizationId;
|
|
53892
|
+
}
|
|
53893
|
+
async function resolveProjectId(api, params) {
|
|
53894
|
+
const explicitId = params.projectId?.trim();
|
|
53895
|
+
if (explicitId) {
|
|
53896
|
+
const bindingContext2 = await loadBindingContext(params.cwd);
|
|
53897
|
+
return { projectId: explicitId, repoRoot: bindingContext2.repoRoot };
|
|
53898
|
+
}
|
|
53899
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53900
|
+
if (!bindingContext.binding) {
|
|
53901
|
+
throw makeNotBoundError("Project id was not provided and the current repository is not bound to Remix.");
|
|
53902
|
+
}
|
|
53903
|
+
const appContext = unwrapResponseObject2(
|
|
53904
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
53905
|
+
"bound app context"
|
|
53906
|
+
);
|
|
53907
|
+
if (!appContext.readableScopes.project) {
|
|
53908
|
+
throw createAccessDeniedError(
|
|
53909
|
+
"The bound app's project is not readable to the current user.",
|
|
53910
|
+
"Use `remix_directory_get_app` or `remix_access_debug` for app-level diagnostics, or pass an explicit project id you can access."
|
|
53911
|
+
);
|
|
53912
|
+
}
|
|
53913
|
+
return {
|
|
53914
|
+
projectId: appContext.projectId,
|
|
53915
|
+
repoRoot: bindingContext.repoRoot
|
|
53916
|
+
};
|
|
53917
|
+
}
|
|
53918
|
+
async function resolveAppId(params) {
|
|
53919
|
+
const explicitId = params.appId?.trim();
|
|
53920
|
+
if (explicitId) {
|
|
53921
|
+
const bindingContext2 = await loadBindingContext(params.cwd);
|
|
53922
|
+
return { appId: explicitId, repoRoot: bindingContext2.repoRoot };
|
|
53923
|
+
}
|
|
53924
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53925
|
+
if (!bindingContext.binding) {
|
|
53926
|
+
throw makeNotBoundError("App id was not provided and the current repository is not bound to Remix.");
|
|
53927
|
+
}
|
|
53928
|
+
return {
|
|
53929
|
+
appId: bindingContext.binding.currentAppId,
|
|
53930
|
+
repoRoot: bindingContext.repoRoot
|
|
53931
|
+
};
|
|
53932
|
+
}
|
|
53933
|
+
function toEffectiveAppRole(role) {
|
|
53934
|
+
switch (role) {
|
|
53935
|
+
case "owner":
|
|
53936
|
+
case "maintainer":
|
|
53937
|
+
case "editor":
|
|
53938
|
+
case "viewer":
|
|
53939
|
+
return role;
|
|
53940
|
+
default:
|
|
53941
|
+
return null;
|
|
53942
|
+
}
|
|
53943
|
+
}
|
|
53944
|
+
function resolveAppAccessSource2(params) {
|
|
53945
|
+
if (params.directAppRole && params.inheritedProjectRole) return "both";
|
|
53946
|
+
if (params.directAppRole) return "direct_app_membership";
|
|
53947
|
+
if (params.inheritedProjectRole) return "project_membership";
|
|
53948
|
+
return "none";
|
|
53949
|
+
}
|
|
53950
|
+
function emptySelfRoles() {
|
|
53951
|
+
return {
|
|
53952
|
+
organizationRole: null,
|
|
53953
|
+
projectRole: null,
|
|
53954
|
+
appRole: null,
|
|
53955
|
+
directAppRole: null,
|
|
53956
|
+
inheritedProjectRole: null,
|
|
53957
|
+
appAccessSource: "none"
|
|
53958
|
+
};
|
|
53959
|
+
}
|
|
53960
|
+
function resolveSelfRolesFromAppContext(appContext) {
|
|
53961
|
+
if (!appContext) return emptySelfRoles();
|
|
53962
|
+
const directAppRole = toEffectiveAppRole(appContext.roles.appRole);
|
|
53963
|
+
const inheritedProjectRole = toEffectiveAppRole(appContext.roles.inheritedProjectRole);
|
|
53964
|
+
return {
|
|
53965
|
+
organizationRole: appContext.roles.organizationRole ?? null,
|
|
53966
|
+
projectRole: appContext.roles.projectRole ?? null,
|
|
53967
|
+
appRole: toEffectiveAppRole(appContext.roles.effectiveAppRole),
|
|
53968
|
+
directAppRole,
|
|
53969
|
+
inheritedProjectRole,
|
|
53970
|
+
appAccessSource: resolveAppAccessSource2({ directAppRole, inheritedProjectRole })
|
|
53971
|
+
};
|
|
53972
|
+
}
|
|
53973
|
+
async function whoAmI(params) {
|
|
53974
|
+
const api = await createApiClient2();
|
|
53975
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
53976
|
+
const me = unwrapResponseObject2(await api.getMe(), "current user");
|
|
53977
|
+
const warnings = bindingContext.binding ? [] : ["No local Remix binding was detected for the provided cwd."];
|
|
53978
|
+
let boundAppContext = null;
|
|
53979
|
+
let boundProject = null;
|
|
53980
|
+
let boundApp = null;
|
|
53981
|
+
if (bindingContext.binding) {
|
|
53982
|
+
try {
|
|
53983
|
+
boundAppContext = unwrapResponseObject2(
|
|
53984
|
+
await api.getAppContext(bindingContext.binding.currentAppId),
|
|
53985
|
+
"bound app context"
|
|
53986
|
+
);
|
|
53987
|
+
} catch (error2) {
|
|
53988
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53989
|
+
warnings.push(
|
|
53990
|
+
"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."
|
|
53991
|
+
);
|
|
53992
|
+
}
|
|
53993
|
+
try {
|
|
53994
|
+
boundApp = unwrapResponseObject2(await api.getApp(bindingContext.binding.currentAppId), "app");
|
|
53995
|
+
} catch (error2) {
|
|
53996
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
53997
|
+
warnings.push("The bound app metadata could not be loaded for the current user.");
|
|
53998
|
+
}
|
|
53999
|
+
if (boundAppContext?.readableScopes.project) {
|
|
54000
|
+
try {
|
|
54001
|
+
boundProject = unwrapResponseObject2(await api.getProject(boundAppContext.projectId), "project");
|
|
54002
|
+
} catch (error2) {
|
|
54003
|
+
if (!isBackendForbidden(error2) && !isBackendNotFound(error2)) throw error2;
|
|
54004
|
+
warnings.push("The bound app is readable, but its project metadata is not currently readable to the current user.");
|
|
54005
|
+
}
|
|
54006
|
+
} else if (boundAppContext) {
|
|
54007
|
+
warnings.push("The bound app is readable, but its project/workspace is not readable to the current user.");
|
|
54008
|
+
}
|
|
54009
|
+
}
|
|
54010
|
+
const roles = resolveSelfRolesFromAppContext(boundAppContext);
|
|
54011
|
+
return {
|
|
54012
|
+
data: {
|
|
54013
|
+
id: me.id ?? null,
|
|
54014
|
+
name: me.name ?? null,
|
|
54015
|
+
email: me.email ?? null,
|
|
54016
|
+
organizationId: me.organizationId ?? null,
|
|
54017
|
+
roles,
|
|
54018
|
+
binding: bindingContext.binding == null ? null : {
|
|
54019
|
+
repoRoot: bindingContext.repoRoot,
|
|
54020
|
+
...bindingContext.binding,
|
|
54021
|
+
projectId: boundAppContext?.projectId ?? bindingContext.binding.projectId,
|
|
54022
|
+
organizationId: boundAppContext?.organizationId ?? null,
|
|
54023
|
+
visibility: boundAppContext?.visibility ?? null,
|
|
54024
|
+
accessPath: boundAppContext?.accessPath ?? null,
|
|
54025
|
+
readableScopes: boundAppContext?.readableScopes ?? null,
|
|
54026
|
+
projectName: boundProject?.name ?? null,
|
|
54027
|
+
appName: boundApp?.name ?? null
|
|
54028
|
+
}
|
|
54029
|
+
},
|
|
54030
|
+
warnings,
|
|
54031
|
+
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."],
|
|
54032
|
+
logContext: {
|
|
54033
|
+
repoRoot: bindingContext.repoRoot,
|
|
54034
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54035
|
+
}
|
|
54036
|
+
};
|
|
54037
|
+
}
|
|
54038
|
+
async function listOrganizations() {
|
|
54039
|
+
const api = await createApiClient2();
|
|
54040
|
+
const organizations = unwrapResponseObject2(await api.listOrganizations(), "organizations");
|
|
54041
|
+
return {
|
|
54042
|
+
data: { organizations },
|
|
54043
|
+
warnings: [],
|
|
54044
|
+
recommendedNextActions: organizations.length ? ["Use `remix_directory_get_organization` for one organization, or `remix_directory_list_projects` to inspect projects under a chosen organization."] : [],
|
|
54045
|
+
logContext: {}
|
|
54046
|
+
};
|
|
54047
|
+
}
|
|
54048
|
+
async function getOrganization(params) {
|
|
54049
|
+
const api = await createApiClient2();
|
|
54050
|
+
const organizationId = await resolveOrganizationId(api, params);
|
|
54051
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54052
|
+
const organization = unwrapResponseObject2(await api.getOrganization(organizationId), "organization");
|
|
54053
|
+
return {
|
|
54054
|
+
data: { organization },
|
|
54055
|
+
warnings: [],
|
|
54056
|
+
recommendedNextActions: ["Use `remix_directory_list_projects` with this organization id to inspect its project directory."],
|
|
54057
|
+
logContext: {
|
|
54058
|
+
repoRoot: bindingContext.repoRoot
|
|
54059
|
+
}
|
|
54060
|
+
};
|
|
54061
|
+
}
|
|
54062
|
+
async function listProjects(params) {
|
|
54063
|
+
const api = await createApiClient2();
|
|
54064
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54065
|
+
const organizationId = params.organizationId !== void 0 ? await resolveOrganizationId(api, { organizationId: params.organizationId, cwd: params.cwd }) : null;
|
|
54066
|
+
const projects = unwrapResponseObject2(
|
|
54067
|
+
await api.listProjects({
|
|
54068
|
+
organizationId: organizationId ?? void 0,
|
|
54069
|
+
clientAppId: params.clientAppId
|
|
54070
|
+
}),
|
|
54071
|
+
"projects"
|
|
54072
|
+
);
|
|
54073
|
+
return {
|
|
54074
|
+
data: {
|
|
54075
|
+
projects,
|
|
54076
|
+
organizationId
|
|
54077
|
+
},
|
|
54078
|
+
warnings: [],
|
|
54079
|
+
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."] : [],
|
|
54080
|
+
logContext: {
|
|
54081
|
+
repoRoot: bindingContext.repoRoot,
|
|
54082
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54083
|
+
}
|
|
54084
|
+
};
|
|
54085
|
+
}
|
|
54086
|
+
async function getProject(params) {
|
|
54087
|
+
const api = await createApiClient2();
|
|
54088
|
+
const target = await resolveProjectId(api, params);
|
|
54089
|
+
const project = unwrapResponseObject2(await api.getProject(target.projectId), "project");
|
|
54090
|
+
return {
|
|
54091
|
+
data: { project },
|
|
54092
|
+
warnings: [],
|
|
54093
|
+
recommendedNextActions: ["Use `remix_directory_list_apps` with this project id to inspect apps under the project."],
|
|
54094
|
+
logContext: {
|
|
54095
|
+
repoRoot: target.repoRoot
|
|
54096
|
+
}
|
|
54097
|
+
};
|
|
54098
|
+
}
|
|
54099
|
+
async function listApps2(params) {
|
|
54100
|
+
const api = await createApiClient2();
|
|
54101
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54102
|
+
const pagination = normalizePagination22(params);
|
|
54103
|
+
const apps = unwrapResponseObject2(
|
|
54104
|
+
await api.listApps({
|
|
54105
|
+
projectId: params.projectId,
|
|
54106
|
+
organizationId: params.organizationId,
|
|
54107
|
+
forked: params.forked,
|
|
54108
|
+
limit: pagination.limit + 1,
|
|
54109
|
+
offset: pagination.offset
|
|
54110
|
+
}),
|
|
54111
|
+
"apps"
|
|
54112
|
+
);
|
|
54113
|
+
return {
|
|
54114
|
+
data: {
|
|
54115
|
+
apps: apps.slice(0, pagination.limit),
|
|
54116
|
+
pagination: {
|
|
54117
|
+
...pagination,
|
|
54118
|
+
hasMore: apps.length > pagination.limit
|
|
54119
|
+
},
|
|
54120
|
+
filters: {
|
|
54121
|
+
projectId: params.projectId ?? null,
|
|
54122
|
+
organizationId: params.organizationId ?? null,
|
|
54123
|
+
forked: params.forked ?? "all"
|
|
54124
|
+
}
|
|
54125
|
+
},
|
|
54126
|
+
warnings: [],
|
|
54127
|
+
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."],
|
|
54128
|
+
logContext: {
|
|
54129
|
+
repoRoot: bindingContext.repoRoot,
|
|
54130
|
+
appId: bindingContext.binding?.currentAppId ?? null
|
|
54131
|
+
}
|
|
54132
|
+
};
|
|
54133
|
+
}
|
|
54134
|
+
async function getApp(params) {
|
|
54135
|
+
const api = await createApiClient2();
|
|
54136
|
+
const target = await resolveAppId(params);
|
|
54137
|
+
const app = unwrapResponseObject2(await api.getApp(target.appId), "app");
|
|
54138
|
+
return {
|
|
54139
|
+
data: { app },
|
|
54140
|
+
warnings: [],
|
|
54141
|
+
recommendedNextActions: ["Use `remix_context_get_app_overview` for status and capability context, or `remix_ops_list_timeline` for bounded historical activity."],
|
|
54142
|
+
logContext: {
|
|
54143
|
+
repoRoot: target.repoRoot,
|
|
54144
|
+
appId: target.appId
|
|
54145
|
+
}
|
|
54146
|
+
};
|
|
54147
|
+
}
|
|
54148
|
+
function getAnnotations2(access) {
|
|
54149
|
+
return {
|
|
54150
|
+
readOnlyHint: access === "read",
|
|
54151
|
+
destructiveHint: false,
|
|
54152
|
+
idempotentHint: true,
|
|
54153
|
+
openWorldHint: false
|
|
54154
|
+
};
|
|
54155
|
+
}
|
|
54156
|
+
function buildSuccessEnvelope2(tool, requestId, result) {
|
|
54157
|
+
return {
|
|
54158
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54159
|
+
ok: true,
|
|
54160
|
+
tool,
|
|
54161
|
+
requestId: requestId ?? null,
|
|
54162
|
+
data: result.data,
|
|
54163
|
+
warnings: result.warnings ?? [],
|
|
54164
|
+
risks: result.risks ?? [],
|
|
54165
|
+
recommendedNextActions: result.recommendedNextActions ?? []
|
|
54166
|
+
};
|
|
54167
|
+
}
|
|
54168
|
+
function deriveErrorRisks2(normalized) {
|
|
54169
|
+
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
54170
|
+
return ["A policy guard blocked a disallowed operation."];
|
|
54171
|
+
}
|
|
54172
|
+
return [];
|
|
54173
|
+
}
|
|
54174
|
+
function buildErrorEnvelope2(tool, requestId, error2) {
|
|
54175
|
+
const normalized = normalizeToolError(error2);
|
|
54176
|
+
return {
|
|
54177
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54178
|
+
ok: false,
|
|
54179
|
+
tool,
|
|
54180
|
+
requestId: requestId ?? null,
|
|
54181
|
+
error: normalized,
|
|
54182
|
+
warnings: [],
|
|
54183
|
+
risks: deriveErrorRisks2(normalized),
|
|
54184
|
+
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
54185
|
+
};
|
|
54186
|
+
}
|
|
54187
|
+
function registerTool2(server, context, params) {
|
|
54188
|
+
const errorSchema = makeErrorSchema();
|
|
54189
|
+
server.registerTool(
|
|
54190
|
+
params.name,
|
|
54191
|
+
{
|
|
54192
|
+
title: params.name,
|
|
54193
|
+
description: params.description,
|
|
54194
|
+
inputSchema: params.inputSchema,
|
|
54195
|
+
outputSchema: params.outputSchema,
|
|
54196
|
+
annotations: getAnnotations2(params.access)
|
|
54197
|
+
},
|
|
54198
|
+
async (rawArgs) => {
|
|
54199
|
+
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
54200
|
+
const startedAt = Date.now();
|
|
54201
|
+
try {
|
|
54202
|
+
assertToolAccess(context.policy, params.access);
|
|
54203
|
+
const result = await params.run(rawArgs);
|
|
54204
|
+
const envelope = buildSuccessEnvelope2(params.name, requestId, result);
|
|
54205
|
+
params.outputSchema.parse(envelope);
|
|
54206
|
+
context.logger.log({
|
|
54207
|
+
level: "info",
|
|
54208
|
+
message: "tool_completed",
|
|
54209
|
+
tool: params.name,
|
|
54210
|
+
requestId: envelope.requestId,
|
|
54211
|
+
durationMs: Date.now() - startedAt,
|
|
54212
|
+
result: "success",
|
|
54213
|
+
repoRoot: result.logContext?.repoRoot ?? null,
|
|
54214
|
+
appId: result.logContext?.appId ?? null,
|
|
54215
|
+
mrId: result.logContext?.mrId ?? null
|
|
54216
|
+
});
|
|
54217
|
+
return makeSuccessResult2(envelope);
|
|
54218
|
+
} catch (error2) {
|
|
54219
|
+
const envelope = buildErrorEnvelope2(params.name, requestId, error2);
|
|
54220
|
+
errorSchema.parse(envelope);
|
|
54221
|
+
context.logger.log({
|
|
54222
|
+
level: "error",
|
|
54223
|
+
message: "tool_failed",
|
|
54224
|
+
tool: params.name,
|
|
54225
|
+
requestId: envelope.requestId,
|
|
54226
|
+
durationMs: Date.now() - startedAt,
|
|
54227
|
+
result: "error",
|
|
54228
|
+
errorCode: envelope.error.code
|
|
54229
|
+
});
|
|
54230
|
+
return makeErrorResult(envelope);
|
|
54231
|
+
}
|
|
54232
|
+
}
|
|
54233
|
+
);
|
|
54234
|
+
}
|
|
54235
|
+
function registerIdentityTools(server, context) {
|
|
54236
|
+
registerTool2(server, context, {
|
|
54237
|
+
name: "remix_identity_whoami",
|
|
54238
|
+
description: "Show the authenticated Remix user and, when cwd is provided, the current local binding and any immediately derivable roles for that bound workspace.",
|
|
54239
|
+
access: "read",
|
|
54240
|
+
inputSchema: whoamiInputSchema,
|
|
54241
|
+
outputSchema: whoamiSuccessSchema,
|
|
54242
|
+
run: async (args) => {
|
|
54243
|
+
const input = external_exports.object(whoamiInputSchema).parse(args);
|
|
54244
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54245
|
+
return whoAmI({ cwd });
|
|
54246
|
+
}
|
|
54247
|
+
});
|
|
54248
|
+
registerTool2(server, context, {
|
|
54249
|
+
name: "remix_directory_list_organizations",
|
|
54250
|
+
description: "List organizations visible to the authenticated Remix user.",
|
|
54251
|
+
access: "read",
|
|
54252
|
+
inputSchema: whoamiInputSchema,
|
|
54253
|
+
outputSchema: listOrganizationsSuccessSchema,
|
|
54254
|
+
run: async () => listOrganizations()
|
|
54255
|
+
});
|
|
54256
|
+
registerTool2(server, context, {
|
|
54257
|
+
name: "remix_directory_get_organization",
|
|
54258
|
+
description: "Fetch one organization by id, or infer the bound repository's organization from cwd when possible.",
|
|
54259
|
+
access: "read",
|
|
54260
|
+
inputSchema: directoryOrganizationInputSchema,
|
|
54261
|
+
outputSchema: getOrganizationSuccessSchema,
|
|
54262
|
+
run: async (args) => {
|
|
54263
|
+
const input = external_exports.object(directoryOrganizationInputSchema).parse(args);
|
|
54264
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54265
|
+
return getOrganization({
|
|
54266
|
+
organizationId: input.organizationId,
|
|
54267
|
+
cwd
|
|
54268
|
+
});
|
|
54269
|
+
}
|
|
54270
|
+
});
|
|
54271
|
+
registerTool2(server, context, {
|
|
54272
|
+
name: "remix_directory_list_projects",
|
|
54273
|
+
description: "List projects visible to the authenticated user, optionally narrowed to one organization or client app.",
|
|
54274
|
+
access: "read",
|
|
54275
|
+
inputSchema: directoryListProjectsInputSchema,
|
|
54276
|
+
outputSchema: listProjectsSuccessSchema,
|
|
54277
|
+
run: async (args) => {
|
|
54278
|
+
const input = external_exports.object(directoryListProjectsInputSchema).parse(args);
|
|
54279
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54280
|
+
return listProjects({
|
|
54281
|
+
organizationId: input.organizationId,
|
|
54282
|
+
clientAppId: input.clientAppId,
|
|
54283
|
+
cwd
|
|
54284
|
+
});
|
|
54285
|
+
}
|
|
54286
|
+
});
|
|
54287
|
+
registerTool2(server, context, {
|
|
54288
|
+
name: "remix_directory_get_project",
|
|
54289
|
+
description: "Fetch one project by id, or infer the bound repository's project from cwd when possible.",
|
|
54290
|
+
access: "read",
|
|
54291
|
+
inputSchema: directoryProjectInputSchema,
|
|
54292
|
+
outputSchema: getProjectSuccessSchema,
|
|
54293
|
+
run: async (args) => {
|
|
54294
|
+
const input = external_exports.object(directoryProjectInputSchema).parse(args);
|
|
54295
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54296
|
+
return getProject({
|
|
54297
|
+
projectId: input.projectId,
|
|
54298
|
+
cwd
|
|
54299
|
+
});
|
|
54300
|
+
}
|
|
54301
|
+
});
|
|
54302
|
+
registerTool2(server, context, {
|
|
54303
|
+
name: "remix_directory_list_apps",
|
|
54304
|
+
description: "List apps visible to the authenticated user, with optional organization or project filters and built-in pagination.",
|
|
54305
|
+
access: "read",
|
|
54306
|
+
inputSchema: directoryListAppsInputSchema,
|
|
54307
|
+
outputSchema: listAppsSuccessSchema,
|
|
54308
|
+
run: async (args) => {
|
|
54309
|
+
const input = external_exports.object(directoryListAppsInputSchema).parse(args);
|
|
54310
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54311
|
+
return listApps2({
|
|
54312
|
+
projectId: input.projectId,
|
|
54313
|
+
organizationId: input.organizationId,
|
|
54314
|
+
forked: input.forked,
|
|
54315
|
+
limit: input.limit,
|
|
54316
|
+
offset: input.offset,
|
|
54317
|
+
cwd
|
|
54318
|
+
});
|
|
54319
|
+
}
|
|
54320
|
+
});
|
|
54321
|
+
registerTool2(server, context, {
|
|
54322
|
+
name: "remix_directory_get_app",
|
|
54323
|
+
description: "Fetch one app by id, or infer the bound repository's current app from cwd when possible.",
|
|
54324
|
+
access: "read",
|
|
54325
|
+
inputSchema: directoryAppInputSchema,
|
|
54326
|
+
outputSchema: getAppSuccessSchema,
|
|
54327
|
+
run: async (args) => {
|
|
54328
|
+
const input = external_exports.object(directoryAppInputSchema).parse(args);
|
|
54329
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
54330
|
+
return getApp({
|
|
54331
|
+
appId: input.appId,
|
|
54332
|
+
cwd
|
|
54333
|
+
});
|
|
54334
|
+
}
|
|
54335
|
+
});
|
|
54336
|
+
}
|
|
54337
|
+
var genericRecordSchema3 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
54338
|
+
var genericArraySchema3 = external_exports.array(genericRecordSchema3);
|
|
52918
54339
|
var memoryKindSchema = external_exports.enum(["collab_turn", "change_step", "merge_request", "reconcile"]);
|
|
52919
|
-
var
|
|
54340
|
+
var paginationSchema3 = external_exports.object({
|
|
52920
54341
|
limit: external_exports.number().int().nonnegative(),
|
|
52921
54342
|
offset: external_exports.number().int().nonnegative(),
|
|
52922
54343
|
hasMore: external_exports.boolean()
|
|
@@ -52949,14 +54370,14 @@ var changeStepDiffInputSchema = {
|
|
|
52949
54370
|
appId: external_exports.string().trim().min(1).optional(),
|
|
52950
54371
|
changeStepId: external_exports.string().trim().min(1)
|
|
52951
54372
|
};
|
|
52952
|
-
var memorySummaryDataSchema =
|
|
54373
|
+
var memorySummaryDataSchema = genericRecordSchema3;
|
|
52953
54374
|
var memorySearchDataSchema = external_exports.object({
|
|
52954
|
-
items:
|
|
52955
|
-
pagination:
|
|
54375
|
+
items: genericArraySchema3,
|
|
54376
|
+
pagination: paginationSchema3
|
|
52956
54377
|
});
|
|
52957
54378
|
var memoryTimelineDataSchema = external_exports.object({
|
|
52958
|
-
items:
|
|
52959
|
-
pagination:
|
|
54379
|
+
items: genericArraySchema3,
|
|
54380
|
+
pagination: paginationSchema3
|
|
52960
54381
|
});
|
|
52961
54382
|
var changeStepDiffDataSchema = external_exports.object({
|
|
52962
54383
|
changeStepId: external_exports.string(),
|
|
@@ -53044,12 +54465,12 @@ function unwrapResponseObject22(resp, label) {
|
|
|
53044
54465
|
}
|
|
53045
54466
|
return obj;
|
|
53046
54467
|
}
|
|
53047
|
-
function
|
|
54468
|
+
function makeNotBoundError2() {
|
|
53048
54469
|
const error2 = new Error("Repository is not bound to Remix.");
|
|
53049
54470
|
error2.hint = "Run `remix_collab_init` in this repository, or pass `appId` explicitly for a direct memory read.";
|
|
53050
54471
|
return error2;
|
|
53051
54472
|
}
|
|
53052
|
-
async function
|
|
54473
|
+
async function maybeFindGitRoot2(cwd) {
|
|
53053
54474
|
try {
|
|
53054
54475
|
return await findGitRoot(cwd);
|
|
53055
54476
|
} catch {
|
|
@@ -53061,13 +54482,13 @@ async function resolveMemoryTarget(params) {
|
|
|
53061
54482
|
if (explicitAppId) {
|
|
53062
54483
|
return {
|
|
53063
54484
|
appId: explicitAppId,
|
|
53064
|
-
repoRoot: await
|
|
54485
|
+
repoRoot: await maybeFindGitRoot2(params.cwd)
|
|
53065
54486
|
};
|
|
53066
54487
|
}
|
|
53067
54488
|
const repoRoot = await findGitRoot(params.cwd);
|
|
53068
54489
|
const binding = await readCollabBinding(repoRoot);
|
|
53069
54490
|
if (!binding) {
|
|
53070
|
-
throw
|
|
54491
|
+
throw makeNotBoundError2();
|
|
53071
54492
|
}
|
|
53072
54493
|
return {
|
|
53073
54494
|
appId: binding.currentAppId,
|
|
@@ -53135,7 +54556,7 @@ async function getChangeStepDiff(params) {
|
|
|
53135
54556
|
logContext: target
|
|
53136
54557
|
};
|
|
53137
54558
|
}
|
|
53138
|
-
function
|
|
54559
|
+
function getAnnotations3(access) {
|
|
53139
54560
|
return {
|
|
53140
54561
|
readOnlyHint: access === "read",
|
|
53141
54562
|
destructiveHint: false,
|
|
@@ -53143,7 +54564,7 @@ function getAnnotations2(access) {
|
|
|
53143
54564
|
openWorldHint: false
|
|
53144
54565
|
};
|
|
53145
54566
|
}
|
|
53146
|
-
function
|
|
54567
|
+
function buildSuccessEnvelope3(tool, requestId, result) {
|
|
53147
54568
|
return {
|
|
53148
54569
|
schemaVersion: SCHEMA_VERSION,
|
|
53149
54570
|
ok: true,
|
|
@@ -53155,7 +54576,7 @@ function buildSuccessEnvelope2(tool, requestId, result) {
|
|
|
53155
54576
|
recommendedNextActions: result.recommendedNextActions ?? []
|
|
53156
54577
|
};
|
|
53157
54578
|
}
|
|
53158
|
-
function
|
|
54579
|
+
function buildErrorEnvelope3(tool, requestId, error2) {
|
|
53159
54580
|
const normalized = normalizeToolError(error2);
|
|
53160
54581
|
return {
|
|
53161
54582
|
schemaVersion: SCHEMA_VERSION,
|
|
@@ -53164,17 +54585,17 @@ function buildErrorEnvelope2(tool, requestId, error2) {
|
|
|
53164
54585
|
requestId: requestId ?? null,
|
|
53165
54586
|
error: normalized,
|
|
53166
54587
|
warnings: [],
|
|
53167
|
-
risks:
|
|
54588
|
+
risks: deriveErrorRisks3(normalized),
|
|
53168
54589
|
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
53169
54590
|
};
|
|
53170
54591
|
}
|
|
53171
|
-
function
|
|
54592
|
+
function deriveErrorRisks3(normalized) {
|
|
53172
54593
|
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
53173
54594
|
return ["A policy guard blocked a disallowed operation."];
|
|
53174
54595
|
}
|
|
53175
54596
|
return [];
|
|
53176
54597
|
}
|
|
53177
|
-
function
|
|
54598
|
+
function registerTool3(server, context, params) {
|
|
53178
54599
|
const errorSchema = makeErrorSchema();
|
|
53179
54600
|
server.registerTool(
|
|
53180
54601
|
params.name,
|
|
@@ -53183,7 +54604,7 @@ function registerTool2(server, context, params) {
|
|
|
53183
54604
|
description: params.description,
|
|
53184
54605
|
inputSchema: params.inputSchema,
|
|
53185
54606
|
outputSchema: params.outputSchema,
|
|
53186
|
-
annotations:
|
|
54607
|
+
annotations: getAnnotations3(params.access)
|
|
53187
54608
|
},
|
|
53188
54609
|
async (rawArgs) => {
|
|
53189
54610
|
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
@@ -53191,7 +54612,7 @@ function registerTool2(server, context, params) {
|
|
|
53191
54612
|
try {
|
|
53192
54613
|
assertToolAccess(context.policy, params.access);
|
|
53193
54614
|
const result = await params.run(rawArgs);
|
|
53194
|
-
const envelope =
|
|
54615
|
+
const envelope = buildSuccessEnvelope3(params.name, requestId, result);
|
|
53195
54616
|
params.outputSchema.parse(envelope);
|
|
53196
54617
|
context.logger.log({
|
|
53197
54618
|
level: "info",
|
|
@@ -53207,7 +54628,7 @@ function registerTool2(server, context, params) {
|
|
|
53207
54628
|
});
|
|
53208
54629
|
return makeSuccessResult2(envelope);
|
|
53209
54630
|
} catch (error2) {
|
|
53210
|
-
const envelope =
|
|
54631
|
+
const envelope = buildErrorEnvelope3(params.name, requestId, error2);
|
|
53211
54632
|
errorSchema.parse(envelope);
|
|
53212
54633
|
context.logger.log({
|
|
53213
54634
|
level: "error",
|
|
@@ -53224,7 +54645,7 @@ function registerTool2(server, context, params) {
|
|
|
53224
54645
|
);
|
|
53225
54646
|
}
|
|
53226
54647
|
function registerMemoryTools(server, context) {
|
|
53227
|
-
|
|
54648
|
+
registerTool3(server, context, {
|
|
53228
54649
|
name: "remix_collab_memory_summary",
|
|
53229
54650
|
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
54651
|
access: "read",
|
|
@@ -53239,7 +54660,7 @@ function registerMemoryTools(server, context) {
|
|
|
53239
54660
|
});
|
|
53240
54661
|
}
|
|
53241
54662
|
});
|
|
53242
|
-
|
|
54663
|
+
registerTool3(server, context, {
|
|
53243
54664
|
name: "remix_collab_memory_search",
|
|
53244
54665
|
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
54666
|
access: "read",
|
|
@@ -53260,7 +54681,7 @@ function registerMemoryTools(server, context) {
|
|
|
53260
54681
|
});
|
|
53261
54682
|
}
|
|
53262
54683
|
});
|
|
53263
|
-
|
|
54684
|
+
registerTool3(server, context, {
|
|
53264
54685
|
name: "remix_collab_memory_timeline",
|
|
53265
54686
|
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
54687
|
access: "read",
|
|
@@ -53280,7 +54701,7 @@ function registerMemoryTools(server, context) {
|
|
|
53280
54701
|
});
|
|
53281
54702
|
}
|
|
53282
54703
|
});
|
|
53283
|
-
|
|
54704
|
+
registerTool3(server, context, {
|
|
53284
54705
|
name: "remix_collab_memory_change_step_diff",
|
|
53285
54706
|
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
54707
|
access: "read",
|
|
@@ -53297,13 +54718,441 @@ function registerMemoryTools(server, context) {
|
|
|
53297
54718
|
}
|
|
53298
54719
|
});
|
|
53299
54720
|
}
|
|
54721
|
+
var genericRecordSchema4 = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
54722
|
+
var appScopedInputSchema = {
|
|
54723
|
+
...commonRequestFieldsSchema,
|
|
54724
|
+
appId: external_exports.string().trim().min(1).optional()
|
|
54725
|
+
};
|
|
54726
|
+
var editQueueInputSchema = {
|
|
54727
|
+
...appScopedInputSchema,
|
|
54728
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54729
|
+
offset: external_exports.number().int().nonnegative().optional()
|
|
54730
|
+
};
|
|
54731
|
+
var bundleInputSchema = {
|
|
54732
|
+
...appScopedInputSchema,
|
|
54733
|
+
bundleId: external_exports.string().trim().min(1)
|
|
54734
|
+
};
|
|
54735
|
+
var timelineInputSchema = {
|
|
54736
|
+
...appScopedInputSchema,
|
|
54737
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54738
|
+
cursor: external_exports.string().trim().min(1).optional()
|
|
54739
|
+
};
|
|
54740
|
+
var agentRunsInputSchema = {
|
|
54741
|
+
...appScopedInputSchema,
|
|
54742
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54743
|
+
offset: external_exports.number().int().nonnegative().optional(),
|
|
54744
|
+
status: external_exports.string().trim().min(1).optional(),
|
|
54745
|
+
currentPhase: external_exports.string().trim().min(1).optional(),
|
|
54746
|
+
createdAfter: external_exports.string().datetime().optional(),
|
|
54747
|
+
createdBefore: external_exports.string().datetime().optional()
|
|
54748
|
+
};
|
|
54749
|
+
var agentRunInputSchema = {
|
|
54750
|
+
...appScopedInputSchema,
|
|
54751
|
+
runId: external_exports.string().trim().min(1)
|
|
54752
|
+
};
|
|
54753
|
+
var agentRunEventsInputSchema = {
|
|
54754
|
+
...appScopedInputSchema,
|
|
54755
|
+
runId: external_exports.string().trim().min(1),
|
|
54756
|
+
limit: external_exports.number().int().positive().max(100).optional(),
|
|
54757
|
+
offset: external_exports.number().int().nonnegative().optional(),
|
|
54758
|
+
createdAfter: external_exports.string().datetime().optional(),
|
|
54759
|
+
createdBefore: external_exports.string().datetime().optional()
|
|
54760
|
+
};
|
|
54761
|
+
var appOverviewSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54762
|
+
var editQueueSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54763
|
+
var bundleSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54764
|
+
var timelineSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54765
|
+
var agentRunsSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54766
|
+
var agentRunSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54767
|
+
var agentRunEventsSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54768
|
+
var sandboxStatusSuccessSchema = makeSuccessSchema(genericRecordSchema4);
|
|
54769
|
+
async function resolveAppTarget(_api, params) {
|
|
54770
|
+
const explicitAppId = params.appId?.trim();
|
|
54771
|
+
const bindingContext = await loadBindingContext(params.cwd);
|
|
54772
|
+
if (explicitAppId) {
|
|
54773
|
+
return {
|
|
54774
|
+
appId: explicitAppId,
|
|
54775
|
+
repoRoot: bindingContext.repoRoot
|
|
54776
|
+
};
|
|
54777
|
+
}
|
|
54778
|
+
if (!bindingContext.binding) {
|
|
54779
|
+
throw makeNotBoundError("App id was not provided and the current repository is not bound to Remix.");
|
|
54780
|
+
}
|
|
54781
|
+
return {
|
|
54782
|
+
appId: bindingContext.binding.currentAppId,
|
|
54783
|
+
repoRoot: bindingContext.repoRoot
|
|
54784
|
+
};
|
|
54785
|
+
}
|
|
54786
|
+
async function getAppOverview(params) {
|
|
54787
|
+
const api = await createApiClient2();
|
|
54788
|
+
const target = await resolveAppTarget(api, params);
|
|
54789
|
+
const data = unwrapResponseObject2(await api.getAppOverview(target.appId), "app overview");
|
|
54790
|
+
return {
|
|
54791
|
+
data,
|
|
54792
|
+
warnings: [],
|
|
54793
|
+
recommendedNextActions: [
|
|
54794
|
+
"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."
|
|
54795
|
+
],
|
|
54796
|
+
logContext: target
|
|
54797
|
+
};
|
|
54798
|
+
}
|
|
54799
|
+
async function getEditQueue(params) {
|
|
54800
|
+
const api = await createApiClient2();
|
|
54801
|
+
const target = await resolveAppTarget(api, params);
|
|
54802
|
+
const data = unwrapResponseObject2(
|
|
54803
|
+
await api.listAppEditQueue(target.appId, {
|
|
54804
|
+
limit: params.limit,
|
|
54805
|
+
offset: params.offset
|
|
54806
|
+
}),
|
|
54807
|
+
"edit queue"
|
|
54808
|
+
);
|
|
54809
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54810
|
+
return {
|
|
54811
|
+
data,
|
|
54812
|
+
warnings: [],
|
|
54813
|
+
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.`] : [],
|
|
54814
|
+
logContext: target
|
|
54815
|
+
};
|
|
54816
|
+
}
|
|
54817
|
+
async function getBundle(params) {
|
|
54818
|
+
const api = await createApiClient2();
|
|
54819
|
+
const target = await resolveAppTarget(api, params);
|
|
54820
|
+
const data = unwrapResponseObject2(await api.getBundle(target.appId, params.bundleId), "bundle");
|
|
54821
|
+
return {
|
|
54822
|
+
data,
|
|
54823
|
+
warnings: [],
|
|
54824
|
+
recommendedNextActions: ["Use the bundle download-url client methods only when you need the actual artifact, not just metadata inspection."],
|
|
54825
|
+
logContext: target
|
|
54826
|
+
};
|
|
54827
|
+
}
|
|
54828
|
+
async function listTimeline(params) {
|
|
54829
|
+
const api = await createApiClient2();
|
|
54830
|
+
const target = await resolveAppTarget(api, params);
|
|
54831
|
+
const data = unwrapResponseObject2(
|
|
54832
|
+
await api.listAppTimeline(target.appId, {
|
|
54833
|
+
limit: params.limit,
|
|
54834
|
+
cursor: params.cursor
|
|
54835
|
+
}),
|
|
54836
|
+
"app timeline"
|
|
54837
|
+
);
|
|
54838
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54839
|
+
return {
|
|
54840
|
+
data,
|
|
54841
|
+
warnings: [],
|
|
54842
|
+
recommendedNextActions: pageInfo?.hasMore === true && typeof pageInfo.nextCursor === "string" ? [`Pass cursor=${pageInfo.nextCursor} to load the next timeline page.`] : [],
|
|
54843
|
+
logContext: target
|
|
54844
|
+
};
|
|
54845
|
+
}
|
|
54846
|
+
async function listAgentRuns(params) {
|
|
54847
|
+
const api = await createApiClient2();
|
|
54848
|
+
const target = await resolveAppTarget(api, params);
|
|
54849
|
+
const data = unwrapResponseObject2(
|
|
54850
|
+
await api.listAgentRuns(target.appId, {
|
|
54851
|
+
limit: params.limit,
|
|
54852
|
+
offset: params.offset,
|
|
54853
|
+
status: params.status,
|
|
54854
|
+
currentPhase: params.currentPhase,
|
|
54855
|
+
createdAfter: params.createdAfter,
|
|
54856
|
+
createdBefore: params.createdBefore
|
|
54857
|
+
}),
|
|
54858
|
+
"agent runs"
|
|
54859
|
+
);
|
|
54860
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54861
|
+
const items = Array.isArray(data.items) ? data.items : [];
|
|
54862
|
+
const firstRunId = items.length > 0 && items[0] && typeof items[0] === "object" && typeof items[0].id === "string" ? items[0].id : null;
|
|
54863
|
+
const recommendedNextActions = [];
|
|
54864
|
+
if (firstRunId) {
|
|
54865
|
+
recommendedNextActions.push(
|
|
54866
|
+
`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.`
|
|
54867
|
+
);
|
|
54868
|
+
}
|
|
54869
|
+
if (pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number") {
|
|
54870
|
+
recommendedNextActions.push(`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next agent-runs page.`);
|
|
54871
|
+
}
|
|
54872
|
+
return {
|
|
54873
|
+
data,
|
|
54874
|
+
warnings: [],
|
|
54875
|
+
recommendedNextActions,
|
|
54876
|
+
logContext: target
|
|
54877
|
+
};
|
|
54878
|
+
}
|
|
54879
|
+
async function getAgentRun(params) {
|
|
54880
|
+
const api = await createApiClient2();
|
|
54881
|
+
const target = await resolveAppTarget(api, params);
|
|
54882
|
+
const data = unwrapResponseObject2(await api.getAgentRun(target.appId, params.runId), "agent run");
|
|
54883
|
+
return {
|
|
54884
|
+
data,
|
|
54885
|
+
warnings: [],
|
|
54886
|
+
recommendedNextActions: [`Use \`remix_ops_list_agent_run_events\` with \`runId=${params.runId}\` for the event stream behind this run.`],
|
|
54887
|
+
logContext: target
|
|
54888
|
+
};
|
|
54889
|
+
}
|
|
54890
|
+
async function listAgentRunEvents(params) {
|
|
54891
|
+
const api = await createApiClient2();
|
|
54892
|
+
const target = await resolveAppTarget(api, params);
|
|
54893
|
+
const data = unwrapResponseObject2(
|
|
54894
|
+
await api.listAgentRunEvents(target.appId, params.runId, {
|
|
54895
|
+
limit: params.limit,
|
|
54896
|
+
offset: params.offset,
|
|
54897
|
+
createdAfter: params.createdAfter,
|
|
54898
|
+
createdBefore: params.createdBefore
|
|
54899
|
+
}),
|
|
54900
|
+
"agent run events"
|
|
54901
|
+
);
|
|
54902
|
+
const pageInfo = typeof data.pageInfo === "object" && data.pageInfo ? data.pageInfo : null;
|
|
54903
|
+
return {
|
|
54904
|
+
data,
|
|
54905
|
+
warnings: [],
|
|
54906
|
+
recommendedNextActions: pageInfo?.hasMore === true && typeof pageInfo.limit === "number" && typeof pageInfo.offset === "number" ? [`Pass offset=${pageInfo.offset + pageInfo.limit} to load the next event page.`] : [],
|
|
54907
|
+
logContext: target
|
|
54908
|
+
};
|
|
54909
|
+
}
|
|
54910
|
+
async function getSandboxStatus(params) {
|
|
54911
|
+
const api = await createApiClient2();
|
|
54912
|
+
const target = await resolveAppTarget(api, params);
|
|
54913
|
+
const data = unwrapResponseObject2(await api.getSandboxStatus(target.appId), "sandbox status");
|
|
54914
|
+
return {
|
|
54915
|
+
data,
|
|
54916
|
+
warnings: [],
|
|
54917
|
+
recommendedNextActions: ["Use the sandbox metadata here to decide whether a resume is plausible before attempting any write-side sandbox action."],
|
|
54918
|
+
logContext: target
|
|
54919
|
+
};
|
|
54920
|
+
}
|
|
54921
|
+
function getAnnotations4(access) {
|
|
54922
|
+
return {
|
|
54923
|
+
readOnlyHint: access === "read",
|
|
54924
|
+
destructiveHint: false,
|
|
54925
|
+
idempotentHint: true,
|
|
54926
|
+
openWorldHint: false
|
|
54927
|
+
};
|
|
54928
|
+
}
|
|
54929
|
+
function buildSuccessEnvelope4(tool, requestId, result) {
|
|
54930
|
+
return {
|
|
54931
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54932
|
+
ok: true,
|
|
54933
|
+
tool,
|
|
54934
|
+
requestId: requestId ?? null,
|
|
54935
|
+
data: result.data,
|
|
54936
|
+
warnings: result.warnings ?? [],
|
|
54937
|
+
risks: result.risks ?? [],
|
|
54938
|
+
recommendedNextActions: result.recommendedNextActions ?? []
|
|
54939
|
+
};
|
|
54940
|
+
}
|
|
54941
|
+
function deriveErrorRisks4(normalized) {
|
|
54942
|
+
if (normalized.code === "DESTRUCTIVE_OPERATION_BLOCKED") {
|
|
54943
|
+
return ["A policy guard blocked a disallowed operation."];
|
|
54944
|
+
}
|
|
54945
|
+
return [];
|
|
54946
|
+
}
|
|
54947
|
+
function buildErrorEnvelope4(tool, requestId, error2) {
|
|
54948
|
+
const normalized = normalizeToolError(error2);
|
|
54949
|
+
return {
|
|
54950
|
+
schemaVersion: SCHEMA_VERSION,
|
|
54951
|
+
ok: false,
|
|
54952
|
+
tool,
|
|
54953
|
+
requestId: requestId ?? null,
|
|
54954
|
+
error: normalized,
|
|
54955
|
+
warnings: [],
|
|
54956
|
+
risks: deriveErrorRisks4(normalized),
|
|
54957
|
+
recommendedNextActions: normalized.code === "AUTH_REQUIRED" ? ["Run `remix login` or set COMERGE_ACCESS_TOKEN, then retry."] : []
|
|
54958
|
+
};
|
|
54959
|
+
}
|
|
54960
|
+
function registerTool4(server, context, params) {
|
|
54961
|
+
const errorSchema = makeErrorSchema();
|
|
54962
|
+
server.registerTool(
|
|
54963
|
+
params.name,
|
|
54964
|
+
{
|
|
54965
|
+
title: params.name,
|
|
54966
|
+
description: params.description,
|
|
54967
|
+
inputSchema: params.inputSchema,
|
|
54968
|
+
outputSchema: params.outputSchema,
|
|
54969
|
+
annotations: getAnnotations4(params.access)
|
|
54970
|
+
},
|
|
54971
|
+
async (rawArgs) => {
|
|
54972
|
+
const requestId = typeof rawArgs.requestId === "string" ? rawArgs.requestId : void 0;
|
|
54973
|
+
const startedAt = Date.now();
|
|
54974
|
+
try {
|
|
54975
|
+
assertToolAccess(context.policy, params.access);
|
|
54976
|
+
const result = await params.run(rawArgs);
|
|
54977
|
+
const envelope = buildSuccessEnvelope4(params.name, requestId, result);
|
|
54978
|
+
params.outputSchema.parse(envelope);
|
|
54979
|
+
context.logger.log({
|
|
54980
|
+
level: "info",
|
|
54981
|
+
message: "tool_completed",
|
|
54982
|
+
tool: params.name,
|
|
54983
|
+
requestId: envelope.requestId,
|
|
54984
|
+
durationMs: Date.now() - startedAt,
|
|
54985
|
+
result: "success",
|
|
54986
|
+
repoRoot: result.logContext?.repoRoot ?? null,
|
|
54987
|
+
appId: result.logContext?.appId ?? null,
|
|
54988
|
+
mrId: result.logContext?.mrId ?? null
|
|
54989
|
+
});
|
|
54990
|
+
return makeSuccessResult2(envelope);
|
|
54991
|
+
} catch (error2) {
|
|
54992
|
+
const envelope = buildErrorEnvelope4(params.name, requestId, error2);
|
|
54993
|
+
errorSchema.parse(envelope);
|
|
54994
|
+
context.logger.log({
|
|
54995
|
+
level: "error",
|
|
54996
|
+
message: "tool_failed",
|
|
54997
|
+
tool: params.name,
|
|
54998
|
+
requestId: envelope.requestId,
|
|
54999
|
+
durationMs: Date.now() - startedAt,
|
|
55000
|
+
result: "error",
|
|
55001
|
+
errorCode: envelope.error.code
|
|
55002
|
+
});
|
|
55003
|
+
return makeErrorResult(envelope);
|
|
55004
|
+
}
|
|
55005
|
+
}
|
|
55006
|
+
);
|
|
55007
|
+
}
|
|
55008
|
+
function registerOpsTools(server, context) {
|
|
55009
|
+
registerTool4(server, context, {
|
|
55010
|
+
name: "remix_context_get_app_overview",
|
|
55011
|
+
description: "Read the current app's overview, capabilities, and workflow readiness without mutating state.",
|
|
55012
|
+
access: "read",
|
|
55013
|
+
inputSchema: appScopedInputSchema,
|
|
55014
|
+
outputSchema: appOverviewSuccessSchema,
|
|
55015
|
+
run: async (args) => {
|
|
55016
|
+
const input = external_exports.object(appScopedInputSchema).parse(args);
|
|
55017
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55018
|
+
return getAppOverview({
|
|
55019
|
+
appId: input.appId,
|
|
55020
|
+
cwd
|
|
55021
|
+
});
|
|
55022
|
+
}
|
|
55023
|
+
});
|
|
55024
|
+
registerTool4(server, context, {
|
|
55025
|
+
name: "remix_ops_get_edit_queue",
|
|
55026
|
+
description: "Inspect the pending edit queue for one app with bounded pagination.",
|
|
55027
|
+
access: "read",
|
|
55028
|
+
inputSchema: editQueueInputSchema,
|
|
55029
|
+
outputSchema: editQueueSuccessSchema,
|
|
55030
|
+
run: async (args) => {
|
|
55031
|
+
const input = external_exports.object(editQueueInputSchema).parse(args);
|
|
55032
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55033
|
+
return getEditQueue({
|
|
55034
|
+
appId: input.appId,
|
|
55035
|
+
cwd,
|
|
55036
|
+
limit: input.limit,
|
|
55037
|
+
offset: input.offset
|
|
55038
|
+
});
|
|
55039
|
+
}
|
|
55040
|
+
});
|
|
55041
|
+
registerTool4(server, context, {
|
|
55042
|
+
name: "remix_ops_get_bundle",
|
|
55043
|
+
description: "Inspect one app bundle by id without downloading the artifact payload.",
|
|
55044
|
+
access: "read",
|
|
55045
|
+
inputSchema: bundleInputSchema,
|
|
55046
|
+
outputSchema: bundleSuccessSchema,
|
|
55047
|
+
run: async (args) => {
|
|
55048
|
+
const input = external_exports.object(bundleInputSchema).parse(args);
|
|
55049
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55050
|
+
return getBundle({
|
|
55051
|
+
appId: input.appId,
|
|
55052
|
+
cwd,
|
|
55053
|
+
bundleId: input.bundleId
|
|
55054
|
+
});
|
|
55055
|
+
}
|
|
55056
|
+
});
|
|
55057
|
+
registerTool4(server, context, {
|
|
55058
|
+
name: "remix_ops_list_timeline",
|
|
55059
|
+
description: "List bounded timeline events for one app using the backend cursor pagination model.",
|
|
55060
|
+
access: "read",
|
|
55061
|
+
inputSchema: timelineInputSchema,
|
|
55062
|
+
outputSchema: timelineSuccessSchema,
|
|
55063
|
+
run: async (args) => {
|
|
55064
|
+
const input = external_exports.object(timelineInputSchema).parse(args);
|
|
55065
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55066
|
+
return listTimeline({
|
|
55067
|
+
appId: input.appId,
|
|
55068
|
+
cwd,
|
|
55069
|
+
limit: input.limit,
|
|
55070
|
+
cursor: input.cursor
|
|
55071
|
+
});
|
|
55072
|
+
}
|
|
55073
|
+
});
|
|
55074
|
+
registerTool4(server, context, {
|
|
55075
|
+
name: "remix_ops_get_agent_run",
|
|
55076
|
+
description: "Fetch one stored agent run for an app, including status, phase, and summary metadata.",
|
|
55077
|
+
access: "read",
|
|
55078
|
+
inputSchema: agentRunInputSchema,
|
|
55079
|
+
outputSchema: agentRunSuccessSchema,
|
|
55080
|
+
run: async (args) => {
|
|
55081
|
+
const input = external_exports.object(agentRunInputSchema).parse(args);
|
|
55082
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55083
|
+
return getAgentRun({
|
|
55084
|
+
appId: input.appId,
|
|
55085
|
+
cwd,
|
|
55086
|
+
runId: input.runId
|
|
55087
|
+
});
|
|
55088
|
+
}
|
|
55089
|
+
});
|
|
55090
|
+
registerTool4(server, context, {
|
|
55091
|
+
name: "remix_ops_list_agent_runs",
|
|
55092
|
+
description: "List paginated agent runs for one app so run ids can be discovered before deeper inspection.",
|
|
55093
|
+
access: "read",
|
|
55094
|
+
inputSchema: agentRunsInputSchema,
|
|
55095
|
+
outputSchema: agentRunsSuccessSchema,
|
|
55096
|
+
run: async (args) => {
|
|
55097
|
+
const input = external_exports.object(agentRunsInputSchema).parse(args);
|
|
55098
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55099
|
+
return listAgentRuns({
|
|
55100
|
+
appId: input.appId,
|
|
55101
|
+
cwd,
|
|
55102
|
+
limit: input.limit,
|
|
55103
|
+
offset: input.offset,
|
|
55104
|
+
status: input.status,
|
|
55105
|
+
currentPhase: input.currentPhase,
|
|
55106
|
+
createdAfter: input.createdAfter,
|
|
55107
|
+
createdBefore: input.createdBefore
|
|
55108
|
+
});
|
|
55109
|
+
}
|
|
55110
|
+
});
|
|
55111
|
+
registerTool4(server, context, {
|
|
55112
|
+
name: "remix_ops_list_agent_run_events",
|
|
55113
|
+
description: "List paginated agent-run events for one stored run, with optional time bounds.",
|
|
55114
|
+
access: "read",
|
|
55115
|
+
inputSchema: agentRunEventsInputSchema,
|
|
55116
|
+
outputSchema: agentRunEventsSuccessSchema,
|
|
55117
|
+
run: async (args) => {
|
|
55118
|
+
const input = external_exports.object(agentRunEventsInputSchema).parse(args);
|
|
55119
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55120
|
+
return listAgentRunEvents({
|
|
55121
|
+
appId: input.appId,
|
|
55122
|
+
cwd,
|
|
55123
|
+
runId: input.runId,
|
|
55124
|
+
limit: input.limit,
|
|
55125
|
+
offset: input.offset,
|
|
55126
|
+
createdAfter: input.createdAfter,
|
|
55127
|
+
createdBefore: input.createdBefore
|
|
55128
|
+
});
|
|
55129
|
+
}
|
|
55130
|
+
});
|
|
55131
|
+
registerTool4(server, context, {
|
|
55132
|
+
name: "remix_ops_get_sandbox_status",
|
|
55133
|
+
description: "Read safe sandbox metadata and the latest migration status for one app without exposing execution handles or secrets.",
|
|
55134
|
+
access: "read",
|
|
55135
|
+
inputSchema: appScopedInputSchema,
|
|
55136
|
+
outputSchema: sandboxStatusSuccessSchema,
|
|
55137
|
+
run: async (args) => {
|
|
55138
|
+
const input = external_exports.object(appScopedInputSchema).parse(args);
|
|
55139
|
+
const cwd = input.cwd ? resolvePolicyCwd(context.policy, input.cwd) : void 0;
|
|
55140
|
+
return getSandboxStatus({
|
|
55141
|
+
appId: input.appId,
|
|
55142
|
+
cwd
|
|
55143
|
+
});
|
|
55144
|
+
}
|
|
55145
|
+
});
|
|
55146
|
+
}
|
|
53300
55147
|
function createRemixMcpServer(params) {
|
|
53301
55148
|
const context = createServerContext({ version: params.version });
|
|
53302
55149
|
const server = new McpServer({
|
|
53303
55150
|
name: context.serverName,
|
|
53304
55151
|
version: context.version
|
|
53305
55152
|
});
|
|
55153
|
+
registerIdentityTools(server, context);
|
|
53306
55154
|
registerCollabTools(server, context);
|
|
55155
|
+
registerOpsTools(server, context);
|
|
53307
55156
|
registerMemoryTools(server, context);
|
|
53308
55157
|
return { server, context };
|
|
53309
55158
|
}
|
|
@@ -53450,7 +55299,7 @@ async function listPendingTurnStateSummaries() {
|
|
|
53450
55299
|
// package.json
|
|
53451
55300
|
var package_default = {
|
|
53452
55301
|
name: "@remixhq/claude-plugin",
|
|
53453
|
-
version: "0.1.
|
|
55302
|
+
version: "0.1.14",
|
|
53454
55303
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
53455
55304
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
53456
55305
|
license: "MIT",
|
|
@@ -53481,8 +55330,8 @@ var package_default = {
|
|
|
53481
55330
|
prepack: "npm run build"
|
|
53482
55331
|
},
|
|
53483
55332
|
dependencies: {
|
|
53484
|
-
"@remixhq/core": "^0.1.
|
|
53485
|
-
"@remixhq/mcp": "^0.1.
|
|
55333
|
+
"@remixhq/core": "^0.1.9",
|
|
55334
|
+
"@remixhq/mcp": "^0.1.9"
|
|
53486
55335
|
},
|
|
53487
55336
|
devDependencies: {
|
|
53488
55337
|
"@types/node": "^25.4.0",
|
|
@@ -53575,7 +55424,7 @@ var outputSchema = external_exports.object({
|
|
|
53575
55424
|
toolName: external_exports.string().nullable(),
|
|
53576
55425
|
repoRoot: external_exports.string().nullable(),
|
|
53577
55426
|
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()]))
|
|
55427
|
+
fields: external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]))
|
|
53579
55428
|
})
|
|
53580
55429
|
),
|
|
53581
55430
|
pendingStates: external_exports.array(
|