fix(pi-coding-agent): show full OAuth login URLs

This commit is contained in:
mastertyko 2026-04-12 18:45:28 +02:00
parent 791ce1b35e
commit f15938ea4c
2 changed files with 54 additions and 2 deletions

View file

@ -0,0 +1,24 @@
import { describe, test } from "node:test";
import assert from "node:assert/strict";
import { buildAuthUrlPresentation } from "../login-dialog.js";
describe("LoginDialogComponent", () => {
test("shows the full OAuth URL when the hyperlink label is truncated", () => {
const presentation = buildAuthUrlPresentation(
"https://auth.example.com/device?code=ABCD-1234&callback=oauth&state=needs-full-visibility",
52,
);
assert.notEqual(
presentation.displayUrl,
"https://auth.example.com/device?code=ABCD-1234&callback=oauth&state=needs-full-visibility",
"narrow terminals should still truncate the hyperlink label",
);
assert.ok(presentation.fullUrlLines.length > 1, "truncated URLs should expose wrapped full-url lines");
assert.match(presentation.fullUrlLines[0] ?? "", /https:\/\/auth\.example\.com\/device\?code=ABCD-1234&/);
assert.match(
presentation.fullUrlLines[presentation.fullUrlLines.length - 1] ?? "",
/state=needs-full-visibility/,
);
});
});

View file

@ -7,6 +7,27 @@ import { theme } from "../theme/theme.js";
import { DynamicBorder } from "./dynamic-border.js";
import { keyHint } from "./keybinding-hints.js";
function wrapPlainText(text: string, width: number): string[] {
const lines: string[] = [];
const safeWidth = Math.max(1, width);
for (let idx = 0; idx < text.length; idx += safeWidth) {
lines.push(text.slice(idx, idx + safeWidth));
}
return lines.length > 0 ? lines : [""];
}
export function buildAuthUrlPresentation(url: string, terminalColumns: number): {
displayUrl: string;
fullUrlLines: string[];
} {
const maxUrlWidth = Math.max(20, terminalColumns - 4);
const displayUrl = truncateToWidth(url, maxUrlWidth);
return {
displayUrl,
fullUrlLines: displayUrl === url ? [] : wrapPlainText(url, maxUrlWidth),
};
}
/**
* Login dialog component - replaces editor during OAuth login flow.
*
@ -124,14 +145,21 @@ export class LoginDialogComponent extends Container implements Focusable {
// Truncate the visible URL text so it never wraps (which would break
// the OSC 8 hyperlink). The full URL is still the link target.
const maxUrlWidth = Math.max(20, this.tui.terminal.columns - 4);
const displayUrl = truncateToWidth(url, maxUrlWidth);
const { displayUrl, fullUrlLines } = buildAuthUrlPresentation(url, this.tui.terminal.columns);
const urlLink = `\x1b]8;;${url}\x07${theme.fg("accent", displayUrl)}\x1b]8;;\x07`;
this.contentContainer.addChild(new Text(urlLink, 1, 0));
const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
this.contentContainer.addChild(new Text(theme.fg("dim", clickHint), 1, 0));
if (fullUrlLines.length > 0) {
this.contentContainer.addChild(new Spacer(1));
this.contentContainer.addChild(new Text(theme.fg("dim", "Full URL:"), 1, 0));
for (const line of fullUrlLines) {
this.contentContainer.addChild(new Text(theme.fg("dim", line), 1, 0));
}
}
if (instructions) {
this.contentContainer.addChild(new Spacer(1));
this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));