635 lines
22 KiB
Markdown
635 lines
22 KiB
Markdown
# pi-remote — iOS Native App Spec (v2)
|
||
|
||
> **Status:** v2 nach Review-Runde 1.
|
||
> Review-Verlauf mit allen Diskussionen: [`SPEC-ios-app-review-v1.md`](./SPEC-ios-app-review-v1.md).
|
||
> Vor Phase 0 ist ein API-Audit nötig — siehe [Spike-0a](#spike-0a--extensionapi-audit).
|
||
|
||
---
|
||
|
||
## 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 und publiziert als
|
||
JSON-Control-Frames:
|
||
```json
|
||
{"type":"state","value":"thinking"|"tool"|"idle"|"awaiting-input",
|
||
"tool":"Edit"|"Read"|...,"ts":1234567890}
|
||
```
|
||
Realisierbarkeit hängt vom Outcome von [Spike-0a](#spike-0a--extensionapi-audit) ab.
|
||
|
||
*Dependencies:* S-01, Spike-0a
|
||
|
||
### S-08 — Slash-Command-Registry
|
||
**SHOULD.** Endpoint `/sessions/<id>/commands` liefert JSON-Liste der
|
||
verfügbaren Slash-Commands inkl. Beschreibung und Argument-Schema, aus
|
||
pi's Registry abgefragt. Dynamisch — Extensions die Commands
|
||
hinzufügen erscheinen automatisch. Realisierbarkeit hängt von Spike-0a
|
||
ab.
|
||
|
||
*Dependencies:* S-01, Spike-0a
|
||
|
||
### 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:* —
|
||
|
||
---
|
||
|
||
## 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
|
||
|
||
### Gruppe T — Tree Navigation (PENDING)
|
||
|
||
> **Status:** Pending — abhängig vom Outcome von
|
||
> [Spike-0a](#spike-0a--extensionapi-audit). Wenn pi's Tree über die
|
||
> ExtensionAPI nicht zugänglich ist, fällt diese Gruppe weg oder wird auf
|
||
> reine Slash-Command-Injection reduziert (`/fork`, `/new`, `/compact`).
|
||
|
||
#### S-13 (NEU) — Tree-State Side-Channel
|
||
**TBD.** Sidecar liefert pi's Conversation-Tree als JSON über
|
||
Side-Channel + Live-Updates bei Branch/Fork/Compact/Checkout:
|
||
|
||
```json
|
||
{
|
||
"type": "tree",
|
||
"nodes": [
|
||
{"id":"abc","parent":null,"summary":"main","msgCount":42,"createdAt":"..."},
|
||
{"id":"def","parent":"abc","summary":"explored iOS","msgCount":18}
|
||
],
|
||
"current": "def"
|
||
}
|
||
```
|
||
|
||
*Dependencies:* Spike-0a
|
||
|
||
#### iOS-T-01 — Native Tree-View
|
||
**TBD.** SwiftUI-Tree-Sheet mit allen Knoten. Tap auf Knoten →
|
||
Checkout via Slash-Command-Injection. Aktueller Knoten visuell
|
||
hervorgehoben.
|
||
|
||
*Dependencies:* S-13
|
||
|
||
#### iOS-T-02 — Branch / Fork Actions
|
||
**TBD.** Aus dem Tree-Sheet heraus `/fork`, `/new`, `/compact` als
|
||
native Buttons. Werden via Slash-Command-Injection an pi gesendet.
|
||
|
||
*Dependencies:* S-13
|
||
|
||
---
|
||
|
||
## 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.
|
||
|
||
---
|
||
|
||
## 7. Spike-0a — ExtensionAPI-Audit
|
||
|
||
**Status:** Muss vor Phase 0 abgeschlossen sein.
|
||
|
||
**Ziel:** Klären, welche der Features S-07, S-08, S-13 sowie Gruppe T
|
||
mit der heutigen pi-ExtensionAPI realisierbar sind und welche Upstream-
|
||
Erweiterungen wir brauchen.
|
||
|
||
**Output:** Markdown-Dokument `docs/EXTENSION-API-AUDIT.md`, das für
|
||
jede ExtensionAPI-Capability dokumentiert:
|
||
- API-Signatur
|
||
- Welche Events / Daten exposed sind
|
||
- Welches Spec-Feature darauf basiert
|
||
- Workaround falls API fehlt (`(pi as any)`, Slash-Injection, etc.)
|
||
- Falls Upstream-Change nötig: konkreter Vorschlag
|
||
|
||
**Konkrete Fragen:**
|
||
- Welche Lifecycle-Events liefert die ExtensionAPI?
|
||
(`thinking-start/end`, `tool-start/end`, `awaiting-input`, ...)
|
||
- Ist die Slash-Command-Registry abrufbar? In welcher Form?
|
||
- Wie ist der Conversation-Tree intern repräsentiert? Read-Access?
|
||
Subscribe? Mutations?
|
||
- Gibt es einen `pi.prompt(text)` oder Äquivalent, das Slash-Commands
|
||
korrekt dispatched?
|
||
- Welche Tool-Call-Daten sind sichtbar (Tool-Name, Argumente,
|
||
Ergebnis)?
|
||
|
||
**Nicht-Blockend:** Stream-Path (S-01–S-06) und Input (S-03) sind vom
|
||
Audit unabhängig — die können parallel oder vorab beginnen.
|
||
|
||
---
|
||
|
||
## 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).
|
||
- **Spike-0a — ExtensionAPI-Audit** — siehe oben.
|
||
- **Phase 1 — Sidecar production-ready** — S-01 bis S-06, S-09, S-10,
|
||
S-11. Optional je nach Audit: S-07, S-08, S-13.
|
||
- **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).
|
||
- **Phase 4 — Tree (conditional)** — Gruppe T, sofern Spike-0a
|
||
positiv.
|
||
|
||
---
|
||
|
||
## 9. Offene Punkte für v3
|
||
|
||
- **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-B** — Wenn Spike-0a zeigt dass S-07/S-08 nicht ohne Hack möglich:
|
||
Hack akzeptieren (`(pi as any)`) oder Upstream-Change pushen?
|
||
- **Q-C** — APNs-Setup Details (Auth-Key-Provisioning, Token-Lifecycle).
|
||
|