mirror of
https://github.com/dirtydishes/dreamio.git
synced 2026-06-06 13:37:24 +00:00
Merge pull request #1 from dirtydishes/lavender/wkwebview-mvp
build wkwebview mvp shell
This commit is contained in:
commit
4926024a66
21 changed files with 1360 additions and 0 deletions
70
.beads/.gitignore
vendored
Normal file
70
.beads/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Dolt database (managed by Dolt, not git)
|
||||||
|
dolt/
|
||||||
|
embeddeddolt/
|
||||||
|
|
||||||
|
# Runtime files
|
||||||
|
bd.sock
|
||||||
|
bd.sock.startlock
|
||||||
|
sync-state.json
|
||||||
|
last-touched
|
||||||
|
.exclusive-lock
|
||||||
|
|
||||||
|
# Daemon runtime (lock, log, pid)
|
||||||
|
daemon.*
|
||||||
|
|
||||||
|
# Push state (runtime, per-machine)
|
||||||
|
push-state.json
|
||||||
|
|
||||||
|
# Lock files (various runtime locks)
|
||||||
|
*.lock
|
||||||
|
|
||||||
|
# Credential key (encryption key for federation peer auth — never commit)
|
||||||
|
.beads-credential-key
|
||||||
|
|
||||||
|
# Local version tracking (prevents upgrade notification spam after git ops)
|
||||||
|
.local_version
|
||||||
|
|
||||||
|
# Worktree redirect file (contains relative path to main repo's .beads/)
|
||||||
|
# Must not be committed as paths would be wrong in other clones
|
||||||
|
redirect
|
||||||
|
|
||||||
|
# Sync state (local-only, per-machine)
|
||||||
|
# These files are machine-specific and should not be shared across clones
|
||||||
|
.sync.lock
|
||||||
|
export-state/
|
||||||
|
export-state.json
|
||||||
|
|
||||||
|
# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned)
|
||||||
|
ephemeral.sqlite3
|
||||||
|
ephemeral.sqlite3-journal
|
||||||
|
ephemeral.sqlite3-wal
|
||||||
|
ephemeral.sqlite3-shm
|
||||||
|
|
||||||
|
# Dolt server management (auto-started by bd)
|
||||||
|
dolt-server.pid
|
||||||
|
dolt-server.log
|
||||||
|
dolt-server.lock
|
||||||
|
dolt-server.port
|
||||||
|
dolt-server.activity
|
||||||
|
|
||||||
|
# Corrupt backup directories (created by bd doctor --fix recovery)
|
||||||
|
*.corrupt.backup/
|
||||||
|
|
||||||
|
# Backup data (auto-exported JSONL, local-only)
|
||||||
|
backup/
|
||||||
|
|
||||||
|
# Per-project environment file (Dolt connection config, GH#2520)
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Legacy files (from pre-Dolt versions)
|
||||||
|
*.db
|
||||||
|
*.db?*
|
||||||
|
*.db-journal
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
db.sqlite
|
||||||
|
bd.db
|
||||||
|
# NOTE: Do NOT add negation patterns here.
|
||||||
|
# They would override fork protection in .git/info/exclude.
|
||||||
|
# Config files (metadata.json, config.yaml) are tracked by git by default
|
||||||
|
# since no pattern above ignores them.
|
||||||
81
.beads/README.md
Normal file
81
.beads/README.md
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Beads - AI-Native Issue Tracking
|
||||||
|
|
||||||
|
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
||||||
|
|
||||||
|
## What is Beads?
|
||||||
|
|
||||||
|
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
||||||
|
|
||||||
|
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Essential Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create new issues
|
||||||
|
bd create "Add user authentication"
|
||||||
|
|
||||||
|
# View all issues
|
||||||
|
bd list
|
||||||
|
|
||||||
|
# View issue details
|
||||||
|
bd show <issue-id>
|
||||||
|
|
||||||
|
# Update issue status
|
||||||
|
bd update <issue-id> --claim
|
||||||
|
bd update <issue-id> --status done
|
||||||
|
|
||||||
|
# Sync with Dolt remote
|
||||||
|
bd dolt push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with Issues
|
||||||
|
|
||||||
|
Issues in Beads are:
|
||||||
|
- **Git-native**: Stored in Dolt database with version control and branching
|
||||||
|
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
||||||
|
- **Branch-aware**: Issues can follow your branch workflow
|
||||||
|
- **Always in sync**: Auto-syncs with your commits
|
||||||
|
|
||||||
|
## Why Beads?
|
||||||
|
|
||||||
|
✨ **AI-Native Design**
|
||||||
|
- Built specifically for AI-assisted development workflows
|
||||||
|
- CLI-first interface works seamlessly with AI coding agents
|
||||||
|
- No context switching to web UIs
|
||||||
|
|
||||||
|
🚀 **Developer Focused**
|
||||||
|
- Issues live in your repo, right next to your code
|
||||||
|
- Works offline, syncs when you push
|
||||||
|
- Fast, lightweight, and stays out of your way
|
||||||
|
|
||||||
|
🔧 **Git Integration**
|
||||||
|
- Automatic sync with git commits
|
||||||
|
- Branch-aware issue tracking
|
||||||
|
- Dolt-native three-way merge resolution
|
||||||
|
|
||||||
|
## Get Started with Beads
|
||||||
|
|
||||||
|
Try Beads in your own projects:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Beads
|
||||||
|
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
||||||
|
|
||||||
|
# Initialize in your repo
|
||||||
|
bd init
|
||||||
|
|
||||||
|
# Create your first issue
|
||||||
|
bd create "Try out Beads"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
||||||
|
- **Quick Start Guide**: Run `bd quickstart`
|
||||||
|
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
||||||
55
.beads/config.yaml
Normal file
55
.beads/config.yaml
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Beads Configuration File
|
||||||
|
# This file configures default behavior for all bd commands in this repository
|
||||||
|
# All settings can also be set via environment variables (BD_* prefix)
|
||||||
|
# or overridden with command-line flags
|
||||||
|
|
||||||
|
# Issue prefix for this repository (used by bd init)
|
||||||
|
# If not set, bd init will auto-detect from directory name
|
||||||
|
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
||||||
|
# issue-prefix: ""
|
||||||
|
|
||||||
|
# Use no-db mode: JSONL-only, no Dolt database
|
||||||
|
# When true, bd will use .beads/issues.jsonl as the source of truth
|
||||||
|
# no-db: false
|
||||||
|
|
||||||
|
# Enable JSON output by default
|
||||||
|
# json: false
|
||||||
|
|
||||||
|
# Feedback title formatting for mutating commands (create/update/close/dep/edit)
|
||||||
|
# 0 = hide titles, N > 0 = truncate to N characters
|
||||||
|
# output:
|
||||||
|
# title-length: 255
|
||||||
|
|
||||||
|
# Default actor for audit trails (overridden by BEADS_ACTOR or --actor)
|
||||||
|
# actor: ""
|
||||||
|
|
||||||
|
# Export events (audit trail) to .beads/events.jsonl on each flush/sync
|
||||||
|
# When enabled, new events are appended incrementally using a high-water mark.
|
||||||
|
# Use 'bd export --events' to trigger manually regardless of this setting.
|
||||||
|
# events-export: false
|
||||||
|
|
||||||
|
# Multi-repo configuration (experimental - bd-307)
|
||||||
|
# Allows hydrating from multiple repositories and routing writes to the correct database
|
||||||
|
# repos:
|
||||||
|
# primary: "." # Primary repo (where this database lives)
|
||||||
|
# additional: # Additional repos to hydrate from (read-only)
|
||||||
|
# - ~/beads-planning # Personal planning repo
|
||||||
|
# - ~/work-planning # Work planning repo
|
||||||
|
|
||||||
|
# JSONL backup (periodic export for off-machine recovery)
|
||||||
|
# Auto-enabled when a git remote exists. Override explicitly:
|
||||||
|
# backup:
|
||||||
|
# enabled: false # Disable auto-backup entirely
|
||||||
|
# interval: 15m # Minimum time between auto-exports
|
||||||
|
# git-push: false # Disable git push (export locally only)
|
||||||
|
# git-repo: "" # Separate git repo for backups (default: project repo)
|
||||||
|
|
||||||
|
# Integration settings (access with 'bd config get/set')
|
||||||
|
# Non-secret keys (stored in the database):
|
||||||
|
# - jira.url, jira.project
|
||||||
|
# - linear.team_id
|
||||||
|
# - github.org, github.repo
|
||||||
|
#
|
||||||
|
# Secret keys (stored in this file but prefer env vars to avoid git exposure):
|
||||||
|
# - linear.api_key → use LINEAR_API_KEY env var instead
|
||||||
|
# - github.token → use GITHUB_TOKEN env var instead
|
||||||
24
.beads/hooks/post-checkout
Executable file
24
.beads/hooks/post-checkout
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# --- BEGIN BEADS INTEGRATION v1.0.4 ---
|
||||||
|
# This section is managed by beads. Do not remove these markers.
|
||||||
|
if command -v bd >/dev/null 2>&1; then
|
||||||
|
export BD_GIT_HOOK=1
|
||||||
|
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout "$_bd_timeout" bd hooks run post-checkout "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
if [ $_bd_exit -eq 124 ]; then
|
||||||
|
echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bd hooks run post-checkout "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -eq 3 ]; then
|
||||||
|
echo >&2 "beads: database not initialized — skipping hook 'post-checkout'"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
|
||||||
|
fi
|
||||||
|
# --- END BEADS INTEGRATION v1.0.4 ---
|
||||||
24
.beads/hooks/post-merge
Executable file
24
.beads/hooks/post-merge
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# --- BEGIN BEADS INTEGRATION v1.0.4 ---
|
||||||
|
# This section is managed by beads. Do not remove these markers.
|
||||||
|
if command -v bd >/dev/null 2>&1; then
|
||||||
|
export BD_GIT_HOOK=1
|
||||||
|
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout "$_bd_timeout" bd hooks run post-merge "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
if [ $_bd_exit -eq 124 ]; then
|
||||||
|
echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bd hooks run post-merge "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -eq 3 ]; then
|
||||||
|
echo >&2 "beads: database not initialized — skipping hook 'post-merge'"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
|
||||||
|
fi
|
||||||
|
# --- END BEADS INTEGRATION v1.0.4 ---
|
||||||
24
.beads/hooks/pre-commit
Executable file
24
.beads/hooks/pre-commit
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# --- BEGIN BEADS INTEGRATION v1.0.4 ---
|
||||||
|
# This section is managed by beads. Do not remove these markers.
|
||||||
|
if command -v bd >/dev/null 2>&1; then
|
||||||
|
export BD_GIT_HOOK=1
|
||||||
|
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout "$_bd_timeout" bd hooks run pre-commit "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
if [ $_bd_exit -eq 124 ]; then
|
||||||
|
echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bd hooks run pre-commit "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -eq 3 ]; then
|
||||||
|
echo >&2 "beads: database not initialized — skipping hook 'pre-commit'"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
|
||||||
|
fi
|
||||||
|
# --- END BEADS INTEGRATION v1.0.4 ---
|
||||||
24
.beads/hooks/pre-push
Executable file
24
.beads/hooks/pre-push
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# --- BEGIN BEADS INTEGRATION v1.0.4 ---
|
||||||
|
# This section is managed by beads. Do not remove these markers.
|
||||||
|
if command -v bd >/dev/null 2>&1; then
|
||||||
|
export BD_GIT_HOOK=1
|
||||||
|
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout "$_bd_timeout" bd hooks run pre-push "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
if [ $_bd_exit -eq 124 ]; then
|
||||||
|
echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bd hooks run pre-push "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -eq 3 ]; then
|
||||||
|
echo >&2 "beads: database not initialized — skipping hook 'pre-push'"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
|
||||||
|
fi
|
||||||
|
# --- END BEADS INTEGRATION v1.0.4 ---
|
||||||
24
.beads/hooks/prepare-commit-msg
Executable file
24
.beads/hooks/prepare-commit-msg
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# --- BEGIN BEADS INTEGRATION v1.0.4 ---
|
||||||
|
# This section is managed by beads. Do not remove these markers.
|
||||||
|
if command -v bd >/dev/null 2>&1; then
|
||||||
|
export BD_GIT_HOOK=1
|
||||||
|
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
if [ $_bd_exit -eq 124 ]; then
|
||||||
|
echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bd hooks run prepare-commit-msg "$@"
|
||||||
|
_bd_exit=$?
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -eq 3 ]; then
|
||||||
|
echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'"
|
||||||
|
_bd_exit=0
|
||||||
|
fi
|
||||||
|
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
|
||||||
|
fi
|
||||||
|
# --- END BEADS INTEGRATION v1.0.4 ---
|
||||||
0
.beads/interactions.jsonl
Normal file
0
.beads/interactions.jsonl
Normal file
7
.beads/metadata.json
Normal file
7
.beads/metadata.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"database": "dolt",
|
||||||
|
"backend": "dolt",
|
||||||
|
"dolt_mode": "embedded",
|
||||||
|
"dolt_database": "dreamio",
|
||||||
|
"project_id": "f6ce7af2-f1c8-4f6c-b8ef-88e924f15d93"
|
||||||
|
}
|
||||||
26
.claude/settings.json
Normal file
26
.claude/settings.json
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PreCompact": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"command": "bd prime",
|
||||||
|
"type": "command"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matcher": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SessionStart": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"command": "bd prime",
|
||||||
|
"type": "command"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matcher": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
# Beads / Dolt files (added by bd init)
|
||||||
|
.dolt/
|
||||||
|
*.db
|
||||||
|
.beads-credential-key
|
||||||
96
AGENTS.md
Normal file
96
AGENTS.md
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
# Agent Instructions
|
||||||
|
|
||||||
|
This project uses **bd** (beads) for issue tracking. Run `bd prime` for full workflow context.
|
||||||
|
|
||||||
|
> **Architecture in one line:** Issues live in a local Dolt database
|
||||||
|
> (`.beads/dolt/`); cross-machine sync uses `bd dolt push/pull` (a
|
||||||
|
> git-compatible protocol), stored under `refs/dolt/data` on your git
|
||||||
|
> remote — separate from `refs/heads/*` where your code lives.
|
||||||
|
> `.beads/issues.jsonl` is a passive export, not the wire protocol.
|
||||||
|
>
|
||||||
|
> See [SYNC_CONCEPTS.md](https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md)
|
||||||
|
> for the one-screen overview and anti-patterns (don't treat JSONL as the
|
||||||
|
> source of truth; don't `bd import` during normal operation; don't
|
||||||
|
> reach for third-party Dolt hosting before trying the default).
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bd ready # Find available work
|
||||||
|
bd show <id> # View issue details
|
||||||
|
bd update <id> --claim # Claim work atomically
|
||||||
|
bd close <id> # Complete work
|
||||||
|
bd dolt push # Push beads data to remote
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non-Interactive Shell Commands
|
||||||
|
|
||||||
|
**ALWAYS use non-interactive flags** with file operations to avoid hanging on confirmation prompts.
|
||||||
|
|
||||||
|
Shell commands like `cp`, `mv`, and `rm` may be aliased to include `-i` (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input.
|
||||||
|
|
||||||
|
**Use these forms instead:**
|
||||||
|
```bash
|
||||||
|
# Force overwrite without prompting
|
||||||
|
cp -f source dest # NOT: cp source dest
|
||||||
|
mv -f source dest # NOT: mv source dest
|
||||||
|
rm -f file # NOT: rm file
|
||||||
|
|
||||||
|
# For recursive operations
|
||||||
|
rm -rf directory # NOT: rm -r directory
|
||||||
|
cp -rf source dest # NOT: cp -r source dest
|
||||||
|
```
|
||||||
|
|
||||||
|
**Other commands that may prompt:**
|
||||||
|
- `scp` - use `-o BatchMode=yes` for non-interactive
|
||||||
|
- `ssh` - use `-o BatchMode=yes` to fail instead of prompting
|
||||||
|
- `apt-get` - use `-y` flag
|
||||||
|
- `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var
|
||||||
|
|
||||||
|
<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:7510c1e2 -->
|
||||||
|
## Beads Issue Tracker
|
||||||
|
|
||||||
|
This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
|
||||||
|
|
||||||
|
### Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bd ready # Find available work
|
||||||
|
bd show <id> # View issue details
|
||||||
|
bd update <id> --claim # Claim work
|
||||||
|
bd close <id> # Complete work
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
|
||||||
|
- Run `bd prime` for detailed command reference and session close protocol
|
||||||
|
- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
|
||||||
|
|
||||||
|
**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.
|
||||||
|
|
||||||
|
## Session Completion
|
||||||
|
|
||||||
|
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||||
|
|
||||||
|
**MANDATORY WORKFLOW:**
|
||||||
|
|
||||||
|
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||||
|
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||||
|
3. **Update issue status** - Close finished work, update in-progress items
|
||||||
|
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||||
|
```bash
|
||||||
|
git pull --rebase
|
||||||
|
git push
|
||||||
|
git status # MUST show "up to date with origin"
|
||||||
|
```
|
||||||
|
5. **Clean up** - Clear stashes, prune remote branches
|
||||||
|
6. **Verify** - All changes committed AND pushed
|
||||||
|
7. **Hand off** - Provide context for next session
|
||||||
|
|
||||||
|
**CRITICAL RULES:**
|
||||||
|
- Work is NOT complete until `git push` succeeds
|
||||||
|
- NEVER stop before pushing - that leaves work stranded locally
|
||||||
|
- NEVER say "ready to push when you are" - YOU must push
|
||||||
|
- If push fails, resolve and retry until it succeeds
|
||||||
|
<!-- END BEADS INTEGRATION -->
|
||||||
70
CLAUDE.md
Normal file
70
CLAUDE.md
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Project Instructions for AI Agents
|
||||||
|
|
||||||
|
This file provides instructions and context for AI coding agents working on this project.
|
||||||
|
|
||||||
|
<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:7510c1e2 -->
|
||||||
|
## Beads Issue Tracker
|
||||||
|
|
||||||
|
This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
|
||||||
|
|
||||||
|
### Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bd ready # Find available work
|
||||||
|
bd show <id> # View issue details
|
||||||
|
bd update <id> --claim # Claim work
|
||||||
|
bd close <id> # Complete work
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
|
||||||
|
- Run `bd prime` for detailed command reference and session close protocol
|
||||||
|
- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
|
||||||
|
|
||||||
|
**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns.
|
||||||
|
|
||||||
|
## Session Completion
|
||||||
|
|
||||||
|
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||||
|
|
||||||
|
**MANDATORY WORKFLOW:**
|
||||||
|
|
||||||
|
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||||
|
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||||
|
3. **Update issue status** - Close finished work, update in-progress items
|
||||||
|
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||||
|
```bash
|
||||||
|
git pull --rebase
|
||||||
|
git push
|
||||||
|
git status # MUST show "up to date with origin"
|
||||||
|
```
|
||||||
|
5. **Clean up** - Clear stashes, prune remote branches
|
||||||
|
6. **Verify** - All changes committed AND pushed
|
||||||
|
7. **Hand off** - Provide context for next session
|
||||||
|
|
||||||
|
**CRITICAL RULES:**
|
||||||
|
- Work is NOT complete until `git push` succeeds
|
||||||
|
- NEVER stop before pushing - that leaves work stranded locally
|
||||||
|
- NEVER say "ready to push when you are" - YOU must push
|
||||||
|
- If push fails, resolve and retry until it succeeds
|
||||||
|
<!-- END BEADS INTEGRATION -->
|
||||||
|
|
||||||
|
|
||||||
|
## Build & Test
|
||||||
|
|
||||||
|
_Add your build and test commands here_
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example:
|
||||||
|
# npm install
|
||||||
|
# npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
_Add a brief overview of your project architecture_
|
||||||
|
|
||||||
|
## Conventions & Patterns
|
||||||
|
|
||||||
|
_Add your project-specific conventions here_
|
||||||
319
Dreamio.xcodeproj/project.pbxproj
Normal file
319
Dreamio.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 56;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
6F2A2B362C00100100DREAMIO /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B332C00100100DREAMIO /* AppDelegate.swift */; };
|
||||||
|
6F2A2B372C00100100DREAMIO /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B342C00100100DREAMIO /* SceneDelegate.swift */; };
|
||||||
|
6F2A2B382C00100100DREAMIO /* DreamioWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B352C00100100DREAMIO /* DreamioWebViewController.swift */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
6F2A2B302C00100100DREAMIO /* Dreamio.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Dreamio.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
6F2A2B332C00100100DREAMIO /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
6F2A2B342C00100100DREAMIO /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
6F2A2B352C00100100DREAMIO /* DreamioWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DreamioWebViewController.swift; sourceTree = "<group>"; };
|
||||||
|
6F2A2B392C00100100DREAMIO /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
6F2A2B2D2C00100100DREAMIO /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
6F2A2B272C00100100DREAMIO = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6F2A2B322C00100100DREAMIO /* Dreamio */,
|
||||||
|
6F2A2B312C00100100DREAMIO /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
6F2A2B312C00100100DREAMIO /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6F2A2B302C00100100DREAMIO /* Dreamio.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
6F2A2B322C00100100DREAMIO /* Dreamio */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6F2A2B332C00100100DREAMIO /* AppDelegate.swift */,
|
||||||
|
6F2A2B342C00100100DREAMIO /* SceneDelegate.swift */,
|
||||||
|
6F2A2B352C00100100DREAMIO /* DreamioWebViewController.swift */,
|
||||||
|
6F2A2B392C00100100DREAMIO /* Info.plist */,
|
||||||
|
);
|
||||||
|
path = Dreamio;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
6F2A2B2F2C00100100DREAMIO /* Dreamio */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 6F2A2B412C00100100DREAMIO /* Build configuration list for PBXNativeTarget "Dreamio" */;
|
||||||
|
buildPhases = (
|
||||||
|
6F2A2B2C2C00100100DREAMIO /* Sources */,
|
||||||
|
6F2A2B2D2C00100100DREAMIO /* Frameworks */,
|
||||||
|
6F2A2B2E2C00100100DREAMIO /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Dreamio;
|
||||||
|
productName = Dreamio;
|
||||||
|
productReference = 6F2A2B302C00100100DREAMIO /* Dreamio.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
6F2A2B282C00100100DREAMIO /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = 1;
|
||||||
|
LastSwiftUpdateCheck = 1600;
|
||||||
|
LastUpgradeCheck = 1600;
|
||||||
|
TargetAttributes = {
|
||||||
|
6F2A2B2F2C00100100DREAMIO = {
|
||||||
|
CreatedOnToolsVersion = 16.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 6F2A2B2B2C00100100DREAMIO /* Build configuration list for PBXProject "Dreamio" */;
|
||||||
|
compatibilityVersion = "Xcode 14.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 6F2A2B272C00100100DREAMIO;
|
||||||
|
productRefGroup = 6F2A2B312C00100100DREAMIO /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
6F2A2B2F2C00100100DREAMIO /* Dreamio */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
6F2A2B2E2C00100100DREAMIO /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
6F2A2B2C2C00100100DREAMIO /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
6F2A2B362C00100100DREAMIO /* AppDelegate.swift in Sources */,
|
||||||
|
6F2A2B372C00100100DREAMIO /* SceneDelegate.swift in Sources */,
|
||||||
|
6F2A2B382C00100100DREAMIO /* DreamioWebViewController.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
6F2A2B3A2C00100100DREAMIO /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
6F2A2B3B2C00100100DREAMIO /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
6F2A2B3E2C00100100DREAMIO /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
|
INFOPLIST_FILE = Dreamio/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 0.1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.kell.dreamio;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
6F2A2B3F2C00100100DREAMIO /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
|
INFOPLIST_FILE = Dreamio/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 0.1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.kell.dreamio;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
6F2A2B2B2C00100100DREAMIO /* Build configuration list for PBXProject "Dreamio" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
6F2A2B3A2C00100100DREAMIO /* Debug */,
|
||||||
|
6F2A2B3B2C00100100DREAMIO /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
6F2A2B412C00100100DREAMIO /* Build configuration list for PBXNativeTarget "Dreamio" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
6F2A2B3E2C00100100DREAMIO /* Debug */,
|
||||||
|
6F2A2B3F2C00100100DREAMIO /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 6F2A2B282C00100100DREAMIO /* Project object */;
|
||||||
|
}
|
||||||
19
Dreamio/AppDelegate.swift
Normal file
19
Dreamio/AppDelegate.swift
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
configurationForConnecting connectingSceneSession: UISceneSession,
|
||||||
|
options: UIScene.ConnectionOptions
|
||||||
|
) -> UISceneConfiguration {
|
||||||
|
UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||||
|
}
|
||||||
|
}
|
||||||
140
Dreamio/DreamioWebViewController.swift
Normal file
140
Dreamio/DreamioWebViewController.swift
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
final class DreamioWebViewController: UIViewController {
|
||||||
|
private enum Constants {
|
||||||
|
static let stremioWebURL = URL(string: "https://web.stremio.com/")!
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var webView: WKWebView = {
|
||||||
|
let configuration = WKWebViewConfiguration()
|
||||||
|
configuration.defaultWebpagePreferences.allowsContentJavaScript = true
|
||||||
|
configuration.allowsInlineMediaPlayback = true
|
||||||
|
configuration.mediaTypesRequiringUserActionForPlayback = []
|
||||||
|
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
|
||||||
|
|
||||||
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||||
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
webView.allowsBackForwardNavigationGestures = true
|
||||||
|
webView.customUserAgent = "Dreamio/0.1 WKWebView"
|
||||||
|
webView.navigationDelegate = self
|
||||||
|
webView.uiDelegate = self
|
||||||
|
webView.scrollView.contentInsetAdjustmentBehavior = .never
|
||||||
|
return webView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let progressView: UIProgressView = {
|
||||||
|
let view = UIProgressView(progressViewStyle: .bar)
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.tintColor = UIColor(red: 0.55, green: 0.35, blue: 0.95, alpha: 1.0)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var progressObservation: NSKeyValueObservation?
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
view.backgroundColor = .systemBackground
|
||||||
|
view.addSubview(webView)
|
||||||
|
view.addSubview(progressView)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
|
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
|
webView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||||
|
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||||
|
progressView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
|
progressView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
|
progressView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
progressObservation = webView.observe(\.estimatedProgress, options: [.new]) { [weak self] webView, _ in
|
||||||
|
self?.updateProgress(webView.estimatedProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDreamio()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadDreamio() {
|
||||||
|
let request = URLRequest(url: Constants.stremioWebURL)
|
||||||
|
webView.load(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateProgress(_ progress: Double) {
|
||||||
|
progressView.isHidden = progress >= 1.0
|
||||||
|
progressView.setProgress(Float(progress), animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showLoadFailure(_ error: Error) {
|
||||||
|
let alert = UIAlertController(
|
||||||
|
title: "Could not load Dreamio",
|
||||||
|
message: error.localizedDescription,
|
||||||
|
preferredStyle: .alert
|
||||||
|
)
|
||||||
|
alert.addAction(UIAlertAction(title: "Retry", style: .default) { [weak self] _ in
|
||||||
|
self?.loadDreamio()
|
||||||
|
})
|
||||||
|
present(alert, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DreamioWebViewController: WKNavigationDelegate {
|
||||||
|
func webView(
|
||||||
|
_ webView: WKWebView,
|
||||||
|
decidePolicyFor navigationAction: WKNavigationAction,
|
||||||
|
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
|
||||||
|
) {
|
||||||
|
guard let url = navigationAction.request.url else {
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if shouldOpenExternally(url: url, navigationType: navigationAction.navigationType) {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decisionHandler(.allow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||||
|
showLoadFailure(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||||
|
showLoadFailure(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func shouldOpenExternally(url: URL, navigationType: WKNavigationType) -> Bool {
|
||||||
|
guard let scheme = url.scheme?.lowercased() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ["http", "https"].contains(scheme) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ["mailto", "tel", "sms"].contains(scheme) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return navigationType == .linkActivated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DreamioWebViewController: WKUIDelegate {
|
||||||
|
func webView(
|
||||||
|
_ webView: WKWebView,
|
||||||
|
createWebViewWith configuration: WKWebViewConfiguration,
|
||||||
|
for navigationAction: WKNavigationAction,
|
||||||
|
windowFeatures: WKWindowFeatures
|
||||||
|
) -> WKWebView? {
|
||||||
|
if navigationAction.targetFrame == nil {
|
||||||
|
webView.load(navigationAction.request)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Dreamio/Info.plist
Normal file
38
Dreamio/Info.plist
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<false/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>Default Configuration</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>UILaunchScreen</key>
|
||||||
|
<dict/>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
20
Dreamio/SceneDelegate.swift
Normal file
20
Dreamio/SceneDelegate.swift
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
|
var window: UIWindow?
|
||||||
|
|
||||||
|
func scene(
|
||||||
|
_ scene: UIScene,
|
||||||
|
willConnectTo session: UISceneSession,
|
||||||
|
options connectionOptions: UIScene.ConnectionOptions
|
||||||
|
) {
|
||||||
|
guard let windowScene = scene as? UIWindowScene else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let window = UIWindow(windowScene: windowScene)
|
||||||
|
window.rootViewController = DreamioWebViewController()
|
||||||
|
window.makeKeyAndVisible()
|
||||||
|
self.window = window
|
||||||
|
}
|
||||||
|
}
|
||||||
34
README.md
Normal file
34
README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Dreamio
|
||||||
|
|
||||||
|
Dreamio is a minimal iOS `WKWebView` wrapper around hosted Stremio Web.
|
||||||
|
|
||||||
|
The MVP intentionally keeps native code thin. It loads `https://web.stremio.com/`
|
||||||
|
inside a UIKit host app, handles new-window navigation in the existing web view,
|
||||||
|
allows inline media playback, and leaves playback viability to real-device
|
||||||
|
testing.
|
||||||
|
|
||||||
|
## Running the MVP
|
||||||
|
|
||||||
|
1. Open `Dreamio.xcodeproj` in Xcode.
|
||||||
|
2. Select the `Dreamio` scheme.
|
||||||
|
3. Pick a real iPhone or iPad device.
|
||||||
|
4. Set a development team for code signing if Xcode asks.
|
||||||
|
5. Build and run.
|
||||||
|
|
||||||
|
The repository machine currently has Command Line Tools selected instead of full
|
||||||
|
Xcode, so command-line `xcodebuild` validation is not available here.
|
||||||
|
|
||||||
|
## MVP Validation Checklist
|
||||||
|
|
||||||
|
- Cold launch loads hosted Stremio Web.
|
||||||
|
- Login completes and persists after app relaunch.
|
||||||
|
- Catalog and library navigation work.
|
||||||
|
- Addon install or configuration flows work, including redirects or popups.
|
||||||
|
- HLS direct stream playback works.
|
||||||
|
- MP4 direct stream playback works.
|
||||||
|
- Unsupported formats fail understandably.
|
||||||
|
- Fullscreen, rotation, pause/resume, and background/foreground behavior are
|
||||||
|
acceptable for v1.
|
||||||
|
|
||||||
|
Track playback results by device, iOS version, stream protocol, container,
|
||||||
|
codec, subtitle type, HTTP status, and WebKit media error when available.
|
||||||
260
docs/turns/2026-05-24-build-wkwebview-mvp-shell.html
Normal file
260
docs/turns/2026-05-24-build-wkwebview-mvp-shell.html
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Dreamio WKWebView MVP Shell</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
--ink: #182033;
|
||||||
|
--muted: #5e6678;
|
||||||
|
--paper: #f7f4ee;
|
||||||
|
--panel: #fffdfa;
|
||||||
|
--line: #ded7ca;
|
||||||
|
--accent: #6f4fd8;
|
||||||
|
--accent-soft: #ede7ff;
|
||||||
|
--code: #282336;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--paper);
|
||||||
|
color: var(--ink);
|
||||||
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: min(920px, calc(100% - 40px));
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 56px 0 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-size: clamp(2rem, 5vw, 4rem);
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 40px 0 12px;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
max-width: 72ch;
|
||||||
|
margin: 0 0 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
max-width: 76ch;
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin: 0.35rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
pre {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: var(--code);
|
||||||
|
background: var(--accent-soft);
|
||||||
|
padding: 0.08rem 0.28rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 18px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
max-width: 760px;
|
||||||
|
padding: 22px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-fallback {
|
||||||
|
display: block;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="module">
|
||||||
|
import { FileDiff } from "https://esm.sh/@pierre/diffs";
|
||||||
|
|
||||||
|
const snippets = [
|
||||||
|
{
|
||||||
|
id: "webview-diff",
|
||||||
|
oldFile: { name: "DreamioWebViewController.swift", contents: "" },
|
||||||
|
newFile: {
|
||||||
|
name: "DreamioWebViewController.swift",
|
||||||
|
contents: `import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
final class DreamioWebViewController: UIViewController {
|
||||||
|
private enum Constants {
|
||||||
|
static let stremioWebURL = URL(string: "https://web.stremio.com/")!
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var webView: WKWebView = {
|
||||||
|
let configuration = WKWebViewConfiguration()
|
||||||
|
configuration.defaultWebpagePreferences.allowsContentJavaScript = true
|
||||||
|
configuration.allowsInlineMediaPlayback = true
|
||||||
|
configuration.mediaTypesRequiringUserActionForPlayback = []
|
||||||
|
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
|
||||||
|
return WKWebView(frame: .zero, configuration: configuration)
|
||||||
|
}()
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "readme-diff",
|
||||||
|
oldFile: { name: "README.md", contents: "" },
|
||||||
|
newFile: {
|
||||||
|
name: "README.md",
|
||||||
|
contents: `# Dreamio
|
||||||
|
|
||||||
|
Dreamio is a minimal iOS WKWebView wrapper around hosted Stremio Web.
|
||||||
|
|
||||||
|
## MVP Validation Checklist
|
||||||
|
|
||||||
|
- Cold launch loads hosted Stremio Web.
|
||||||
|
- Login completes and persists after app relaunch.
|
||||||
|
- HLS direct stream playback works.
|
||||||
|
- MP4 direct stream playback works.`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const snippet of snippets) {
|
||||||
|
const target = document.getElementById(snippet.id);
|
||||||
|
if (!target) continue;
|
||||||
|
try {
|
||||||
|
new FileDiff({ theme: "github-light" }).render({
|
||||||
|
oldFile: snippet.oldFile,
|
||||||
|
newFile: snippet.newFile,
|
||||||
|
containerWrapper: target
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
target.hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<header>
|
||||||
|
<div class="eyebrow">Repository implementation turn</div>
|
||||||
|
<h1>Dreamio WKWebView MVP shell</h1>
|
||||||
|
<p class="summary">Created the first runnable Dreamio app shape: a thin iOS UIKit host with a single <code>WKWebView</code> that loads hosted Stremio Web, handles popup-style navigation in place, allows inline media playback, and gives the user a concrete real-device validation checklist.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Summary</h2>
|
||||||
|
<p>The repository moved from planning-only files to an MVP iOS app scaffold. The app is intentionally narrow: it exists to prove whether hosted Stremio Web can support login, browsing, addon flows, and direct playback inside <code>WKWebView</code> on real iPhone and iPad hardware.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Changes Made</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Added <code>Dreamio.xcodeproj</code> with a single iOS application target.</li>
|
||||||
|
<li>Added a UIKit lifecycle with <code>AppDelegate</code> and <code>SceneDelegate</code>.</li>
|
||||||
|
<li>Added <code>DreamioWebViewController</code>, which loads <code>https://web.stremio.com/</code> in a configured <code>WKWebView</code>.</li>
|
||||||
|
<li>Enabled inline media playback, JavaScript window opening, back-forward gestures, and a small load progress indicator.</li>
|
||||||
|
<li>Added basic external URL handling and in-place handling for new-window flows.</li>
|
||||||
|
<li>Added <code>README.md</code> with run instructions and the MVP validation checklist.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Context</h2>
|
||||||
|
<p>The source plan in <code>/Users/kell/dreamio-plan.md</code> recommends starting with hosted Stremio Web before bundling local assets. This implementation follows that gate exactly: no local Stremio Web fork, no native player bridge, no torrent engine, and no App Store positioning work.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Important Implementation Details</h2>
|
||||||
|
<ul>
|
||||||
|
<li>The MVP URL is centralized in <code>DreamioWebViewController.Constants.stremioWebURL</code>.</li>
|
||||||
|
<li><code>WKUIDelegate</code> loads targetless popup requests in the existing web view so auth or addon flows do not vanish.</li>
|
||||||
|
<li>Non-HTTP user-activated links such as <code>mailto:</code>, <code>tel:</code>, and <code>sms:</code> open externally.</li>
|
||||||
|
<li>Orientation support includes portrait and landscape on iPhone, plus upside-down portrait on iPad.</li>
|
||||||
|
<li>Code signing is left automatic with an empty development team, so Xcode can prompt for the correct personal or team signing identity.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Relevant Diff Snippets</h2>
|
||||||
|
<p>The snippets below are rendered with <a href="https://diffs.com/docs">Diffs</a> when the document has network access, with plain-code fallback content retained in the page.</p>
|
||||||
|
<div id="webview-diff"></div>
|
||||||
|
<pre class="diff-fallback"><code>+++ Dreamio/DreamioWebViewController.swift
|
||||||
|
+ WKWebView configuration loads https://web.stremio.com/
|
||||||
|
+ Inline media playback is enabled.
|
||||||
|
+ Popup/new-window requests are loaded in the existing web view.
|
||||||
|
+ Basic load failure UI offers Retry.</code></pre>
|
||||||
|
<div id="readme-diff"></div>
|
||||||
|
<pre class="diff-fallback"><code>+++ README.md
|
||||||
|
+ Added Xcode run instructions.
|
||||||
|
+ Added hosted web, login, addon, HLS, MP4, fullscreen, rotation, and relaunch validation checklist.</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Expected Impact for End-Users</h2>
|
||||||
|
<p>The user can now open the project in Xcode, install it on a real iOS device, and start testing whether Stremio Web is viable inside a private Dreamio shell. The app should feel like a focused wrapper, not a rewritten media application.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Validation</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Ran <code>plutil -lint Dreamio/Info.plist</code>: passed.</li>
|
||||||
|
<li>Ran <code>plutil -lint Dreamio.xcodeproj/project.pbxproj</code>: passed.</li>
|
||||||
|
<li>Checked local Swift availability with <code>swift --version</code>: available.</li>
|
||||||
|
<li>Attempted to check Xcode build availability with <code>xcodebuild -version</code>: blocked because the active developer directory is Command Line Tools, not full Xcode.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Issues, Limitations, and Mitigations</h2>
|
||||||
|
<ul>
|
||||||
|
<li>The app has not been compiled on this machine because full Xcode is not selected. Mitigation: open the project in Xcode or switch <code>xcode-select</code> to a full Xcode install, then build on device.</li>
|
||||||
|
<li>No real-device playback gate has been passed yet. Mitigation: use the README checklist and record stream failures by protocol, container, codec, subtitles, HTTP status, and WebKit error.</li>
|
||||||
|
<li>Beads Dolt sync could not pull because no remote is configured. Mitigation: this is documented in the handoff, and the local issue was still created and updated.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Follow-up Work</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Run the app on a real iPhone and iPad, then update the validation checklist with concrete results.</li>
|
||||||
|
<li>Add a small diagnostics screen or log export if WebKit playback failures are hard to capture manually.</li>
|
||||||
|
<li>Only after hosted viability passes, pin and evaluate bundled <code>stremio-web</code> assets.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue