Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
out
dist
website/.astro
release
.DS_Store
*.log
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"prepare:tts-assets": "node scripts/prepare_tts_assets.mjs",
"check:tts-assets": "node scripts/check_tts_assets.mjs",
"smoke:tts": "node scripts/smoke_tts.mjs",
"website:install": "pnpm --dir website install",
"website:build": "pnpm --dir website build",
"website:dev": "pnpm --dir website dev",
"website:check": "pnpm --dir website build",
"check:website": "node scripts/check_website.mjs",
"smoke:release-artifacts": "node scripts/release_artifact_smoke.mjs",
"check:teacher-quality": "pnpm build && pnpm eval:teacher && pnpm eval:claims && pnpm eval:quality-gate && pnpm check:knowledge-sources && pnpm eval:knowledge-coverage && pnpm eval:shape-recognition && pnpm eval:move-range && pnpm eval:engine-silver && pnpm eval:teacher-style && pnpm eval:teacher-session && pnpm eval:tts-provider-policy",
"package": "pnpm dist",
Expand Down
2,609 changes: 2,598 additions & 11 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
packages:
- "."
- "website"
78 changes: 78 additions & 0 deletions scripts/check_website.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env node
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
import { join } from 'node:path'

const root = process.cwd()
const websiteRoot = join(root, 'website')
const failures = []

function fail(message) {
failures.push(message)
}

function requireFile(relativePath) {
const path = join(root, relativePath)
if (!existsSync(path)) fail(`missing ${relativePath}`)
return path
}

function read(relativePath) {
const path = requireFile(relativePath)
return existsSync(path) ? readFileSync(path, 'utf8') : ''
}

function walk(dir) {
if (!existsSync(dir)) return []
const entries = []
for (const name of readdirSync(dir)) {
const path = join(dir, name)
const stat = statSync(path)
if (stat.isDirectory()) entries.push(...walk(path))
else entries.push(path)
}
return entries
}

requireFile('website/package.json')
requireFile('website/src/pages/index.astro')
requireFile('website/src/pages/download.astro')
requireFile('website/src/pages/privacy.astro')
requireFile('website/DEPLOYMENT.md')

const index = read('website/src/pages/index.astro')
const privacy = read('website/src/pages/privacy.astro')
const deployment = read('website/DEPLOYMENT.md')

if (!index.toLowerCase().includes('goagent')) fail('homepage must contain goagent')
if (!index.includes('https://github.com/wimi321/GoAgent/releases')) fail('homepage must link GitHub Releases')
for (const keyword of ['本地', 'LLM', 'TTS']) {
if (!privacy.includes(keyword)) fail(`privacy page must contain ${keyword}`)
}
for (const keyword of ['Cloudflare Pages', 'Spaceship', 'goagent.top']) {
if (!deployment.includes(keyword)) fail(`DEPLOYMENT.md must contain ${keyword}`)
}

for (const path of walk(join(websiteRoot, 'public'))) {
if (/\.(exe|dmg|zip|tar\.gz)$/i.test(path)) fail(`website public must not contain installer/archive: ${path}`)
}

for (const path of walk(websiteRoot)) {
if (path.includes(`${join('website', 'dist')}${'/'.replace('/', '')}`)) continue
const stat = statSync(path)
if (stat.size > 1024 * 1024 && path.includes(`${join('website', 'public')}`)) {
fail(`large static public file should not be committed: ${path}`)
}
const textFile = /\.(astro|css|js|mjs|json|md|txt|svg|html|yml|yaml)$/i.test(path)
if (textFile) {
const body = readFileSync(path, 'utf8')
if (body.includes('goagnet.top')) fail(`wrong domain goagnet.top found in ${path}`)
if (body.includes('goagent.com')) fail(`unexpected domain goagent.com found in ${path}`)
}
}

if (failures.length) {
for (const failure of failures) console.error(`[check-website] ${failure}`)
process.exit(1)
}

console.log('[check-website] website contract OK')
96 changes: 96 additions & 0 deletions website/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# goagent.top Cloudflare Pages 部署说明

goagent 官网使用 Cloudflare Pages 部署,部署目录为 `website/`。官网只提供静态页面,不依赖 VPS、数据库或服务端 API。

## 1. Cloudflare 和域名

1. 在 Cloudflare 添加 `goagent.top` 站点。
2. 在 Spaceship 把 `goagent.top` 的 nameservers 改成 Cloudflare 分配的 nameservers。
3. DNS 传播可能最长 48 小时。传播期间 `goagent.top`、`www.goagent.top` 可能出现间歇性不可访问。
4. 不要在文档或代码中写死 Cloudflare 分配的 nameserver 名称,以 Cloudflare 控制台显示为准。

## 2. Cloudflare Pages 项目

在 Cloudflare Pages 创建项目:

- 连接 GitHub 仓库:`wimi321/GoAgent`
- Root directory: `website`
- Build command: `pnpm build`
- Output directory: `dist`
- Framework preset: Astro

`website/` 是独立 Astro 静态站,生成纯静态 HTML/CSS/少量 JS,不使用服务端渲染。

## 3. Custom domains

在 Pages 项目的 Custom domains 中添加:

- `goagent.top`
- `www.goagent.top`

建议 apex 作为主域名:`goagent.top`。

项目内已经提供 `_redirects`:

