Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/loopover-mcp/bin/loopover-mcp.js
Original file line number Diff line number Diff line change
Expand Up @@ -3865,12 +3865,27 @@ function printDecisionPackHelp() {
);
}

function printContributorProfileHelp() {
process.stdout.write(
[
"Usage: loopover-mcp contributor-profile --login <github-login> [--json]",
"",
"Fetch the contributor profile for a GitHub login.",
"Mirrors the loopover_get_contributor_profile MCP tool and GET /v1/contributors/{login}/profile. No source upload.",
"",
"Login resolves from --login, the active session, LOOPOVER_LOGIN, then GITHUB_LOGIN.",
"Pass --json for machine-readable output.",
].join("\n") + "\n",
);
}

// #6737: CLI mirror of the loopover_get_contributor_profile MCP tool and GET /v1/contributors/{login}/profile
// (requireContributorAccess-gated -- the same gate decision-pack/repo-decision already satisfy). Login resolves
// from --login / the active session / LOOPOVER_LOGIN / GITHUB_LOGIN, exactly like the sibling contributor
// commands, so an already-logged-in contributor never retypes their own login. Named `contributor-profile`
// because the top-level `profile` command already manages MCP client profiles.
async function contributorProfileCli(options) {
if (options.help === true) return printContributorProfileHelp();
const login = options.login ?? activeProfile.session?.login ?? process.env.LOOPOVER_LOGIN ?? process.env.GITHUB_LOGIN;
if (!login) throw new Error("Pass --login <github-login>, log in with `loopover-mcp login`, or set LOOPOVER_LOGIN.");
const payload = await apiGet(`/v1/contributors/${encodeURIComponent(login)}/profile`);
Expand Down
11 changes: 10 additions & 1 deletion test/unit/mcp-cli-contributor-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { closeFixtureServer, runAsync, runExpectingFailure, startFixtureServer } from "./support/mcp-cli-harness";
import { closeFixtureServer, run, runAsync, runExpectingFailure, startFixtureServer } from "./support/mcp-cli-harness";

describe("loopover-mcp CLI — contributor-profile (#6737)", () => {
let tempDir: string | null = null;
Expand Down Expand Up @@ -49,4 +49,13 @@ describe("loopover-mcp CLI — contributor-profile (#6737)", () => {
expect(`${failure.stdout}${failure.stderr}`).toMatch(/Pass --login/);
expect(requests.filter((url) => url.includes("/profile"))).toHaveLength(0);
});

it("prints usage for --help without resolving a login or hitting the network (#6992)", () => {
// --help must short-circuit BEFORE login resolution, so this succeeds with no --login and no server --
// previously it fell through and threw the "Pass --login" error instead of printing usage.
const help = run(["contributor-profile", "--help"], { LOOPOVER_LOGIN: "", GITHUB_LOGIN: "" });
expect(help).toContain("Usage: loopover-mcp contributor-profile --login <github-login> [--json]");
expect(help).toContain("Mirrors the loopover_get_contributor_profile MCP tool");
expect(help).not.toMatch(/Pass --login/);
});
});