Skip to content
Prev Previous commit
Polish compact help formatting and test assertions
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
  • Loading branch information
Copilot and pelikhan authored Jun 9, 2026
commit f4a7fefb1fad4f79358533a29d6dad99a451eab8
5 changes: 4 additions & 1 deletion actions/setup/js/mcp_cli_bridge.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,7 @@ function summarizeHelpText(value, maxLen) {
*/
function formatCompactNameLines(names, maxLines) {
if (!Array.isArray(names) || names.length === 0) {
// Callers spread the result into help lines, so empty input should contribute no lines.
return [];
}
if (!Number.isFinite(maxLines) || maxLines <= 0) {
Expand All @@ -868,6 +869,7 @@ function formatCompactNameLines(names, maxLines) {
let current = " ";
for (const name of names) {
const token = current.trim() ? `, ${name}` : name;
// A single very long name may still exceed the width target; we keep it intact.
const shouldStartNewLine = current.length + token.length > COMPACT_NAME_LINE_TARGET_WIDTH;
if (shouldStartNewLine) {
lines.push(current);
Expand All @@ -880,9 +882,10 @@ function formatCompactNameLines(names, maxLines) {
lines.push(current);
}
if (lines.length > maxLines) {
// Keep all names visible by collapsing overflow into the last allowed line.
// Keep maxLines - 1 full lines and collapse the remaining names into the final allowed line.
const compactTail = lines
.slice(maxLines - 1)
// Trim per-line indentation before rebuilding a single indented tail line.
.map(line => line.trim())
.join(", ");
return [...lines.slice(0, maxLines - 1), ` ${compactTail}`];
Expand Down
39 changes: 22 additions & 17 deletions actions/setup/js/mcp_cli_bridge.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,11 @@ describe("mcp_cli_bridge.cjs", () => {
showHelp("safeoutputs", tools);

const outputLines = stdoutChunks.join("").trimEnd().split("\n");
const output = outputLines.join("\n");
expect(outputLines.length).toBeLessThanOrEqual(20);
expect(outputLines.join("\n")).not.toMatch(/\.\.\. \+\d+ more command\(s\)/);
expect(output).not.toMatch(/\.\.\. \+\d+ more command\(s\)/);
for (const tool of tools) {
expect(outputLines.join("\n")).toContain(tool.name);
expect(output).toContain(tool.name);
}
});

Expand All @@ -237,10 +238,11 @@ describe("mcp_cli_bridge.cjs", () => {
showHelp("safeoutputs", tools);

const outputLines = stdoutChunks.join("").trimEnd().split("\n");
const output = outputLines.join("\n");
expect(outputLines.length).toBeLessThanOrEqual(20);
expect(outputLines.join("\n")).not.toMatch(/\.\.\. \+\d+ more command\(s\)/);
expect(output).not.toMatch(/\.\.\. \+\d+ more command\(s\)/);
for (const tool of tools) {
expect(outputLines.join("\n")).toContain(tool.name);
expect(output).toContain(tool.name);
}
});
Comment on lines +215 to +230

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] summarizeHelpText is a pure, deterministic utility that now drives all help truncation, but it has no dedicated unit tests. Its edge cases — multi-space collapsing, exactly-at-limit strings, maxLen <= 0, and the maxLen - 1 slice boundary — are only exercised indirectly through showHelp / showToolHelp.

💡 Suggested test skeleton
describe("summarizeHelpText", () => {
  // Need to export it first, or test via a helper that calls it directly.
  it("collapses internal whitespace", () => {
    expect(summarizeHelpText("foo   bar\n  baz", 100)).toBe("foo bar baz");
  });
  it("returns full string when within limit", () => {
    expect(summarizeHelpText("hello", 5)).toBe("hello");
  });
  it("truncates with ellipsis when over limit", () => {
    expect(summarizeHelpText("hello world", 8)).toBe("hello w...");
  });
  it("returns normalized text when maxLen <= 0", () => {
    expect(summarizeHelpText("text", 0)).toBe("text");
  });
});

This would also catch the maxLen=1 edge case noted separately.


Expand All @@ -262,14 +264,15 @@ describe("mcp_cli_bridge.cjs", () => {
]);

const outputLines = stdoutChunks.join("").trimEnd().split("\n");
const output = outputLines.join("\n");
expect(outputLines.length).toBeLessThanOrEqual(30);
expect(outputLines.join("\n")).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(outputLines.join("\n")).toContain("Required options are marked with *.");
expect(output).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(output).toContain("Required options are marked with *.");
for (let i = 1; i <= 24; i++) {
expect(outputLines.join("\n")).toContain(`--field_${i}`);
expect(output).toContain(`--field_${i}`);
}
expect(outputLines.join("\n")).toContain("--field_1*");
expect(outputLines.join("\n")).toContain("--field_2*");
expect(output).toContain("--field_1*");
expect(output).toContain("--field_2*");
});

it("does not truncate command help when options exactly fit the line budget", () => {
Expand All @@ -290,15 +293,16 @@ describe("mcp_cli_bridge.cjs", () => {
]);

const outputLines = stdoutChunks.join("").trimEnd().split("\n");
const output = outputLines.join("\n");
expect(outputLines.length).toBeLessThanOrEqual(30);
expect(outputLines.join("\n")).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(outputLines.join("\n")).toContain("Required options are marked with *.");
expect(output).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(output).toContain("Required options are marked with *.");
for (let i = 1; i <= 13; i++) {
expect(outputLines.join("\n")).toContain(`--field_${i}`);
expect(output).toContain(`--field_${i}`);
}
});

it("keeps required-note when required options are in the compact list", () => {
it("keeps required note when required options are in the compact list", () => {
const properties = {};
for (let i = 1; i <= 24; i++) {
properties[`field_${i}`] = { type: "string", description: `Field ${i}.` };
Expand All @@ -316,10 +320,11 @@ describe("mcp_cli_bridge.cjs", () => {
]);

const outputLines = stdoutChunks.join("").trimEnd().split("\n");
expect(outputLines.join("\n")).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(outputLines.join("\n")).toContain("Required options are marked with *.");
expect(outputLines.join("\n")).toContain("--field_23*");
expect(outputLines.join("\n")).toContain("--field_24*");
const output = outputLines.join("\n");
expect(output).not.toMatch(/\.\.\. \+\d+ more option\(s\)/);
expect(output).toContain("Required options are marked with *.");
expect(output).toContain("--field_23*");
expect(output).toContain("--field_24*");
});

describe("stdin placeholder removed — '-' is always a literal value", () => {
Expand Down
Loading