Simplify auth and search client, drop local JWT expiry tracking

Auth:
- Remove jwt.ts — stop decoding JWT exp claims locally
- Simplify OTP login: direct token extraction from verify response,
  remove CookieJar, BFS token extraction, session fallback, CF bypass
- Storage: drop expires field, store token-only; clear on 401/403
- Single auth path: try stored token → macOS app → OTP fallback

Search client:
- Remove Cloudflare subprocess fallback (fetchViaBunRuntime)
- Remove streamFromText, isCloudflareChallenge, BunFetchResult
- Simplify SSE fetch to single fetch() call with abort signal
- Let server validate tokens; clear cache on auth errors

Render:
- Extract shared utilities (asString, truncate) to render/util.ts
- Simplify call.ts and result.ts to import from shared module

Tests:
- Remove jwt.test.ts (module deleted)
- Add otp-flow.test.ts for email OTP authentication
- Simplify login and client tests for reduced code paths

Add debug scripts and plan documents.
This commit is contained in:
Ivan Pereira
2026-02-18 08:03:39 +00:00
parent f42531b07c
commit 501935fe1c
17 changed files with 586 additions and 772 deletions
+1 -21
View File
@@ -1,5 +1,6 @@
import type { Theme } from "@mariozechner/pi-coding-agent";
import { Text } from "@mariozechner/pi-tui";
import { asString, asPositiveNumber, truncate } from "./util.js";
interface PerplexityCallArgs {
query?: unknown;
@@ -8,27 +9,6 @@ interface PerplexityCallArgs {
}
const RECENCY_VALUES = new Set(["hour", "day", "week", "month", "year"] as const);
function asString(value: unknown): string | undefined {
return typeof value === "string" ? value : undefined;
}
function asPositiveNumber(value: unknown): number | undefined {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
return undefined;
}
return value;
}
function truncate(text: string, maxLength: number): string {
if (text.length <= maxLength) {
return text;
}
return `${text.slice(0, Math.max(1, maxLength - 1))}`;
}
export function renderPerplexityCall(args: PerplexityCallArgs, theme: Theme): Text {
const query = asString(args?.query)?.trim();
const recencyRaw = asString(args?.recency)?.trim().toLowerCase();
+6 -18
View File
@@ -1,5 +1,6 @@
import type { AgentToolResult, Theme, ToolRenderResultOptions } from "@mariozechner/pi-coding-agent";
import { Text } from "@mariozechner/pi-tui";
import { asString, asNumber, truncate } from "./util.js";
interface PerplexityResultDetails {
model?: unknown;
@@ -9,23 +10,6 @@ interface PerplexityResultDetails {
toolCallId?: unknown;
error?: unknown;
}
function asString(value: unknown): string | undefined {
return typeof value === "string" ? value : undefined;
}
function asNumber(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
}
function truncate(text: string, maxLength: number): string {
if (text.length <= maxLength) {
return text;
}
return `${text.slice(0, Math.max(1, maxLength - 1))}`;
}
function extractTextContent(result: AgentToolResult<PerplexityResultDetails>): string | undefined {
if (!Array.isArray(result?.content)) {
return undefined;
@@ -63,7 +47,11 @@ export function renderPerplexityResult(
options: ToolRenderResultOptions,
theme: Theme,
): Text {
const details = (result?.details ?? {}) as PerplexityResultDetails;
const raw = result?.details;
const details: PerplexityResultDetails =
raw && typeof raw === "object" && !Array.isArray(raw)
? (raw as PerplexityResultDetails)
: {};
const contentText = extractTextContent(result);
if (options?.isPartial) {
+28
View File
@@ -0,0 +1,28 @@
export function asString(value: unknown): string | undefined {
return typeof value === "string" ? value : undefined;
}
/** Safely extract a message from an unknown caught value. */
export function errorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
if (typeof error === "string") return error;
return "Unknown error";
}
export function asNumber(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
}
export function asPositiveNumber(value: unknown): number | undefined {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
return undefined;
}
return value;
}
export function truncate(text: string, maxLength: number): string {
if (text.length <= maxLength) {
return text;
}
return `${text.slice(0, Math.max(1, maxLength - 1))}`;
}