Rename all workspace packages from @paperclip/* to @paperclipai/* and the CLI binary from `paperclip` to `paperclipai` in preparation for npm publishing. Bump CLI version to 0.1.0 and add package metadata (description, keywords, license, repository, files). Update all imports, documentation, user-facing messages, and tests accordingly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
75 lines
2.6 KiB
TypeScript
75 lines
2.6 KiB
TypeScript
import { type ClassValue, clsx } from "clsx";
|
|
import { twMerge } from "tailwind-merge";
|
|
import { deriveAgentUrlKey, deriveProjectUrlKey } from "@paperclipai/shared";
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
|
|
export function formatCents(cents: number): string {
|
|
return `$${(cents / 100).toFixed(2)}`;
|
|
}
|
|
|
|
export function formatDate(date: Date | string): string {
|
|
return new Date(date).toLocaleDateString("en-US", {
|
|
month: "short",
|
|
day: "numeric",
|
|
year: "numeric",
|
|
});
|
|
}
|
|
|
|
export function formatDateTime(date: Date | string): string {
|
|
return new Date(date).toLocaleString("en-US", {
|
|
month: "short",
|
|
day: "numeric",
|
|
year: "numeric",
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
});
|
|
}
|
|
|
|
export function relativeTime(date: Date | string): string {
|
|
const now = Date.now();
|
|
const then = new Date(date).getTime();
|
|
const diffSec = Math.round((now - then) / 1000);
|
|
if (diffSec < 60) return "just now";
|
|
const diffMin = Math.round(diffSec / 60);
|
|
if (diffMin < 60) return `${diffMin}m ago`;
|
|
const diffHr = Math.round(diffMin / 60);
|
|
if (diffHr < 24) return `${diffHr}h ago`;
|
|
const diffDay = Math.round(diffHr / 24);
|
|
if (diffDay < 30) return `${diffDay}d ago`;
|
|
return formatDate(date);
|
|
}
|
|
|
|
export function formatTokens(n: number): string {
|
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
|
|
return String(n);
|
|
}
|
|
|
|
/** Build an issue URL using the human-readable identifier when available. */
|
|
export function issueUrl(issue: { id: string; identifier?: string | null }): string {
|
|
return `/issues/${issue.identifier ?? issue.id}`;
|
|
}
|
|
|
|
/** Build an agent route URL using the short URL key when available. */
|
|
export function agentRouteRef(agent: { id: string; urlKey?: string | null; name?: string | null }): string {
|
|
return agent.urlKey ?? deriveAgentUrlKey(agent.name, agent.id);
|
|
}
|
|
|
|
/** Build an agent URL using the short URL key when available. */
|
|
export function agentUrl(agent: { id: string; urlKey?: string | null; name?: string | null }): string {
|
|
return `/agents/${agentRouteRef(agent)}`;
|
|
}
|
|
|
|
/** Build a project route reference using the short URL key when available. */
|
|
export function projectRouteRef(project: { id: string; urlKey?: string | null; name?: string | null }): string {
|
|
return project.urlKey ?? deriveProjectUrlKey(project.name, project.id);
|
|
}
|
|
|
|
/** Build a project URL using the short URL key when available. */
|
|
export function projectUrl(project: { id: string; urlKey?: string | null; name?: string | null }): string {
|
|
return `/projects/${projectRouteRef(project)}`;
|
|
}
|