Rebrand Pinscope to Periscope across product and codebase.

Rename the core package to periscopex, update UI/docs/Docker/deploy defaults to periscope.michelebigi.it, and keep legacy version/storage key aliases so existing projects keep working.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-13 20:02:04 +02:00
co-authored by Cursor
parent 556306bf4d
commit 8d2b85600f
177 changed files with 869 additions and 766 deletions
+7 -4
View File
@@ -29,7 +29,7 @@ import type {
ValidationReport,
} from "./types";
// Mirror of backend.pinscopex.utils.safe_mpn — used to match MPNs
// Mirror of backend.periscopex.utils.safe_mpn — used to match MPNs
// against datasheet filename stems returned by the server.
export function safeMpn(mpn: string): string {
return mpn.replace(/\//g, "_").replace(/:/g, "_");
@@ -102,7 +102,10 @@ function mapProject(p: Record<string, unknown>): Project {
lcscToMpn: (p.lcsc_to_mpn as Record<string, string> | null) ?? null,
lcscPayloads: (p.lcsc_payloads as Record<string, LcscPayload> | null) ?? null,
componentMpns: (p.component_mpns as ComponentMpnBuckets | null) ?? null,
pinscopeVersion: (p.pinscope_version as string | null | undefined) ?? null,
periscopeVersion:
(p.periscope_version as string | null | undefined) ??
(p.pinscope_version as string | null | undefined) ??
null,
netlistFormat: (p.netlist_format as Project["netlistFormat"]) ?? null,
netlistSubdesigns: (p.netlist_subdesigns as string[] | null) ?? null,
placementStatus: (p.placement_status as Project["placementStatus"]) ?? "draft",
@@ -817,7 +820,7 @@ export async function downloadEcoCsv(projectId: string): Promise<void> {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "pinscope-eco.csv";
a.download = "periscope-eco.csv";
a.click();
URL.revokeObjectURL(url);
}
@@ -1125,7 +1128,7 @@ export interface LcscResolvePassiveResponse {
mpn: string;
safe_mpn: string;
// Shape mirrors the persisted passive specs model in
// backend/pinscopex/models.py — a discriminated union over `specs_type`.
// backend/periscopex/models.py — a discriminated union over `specs_type`.
// Keep loose at this layer; the wizard surfaces a small summary.
model: Record<string, unknown>;
cached: boolean;
+21 -2
View File
@@ -2,7 +2,7 @@
* Open-core auth switch.
*
* - Clerk: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY set (cloud build).
* - Local: NEXT_PUBLIC_AUTH_MODE=local (self-host Pinscope accounts).
* - Local: NEXT_PUBLIC_AUTH_MODE=local (self-host Periscope accounts).
* - Off: neither — signed-in stub user "local", matching backend.
*
* NEXT_PUBLIC_* vars are inlined at build time.
@@ -16,4 +16,23 @@ export const localAuthEnabled =
process.env.NEXT_PUBLIC_AUTH_MODE === "local" &&
!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
export const TOKEN_STORAGE_KEY = "pinscope_token";
export const TOKEN_STORAGE_KEY = "periscope_token";
/** Pre-rebrand localStorage key — read once and migrate. */
export const LEGACY_TOKEN_STORAGE_KEY = "pinscope_token";
export function readAuthToken(): string | null {
if (typeof window === "undefined") return null;
try {
const current = window.localStorage.getItem(TOKEN_STORAGE_KEY);
if (current) return current;
const legacy = window.localStorage.getItem(LEGACY_TOKEN_STORAGE_KEY);
if (legacy) {
window.localStorage.setItem(TOKEN_STORAGE_KEY, legacy);
window.localStorage.removeItem(LEGACY_TOKEN_STORAGE_KEY);
return legacy;
}
} catch {
/* ignore */
}
return null;
}
+3 -3
View File
@@ -1,12 +1,12 @@
export const SITE_URL = (
process.env.NEXT_PUBLIC_SITE_URL?.trim().replace(/\/$/, "") ||
"https://pinscope.ai"
"https://periscope.michelebigi.it"
);
export const SITE_NAME = "Pinscope";
export const SITE_NAME = "Periscope";
export const SITE_DESCRIPTION =
"Pinscope reviews your schematic against every datasheet and catches the errors that would otherwise surface at bring-up. Works with KiCad, Altium, OrCAD, Cadence, Siemens, EasyEDA, and EAGLE.";
"Periscope reviews your schematic against every datasheet and catches the errors that would otherwise surface at bring-up. Works with KiCad, Altium, OrCAD, Cadence, Siemens, EasyEDA, and EAGLE.";
export const SITE_TAGLINE = "Agentic schematic validation";
+42
View File
@@ -0,0 +1,42 @@
/** Migrate localStorage keys from pre-rebrand `pinscopex:` prefix. */
export function migrateLocalKey(newKey: string, legacyKey: string): string | null {
if (typeof window === "undefined") return null;
try {
const current = localStorage.getItem(newKey);
if (current != null) return current;
const legacy = localStorage.getItem(legacyKey);
if (legacy != null) {
localStorage.setItem(newKey, legacy);
localStorage.removeItem(legacyKey);
return legacy;
}
} catch {
/* ignore */
}
return null;
}
export function reviewedFindingsKey(projectId: string) {
return `periscopex:reviewed-findings:${projectId}`;
}
export function legacyReviewedFindingsKey(projectId: string) {
return `pinscopex:reviewed-findings:${projectId}`;
}
export function deratingSettingsKey(projectId: string) {
return `periscopex:derating-settings:${projectId}`;
}
export function legacyDeratingSettingsKey(projectId: string) {
return `pinscopex:derating-settings:${projectId}`;
}
export function deratingOverridesKey(projectId: string) {
return `periscopex:derating-overrides:${projectId}`;
}
export function legacyDeratingOverridesKey(projectId: string) {
return `pinscopex:derating-overrides:${projectId}`;
}
+1 -1
View File
@@ -272,7 +272,7 @@ export interface Project {
lcscToMpn?: Record<string, string> | null;
lcscPayloads?: Record<string, LcscPayload> | null;
componentMpns?: ComponentMpnBuckets | null;
pinscopeVersion?: string | null;
periscopeVersion?: string | null;
// "pads" | "edif" | "kicad_*" — netlist the user uploaded. null on legacy projects.
// projects predating EDIF support; treat null as PADS for rendering.
netlistFormat?: "pads" | "edif" | "kicad_xml" | "kicad_sexp" | "kicad_sch" | null;