Merge landing-ci: landing site, nginx image, Gitea CI for landing + DMG
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
tags: ["v*"]
|
||||
paths:
|
||||
- "landing/**"
|
||||
- "app/**"
|
||||
- "crates/**"
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
- ".gitea/workflows/build.yaml"
|
||||
|
||||
env:
|
||||
REGISTRY: git.realmanual.ru
|
||||
IMAGE_PREFIX: ${{ gitea.repository }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
# ---------------------------------------------------------------------------
|
||||
# Decide what changed so we don't rebuild the (slow) DMG on a landing-only edit
|
||||
# and vice versa. Tags always build everything (release).
|
||||
# ---------------------------------------------------------------------------
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-22.04
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
outputs:
|
||||
landing: ${{ steps.filter.outputs.landing }}
|
||||
app: ${{ steps.filter.outputs.app }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with: { fetch-depth: 2 }
|
||||
- id: filter
|
||||
uses: dorny/paths-filter@v3
|
||||
with:
|
||||
filters: |
|
||||
landing:
|
||||
- 'landing/**'
|
||||
app:
|
||||
- 'app/**'
|
||||
- 'crates/**'
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Landing → static nginx image pushed to the Gitea registry.
|
||||
# ---------------------------------------------------------------------------
|
||||
landing:
|
||||
name: Build & push landing
|
||||
needs: changes
|
||||
if: needs.changes.outputs.landing == 'true' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-22.04
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.VERSION }}
|
||||
status: ${{ steps.build.outcome }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Read version
|
||||
id: version
|
||||
run: echo "VERSION=$(cat ./landing/VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Log in to Gitea Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.TOKEN }}
|
||||
- name: Build and push
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./landing
|
||||
file: ./landing/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/spacesh-landing:${{ steps.version.outputs.VERSION }}
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/spacesh-landing:latest
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# macOS app → universal (Intel + Apple Silicon) .dmg.
|
||||
# REQUIRES a self-hosted macOS runner labelled `macos` — Tauri cannot
|
||||
# cross-compile a macOS bundle from Linux. The DMG is UNSIGNED (no Developer
|
||||
# ID secrets configured); Gatekeeper will warn on first open. To sign+notarize
|
||||
# later, set APPLE_CERTIFICATE / APPLE_SIGNING_IDENTITY / APPLE_ID secrets and
|
||||
# pass them through to `tauri build`.
|
||||
# ---------------------------------------------------------------------------
|
||||
dmg:
|
||||
name: Build macOS DMG
|
||||
needs: changes
|
||||
if: needs.changes.outputs.app == 'true' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: macos
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.VERSION }}
|
||||
status: ${{ steps.build.outcome }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Read version
|
||||
id: version
|
||||
run: echo "VERSION=$(node -p "require('./app/src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install Rust + macOS targets
|
||||
run: |
|
||||
if ! command -v rustup >/dev/null; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
fi
|
||||
rustup target add aarch64-apple-darwin x86_64-apple-darwin
|
||||
- name: Install frontend deps
|
||||
working-directory: app
|
||||
run: npm ci
|
||||
- name: Build universal DMG
|
||||
id: build
|
||||
working-directory: app
|
||||
run: npm run tauri build -- --target universal-apple-darwin
|
||||
- name: Collect DMG
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist
|
||||
cp app/src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg dist/
|
||||
ls -lh dist
|
||||
- name: Upload DMG artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: spacesh-dmg-${{ steps.version.outputs.VERSION }}
|
||||
path: dist/*.dmg
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary → Max.
|
||||
# ---------------------------------------------------------------------------
|
||||
notify:
|
||||
name: Notify Max
|
||||
needs: [landing, dmg]
|
||||
if: always()
|
||||
runs-on: ubuntu-22.04
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Compose & send summary
|
||||
run: |
|
||||
line_for() {
|
||||
local name="$1" result="$2" ver="$3"
|
||||
case "$result" in
|
||||
success) echo "✅ $name собран (\`$ver\`)";;
|
||||
failure) echo "❌ $name — ошибка сборки";;
|
||||
skipped) echo "➖ $name без изменений";;
|
||||
*) echo "❔ $name — $result";;
|
||||
esac
|
||||
}
|
||||
summary=""
|
||||
summary="$summary"$'\n'"$(line_for spacesh-landing '${{ needs.landing.result }}' '${{ needs.landing.outputs.version }}')"
|
||||
summary="$summary"$'\n'"$(line_for spacesh-dmg '${{ needs.dmg.result }}' '${{ needs.dmg.outputs.version }}')"
|
||||
|
||||
url="${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_number }}"
|
||||
text=$(printf '**Build**%s\n\n[лог](%s)' "$summary" "$url")
|
||||
|
||||
curl -s -X POST "https://platform-api.max.ru/messages?chat_id=${{ secrets.MAX_CHAT_ID }}" \
|
||||
-H "Authorization: ${{ secrets.MAX_BOT_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n --arg t "$text" '{text:$t,format:"markdown"}')"
|
||||
@@ -0,0 +1,183 @@
|
||||
# spacesh — лендинг (бриф + текст)
|
||||
|
||||
Домен: **spaceshell.ru** · Язык: русский · Стиль: terminal-dark · CTA: Скачать для macOS
|
||||
|
||||
---
|
||||
|
||||
## 1. Промпт для разработки
|
||||
|
||||
> Скопировать целиком в AI-билдер (v0 / Lovable / Claude) или дать фронтенд-разработчику.
|
||||
|
||||
```
|
||||
Построй одностраничный лендинг для продукта «spacesh» — терминал-воркспейс
|
||||
для параллельного запуска AI-агентов на macOS. Домен spaceshell.ru. Язык
|
||||
интерфейса — русский. Стадия — early access (pre-v1), будь честен в формулировках.
|
||||
|
||||
# Стек и поставка
|
||||
- Astro + Tailwind CSS. Один статический маршрут, деплой на любой статический хост.
|
||||
- Анимации hero — один React-остров (Astro island) или чистый CSS/Canvas; остальная
|
||||
страница — zero-JS. Цель Lighthouse: 95+ по всем осям, LCP < 1.5s.
|
||||
- Семантический HTML, корректная иерархия заголовков, prefers-reduced-motion.
|
||||
|
||||
# Позиционирование (одной фразой)
|
||||
«spacesh держит живые сессии AI-агентов в фоновом демоне — закрой окно, обнови
|
||||
приложение, словив краш: агенты продолжают работать».
|
||||
|
||||
# Визуальный язык — terminal-dark
|
||||
- Фон: #0A0D12 (база), панели #0E1116 / #11161F, границы #232A33 / #323C49.
|
||||
- Текст: #E6EDF3 (основной), #8B97A6 (вторичный), #5A6573 (приглушённый).
|
||||
- Акцент: бирюзовый неон #34D3C2 (primary), синий #4F9CF9 (secondary). Статусы:
|
||||
work #4C8DFF, wait #F2B84B, done #3FB950, error #F4544E.
|
||||
- Шрифты: JetBrains Mono (заголовки-акценты, код, лейблы, цифры) + Inter (тело).
|
||||
- Текстуры: едва заметная сетка/scanlines на фоне hero, мягкое свечение (glow) под
|
||||
акцентными элементами, скруглённые панели radius 8–14 как в самом приложении.
|
||||
- Курсор-каретка (мигающий блок ▌) как лейтмотив бренда; иконка приложения —
|
||||
тёмная плитка с промптом «>_» бирюзой (есть в app/src-tauri/icons/icon.svg).
|
||||
|
||||
# Структура секций (сверху вниз)
|
||||
1. Хедер: лого «spacesh» (mono) + nav (Возможности · Как работает · CLI · GitHub) +
|
||||
кнопка «Скачать для macOS». Sticky, прозрачный → размытие при скролле.
|
||||
2. Hero:
|
||||
- Eyebrow: «Терминал-воркспейс для AI-агентов · macOS».
|
||||
- H1 (крупно, mono-акцент в части слова): см. текст ниже.
|
||||
- Подзаголовок, две кнопки: primary «Скачать для macOS», secondary «Как это работает».
|
||||
- Микро-строка под кнопками: «macOS 13+ · Apple Silicon и Intel · открытый исходник».
|
||||
- Справа/снизу — АНИМИРОВАННЫЙ макет приложения: сетка из 3–4 терминал-панелей,
|
||||
в каждой «агент» (Claude Code, Codex, Gemini, shell) со status-кольцом; в одной
|
||||
идёт печать вывода (typewriter), кольца переключаются work→done. Ключевой момент
|
||||
анимации: окно «закрывается» (затемняется), а маленький бейдж «daemon · alive»
|
||||
продолжает гореть, затем окно возвращается и мгновенно перерисовывается из снапшота.
|
||||
3. Лента агентов: «Работает с: Claude Code · Codex · Gemini · opencode · shell».
|
||||
4. Проблема → решение (короткий контраст-блок): «GUI падает — агент умирает вместе с
|
||||
ним» → ответ spacesh.
|
||||
5. Сетка возможностей (6 карточек, terminal-dark, с mono-заголовками и иконкой):
|
||||
демон-источник истины, параллельные агенты в гриде, статусы пушем, гибридный
|
||||
терминал (поиск/снапшоты), CLI, тема/настройки. Тексты — ниже.
|
||||
6. «Как это работает» — 3 шага с мини-диаграммой (spawn → daemon владеет PTY → reattach
|
||||
из снапшота). Подпись про один Unix-сокет и length-prefixed JSON.
|
||||
7. Полоса «В планах» (roadmap, честно): внешние уведомления Telegram + MAX,
|
||||
diff-просмотр изменений агента, remote через SSH-туннель.
|
||||
8. Tech-полоса: «Rust · Tauri 2 · tokio · xterm.js · alacritty» + бюджет «< 16 мс на нажатие».
|
||||
9. Финальный CTA: крупная кнопка «Скачать для macOS» + ссылка «Исходники на GitHub».
|
||||
Опционально мини-форма email «Сообщить о релизе».
|
||||
10. Футер: spaceshell.ru, © 2026, ссылки (GitHub, Документация, Лицензия), строка
|
||||
«Сделано для тех, кто гоняет агентов пачками».
|
||||
|
||||
# Интерактив и анимации
|
||||
- Hero-терминал: печать вывода через requestAnimationFrame, мигающая каретка,
|
||||
плавная смена status-колец. Уважать prefers-reduced-motion (показывать статичный кадр).
|
||||
- Карточки возможностей: лёгкий lift + свечение границы на hover.
|
||||
- Скролл-ревилы (fade/translate, ≤ 300мс), без тяжёлых либ.
|
||||
|
||||
# SEO / мета (RU)
|
||||
- <title>spacesh — терминал-воркспейс для AI-агентов на macOS</title>
|
||||
- description: «Запускай Claude Code, Codex, Gemini и shell параллельно. Фоновый демон
|
||||
держит сессии живыми: закрыл окно — агенты работают. Скачать для macOS.»
|
||||
- canonical https://spaceshell.ru, og:title/description/image (тёмный OG 1200×630 со
|
||||
скрином сетки панелей и каретки), lang=ru, theme-color #0A0D12, favicon из иконки app.
|
||||
|
||||
# Адаптив
|
||||
- Desktop-first, но полностью отзывчиво. На мобильном hero-сетка сворачивается в
|
||||
одну панель + краткий список возможностей; кнопка CTA закреплена снизу.
|
||||
|
||||
# Не делать
|
||||
- Никаких стоковых «AI-градиентов», 3D-блобов, фейковых логотипов компаний.
|
||||
- Не обещать фич из roadmap как готовых — секция «В планах» отдельно.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Текст лендинга (готовая копирайт-копия)
|
||||
|
||||
### Хедер
|
||||
- Лого: `spacesh`
|
||||
- Меню: Возможности · Как работает · CLI · GitHub
|
||||
- Кнопка: **Скачать для macOS**
|
||||
|
||||
### Hero
|
||||
- Надстрочник: `Терминал-воркспейс для AI-агентов · macOS`
|
||||
- **H1:** Гоняй десяток AI-агентов параллельно. **Не теряй ни одного.**
|
||||
- Подзаголовок: spacesh держит живые сессии Claude Code, Codex, Gemini и shell в
|
||||
фоновом демоне. Закрыл окно, обновил приложение, словил краш — агенты продолжают работать.
|
||||
- Кнопки: **Скачать для macOS** · Как это работает
|
||||
- Микро-строка: macOS 13+ · Apple Silicon и Intel · открытый исходник · early access
|
||||
|
||||
### Лента агентов
|
||||
Работает с: **Claude Code · Codex · Gemini · opencode · shell**
|
||||
|
||||
### Проблема → решение
|
||||
**Обычный терминал привязывает агента к окну.** Закрыл вкладку, перезапустил приложение,
|
||||
упал GUI — длинная сессия агента умирает вместе с ним.
|
||||
|
||||
**spacesh разрывает эту связь.** Сессиями владеет фоновый демон, а не окно. Интерфейс —
|
||||
всего лишь вид поверх него.
|
||||
|
||||
### Возможности (6 карточек)
|
||||
|
||||
**`daemon` Демон — источник истины**
|
||||
`spaceshd` владеет живыми PTY-сессиями. GUI и CLI — тонкие клиенты поверх одного
|
||||
Unix-сокета. Убей интерфейс — агент жив. Открой заново — экран восстановится из
|
||||
снапшота за доли секунды.
|
||||
|
||||
**`grid` Параллельные агенты в одной сетке**
|
||||
Несколько агентов в раскладке-гриде: сплиты, зум панели, перетаскивание, пресеты
|
||||
(2×2, 1+2, 2×3…), воркспейсы и избранное. Один клик в GUI и `spacesh focus` из
|
||||
скрипта — одна и та же команда.
|
||||
|
||||
**`status` Статусы без догадок**
|
||||
`work · wait · done · error · idle` приходят пушем — от хуков агентов, маркеров
|
||||
OSC 133 и паттернов как запасной вариант. Кольца, бейджи, центр событий и нативные
|
||||
уведомления macOS.
|
||||
|
||||
**`search` Гибридный терминал**
|
||||
xterm.js рисует, грид alacritty в демоне анализирует. Отсюда — поиск по скроллбэку
|
||||
(⌘F) с подсветкой, извлечение последней команды и мгновенные снапшоты для reattach.
|
||||
|
||||
**`cli` CLI как первый класс**
|
||||
`spacesh status --json`, `focus`, `new-surface`, `notify` — те же команды, что и в
|
||||
интерфейсе, плюс shell-completions. Встраивай spacesh в свои пайплайны.
|
||||
|
||||
**`theme` Под себя**
|
||||
Тёмная и светлая темы, акцентные цвета, шрифт и размер терминала, дефолтный shell —
|
||||
всё хранится демоном в `config.toml` и применяется на лету ко всем окнам.
|
||||
|
||||
### Как это работает (3 шага)
|
||||
1. **Запуск.** Создаёшь воркспейс и панели — демон спавнит PTY-сессии под агентов.
|
||||
2. **Демон владеет.** Байты летают GUI ↔ демон ↔ PTY по одному сокету. Интерфейс
|
||||
состояния не хранит — только команды и события.
|
||||
3. **Reattach.** Закрыл и открыл приложение — демон отдаёт снапшот экрана, окно
|
||||
перерисовывается мгновенно, дальше идёт живой вывод.
|
||||
|
||||
### В планах
|
||||
Внешние уведомления в Telegram и MAX · diff-просмотр изменений агента · удалённая
|
||||
работа через SSH-туннель к демону.
|
||||
|
||||
### Tech
|
||||
Rust · Tauri 2 · tokio · xterm.js · alacritty — нативно и быстро. Бюджет отклика:
|
||||
меньше 16 мс на нажатие клавиши.
|
||||
|
||||
### Финальный CTA
|
||||
**Готов гонять агентов пачками?**
|
||||
Кнопка: **Скачать для macOS** · Исходники на GitHub
|
||||
(опц.) Форма: «Оставь email — сообщим о релизе»
|
||||
|
||||
### Футер
|
||||
spaceshell.ru · © 2026 spacesh · GitHub · Документация · Лицензия
|
||||
«Сделано для тех, кто запускает агентов пачками.»
|
||||
|
||||
---
|
||||
|
||||
## 3. SEO-мета (готово к вставке)
|
||||
|
||||
```html
|
||||
<html lang="ru">
|
||||
<title>spacesh — терминал-воркспейс для AI-агентов на macOS</title>
|
||||
<meta name="description" content="Запускай Claude Code, Codex, Gemini и shell параллельно. Фоновый демон держит сессии живыми: закрыл окно — агенты работают. Скачать для macOS.">
|
||||
<link rel="canonical" href="https://spaceshell.ru">
|
||||
<meta property="og:title" content="spacesh — терминал-воркспейс для AI-агентов">
|
||||
<meta property="og:description" content="Десяток AI-агентов параллельно. Демон держит сессии живыми — закрой окно, агенты работают.">
|
||||
<meta property="og:url" content="https://spaceshell.ru">
|
||||
<meta property="og:image" content="https://spaceshell.ru/og.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="theme-color" content="#0A0D12">
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
VERSION
|
||||
*.md
|
||||
@@ -0,0 +1,9 @@
|
||||
# Static landing for spaceshell.ru — served by nginx.
|
||||
# Build context is ./landing (see .gitea/workflows/build.yaml).
|
||||
FROM nginx:1.27-alpine
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY index.html /usr/share/nginx/html/index.html
|
||||
COPY pics/ /usr/share/nginx/html/pics/
|
||||
|
||||
EXPOSE 80
|
||||
@@ -0,0 +1 @@
|
||||
0.1.0
|
||||
+1188
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 6;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
||||
|
||||
# Long cache for fingerprint-free static assets; HTML stays revalidated.
|
||||
location ~* \.(?:css|js|png|jpe?g|gif|svg|webp|woff2?)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location = /index.html {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 651 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 279 KiB |
Reference in New Issue
Block a user