fork: remove public website
Drops website/ (Astro marketing site), its build script, deploy and CI workflows, dependabot block, and doc references. docs/ stays canonical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
name: Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ["website/**"]
|
||||
pull_request:
|
||||
paths: ["website/**"]
|
||||
|
||||
concurrency:
|
||||
group: website-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Website Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install and build
|
||||
working-directory: website
|
||||
run: npm install && npm run build
|
||||
@@ -202,39 +202,3 @@ updates:
|
||||
acp:
|
||||
patterns: ["@agentclientprotocol/*"]
|
||||
update-types: ["minor", "patch"]
|
||||
|
||||
# npm: website
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/website"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
time: "06:00"
|
||||
timezone: "Etc/UTC"
|
||||
open-pull-requests-limit: 3
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "javascript"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
semver-minor-days: 14
|
||||
semver-major-days: 28
|
||||
groups:
|
||||
tailwind:
|
||||
patterns:
|
||||
- "tailwindcss"
|
||||
- "@tailwindcss/*"
|
||||
update-types: ["minor", "patch"]
|
||||
website-minor-patch:
|
||||
patterns: ["*"]
|
||||
exclude-patterns:
|
||||
- "tailwindcss"
|
||||
- "@tailwindcss/*"
|
||||
update-types: ["minor", "patch"]
|
||||
ignore:
|
||||
- dependency-name: "tailwindcss"
|
||||
update-types: ["version-update:semver-major"]
|
||||
- dependency-name: "@tailwindcss/*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
@@ -323,15 +323,3 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
nix build --no-link .#packages.x86_64-linux.aoe-web-frontend
|
||||
|
||||
website:
|
||||
name: Website Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
- name: Install and build
|
||||
working-directory: website
|
||||
run: npm install && npm run build
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
name: Deploy Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'website/**'
|
||||
- 'docs/**'
|
||||
- 'assets/**'
|
||||
- 'scripts/build-site.sh'
|
||||
- 'scripts/install.sh'
|
||||
- 'src/**'
|
||||
- 'xtask/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Generate CLI documentation
|
||||
run: |
|
||||
mkdir -p target/ci-web-dist
|
||||
printf '<!doctype html><title>aoe docs placeholder</title>\n' > target/ci-web-dist/index.html
|
||||
AOE_WEB_DIST="$PWD/target/ci-web-dist" cargo xtask gen-docs
|
||||
|
||||
- name: Build site
|
||||
run: ./scripts/build-site.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
||||
with:
|
||||
path: dist
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||
+1
-15
@@ -2,15 +2,12 @@
|
||||
.claude/
|
||||
# Rust build artifacts
|
||||
/target/
|
||||
# JS / Python tooling artifacts (per-subproject installs in web/, website/, etc.)
|
||||
# JS / Python tooling artifacts (per-subproject installs in web/, etc.)
|
||||
node_modules/
|
||||
.venv/
|
||||
# Documentation build output
|
||||
/book/
|
||||
|
||||
# Website build output
|
||||
/dist/
|
||||
|
||||
# Binaries
|
||||
*.exe
|
||||
*.exe~
|
||||
@@ -57,17 +54,6 @@ sdd-*/
|
||||
*.screenstudio/
|
||||
|
||||
debug.log
|
||||
website/.next/
|
||||
|
||||
# Generated by website/scripts/sync-docs.mjs (source of truth is docs/)
|
||||
website/src/pages/guides/*.md
|
||||
website/src/pages/guides/web/*.md
|
||||
website/src/pages/docs/*.md
|
||||
website/src/pages/docs/guides/*.md
|
||||
website/src/pages/docs/cli/*.md
|
||||
website/src/pages/docs/structured-view/*.md
|
||||
website/src/pages/docs/development/*.md
|
||||
website/src/pages/docs/development/internals/*.md
|
||||
.worktrees/
|
||||
.gstack/
|
||||
.playwright-mcp/
|
||||
|
||||
@@ -221,14 +221,9 @@ Step-by-step recipe: `docs/development/adding-a-migration.md`.
|
||||
|
||||
Every compile-time embedded asset (`include_bytes!`, `include_str!`, `include!`) that is not a `*.rs` or `*.toml` must be unioned into `commonArgs.src` in `flake.nix`; otherwise the Cargo source filter drops it and `nix build` fails on it while `cargo build` stays green (#3204). `scripts/check-nix-embedded-assets.py` validates this on every PR.
|
||||
|
||||
## Website & Documentation
|
||||
## Documentation
|
||||
|
||||
The public website (agent-of-empires.com) is an Astro static site in `website/`.
|
||||
|
||||
- **`docs/`** is the canonical source for all documentation and guide content. Edit docs here, never on the website side.
|
||||
- Astro component pages (`*.astro`) like `website/src/pages/guides/index.astro` are not generated; edit them directly.
|
||||
|
||||
To add a new page to the website, follow `docs/development/adding-a-website-page.md`.
|
||||
`docs/` is the canonical source for all documentation and guide content.
|
||||
|
||||
## Design System
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Design System -- Agent of Empires
|
||||
|
||||
> **Scope note (2026-05-17):** Color is unified across the TUI and the web dashboard via the canonical theme TOML model. The TUI renders directly from a `Theme`; the web dashboard renders from a server-side projection (`ResolvedTheme`) of the same `Theme`. Surfaces (TUI vs web vs marketing) still differ on typography, density, and motion, but the color palette follows the user's chosen theme on both code surfaces. See the [Theme system](#theme-system) and [Web Dashboard subset](#web-dashboard-subset) sections below.
|
||||
> **Scope note (2026-05-17):** Color is unified across the TUI and the web dashboard via the canonical theme TOML model. The TUI renders directly from a `Theme`; the web dashboard renders from a server-side projection (`ResolvedTheme`) of the same `Theme`. Surfaces (TUI vs web) still differ on typography, density, and motion, but the color palette follows the user's chosen theme on both code surfaces. See the [Theme system](#theme-system) and [Web Dashboard subset](#web-dashboard-subset) sections below.
|
||||
|
||||
## Product Context
|
||||
- **What this is:** Terminal session manager for AI coding agents (Claude Code, Gemini CLI, OpenCode, Codex, Mistral Vibe, etc.)
|
||||
- **Who it's for:** Developers who run multiple AI coding agents in parallel and want a single dashboard to manage them
|
||||
- **Space/industry:** Developer tools, terminal utilities, AI coding infrastructure
|
||||
- **Project type:** Open source CLI/TUI tool with a marketing/docs website (Astro + Tailwind)
|
||||
- **Project type:** Open source CLI/TUI tool
|
||||
- **Peers:** Warp, Zed, Ghostty, tmux ecosystem tools
|
||||
|
||||
## Aesthetic Direction
|
||||
@@ -227,13 +227,9 @@ The user's chosen theme is the source of truth for color on both the TUI and the
|
||||
- Existing custom TOML themes (`~/.agent-of-empires/themes/*.toml`) parse unchanged. The new optional metadata fields default to `None` / empty for custom themes that omit them; the server falls back to luminance classification and appearance-based syntax theme selection.
|
||||
- The TOML schema does **not** declare ANSI 16 colors per theme; the resolver derives them from semantic fields (ANSI 1 = error, 2 = running, ...). An optional `[terminal]` override section is future work; v1 derives so user themes work without authoring 16 hexes.
|
||||
|
||||
### Marketing site (`website/`)
|
||||
|
||||
The marketing site has its own palette (the original warm-navy Empire-aligned ramp documented in the [Color](#color) section above). It is brand expression, not user surface, so the user's theme picker doesn't affect it.
|
||||
|
||||
## Web Dashboard subset
|
||||
|
||||
The web dashboard (`web/`) is a utility that sits between a developer and a terminal. It is dense, keyboard-driven, and deliberately quieter than the marketing site. Use these rules when editing anything under `web/`.
|
||||
The web dashboard (`web/`) is a utility that sits between a developer and a terminal. It is dense, keyboard-driven, and deliberately quiet. Use these rules when editing anything under `web/`.
|
||||
|
||||
### Typography
|
||||
|
||||
@@ -252,15 +248,15 @@ The web dashboard (`web/`) is a utility that sits between a developer and a term
|
||||
|
||||
### Density and motion
|
||||
|
||||
- Row heights: 28-32px. Buttons: 32-40px. The dashboard is denser than the marketing site on purpose.
|
||||
- Row heights: 28-32px. Buttons: 32-40px. The dashboard is dense on purpose.
|
||||
- Border radii: `rounded-md` (6px) for inline affordances, `rounded-lg` (8px) for panels and dialogs. No `rounded-xl` or larger in the dashboard.
|
||||
- Motion: `animate-fade-in`, `animate-slide-up`, and `animate-term-cursor-blink` (the live terminal's focused-cursor blink, a terminal convention rather than decorative motion) are the only named transitions. Prefer `transition-colors` for hover/focus. Avoid scaling, parallax, or layered motion.
|
||||
|
||||
### What stays per-surface
|
||||
|
||||
- Font families (Geist on the dashboard, Satoshi/DM Sans on marketing).
|
||||
- Density (denser on the dashboard than on the marketing site).
|
||||
- Motion (minimal-functional on both; no decorative motion in the dashboard).
|
||||
- Font families (Geist on the dashboard, TUI inherits the terminal).
|
||||
- Density (denser on the dashboard than the TUI can be).
|
||||
- Motion (minimal-functional; no decorative motion in the dashboard).
|
||||
|
||||
### What to avoid
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# Adding a new page to the website
|
||||
|
||||
The public website (agent-of-empires.com) is an Astro static site in `website/`.
|
||||
`docs/` is the canonical source for all documentation and guide content: edit
|
||||
docs there, never on the website side.
|
||||
|
||||
1. Create the page in `docs/` (with a `# Title` as the first line).
|
||||
2. Add an entry to the `PAGES` array in `website/scripts/sync-docs.mjs` with `source`, `dest`, `title`, and `description`.
|
||||
3. Add the page's source path → website URL mapping to `URL_MAP` in the same script.
|
||||
4. Add a nav entry in `website/src/data/docsNav.ts`.
|
||||
|
||||
The CI workflow (`.github/workflows/docs.yml`) triggers on changes to `docs/**`,
|
||||
`website/**`, and other relevant paths.
|
||||
|
||||
Astro component pages (`*.astro`) like `website/src/pages/guides/index.astro` are
|
||||
not generated; edit them directly.
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Build the full Agent of Empires website
|
||||
# Output: dist/ directory ready for deployment
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
DIST_DIR="$ROOT_DIR/dist"
|
||||
|
||||
echo "Building Agent of Empires website..."
|
||||
|
||||
# Clean previous build
|
||||
rm -rf "$DIST_DIR"
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
# 1. Copy shared assets to website/public before Astro build
|
||||
echo "Copying assets to website..."
|
||||
mkdir -p "$ROOT_DIR/website/public/assets"
|
||||
cp "$ROOT_DIR/assets/logo.svg" "$ROOT_DIR/website/public/assets/"
|
||||
cp "$ROOT_DIR/assets/logo.png" "$ROOT_DIR/website/public/assets/"
|
||||
cp "$ROOT_DIR/assets/social-preview.png" "$ROOT_DIR/website/public/assets/" 2>/dev/null || true
|
||||
cp "$ROOT_DIR/assets/social-preview.svg" "$ROOT_DIR/website/public/assets/" 2>/dev/null || true
|
||||
for f in "$ROOT_DIR/docs/assets/"*; do
|
||||
[ -f "$f" ] || continue
|
||||
cp "$f" "$ROOT_DIR/website/public/assets/"
|
||||
echo " - $(basename "$f") copied ($(du -h "$f" | cut -f1))"
|
||||
done
|
||||
|
||||
# 2. Build Astro website
|
||||
echo "Building Astro website..."
|
||||
(cd "$ROOT_DIR/website" && npm install && npm run build)
|
||||
|
||||
# 3. Copy Astro output to dist/
|
||||
echo "Copying website..."
|
||||
cp -r "$ROOT_DIR/website/dist/"* "$DIST_DIR/"
|
||||
|
||||
# 4. Copy install script
|
||||
echo "Copying install script..."
|
||||
cp "$ROOT_DIR/scripts/install.sh" "$DIST_DIR/"
|
||||
|
||||
# 5. Create a simple 404 page that redirects to home
|
||||
cat > "$DIST_DIR/404.html" << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Page Not Found - Agent of Empires</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-slate-950 text-gray-100 min-h-screen flex items-center justify-center">
|
||||
<div class="text-center px-6">
|
||||
<img src="/assets/logo.svg" alt="Agent of Empires" class="w-16 h-16 mx-auto mb-6 opacity-50">
|
||||
<h1 class="text-4xl font-bold mb-4">404</h1>
|
||||
<p class="text-gray-400 mb-8">Page not found</p>
|
||||
<a href="/" class="bg-amber-600 hover:bg-amber-500 text-white font-semibold px-6 py-3 rounded-lg transition-colors">
|
||||
Go Home
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# 6. Create CNAME file for GitHub Pages (if using custom domain)
|
||||
echo "agent-of-empires.com" > "$DIST_DIR/CNAME"
|
||||
|
||||
echo ""
|
||||
echo "Build complete! Output in: $DIST_DIR"
|
||||
echo ""
|
||||
echo "Directory structure:"
|
||||
find "$DIST_DIR" -type f -print 2>/dev/null | head -20 | sed "s|$DIST_DIR|dist|" || true
|
||||
echo ""
|
||||
echo "To preview locally:"
|
||||
echo " cd $DIST_DIR && python3 -m http.server 8000"
|
||||
echo ""
|
||||
echo "To deploy to GitHub Pages, Cloudflare Pages, or Netlify:"
|
||||
echo " Point your deployment to the dist/ directory"
|
||||
@@ -1,10 +0,0 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.astro/
|
||||
|
||||
# Auto-generated during build
|
||||
public/assets/*
|
||||
!public/assets/.gitkeep
|
||||
!public/assets/social-banner.svg
|
||||
!public/assets/social-preview.png
|
||||
sitemap.xml
|
||||
@@ -1 +0,0 @@
|
||||
min-release-age=7
|
||||
@@ -1,29 +0,0 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
import sitemap from '@astrojs/sitemap';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig({
|
||||
site: 'https://agent-of-empires.com',
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
},
|
||||
// The "cockpit" docs were renamed to "structured-view" (the web dashboard's
|
||||
// default structured view). Redirect the old URLs so external links and search
|
||||
// results keep working. Astro emits static meta-refresh pages for these
|
||||
// on `astro build`, which works on the GitHub Pages static host.
|
||||
redirects: {
|
||||
'/docs/cockpit/': '/docs/structured-view/',
|
||||
'/docs/cockpit/setup/': '/docs/structured-view/setup/',
|
||||
'/docs/cockpit/interface/': '/docs/structured-view/interface/',
|
||||
'/docs/cockpit/controls/': '/docs/structured-view/controls/',
|
||||
'/docs/cockpit/persistence/': '/docs/structured-view/persistence/',
|
||||
'/docs/cockpit/troubleshooting/': '/docs/structured-view/troubleshooting/',
|
||||
'/docs/cockpit/multi-agent/': '/docs/structured-view/multi-agent/',
|
||||
},
|
||||
integrations: [
|
||||
sitemap({
|
||||
changefreq: 'weekly',
|
||||
priority: 0.7,
|
||||
}),
|
||||
],
|
||||
});
|
||||
Generated
-4784
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "agent-of-empires-website",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"copy-assets": "cp ../assets/logo.svg ../assets/logo.png ../assets/logo-youtube.png ../assets/social-preview.png public/assets/ && cp ../docs/assets/*.gif ../docs/assets/*.png public/assets/ && mkdir -p public/assets/structured-view public/assets/web && cp ../docs/assets/structured-view/*.png public/assets/structured-view/ && cp ../docs/assets/web/*.png public/assets/web/",
|
||||
"sync-docs": "node scripts/sync-docs.mjs",
|
||||
"dev": "npm run copy-assets && npm run sync-docs && astro dev",
|
||||
"build": "npm run copy-assets && npm run sync-docs && astro build",
|
||||
"preview": "astro preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/sitemap": "3.7.3",
|
||||
"@tailwindcss/vite": "^4.3.3",
|
||||
"astro": "^7.1.6",
|
||||
"tailwindcss": "^4.2.4"
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="640" viewBox="0 0 1280 640">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#0f172a"/>
|
||||
<stop offset="100%" stop-color="#020617"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="win-back" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#78350f"/>
|
||||
<stop offset="100%" stop-color="#451a03"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="win-mid" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#92400e"/>
|
||||
<stop offset="100%" stop-color="#78350f"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="win-front" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#f59e0b"/>
|
||||
<stop offset="100%" stop-color="#d97706"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="titlebar" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#fbbf24"/>
|
||||
<stop offset="100%" stop-color="#f59e0b"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="accent-line" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#d97706"/>
|
||||
<stop offset="50%" stop-color="#0d9488"/>
|
||||
<stop offset="100%" stop-color="#0d9488" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect width="1280" height="640" fill="url(#bg)"/>
|
||||
|
||||
<!-- Subtle grid lines -->
|
||||
<g stroke="#334155" stroke-width="0.5" opacity="0.12">
|
||||
<line x1="0" y1="160" x2="1280" y2="160"/>
|
||||
<line x1="0" y1="320" x2="1280" y2="320"/>
|
||||
<line x1="0" y1="480" x2="1280" y2="480"/>
|
||||
<line x1="320" y1="0" x2="320" y2="640"/>
|
||||
<line x1="640" y1="0" x2="640" y2="640"/>
|
||||
<line x1="960" y1="0" x2="960" y2="640"/>
|
||||
</g>
|
||||
|
||||
<!-- Decorative background terminal shapes (scattered, faded, 3 panes each) -->
|
||||
<g transform="translate(40, 80) scale(1.2)" opacity="0.08">
|
||||
<rect x="10" y="38" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="20" y="28" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="32" y="18" width="82" height="66" rx="6" fill="#94a3b8"/>
|
||||
</g>
|
||||
<g transform="translate(980, 60) scale(1.0)" opacity="0.06">
|
||||
<rect x="10" y="38" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="20" y="28" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="32" y="18" width="82" height="66" rx="6" fill="#94a3b8"/>
|
||||
</g>
|
||||
<g transform="translate(30, 400) scale(0.9)" opacity="0.06">
|
||||
<rect x="10" y="38" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="20" y="28" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="32" y="18" width="82" height="66" rx="6" fill="#94a3b8"/>
|
||||
</g>
|
||||
<g transform="translate(1050, 380) scale(1.1)" opacity="0.07">
|
||||
<rect x="10" y="38" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="20" y="28" width="76" height="60" rx="6" fill="#94a3b8"/>
|
||||
<rect x="32" y="18" width="82" height="66" rx="6" fill="#94a3b8"/>
|
||||
</g>
|
||||
|
||||
<!-- Main icon -->
|
||||
<g transform="translate(450, 170) scale(1.6)">
|
||||
<rect x="10" y="38" width="76" height="60" rx="6" fill="url(#win-back)" opacity="0.6"/>
|
||||
<rect x="20" y="28" width="76" height="60" rx="6" fill="url(#win-mid)" opacity="0.7"/>
|
||||
<g>
|
||||
<rect x="32" y="18" width="82" height="66" rx="6" fill="url(#win-front)"/>
|
||||
<rect x="32" y="18" width="82" height="18" rx="6" fill="url(#titlebar)"/>
|
||||
<rect x="32" y="30" width="82" height="6" fill="url(#titlebar)"/>
|
||||
<circle cx="46" cy="28" r="2.8" fill="#b45309" opacity="0.55"/>
|
||||
<circle cx="55" cy="28" r="2.8" fill="#b45309" opacity="0.55"/>
|
||||
<circle cx="64" cy="28" r="2.8" fill="#b45309" opacity="0.55"/>
|
||||
<rect x="36" y="39" width="74" height="41" rx="3" fill="#b45309" opacity="0.22"/>
|
||||
<text x="45" y="65" font-family="'Courier New', monospace" font-size="20" font-weight="bold" fill="#fef3c7" opacity="0.85">$</text>
|
||||
<rect x="64" y="51" width="9" height="17" rx="2" fill="#fef3c7" opacity="0.75"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- "aoe" text -->
|
||||
<text x="680" y="258" font-family="'Satoshi', 'DM Sans', 'Inter', system-ui, sans-serif" font-size="56" font-weight="400" fill="#e2e8f0" letter-spacing="0.12em">aoe</text>
|
||||
|
||||
<!-- "AGENT OF EMPIRES" subtitle -->
|
||||
<text x="680" y="292" font-family="'JetBrains Mono', 'SF Mono', monospace" font-size="14" fill="#64748b" letter-spacing="0.2em">AGENT OF EMPIRES</text>
|
||||
|
||||
<!-- Tagline -->
|
||||
<text x="640" y="398" font-family="'DM Sans', 'Inter', system-ui, sans-serif" font-size="22" fill="#94a3b8">Conquer your codebase.</text>
|
||||
|
||||
<!-- Accent line -->
|
||||
<rect x="640" y="430" width="200" height="2" fill="url(#accent-line)" rx="1"/>
|
||||
|
||||
<!-- Bottom border gradient -->
|
||||
<rect x="0" y="636" width="1280" height="4" fill="url(#accent-line)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
@@ -1,176 +0,0 @@
|
||||
// Hero demo toggle: swap the framed screenshot between the TUI and the web dashboard.
|
||||
// Both surfaces drive the same live sessions; neither is primary.
|
||||
function switchDemo(which) {
|
||||
var img = document.getElementById('demo-img');
|
||||
var label = document.getElementById('demo-chrome-label');
|
||||
if (!img) return;
|
||||
|
||||
var demos = {
|
||||
tui: {
|
||||
src: '/assets/demo.gif',
|
||||
alt: 'Agent of Empires TUI showing session management with Claude Code, git worktree creation, and Docker container status indicators',
|
||||
label: 'aoe · session manager',
|
||||
},
|
||||
web: {
|
||||
src: '/assets/web-desktop.gif',
|
||||
alt: 'Agent of Empires web dashboard driving live agent sessions from the browser',
|
||||
label: 'aoe · web dashboard',
|
||||
},
|
||||
};
|
||||
var demo = demos[which] || demos.tui;
|
||||
|
||||
img.src = demo.src;
|
||||
img.alt = demo.alt;
|
||||
if (label) label.textContent = demo.label;
|
||||
|
||||
document.querySelectorAll('.demo-tab').forEach(function(t) {
|
||||
if (t.dataset.demo === which) {
|
||||
t.classList.add('demo-tab-active');
|
||||
t.setAttribute('aria-pressed', 'true');
|
||||
} else {
|
||||
t.classList.remove('demo-tab-active');
|
||||
t.setAttribute('aria-pressed', 'false');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Compact install widget: toggle Homebrew vs install script, copy the active one.
|
||||
function switchInstall(btn, which) {
|
||||
var group = btn.closest('.install-group');
|
||||
if (!group) return;
|
||||
group.dataset.active = which;
|
||||
group.querySelectorAll('[data-install-view]').forEach(function(v) {
|
||||
v.classList.toggle('hidden', v.dataset.installView !== which);
|
||||
});
|
||||
group.querySelectorAll('button[data-install]').forEach(function(t) {
|
||||
var on = t.dataset.install === which;
|
||||
t.classList.toggle('demo-tab-active', on);
|
||||
t.setAttribute('aria-pressed', on ? 'true' : 'false');
|
||||
});
|
||||
}
|
||||
|
||||
function copyInstall(btn) {
|
||||
var group = btn.closest('.install-group');
|
||||
if (!group) return;
|
||||
var which = group.dataset.active || 'brew';
|
||||
var cmd = which === 'curl' ? group.dataset.curl : group.dataset.brew;
|
||||
copyCommand(cmd, btn);
|
||||
}
|
||||
|
||||
function copyCommand(cmd, btn) {
|
||||
function showCopied() {
|
||||
btn.innerHTML = '<svg class="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg><span class="copy-tooltip">Copied!</span>';
|
||||
setTimeout(function() {
|
||||
btn.innerHTML = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/></svg>';
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(cmd).then(showCopied).catch(function() {
|
||||
fallbackCopy(cmd);
|
||||
showCopied();
|
||||
});
|
||||
} else {
|
||||
fallbackCopy(cmd);
|
||||
showCopied();
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopy(text) {
|
||||
var textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.opacity = '0';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
// Mobile sidebar toggle
|
||||
function toggleMobileSidebar(btn) {
|
||||
var expanded = btn.getAttribute('aria-expanded') === 'true';
|
||||
var menuId = btn.getAttribute('aria-controls');
|
||||
var menu = document.getElementById(menuId);
|
||||
if (!menu) return;
|
||||
|
||||
btn.setAttribute('aria-expanded', String(!expanded));
|
||||
menu.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
// Fetch GitHub star count (only when the badge is on the page; it isn't on docs pages)
|
||||
const starCountEl = document.getElementById('star-count');
|
||||
if (starCountEl) {
|
||||
fetch('https://api.github.com/repos/agent-of-empires/agent-of-empires')
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error('star count fetch failed: ' + res.status);
|
||||
return res.json();
|
||||
})
|
||||
.then(data => {
|
||||
const count = data.stargazers_count;
|
||||
if (count !== undefined) {
|
||||
starCountEl.textContent = count >= 1000 ? (count / 1000).toFixed(1) + 'k' : count;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
starCountEl.textContent = '';
|
||||
});
|
||||
}
|
||||
|
||||
// Theme toggle
|
||||
function initThemeToggle() {
|
||||
function updateIcons(theme) {
|
||||
document.querySelectorAll('.theme-icon-sun').forEach(function(el) {
|
||||
el.classList.toggle('hidden', theme === 'light');
|
||||
});
|
||||
document.querySelectorAll('.theme-icon-moon').forEach(function(el) {
|
||||
el.classList.toggle('hidden', theme === 'dark');
|
||||
});
|
||||
document.querySelectorAll('.theme-label').forEach(function(el) {
|
||||
el.textContent = theme === 'dark' ? 'Light mode' : 'Dark mode';
|
||||
});
|
||||
}
|
||||
|
||||
var currentTheme = document.documentElement.dataset.theme || 'dark';
|
||||
updateIcons(currentTheme);
|
||||
|
||||
document.querySelectorAll('#theme-toggle, #theme-toggle-mobile').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.dataset.theme = next;
|
||||
document.documentElement.style.colorScheme = next;
|
||||
localStorage.setItem('theme', next);
|
||||
updateIcons(next);
|
||||
});
|
||||
});
|
||||
|
||||
// Follow the OS theme live until the visitor picks one explicitly.
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
|
||||
var stored = localStorage.getItem('theme');
|
||||
if (stored === 'dark' || stored === 'light') return;
|
||||
var theme = e.matches ? 'dark' : 'light';
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
updateIcons(theme);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initThemeToggle();
|
||||
|
||||
// Scroll-triggered animations
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('is-visible');
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
document.querySelectorAll('.animate-on-scroll').forEach((el) => {
|
||||
observer.observe(el);
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,581 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// Syncs docs/ → website/src/pages/ (guides and docs pages).
|
||||
//
|
||||
// Single source of truth: docs/ contains the canonical markdown.
|
||||
// This script strips the # Title line, rewrites relative links for the
|
||||
// website URL scheme, and prepends Astro frontmatter.
|
||||
//
|
||||
// Generated files are .gitignored; do NOT edit them by hand.
|
||||
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
||||
import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, "..", "..");
|
||||
const PAGES_DIR = join(__dirname, "..", "src", "pages");
|
||||
|
||||
// All pages to sync. "source" is relative to repo root, "dest" is relative
|
||||
// to website/src/pages/. Layout path is computed from dest depth.
|
||||
const PAGES = [
|
||||
// --- Guides (docs/guides/ → pages/guides/) ---
|
||||
{
|
||||
source: "docs/guides/shell-completions.md",
|
||||
dest: "guides/shell-completions.md",
|
||||
title: "Shell Completions",
|
||||
description:
|
||||
"Install and refresh tab-completion for the aoe CLI in bash, zsh, fish, PowerShell, and elvish.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/diff-view.md",
|
||||
dest: "guides/diff-view.md",
|
||||
title: "Diff View",
|
||||
description:
|
||||
"Review git changes and edit files directly from the Agent of Empires TUI.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/repo-config.md",
|
||||
dest: "guides/repo-config.md",
|
||||
title: "Repository Configuration & Hooks",
|
||||
description:
|
||||
"Per-repo configuration and hooks for Agent of Empires sessions.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/mcp-servers.md",
|
||||
dest: "guides/mcp-servers.md",
|
||||
title: "MCP Servers",
|
||||
description:
|
||||
"Forward configured MCP servers to structured-view agents via mcp.json.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/sandbox.md",
|
||||
dest: "guides/sandbox.md",
|
||||
title: "Docker Sandbox: Quick Reference",
|
||||
description:
|
||||
"Run AI coding agents in isolated Docker containers with Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/otari-telemetry.md",
|
||||
dest: "guides/otari-telemetry.md",
|
||||
title: "Claude Code Telemetry to Otari",
|
||||
description:
|
||||
"Export Claude Code usage from host and AoE sandbox sessions to a self-hosted Otari gateway.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/tmux-status-bar.md",
|
||||
dest: "guides/tmux-status-bar.md",
|
||||
title: "tmux Status Bar",
|
||||
description:
|
||||
"Configure the tmux status bar to display Agent of Empires session information.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/web-dashboard.md",
|
||||
dest: "guides/web-dashboard.md",
|
||||
title: "Web Dashboard (Experimental)",
|
||||
description:
|
||||
"Remote access to AI coding agent sessions from any browser with Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/remote-phone-access.md",
|
||||
dest: "guides/remote-phone-access.md",
|
||||
title: "Remote Access from Your Phone",
|
||||
description:
|
||||
"Access your Agent of Empires sessions from your phone via Tailscale Funnel or Cloudflare Tunnel with QR pairing.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/tailscale.md",
|
||||
dest: "guides/tailscale.md",
|
||||
title: "Tailscale Setup",
|
||||
description:
|
||||
"Set up Tailscale from scratch to reach your AOE TUI and web dashboard from any device on your tailnet.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/web/dashboard.md",
|
||||
dest: "guides/web/dashboard.md",
|
||||
title: "Dashboard & Workspaces",
|
||||
description:
|
||||
"The web dashboard layout: workspace sidebar, status glyphs, the session-creation wizard, command palette, sidebar sort, and triage.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/web/terminal.md",
|
||||
dest: "guides/web/terminal.md",
|
||||
title: "Terminal View",
|
||||
description:
|
||||
"The browser agent and paired terminals: PTY relay, scrollback, reconnect behavior, WebSocket close codes, and read-only mode.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/web/diff.md",
|
||||
dest: "guides/web/diff.md",
|
||||
title: "Web Diff View",
|
||||
description:
|
||||
"Review a session's changes from the browser: the flat / tree changed-files list, per-repo base override, and inline review comments.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/web/settings.md",
|
||||
dest: "guides/web/settings.md",
|
||||
title: "Settings & Profiles",
|
||||
description:
|
||||
"The web settings tabs, the profile picker, connected-device tracking, and the step-up elevation gate for persisted config edits.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/worktrees.md",
|
||||
dest: "guides/worktrees.md",
|
||||
title: "Worktrees Reference",
|
||||
description:
|
||||
"Git worktree commands and configuration reference for Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/agent-override.md",
|
||||
dest: "guides/agent-override.md",
|
||||
title: "Agent Command Overrides",
|
||||
description:
|
||||
"Override agent commands with custom scripts or sandboxed wrappers in Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/session-resume.md",
|
||||
dest: "guides/session-resume.md",
|
||||
title: "Session Resume (Claude)",
|
||||
description:
|
||||
"Persist and resume Claude Code conversations across reboots, upgrades, and runtime rotations.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/session-fork.md",
|
||||
dest: "guides/session-fork.md",
|
||||
title: "Forking Sessions",
|
||||
description:
|
||||
"Fork a session to start a second agent from its context, then diverge onto a different task, leaving the original untouched.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/multi-repo-workspaces.md",
|
||||
dest: "guides/multi-repo-workspaces.md",
|
||||
title: "Multi-Repo Workspaces",
|
||||
description:
|
||||
"Drive a single Agent of Empires session across several git repositories with the project registry and multi-select pickers.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/scratch-sessions.md",
|
||||
dest: "guides/scratch-sessions.md",
|
||||
title: "Scratch Sessions",
|
||||
description:
|
||||
"Launch a session in a fresh scratch directory under ~/.agent-of-empires/scratch/ with no project path. The directory is removed when the session is deleted.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/live-mode.md",
|
||||
dest: "guides/live-mode.md",
|
||||
title: "Live Mode",
|
||||
description:
|
||||
"A feels-attached alternative to a full tmux attach: the dashboard stays visible while keystrokes relay to the agent. Covers the Ctrl+B leader menu, the collapsible sidebar, scrolling, and the exit chord.",
|
||||
},
|
||||
|
||||
// --- Docs pages (docs/ → pages/docs/) ---
|
||||
{
|
||||
source: "docs/plugins.md",
|
||||
dest: "docs/plugins.md",
|
||||
title: "Plugins",
|
||||
description:
|
||||
"Enable, disable, install, and update plugins from the CLI, TUI, or web dashboard; capability approvals, bundled plugins, and writing your own.",
|
||||
},
|
||||
{
|
||||
source: "docs/index.md",
|
||||
dest: "docs/index.md",
|
||||
title: "Agent of Empires",
|
||||
description:
|
||||
"Terminal session manager for AI coding agents on Linux and macOS, built on tmux and written in Rust.",
|
||||
},
|
||||
{
|
||||
source: "docs/installation.md",
|
||||
dest: "docs/installation.md",
|
||||
title: "Installation",
|
||||
description:
|
||||
"Install Agent of Empires on Linux or macOS via the install script, Homebrew, or from source.",
|
||||
},
|
||||
{
|
||||
source: "docs/quick-start.md",
|
||||
dest: "docs/quick-start.md",
|
||||
title: "Quick Start",
|
||||
description:
|
||||
"Get up and running with Agent of Empires in minutes. Create sessions, attach to agents, and use worktrees.",
|
||||
},
|
||||
{
|
||||
source: "docs/development.md",
|
||||
dest: "docs/development.md",
|
||||
title: "Development",
|
||||
description: "Build, run, and test Agent of Empires from source.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/adding-agents.md",
|
||||
dest: "docs/development/adding-agents.md",
|
||||
title: "Adding a New Agent",
|
||||
description:
|
||||
"Step-by-step guide for adding support for a new AI coding agent to AoE.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/adding-settings.md",
|
||||
dest: "docs/development/adding-settings.md",
|
||||
title: "Adding a Setting",
|
||||
description:
|
||||
"How to add a configuration setting with the single-source schema that drives the TUI, web dashboard, and server.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/logging.md",
|
||||
dest: "docs/development/logging.md",
|
||||
title: "Logging",
|
||||
description:
|
||||
"Logging targets, env-var matrix, runtime control endpoint, and browser-side error relay for Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/playwright.md",
|
||||
dest: "docs/development/playwright.md",
|
||||
title: "Playwright + Vitest testing",
|
||||
description:
|
||||
"Long-form reference for the web dashboard test pipeline: mocked vs live Playwright, Vitest contract tests, fake ACP agent, coverage matrix, coverage reports.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/releases.md",
|
||||
dest: "docs/development/releases.md",
|
||||
title: "Releases",
|
||||
description:
|
||||
"Weekly release cadence, automated staging PR, post-merge tagger, and emergency-release path for Agent of Empires maintainers.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/web-dashboard.md",
|
||||
dest: "docs/development/web-dashboard.md",
|
||||
title: "Web Dashboard Development",
|
||||
description:
|
||||
"Build the web dashboard from source, run the frontend dev workflow (cargo xtask dev and manual Vite + VITE_PROXY), and the server architecture.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/internals/structured-view.md",
|
||||
dest: "docs/development/internals/structured-view.md",
|
||||
title: "Structured View Internals",
|
||||
description:
|
||||
"Contributor reference for the ACP subsystem: worker lifecycle and persistence, stuck-turn watchdogs, rate-limit handling, agent profiles, and the security model.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/internals/sandbox.md",
|
||||
dest: "docs/development/internals/sandbox.md",
|
||||
title: "Sandbox Internals",
|
||||
description:
|
||||
"Contributor reference for Docker sandbox internals: shared agent credential sync, the container lifecycle, Vertex AI wiring, and GH_TOKEN forwarding.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/internals/plugin-system.md",
|
||||
dest: "docs/development/internals/plugin-system.md",
|
||||
title: "Plugin System Internals",
|
||||
description:
|
||||
"Code-level design for the plugin system: subprocess JSON-RPC runtime, core event bus, contribution registries, capability model, and the phased rollout.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/writing-plugins.md",
|
||||
dest: "docs/development/writing-plugins.md",
|
||||
title: "Writing Plugins",
|
||||
description:
|
||||
"Build an Agent of Empires plugin end to end: scaffold from the template, declare the manifest, write the JSON-RPC worker, install locally, and publish.",
|
||||
},
|
||||
{
|
||||
source: "docs/development/internals/sessions.md",
|
||||
dest: "docs/development/internals/sessions.md",
|
||||
title: "Session & Worktree Internals",
|
||||
description:
|
||||
"Contributor reference for the session layer: Claude conversation resume, worktree creation, scratch-session cleanup, and MCP server forwarding.",
|
||||
},
|
||||
{
|
||||
source: "docs/sounds.md",
|
||||
dest: "docs/sounds.md",
|
||||
title: "Sound Effects",
|
||||
description:
|
||||
"Configure audio feedback for agent state transitions in Agent of Empires.",
|
||||
},
|
||||
{
|
||||
source: "docs/push-notifications.md",
|
||||
dest: "docs/push-notifications.md",
|
||||
title: "Push Notifications",
|
||||
description:
|
||||
"Browser and PWA push notifications for Agent of Empires session status changes and structured view approvals.",
|
||||
},
|
||||
{
|
||||
source: "docs/features.md",
|
||||
dest: "docs/features.md",
|
||||
title: "Features",
|
||||
description:
|
||||
"Canonical inventory of every Agent of Empires feature, grouped by surface and capability, with links to each guide.",
|
||||
},
|
||||
{
|
||||
source: "docs/github-integration.md",
|
||||
dest: "docs/github-integration.md",
|
||||
title: "GitHub Integration",
|
||||
description:
|
||||
"How Agent of Empires resolves a GitHub token, the per-failure hints it shows, and what is deferred to follow-ups.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/podman.md",
|
||||
dest: "guides/podman.md",
|
||||
title: "Podman",
|
||||
description:
|
||||
"Run Agent of Empires sandboxes on Podman, a daemonless and rootless Docker alternative.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/apple-containers.md",
|
||||
dest: "guides/apple-containers.md",
|
||||
title: "Apple Containers",
|
||||
description:
|
||||
"Run Agent of Empires sandboxes on Apple's native macOS container runtime on Apple silicon.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/configuration.md",
|
||||
dest: "docs/guides/configuration.md",
|
||||
title: "Configuration Reference",
|
||||
description:
|
||||
"Complete configuration reference for Agent of Empires settings, profiles, and repo config.",
|
||||
},
|
||||
{
|
||||
source: "docs/cli/reference.md",
|
||||
dest: "docs/cli/reference.md",
|
||||
title: "CLI Reference",
|
||||
description:
|
||||
"Complete command-line reference for the aoe CLI tool.",
|
||||
},
|
||||
{
|
||||
source: "docs/structured-view.md",
|
||||
dest: "docs/structured-view.md",
|
||||
title: "Structured View (Web Dashboard)",
|
||||
description:
|
||||
"The web dashboard's default structured view: native rendering of AI agent state via the Agent Client Protocol (ACP). Plan panels, tool-call cards, swipe-to-approve, multi-provider support.",
|
||||
},
|
||||
{
|
||||
source: "docs/structured-view/interface.md",
|
||||
dest: "docs/structured-view/interface.md",
|
||||
title: "Structured View Interface",
|
||||
description:
|
||||
"The TUI and web structured views: keybinds, composer behavior on desktop and touch, queued prompts, and timeline card grouping.",
|
||||
},
|
||||
{
|
||||
source: "docs/structured-view/controls.md",
|
||||
dest: "docs/structured-view/controls.md",
|
||||
title: "Structured View Modes, Approvals & Model Controls",
|
||||
description:
|
||||
"Permission modes, YOLO and bypassPermissions, approval cards and notifications, plus the model and reasoning-effort selectors.",
|
||||
},
|
||||
{
|
||||
source: "docs/structured-view/troubleshooting.md",
|
||||
dest: "docs/structured-view/troubleshooting.md",
|
||||
title: "Structured View Troubleshooting",
|
||||
description:
|
||||
"The structured view security model plus a field guide to every failure mode: doctor errors, spawn failures, rate limits, stuck turns, and the watchdog.",
|
||||
},
|
||||
{
|
||||
source: "docs/guides/tool-sessions.md",
|
||||
dest: "guides/tool-sessions.md",
|
||||
title: "Tool Sessions",
|
||||
description:
|
||||
"Configure persistent dev-tool sessions (lazygit, yazi, tig, etc.) tied to each agent session's working directory, with hotkey, picker, and command-palette access.",
|
||||
},
|
||||
{
|
||||
source: "docs/api.md",
|
||||
dest: "docs/api.md",
|
||||
title: "HTTP API Reference",
|
||||
description:
|
||||
"REST endpoints for driving Agent of Empires sessions from external orchestrators.",
|
||||
},
|
||||
{
|
||||
source: "docs/plugin-api.md",
|
||||
dest: "docs/plugin-api.md",
|
||||
title: "Plugin API Reference",
|
||||
description:
|
||||
"Field-by-field reference for the aoe-plugin.toml manifest: identity, capabilities, commands, settings, UI slots, status, screenshots, and runtime.",
|
||||
},
|
||||
{
|
||||
source: "docs/telemetry.md",
|
||||
dest: "docs/telemetry.md",
|
||||
title: "Telemetry",
|
||||
description:
|
||||
"How Agent of Empires' anonymous, opt-in usage telemetry works: what is and isn't collected, the DO_NOT_TRACK override, and how to enable or disable it.",
|
||||
},
|
||||
];
|
||||
|
||||
// Every known docs path → website URL, used for link rewriting.
|
||||
const URL_MAP = {
|
||||
// Docs pages
|
||||
"docs/plugins.md": "/docs/plugins/",
|
||||
"docs/index.md": "/docs/",
|
||||
"docs/installation.md": "/docs/installation/",
|
||||
"docs/quick-start.md": "/docs/quick-start/",
|
||||
"docs/sounds.md": "/docs/sounds/",
|
||||
"docs/push-notifications.md": "/docs/push-notifications/",
|
||||
"docs/features.md": "/docs/features/",
|
||||
"docs/github-integration.md": "/docs/github-integration/",
|
||||
"docs/development.md": "/docs/development/",
|
||||
"docs/development/adding-agents.md": "/docs/development/adding-agents/",
|
||||
"docs/development/adding-settings.md": "/docs/development/adding-settings/",
|
||||
"docs/development/logging.md": "/docs/development/logging/",
|
||||
"docs/development/playwright.md": "/docs/development/playwright/",
|
||||
"docs/development/releases.md": "/docs/development/releases/",
|
||||
"docs/development/web-dashboard.md": "/docs/development/web-dashboard/",
|
||||
"docs/development/internals/structured-view.md": "/docs/development/internals/structured-view/",
|
||||
"docs/development/internals/sandbox.md": "/docs/development/internals/sandbox/",
|
||||
"docs/development/internals/plugin-system.md": "/docs/development/internals/plugin-system/",
|
||||
"docs/development/writing-plugins.md": "/docs/development/writing-plugins/",
|
||||
"docs/development/internals/sessions.md": "/docs/development/internals/sessions/",
|
||||
"docs/guides/configuration.md": "/docs/guides/configuration/",
|
||||
"docs/cli/reference.md": "/docs/cli/reference/",
|
||||
"docs/structured-view.md": "/docs/structured-view/",
|
||||
"docs/structured-view/interface.md": "/docs/structured-view/interface/",
|
||||
"docs/structured-view/controls.md": "/docs/structured-view/controls/",
|
||||
"docs/structured-view/troubleshooting.md": "/docs/structured-view/troubleshooting/",
|
||||
"docs/api.md": "/docs/api/",
|
||||
"docs/plugin-api.md": "/docs/plugin-api/",
|
||||
"docs/telemetry.md": "/docs/telemetry/",
|
||||
// Guides
|
||||
"docs/guides/shell-completions.md": "/guides/shell-completions/",
|
||||
"docs/guides/diff-view.md": "/guides/diff-view/",
|
||||
"docs/guides/repo-config.md": "/guides/repo-config/",
|
||||
"docs/guides/mcp-servers.md": "/guides/mcp-servers/",
|
||||
"docs/guides/sandbox.md": "/guides/sandbox/",
|
||||
"docs/guides/otari-telemetry.md": "/guides/otari-telemetry/",
|
||||
"docs/guides/tmux-status-bar.md": "/guides/tmux-status-bar/",
|
||||
"docs/guides/web-dashboard.md": "/guides/web-dashboard/",
|
||||
"docs/guides/web/dashboard.md": "/guides/web/dashboard/",
|
||||
"docs/guides/web/terminal.md": "/guides/web/terminal/",
|
||||
"docs/guides/web/diff.md": "/guides/web/diff/",
|
||||
"docs/guides/web/settings.md": "/guides/web/settings/",
|
||||
"docs/guides/remote-phone-access.md": "/guides/remote-phone-access/",
|
||||
"docs/guides/tailscale.md": "/guides/tailscale/",
|
||||
"docs/guides/worktrees.md": "/guides/worktrees/",
|
||||
"docs/guides/agent-override.md": "/guides/agent-override/",
|
||||
"docs/guides/session-resume.md": "/guides/session-resume/",
|
||||
"docs/guides/session-fork.md": "/guides/session-fork/",
|
||||
"docs/guides/multi-repo-workspaces.md": "/guides/multi-repo-workspaces/",
|
||||
"docs/guides/scratch-sessions.md": "/guides/scratch-sessions/",
|
||||
"docs/guides/live-mode.md": "/guides/live-mode/",
|
||||
"docs/guides/tool-sessions.md": "/guides/tool-sessions/",
|
||||
"docs/guides/podman.md": "/guides/podman/",
|
||||
"docs/guides/apple-containers.md": "/guides/apple-containers/",
|
||||
};
|
||||
|
||||
const GITHUB_BASE =
|
||||
"https://github.com/agent-of-empires/agent-of-empires/blob/main/";
|
||||
|
||||
function rewriteLinks(content, sourceDir) {
|
||||
// Rewrite markdown links to .md files: [text](target.md) or [text](target.md#anchor)
|
||||
content = content.replace(
|
||||
/\]\(([^)]+\.md(?:#[^)]*)?)\)/g,
|
||||
(_match, link) => {
|
||||
if (link.startsWith("http://") || link.startsWith("https://")) {
|
||||
return `](${link})`;
|
||||
}
|
||||
const hashIdx = link.indexOf("#");
|
||||
const targetFile = hashIdx >= 0 ? link.slice(0, hashIdx) : link;
|
||||
const anchor = hashIdx >= 0 ? link.slice(hashIdx) : "";
|
||||
const resolved = join(sourceDir, targetFile)
|
||||
.replace(/\\/g, "/")
|
||||
.replace(/^\.\//, "");
|
||||
const websiteUrl = URL_MAP[resolved];
|
||||
if (websiteUrl) {
|
||||
return `](${websiteUrl}${anchor})`;
|
||||
}
|
||||
return `](${GITHUB_BASE}${resolved}${anchor})`;
|
||||
}
|
||||
);
|
||||
|
||||
// Rewrite HTML href links to .md or .html files (e.g., <a href="installation.html">)
|
||||
content = content.replace(
|
||||
/href="([^"]+\.(?:md|html)(?:#[^"]*)?)"/g,
|
||||
(_match, link) => {
|
||||
if (link.startsWith("http://") || link.startsWith("https://")) {
|
||||
return `href="${link}"`;
|
||||
}
|
||||
const hashIdx = link.indexOf("#");
|
||||
const targetFile = hashIdx >= 0 ? link.slice(0, hashIdx) : link;
|
||||
const anchor = hashIdx >= 0 ? link.slice(hashIdx) : "";
|
||||
// Normalize .html to .md for lookup
|
||||
const targetMd = targetFile.replace(/\.html$/, ".md");
|
||||
const resolved = join(sourceDir, targetMd)
|
||||
.replace(/\\/g, "/")
|
||||
.replace(/^\.\//, "");
|
||||
const websiteUrl = URL_MAP[resolved];
|
||||
if (websiteUrl) {
|
||||
return `href="${websiteUrl}${anchor}"`;
|
||||
}
|
||||
return _match;
|
||||
}
|
||||
);
|
||||
|
||||
// Rewrite relative image/asset paths to absolute (/assets/...).
|
||||
// The build copies docs/assets/* to website/public/assets/. Both
|
||||
// `assets/foo.png` (used by root-level docs like docs/index.md) and
|
||||
// `../assets/foo.png` (used by guides at docs/guides/foo.md) map to
|
||||
// the same place, so normalize both to `/assets/`. This catches
|
||||
// markdown links, markdown images ( contains ](..)), and
|
||||
// HTML-less references alike. `(?:\.\.\/)*` handles any depth of
|
||||
// parent-directory hops so deeper-nested docs future-proof through.
|
||||
content = content.replace(/\]\((?:\.\.\/)*assets\//g, "](/assets/");
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function computeLayoutPath(dest) {
|
||||
// Layout is at website/src/layouts/Docs.astro.
|
||||
// A page at website/src/pages/guides/foo.md needs ../../layouts/Docs.astro
|
||||
// A page at website/src/pages/docs/cli/ref.md needs ../../../layouts/Docs.astro
|
||||
const segments = dirname(dest).split("/").filter((s) => s !== ".");
|
||||
const depth = segments.length + 1; // +1 to go from pages/ up to src/
|
||||
return "../".repeat(depth) + "layouts/Docs.astro";
|
||||
}
|
||||
|
||||
function escapeYaml(str) {
|
||||
if (/[:"'\\]/.test(str)) {
|
||||
return `"${str.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
console.log("Syncing docs to website...");
|
||||
|
||||
for (const page of PAGES) {
|
||||
const sourcePath = join(ROOT, page.source);
|
||||
let content = readFileSync(sourcePath, "utf8");
|
||||
|
||||
// Strip the leading # Title line (first non-empty line starting with #)
|
||||
content = content.replace(/^# .+\n\n?/, "");
|
||||
|
||||
// Rewrite links
|
||||
const sourceDir = dirname(page.source);
|
||||
content = rewriteLinks(content, sourceDir);
|
||||
|
||||
// Prepend Astro frontmatter
|
||||
const layout = computeLayoutPath(page.dest);
|
||||
const frontmatter = [
|
||||
"---",
|
||||
`layout: ${layout}`,
|
||||
`title: ${escapeYaml(page.title)}`,
|
||||
`description: ${escapeYaml(page.description)}`,
|
||||
"---",
|
||||
"",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
const destPath = join(PAGES_DIR, page.dest);
|
||||
mkdirSync(dirname(destPath), { recursive: true });
|
||||
writeFileSync(destPath, frontmatter + content);
|
||||
|
||||
console.log(` ${page.source} -> ${page.dest}`);
|
||||
}
|
||||
|
||||
// Verify every synced page appears in docsNav.ts
|
||||
const navPath = join(__dirname, "..", "src", "data", "docsNav.ts");
|
||||
const navSource = readFileSync(navPath, "utf8");
|
||||
const navHrefs = new Set([...navSource.matchAll(/href:\s*"([^"]+)"/g)].map((m) => m[1]));
|
||||
let missing = 0;
|
||||
for (const page of PAGES) {
|
||||
const url = "/" + page.dest.replace(/\.md$/, "/").replace(/\/index\/$/, "/");
|
||||
if (!navHrefs.has(url)) {
|
||||
console.error(` WARNING: ${url} (from ${page.source}) is not in docsNav.ts`);
|
||||
missing++;
|
||||
}
|
||||
}
|
||||
if (missing > 0) {
|
||||
console.error(`\n${missing} page(s) missing from sidebar navigation (website/src/data/docsNav.ts)`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Done.");
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
type?: 'tip' | 'warning' | 'info' | 'note';
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const { type = 'info', title } = Astro.props;
|
||||
|
||||
const titles: Record<string, string> = {
|
||||
tip: 'Tip',
|
||||
warning: 'Warning',
|
||||
info: 'Info',
|
||||
note: 'Note',
|
||||
};
|
||||
|
||||
const icons: Record<string, string> = {
|
||||
tip: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>',
|
||||
warning: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4.5c-.77-.833-2.694-.833-3.464 0L3.34 16.5c-.77.833.192 2.5 1.732 2.5z"/>',
|
||||
info: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>',
|
||||
note: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>',
|
||||
};
|
||||
|
||||
const displayTitle = title || titles[type];
|
||||
---
|
||||
|
||||
<div class={`callout callout-${type}`}>
|
||||
<svg class="callout-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<Fragment set:html={icons[type]} />
|
||||
</svg>
|
||||
<div class="callout-content">
|
||||
<p class="font-semibold text-sm mb-1" style={`color: inherit; opacity: 0.9;`}>{displayTitle}</p>
|
||||
<div class="text-sm" style="color: #cbd5e1;">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
import { docsNav, getFlatNavItems } from '../data/docsNav';
|
||||
|
||||
const currentPath = Astro.url.pathname;
|
||||
|
||||
function normalize(path: string): string {
|
||||
return path.replace(/\/index\.html$/, '/').replace(/\.html$/, '/').replace(/\/$/, '') || '/';
|
||||
}
|
||||
|
||||
function isActive(href: string): boolean {
|
||||
return normalize(currentPath) === normalize(href);
|
||||
}
|
||||
|
||||
const flatItems = getFlatNavItems();
|
||||
const currentItem = flatItems.find((item) => isActive(item.href));
|
||||
---
|
||||
|
||||
<!-- Desktop sidebar -->
|
||||
<aside class="docs-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<a href="/docs/" class="sidebar-logo">Documentation</a>
|
||||
</div>
|
||||
<nav>
|
||||
{docsNav.map((section) => (
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-title">{section.title}</div>
|
||||
{section.items.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
class:list={['sidebar-link', { 'sidebar-link-active': isActive(item.href) }]}
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Mobile navigation -->
|
||||
<div class="mobile-sidebar-nav">
|
||||
<button class="mobile-sidebar-toggle" onclick="toggleMobileSidebar(this)" aria-expanded="false" aria-controls="docs-mobile-menu">
|
||||
<span class="mobile-sidebar-label">{currentItem ? currentItem.title : 'Documentation'}</span>
|
||||
<svg class="mobile-sidebar-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<nav class="mobile-sidebar-menu hidden" id="docs-mobile-menu">
|
||||
{docsNav.map((section) => (
|
||||
<Fragment>
|
||||
<div class="mobile-sidebar-section-title">{section.title}</div>
|
||||
{section.items.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
class:list={['mobile-sidebar-link', { 'mobile-sidebar-link-active': isActive(item.href) }]}
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
n: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
const { title, description, n, href } = Astro.props;
|
||||
const Tag = href ? 'a' : 'div';
|
||||
---
|
||||
|
||||
<Tag
|
||||
{...(href ? { href } : {})}
|
||||
class:list={['feature-cell block p-7 h-full', href && 'group']}
|
||||
>
|
||||
<div class="flex items-center justify-between mb-3.5">
|
||||
<span class="font-mono text-xs text-brand-500">{n}</span>
|
||||
{href && (
|
||||
<svg class="w-3.5 h-3.5 text-brand-500 opacity-0 -translate-x-1 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold font-display mb-2">{title}</h3>
|
||||
<p class="text-sm text-gray-400 leading-relaxed">{description}</p>
|
||||
</Tag>
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
---
|
||||
|
||||
<footer class="pt-0 pb-8 px-6">
|
||||
<div class="footer-gradient-border mb-12"></div>
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 mb-12">
|
||||
<!-- Brand -->
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<img src="/assets/logo.svg" alt="Agent of Empires" class="w-7 h-7">
|
||||
<span class="text-white font-semibold">Agent of Empires</span>
|
||||
</div>
|
||||
<p class="text-gray-500 text-sm leading-relaxed">Terminal session manager for AI coding agents. Built with Rust, powered by tmux.</p>
|
||||
</div>
|
||||
|
||||
<!-- Product -->
|
||||
<div>
|
||||
<h4 class="text-gray-100 font-semibold text-sm uppercase tracking-wider mb-4">Product</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a href="/tui/" class="text-gray-400 hover:text-white transition-colors">TUI</a></li>
|
||||
<li><a href="/web/" class="text-gray-400 hover:text-white transition-colors">Web Dashboard</a></li>
|
||||
<li><a href="/docs/" class="text-gray-400 hover:text-white transition-colors">Documentation</a></li>
|
||||
<li><a href="/docs/installation/" class="text-gray-400 hover:text-white transition-colors">Installation</a></li>
|
||||
<li><a href="/docs/quick-start/" class="text-gray-400 hover:text-white transition-colors">Quick Start</a></li>
|
||||
<li><a href="https://github.com/agent-of-empires/agent-of-empires/releases" class="text-gray-400 hover:text-white transition-colors">Releases</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Resources -->
|
||||
<div>
|
||||
<h4 class="text-gray-100 font-semibold text-sm uppercase tracking-wider mb-4">Resources</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a href="/guides/" class="text-gray-400 hover:text-white transition-colors">Guides</a></li>
|
||||
<li><a href="https://www.youtube.com/@agent-of-empires" target="_blank" rel="noopener" class="text-gray-400 hover:text-white transition-colors">YouTube</a></li>
|
||||
<li><a href="/merch/" class="text-gray-400 hover:text-white transition-colors">Merch</a></li>
|
||||
<li><a href="/cityhall/" class="text-gray-400 hover:text-white transition-colors">CityHall <span class="text-gray-600">(experimental)</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Community -->
|
||||
<div>
|
||||
<h4 class="text-gray-100 font-semibold text-sm uppercase tracking-wider mb-4">Community</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a href="https://github.com/agent-of-empires/agent-of-empires" class="text-gray-400 hover:text-white transition-colors">GitHub</a></li>
|
||||
<li><a href="https://github.com/agent-of-empires/agent-of-empires/issues" class="text-gray-400 hover:text-white transition-colors">Issues</a></li>
|
||||
<li><a href="https://github.com/orgs/agent-of-empires/projects/1" class="text-gray-400 hover:text-white transition-colors">Roadmap</a></li>
|
||||
<li><a href="https://github.com/agent-of-empires/agent-of-empires/blob/main/LICENSE" class="text-gray-400 hover:text-white transition-colors">MIT License</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom bar -->
|
||||
<div class="border-t border-surface-800/50 pt-6 flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||
<p class="text-gray-600 text-sm">Built by the Agent of Empires community</p>
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="https://x.com/agentofempires" class="text-gray-500 hover:text-white transition-colors" aria-label="Follow on X (Twitter)">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
|
||||
</a>
|
||||
<a href="https://github.com/agent-of-empires/agent-of-empires" class="text-gray-500 hover:text-white transition-colors" aria-label="GitHub repository">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
interface NavItem {
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
prev?: NavItem;
|
||||
next?: NavItem;
|
||||
}
|
||||
|
||||
const { prev, next } = Astro.props;
|
||||
---
|
||||
|
||||
<nav class="mt-16 pt-8 border-t border-surface-700/50 grid gap-4" style={`grid-template-columns: ${prev && next ? '1fr 1fr' : '1fr'};`} aria-label="Guide navigation">
|
||||
{prev && (
|
||||
<a href={prev.href} class="group feature-card rounded-xl p-5 flex items-center gap-3 no-underline" style={!next ? 'max-width: 50%;' : ''}>
|
||||
<svg class="w-5 h-5 text-gray-500 group-hover:text-brand-400 transition-colors flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500 uppercase tracking-wider">Previous</span>
|
||||
<p class="text-sm font-medium text-gray-100 group-hover:text-white transition-colors mt-0.5">{prev.label}</p>
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
{next && (
|
||||
<a href={next.href} class={`group feature-card rounded-xl p-5 flex items-center justify-end gap-3 text-right no-underline ${!prev ? 'ml-auto' : ''}`} style={!prev ? 'max-width: 50%;' : ''}>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500 uppercase tracking-wider">Next</span>
|
||||
<p class="text-sm font-medium text-gray-100 group-hover:text-white transition-colors mt-0.5">{next.label}</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-500 group-hover:text-brand-400 transition-colors flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</a>
|
||||
)}
|
||||
</nav>
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
// Compact install widget: toggle between Homebrew and the install script, with a
|
||||
// copy button for whichever command is active. Reuses copyCommand() from main.js.
|
||||
interface Props {
|
||||
class?: string;
|
||||
}
|
||||
const { class: className = '' } = Astro.props;
|
||||
|
||||
const brew = 'brew install aoe';
|
||||
const curl =
|
||||
'curl -fsSL https://raw.githubusercontent.com/agent-of-empires/agent-of-empires/main/scripts/install.sh | bash';
|
||||
---
|
||||
|
||||
<div
|
||||
class:list={['install-group flex flex-col items-start gap-2 w-full max-w-md', className]}
|
||||
data-brew={brew}
|
||||
data-curl={curl}
|
||||
data-active="brew"
|
||||
>
|
||||
<div class="demo-toggle inline-flex gap-0.5 rounded-lg p-0.5 font-mono text-xs w-fit" role="group" aria-label="Install method">
|
||||
<button class="demo-tab demo-tab-active rounded-md px-3 py-1" data-install="brew" aria-pressed="true" onclick="switchInstall(this, 'brew')">Homebrew</button>
|
||||
<button class="demo-tab rounded-md px-3 py-1" data-install="curl" aria-pressed="false" onclick="switchInstall(this, 'curl')">Install script</button>
|
||||
</div>
|
||||
<div class="install-inline flex items-start gap-2 rounded-xl px-4 py-3 font-mono text-sm w-full">
|
||||
<code class="flex-1 min-w-0 break-all leading-relaxed text-gray-100">
|
||||
<span data-install-view="brew"><span class="text-gray-500 select-none">$ </span><span class="text-brand-400">brew</span> install aoe</span><span data-install-view="curl" class="hidden"><span class="text-gray-500 select-none">$ </span><span class="text-brand-400">curl</span> -fsSL https://raw.githubusercontent.com/agent-of-empires/agent-of-empires/main/scripts/install.sh <span class="text-gray-500">|</span> bash</span>
|
||||
</code>
|
||||
<button
|
||||
onclick="copyInstall(this)"
|
||||
class="install-copy-btn text-gray-500 hover:text-brand-400 transition-colors flex-shrink-0 pl-3 ml-1 border-l border-surface-700"
|
||||
title="Copy to clipboard"
|
||||
aria-label="Copy install command"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
---
|
||||
|
||||
<nav class="fixed top-0 left-0 right-0 z-50 bg-surface-950/80 backdrop-blur-xl border-b border-surface-800/50">
|
||||
<div class="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||
<a href="/" class="flex items-center gap-3 group">
|
||||
<img src="/assets/logo.svg" alt="Agent of Empires" width="32" height="32" fetchpriority="high" class="w-8 h-8 transition-transform group-hover:scale-110">
|
||||
<span class="font-semibold text-lg font-display">aoe</span>
|
||||
</a>
|
||||
|
||||
<!-- Desktop nav -->
|
||||
<div class="hidden lg:flex items-center gap-5">
|
||||
<a href="/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">Home</a>
|
||||
<a href="/tui/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">TUI</a>
|
||||
<a href="/web/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">Web</a>
|
||||
<a href="/cityhall/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">CityHall</a>
|
||||
<a href="/docs/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">Docs</a>
|
||||
<a href="/guides/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium py-3 px-2">Guides</a>
|
||||
<a href="https://github.com/agent-of-empires/agent-of-empires" class="text-gray-200 hover:text-white transition-colors flex items-center py-3 px-2" aria-label="GitHub" title="GitHub">
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
</a>
|
||||
<button id="theme-toggle" class="text-gray-200 hover:text-white transition-colors p-2" aria-label="Toggle theme">
|
||||
<svg class="theme-icon-sun w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
<svg class="theme-icon-moon w-5 h-5 hidden" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Mobile right-side controls -->
|
||||
<div class="flex lg:hidden items-center gap-1">
|
||||
<button id="theme-toggle-mobile" class="text-gray-200 hover:text-white transition-colors p-2" aria-label="Toggle theme">
|
||||
<svg class="theme-icon-sun w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
<svg class="theme-icon-moon w-5 h-5 hidden" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button id="mobile-menu-btn" class="text-gray-200 hover:text-white transition-colors p-2" aria-label="Toggle menu" aria-expanded="false">
|
||||
<svg id="menu-icon-open" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||
</svg>
|
||||
<svg id="menu-icon-close" class="w-6 h-6 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile dropdown menu -->
|
||||
<div id="mobile-menu" class="hidden lg:hidden border-t border-surface-800/50 bg-surface-950/95 backdrop-blur-xl">
|
||||
<div class="max-w-6xl mx-auto px-6 py-4 flex flex-col gap-4">
|
||||
<a href="/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">Home</a>
|
||||
<a href="/tui/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">TUI</a>
|
||||
<a href="/web/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">Web</a>
|
||||
<a href="/cityhall/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">CityHall</a>
|
||||
<a href="/docs/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">Docs</a>
|
||||
<a href="/guides/" class="text-gray-200 hover:text-white transition-colors text-sm font-medium">Guides</a>
|
||||
<a href="https://github.com/agent-of-empires/agent-of-empires" class="text-gray-200 hover:text-white transition-colors flex items-center gap-2 text-sm font-medium">
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
const btn = document.getElementById('mobile-menu-btn');
|
||||
const menu = document.getElementById('mobile-menu');
|
||||
const iconOpen = document.getElementById('menu-icon-open');
|
||||
const iconClose = document.getElementById('menu-icon-close');
|
||||
|
||||
btn?.addEventListener('click', () => {
|
||||
const isOpen = !menu?.classList.contains('hidden');
|
||||
menu?.classList.toggle('hidden');
|
||||
iconOpen?.classList.toggle('hidden');
|
||||
iconClose?.classList.toggle('hidden');
|
||||
btn.setAttribute('aria-expanded', String(!isOpen));
|
||||
});
|
||||
</script>
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
number: number;
|
||||
title: string;
|
||||
showLine?: boolean;
|
||||
}
|
||||
|
||||
const { number, title, showLine = true } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="flex gap-8 items-start animate-on-scroll">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-12 h-12 bg-brand-600 rounded-full flex items-center justify-center flex-shrink-0 font-bold text-lg">{number}</div>
|
||||
{showLine && <div class="w-0.5 h-16 step-line mt-4"></div>}
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
<h3 class="text-xl font-semibold mb-3">{title}</h3>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
// Embedded YouTube channel playlist plus channel/subscribe footer.
|
||||
// Shared by the homepage, the docs index, and the guides index so the markup
|
||||
// lives in one place. Pass `class` to size/space the wrapper at each call site.
|
||||
interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = '' } = Astro.props;
|
||||
---
|
||||
|
||||
<div class:list={['rounded-2xl overflow-hidden bg-surface-800 border border-surface-700/50', className]}>
|
||||
<iframe
|
||||
width="100%"
|
||||
style="aspect-ratio:16/9;display:block"
|
||||
src="https://www.youtube-nocookie.com/embed/videoseries?list=UUjGgsnOCZXvvk6UwUQAuwPg"
|
||||
title="Agent of Empires YouTube Channel"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
<div class="flex items-center gap-4 p-4">
|
||||
<a href="https://www.youtube.com/@agent-of-empires" target="_blank" rel="noopener" class="flex items-center gap-3 flex-1 min-w-0 group">
|
||||
<img src="/assets/logo-youtube.png" alt="Agent of Empires" class="w-10 h-10 rounded-full shrink-0" width="40" height="40">
|
||||
<div class="min-w-0">
|
||||
<span class="text-white font-semibold group-hover:text-brand-400 transition-colors">Agent of Empires</span>
|
||||
<p class="text-gray-500 text-sm">Tutorials, walkthroughs, and tips</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@agent-of-empires?sub_confirmation=1" target="_blank" rel="noopener" class="shrink-0 inline-flex items-center gap-2 px-4 py-2 rounded-full bg-red-600 hover:bg-red-500 text-white text-sm font-semibold transition-colors">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
||||
Subscribe
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,127 +0,0 @@
|
||||
export interface NavItem {
|
||||
title: string;
|
||||
href: string;
|
||||
/** Short blurb shown on the guides landing page. Unused by the sidebar. */
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface NavSection {
|
||||
title: string;
|
||||
items: NavItem[];
|
||||
}
|
||||
|
||||
export const docsNav: NavSection[] = [
|
||||
{
|
||||
title: "Getting Started",
|
||||
items: [
|
||||
{ title: "Introduction", href: "/docs/" },
|
||||
{ title: "Features", href: "/docs/features/" },
|
||||
{ title: "Installation", href: "/docs/installation/" },
|
||||
{ title: "Quick Start", href: "/docs/quick-start/" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Guides",
|
||||
items: [
|
||||
{ title: "Docker Sandbox", href: "/guides/sandbox/", description: "Run AI coding agents in isolated Docker containers." },
|
||||
{ title: "Claude Code Telemetry to Otari", href: "/guides/otari-telemetry/", description: "Export Claude Code usage from host and sandbox sessions to Otari." },
|
||||
{ title: "Podman", href: "/guides/podman/", description: "Use Podman as a rootless alternative to Docker for sandboxing." },
|
||||
{ title: "Apple Containers", href: "/guides/apple-containers/", description: "Sandbox agents with Apple's native container framework on macOS." },
|
||||
{ title: "Live Mode", href: "/guides/live-mode/", description: "Watch a session stream live and type into it from the TUI." },
|
||||
{ title: "Repo Config & Hooks", href: "/guides/repo-config/", description: "Per-repo configuration and lifecycle hooks for sessions." },
|
||||
{ title: "Git Worktrees", href: "/guides/worktrees/", description: "How AoE creates and cleans up a git worktree per session." },
|
||||
{ title: "Multi-Repo Workspaces", href: "/guides/multi-repo-workspaces/", description: "Drive one session across several git repositories at once." },
|
||||
{ title: "Scratch Sessions", href: "/guides/scratch-sessions/", description: "Throwaway sessions for quick experiments without a worktree." },
|
||||
{ title: "Diff View", href: "/guides/diff-view/", description: "Review git changes and edit files from the TUI." },
|
||||
{ title: "tmux Status Bar", href: "/guides/tmux-status-bar/", description: "Show live session status in your tmux status bar." },
|
||||
{ title: "Agent Command Overrides", href: "/guides/agent-override/", description: "Customize the command used to launch each agent." },
|
||||
{ title: "Tool Sessions", href: "/guides/tool-sessions/", description: "Run plain shell or tool sessions alongside your agents." },
|
||||
{ title: "MCP Servers", href: "/guides/mcp-servers/", description: "Forward configured MCP servers to structured-view agents." },
|
||||
{ title: "Session Resume (Claude)", href: "/guides/session-resume/", description: "Resume a previous Claude Code conversation in a session." },
|
||||
{ title: "Forking Sessions", href: "/guides/session-fork/", description: "Branch a session's conversation into a new, independent session." },
|
||||
{ title: "Shell Completions", href: "/guides/shell-completions/", description: "Install and refresh tab-completion for the aoe CLI." },
|
||||
{ title: "Sound Effects", href: "/docs/sounds/", description: "Play sounds when agents need input or finish work." },
|
||||
{ title: "Push Notifications", href: "/docs/push-notifications/", description: "Get notified when a session needs your attention." },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Web Dashboard",
|
||||
items: [
|
||||
{ title: "Overview", href: "/guides/web-dashboard/", description: "Remote access to your sessions from any browser." },
|
||||
{ title: "Dashboard & Workspaces", href: "/guides/web/dashboard/", description: "The dashboard layout: workspace sidebar, status glyphs, and the session wizard." },
|
||||
{ title: "Terminal View", href: "/guides/web/terminal/", description: "A real terminal in the browser, backed by your tmux session." },
|
||||
{ title: "Diff View", href: "/guides/web/diff/", description: "Review and stage git changes from the web dashboard." },
|
||||
{ title: "Settings & Profiles", href: "/guides/web/settings/", description: "Manage settings and configuration profiles from the web." },
|
||||
{ title: "Remote Phone Access", href: "/guides/remote-phone-access/", description: "Expose the dashboard over HTTPS with QR pairing." },
|
||||
{ title: "Tailscale Setup", href: "/guides/tailscale/", description: "Set up Tailscale from scratch for remote access to your AOE sessions." },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Structured View",
|
||||
items: [
|
||||
{ title: "Overview", href: "/docs/structured-view/" },
|
||||
{ title: "Interface", href: "/docs/structured-view/interface/" },
|
||||
{ title: "Modes, Approvals & Models", href: "/docs/structured-view/controls/" },
|
||||
{ title: "Troubleshooting", href: "/docs/structured-view/troubleshooting/" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Reference",
|
||||
items: [
|
||||
{ title: "CLI Reference", href: "/docs/cli/reference/" },
|
||||
{ title: "HTTP API Reference", href: "/docs/api/" },
|
||||
{ title: "Telemetry", href: "/docs/telemetry/" },
|
||||
{ title: "GitHub Integration", href: "/docs/github-integration/" },
|
||||
{ title: "Configuration", href: "/docs/guides/configuration/" },
|
||||
{ title: "Plugins", href: "/docs/plugins/" },
|
||||
{ title: "Plugin API Reference", href: "/docs/plugin-api/" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Contributing",
|
||||
items: [
|
||||
{ title: "Development", href: "/docs/development/" },
|
||||
{ title: "Adding a New Agent", href: "/docs/development/adding-agents/" },
|
||||
{ title: "Adding a Setting", href: "/docs/development/adding-settings/" },
|
||||
{ title: "Logging", href: "/docs/development/logging/" },
|
||||
{ title: "Playwright + Vitest testing", href: "/docs/development/playwright/" },
|
||||
{ title: "Releases", href: "/docs/development/releases/" },
|
||||
{
|
||||
title: "Web Dashboard Development",
|
||||
href: "/docs/development/web-dashboard/",
|
||||
},
|
||||
{ title: "Writing Plugins", href: "/docs/development/writing-plugins/" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Internals (Contributor)",
|
||||
items: [
|
||||
{ title: "Structured View Internals", href: "/docs/development/internals/structured-view/" },
|
||||
{ title: "Sandbox Internals", href: "/docs/development/internals/sandbox/" },
|
||||
{ title: "Session & Worktree Internals", href: "/docs/development/internals/sessions/" },
|
||||
{ title: "Plugin System Internals", href: "/docs/development/internals/plugin-system/" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export function getFlatNavItems(): NavItem[] {
|
||||
return docsNav.flatMap((section) => section.items);
|
||||
}
|
||||
|
||||
/** Section titles featured on the /guides/ landing page, in display order. */
|
||||
const GUIDE_SECTION_TITLES = ["Guides", "Web Dashboard"];
|
||||
|
||||
/**
|
||||
* Sections to feature on the guides landing page. Derived from `docsNav` so the
|
||||
* landing page and the docs sidebar can never drift apart: add a guide once,
|
||||
* here, and it shows up in both places.
|
||||
*/
|
||||
export function getGuideSections(): NavSection[] {
|
||||
return GUIDE_SECTION_TITLES.map((title) => {
|
||||
const section = docsNav.find((s) => s.title === title);
|
||||
if (!section) {
|
||||
throw new Error(`getGuideSections: no docsNav section titled "${title}"`);
|
||||
}
|
||||
return section;
|
||||
});
|
||||
}
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
ogTitle?: string;
|
||||
ogDescription?: string;
|
||||
ogImage?: string;
|
||||
}
|
||||
|
||||
const siteUrl = Astro.site?.toString().replace(/\/$/, '') ?? '';
|
||||
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
ogTitle = 'Agent of Empires',
|
||||
ogDescription = 'Terminal session manager for AI coding agents. Git worktrees, Docker sandboxing, beautiful TUI.',
|
||||
ogImage = `${siteUrl}/assets/social-preview.png`
|
||||
} = Astro.props;
|
||||
|
||||
import '../styles/global.css';
|
||||
|
||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||
|
||||
const structuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareApplication",
|
||||
"name": "Agent of Empires",
|
||||
"description": "A terminal session manager for Linux and macOS using tmux to manage and monitor AI coding agents. Features git worktrees, Docker sandboxing, and a beautiful TUI.",
|
||||
"url": siteUrl,
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "Linux, macOS",
|
||||
"programmingLanguage": "Rust",
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "USD"
|
||||
},
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "Agent of Empires",
|
||||
"url": "https://agent-of-empires.com"
|
||||
},
|
||||
"license": "https://github.com/agent-of-empires/agent-of-empires/blob/main/LICENSE",
|
||||
"codeRepository": "https://github.com/agent-of-empires/agent-of-empires",
|
||||
"keywords": ["AI coding agent", "terminal session manager", "tmux", "Claude Code", "Codex", "OpenCode", "Mistral Vibe", "Gemini CLI", "git worktrees", "Docker sandbox"]
|
||||
};
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark" style="color-scheme: dark">
|
||||
<head>
|
||||
<script is:inline>
|
||||
(function() {
|
||||
var stored = localStorage.getItem('theme');
|
||||
var theme = (stored === 'dark' || stored === 'light')
|
||||
? stored
|
||||
: (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
})();
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description}>
|
||||
<meta name="keywords" content="AI coding agent, terminal session manager, tmux, Claude Code, Codex, OpenCode, Mistral Vibe, Gemini CLI, git worktrees, Docker sandbox, Rust, TUI, CLI, developer tools">
|
||||
<meta name="author" content="Agent of Empires community">
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="canonical" href={canonicalURL}>
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content={ogTitle}>
|
||||
<meta property="og:description" content={ogDescription}>
|
||||
<meta property="og:image" content={ogImage}>
|
||||
<meta property="og:url" content={canonicalURL}>
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Agent of Empires">
|
||||
<meta property="og:locale" content="en_US">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@agentofempires">
|
||||
<meta name="twitter:creator" content="@agentofempires">
|
||||
<meta name="twitter:title" content={ogTitle}>
|
||||
<meta name="twitter:description" content={ogDescription}>
|
||||
<meta name="twitter:image" content={ogImage}>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
|
||||
<link rel="icon" type="image/png" href="/assets/logo.png">
|
||||
|
||||
<!-- Preload the nav logo so it never flashes its alt text on a cold cache -->
|
||||
<link rel="preload" as="image" href="/assets/logo.svg" fetchpriority="high">
|
||||
|
||||
<!-- Structured Data -->
|
||||
<script type="application/ld+json" set:html={JSON.stringify(structuredData)} />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="preconnect" href="https://api.fontshare.com" crossorigin>
|
||||
<link rel="preload" href="https://api.fontshare.com/v2/css?f[]=satoshi@400,500,600,700,900&display=swap" as="style">
|
||||
<link href="https://api.fontshare.com/v2/css?f[]=satoshi@400,500,600,700,900&display=swap" rel="stylesheet">
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" as="style">
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/styles.css">
|
||||
</head>
|
||||
<body class="gradient-bg min-h-screen text-gray-100 antialiased">
|
||||
<slot />
|
||||
<script is:inline src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
import Base from './Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import DocsSidebar from '../components/DocsSidebar.astro';
|
||||
import GuideNav from '../components/GuideNav.astro';
|
||||
import { docsNav, getFlatNavItems } from '../data/docsNav';
|
||||
|
||||
interface Props {
|
||||
frontmatter: {
|
||||
title: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const { frontmatter } = Astro.props;
|
||||
const currentPath = Astro.url.pathname;
|
||||
|
||||
function normalize(path: string): string {
|
||||
return path.replace(/\/index\.html$/, '/').replace(/\.html$/, '/').replace(/\/$/, '') || '/';
|
||||
}
|
||||
|
||||
// Compute prev/next
|
||||
const flatItems = getFlatNavItems();
|
||||
const currentIndex = flatItems.findIndex((item) => normalize(currentPath) === normalize(item.href));
|
||||
|
||||
const prev = currentIndex > 0 ? flatItems[currentIndex - 1] : undefined;
|
||||
const next = currentIndex < flatItems.length - 1 ? flatItems[currentIndex + 1] : undefined;
|
||||
---
|
||||
|
||||
<Base
|
||||
title={`${frontmatter.title} - Agent of Empires`}
|
||||
description={frontmatter.description || `${frontmatter.title} - Agent of Empires documentation`}
|
||||
>
|
||||
<Nav />
|
||||
<div class="docs-layout">
|
||||
<DocsSidebar />
|
||||
<main class="docs-content">
|
||||
<h1 class="text-3xl font-bold text-white mb-8 text-gradient font-display">
|
||||
{frontmatter.title}
|
||||
</h1>
|
||||
<div class="prose-content">
|
||||
<slot />
|
||||
</div>
|
||||
<GuideNav
|
||||
prev={prev ? { label: prev.title, href: prev.href } : undefined}
|
||||
next={next ? { label: next.title, href: next.href } : undefined}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,89 +0,0 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import FeatureCard from '../components/FeatureCard.astro';
|
||||
|
||||
const repo = 'https://github.com/agent-of-empires/cityhall';
|
||||
const docs = 'https://cityhall.agent-of-empires.com/docs/';
|
||||
|
||||
const features = [
|
||||
{ n: '01', title: 'User management', description: 'Accounts, authentication, email invites, password reset, and a forced password change on first login.' },
|
||||
{ n: '02', title: 'Role-based access', description: 'Roles built from permission keys, so each teammate gets exactly the access they need and nothing more.' },
|
||||
{ n: '03', title: 'Single sign-on', description: 'Log in through any OpenID Connect provider your organization already runs.' },
|
||||
{ n: '04', title: 'Email / SMTP', description: 'Transactional email for invites and verification, wired through your own SMTP server.' },
|
||||
{ n: '05', title: 'Optional self-signup', description: 'Open registration with email verification when you want hands-off onboarding for a team.' },
|
||||
{ n: '06', title: 'One Rust binary', description: 'API, web frontend, and CLI ship as a single binary. Bring any SeaORM database: SQLite, Postgres, or MySQL.' },
|
||||
];
|
||||
---
|
||||
|
||||
<Base
|
||||
title="CityHall (Experimental) - Agent of Empires"
|
||||
description="CityHall is the self-hostable control-plane server for Agent of Empires: run and coordinate aoe across many machines for a whole team, with accounts, roles, SSO, and invites."
|
||||
>
|
||||
<Nav />
|
||||
|
||||
<main>
|
||||
<!-- Hero -->
|
||||
<section class="pt-28 pb-10 px-6 hero-glow">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="experimental-badge inline-flex items-center gap-2 rounded-full px-3 py-1 font-mono text-[11px] uppercase tracking-widest mb-6">
|
||||
Experimental · Labs · v0.1.0
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-semibold tracking-hero font-display leading-[1.05] text-white max-w-3xl mb-6">
|
||||
Run Agent of Empires for a whole team.
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-300 max-w-2xl leading-relaxed mb-8">
|
||||
CityHall is a self-hostable control-plane server for Agent of Empires. Instead of everyone running
|
||||
an isolated local instance, a team runs and coordinates aoe across many machines from one shared
|
||||
backend, with accounts, roles, single sign-on, and invites.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-3.5 items-center mb-6">
|
||||
<a href={repo} target="_blank" rel="noopener" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
View on GitHub
|
||||
</a>
|
||||
<a href={docs} target="_blank" rel="noopener" class="btn-secondary text-base inline-flex items-center gap-2">Read the docs</a>
|
||||
<a href="/" class="btn-secondary text-base inline-flex items-center gap-2">Back to aoe</a>
|
||||
</div>
|
||||
<p class="font-mono text-xs text-gray-500 max-w-xl">
|
||||
Early and evolving. Expect rough edges, breaking changes, and gaps in the docs. Feedback and
|
||||
contributions welcome.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Feature grid -->
|
||||
<section class="py-16 px-6">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">The control plane</span>
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mt-3">One shared backend for the team</h2>
|
||||
</div>
|
||||
<div class="feature-grid grid md:grid-cols-2 lg:grid-cols-3 gap-px rounded-2xl overflow-hidden animate-on-scroll">
|
||||
{features.map((f) => (
|
||||
<FeatureCard n={f.n} title={f.title} description={f.description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="cta-band py-20 px-6 text-center animate-on-scroll">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mb-4">Kick the tires</h2>
|
||||
<p class="text-gray-400 mb-8">Read the setup guide and the source on GitHub. Open source, MIT licensed.</p>
|
||||
<div class="flex gap-3.5 justify-center flex-wrap items-center">
|
||||
<a href={repo} target="_blank" rel="noopener" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
View on GitHub
|
||||
</a>
|
||||
<a href={docs} target="_blank" rel="noopener" class="btn-secondary text-base inline-flex items-center gap-2">Read the docs</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
import Base from '../../layouts/Base.astro';
|
||||
import Nav from '../../components/Nav.astro';
|
||||
import Footer from '../../components/Footer.astro';
|
||||
import YouTubeChannel from '../../components/YouTubeChannel.astro';
|
||||
import { getGuideSections } from '../../data/docsNav';
|
||||
|
||||
const sections = getGuideSections();
|
||||
---
|
||||
|
||||
<Base
|
||||
title="Guides - Agent of Empires"
|
||||
description="Step-by-step guides for Agent of Empires: sandboxing, git worktrees, the web dashboard, and more."
|
||||
>
|
||||
<Nav />
|
||||
<main class="max-w-6xl mx-auto px-6 pt-32 pb-24">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">Guides</span>
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-white mb-6 mt-3 font-display">Guides</h1>
|
||||
<p class="text-lg text-gray-100 leading-relaxed mb-16 max-w-2xl">
|
||||
Practical, task-focused walkthroughs for getting the most out of aoe. Start anywhere, or
|
||||
head to the <a href="/docs/quick-start/" class="text-brand-500 hover:text-brand-400 transition-colors">Quick Start</a>
|
||||
if you're brand new.
|
||||
</p>
|
||||
|
||||
{sections.map((section) => (
|
||||
<section class="mb-16">
|
||||
<h2 class="text-2xl font-semibold text-white mb-6 font-display">{section.title}</h2>
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{section.items.map((guide) => (
|
||||
<a href={guide.href} class="feature-card rounded-xl p-5 group">
|
||||
<span class="text-white font-medium group-hover:text-brand-400 transition-colors">{guide.title}</span>
|
||||
{guide.description && (
|
||||
<p class="text-gray-400 text-sm mt-1.5 leading-relaxed">{guide.description}</p>
|
||||
)}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
|
||||
<section class="mb-12">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">Learn</span>
|
||||
<h2 class="text-2xl font-semibold text-white mb-4 mt-3 font-display">Video tutorials</h2>
|
||||
<p class="text-gray-400 leading-relaxed mb-6 max-w-xl">
|
||||
Prefer watching? Our YouTube channel has walkthroughs, setup guides, and tips.
|
||||
</p>
|
||||
<YouTubeChannel class="max-w-2xl" />
|
||||
</section>
|
||||
|
||||
<p class="text-gray-400 leading-relaxed">
|
||||
Have a guide you'd like to see? <a href="https://github.com/agent-of-empires/agent-of-empires/issues" target="_blank" rel="noopener" class="text-brand-500 hover:text-brand-400 transition-colors">Open a GitHub issue</a> and let us know.
|
||||
</p>
|
||||
</main>
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,224 +0,0 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import FeatureCard from '../components/FeatureCard.astro';
|
||||
import InstallInline from '../components/InstallInline.astro';
|
||||
import YouTubeChannel from '../components/YouTubeChannel.astro';
|
||||
|
||||
// Neither the TUI nor the web dashboard is primary: they are two front-ends onto
|
||||
// the same live sessions. TUI (01) and Web Dashboard (04) link to their own pages.
|
||||
const compactFeatures = [
|
||||
{
|
||||
n: '01',
|
||||
title: 'TUI Dashboard',
|
||||
description: 'Visual interface to manage all your AI coding sessions. See status at a glance, navigate with keyboard shortcuts.',
|
||||
href: '/tui/',
|
||||
},
|
||||
{
|
||||
n: '02',
|
||||
title: 'Git Worktrees',
|
||||
description: 'Run parallel agents on different branches of the same repo. Automatic worktree creation and cleanup.',
|
||||
},
|
||||
{
|
||||
n: '03',
|
||||
title: 'Docker Sandbox',
|
||||
description: 'Run agents in isolated containers for safety. Configurable volume mounts, persistent auth, and automatic lifecycle management.',
|
||||
},
|
||||
{
|
||||
n: '04',
|
||||
title: 'Web Dashboard',
|
||||
description: 'Drive the same sessions from any browser. Real terminal in the page, PWA install on desktop and mobile.',
|
||||
href: '/web/',
|
||||
},
|
||||
{
|
||||
n: '05',
|
||||
title: 'Structured View',
|
||||
description: 'Mobile-first native rendering of agent state via the Agent Client Protocol. Plan panels, tool-call cards, swipe-to-approve.',
|
||||
},
|
||||
{
|
||||
n: '06',
|
||||
title: 'Remote Phone Access',
|
||||
description: 'Press R to expose the dashboard over HTTPS with QR pairing. Tailscale Funnel or Cloudflare Tunnel.',
|
||||
},
|
||||
{
|
||||
n: '07',
|
||||
title: 'Multi-Repo Workspaces',
|
||||
description: 'Drive one session across several git repositories with project registry and multi-select pickers.',
|
||||
},
|
||||
{
|
||||
n: '08',
|
||||
title: 'Status Detection',
|
||||
description: 'Know when agents are working, waiting for input, or idle without switching sessions.',
|
||||
},
|
||||
{
|
||||
n: '09',
|
||||
title: 'tmux Persistence',
|
||||
description: 'Sessions persist in tmux. Close aoe anytime and your agents keep running.',
|
||||
},
|
||||
];
|
||||
|
||||
const agents = ['Claude Code', 'Codex', 'OpenCode', 'Gemini CLI', 'Mistral Vibe'];
|
||||
---
|
||||
|
||||
<Base
|
||||
title="Agent of Empires - Terminal & Web Session Manager for AI Coding Agents"
|
||||
description="Run Claude Code, Codex, OpenCode, and Gemini CLI in parallel and manage every session from one place. Git worktrees, Docker sandboxing, and one control surface you drive from a keyboard-driven TUI or a web dashboard. Written in Rust."
|
||||
>
|
||||
<Nav />
|
||||
|
||||
<main>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-28 pb-10 px-6 hero-glow hero-gradient-animated">
|
||||
<div class="max-w-6xl mx-auto grid lg:grid-cols-2 gap-14 items-center">
|
||||
<!-- Left: copy -->
|
||||
<div>
|
||||
<div class="eyebrow-pill inline-flex items-center gap-2 rounded-full px-3 py-1.5 font-mono text-xs uppercase tracking-widest mb-6">
|
||||
Built in Rust · powered by tmux
|
||||
</div>
|
||||
<h1 class="text-5xl md:text-6xl lg:text-7xl font-semibold tracking-hero font-display leading-[1.02] text-white max-w-2xl mb-6">
|
||||
Run your AI coding agents in parallel, and manage them from one place.
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-300 leading-relaxed max-w-xl mb-9">
|
||||
Launch your favorite coding agents, each in its own session. Git worktrees for parallel
|
||||
branches, Docker sandboxing for safety, and a keyboard-driven TUI and web dashboard that
|
||||
keep every agent's status in view, at your desk or on your phone.
|
||||
</p>
|
||||
<InstallInline class="mb-5" />
|
||||
<div class="flex flex-wrap gap-3.5 items-center">
|
||||
<a href="/docs/quick-start/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Get started
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: demo surface (TUI / Web), neither presented as primary -->
|
||||
<div>
|
||||
<div class="demo-toggle inline-flex gap-1 rounded-xl p-1 font-mono text-sm w-fit mb-4" role="group" aria-label="Demo surface">
|
||||
<button class="demo-tab demo-tab-active rounded-lg px-5 py-2 font-medium" data-demo="tui" aria-pressed="true" onclick="switchDemo('tui')">TUI</button>
|
||||
<button class="demo-tab rounded-lg px-5 py-2 font-medium" data-demo="web" aria-pressed="false" onclick="switchDemo('web')">Web Dashboard</button>
|
||||
</div>
|
||||
<div class="terminal-window rounded-2xl overflow-hidden shadow-2xl">
|
||||
<div class="flex items-center gap-2 px-4 py-3 bg-surface-850 border-b border-surface-700/50">
|
||||
<span class="w-3 h-3 rounded-full bg-red-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-yellow-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-green-500"></span>
|
||||
<span id="demo-chrome-label" class="ml-2 font-mono text-xs text-gray-400">aoe · session manager</span>
|
||||
</div>
|
||||
<img
|
||||
id="demo-img"
|
||||
src="/assets/demo.gif"
|
||||
alt="Agent of Empires TUI showing session management with Claude Code, git worktree creation, and Docker container status indicators"
|
||||
class="block w-full"
|
||||
width="960"
|
||||
height="576"
|
||||
fetchpriority="high"
|
||||
>
|
||||
</div>
|
||||
<p class="mt-4 font-mono text-xs text-gray-500">
|
||||
Same live sessions, two front-ends:
|
||||
<a href="/tui/" class="text-brand-400 hover:text-brand-300">the TUI</a>
|
||||
and
|
||||
<a href="/web/" class="text-brand-400 hover:text-brand-300">the web dashboard</a>.
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-gray-400">
|
||||
<a href="https://www.youtube.com/watch?v=Kk8dX_F-P4E" target="_blank" rel="noopener" class="text-brand-400 hover:text-brand-300 underline">Watch the getting started video</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Works with -->
|
||||
<section class="px-6 animate-on-scroll">
|
||||
<div class="max-w-6xl mx-auto works-strip flex flex-wrap items-center gap-x-7 gap-y-2 py-5">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-gray-600">Works with</span>
|
||||
{agents.map((a) => (
|
||||
<span class="font-mono text-sm text-gray-400">{a}</span>
|
||||
))}
|
||||
<span class="font-mono text-sm text-gray-600 italic">and more</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Feature grid -->
|
||||
<section class="py-16 px-6">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">Features</span>
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mt-3">Everything runs in one place</h2>
|
||||
</div>
|
||||
<div class="feature-grid grid md:grid-cols-2 lg:grid-cols-3 gap-px rounded-2xl overflow-hidden animate-on-scroll">
|
||||
{compactFeatures.map((feature) => (
|
||||
<FeatureCard n={feature.n} title={feature.title} description={feature.description} href={feature.href} />
|
||||
))}
|
||||
</div>
|
||||
<div class="mt-8 flex justify-center">
|
||||
<a href="/docs/features/" class="btn-secondary text-base inline-flex items-center gap-2 group">
|
||||
See all features
|
||||
<svg class="w-4 h-4 group-hover:translate-x-0.5 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Learn / YouTube -->
|
||||
<section class="py-12 px-6 animate-on-scroll">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">Learn</span>
|
||||
<h2 class="text-3xl md:text-4xl font-semibold mt-3 mb-4 font-display">Tutorials & help videos</h2>
|
||||
<p class="text-gray-300 text-lg leading-relaxed mb-8 max-w-xl">Watch walkthroughs, setup guides, and tips for getting the most out of aoe on our YouTube channel.</p>
|
||||
</div>
|
||||
<YouTubeChannel class="max-w-3xl" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CityHall (experimental) -->
|
||||
<section class="py-12 px-6 animate-on-scroll">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="feature-card rounded-2xl p-8 md:p-10 flex flex-col md:flex-row md:items-center gap-6 justify-between">
|
||||
<div class="max-w-2xl">
|
||||
<span class="experimental-badge inline-flex items-center gap-2 rounded-full px-3 py-1 font-mono text-[11px] uppercase tracking-widest mb-4">Experimental · Labs</span>
|
||||
<h2 class="text-2xl md:text-3xl font-semibold font-display mb-3">CityHall: run aoe for a whole team</h2>
|
||||
<p class="text-gray-400 leading-relaxed">A self-hostable control-plane server that coordinates Agent of Empires across many machines from one shared backend: user accounts, roles, SSO, and email invites. Early and evolving, out in the open.</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row md:flex-col gap-3 shrink-0">
|
||||
<a href="/cityhall/" class="btn-primary text-base inline-flex items-center justify-center gap-2">
|
||||
Learn more
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://github.com/agent-of-empires/cityhall" target="_blank" rel="noopener" class="btn-secondary text-base inline-flex items-center justify-center gap-2">
|
||||
View on GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Closing CTA -->
|
||||
<section class="cta-band py-20 px-6 text-center animate-on-scroll">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mb-4">Take command of your agents</h2>
|
||||
<p class="text-gray-400 mb-8">Free and open source. MIT licensed.</p>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<InstallInline />
|
||||
<a href="/docs/quick-start/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Get started
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
|
||||
const STORE_URL = 'https://brake.printful.me/';
|
||||
---
|
||||
|
||||
<Base
|
||||
title="Merch — Agent of Empires"
|
||||
description="Agent of Empires merch store. Fulfilled by Printful, ships worldwide."
|
||||
ogTitle="Agent of Empires Merch"
|
||||
ogDescription="Agent of Empires merch store. Fulfilled by Printful, ships worldwide."
|
||||
>
|
||||
<Nav />
|
||||
|
||||
<main>
|
||||
<section class="relative pt-32 pb-20 px-6 hero-glow hero-gradient-animated">
|
||||
<div class="max-w-3xl mx-auto text-center">
|
||||
<img src="/assets/logo.svg" alt="Agent of Empires" class="w-20 h-20 mx-auto mb-8 drop-shadow-2xl" width="80" height="80">
|
||||
<h1 class="text-5xl md:text-6xl lg:text-7xl font-semibold mb-6 tracking-hero font-display">
|
||||
<span class="text-gradient">Merch</span>
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-100 leading-relaxed mb-10">
|
||||
Wear the project. Browse the store and pick something up.
|
||||
</p>
|
||||
|
||||
<a
|
||||
href={STORE_URL}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="btn-primary text-base px-8 py-3.5 inline-flex items-center justify-center gap-2"
|
||||
>
|
||||
Visit the Store
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<p class="text-sm text-gray-400 mt-10">
|
||||
Fulfilled by <a href="https://www.printful.com/" target="_blank" rel="noopener" class="text-brand-400 hover:text-brand-300 underline">Printful</a>. Ships worldwide.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,19 +0,0 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
|
||||
export const GET: APIRoute = ({ site }) => {
|
||||
const siteUrl = site?.toString().replace(/\/$/, '') ?? '';
|
||||
|
||||
const robotsTxt = `# robots.txt
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
# Sitemap location
|
||||
Sitemap: ${siteUrl}/sitemap-index.xml
|
||||
`;
|
||||
|
||||
return new Response(robotsTxt, {
|
||||
headers: {
|
||||
'Content-Type': 'text/plain; charset=utf-8',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,121 +0,0 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import FeatureCard from '../components/FeatureCard.astro';
|
||||
import InstallInline from '../components/InstallInline.astro';
|
||||
|
||||
const features = [
|
||||
{ n: '01', title: 'Session dashboard', description: 'Every AI coding session in one list with live status. Jump between agents, groups, and repos without leaving the keyboard.' },
|
||||
{ n: '02', title: 'Keyboard-first', description: 'Launch, attach, rename, and kill agents with single keystrokes. Built for people who never reach for the mouse.' },
|
||||
{ n: '03', title: 'Status detection', description: 'See when an agent is working, waiting for input, or idle, so you always know which session needs you next.' },
|
||||
{ n: '04', title: 'Git worktrees', description: 'Spin up an isolated worktree per agent and clean it up automatically when the work is merged or dropped.' },
|
||||
{ n: '05', title: 'Docker sandboxing', description: 'Run agents in isolated containers with configurable mounts and persistent auth, managed for you.' },
|
||||
{ n: '06', title: 'tmux persistence', description: 'Sessions live in tmux. Close aoe anytime and your agents keep running; reattach whenever you come back.' },
|
||||
];
|
||||
---
|
||||
|
||||
<Base
|
||||
title="The TUI - Agent of Empires"
|
||||
description="A keyboard-driven terminal dashboard for your AI coding agents. See every session at a glance, launch and kill agents with a keystroke, and keep them running in tmux."
|
||||
>
|
||||
<Nav />
|
||||
|
||||
<main>
|
||||
<!-- Hero -->
|
||||
<section class="pt-28 pb-10 px-6 hero-glow">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="eyebrow-pill inline-flex items-center gap-2 rounded-full px-3 py-1.5 font-mono text-xs uppercase tracking-widest mb-6">
|
||||
Front-end · Terminal UI
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-semibold tracking-hero font-display leading-[1.05] text-white max-w-3xl mb-6">
|
||||
A keyboard-driven command center in your terminal.
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-300 max-w-2xl leading-relaxed mb-8">
|
||||
See every AI coding session at a glance, launch and kill agents with a keystroke, and never lose
|
||||
your place. The TUI is the native front-end to Agent of Empires. The
|
||||
<a href="/web/" class="text-brand-400 hover:text-brand-300">web dashboard</a> drives the very
|
||||
same sessions from a browser, so you can pick whichever fits where you are.
|
||||
</p>
|
||||
<InstallInline class="mb-5" />
|
||||
<div class="flex flex-wrap gap-3.5 items-center mb-10">
|
||||
<a href="/docs/quick-start/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Get started
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="terminal-window rounded-2xl overflow-hidden shadow-2xl">
|
||||
<div class="flex items-center gap-2 px-4 py-3 bg-surface-850 border-b border-surface-700/50">
|
||||
<span class="w-3 h-3 rounded-full bg-red-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-yellow-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-green-500"></span>
|
||||
<span class="ml-2 font-mono text-xs text-gray-400">aoe · session manager</span>
|
||||
</div>
|
||||
<img
|
||||
src="/assets/demo.gif"
|
||||
alt="Agent of Empires TUI showing session management with Claude Code, git worktree creation, and Docker container status indicators"
|
||||
class="block w-full"
|
||||
width="960"
|
||||
height="576"
|
||||
fetchpriority="high"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Feature grid -->
|
||||
<section class="py-16 px-6">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">In the TUI</span>
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mt-3">Built for the keyboard</h2>
|
||||
</div>
|
||||
<div class="feature-grid grid md:grid-cols-2 lg:grid-cols-3 gap-px rounded-2xl overflow-hidden animate-on-scroll">
|
||||
{features.map((f) => (
|
||||
<FeatureCard n={f.n} title={f.title} description={f.description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cross-surface -->
|
||||
<section class="pb-4 px-6 animate-on-scroll">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="feature-card rounded-2xl p-8 flex flex-col sm:flex-row sm:items-center gap-4 justify-between">
|
||||
<div>
|
||||
<h2 class="text-xl md:text-2xl font-semibold font-display mb-2">Away from your desk?</h2>
|
||||
<p class="text-gray-400 leading-relaxed max-w-xl">The web dashboard renders the same live sessions in any browser, installs as a PWA, and pairs to your phone over HTTPS.</p>
|
||||
</div>
|
||||
<a href="/web/" class="btn-secondary text-base inline-flex items-center gap-2 shrink-0 group">
|
||||
Explore the web dashboard
|
||||
<svg class="w-4 h-4 group-hover:translate-x-0.5 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="cta-band py-20 px-6 text-center mt-12 animate-on-scroll">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mb-4">Get the TUI running</h2>
|
||||
<p class="text-gray-400 mb-8">Free and open source. MIT licensed.</p>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<InstallInline />
|
||||
<a href="/docs/quick-start/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Get started
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,120 +0,0 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
import FeatureCard from '../components/FeatureCard.astro';
|
||||
import InstallInline from '../components/InstallInline.astro';
|
||||
|
||||
const features = [
|
||||
{ n: '01', title: 'Real terminal in the browser', description: 'A full terminal streamed over WebSocket renders the same session in the page, not a screenshot or a summary.' },
|
||||
{ n: '02', title: 'Installable PWA', description: 'Add to home screen on iOS or install in Chrome on desktop. It behaves like a native app once installed.' },
|
||||
{ n: '03', title: 'Remote phone access', description: 'Press R to expose the dashboard over HTTPS with QR pairing via Tailscale Funnel or Cloudflare Tunnel.' },
|
||||
{ n: '04', title: 'Structured view', description: 'Mobile-first native rendering of agent state via the Agent Client Protocol: plan panels, tool-call cards, swipe-to-approve.' },
|
||||
{ n: '05', title: 'Token auth', description: 'Token-based authentication by default, with persisted login sessions so signed-in devices survive a daemon restart.' },
|
||||
{ n: '06', title: 'Read-only mode', description: 'Hand out a view-only link so a teammate can watch a session live without being able to type into it.' },
|
||||
];
|
||||
---
|
||||
|
||||
<Base
|
||||
title="The Web Dashboard - Agent of Empires"
|
||||
description="Drive the same AI coding sessions from any browser. A real terminal in the page, installable as a PWA, with remote phone access, a mobile structured view, and token auth."
|
||||
>
|
||||
<Nav />
|
||||
|
||||
<main>
|
||||
<!-- Hero -->
|
||||
<section class="pt-28 pb-10 px-6 hero-glow">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="eyebrow-pill inline-flex items-center gap-2 rounded-full px-3 py-1.5 font-mono text-xs uppercase tracking-widest mb-6">
|
||||
Front-end · Web dashboard
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-semibold tracking-hero font-display leading-[1.05] text-white max-w-3xl mb-6">
|
||||
Drive the same sessions from any browser.
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-gray-300 max-w-2xl leading-relaxed mb-8">
|
||||
A real terminal in the page, installable as a PWA, and pairable to your phone over HTTPS. The web
|
||||
dashboard is a first-class front-end to Agent of Empires, driving the very same live sessions as the
|
||||
<a href="/tui/" class="text-brand-400 hover:text-brand-300">keyboard-driven TUI</a>.
|
||||
</p>
|
||||
<InstallInline class="mb-5" />
|
||||
<div class="flex flex-wrap gap-3.5 items-center mb-10">
|
||||
<a href="/guides/web-dashboard/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Set up the dashboard
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="terminal-window rounded-2xl overflow-hidden shadow-2xl">
|
||||
<div class="flex items-center gap-2 px-4 py-3 bg-surface-850 border-b border-surface-700/50">
|
||||
<span class="w-3 h-3 rounded-full bg-red-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-yellow-500"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-green-500"></span>
|
||||
<span class="ml-2 font-mono text-xs text-gray-400">aoe · web dashboard</span>
|
||||
</div>
|
||||
<img
|
||||
src="/assets/web-desktop.gif"
|
||||
alt="Agent of Empires web dashboard driving live agent sessions from the browser"
|
||||
class="block w-full"
|
||||
width="960"
|
||||
height="600"
|
||||
fetchpriority="high"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Feature grid -->
|
||||
<section class="py-16 px-6">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<span class="font-mono text-xs uppercase tracking-widest text-brand-600">In the browser</span>
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mt-3">Your sessions, anywhere</h2>
|
||||
</div>
|
||||
<div class="feature-grid grid md:grid-cols-2 lg:grid-cols-3 gap-px rounded-2xl overflow-hidden animate-on-scroll">
|
||||
{features.map((f) => (
|
||||
<FeatureCard n={f.n} title={f.title} description={f.description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cross-surface -->
|
||||
<section class="pb-4 px-6 animate-on-scroll">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="feature-card rounded-2xl p-8 flex flex-col sm:flex-row sm:items-center gap-4 justify-between">
|
||||
<div>
|
||||
<h2 class="text-xl md:text-2xl font-semibold font-display mb-2">At your desk?</h2>
|
||||
<p class="text-gray-400 leading-relaxed max-w-xl">The native TUI puts the same sessions one keystroke away, with status detection, git worktrees, and tmux persistence.</p>
|
||||
</div>
|
||||
<a href="/tui/" class="btn-secondary text-base inline-flex items-center gap-2 shrink-0 group">
|
||||
Explore the TUI
|
||||
<svg class="w-4 h-4 group-hover:translate-x-0.5 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="cta-band py-20 px-6 text-center mt-12 animate-on-scroll">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold font-display mb-4">Open the dashboard</h2>
|
||||
<p class="text-gray-400 mb-8">Install aoe, then run <code class="font-mono text-brand-400">aoe serve</code>.</p>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<InstallInline />
|
||||
<a href="/guides/web-dashboard/" class="btn-primary text-base inline-flex items-center gap-2">
|
||||
Set up the dashboard
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</Base>
|
||||
@@ -1,64 +0,0 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--font-sans: 'DM Sans', 'DM Sans Fallback', system-ui, sans-serif;
|
||||
--font-display: 'Satoshi', 'DM Sans', system-ui, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', monospace;
|
||||
|
||||
--color-brand-50: #fffbeb;
|
||||
--color-brand-100: #fef3c7;
|
||||
--color-brand-200: #fde68a;
|
||||
--color-brand-300: #fcd34d;
|
||||
--color-brand-400: #fbbf24;
|
||||
--color-brand-500: #f59e0b;
|
||||
--color-brand-600: #d97706;
|
||||
--color-brand-700: #b45309;
|
||||
--color-brand-800: #92400e;
|
||||
--color-brand-900: #78350f;
|
||||
|
||||
--color-accent-50: #f0fdfa;
|
||||
--color-accent-100: #ccfbf1;
|
||||
--color-accent-200: #99f6e4;
|
||||
--color-accent-300: #5eead4;
|
||||
--color-accent-400: #2dd4bf;
|
||||
--color-accent-500: #14b8a6;
|
||||
--color-accent-600: #0d9488;
|
||||
--color-accent-700: #0f766e;
|
||||
--color-accent-800: #115e59;
|
||||
--color-accent-900: #134e4a;
|
||||
|
||||
--color-surface-50: #f8fafc;
|
||||
--color-surface-100: #f1f5f9;
|
||||
--color-surface-200: #e2e8f0;
|
||||
--color-surface-700: #334155;
|
||||
--color-surface-800: #1e293b;
|
||||
--color-surface-850: #162032;
|
||||
--color-surface-900: #0f172a;
|
||||
--color-surface-950: #020617;
|
||||
|
||||
--tracking-hero: -0.02em;
|
||||
|
||||
--animate-fade-in-up: fade-in-up 0.6s ease-out forwards;
|
||||
--animate-gradient-shift: gradient-shift 8s ease infinite;
|
||||
|
||||
@keyframes fade-in-up {
|
||||
0% { opacity: 0; transform: translateY(20px); }
|
||||
100% { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes gradient-shift {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Preserve v3 default border color (gray-200) instead of v4's currentColor. */
|
||||
@layer base {
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentColor);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user