From 87f98e0e24344468aadb91e7b9da691f1416927f Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+catomean@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:12:53 +0200 Subject: [PATCH 1/3] chore: add a formatter, matching the style this repo already writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit singleQuote=false was chosen by counting this repo's own imports, not by fleet decree. The fleet is genuinely split and the two repos that already had a .prettierrc disagreed with each other, so there was no standard to restore. Quote style does not cross repo boundaries; having a gate does. Markdown is ignored for now — prettier rewraps prose, which would bury the real diff. Co-Authored-By: Claude Opus 5 --- .prettierignore | 31 +++++++++++++++++++++++++++++++ .prettierrc | 9 +++++++++ package-lock.json | 20 ++++++++++++++++++++ package.json | 7 +++++-- 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b698663 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,31 @@ +# Build output and vendored trees — formatting these is noise. +node_modules +.next +dist +build +out +coverage +.turbo +.vercel +*.min.js +*.min.css + +# Generated during a build, so it is absent locally and present in CI — which +# makes a clean local --check no evidence at all. Contentlayer's output also +# uses import assertions, which prettier's parser rejects outright. +.contentlayer +.astro +.svelte-kit +storybook-static +test-results +playwright-report + +# Lockfiles are generated; prettier would rewrite them wholesale. +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Markdown is deliberately out of scope for now. Prettier rewraps prose, which +# is where it is most opinionated and least useful, and it would bury the real +# diff. Remove this line when you want docs formatted too. +*.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a2f11f0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": false, + "printWidth": 100, + "tabWidth": 2, + "trailingComma": "all", + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/package-lock.json b/package-lock.json index 4eaf4de..e0af927 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,10 +21,14 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.3.3", + "prettier": "3.9.6", "tailwindcss": "^4", "tsx": "^4.23.12", "typescript": "^5", "vitest": "^4.1.11" + }, + "engines": { + "node": ">=20" } }, "node_modules/@alloc/quick-lru": { @@ -6687,6 +6691,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", diff --git a/package.json b/package.json index 7bc08f9..b58d0b1 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,10 @@ "typecheck": "tsc --noEmit", "test": "vitest run", "test:watch": "vitest", - "verify": "npm run lint && npm run typecheck && npm run test", - "analyze": "tsx scripts/analyze-cli.ts" + "verify": "npm run format:check && npm run lint && npm run typecheck && npm run test", + "analyze": "tsx scripts/analyze-cli.ts", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "ai-kit": "github:bitbaum/ai-kit#v0.4.0", @@ -31,6 +33,7 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.3.3", + "prettier": "3.9.6", "tailwindcss": "^4", "tsx": "^4.23.12", "typescript": "^5", From ab0a1a149be19c641511b1f39466f9cb17f1ef32 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+catomean@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:13:07 +0200 Subject: [PATCH 2/3] style: format with prettier (13 files) Mechanical. No behaviour change. This SHA is listed in .git-blame-ignore-revs so `git blame` skips it. Co-Authored-By: Claude Opus 5 --- .github/workflows/auto-merge.yml | 6 +- next.config.ts | 4 +- scripts/analyze-cli.ts | 9 +- src/app/globals.css | 100 ++++---- src/app/layout.tsx | 5 +- src/app/page.tsx | 23 +- src/lib/analysis.ts | 19 +- src/lib/article-fetch.test.ts | 219 +++++++++--------- src/lib/article-fetch.ts | 3 +- src/lib/claim-types.test.ts | 89 ++++--- src/lib/llm.test.ts | 386 +++++++++++++++---------------- src/lib/llm.ts | 12 +- vitest.config.ts | 12 +- 13 files changed, 447 insertions(+), 440 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index d05072e..011480b 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -19,10 +19,10 @@ name: Auto-merge on: workflow_run: - workflows: ['CI'] + workflows: ["CI"] types: [completed] schedule: - - cron: '*/10 * * * *' + - cron: "*/10 * * * *" workflow_dispatch: {} # Declared on the CALLER as well as inside the reusable workflow: a called @@ -46,4 +46,4 @@ jobs: # SPACE-separated: the sweep word-splits this. A comma would become one # bogus token, every dispatch would fail, and the only symptom would be # that nothing deploys — while the sweep still reported success. - rearm_workflows: 'ci.yml' + rearm_workflows: "ci.yml" diff --git a/next.config.ts b/next.config.ts index e9ffa30..41a9c18 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,5 @@ import type { NextConfig } from "next"; -const nextConfig: NextConfig = { - /* config options here */ -}; +const nextConfig: NextConfig = {/* config options here */}; export default nextConfig; diff --git a/scripts/analyze-cli.ts b/scripts/analyze-cli.ts index 0a275b6..0436ab4 100644 --- a/scripts/analyze-cli.ts +++ b/scripts/analyze-cli.ts @@ -28,7 +28,10 @@ function loadDotEnvLocal(): void { const key = trimmed.slice(0, eq).trim(); let value = trimmed.slice(eq + 1).trim(); // Strip simple surrounding quotes. - if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { value = value.slice(1, -1); } if (!process.env[key]) process.env[key] = value; @@ -93,7 +96,9 @@ function renderMarkdown(url: string, result: AnalysisResult): string { lines.push("---"); lines.push(""); const truncNote = result.truncated ? " (truncated — article was longer)" : ""; - lines.push(`*Generated by truthseeker · ${result.fetched.textLength.toLocaleString()} chars examined${truncNote} · ${result.durationMs}ms*`); + lines.push( + `*Generated by truthseeker · ${result.fetched.textLength.toLocaleString()} chars examined${truncNote} · ${result.durationMs}ms*`, + ); return lines.join("\n"); } diff --git a/src/app/globals.css b/src/app/globals.css index 2edaa31..0e69bc8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -10,106 +10,110 @@ :root { /* -- Tier 1: primitive palette (raw values — not used directly by components) */ - --primitive-ink-950: #0c0e12; /* near-black, cool slate */ + --primitive-ink-950: #0c0e12; /* near-black, cool slate */ --primitive-ink-900: #14171d; --primitive-ink-800: #1c212a; --primitive-ink-700: #2a313d; --primitive-ink-500: #5b6675; --primitive-ink-400: #7d899a; - --primitive-paper-50: #f7f6f3; /* warm forensic paper, not pure white */ - --primitive-paper-0: #fcfbf9; - --primitive-line: #e4e1da; + --primitive-paper-50: #f7f6f3; /* warm forensic paper, not pure white */ + --primitive-paper-0: #fcfbf9; + --primitive-line: #e4e1da; - --primitive-amber-500: #c8851a; /* highlighter / evidence-mark — brand */ + --primitive-amber-500: #c8851a; /* highlighter / evidence-mark — brand */ --primitive-amber-400: #e0a234; /* claim-type primitives — the product's signature spectrum */ - --primitive-teal-500: #0e8c87; /* factual — verifiable, measured */ - --primitive-teal-400: #34b3ae; - --primitive-violet-500: #7a5cd6; /* normative — values / "should" */ + --primitive-teal-500: #0e8c87; /* factual — verifiable, measured */ + --primitive-teal-400: #34b3ae; + --primitive-violet-500: #7a5cd6; /* normative — values / "should" */ --primitive-violet-400: #9a82e6; - --primitive-rust-500: #c25a2e; /* causal — chains of reasoning */ - --primitive-rust-400: #df7a4e; + --primitive-rust-500: #c25a2e; /* causal — chains of reasoning */ + --primitive-rust-400: #df7a4e; /* -- Tier 2: semantic tokens (what things MEAN — components use only these) */ - --color-bg: var(--primitive-paper-50); - --color-surface: var(--primitive-paper-0); + --color-bg: var(--primitive-paper-50); + --color-surface: var(--primitive-paper-0); --color-surface-raised: #ffffff; - --color-border: var(--primitive-line); + --color-border: var(--primitive-line); --color-border-strong: #cfcabf; - --color-text: var(--primitive-ink-950); - --color-text-muted: var(--primitive-ink-500); - --color-brand: var(--primitive-amber-500); - --color-on-brand: #ffffff; + --color-text: var(--primitive-ink-950); + --color-text-muted: var(--primitive-ink-500); + --color-brand: var(--primitive-amber-500); + --color-on-brand: #ffffff; /* mono accent — the "evidence log" technical voice */ --color-mono-accent: var(--primitive-ink-700); /* claim-type semantic tokens */ - --color-factual: var(--primitive-teal-500); + --color-factual: var(--primitive-teal-500); --color-factual-soft: color-mix(in srgb, var(--primitive-teal-500) 12%, var(--color-surface)); - --color-normative: var(--primitive-violet-500); + --color-normative: var(--primitive-violet-500); --color-normative-soft: color-mix(in srgb, var(--primitive-violet-500) 12%, var(--color-surface)); - --color-causal: var(--primitive-rust-500); + --color-causal: var(--primitive-rust-500); --color-causal-soft: color-mix(in srgb, var(--primitive-rust-500) 12%, var(--color-surface)); /* error / warning — a forensic flag, not generic amber */ - --color-flag: #b4451f; - --color-flag-soft: color-mix(in srgb, #b4451f 8%, var(--color-surface)); + --color-flag: #b4451f; + --color-flag-soft: color-mix(in srgb, #b4451f 8%, var(--color-surface)); /* radii / shadows */ - --radius-card: 4px; /* sharp corners suit the forensic concept */ + --radius-card: 4px; /* sharp corners suit the forensic concept */ --radius-chip: 3px; --shadow-card: 0 1px 2px rgb(12 14 18 / 0.04), 0 1px 8px rgb(12 14 18 / 0.04); } @media (prefers-color-scheme: dark) { :root { - --color-bg: var(--primitive-ink-950); - --color-surface: var(--primitive-ink-900); + --color-bg: var(--primitive-ink-950); + --color-surface: var(--primitive-ink-900); --color-surface-raised: var(--primitive-ink-800); - --color-border: var(--primitive-ink-800); + --color-border: var(--primitive-ink-800); --color-border-strong: var(--primitive-ink-700); - --color-text: var(--primitive-paper-50); - --color-text-muted: var(--primitive-ink-400); - --color-brand: var(--primitive-amber-400); - --color-on-brand: var(--primitive-ink-950); + --color-text: var(--primitive-paper-50); + --color-text-muted: var(--primitive-ink-400); + --color-brand: var(--primitive-amber-400); + --color-on-brand: var(--primitive-ink-950); --color-mono-accent: var(--primitive-ink-400); - --color-factual: var(--primitive-teal-400); + --color-factual: var(--primitive-teal-400); --color-factual-soft: color-mix(in srgb, var(--primitive-teal-400) 14%, var(--color-surface)); - --color-normative: var(--primitive-violet-400); - --color-normative-soft: color-mix(in srgb, var(--primitive-violet-400) 14%, var(--color-surface)); - --color-causal: var(--primitive-rust-400); + --color-normative: var(--primitive-violet-400); + --color-normative-soft: color-mix( + in srgb, + var(--primitive-violet-400) 14%, + var(--color-surface) + ); + --color-causal: var(--primitive-rust-400); --color-causal-soft: color-mix(in srgb, var(--primitive-rust-400) 14%, var(--color-surface)); - --color-flag: #e07a52; - --color-flag-soft: color-mix(in srgb, #e07a52 12%, var(--color-surface)); + --color-flag: #e07a52; + --color-flag-soft: color-mix(in srgb, #e07a52 12%, var(--color-surface)); --shadow-card: 0 1px 2px rgb(0 0 0 / 0.3), 0 1px 10px rgb(0 0 0 / 0.25); } } @theme inline { - --color-bg: var(--color-bg); - --color-surface: var(--color-surface); + --color-bg: var(--color-bg); + --color-surface: var(--color-surface); --color-surface-raised: var(--color-surface-raised); - --color-border: var(--color-border); + --color-border: var(--color-border); --color-border-strong: var(--color-border-strong); - --color-text: var(--color-text); - --color-text-muted: var(--color-text-muted); - --color-brand: var(--color-brand); - --color-on-brand: var(--color-on-brand); - --color-mono-accent: var(--color-mono-accent); + --color-text: var(--color-text); + --color-text-muted: var(--color-text-muted); + --color-brand: var(--color-brand); + --color-on-brand: var(--color-on-brand); + --color-mono-accent: var(--color-mono-accent); - --color-factual: var(--color-factual); + --color-factual: var(--color-factual); --color-factual-soft: var(--color-factual-soft); - --color-normative: var(--color-normative); + --color-normative: var(--color-normative); --color-normative-soft: var(--color-normative-soft); - --color-causal: var(--color-causal); + --color-causal: var(--color-causal); --color-causal-soft: var(--color-causal-soft); - --color-flag: var(--color-flag); + --color-flag: var(--color-flag); --color-flag-soft: var(--color-flag-soft); --radius-card: var(--radius-card); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8d58f32..f539b9e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -32,10 +32,7 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + {children} ); diff --git a/src/app/page.tsx b/src/app/page.tsx index c2c7875..16c591f 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -64,9 +64,8 @@ export default function Home() { truth/seeker

- Paste an article URL. Get a forensic breakdown — every claim tagged, - its sources named, its biases surfaced, and a first-principles critique - you can argue with. + Paste an article URL. Get a forensic breakdown — every claim tagged, its sources named, + its biases surfaced, and a first-principles critique you can argue with.

@@ -116,7 +115,9 @@ function ClaimLegend() {
- + {c.label}
@@ -136,9 +137,9 @@ function EmptyState() { How it reads an article

- truthseeker doesn't tell you whether an article is true. It exposes - its structure so you can judge it - yourself. Every load-bearing claim is sorted into one of three kinds: + truthseeker doesn't tell you whether an article is true. It exposes its{" "} + structure so you can judge it yourself. Every + load-bearing claim is sorted into one of three kinds:

    @@ -166,9 +167,7 @@ function LoadingState() { -

    - Examining -

    +

    Examining