This commit is contained in:
ZacharyZhang-NY committed 2026-04-04 17:01:26 -04:00
1 parent 67c757f481
commit b8dda3c8d0
77 files changed
+1577 -2808

No files matched your search

+34 -7
View File
@@ -1,10 +1,38 @@
"use client";
import { useEffect, useState } from "react";
import { motion } from "framer-motion";
import { AsciiBackground } from "./ascii-background";
import { platformDownloads, releaseVersion } from "./release-links.generated";
import { DOWNLOAD_COUNT_SEED, getTrackedDownloadHref } from "../lib/downloads";
export function DownloadSection() {
const [downloadCount, setDownloadCount] = useState(DOWNLOAD_COUNT_SEED);
useEffect(() => {
let cancelled = false;
async function loadDownloadCount() {
try {
const response = await fetch("/api/download-stats", { cache: "no-store" });
if (!response.ok) {
throw new Error(`Failed to fetch download count: ${response.status}`);
}
const data = await response.json() as { downloads?: number };
if (!cancelled && typeof data.downloads === "number") {
setDownloadCount(data.downloads);
}
} catch {
// Keep the seeded count visible when the dynamic endpoint is unavailable.
}
}
void loadDownloadCount();
return () => {
cancelled = true;
};
}, []);
return (
<section id="download" className="py-24 lg:py-40 px-4 sm:px-6 lg:px-8 relative overflow-hidden">
<motion.div
@@ -44,7 +72,10 @@ export function DownloadSection() {
Install the Right Build for Your Machine
</h2>
<p className="text-[var(--text-on-cta-muted)] text-lg max-w-xl mx-auto mb-12 leading-relaxed">
Full release matrix hosted on our Cloudflare release lane. Version {releaseVersion}.
Version {releaseVersion}.
</p>
<p className="text-[var(--text-on-cta-faint)] text-sm max-w-xl mx-auto mb-12 leading-relaxed -mt-8">
Downloads: {downloadCount.toLocaleString("en-US")}
</p>
<div className="w-full mt-2 grid grid-cols-1 md:grid-cols-3 gap-6">
@@ -60,20 +91,16 @@ export function DownloadSection() {
<p className="font-mono text-xs uppercase tracking-[0.25em] text-[var(--text-on-cta-faint)] mb-3">
{download.title}
</p>
<p className="text-[var(--text-on-cta-muted)] text-sm leading-relaxed mb-4">{download.note}</p>
<div className="space-y-2.5">
{download.assets.map((asset) => (
<a
key={asset.id}
href={asset.href}
href={getTrackedDownloadHref(asset.id)}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-between gap-3 rounded-xl border border-white/12 bg-black/10 px-4 py-3 text-sm text-[var(--text-on-cta)] transition-colors duration-200 hover:bg-black/18"
className="flex items-center rounded-xl border border-white/12 bg-black/10 px-4 py-3 text-sm text-[var(--text-on-cta)] transition-colors duration-200 hover:bg-black/18"
>
<span className="font-semibold tracking-tight">{asset.label}</span>
<span className="font-mono text-xs uppercase tracking-[0.18em] text-[var(--text-on-cta-faint)]">
{asset.note}
</span>
</a>
))}
</div>
+5 -20
View File
@@ -1,20 +1,8 @@
import { AsciiBackground } from "./ascii-background";
import { IconMark } from "./icon-mark";
import { CONTACT_EMAIL, WEBSITE_URL } from "./site-constants";
import { platformDownloads } from "./release-links.generated";
import { ThemeToggle } from "./theme-toggle";
function findAsset(platformId: string, assetId: string) {
const platform = platformDownloads.find((entry) => entry.id === platformId);
if (!platform) {
throw new Error(`Missing platform download entry for ${platformId}`);
}
const asset = platform.assets.find((entry) => entry.id === assetId);
if (!asset) {
throw new Error(`Missing asset ${assetId} for ${platformId}`);
}
return asset.href;
}
import { getTrackedDownloadHref } from "../lib/downloads";
const footerGroups = [
{
@@ -29,10 +17,10 @@ const footerGroups = [
{
title: "Downloads",
links: [
{ label: "Apple Silicon", href: findAsset("macos", "macos-arm64-dmg"), external: true },
{ label: "Intel Mac", href: findAsset("macos", "macos-x64-dmg"), external: true },
{ label: "Windows Installer", href: findAsset("windows", "windows-universal-installer"), external: true },
{ label: "Linux x64 AppImage", href: findAsset("linux", "linux-x64-appimage"), external: true },
{ label: "Apple Silicon", href: getTrackedDownloadHref("macos-arm64-dmg"), external: true },
{ label: "Intel Mac", href: getTrackedDownloadHref("macos-x64-dmg"), external: true },
{ label: "Windows Installer", href: getTrackedDownloadHref("windows-universal-installer"), external: true },
{ label: "Linux x64 AppImage", href: getTrackedDownloadHref("linux-x64-appimage"), external: true },
],
},
{
@@ -91,9 +79,6 @@ export function Footer() {
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div className="flex items-center gap-4 text-xs text-[var(--muted)]">
<span>© {year} AgentCompany</span>
<span className="hidden sm:inline-flex items-center gap-1.5">
Cloudflare-hosted desktop builds
</span>
</div>
<div className="flex items-center gap-1">
+1 -1
View File
@@ -54,7 +54,7 @@ export function Hero() {
<div className="flex flex-col items-center text-center">
<motion.div {...heroMotion(0.05)}>
<span className="inline-flex items-center px-4 py-1.5 rounded-full text-xs font-semibold tracking-wide bg-[var(--accent-soft)] text-[var(--accent)] dark:text-[var(--muted-strong)] border border-[var(--border)]">
Local-First · Desktop App
Agent Company
</span>
</motion.div>
+10 -10
View File
@@ -12,7 +12,7 @@ export type PlatformDownload = {
assets: PlatformDownloadAsset[];
};
export const releaseVersion = "0.4.150";
export const releaseVersion = "0.4.151";
export const platformDownloads: PlatformDownload[] = [
{
@@ -23,13 +23,13 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "macos-arm64-dmg",
label: "Apple Silicon DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.150-arm64.dmg",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151-arm64.dmg",
note: "arm64",
},
{
id: "macos-x64-dmg",
label: "Intel Mac DMG",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.150.dmg",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151.dmg",
note: "x64",
},
],
@@ -42,7 +42,7 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "windows-universal-installer",
label: "Windows Universal Installer",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.150.exe",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany.Setup.0.4.151.exe",
note: "arm64 + x64 + ia32",
},
],
@@ -55,37 +55,37 @@ export const platformDownloads: PlatformDownload[] = [
{
id: "linux-x64-appimage",
label: "Linux x64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.150.AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151.AppImage",
note: "x64",
},
{
id: "linux-x64-deb",
label: "Linux x64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.150_amd64.deb",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.151_amd64.deb",
note: "x64",
},
{
id: "linux-x64-rpm",
label: "Linux x64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.150.x86_64.rpm",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.151.x86_64.rpm",
note: "x64",
},
{
id: "linux-arm64-appimage",
label: "Linux ARM64 AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.150-arm64.AppImage",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/AgentCompany-0.4.151-arm64.AppImage",
note: "arm64",
},
{
id: "linux-arm64-deb",
label: "Linux ARM64 DEB",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.150_arm64.deb",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company_0.4.151_arm64.deb",
note: "arm64",
},
{
id: "linux-arm64-rpm",
label: "Linux ARM64 RPM",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.150.aarch64.rpm",
href: "https://pub-a19a3a2c1d2e4fa3a9c120b184024448.r2.dev/AC/agent-company-0.4.151.aarch64.rpm",
note: "arm64",
},
],
+34
View File
@@ -0,0 +1,34 @@
import type { CounterDatabase, PagesHandler } from "../types";
import { DOWNLOAD_COUNT_SEED } from "../../lib/downloads";
interface Env {
DOWNLOAD_COUNTER_DB: CounterDatabase;
}
async function readDownloadCount(db: CounterDatabase) {
const result = await db
.prepare(`
SELECT
COALESCE(
(SELECT value FROM download_counter_settings WHERE key = 'base_downloads'),
?
) + COUNT(*) AS downloads
FROM unique_download_windows
`)
.bind(DOWNLOAD_COUNT_SEED)
.first<{ downloads: number }>();
return result?.downloads ?? DOWNLOAD_COUNT_SEED;
}
export const onRequestGet: PagesHandler<Env> = async (context) => {
const downloads = await readDownloadCount(context.env.DOWNLOAD_COUNTER_DB);
return Response.json(
{ downloads },
{
headers: {
"Cache-Control": "no-store",
},
},
);
};
+73
View File
@@ -0,0 +1,73 @@
import {
DOWNLOAD_DEDUP_WINDOW_MS,
getDownloadAsset,
} from "../../lib/downloads";
import type { CounterDatabase, PagesHandler } from "../types";
interface Env {
DOWNLOAD_COUNTER_DB: CounterDatabase;
DOWNLOAD_COUNTER_SALT?: string;
}
function getClientIp(request: Request) {
const cfConnectingIp = request.headers.get("CF-Connecting-IP")?.trim();
if (cfConnectingIp) {
return cfConnectingIp;
}
const forwardedFor = request.headers.get("X-Forwarded-For")?.split(",")[0]?.trim();
return forwardedFor || null;
}
function getWindowKey(now = Date.now()) {
return Math.floor(now / DOWNLOAD_DEDUP_WINDOW_MS);
}
async function sha256Hex(input: string) {
const buffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
return Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, "0")).join("");
}
async function countUniqueDownload(db: CounterDatabase, request: Request, assetId: string, salt: string | undefined) {
const clientIp = getClientIp(request);
if (!clientIp) {
return;
}
const ipHash = await sha256Hex(`${salt ?? ""}:${clientIp}`);
const windowKey = getWindowKey();
await db
.prepare(`
INSERT OR IGNORE INTO unique_download_windows (
ip_hash,
window_key,
first_asset_id,
created_at
) VALUES (?, ?, ?, datetime('now'))
`)
.bind(ipHash, windowKey, assetId)
.run();
}
export const onRequestGet: PagesHandler<Env> = async (context) => {
const url = new URL(context.request.url);
const assetId = url.searchParams.get("asset")?.trim();
if (!assetId) {
return new Response("Missing asset parameter.", { status: 400 });
}
const asset = getDownloadAsset(assetId);
if (!asset) {
return new Response("Unknown asset.", { status: 404 });
}
await countUniqueDownload(
context.env.DOWNLOAD_COUNTER_DB,
context.request,
asset.id,
context.env.DOWNLOAD_COUNTER_SALT,
);
return Response.redirect(asset.href, 302);
};
+17
View File
@@ -0,0 +1,17 @@
export interface CounterDbStatement {
bind(...values: unknown[]): {
first<T = unknown>(): Promise<T | null>;
run(): Promise<unknown>;
};
}
export interface CounterDatabase {
prepare(query: string): CounterDbStatement;
}
export interface PagesHandlerContext<Env> {
request: Request;
env: Env;
}
export type PagesHandler<Env> = (context: PagesHandlerContext<Env>) => Response | Promise<Response>;
+28
View File
@@ -0,0 +1,28 @@
import { platformDownloads, type PlatformDownloadAsset } from "../components/release-links.generated";
export const DOWNLOAD_COUNT_SEED = 13674;
export const DOWNLOAD_DEDUP_WINDOW_HOURS = 24;
export const DOWNLOAD_DEDUP_WINDOW_MS = DOWNLOAD_DEDUP_WINDOW_HOURS * 60 * 60 * 1000;
export type ReleaseDownloadAsset = PlatformDownloadAsset & {
platformId: "macos" | "windows" | "linux";
platformTitle: string;
};
export const downloadAssets: ReleaseDownloadAsset[] = platformDownloads.flatMap((platform) =>
platform.assets.map((asset) => ({
...asset,
platformId: platform.id,
platformTitle: platform.title,
})),
);
const downloadAssetMap = new Map(downloadAssets.map((asset) => [asset.id, asset]));
export function getDownloadAsset(assetId: string) {
return downloadAssetMap.get(assetId) ?? null;
}
export function getTrackedDownloadHref(assetId: string) {
return `/api/download?asset=${encodeURIComponent(assetId)}`;
}
@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS download_counter_settings (
key TEXT PRIMARY KEY,
value INTEGER NOT NULL
);
INSERT OR IGNORE INTO download_counter_settings (key, value)
VALUES ('base_downloads', 13674);
CREATE TABLE IF NOT EXISTS unique_download_windows (
ip_hash TEXT NOT NULL,
window_key INTEGER NOT NULL,
first_asset_id TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (ip_hash, window_key)
);
CREATE INDEX IF NOT EXISTS idx_unique_download_windows_created_at
ON unique_download_windows(created_at);
+8
View File
@@ -1,3 +1,11 @@
name = "agentcompany"
compatibility_date = "2026-04-03"
pages_build_output_dir = "out"
[vars]
DOWNLOAD_COUNTER_SALT = "agentcompany-download-counter-v1"
[[d1_databases]]
binding = "DOWNLOAD_COUNTER_DB"
database_name = "agentcompany-landing-downloads"
database_id = "dfa3f0f3-009b-4436-b519-5b50ae6b1cf9"