diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..482d520 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -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"}')" diff --git a/DOCS/landing/spaceshell-landing.md b/DOCS/landing/spaceshell-landing.md new file mode 100644 index 0000000..dd49bbc --- /dev/null +++ b/DOCS/landing/spaceshell-landing.md @@ -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) +- spacesh — терминал-воркспейс для AI-агентов на macOS +- 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 + +spacesh — терминал-воркспейс для AI-агентов на macOS + + + + + + + + +``` diff --git a/landing/.dockerignore b/landing/.dockerignore new file mode 100644 index 0000000..6fdb414 --- /dev/null +++ b/landing/.dockerignore @@ -0,0 +1,4 @@ +Dockerfile +.dockerignore +VERSION +*.md diff --git a/landing/Dockerfile b/landing/Dockerfile new file mode 100644 index 0000000..c75d26c --- /dev/null +++ b/landing/Dockerfile @@ -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 diff --git a/landing/VERSION b/landing/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/landing/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/landing/index.html b/landing/index.html new file mode 100644 index 0000000..712e1bc --- /dev/null +++ b/landing/index.html @@ -0,0 +1,1188 @@ + + + + + + spacesh — терминал-воркспейс для AI-агентов на macOS + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Терминал-воркспейс для AI-агентов · macOS

+

+ Гоняй десяток AI-агентов параллельно. Не теряй ни одного. +

+

+ spacesh держит живые сессии Claude Code, Codex, Gemini и shell в фоновом демоне. + Закрыл окно, обновил приложение, словил краш — агенты продолжают работать. +

+ +

+ macOS 13+ · Apple Silicon и Intel · открытый исходник · early access +

+
+ +
+
+
+ + + +
+ spacesh — workspace +
+
+
+
+ + + claude-code + +
+
+
+
+
+
+
+ + + codex + +
+
+ Refactored auth module
+ 3 files changed +
+
+
+
+ + + gemini + +
+
+ Waiting for API...
+ rate limit cooldown +
+
+
+
+ + + shell + +
+
+ ~/projects/app $ +
+
+
+
+ + daemon · alive +
+
+
+
+
+ + +
+
+
+ Работает с: + Claude Code + Codex + Gemini + opencode + shell +
+
+
+ + +
+
+
+
+

Проблема

+

Обычный терминал привязывает агента к окну.

+

+ Закрыл вкладку, перезапустил приложение, упал GUI — длинная сессия агента умирает вместе с ним. +

+
+
+

Решение

+

spacesh разрывает эту связь.

+

+ Сессиями владеет фоновый демон, а не окно. Интерфейс — всего лишь вид поверх него. +

+
+
+
+
+ + +
+
+
+

Возможности

+
+
+
+ daemon +

Демон — источник истины

+

+ spaceshd владеет живыми PTY-сессиями. GUI и CLI — тонкие клиенты поверх одного Unix-сокета. + Убей интерфейс — агент жив. Открой заново — экран восстановится из снапшота за доли секунды. +

+
+
+ grid +

Параллельные агенты в одной сетке

+

+ Несколько агентов в раскладке-гриде: сплиты, зум панели, перетаскивание, пресеты (2×2, 1+2, 2×3…), + воркспейсы и избранное. +

+
+
+ 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 и применяется на лету ко всем окнам. +

+
+
+
+
+ + +
+
+
+

Как это работает

+
+
+
+
01
+

Запуск

+

+ Создаёшь воркспейс и панели — демон спавнит PTY-сессии под агентов. +

+
+ spawn → spaceshd → PTY +
+
+
+
02
+

Демон владеет

+

+ Байты летают GUI ↔ демон ↔ PTY по одному сокету. Интерфейс состояния не хранит — только команды и события. +

+
+ GUI ⇄ Unix socket ⇄ PTY +
+
+
+
03
+

Reattach

+

+ Закрыл и открыл приложение — демон отдаёт снапшот экрана, окно перерисовывается мгновенно. +

+
+ snapshot → restore → live +
+
+
+
+
+ + +
+
+
+

В планах

+

Над чем работаем

+
+ + + Внешние уведомления в Telegram и MAX + + + + diff-просмотр изменений агента + + + + Удалённая работа через SSH-туннель к демону + +
+
+
+
+ + +
+
+
+ Rust + Tauri 2 + tokio + xterm.js + alacritty + < 16 мс на нажатие клавиши +
+
+
+ + +
+
+

Готов гонять агентов пачками?

+ + + Исходники на GitHub → + +
+
+ + + + + + + \ No newline at end of file diff --git a/landing/nginx.conf b/landing/nginx.conf new file mode 100644 index 0000000..c0c3970 --- /dev/null +++ b/landing/nginx.conf @@ -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; + } +} diff --git a/landing/pics/pic1.png b/landing/pics/pic1.png new file mode 100644 index 0000000..d6805ad Binary files /dev/null and b/landing/pics/pic1.png differ diff --git a/landing/pics/pic2.png b/landing/pics/pic2.png new file mode 100644 index 0000000..3f8d484 Binary files /dev/null and b/landing/pics/pic2.png differ