590 lines
21 KiB
Markdown
590 lines
21 KiB
Markdown
# pi-remote — iOS Native App Spec (v3)
|
||
|
||
> **Status:** v3 nach ExtensionAPI-Audit.
|
||
> Audit-Ergebnis: [`EXTENSION-API-AUDIT.md`](./EXTENSION-API-AUDIT.md).
|
||
> Review-Verlauf v1: [`SPEC-ios-app-review-v1.md`](./SPEC-ios-app-review-v1.md).
|
||
>
|
||
> **Changelog v2 → v3:**
|
||
> - Audit hat S-07, S-08 und Tree-Read als out-of-the-box machbar bestätigt → von PENDING auf firm SHOULD.
|
||
> - **Tree-Navigation komplett aus iOS entfernt.** Gruppe T gestrichen. Begründung: Slash-Command-Dispatch ist in der ExtensionAPI blockiert, Workarounds (Hack oder Re-Implement) sind nicht den Aufwand wert. Tree-Navigation bleibt nativ in pi.
|
||
> - Spike-0a abgeschlossen, ist nun referenziertes Audit-Dokument.
|
||
|
||
---
|
||
|
||
## 1. Vision
|
||
|
||
Eine iOS-App, die laufende `pi`-Sessions **byte-genau spiegelt**, wie sie im
|
||
SSH-Terminal aussehen — und durch native iOS-Mittel (Touch, Sprache,
|
||
Notifications, System-Integration) die Bedienung dieser Terminal-Umgebung
|
||
unterwegs angenehm macht.
|
||
|
||
**Kein Hybrid-Rendering.** Was im Terminal ANSI ist, bleibt in der App ANSI.
|
||
Die App fügt eine *Augmentation-Schicht* hinzu, kein paralleles UI.
|
||
|
||
**Kernszenarien:**
|
||
|
||
1. **Long-Visit-Sync** — Eine Session läuft tagelang. Nutzer "besucht" sie
|
||
unregelmäßig vom Mac (SSH) und iPhone (App). Beide zeigen jederzeit
|
||
denselben State. Reattach ist instant.
|
||
2. **Session-Lifecycle vom Phone** — Sessions vom iPhone aus spawnen,
|
||
benennen, switchen und beenden — so easy wie native iOS-Tabs.
|
||
|
||
---
|
||
|
||
## 2. Principles
|
||
|
||
- **P-1** — Der Terminal-Stream ist die einzige Wahrheit für Inhalt.
|
||
Strukturierte Events dienen ausschließlich Statusanzeigen,
|
||
Notifications und Meta-State (z.B. Tree-Navigation). Niemals
|
||
Re-Rendering von Stream-Inhalt.
|
||
- **P-2** — SSH-Erfahrung bleibt unverändert. Der Mac-Workflow ändert
|
||
sich durch dieses Projekt nicht spürbar.
|
||
- **P-3** — Reconnect ist die wichtigste Operation. Sichtbares Ergebnis
|
||
< 1s nach App-Wake.
|
||
- **P-4** — Touch-UX wird *zur Terminal-Bedienung* gebaut, nicht
|
||
*anstelle* von Terminal-Bedienung.
|
||
- **P-5** — Solo-Use. Multi-User, Sharing, Org-Features sind out of scope.
|
||
- **P-6** — Server-State wird in tmux gehalten, wo möglich. Kein
|
||
paralleler State-Store im Sidecar.
|
||
|
||
---
|
||
|
||
## 3. Architecture
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ Server │
|
||
│ │
|
||
│ pi (Ink TUI) ◄─► tmux session ◄─► SSH-Client (Mac) │
|
||
│ │ │
|
||
│ │ pipe-pane (raw bytes) │
|
||
│ │ send-keys │
|
||
│ ▼ │
|
||
│ pi-remote sidecar │
|
||
│ │ │
|
||
│ │ WebSocket (wss://) │
|
||
│ │ ├─ raw ANSI stream (binary) │
|
||
│ │ ├─ control (send-keys, JSON) │
|
||
│ │ └─ side-channel (state, JSON) │
|
||
└─────────────────────────┼────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────┐
|
||
│ iOS App │
|
||
│ ┌────────────────────┐ │
|
||
│ │ SwiftTerm renderer │ │
|
||
│ └────────────────────┘ │
|
||
│ ┌────────────────────┐ │
|
||
│ │ Augmentation layer │ │
|
||
│ └────────────────────┘ │
|
||
└──────────────────────────┘
|
||
```
|
||
|
||
**Komponenten:**
|
||
|
||
- **tmux** — Session-Persistenz, Multi-Client-Attach, Pane-Pipe, Send-Keys.
|
||
Sessions als stable IDs, Metadaten via tmux User-Options
|
||
(`@description`, `@project`, etc.).
|
||
- **Sidecar** (`pi-remote-control` erweitert) — Node-Prozess. Spawn /
|
||
Reattach tmux, exponiert WebSocket-API, hält Ringbuffer für Replay,
|
||
leitet ExtensionAPI-Metadaten als Side-Channel weiter.
|
||
- **iOS-App** — SwiftUI-Shell, SwiftTerm als Renderer-View, eigener
|
||
Augmentation-Layer.
|
||
|
||
**Datenfluss Stream:** `pi` → tmux pipe-pane → sidecar ringbuffer → WS
|
||
(binär, `permessage-deflate`) → iOS SwiftTerm.
|
||
|
||
**Datenfluss Input:** iOS → WS → sidecar → `tmux send-keys` → tmux pane →
|
||
pi stdin. Mac-SSH-Client sieht denselben Input.
|
||
|
||
**Konventionen:**
|
||
|
||
- Terminal-Size: tmux pane fixiert auf **120 × 40**. Client rendert mit
|
||
Pinch-Zoom auf die physische Display-Größe.
|
||
- WebSocket-Frames: binär = ANSI-Stream-Chunk; text = JSON-Control
|
||
(input, side-channel, snapshot-request).
|
||
- Alternate-Screen-Buffer wird vom Client erkannt und nicht in den
|
||
Scrollback-Cache aufgenommen.
|
||
- Terminal-Title-Sequences werden ignoriert.
|
||
- Mouse-Tracking-Sequenzen werden weitergeleitet, vom Client aber nicht
|
||
visualisiert (Touch-UX).
|
||
|
||
---
|
||
|
||
## 4. Server Features (Sidecar)
|
||
|
||
### S-01 — tmux launcher / attach
|
||
**MUST.** CLI `pi-remote attach [<session>]`. Existiert die Session,
|
||
reattach; sonst neu spawnen (`tmux new-session -d -s <name> 'pi'`) und
|
||
attach. Default-Session: `pi-main`. Per Projekt benennbar.
|
||
|
||
*Dependencies:* —
|
||
|
||
### S-02 — Raw ANSI WebSocket Stream
|
||
**MUST.** Endpoint `/stream/<session>`.
|
||
- Binäre Frames für ANSI-Bytes aus `tmux pipe-pane`.
|
||
- WebSocket-Extension `permessage-deflate` aktiv (3–5× Compression
|
||
typisch für ANSI).
|
||
- Eine Verbindung = ein Pane.
|
||
- Alternate-Screen-Sequenzen werden durchgereicht; Sidecar markiert sie
|
||
nicht separat (Client tracked).
|
||
|
||
*Dependencies:* S-01
|
||
|
||
### S-03 — Send-Keys-Endpoint
|
||
**MUST.** WS-Text-Frames als JSON: `{type:"keys", data:"..."}` für
|
||
literal-Text, oder `{type:"key", name:"escape"|"tab"|"up"|...}` für
|
||
Spezialtasten. Sidecar mapped auf `tmux send-keys` oder
|
||
`tmux send-keys -l`. Bracketed-Paste-Frames
|
||
(`{type:"paste", data:"..."}`) wrappen automatisch mit `\e[200~ ... \e[201~`.
|
||
|
||
*Dependencies:* S-01
|
||
|
||
### S-04 — Sequence-Cursor & Delta-Replay
|
||
**MUST.** Sidecar nummeriert Chunks ausgehend (monotone u64). Client
|
||
sendet bei Reconnect `{type:"resume", lastSeq:<n>}`. Server liefert ab
|
||
`lastSeq+1` weiter. Falls Lücke → Snapshot (S-05).
|
||
|
||
*Dependencies:* S-02
|
||
|
||
### S-05 — Snapshot-Endpoint
|
||
**MUST.** Wenn `lastSeq` außerhalb des Ringbuffers liegt:
|
||
`tmux capture-pane -p -e -S -10000` als Snapshot + neuen Start-Seq.
|
||
Snapshot wird komprimiert über WS geliefert.
|
||
|
||
*Dependencies:* S-01, S-04
|
||
|
||
### S-06 — Per-Session Disk Buffer
|
||
**SHOULD.** Sidecar persistiert ANSI-Stream pro Session in eine
|
||
einzelne Datei `/var/lib/pi-remote/buffer/<session>.log`.
|
||
|
||
- **Pro Session**: hartes Cap = **100MB** (configurable). Bei
|
||
Überlauf wird der Schreibvorgang gestoppt; existierender Inhalt
|
||
bleibt unangetastet. Neue Bytes ab dem Punkt fehlen im Buffer —
|
||
Snapshot via S-05 funktioniert weiterhin direkt aus tmux.
|
||
- **Global**: Hartes Total-Cap = **1GB** über alle Sessions; wenn
|
||
überschritten, schaltet der Sidecar Buffer-Schreiben global ab und
|
||
meldet `degraded` über S-13.
|
||
- **Idle-Cleanup**: Sessions ohne Output UND ohne Client seit > 30
|
||
Tagen → Buffer-Datei wird gelöscht (Session selbst nur falls
|
||
ebenfalls beendet).
|
||
- **Disk-Watchdog**: Bei freiem Platz < 1GB → Buffer-Schreiben global
|
||
aus, Health-Status `degraded`.
|
||
- Konfigurierbar via `~/.config/pi-remote/config.toml`.
|
||
|
||
*Dependencies:* S-02
|
||
|
||
### S-07 — State Side-Channel
|
||
**SHOULD.** Sidecar abonniert pi-ExtensionAPI-Events (`agent_start`,
|
||
`agent_end`, `tool_execution_start`, `tool_execution_end`,
|
||
`session_tree`, `session_compact`) und publiziert als JSON-Control-Frames:
|
||
```json
|
||
{"type":"state","value":"thinking"|"tool"|"idle"|"awaiting-input",
|
||
"tool":"Edit"|"Read"|...,"ts":1234567890}
|
||
```
|
||
`awaiting-input` wird abgeleitet aus `agent_end` + `ctx.isIdle()`,
|
||
da kein explizites Event existiert (siehe Audit §3.1).
|
||
|
||
*Dependencies:* S-01
|
||
|
||
### S-08 — Slash-Command-Registry
|
||
**SHOULD.** Endpoint `/sessions/<id>/commands` liefert JSON-Liste der
|
||
verfügbaren Slash-Commands inkl. Beschreibung und Argument-Schema via
|
||
`pi.getCommands()` (laut Audit out-of-the-box verfügbar). Dynamisch —
|
||
Extensions die Commands hinzufügen erscheinen automatisch.
|
||
|
||
*Dependencies:* S-01
|
||
|
||
### S-09 — Multi-Session-Management
|
||
**MUST.** Sidecar verwaltet mehrere tmux-Sessions parallel, alle robust
|
||
gegen Sidecar-Restart (tmux überlebt, Sidecar reattached beim Boot).
|
||
|
||
**Endpoints:**
|
||
- `GET /sessions` — Liste mit Metadaten (Name, Description, Created,
|
||
letzter Output, Connected-Clients, Pi-State).
|
||
- `POST /sessions` — neue Session spawnen, Body optional `{name, project}`.
|
||
- `PATCH /sessions/<id>` — umbenennen / Description ändern.
|
||
- `DELETE /sessions/<id>` — Session beenden (tmux kill-session + Buffer
|
||
optional löschen).
|
||
|
||
**State:** Ausschließlich in tmux gehalten. Sessions haben Namen
|
||
(stable ID), Metadaten via tmux User-Options:
|
||
- `@description` — Auto- oder manuell vergeben (siehe S-09a)
|
||
- `@project` — optional, vom User gesetzt
|
||
- `@created` — Timestamp
|
||
|
||
Kein eigener JSON-State-Store im Sidecar.
|
||
|
||
*Dependencies:* S-01
|
||
|
||
### S-09a — Auto-Naming via pi
|
||
**NICE.** Nach ~3 User-Messages in einer namenlosen Session triggert
|
||
der Sidecar einen One-Shot-Call via pi-CLI:
|
||
|
||
```bash
|
||
pi --one-shot --model claude-haiku-4-5 \
|
||
--prompt "Title for this conversation in 2-4 words: <transcript>"
|
||
```
|
||
|
||
(genaue CLI-Flags TBD; pi's eigene Anthropic-Auth wird verwendet, keine
|
||
separaten Credentials nötig)
|
||
|
||
Ergebnis landet als `@description` in tmux. Manuelles Umbenennen aus
|
||
der App jederzeit möglich und überschreibt.
|
||
|
||
*Dependencies:* S-09, pi-CLI one-shot mode
|
||
|
||
### S-10 — Pairing & Bearer-Token-Auth
|
||
**MUST.** CLI `pi-remote pair` generiert ein kurzlebiges (5min)
|
||
Pairing-Token und druckt einen QR-Code im Terminal (Unicode block
|
||
chars, via `qrcode-terminal`).
|
||
|
||
QR-Inhalt: `pi-remote://<host>:<port>?pair=<token>&fp=<sha256-cert-fp>`
|
||
|
||
iOS-App scannt → tauscht Pairing-Token gegen permanenten Bearer-Token,
|
||
pinnt den TLS-Fingerprint. Token im Keychain (iOS-G-01).
|
||
|
||
CLI:
|
||
- `pi-remote auth list` — alle Tokens
|
||
- `pi-remote auth revoke <name>` — Token widerrufen
|
||
- `pi-remote auth name <name>` — Token umbenennen (z.B. "jay's iPhone")
|
||
|
||
*Dependencies:* S-11
|
||
|
||
### S-11 — TLS via Self-Signed + Trust-on-First-Use
|
||
**MUST.** Sidecar generiert beim ersten Start ein selbstsigniertes
|
||
Cert (ED25519 oder RSA-2048), 10 Jahre gültig, persistent auf Disk.
|
||
SHA-256-Fingerprint wird in den QR aus S-10 mit aufgenommen. Client
|
||
pinnt den Fingerprint beim Pairing. Bei Cert-Rotation (z.B. neuer
|
||
Host) muss re-paired werden.
|
||
|
||
Kein Let's Encrypt, keine CA, kein Reverse-Proxy nötig.
|
||
|
||
*Dependencies:* —
|
||
|
||
### S-12 — Health & Metrics
|
||
**NICE.** `/health` Endpoint mit Session-Count, Buffer-Size,
|
||
Connected-Clients, Disk-Watchdog-Status. Für Monitoring und
|
||
Selbst-Debugging.
|
||
|
||
*Dependencies:* —
|
||
|
||
> S-13 (Tree-State Side-Channel) wurde in v3 gestrichen.
|
||
> Begründung: siehe Out-of-Scope und Changelog.
|
||
|
||
---
|
||
|
||
## 5. iOS Client Features
|
||
|
||
### Gruppe A — Rendering & Stream
|
||
|
||
#### iOS-A-01 — SwiftTerm-Renderer
|
||
**MUST.** Vollwertiger ANSI-Terminal-View. Renderer-Setup mit
|
||
Truecolor, 120×40 fixed grid, configurable Font + Theme.
|
||
|
||
*Dependencies:* S-02
|
||
|
||
#### iOS-A-02 — Sequence-Cursor & Reconnect
|
||
**MUST.** Client speichert lokal pro Session den letzten `seq`. Bei
|
||
WS-Reconnect: schickt `{type:"resume", lastSeq}`, verarbeitet Delta
|
||
oder Snapshot.
|
||
|
||
*Dependencies:* S-04, S-05
|
||
|
||
#### iOS-A-03 — Stale-Frame-Display
|
||
**SHOULD.** Während Sync nach App-Wake: letzten Frame einfrieren,
|
||
"syncing…" als subtile Overlay-Pill anzeigen. Kein leerer Screen.
|
||
|
||
*Dependencies:* iOS-A-02
|
||
|
||
#### iOS-A-04 — Local Scrollback-Cache
|
||
**SHOULD.** App puffert empfangene Bytes lokal pro Session (rolling,
|
||
default 5MB) für Offline-Scrolling und Suche. Alternate-Screen-Inhalt
|
||
wird ausgenommen.
|
||
|
||
*Dependencies:* iOS-A-01
|
||
|
||
#### iOS-A-05 — Themes & Fonts
|
||
**SHOULD.** Eingebaute Themes:
|
||
- Default-Dark, Default-Light
|
||
- Solarized Light, Solarized Dark
|
||
- Monokai, Dracula
|
||
- Nord, Gruvbox Dark, Gruvbox Light
|
||
- Tomorrow Night
|
||
- GitHub Light, GitHub Dark
|
||
- System (folgt iOS Light/Dark Mode)
|
||
|
||
Eingebaute Fonts (gebundlet):
|
||
- JetBrains Mono (Default)
|
||
- Hack
|
||
- SF Mono
|
||
- Menlo
|
||
- Fira Code
|
||
- Cascadia Code
|
||
- IBM Plex Mono
|
||
- Monaspace Neon
|
||
|
||
Custom Themes editierbar, iCloud-Sync nur für Custom.
|
||
|
||
*Dependencies:* iOS-A-01
|
||
|
||
### Gruppe B — Input & Modifier
|
||
|
||
#### iOS-B-01 — Software-Keyboard, Direct-Passthrough
|
||
**MUST.** Standard-iOS-Keyboard. **Mode (b) direct-passthrough**:
|
||
jeder Tastendruck geht sofort als `send-keys`. Enter sendet `\r` an
|
||
pi → pi behandelt selbst. Kein App-eigenes Compose-Feld.
|
||
|
||
Shift+Enter (newline) via dediziertem `⇧↵`-Button in der Modifier-Bar
|
||
(siehe iOS-B-02).
|
||
|
||
*Dependencies:* S-03
|
||
|
||
#### iOS-B-02 — Modifier-Bar
|
||
**MUST.** Accessory-Bar über der Tastatur:
|
||
|
||
```
|
||
[Ctrl] [Esc] [Tab] [←] [↑] [↓] [→] [⇧↵] [🎙] [📋]
|
||
```
|
||
|
||
- **Ctrl** ganz links — Sticky-Toggle: ein Tap → leuchtet → nächste
|
||
Taste wird als Ctrl+X gesendet. Beliebige Ctrl-Combos möglich
|
||
(Ctrl-C, Ctrl-D, Ctrl-L, Ctrl-U, ...).
|
||
- **Esc** — eigener Button, dauerhaft sichtbar.
|
||
- **Tab** — Autocomplete in pi.
|
||
- **Pfeiltasten** (Mitte) — History scrollen, in Menüs navigieren,
|
||
Input-Cursor bewegen.
|
||
- **`⇧↵`** — Shift+Enter, ein Tap = `\n` (newline in pi multi-line).
|
||
- **`🎙`** — Voice-Input (iOS-C-06).
|
||
- **`📋`** — Paste-Button ganz rechts (öffnet Paste-Sheet, iOS-B-08).
|
||
|
||
Bei knappem Platz (iPhone-Portrait) ist die Bar horizontal scrollbar.
|
||
|
||
*Dependencies:* iOS-B-01
|
||
|
||
#### iOS-B-03 — Long-Press-Repeat
|
||
**SHOULD.** Long-Press auf Pfeiltasten oder Backspace → repeat mit
|
||
Beschleunigung.
|
||
|
||
*Dependencies:* iOS-B-02
|
||
|
||
#### iOS-B-04 — Selection & Copy
|
||
**MUST.** Doppel-Tap → Wort. Tripel-Tap → Zeile. Long-Press + Drag →
|
||
Range. Native iOS-Copy-Menu.
|
||
|
||
*Dependencies:* iOS-A-01
|
||
|
||
#### iOS-B-05 — Pinch-Zoom Font
|
||
**SHOULD.** Pinch in der Terminal-View → Font-Size live.
|
||
|
||
*Dependencies:* iOS-A-01
|
||
|
||
#### iOS-B-06 — Hardware-Keyboard-Support
|
||
**SHOULD.** Externe iPad-Keyboards:
|
||
- Caps→Esc-Remap (optional)
|
||
- Modifier-Pass-Through (Cmd, Option, Ctrl)
|
||
- App-Shortcuts:
|
||
- Cmd-K — Clear
|
||
- Cmd-T — New session
|
||
- Cmd-1..9 — Session switch
|
||
- Cmd-F — Scrollback-Search
|
||
- Cmd-, — Settings
|
||
- Cmd-Shift-P — Slash-Command-Palette
|
||
|
||
*Dependencies:* iOS-B-01
|
||
|
||
#### iOS-B-07 — Reachability / One-Hand-Mode
|
||
**NICE.** iPhone-Querformat: Modifier-Bar gespiegelt für einhändige
|
||
Bedienung.
|
||
|
||
*Dependencies:* iOS-B-02
|
||
|
||
#### iOS-B-08 — Smart Paste (Confirm)
|
||
**SHOULD.** `📋`-Button in der Modifier-Bar zeigt Clipboard-Vorschau-
|
||
Chip ("📋 12 lines, 847 chars"). Tap → Sheet mit vollem Preview,
|
||
Insert / Cancel. Verhindert versehentliches Paste großer Blobs.
|
||
|
||
*Dependencies:* iOS-B-01
|
||
|
||
#### iOS-B-09 — Bracketed-Paste-Compliance
|
||
**SHOULD.** Client trackt im Stream `\e[?2004h` / `\e[?2004l`. Wenn
|
||
aktiv, wird bei Paste die `{type:"paste"}` Variante an S-03 geschickt,
|
||
sodass pi den ganzen Block als Paste erkennt.
|
||
|
||
*Dependencies:* S-03, iOS-B-08
|
||
|
||
### Gruppe C — Pi-aware Augmentation
|
||
|
||
#### iOS-C-01 — Status-Bar
|
||
**MUST.** Top-Bar zeigt: Connection-Status, Session-Name, Pi-State
|
||
(`● thinking` / `⏵ tool: Edit` / `▶ awaiting` / `⏸ idle`) basierend auf
|
||
S-07.
|
||
|
||
*Dependencies:* S-07
|
||
|
||
#### iOS-C-02 — Push-Notification bei Awaiting-Input
|
||
**MUST.** Wenn App im Background und Pi wechselt zu `awaiting-input`:
|
||
Push-Notification "Pi ist fertig". Tap → App öffnet in der richtigen
|
||
Session.
|
||
|
||
*Dependencies:* S-07, APNs
|
||
|
||
#### iOS-C-03 — Haptic Feedback bei State-Wechseln
|
||
**NICE.** Subtile Vibration bei `thinking → idle` oder
|
||
`thinking → awaiting-input`.
|
||
|
||
*Dependencies:* S-07
|
||
|
||
#### iOS-C-04 — Slash-Command-Palette
|
||
**SHOULD.** **Long-Press auf die Modifier-Bar** → öffnet Sheet mit
|
||
nativer Liste aller Slash-Commands (aus S-08), Fuzzy-Search. Tap →
|
||
injiziert via `send-keys`. Commands mit Argumenten → Formular-View.
|
||
|
||
*Dependencies:* S-03, S-08
|
||
|
||
#### iOS-C-05 — Voice-to-Prompt
|
||
**NICE.** `🎙`-Button → Speech-Recognition (lokal, iOS native) →
|
||
editable Preview → Send.
|
||
|
||
*Dependencies:* iOS-B-01, Mic-Permission
|
||
|
||
### Gruppe D — Session & Navigation
|
||
|
||
#### iOS-D-01 — Session-Switcher (MUST)
|
||
**MUST.** Native iOS-Liste der verfügbaren Sessions (via S-09). Spawn /
|
||
Rename / Kill direkt aus dem Switcher.
|
||
|
||
*Dependencies:* S-09
|
||
|
||
#### iOS-D-01a — Background Pre-Connect
|
||
**SHOULD.** App connectet im Hintergrund zu allen bekannten Sessions
|
||
parallel, hält pro Session einen kleinen In-Memory-Stream-Buffer +
|
||
letzten Frame. Switch = Renderer wechselt instant.
|
||
|
||
Kosten: ein Socket pro Session, ein paar MB RAM. Akzeptabel solange
|
||
< ~10 aktive Sessions.
|
||
|
||
*Dependencies:* iOS-D-01
|
||
|
||
#### iOS-D-01b — Optimistic-Switch mit Stale-Frame
|
||
**SHOULD.** Swipe zu Session B → sofort gecachten Frame zeigen,
|
||
parallel live-Sync. Niemals leerer Screen, nur kurze "sync"-Pille.
|
||
|
||
*Dependencies:* iOS-D-01, iOS-D-01a
|
||
|
||
#### iOS-D-01c — Predictive Thumbnails
|
||
**SHOULD.** Im Session-Switcher zeigt jede Session eine kleine Live-
|
||
Mini-Vorschau (z.B. 40×12 Zeichen Snapshot via `tmux capture-pane`).
|
||
Beim Öffnen des Switchers werden die Thumbnails aktualisiert.
|
||
|
||
*Dependencies:* iOS-D-01
|
||
|
||
#### iOS-D-02 — Scrollback-Search
|
||
**SHOULD.** Such-Sheet sucht im lokalen Scrollback-Cache (iOS-A-04)
|
||
mit Highlight + Jump-to-Match. Auch offline nutzbar.
|
||
|
||
*Dependencies:* iOS-A-04
|
||
|
||
### Gruppe E — Background & Lifecycle
|
||
|
||
#### iOS-E-01 — WS-Keepalive
|
||
**MUST.** Ping/Pong-Frames im Foreground halten Connection. iOS
|
||
suspended WS gerne ohne Notification.
|
||
|
||
*Dependencies:* S-02
|
||
|
||
#### iOS-E-02 — Wake-up-Sync
|
||
**MUST.** App-Foreground-Event triggert sofort Reconnect + Delta-Pull.
|
||
Spinner falls > 200ms. Ziel < 1s sichtbarer Sync (P-3).
|
||
|
||
*Dependencies:* iOS-A-02
|
||
|
||
### Gruppe F — Security
|
||
|
||
#### iOS-F-01 — Token im Keychain
|
||
**MUST.** Bearer-Token aus S-10 wird im iOS Keychain gespeichert.
|
||
|
||
*Dependencies:* S-10
|
||
|
||
#### iOS-F-02 — Face-ID / Touch-ID Gate
|
||
**SHOULD.** Biometrie-Lock vorm Öffnen der App. **Opt-in via Setting,
|
||
default off.**
|
||
|
||
*Dependencies:* —
|
||
|
||
#### iOS-F-03 — TLS-Pinning via QR-Pairing
|
||
**MUST.** Beim Pairing (S-10) wird der Cert-Fingerprint gepinnt. Jede
|
||
künftige Connection verifiziert dagegen. Re-Pairing bei Cert-Rotation.
|
||
|
||
*Dependencies:* S-10, S-11
|
||
|
||
---
|
||
|
||
## 6. Out of Scope (locked)
|
||
|
||
- **Rich Chat-Rendering.** Wir parsen den Stream nicht. ANSI bleibt ANSI.
|
||
- **Embedded Mini-Terminals / Block-Selection.** Es gibt einen Stream.
|
||
- **Multi-User-Sharing.** Solo.
|
||
- **Org/Team-Features, Cloud-Hosted-Service.** Selbstgehostet.
|
||
- **Inline-Image-Rendering** (iTerm2 protocol etc.). Eventuell später.
|
||
- **Eigenes Mosh.** tmux + WebSocket reicht.
|
||
- **Cross-platform-Clients (Android / Web).** Nur iOS nativ. Die
|
||
bestehende HTML-UI bleibt als separates Artefakt.
|
||
- **Silent-Push-Background-Wake.** iOS coalesced unzuverlässig; manueller
|
||
Wake-up-Sync (iOS-E-02) reicht.
|
||
- **Marker-Detection / Jump-to-Marker.** Pi liefert keine zuverlässigen
|
||
Marker.
|
||
- **Tap-to-Cursor.** Ohne Marker-Detection nicht robust machbar.
|
||
- **Eigener Sidecar-State-Store.** State lebt in tmux (P-6).
|
||
- **Disk-Buffer-Rotation.** Ein Cap, drüber hinaus = Daten verloren.
|
||
Snapshot funktioniert weiter.
|
||
- **Bookmarks / manuelle Marker.** Pi-interne Tools sollen das übernehmen.
|
||
- **Snippet-Library** (Prompts mit Variablen). Pi-interne Tools.
|
||
- **Tree-View / Tree-Navigation in iOS** (jeglicher Form, read-only
|
||
oder interaktiv). Tree wird ausschließlich nativ in pi bedient. Audit
|
||
hat gezeigt: Slash-Command-Dispatch ist in der ExtensionAPI nicht sauber
|
||
zugänglich; Workarounds sind die Komplexität nicht wert.
|
||
|
||
---
|
||
|
||
## 7. ExtensionAPI-Audit (abgeschlossen)
|
||
|
||
Das Audit wurde durchgeführt; Ergebnis liegt in
|
||
[`EXTENSION-API-AUDIT.md`](./EXTENSION-API-AUDIT.md).
|
||
|
||
**Kernergebnisse:**
|
||
- S-07, S-08, sowie Tree-**Read** sind out-of-the-box machbar.
|
||
- Tree-**Write** (Slash-Command-Dispatch wie `/fork`, `/checkout`,
|
||
`/new`) ist nicht sauber zugänglich → Gruppe T gestrichen (siehe
|
||
Out-of-Scope).
|
||
- Tool-Call-Daten sind vollständig verfügbar (Name, Args, Result).
|
||
|
||
Kein weiterer Spike vor Phase 1 nötig.
|
||
|
||
---
|
||
|
||
## 8. Phasen
|
||
|
||
> Phase-Aufwände bewusst weggelassen (sind in v1 gestrichen worden).
|
||
|
||
- **Spike-0 — Stream-PoC** — `pi-remote-control` um tmux pipe-pane +
|
||
WS-Stream erweitern. Verifizieren dass pi sauber in tmux läuft (kein
|
||
Crash, Alternate-Screen sauber, kein Latency-Problem).
|
||
- **Phase 1 — Sidecar production-ready** — S-01 bis S-12 (alle), S-09a
|
||
optional.
|
||
- **Phase 2 — iOS-App MVP** — Renderer (Gruppe A), Input (Gruppe B
|
||
ohne Hardware-KB), Status-Bar (iOS-C-01), Session-Switcher
|
||
(iOS-D-01 + a/b), Reconnect-Lifecycle (Gruppe E), Auth (Gruppe F).
|
||
- **Phase 3 — iOS-App Augmentation** — Slash-Palette (iOS-C-04),
|
||
Voice (iOS-C-05), Thumbnails (iOS-D-01c), Scrollback-Search
|
||
(iOS-D-02), Hardware-KB (iOS-B-06).
|
||
|
||
---
|
||
|
||
## 9. Offene Punkte für v4
|
||
|
||
- **Q-A** — pi-CLI one-shot mode für S-09a: CLI-Flags müssen verifiziert
|
||
werden. Existiert das in der heutigen pi-CLI?
|
||
- **Q-C** — APNs-Setup Details (Auth-Key-Provisioning, Token-Lifecycle).
|
||
|