```text
https://www.goagent.top/* https://goagent.top/:splat 301
```

如果 Cloudflare Pages 控制台中另行配置了 www 跳转,也可以保留该文件作为静态部署兜底。

## 4. 下载文件策略

不要把安装包放入 Cloudflare Pages:

- Pages 适合静态官网,不适合作为大型安装包仓库。
- Pages 单文件大小有限,不适合托管 `.exe`、`.dmg`、`.zip`。
- 官网下载按钮链接 GitHub Releases:
`https://github.com/wimi321/GoAgent/releases`

未来可以用 VPS 或对象存储做:

- `api.goagent.top`
- `download.goagent.top`
- release mirror

但 VPS 不参与官网主站。

## 5. 本地构建和检查

从仓库根目录执行:

```bash
pnpm install
pnpm website:build
pnpm check:website
```

也可以在 `website/` 内执行:

```bash
cd website
pnpm install
pnpm build
```

构建输出目录为:

```text
website/dist
```

## 6. 部署后验收

发布后检查:

```bash
curl -I https://goagent.top/
curl -I https://www.goagent.top/
curl https://goagent.top/ | grep -i goagent
```

期望:

- `https://goagent.top/` 返回 200。
- `https://www.goagent.top/` 跳转到 `https://goagent.top/` 或正常展示同一站点。
- 页面中包含 `goagent`、GitHub Releases 链接和隐私说明入口。
7 changes: 7 additions & 0 deletions website/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config'

export default defineConfig({
site: 'https://goagent.top',
output: 'static',
trailingSlash: 'never'
})
16 changes: 16 additions & 0 deletions website/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@goagent/website",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"astro": "^5.16.4",
"typescript": "^5.9.3"
}
}
4 changes: 4 additions & 0 deletions website/public/_headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
1 change: 1 addition & 0 deletions website/public/_redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://www.goagent.top/* https://goagent.top/:splat 301
41 changes: 41 additions & 0 deletions website/public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions website/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://goagent.top/sitemap-index.xml
1 change: 1 addition & 0 deletions website/public/screenshots/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

73 changes: 73 additions & 0 deletions website/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
import '../styles/global.css'

interface Props {
title?: string
description?: string
canonical?: string
}

const {
title = 'goagent - 本地优先的围棋 AI 老师',
description = 'goagent 是本地优先的围棋智能体:KataGo 负责事实,多模态 LLM 负责讲解,质量门禁负责防止编造。',
canonical = new URL(Astro.url.pathname, 'https://goagent.top').toString()
} = Astro.props

const navItems = [
{ href: '/', label: '首页' },
{ href: '/download', label: '下载' },
{ href: '/docs', label: '文档' },
{ href: '/privacy', label: '隐私' },
{ href: '/faq', label: 'FAQ' },
{ href: '/changelog', label: 'Changelog' }
]
---
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:url" content={canonical} />
<meta property="og:image" content="https://goagent.top/logo.svg" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#f6efe2" />
<link rel="icon" href="/logo.svg" type="image/svg+xml" />
</head>
<body>
<div class="site-shell">
<header class="site-header">
<a class="brand" href="/" aria-label="goagent home">
<img src="/logo.svg" alt="" width="36" height="36" />
<span>goagent</span>
</a>
<nav aria-label="主导航">
{navItems.map((item) => <a href={item.href}>{item.label}</a>)}
</nav>
<a class="header-cta" href="https://github.com/wimi321/GoAgent/releases">下载最新版</a>
</header>
<main>
<slot />
</main>
<footer class="site-footer">
<div>
<strong>goagent</strong>
<p>本地优先的围棋 AI 老师。KataGo gives evidence. LLM explains.</p>
</div>
<div class="footer-links">
<a href="https://github.com/wimi321/GoAgent">GitHub</a>
<a href="https://github.com/wimi321/GoAgent/releases">Releases</a>
<a href="https://github.com/wimi321/GoAgent/issues">Issues</a>
<a href="/privacy">Privacy</a>
<a href="https://github.com/wimi321/GoAgent/blob/main/LICENSE">License MIT</a>
</div>
<p class="copyright">Copyright © {new Date().getFullYear()} goagent contributors.</p>
</footer>
</div>
</body>
</html>
20 changes: 20 additions & 0 deletions website/src/pages/changelog.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
import BaseLayout from '../layouts/BaseLayout.astro'
---
<BaseLayout title="goagent Changelog" description="goagent 近期版本摘要和后续路线。">
<section class="page-hero">
<p class="eyebrow">Changelog</p>
<h1>版本摘要</h1>
<p class="lead">官网第一版先手写近期版本摘要;完整记录请查看 GitHub Releases 和仓库 CHANGELOG。</p>
</section>
<section class="content-stack">
<article class="doc-card">
<h2>0.3.x</h2>
<p>围绕真实复盘质量持续强化:棋形识别、区间复盘、老师会话、学生设置、知识库来源策略、质量评测、KataGo engine telemetry 和多语言 UI。</p>
</article>
<article class="doc-card">
<h2>后续版本</h2>
<p>TTS、真实教学评测、常驻 KataGo Engine Pool、自动更新、发布包 smoke test 和更完整的视觉 QA 仍会继续推进。</p>
</article>
</section>
</BaseLayout>
Loading
Loading