feat: add daily product intelligence and versioned site assets (#64)

Adds privacy-safe aggregate product intelligence, reviewed/versioned website assets, and a dispatch-only rollout until the dedicated Sentry token is verified. Independent review blockers were fixed in 8bc47e4; app checks, website production build, Android CI, and iOS CI are green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Den
2026-07-15 11:59:40 -07:00
committed by GitHub
parent cbe00c3222
commit 5c14ce0a5d
46 changed files with 4539 additions and 1 deletions

View File

@@ -0,0 +1,61 @@
import type { Metadata } from 'next'
import { readFileSync } from 'fs'
import path from 'path'
export const metadata: Metadata = {
title: 'Privacy Policy',
description:
'OpenCode Mobile privacy policy. We do not collect your code, prompts, or AI responses. Crash diagnostics via Sentry are opt-in only.',
alternates: { canonical: 'https://opencode.agentlabs.cc/privacy' },
openGraph: {
title: 'Privacy Policy | OpenCode Mobile',
description: 'OpenCode Mobile privacy policy — minimal data collection, opt-in crash reporting.',
url: 'https://opencode.agentlabs.cc/privacy',
},
}
export default function PrivacyPage() {
// Read the canonical privacy policy HTML generated by the Android distribution workflow.
// This ensures the policy shown on the site is always in sync with app store submissions.
const policyPath = path.join(
process.cwd(),
'../../../opencode-mobile/distribution/privacy-policy.html',
)
let policyHtml = ''
try {
const raw = readFileSync(policyPath, 'utf8')
// Extract just the <body> content so we can render it inside our layout
const bodyMatch = raw.match(/<body[^>]*>([\s\S]*?)<\/body>/i)
policyHtml = bodyMatch ? bodyMatch[1] : raw
} catch {
policyHtml = `<p style="color:#94A3B8">Privacy policy document not found. Please contact
<a href="mailto:support@vibebrowser.app" style="color:#3B82F6">support@vibebrowser.app</a>.</p>`
}
return (
<div className="max-w-3xl mx-auto px-4 sm:px-6 py-16">
{/* Override the inline HTML colors from the standalone file with dark theme */}
<style>{`
.privacy-content body { color: inherit; background: transparent; }
.privacy-content header { border-bottom-color: #3B82F6; }
.privacy-content header h1 { color: #F1F5F9; }
.privacy-content .meta { color: #94A3B8; }
.privacy-content h2 { color: #F1F5F9; border-left-color: #3B82F6; }
.privacy-content p, .privacy-content li { color: #CBD5E1; }
.privacy-content a { color: #3B82F6; }
.privacy-content .highlight-box { background: rgba(59,130,246,0.1); border-color: rgba(59,130,246,0.4); }
.privacy-content .highlight-box strong { color: #93C5FD; }
.privacy-content th { background: #1E293B; border-color: #334155; color: #F1F5F9; }
.privacy-content td { border-color: #334155; color: #CBD5E1; }
.privacy-content tr:nth-child(even) td { background: rgba(30,41,59,0.5); }
.privacy-content footer { border-top-color: #334155; color: #64748B; }
.privacy-content code { color: #94A3B8; font-size: 0.85em; }
`}</style>
<div
className="privacy-content"
dangerouslySetInnerHTML={{ __html: policyHtml }}
/>
</div>
)
}