diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..34b8d03 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + verify: + runs-on: windows-latest + timeout-minutes: 20 + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "8.0.x" + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Run canonical source gate + shell: pwsh + run: .\scripts\test-product-flow.ps1 -Source diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index deef05d..9061ed8 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -20,6 +20,11 @@ jobs: with: dotnet-version: "8.0.x" + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + - name: Install Inno Setup shell: pwsh run: choco install innosetup --no-progress --yes diff --git a/.gitignore b/.gitignore index 1918744..0830198 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,10 @@ captures/ third_party/Windows-driver-samples/ # Local inspection / temp dumps (never publish) +scratch/ test-results/ *.user.json +driver/*-capture.png # Local secrets templates may live under docs; real secrets stay out of git .env diff --git a/README.md b/README.md index 2995eaf..23784d7 100644 --- a/README.md +++ b/README.md @@ -1,350 +1,229 @@ # VibeDeck -VibeDeck turns a spare phone or e-paper device into a private Windows work surface you can securely reach from the next room or another network: a wireless second screen, system dashboard, and AI-usage sideboard in one browser/PWA. +**A trusted second surface for your Windows work—not another tiny mirrored desktop.** -The display, dashboard data, input, and pairing authority stay on the Windows Host. iPhone, Android, and BOOX devices connect through Safari, Chrome, or an installable PWA. After explicit approval on the PC, a paired browser can reconnect through the PC's automatically assigned HTTPS address even when it is no longer on the same LAN. VibeDeck's hosted control plane routes the encrypted connection but never receives a VibeDeck account or gains the authority to approve a device; users do not need a Cloudflare account, VPN, or router port forwarding. +VibeDeck turns a spare phone, tablet, or e-paper reader into a secure Windows display, system sideboard, and AI-usage companion. One browser/PWA works across iPhone, Android, and BOOX. Pairing authority, display capture, input, and private data stay on the Windows PC. -## Product Architecture +[Download the latest Windows release](https://github.com/mabyes1/phoneMonitor/releases/latest) · [Build Week submission notes](docs/build-week-submission.md) · [Changelog](CHANGELOG.md) · [MIT License](LICENSE) -| Component | Supported product path | +| Wireless display and remote control | Phone-first information board | |---|---| -| Windows Host | Install with `VibeDeck-Setup-.exe`; it starts in the signed-in desktop session | -| Phone and e-paper clients | Safari, Chrome, or Add to Home Screen/PWA | -| Virtual display | Optional; required only for second-screen mode | -| Windows notifications | Optional packaged companion; it forwards notifications to the Host | -| Product updates | Run a newer Setup with the same AppId | -| Trusted HTTPS | Setup includes a hidden connector; VibeDeck automatically assigns and maintains the PC URL | -| Source development | Use `start.bat` or `scripts\dev-run.ps1` | +| ![VibeDeck wireless display](.codex-media/vibedeck-monitor.png) | ![VibeDeck information board](.codex-media/vibedeck-board.png) | -The Host must not run as a Windows Service. A service runs in Session 0 and cannot enumerate or capture displays belonging to the signed-in user. VibeDeck instead launches as a hidden background process in the interactive desktop session. +## Why VibeDeck -## Judge Quick Start - -VibeDeck is a Windows x64 product. A modern browser is the only requirement on iPhone, Android, and BOOX; no native mobile client is installed. - -1. **Run the product.** For a release build, run `VibeDeck-Setup-.exe`. To reproduce from source, install the .NET 8 SDK, stop any installed Host that owns ports 5000/5443, then run `start.bat`. -2. **Open the PC console.** Visit `http://127.0.0.1:5000` and use **Device setup** to view the pairing route or create the optional virtual display. -3. **Verify without physical devices.** Run `scripts\open-device-lab.ps1`, then switch among BOOX Go Color 7, Galaxy S23, and iPhone XS profiles. The lab loads the real VibeDeck client at its exact target viewport. -4. **Run the checks.** Use `scripts\test-product-flow.ps1 -Source` for source validation, or `scripts\test-product-flow.ps1 -Installed` after Setup. Add `-RequireVirtualDisplay` only when testing Display mode. - -The most complete product path is Windows Setup → browser-trusted QR pairing → explicit six-digit approval on the PC → Display, Sideboard, or Quota from the same paired browser, on the local Wi-Fi or later from another network. Sideboard and Quota do not need the optional virtual display. - -## Features - -- A real Windows virtual monitor that accepts normal desktop windows. -- A trusted remote-screen selector for viewing and controlling the PC's existing physical displays. -- Touch/mouse control plus a mobile soft-keyboard bridge for Unicode text and common Windows keys. -- Low-latency WebRTC H.264 streaming with a JPEG compatibility fallback. -- Responsive phone, tablet, and e-paper layouts from one browser/PWA client. -- Live CPU, GPU, memory, storage, network, weather, and process information. -- AI-tool usage and quota cards. -- Configurable dashboard layouts and activity updates. -- Optional Windows notification integration. -- Persistent trusted-device access across networks, without a VPN or router port forwarding. -- Local device approval remains authoritative; the cloud control plane cannot approve a phone. -- Automatic browser-trusted HTTPS without certificate installation, command windows, or a user Cloudflare account. -- Windows Setup, in-place updates, autostart, and persistent product data. - -## Showcase - -### Wireless second-screen mode - -VibeDeck streams a live Windows virtual display to an approved browser on the local network or through its secure public route. - -![VibeDeck wireless second-screen mode](.codex-media/vibedeck-monitor.png) - -### Information Board - -The same device can become a focused desktop sideboard with live system telemetry, process insights, and AI-usage information. +A spare phone is technically a screen, but shrinking a full desktop onto it is rarely useful. VibeDeck gives that screen a role that fits its size: -![VibeDeck Information Board](.codex-media/vibedeck-board.png) - -## Requirements - -For an installed build: - -- Windows 10 or Windows 11 on x64. -- A phone or e-paper device with Internet access, using the automatically assigned VibeDeck secure URL. Local Wi-Fi and private VPN routes remain available as fallbacks. -- The optional virtual display only when using second-screen mode. - -Building from source additionally requires the .NET 8 SDK. Creating the Windows installer requires Inno Setup 6. - -## Install VibeDeck - -For a complete build + install from this repository, double-click `install.bat`. It builds the canonical Setup, requests administrator permission once, installs silently, starts the Host hidden, and verifies the running product. - -Run the packaged installer: - -```text -VibeDeck-Setup-.exe -``` +| Mode | What it does | Extra hardware or setup | +|---|---|---| +| **Display** | Streams a Windows virtual display or an existing physical monitor; supports touch/mouse and mobile keyboard input | Existing-monitor control works immediately; the extended display is optional | +| **Sideboard** | Shows CPU, GPU, memory, storage, network, weather, processes, activity, and custom cards | None | +| **Quota** | Keeps Codex and AGY usage, reset windows, accounts, and remaining credits visible | Local CLI/account data on the Host PC | -Setup performs the complete product installation: +The same approved browser can move among all three roles. It can reconnect on the LAN or through its installation-specific HTTPS address without a VibeDeck account, VPN, or router port forwarding. Every new browser still requires an explicit six-digit approval on the PC. -- installs the application under `C:\Program Files\VibeDeck`; -- stores persistent product data under `%ProgramData%\VibeDeck`; -- creates Start menu and desktop shortcuts; -- configures hidden autostart in the signed-in desktop session; -- creates the firewall rules required for LAN access; -- removes obsolete VibeDeck Windows Service registrations. -- installs the verified background HTTPS connector managed by the Host. +## Judge Quick Start -After installation, open: +### Option A — product path -```text -http://127.0.0.1:5000 -``` +1. Open the [latest release](https://github.com/mabyes1/phoneMonitor/releases/latest) and download `VibeDeck-Setup-.exe` plus its `.sha256` file. +2. Run Setup on Windows 10 or 11 x64. VibeDeck starts in the signed-in desktop session. +3. Open `http://127.0.0.1:5000` on the PC. +4. Select **Device setup** to pair a real browser, or run `scripts\open-device-lab.ps1` to inspect the actual client at BOOX Go Color 7, Galaxy S23, and iPhone XS viewports without owning those devices. +5. Try **Sideboard** and **Quota** first; neither requires the optional virtual display. -### Build the installer from source +Setup may show the normal Windows publisher warning until the project has a production code-signing certificate. It does not enable test-signing mode or disable Secure Boot. -```powershell -scripts\package-windows-setup.ps1 -``` +### Option B — reproduce from source -The default version comes from `src/PhoneMonitor.Host/PhoneMonitor.Host.csproj`. To specify it explicitly: +Prerequisites: Windows 10/11 x64 and the [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0). Node.js is only required for the repository validation command. ```powershell -scripts\package-windows-setup.ps1 -Version 0.1.1 +git clone https://github.com/mabyes1/phoneMonitor.git +cd phoneMonitor +.\start.bat ``` -Output: +Then open `http://127.0.0.1:5000`. -```text -artifacts\windows-setup\VibeDeck-Setup-.exe -``` - -To build only the installation payload without compiling the Setup executable: +Run the complete source gate: ```powershell -scripts\package-windows-setup.ps1 -SkipInno +.\scripts\test-product-flow.ps1 -Source ``` -The packaging script normally runs tests, JavaScript syntax checks, product-path checks, and payload validation before producing the installer. - -## Update an Existing Installation - -Installed users update from the local PC UI: press **Check for updates**, then **Install vX.Y.Z**. VibeDeck verifies the published Setup file before handing it to the normal Windows installer; paired devices and layouts remain in `%ProgramData%\VibeDeck`. See `docs/product-updates.md` for the user and publisher flow. +No sample dataset or external account is required for the core experience. Device Lab supplies deterministic viewport and trust-state previews; live Quota cards are optional and read only the corresponding tools already used on the Host PC. -For repository development only, double-click `update.bat`. It builds a local Setup and performs the same in-place replacement and installed-product checks. Do not distribute `update.bat` to users. +## What Makes It Different -1. Build or download a newer Setup version. -2. Run it without uninstalling the existing version. -3. Setup stops the old Host, replaces application files, removes obsolete service registrations, and starts the new Host in the desktop session. -4. `%ProgramData%\VibeDeck` is preserved, including paired devices, certificates, quota accounts, custom cards, and notification settings. +- **Role-specific, not mirror-only.** A spare screen can be a real extended display, a remote-control surface, a glanceable system board, or an AI quota view. +- **One client everywhere.** Safari, Chrome, and an installable PWA share one code path across iPhone, Android, and BOOX; there is no native mobile package to install. +- **PC-controlled trust.** A public route can carry encrypted traffic, but it cannot approve a device. Pairing and revocation remain local PC decisions. +- **Built for awkward real constraints.** VibeDeck handles Windows interactive-session boundaries, WebRTC fallback, e-paper layouts, persistent state, installation, updates, diagnostics, and multilingual UI instead of stopping at a demo. +- **Useful without the driver.** Existing-monitor control, Sideboard, Quota, pairing, and Device Lab work before the optional virtual display is installed. -Verify the updated installation: +## OpenAI Build Week -```powershell -scripts\test-product-flow.ps1 -Installed -``` +VibeDeck entered OpenAI Build Week as an existing Windows virtual-display and browser-streaming prototype. Only work completed after the official submission-period cutoff is presented as Build Week work. -If the optional virtual display is installed: +### Verifiable development window -```powershell -scripts\test-product-flow.ps1 -Installed -RequireVirtualDisplay -``` +| Evidence | Value | +|---|---| +| Official cutoff | `2026-07-13 09:00 PDT` / `2026-07-14 00:00 UTC+8` | +| Pre-event baseline | [`872a985`](https://github.com/mabyes1/phoneMonitor/commit/872a985c27dbb8c486aef50b7e76a2b1c67d5f8d), committed `2026-07-13 23:52 UTC+8` | +| First eligible commit | [`21c27e3`](https://github.com/mabyes1/phoneMonitor/commit/21c27e3), committed `2026-07-14 00:02 UTC+8` | +| Core submission range | [`21c27e3..fc81cce`](https://github.com/mabyes1/phoneMonitor/compare/872a985...fc81cce) — 21 commits after the baseline | +| Primary Codex `/feedback` session | `019f6890-877f-71e0-9ffa-7cf4d4457f2a` | -These checks verify that: +### What existed before vs. what was built during Build Week -- no obsolete Host service remains; -- the Host runs outside Session 0; -- port 5000 belongs to the correct Host process; -- Windows display enumeration is coming from the interactive session; -- the PhoneMonitor virtual display is available when required. +| Before the event | Built or meaningfully extended during the event | +|---|---| +| Windows virtual-display and web-streaming prototype | Canonical Windows Setup, in-place updates, autostart, persistent product data, and release checks | +| Early browser client and dashboard experiments | One responsive/PWA product path for iPhone, Android, and BOOX, including multilingual and e-paper-specific layouts | +| LAN-oriented pairing and display flow | Explicit six-digit PC approval, persistent browser identity, revocation, managed HTTPS routing, and reconnect across networks | +| Basic display viewing | Existing-monitor selector, WebRTC H.264/JPEG fallback, touch/mouse control, and mobile Unicode keyboard bridge | +| Prototype telemetry and quota ideas | Configurable Sideboard layouts, activity, custom cards, Codex/AGY quota workflows, Device Lab, diagnostics, and regression gates | -## Connect a Phone or E-Paper Device +### How Codex and GPT-5.6 contributed -The preferred path is to open the QR code shown by the PC Host. VibeDeck automatically assigns a secure URL shaped like: +Codex was used as an engineering partner for planning, implementation, debugging, review, testing, packaging, and delivery preparation. GPT-5.6 was most valuable where several systems interacted and a locally correct change could still break the product as a whole. -```text -https://.vibedeck.pp.ua/ -``` +| Challenge | Human decision | Codex + GPT-5.6 contribution | Evidence | +|---|---|---|---| +| A Windows Service cannot capture the signed-in user's displays | Keep the Host in the interactive desktop session and make Setup the only product path | Traced the Session 0 failure, redesigned install/update/autostart behavior, and added product-flow checks | [`2824352`](https://github.com/mabyes1/phoneMonitor/commit/2824352), [`dcae485`](https://github.com/mabyes1/phoneMonitor/commit/dcae485), [`30e233e`](https://github.com/mabyes1/phoneMonitor/commit/30e233e) | +| One client had to work on phones and slow e-paper devices | Keep a single browser/PWA client instead of restoring native shells | Iterated responsive layouts, safe areas, e-paper constraints, localization, and deterministic Device Lab checks | [`cba7816`](https://github.com/mabyes1/phoneMonitor/commit/cba7816), [`ffece3c`](https://github.com/mabyes1/phoneMonitor/commit/ffece3c), [`db4c62c`](https://github.com/mabyes1/phoneMonitor/commit/db4c62c) | +| Remote access must not weaken local pairing authority | Let the cloud route traffic, never approve devices | Reviewed trust boundaries, implemented one-time connection codes and per-installation routing, then hardened pairing and reconnect behavior | [`5b65ace`](https://github.com/mabyes1/phoneMonitor/commit/5b65ace), [`012ad15`](https://github.com/mabyes1/phoneMonitor/commit/012ad15), [`c4458a8`](https://github.com/mabyes1/phoneMonitor/commit/c4458a8) | +| A small screen needed to be useful beyond mirroring | Treat Display, Sideboard, and Quota as distinct jobs | Implemented the existing-monitor selector, remote input, mobile keyboard bridge, and mobile energy/performance decisions | [`fc81cce`](https://github.com/mabyes1/phoneMonitor/commit/fc81cce) | +| A hackathon prototype still had to be testable | Prefer reproducible gates and real-device judgment over screenshots alone | Added source/payload/installed checks, worker tests, release packaging, diagnostics, and submission evidence | [`2c766f7`](https://github.com/mabyes1/phoneMonitor/commit/2c766f7), [`5b65ace`](https://github.com/mabyes1/phoneMonitor/commit/5b65ace), [`cd203d2`](https://github.com/mabyes1/phoneMonitor/commit/cd203d2) | -This browser-trusted route does not require accepting a dangerous-page warning, installing a phone certificate, opening a command window, configuring Cloudflare, joining a VPN, or forwarding a router port. The Host still requires the normal phone request, six-digit verification code, and PC **Allow** action. Once approved, that browser keeps a device-specific credential and can reconnect from another network while the Windows PC, Host, and secure connector are online. If the Internet control plane is temporarily unavailable, the UI falls back to the existing local-network HTTPS route instead of advertising a dead public URL. +Human judgment remained responsible for product scope, security trade-offs, real-device acceptance, and the final quality bar. The commit history is intentionally retained as evidence rather than squashed into a single submission commit. -The local-network fallback opens the HTTPS address shown by the PC Host, for example: +## Architecture ```text -https://192.168.1.20:5443 -``` - -On first connection: - -1. Request pairing from the phone. -2. Confirm the device name and six-digit code on the PC. -3. Select **Allow** on the PC. -4. Open Display and choose the VibeDeck extended display, the Windows primary display, or another connected screen. Touch controls the mouse; **Keyboard** opens the phone input method for the focused Windows app. -5. Switch between Display, Information Board, and Quota modes on the client. - -The phone and PC show the same explicit pairing progress: - -| Progress | Meaning | -|---:|---| -| 0–20% | Host, HTTPS address, and QR code are being prepared | -| 25% | Phone reached the Host and is waiting for **Start pairing** | -| 40% | Browser identity and the exact available device model are being read | -| 70–75% | Request and six-digit code reached the PC; waiting for **Allow** | -| 90% | Approval succeeded and the persistent credential is being saved | -| 100% | Pairing is saved, or an existing pairing was restored; the page reloads automatically | - -Pairing is attached to a persistent browser-instance ID and stored under `%ProgramData%\VibeDeck\devices`. Re-pairing the same browser continues the existing device record and rotates its credential instead of adding a duplicate. Android Chromium reports its model when available, so known devices appear as names such as `BOOX Go Color 7` and `Samsung SM-S9110`; browsers that intentionally hide the model fall back to a platform name. The secure URL assignment is persisted separately in `%ProgramData%\VibeDeck\connect` and only the local PC can change it. - -Information Board and Quota modes do not require the virtual display. iPhone, Android, and BOOX all use the same Host-served web application; responsive and e-paper styles handle platform differences. - -The managed secure URL is the normal cross-network path. Tailscale and other private-network routes remain optional alternatives described in `docs/remote-access.md`; local HTTPS details are documented in `docs/https-onboarding.md`. - -## Remote Screen and Virtual Display - -Display mode can show an existing physical Windows monitor without installing the virtual display. The source picker remembers the selected monitor in that paired browser and uses the same WebRTC H.264 stream, JPEG fallback, and input channel across local or remote networks. Standard text, Enter, Backspace, navigation keys, and common modifier shortcuts can be sent through the phone keyboard; Windows secure desktop surfaces such as UAC and Ctrl+Alt+Delete remain outside the normal signed-in session. - -Only the extended second-screen workflow requires the PhoneMonitor virtual display. - -When the PC UI reports that no virtual display is available, select **Create virtual display** and approve the Windows elevation prompt. Normal users do not need the Windows Driver Kit, test-signing mode, or driver-development scripts. - -The Host must run in the local signed-in desktop session. If `/api/displays` reports only `WinDisc 1024x768`, the Host is running in the wrong session; this is not evidence that the virtual display driver is missing. - -Driver-development tools remain under `driver/` and `scripts/*driver*.ps1`, but they are not part of the normal product installation path. - -## Windows Notification Companion - -Windows `userNotificationListener` access requires packaged application identity, so notification capture is implemented as an optional MSIX companion. It forwards notification data to the Host and must not listen on ports 5000 or 5443. - -Build and install the development package: +Approved browser / PWA + ├─ Display: WebRTC H.264 → JPEG fallback + ├─ Input: pointer + Unicode keyboard bridge + ├─ Sideboard / Quota / custom cards + └─ Pairing request + device credential + │ + HTTPS / WebSocket + │ +Windows Host (signed-in desktop session) + ├─ local PC approval and trusted-device store + ├─ DXGI display capture and Windows input + ├─ telemetry, quota readers, layouts, diagnostics + ├─ optional virtual-display installer + └─ managed connector → installation-specific HTTPS route + │ +Cloud control plane + └─ routes encrypted traffic and one-time connection codes; + it cannot approve or revoke a device +``` + +More detail: [product architecture](docs/product-architecture.md), [protocol](docs/protocol.md), [remote access](docs/remote-access.md), and [HTTPS onboarding](docs/https-onboarding.md). + +## Trust, Privacy, and Security Boundaries + +- The PC must explicitly approve each browser with a matching six-digit code. +- Device credentials are random, stored as hashes on the Host, and can be revoked from the PC. +- Public requests are accepted only through the installation's exact managed hostname and loopback connector path. +- The connector/control plane carries traffic but has no PC action token and cannot approve a device. +- VibeDeck has no cloud user account and does not upload display frames, quota data, or dashboard state to an application database. +- Quota integrations read local metadata/cache state; users are not asked to paste Codex tokens into the UI. +- Administrative actions such as virtual-display installation and product updates are local-PC-only. + +See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for bundled/downloaded components. This is an early open-source release, not a completed security audit; production code signing and further control-plane hardening remain roadmap work. + +## Install, Pair, and Use + +### Windows Setup + +Setup installs under `C:\Program Files\VibeDeck`, keeps mutable product data under `%ProgramData%\VibeDeck`, creates shortcuts and firewall rules, and starts the Host in the signed-in desktop session. Build it from source with: ```powershell -scripts\package-windows-notifications.ps1 -Install +.\scripts\package-windows-setup.ps1 ``` -If Windows requires machine-level trust for the development certificate, run from an elevated PowerShell window: - -```powershell -scripts\package-windows-notifications.ps1 -RegisterOnly -InstallCertificateMachine -``` - -The companion process is `VibeDeck.Notifications.exe`. See `docs/windows-notifications.md` for details. - -## Run from Source - -Start the project with: +The version defaults to `src/PhoneMonitor.Host/PhoneMonitor.Host.csproj`. Output: ```text -start.bat +artifacts\windows-setup\VibeDeck-Setup-.exe ``` -or: +### Pair a browser -```powershell -scripts\dev-run.ps1 -``` +1. Open the QR code shown on the PC console, or open the Host URL manually. +2. Select **Start pairing** on the phone/browser. +3. Match the six-digit code and device name on the PC. +4. Select **Allow** on the PC. +5. Switch among Display, Sideboard, and Quota. Pairings persist until revoked. -Source-development data is stored under `%LocalAppData%\PhoneMonitor`. Installed-product data is stored under `%ProgramData%\VibeDeck`. +The preferred managed URL looks like `https://.vibedeck.pp.ua/`. Local HTTPS and private-network routes remain available as fallbacks. -The source and installed Hosts cannot use port 5000 at the same time. Stop the installed Host before starting source development. The notification companion may remain running. +### Optional virtual display -Run the source product-flow checks with: +Display mode can control an existing physical monitor without a driver. To create a separate Windows extended display, select **Create virtual display** on the local PC and accept the elevation prompt. VibeDeck verifies the pinned download hash and driver signature; normal users do not need the WDK or Windows test-signing mode. -```powershell -scripts\test-product-flow.ps1 -Source -``` +## Validation -## Uninstall +Verified on Windows x64 on 2026-07-20: **59/59 .NET tests passed**, **7/7 managed-connector Worker tests passed**, all browser JavaScript and shipped PowerShell parsed successfully, and `VibeDeck-Setup-0.1.31.exe` was produced with matching `0.1.31` file/product metadata. The release workflow publishes a SHA-256 sidecar for the tagged build. -Prefer Windows **Installed apps**, or run from an elevated PowerShell window: +The source gate restores dependencies and checks: -```powershell -scripts\uninstall-windows-product.ps1 -``` - -To preserve product data: +- all .NET Release tests; +- Cloudflare Worker tests; +- every browser JavaScript file with `node --check`; +- shipped PowerShell syntax; +- canonical product paths and removed legacy clients. ```powershell -scripts\uninstall-windows-product.ps1 -KeepData +.\scripts\test-product-flow.ps1 -Source ``` -The notification companion is a separate MSIX package. Remove it with: +Build and validate the release payload: ```powershell -scripts\package-windows-notifications.ps1 -Uninstall +.\scripts\package-windows-setup.ps1 +.\scripts\test-product-flow.ps1 -Payload -PayloadPath .\artifacts\windows-setup\payload ``` -## Troubleshooting - -| Symptom | First check | -|---|---| -| PC page does not open | Start VibeDeck, then run `scripts\test-product-flow.ps1 -Installed` | -| Virtual display is installed but missing | Check the Host session; do not reinstall the driver solely because `WinDisc` appears | -| Phone cannot connect | Confirm the PC is signed in, the Host and secure connector are online, and the assigned HTTPS URL opens | -| Phone UI looks like an old app | Close obsolete clients and use Safari, Chrome, or the PWA | -| A paired phone asks to pair again | Run `scripts\test-product-flow.ps1 -Installed`, then verify `%ProgramData%\VibeDeck\devices\trusted-devices.json`; Setup grants signed-in users write access and the Host keeps a `.bak` recovery copy | -| Refresh briefly opens PowerShell | Update to the latest Setup; the local information collector is launched non-interactively with a hidden window | -| Windows notifications do not appear | Confirm that the companion is connected and allowed | -| Data appears missing after an update | Verify `%ProgramData%\VibeDeck`; do not confuse it with the development data directory | -| Quota cards have no data | Use the corresponding local CLI/account on the Host PC, then refresh the card | - -## Repository Structure - -- `src/PhoneMonitor.Host`: Windows Host, APIs, streaming, and browser/PWA client. -- `packaging/windows-setup`: canonical Windows Setup packaging. -- `packaging/windows-notifications`: optional notification companion package. -- `scripts/test-product-flow.ps1`: shared source, payload, and installed-product checks. -- `driver`: virtual display development project. -- `docs`: protocol, remote access, HTTPS, notifications, product, and release documentation. -- `AGENTS.md`: engineering constraints for future development and debugging. - -## Release Checklist +After installing: ```powershell -scripts\test-product-flow.ps1 -Source -scripts\package-windows-setup.ps1 -# Run the new Setup for a clean installation or in-place update. -scripts\test-product-flow.ps1 -Installed +.\scripts\test-product-flow.ps1 -Installed +# Add -RequireVirtualDisplay only when testing the extended-display path. ``` -See `docs/release-checklist.md` for the complete manual checklist. - -## OpenAI Build Week - -VibeDeck entered OpenAI Build Week as an existing Windows virtual-display prototype. During the submission period, it was meaningfully extended into a complete product workflow with Codex and GPT-5.6. - -Build Week work includes: - -- redesigned responsive phone and e-paper interfaces, including rotation and overlay fixes; -- a Windows Setup and upgrade path that preserves product data and starts the Host in the signed-in desktop session; -- improved virtual-display discovery and setup guidance; -- a single browser/PWA product path for iPhone, Android, and BOOX devices; -- automatic per-PC secure routing so an approved device can reconnect across networks without VPN or port-forwarding setup; -- configurable dashboard layouts, activity updates, quota cards, and optional Windows notification integration; -- installed-product and source-product flow checks for packaging and release verification. - -### Codex + GPT-5.6 evidence - -| Product decision | How Codex and GPT-5.6 accelerated the work | Verifiable result | -|---|---|---| -| Make the prototype installable | Reasoned through the signed-in desktop-session requirement, installer lifecycle, updates, and data ownership. | Windows Setup replaces app files while `%ProgramData%\VibeDeck` preserves pairings, layouts, diagnostics, and quota data. | -| Keep one phone client across devices | Iterated responsive layouts, e-paper constraints, browser-media fallbacks, and first-run pairing flows. | One browser/PWA client serves iPhone, Android, and BOOX; Device Lab validates the exact S23, iPhone XS, and BOOX viewports. | -| Turn debugging into product behavior | Planned and reviewed diagnostics, tests, product-path guardrails, and release checks. | Auditable diagnostic trail plus source, payload, and installed-product flow checks. | +The repository also contains unit/contract tests for device trust, pairing, managed connectors, public endpoints, updates, Windows input, dashboard layouts, custom sources, localization, quotas, and audit trails. -Codex was used as an engineering partner for planning, implementation, debugging, review, testing, packaging, and delivery assets. GPT-5.6 helped reason across Windows session behavior, display enumeration, browser-media constraints, mobile and e-paper layouts, and installer lifecycle. Faster model tiers handled repetitive layout and workflow passes; deeper reasoning was reserved for system design, larger refactors, and review. Human judgment remained responsible for trade-offs, real-device acceptance, and the final quality bar. +## Supported Platforms and Constraints -The project is not a generic screen-mirroring clone: VibeDeck gives the same spare device a durable role as an optional Windows display, a glanceable sideboard, or an AI quota surface—then keeps that trusted work surface available beyond the desk and beyond the local network. +- **Host:** Windows 10 or Windows 11 x64. +- **Clients:** current Safari or Chromium-based browsers; installable PWA supported. +- **Tested layouts:** iPhone XS, Galaxy S23, and BOOX Go Color 7 representative viewports; real-device checks remain the final authority. +- **Display capture:** the Host must run in the signed-in desktop session, not as a Windows Service or through an RDP display session. +- **Secure desktop:** UAC and Ctrl+Alt+Delete are intentionally outside normal remote input. +- **Internet route:** cross-network access requires the Windows PC, Host, and connector to remain online. +- **Notifications:** Windows notification capture is an optional packaged companion because the API requires package identity. -Dated commits and Codex session logs document work completed during the event. The primary Build Week Codex session ID is: +## Repository Map -```text -019f6890-877f-71e0-9ffa-7cf4d4457f2a -``` - -See [`docs/build-week-submission.md`](docs/build-week-submission.md) for the ready-to-paste Devpost copy, required submission assets, and final submission checklist. - -## Roadmap +| Path | Purpose | +|---|---| +| `src/PhoneMonitor.Host` | Windows Host, APIs, capture/input, security, telemetry, and browser/PWA client | +| `workers/vibedeck-connect-code` | Managed endpoint and one-time connection-code control plane | +| `packaging/windows-setup` | Canonical Windows installer | +| `packaging/windows-notifications` | Optional notification companion | +| `tests/PhoneMonitor.Host.Tests` | .NET unit and contract tests | +| `scripts/test-product-flow.ps1` | Source, payload, and installed-product validation | +| `driver` | Virtual-display development project; not the normal installation path | +| `docs` | Architecture, protocol, onboarding, release, and submission documentation | -- Current refactoring priorities and first-run UX acceptance criteria are documented in [`docs/technical-debt-roadmap.md`](docs/technical-debt-roadmap.md) and [`docs/ui-ux-pairing-review.md`](docs/ui-ux-pairing-review.md). -- Continue translation coverage and multilingual regression checks across newly added product flows. -- Improve adaptive stream quality and latency handling. -- Add more dashboard modules and integrations. -- Make e-paper refresh behavior configurable. -- Simplify signed distribution for non-technical users. +Useful documents: [release checklist](docs/release-checklist.md), [product updates](docs/product-updates.md), [custom data sources](docs/custom-data-sources-spec.md), and [technical debt roadmap](docs/technical-debt-roadmap.md). ## License -[MIT](LICENSE) +VibeDeck is released under the [MIT License](LICENSE). Third-party components remain under their respective licenses; see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 085121e..152eaa7 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -12,3 +12,14 @@ VibeDeck 的「建立虛擬螢幕」會在使用者明確操作後,下載並 - SHA-256: `a15557da24a9efca203158de3b43b0eaf982db231f0194031f1ed428bc13e669` 安裝器固定版本、驗證下載檔雜湊與驅動 Authenticode 簽章,驗證失敗時不會安裝。VibeDeck 不會關閉 Secure Boot,也不會開啟 Windows 測試簽章模式。 + + + +## Managed HTTPS Connector + +VibeDeck Windows Setup bundles: + +- cloudflared 2026.7.2 + - Source: https://github.com/cloudflare/cloudflared + - The packaging script pins the binary and license SHA-256 values and verifies the binary's Cloudflare, Inc. Authenticode signature. + - The upstream license text is bundled in each installation at `licenses/cloudflared-LICENSE.txt`. diff --git a/docs/build-week-submission.md b/docs/build-week-submission.md index 681a6b0..f9590f5 100644 --- a/docs/build-week-submission.md +++ b/docs/build-week-submission.md @@ -1,64 +1,97 @@ -# VibeDeck — Build Week Submission Kit +# VibeDeck — OpenAI Build Week Submission Kit -This file contains the final English copy and asset checklist for the OpenAI Build Week Devpost submission. It is written for the **Work & Productivity** category. +This is the final English source copy for the Devpost submission. Official deadline: **July 21, 2026 at 5:00 PM PDT** (**July 22 at 8:00 AM UTC+8**). ## Submission Fields -| Field | Copy | +| Field | Final copy | |---|---| | Project name | `VibeDeck` | | Category | `Work & Productivity` | -| Tagline | `Your spare screen, securely connected to your Windows workspace from anywhere.` | -| Short description | `VibeDeck turns a spare phone or BOOX into a trusted Windows work surface—wireless display, live sideboard, and AI quota view—that reconnects through one secure browser/PWA path across local or remote networks.` | +| Tagline | `A trusted second surface for your Windows work.` | +| Repository | `https://github.com/mabyes1/phoneMonitor` | +| Release/testing URL | `https://github.com/mabyes1/phoneMonitor/releases/latest` | +| Primary `/feedback` Codex Session ID | `019f6890-877f-71e0-9ffa-7cf4d4457f2a` | + +**Short description** + +> VibeDeck turns a spare phone or e-paper reader into a secure Windows display, system sideboard, and AI-usage companion through one browser/PWA—locally or across networks, with approval staying on the PC. ## Long Description ### Bring idle screens back to work -Most desks already have a second screen: an older phone, a small tablet, or an e-paper reader that is no longer central to daily work. Existing virtual-monitor tools can mirror a desktop, but a phone-sized screen is often a poor miniature desktop. It is better at a focused role: a glanceable system sideboard, an AI quota view, or a small display surface when one is actually needed. +Most desks already have another screen: an older phone, a small tablet, or an e-paper reader. Generic mirroring makes that device a cramped miniature desktop. VibeDeck gives it a role that matches its size: a real Windows display when needed, a glanceable system sideboard the rest of the time, and a persistent view of AI-tool usage. + +One Windows Host serves iPhone, Android, and BOOX through Safari, Chrome, or an installable PWA. A browser requests access, shows a six-digit code, and must be explicitly approved on the PC. Once approved, it can reconnect on the same Wi-Fi or through the installation's browser-trusted HTTPS address. There is no native mobile app, VibeDeck account, VPN, or router port-forwarding setup. -VibeDeck turns those devices into persistent companions for a Windows workstation. One Windows Host serves iPhone, Android, and BOOX through Safari, Chrome, or an installable PWA. Pair once with explicit approval on the PC, then reconnect from the same Wi-Fi or another network through an automatically assigned, browser-trusted HTTPS address. There is no native mobile app, VibeDeck account, VPN, or router port forwarding to configure. +### Three useful roles -### What VibeDeck does +- **Display:** stream a real Windows virtual display or choose an existing monitor. The approved browser receives WebRTC H.264 with a JPEG fallback and can use touch/mouse control plus its mobile keyboard. +- **Sideboard:** show live CPU, GPU, memory, storage, network, weather, processes, activity, and custom cards in a phone-first layout. +- **Quota:** keep Codex and AGY usage, reset windows, accounts, and remaining credits visible without opening another dashboard. -- **Display mode:** creates an optional, real Windows virtual monitor or securely switches to an existing physical monitor. The approved browser receives WebRTC H.264 with a JPEG compatibility fallback and can use touch/mouse control plus its mobile keyboard. -- **Sideboard mode:** shows live system telemetry, activity, and focused work context in a phone-first layout instead of shrinking the whole desktop. -- **Quota mode:** keeps Codex and AGY limits, reset windows, accounts, and remaining ChatGPT Credits visible without opening another dashboard. -- **Trusted pairing:** the PC presents a secure URL and QR code; the phone request is matched with a six-digit code and explicitly approved on the PC. Pairings persist with the browser identity. -- **Secure access across networks:** every installation can receive its own managed HTTPS route. An approved browser can reconnect away from the original LAN, while the PC remains the sole pairing authority. -- **Product behavior:** Windows Setup supports in-place updates, product data survives replaceable application files, and a diagnostic trail makes the next issue easier to locate. +Only the extended-display workflow needs the optional virtual display. Existing-monitor control, Sideboard, Quota, pairing, and Device Lab work without it. ### Why it is different -VibeDeck is not trying to replace a large second monitor or stop at generic screen mirroring. It gives a spare device a durable, role-specific place in a Windows workflow, whether that device is beside the keyboard, elsewhere in the building, or on another network. The same paired browser can become an extended display, a trusted remote-control surface for an existing monitor, a glanceable information board, or an AI usage companion. The product is designed around the awkward realities that prototypes usually skip: browser trust, explicit pairing, secure cross-network routing, signed-in Windows desktop sessions, persistent state, e-paper constraints, multilingual UI, installation, updates, and real-device verification. +VibeDeck is built around the realities that prototypes often skip: Windows interactive-session boundaries, explicit device trust, secure reconnect across networks, browser-media fallback, persistent state, installation and updates, e-paper readability, multilingual UI, diagnostics, and repeatable release checks. The cloud control plane can route encrypted traffic and resolve one-time connection codes, but it cannot approve or revoke a device; the Windows PC remains authoritative. + +### Built with Codex and GPT-5.6 + +VibeDeck existed before Build Week as a Windows virtual-display and browser-streaming prototype. The official cutoff was `2026-07-13 09:00 PDT` (`2026-07-14 00:00 UTC+8`). The last pre-event baseline is commit [`872a985`](https://github.com/mabyes1/phoneMonitor/commit/872a985c27dbb8c486aef50b7e76a2b1c67d5f8d), and the 21-commit core event range is [`21c27e3..fc81cce`](https://github.com/mabyes1/phoneMonitor/compare/872a985...fc81cce). -### Built with Codex + GPT-5.6 +During the event, Codex and GPT-5.6 helped turn the prototype into a coherent product: Windows Setup and updates, signed-in-session startup, persistent product data, one browser/PWA path across three device classes, managed HTTPS routing, hardened pairing, existing-monitor control, mobile keyboard input, e-paper and multilingual layouts, Device Lab, diagnostics, tests, packaging, and delivery assets. -Codex was the engineering partner throughout the Build Week: planning, implementation, debugging, review, test design, packaging, and final delivery preparation. GPT-5.6 helped reason about the cross-system decisions that made the prototype a usable product: the Windows interactive-session boundary, display enumeration, browser-media fallbacks, secure pairing and cross-network routing, persistent data ownership, e-paper layout constraints, and installer/update behavior. +Codex accelerated planning, implementation, debugging, review, test design, and release preparation. GPT-5.6 was used for the cross-system decisions where a local fix could break another layer: Session 0 versus interactive display capture, browser trust versus remote access, pairing authority versus cloud routing, media fallbacks, state ownership, and installer lifecycle. Human judgment owned the product scope, security trade-offs, real-device validation, and final acceptance. -The work was intentionally routed by task. Faster model tiers accelerated repetitive layout and workflow loops. Deeper reasoning was used for product planning, larger refactors, and review. Human judgment owned the actual product trade-offs, real-device validation, and the final quality bar. AI amplified a solo builder's throughput; it did not replace responsibility for the finished result. +## Testing Instructions — Paste into Devpost -### How to run and verify +> **Platform:** Windows 10 or 11 x64. The client is a current Safari or Chromium browser on any phone/tablet; a physical phone is optional for the first review. +> +> 1. Download `VibeDeck-Setup-.exe` and its `.sha256` from the latest GitHub Release. +> 2. Run Setup, then open `http://127.0.0.1:5000` on the Windows PC. +> 3. Without a phone, run `scripts\open-device-lab.ps1` from the repository. Switch among BOOX Go Color 7, Galaxy S23, and iPhone XS profiles; these load the real client at the target viewport. +> 4. With a phone, open the QR URL, select Start pairing, match the six-digit code, and approve the request on the PC. +> 5. Try Sideboard and Quota first; neither requires the optional virtual display. Display mode can control an existing monitor immediately. Creating a separate extended display is optional and requires one local elevation prompt. +> 6. Automated source verification: `scripts\test-product-flow.ps1 -Source`. Installed-product verification: `scripts\test-product-flow.ps1 -Installed`. +> +> Setup may show the standard Windows unknown-publisher warning because this early open-source release does not yet have a production code-signing certificate. The project does not disable Secure Boot or enable Windows test-signing mode. -VibeDeck runs on Windows 10 or 11 x64. Run the supplied `VibeDeck-Setup-.exe` for the product path, or install the .NET 8 SDK and run `start.bat` from this repository for source development. Visit `http://127.0.0.1:5000` to open the PC console. +## Demo Video Plan — Maximum 2:40 -The repository includes `scripts\test-product-flow.ps1 -Source` and `scripts\test-product-flow.ps1 -Installed` for product-path checks. The local Device Lab can load the real client at BOOX Go Color 7, Galaxy S23, and iPhone XS viewports, so reviewers can inspect responsive and e-paper behavior without owning all three devices. +The official requirement is a **public YouTube video under three minutes with audio** that explains both what was built and how Codex and GPT-5.6 were used. -### Notes for reviewers +| Time | Show | Narration goal | +|---:|---|---| +| 0:00–0:15 | Spare phone/BOOX beside the Windows PC | State the problem and one-line promise | +| 0:15–0:45 | QR → browser request → matching six-digit code → PC Allow | Prove the trust model and usable onboarding | +| 0:45–1:20 | Existing-monitor or virtual-display stream, touch, keyboard | Show a working non-trivial product, not slides | +| 1:20–1:45 | Sideboard and Quota on phone and e-paper layouts | Show why this is more useful than generic mirroring | +| 1:45–2:05 | Reconnect through the managed HTTPS URL or explain the route | Show cross-network value while PC approval remains authoritative | +| 2:05–2:35 | Commit range, tests/Device Lab, installer/release | Explain exactly how Codex + GPT-5.6 accelerated the Build Week extension and what remained human-owned | +| 2:35–2:40 | Product name + repository URL | End with one clear call to test it | -The Windows Host must be running in a signed-in desktop session; a Windows Service cannot capture or enumerate that user's display. For cross-network access, the PC must be online with the Host and managed connector running. Existing-monitor remote control does not require the optional virtual display; only the extended second-screen workflow does. Sideboard and Quota also work without it. Phone clients are intentionally browser/PWA-only, so the mobile path remains identical across iPhone, Android, and BOOX. Access is not public: the PC must explicitly approve each browser, and paired devices can be revoked from the PC. +Do not include copyrighted music, personal account details, unsafe QR codes, reusable device credentials, or local IP addresses in the uploaded video. -## Attach Before Submitting +## Final Human Checklist -- [ ] Public YouTube URL for the V9 demo video (under three minutes, with audio that explains both Codex and GPT-5.6 use). -- [ ] Public repository URL, or a private repository shared with `testing@devpost.com` and `build-week-event@openai.com`. -- [ ] `/feedback` Codex Session ID: `019f6890-877f-71e0-9ffa-7cf4d4457f2a`. -- [ ] Optional companion PDF upload: `VibeDeck-Build-Week-Companion-Book-v8-bilingual.pdf`. -- [ ] Confirm that the uploaded video, PDF, screenshots, and repository contain no personal account details, local IP addresses, unsafe QR code, or third-party material without permission. +### Required before clicking Submit -## Prepared Local Assets +- [ ] Register/join OpenAI Build Week on Devpost and confirm eligibility/team representation. +- [ ] Merge and push the final submission branch to the public repository. +- [ ] Tag the exact tested commit (for example `v0.1.31`) and verify GitHub Release contains the Setup and `.sha256` assets. +- [ ] Download the release assets from GitHub—not the local build folder—and smoke-test them on Windows. +- [ ] Upload a public YouTube video under three minutes; verify it plays while signed out and contains audible Codex + GPT-5.6 explanation. +- [ ] Add the public YouTube URL to Devpost. +- [ ] Select **Work & Productivity**. +- [ ] Paste the repository, release/testing URL, short/long description, and testing instructions. +- [ ] Paste `/feedback` Session ID `019f6890-877f-71e0-9ffa-7cf4d4457f2a`. +- [ ] Confirm the submitted repo/video/screenshots contain no PII, secrets, unsafe QR codes, or unlicensed music/assets. +- [ ] Submit before **July 21, 2026 5:00 PM PDT / July 22 8:00 AM UTC+8**. -These files are prepared locally and must be uploaded separately because `artifacts/` is intentionally ignored by Git: +### Recommended final evidence -- `artifacts\hackathon-trailer\v8\out\VibeDeck-Build-Week-Demo-v9.mp4` -- `artifacts\hackathon-trailer\v8\companion-book\out\VibeDeck-Build-Week-Companion-Book-v8-bilingual.pdf` +- [ ] Record the final .NET test count, Worker test count, and installer smoke result in the submission notes. +- [ ] Keep the baseline/compare links visible in README so judges can distinguish pre-event work. +- [ ] Confirm the release remains freely downloadable through the end of judging. diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 3498985..61a57e0 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -10,9 +10,10 @@ scripts\test-product-flow.ps1 -Source 必須通過: -- Release 單元測試。 +- Release 單元測試(命令會先 restore,乾淨 runner 不得以零測試假綠)。 +- Managed connector Worker 測試。 - 所有 Web JavaScript 語法檢查。 -- 安裝/更新 PowerShell 語法檢查。 +- 安裝/更新與 payload 內 PowerShell 語法檢查。 - 不存在原生手機 App、portable ZIP 或 Host Windows Service 產品路徑。 ## 2. 建立唯一正式安裝包 @@ -26,7 +27,7 @@ scripts\package-windows-setup.ps1 或指定新版本: ```powershell -scripts\package-windows-setup.ps1 -Version 0.1.1 +scripts\package-windows-setup.ps1 -Version 0.1.31 ``` 確認 `artifacts\windows-setup\VibeDeck-Setup-.exe` 已建立。打包腳本會再次驗證 staged payload。 diff --git a/docs/screenshots/01-display-stream.png b/docs/screenshots/01-display-stream.png deleted file mode 100644 index 367044f..0000000 Binary files a/docs/screenshots/01-display-stream.png and /dev/null differ diff --git a/docs/screenshots/02-device-connect.png b/docs/screenshots/02-device-connect.png deleted file mode 100644 index 2da02d8..0000000 Binary files a/docs/screenshots/02-device-connect.png and /dev/null differ diff --git a/docs/screenshots/03-sideboard.jpg b/docs/screenshots/03-sideboard.jpg deleted file mode 100644 index 4a37c2d..0000000 Binary files a/docs/screenshots/03-sideboard.jpg and /dev/null differ diff --git a/docs/screenshots/04-sideboard-command.jpg b/docs/screenshots/04-sideboard-command.jpg deleted file mode 100644 index 7197e37..0000000 Binary files a/docs/screenshots/04-sideboard-command.jpg and /dev/null differ diff --git a/docs/screenshots/05-boox-eink.jpg b/docs/screenshots/05-boox-eink.jpg deleted file mode 100644 index a592f9d..0000000 Binary files a/docs/screenshots/05-boox-eink.jpg and /dev/null differ diff --git a/docs/screenshots/app-icon.png b/docs/screenshots/app-icon.png deleted file mode 100644 index 9b235a5..0000000 Binary files a/docs/screenshots/app-icon.png and /dev/null differ diff --git a/driver/display10-capture.png b/driver/display10-capture.png deleted file mode 100644 index 98d9e36..0000000 Binary files a/driver/display10-capture.png and /dev/null differ diff --git a/packaging/windows-setup/VibeDeck.iss b/packaging/windows-setup/VibeDeck.iss index 5a4bc7a..690198e 100644 --- a/packaging/windows-setup/VibeDeck.iss +++ b/packaging/windows-setup/VibeDeck.iss @@ -2,7 +2,7 @@ ; Built by scripts\package-windows-setup.ps1 #ifndef MyAppVersion - #define MyAppVersion "0.1.0" + #define MyAppVersion "0.1.31" #endif #ifndef MyPayloadDir diff --git a/scratch/DxgiTest.cs b/scratch/DxgiTest.cs deleted file mode 100644 index ec1e89a..0000000 --- a/scratch/DxgiTest.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Diagnostics; -using System.Drawing; -using SharpDX.Direct3D11; -using SharpDX.DXGI; -using Device = SharpDX.Direct3D11.Device; - -namespace DxgiTest -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Starting DXGI Desktop Duplication Diagnostic Test..."); - - string deviceName = "\\\\.\\DISPLAY1"; - if (args.Length > 0) - { - deviceName = args[0]; - } - - Console.WriteLine($"Target Display: {deviceName}"); - - try - { - using (var factory = new Factory1()) - { - Adapter1 selectedAdapter = null; - Output selectedOutput = null; - - foreach (var adapter in factory.Adapters1) - { - foreach (var output in adapter.Outputs) - { - Console.WriteLine($"Found display: {output.Description.DeviceName} ({output.Description.DesktopBounds.Width}x{output.Description.DesktopBounds.Height})"); - if (string.Equals(output.Description.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase)) - { - selectedAdapter = adapter; - selectedOutput = output; - } - } - } - - if (selectedOutput == null) - { - if (factory.Adapters1.Length > 0 && factory.Adapters1[0].Outputs.Length > 0) - { - Console.WriteLine($"Display {deviceName} not found. Falling back to default display {factory.Adapters1[0].Outputs[0].Description.DeviceName}"); - selectedAdapter = factory.Adapters1[0]; - selectedOutput = factory.Adapters1[0].Outputs[0]; - } - else - { - Console.WriteLine("Error: No displays/adapters found."); - return; - } - } - - using (var d3dDevice = new Device(selectedAdapter, DeviceCreationFlags.None, SharpDX.Direct3D.FeatureLevel.Level_11_0)) - using (var output1 = selectedOutput.QueryInterface()) - using (var duplication = output1.DuplicateOutput(d3dDevice)) - { - Console.WriteLine("DXGI Desktop Duplication initialized successfully!"); - Console.WriteLine("Running 5-second capture loop... Move your mouse or open a window to trigger screen updates."); - - int successCount = 0; - int timeoutCount = 0; - int otherCount = 0; - var stopwatch = Stopwatch.StartNew(); - - while (stopwatch.ElapsedMilliseconds < 5000) - { - var result = duplication.TryAcquireNextFrame(10, out var frameInfo, out var resource); - if (result.Success) - { - successCount++; - resource.Dispose(); - duplication.ReleaseFrame(); - } - else if (result.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) - { - timeoutCount++; - } - else - { - otherCount++; - } - System.Threading.Thread.Sleep(16); // Simulate ~60fps polling - } - - Console.WriteLine("\n--- Diagnostic Results ---"); - Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms"); - Console.WriteLine($"Successful frames captured: {successCount}"); - Console.WriteLine($"Timeout frames (no change): {timeoutCount}"); - Console.WriteLine($"Other failures: {otherCount}"); - - if (successCount == 0) - { - Console.WriteLine("\nWARNING: Captured 0 frames. DXGI Desktop Duplication is NOT receiving screen updates on this display."); - } - else - { - Console.WriteLine("\nSUCCESS: DXGI Desktop Duplication is working perfectly."); - } - } - } - } - catch (Exception ex) - { - Console.WriteLine($"\nDXGI Initialization Failed: {ex.Message}"); - Console.WriteLine(ex.StackTrace); - } - } - } -} diff --git a/scratch/cdp-eval.js b/scratch/cdp-eval.js deleted file mode 100644 index 57ca716..0000000 --- a/scratch/cdp-eval.js +++ /dev/null @@ -1,46 +0,0 @@ -// node cdp-eval.js — prints eval result JSON -const http = require("http"); -const [, , url, w = "844", h = "390", waitMs = "5000", mobile = "1", evalJs = "1"] = process.argv; -const CHROME = "C:/Program Files/Google/Chrome/Application/chrome.exe"; -const PORT = 9335; -function jget(path) { - return new Promise((resolve, reject) => { - http.get({ host: "127.0.0.1", port: PORT, path }, (res) => { - let d = ""; res.on("data", (c) => (d += c)); res.on("end", () => resolve(JSON.parse(d))); - }).on("error", reject); - }); -} -const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); -(async () => { - const { spawn } = require("child_process"); - const chrome = spawn(CHROME, [ - "--headless=new", "--disable-gpu", "--no-sandbox", "--ignore-certificate-errors", - `--remote-debugging-port=${PORT}`, `--user-data-dir=${process.env.TEMP}/chrome-cdp-${Date.now()}`, "about:blank", - ], { stdio: "ignore" }); - try { - let targets = null; - for (let i = 0; i < 40; i++) { await sleep(250); try { targets = await jget("/json/list"); break; } catch {} } - const page = targets.find((t) => t.type === "page"); - const ws = new WebSocket(page.webSocketDebuggerUrl); - let id = 0; const pending = new Map(); - const send = (method, params = {}) => new Promise((resolve) => { - const mid = ++id; pending.set(mid, { resolve }); - ws.send(JSON.stringify({ id: mid, method, params })); - }); - ws.onmessage = (ev) => { - const m = JSON.parse(ev.data); - if (m.id && pending.has(m.id)) { pending.get(m.id).resolve(m.result); pending.delete(m.id); } - }; - await new Promise((r) => (ws.onopen = r)); - if (mobile === "1") { - await send("Emulation.setDeviceMetricsOverride", { width: +w, height: +h, deviceScaleFactor: 2, mobile: true }); - await send("Emulation.setUserAgentOverride", { userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" }); - } else { - await send("Emulation.setDeviceMetricsOverride", { width: +w, height: +h, deviceScaleFactor: 1, mobile: false }); - } - await send("Page.navigate", { url }); - await sleep(+waitMs); - const r = await send("Runtime.evaluate", { expression: evalJs, returnByValue: true }); - console.log(JSON.stringify(r.result.value ?? r.result, null, 1)); - } finally { chrome.kill("SIGKILL"); } -})().catch((e) => { console.error(e); process.exit(1); }); diff --git a/scratch/shot-click.js b/scratch/shot-click.js deleted file mode 100644 index 2fe919d..0000000 --- a/scratch/shot-click.js +++ /dev/null @@ -1,59 +0,0 @@ -// CDP: navigate, optionally evaluate JS (e.g. click), then screenshot. -// node shot-click.js -const http = require("http"); -const [, , url, outfile, w = "390", h = "844", waitMs = "4000", mobile = "1", evalJs = ""] = process.argv; -const CHROME = "C:/Program Files/Google/Chrome/Application/chrome.exe"; -const PORT = 9334; -function jget(path) { - return new Promise((resolve, reject) => { - http.get({ host: "127.0.0.1", port: PORT, path }, (res) => { - let d = ""; res.on("data", (c) => (d += c)); res.on("end", () => resolve(JSON.parse(d))); - }).on("error", reject); - }); -} -const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); -(async () => { - const { spawn } = require("child_process"); - const chrome = spawn(CHROME, [ - "--headless=new", "--disable-gpu", "--no-sandbox", "--hide-scrollbars", - "--ignore-certificate-errors", `--remote-debugging-port=${PORT}`, - `--user-data-dir=${process.env.TEMP}/chrome-cdp-${Date.now()}`, "about:blank", - ], { stdio: "ignore" }); - try { - let targets = null; - for (let i = 0; i < 40; i++) { await sleep(250); try { targets = await jget("/json/list"); break; } catch {} } - const page = targets.find((t) => t.type === "page"); - const ws = new WebSocket(page.webSocketDebuggerUrl); - let id = 0; const pending = new Map(); - const send = (method, params = {}) => new Promise((resolve) => { - const mid = ++id; pending.set(mid, { resolve }); - ws.send(JSON.stringify({ id: mid, method, params })); - }); - ws.onmessage = (ev) => { - const m = JSON.parse(ev.data); - if (m.id && pending.has(m.id)) { pending.get(m.id).resolve(m.result); pending.delete(m.id); } - }; - await new Promise((r) => (ws.onopen = r)); - await send("Page.enable"); - if (mobile === "1") { - await send("Emulation.setDeviceMetricsOverride", { width: +w, height: +h, deviceScaleFactor: 2, mobile: true }); - await send("Emulation.setUserAgentOverride", { userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" }); - } else { - await send("Emulation.setDeviceMetricsOverride", { width: +w, height: +h, deviceScaleFactor: 1, mobile: false }); - } - await send("Page.navigate", { url }); - await sleep(+waitMs); - if (evalJs) { - await send("Runtime.evaluate", { expression: evalJs, returnByValue: true }); - await sleep(1500); - } - const shot = await send("Page.captureScreenshot", { format: "png" }); - require("fs").writeFileSync(outfile, Buffer.from(shot.data, "base64")); - console.log("saved", outfile); - const m = await send("Runtime.evaluate", { - expression: `JSON.stringify({bodyClass:document.body.className,switchVisible:getComputedStyle(document.querySelector('.dashboard-mode-switch')||document.body).display,connVisible:getComputedStyle(document.querySelector('[data-eink-connection-state]')||document.body).display,topFs:getComputedStyle(document.getElementById('fullscreen')||document.body).display,cardFs:getComputedStyle(document.getElementById('mobileFullscreen')||document.body).display})`, - returnByValue: true, - }); - console.log("metrics", m.result.value); - } finally { chrome.kill("SIGKILL"); } -})().catch((e) => { console.error(e); process.exit(1); }); diff --git a/scratch/shot.js b/scratch/shot.js deleted file mode 100644 index f385461..0000000 --- a/scratch/shot.js +++ /dev/null @@ -1,78 +0,0 @@ -// CDP screenshot tool: node shot.js [mobile] -const http = require("http"); - -const [, , url, outfile, w = "390", h = "844", waitMs = "4000", mobile = "1"] = process.argv; -const CHROME = "C:/Program Files/Google/Chrome/Application/chrome.exe"; -const PORT = 9333; - -function jget(path) { - return new Promise((resolve, reject) => { - http.get({ host: "127.0.0.1", port: PORT, path }, (res) => { - let data = ""; - res.on("data", (c) => (data += c)); - res.on("end", () => resolve(JSON.parse(data))); - }).on("error", reject); - }); -} -const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); - -(async () => { - const { spawn } = require("child_process"); - const args = [ - "--headless=new", "--disable-gpu", "--no-sandbox", "--hide-scrollbars", - "--ignore-certificate-errors", - `--remote-debugging-port=${PORT}`, - `--user-data-dir=${process.env.TEMP}/chrome-cdp-${Date.now()}`, - "about:blank", - ]; - const chrome = spawn(CHROME, args, { stdio: "ignore" }); - try { - let targets = null; - for (let i = 0; i < 40; i++) { - await sleep(250); - try { targets = await jget("/json/list"); break; } catch {} - } - const page = targets.find((t) => t.type === "page"); - const ws = new WebSocket(page.webSocketDebuggerUrl); - let id = 0; - const pending = new Map(); - const send = (method, params = {}) => - new Promise((resolve) => { - const mid = ++id; - pending.set(mid, { resolve }); - ws.send(JSON.stringify({ id: mid, method, params })); - }); - ws.onmessage = (ev) => { - const msg = JSON.parse(ev.data); - if (msg.id && pending.has(msg.id)) { - pending.get(msg.id).resolve(msg.result); - pending.delete(msg.id); - } - }; - await new Promise((r) => (ws.onopen = r)); - await send("Page.enable"); - if (mobile === "1") { - await send("Emulation.setDeviceMetricsOverride", { - width: +w, height: +h, deviceScaleFactor: 2, mobile: true, - }); - await send("Emulation.setUserAgentOverride", { - userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1", - }); - await send("Emulation.setTouchEmulationEnabled", { enabled: true }); - } else { - await send("Emulation.setDeviceMetricsOverride", { width: +w, height: +h, deviceScaleFactor: 1, mobile: false }); - } - await send("Page.navigate", { url }); - await sleep(+waitMs); - const shot = await send("Page.captureScreenshot", { format: "png" }); - require("fs").writeFileSync(outfile, Buffer.from(shot.data, "base64")); - console.log("saved", outfile); - const m = await send("Runtime.evaluate", { - expression: `JSON.stringify({sw:document.documentElement.scrollWidth,iw:window.innerWidth,bodyClass:document.body.className,overflow:document.documentElement.scrollWidth>window.innerWidth})`, - returnByValue: true, - }); - console.log("metrics", m.result.value); - } finally { - chrome.kill("SIGKILL"); - } -})().catch((e) => { console.error(e); process.exit(1); }); diff --git a/scratch/v9-final-review/accurate-t122.png b/scratch/v9-final-review/accurate-t122.png deleted file mode 100644 index b762c85..0000000 Binary files a/scratch/v9-final-review/accurate-t122.png and /dev/null differ diff --git a/scratch/v9-final-review/accurate-t124.png b/scratch/v9-final-review/accurate-t124.png deleted file mode 100644 index e2a4278..0000000 Binary files a/scratch/v9-final-review/accurate-t124.png and /dev/null differ diff --git a/scratch/v9-final-review/accurate-t125.png b/scratch/v9-final-review/accurate-t125.png deleted file mode 100644 index c9eaebe..0000000 Binary files a/scratch/v9-final-review/accurate-t125.png and /dev/null differ diff --git a/scratch/v9-final-review/accurate-t126.png b/scratch/v9-final-review/accurate-t126.png deleted file mode 100644 index 5039e18..0000000 Binary files a/scratch/v9-final-review/accurate-t126.png and /dev/null differ diff --git a/scratch/v9-final-review/contact-sheet.png b/scratch/v9-final-review/contact-sheet.png deleted file mode 100644 index 96c39b5..0000000 Binary files a/scratch/v9-final-review/contact-sheet.png and /dev/null differ diff --git a/scratch/v9-final-review/device-lab-clip-sheet.png b/scratch/v9-final-review/device-lab-clip-sheet.png deleted file mode 100644 index 5d17b04..0000000 Binary files a/scratch/v9-final-review/device-lab-clip-sheet.png and /dev/null differ diff --git a/scratch/v9-final-review/end-sequence-accurate.png b/scratch/v9-final-review/end-sequence-accurate.png deleted file mode 100644 index 72a2bb5..0000000 Binary files a/scratch/v9-final-review/end-sequence-accurate.png and /dev/null differ diff --git a/scratch/v9-final-review/end.png b/scratch/v9-final-review/end.png deleted file mode 100644 index 2c41ea1..0000000 Binary files a/scratch/v9-final-review/end.png and /dev/null differ diff --git a/scratch/v9-final-review/recheck-end.png b/scratch/v9-final-review/recheck-end.png deleted file mode 100644 index c9eaebe..0000000 Binary files a/scratch/v9-final-review/recheck-end.png and /dev/null differ diff --git a/scratch/v9-final-review/recheck-t110.png b/scratch/v9-final-review/recheck-t110.png deleted file mode 100644 index bf4bcd6..0000000 Binary files a/scratch/v9-final-review/recheck-t110.png and /dev/null differ diff --git a/scratch/v9-final-review/recheck-t6.png b/scratch/v9-final-review/recheck-t6.png deleted file mode 100644 index c77563b..0000000 Binary files a/scratch/v9-final-review/recheck-t6.png and /dev/null differ diff --git a/scratch/v9-final-review/start.png b/scratch/v9-final-review/start.png deleted file mode 100644 index 2b4c4d3..0000000 Binary files a/scratch/v9-final-review/start.png and /dev/null differ diff --git a/scratch/v9-final-review/t110.png b/scratch/v9-final-review/t110.png deleted file mode 100644 index 1ac0187..0000000 Binary files a/scratch/v9-final-review/t110.png and /dev/null differ diff --git a/scratch/v9-final-review/t124.png b/scratch/v9-final-review/t124.png deleted file mode 100644 index 6e2f0cb..0000000 Binary files a/scratch/v9-final-review/t124.png and /dev/null differ diff --git a/scratch/v9-final-review/t14.png b/scratch/v9-final-review/t14.png deleted file mode 100644 index 97b5d3d..0000000 Binary files a/scratch/v9-final-review/t14.png and /dev/null differ diff --git a/scratch/v9-final-review/t2.png b/scratch/v9-final-review/t2.png deleted file mode 100644 index 03b8b24..0000000 Binary files a/scratch/v9-final-review/t2.png and /dev/null differ diff --git a/scratch/v9-final-review/t30.png b/scratch/v9-final-review/t30.png deleted file mode 100644 index f8f27f7..0000000 Binary files a/scratch/v9-final-review/t30.png and /dev/null differ diff --git a/scratch/v9-final-review/t4.png b/scratch/v9-final-review/t4.png deleted file mode 100644 index 2392b73..0000000 Binary files a/scratch/v9-final-review/t4.png and /dev/null differ diff --git a/scratch/v9-final-review/t46.png b/scratch/v9-final-review/t46.png deleted file mode 100644 index 2856e4a..0000000 Binary files a/scratch/v9-final-review/t46.png and /dev/null differ diff --git a/scratch/v9-final-review/t6.png b/scratch/v9-final-review/t6.png deleted file mode 100644 index 8e4870b..0000000 Binary files a/scratch/v9-final-review/t6.png and /dev/null differ diff --git a/scratch/v9-final-review/t62.png b/scratch/v9-final-review/t62.png deleted file mode 100644 index 07328f9..0000000 Binary files a/scratch/v9-final-review/t62.png and /dev/null differ diff --git a/scratch/v9-final-review/t78.png b/scratch/v9-final-review/t78.png deleted file mode 100644 index ed198c2..0000000 Binary files a/scratch/v9-final-review/t78.png and /dev/null differ diff --git a/scratch/v9-final-review/t94.png b/scratch/v9-final-review/t94.png deleted file mode 100644 index 6eeec29..0000000 Binary files a/scratch/v9-final-review/t94.png and /dev/null differ diff --git a/scratch/v9-final-review/v9-t110-buildweek.png b/scratch/v9-final-review/v9-t110-buildweek.png deleted file mode 100644 index 8a86489..0000000 Binary files a/scratch/v9-final-review/v9-t110-buildweek.png and /dev/null differ diff --git a/scratch/v9-final-review/v9-t16-subtitle.png b/scratch/v9-final-review/v9-t16-subtitle.png deleted file mode 100644 index 4627045..0000000 Binary files a/scratch/v9-final-review/v9-t16-subtitle.png and /dev/null differ diff --git a/scratch/v9-final-review/v9-t18-subtitle.png b/scratch/v9-final-review/v9-t18-subtitle.png deleted file mode 100644 index 6564d32..0000000 Binary files a/scratch/v9-final-review/v9-t18-subtitle.png and /dev/null differ diff --git a/scratch/v9-final-review/v9-t80-locales.png b/scratch/v9-final-review/v9-t80-locales.png deleted file mode 100644 index 44fcad5..0000000 Binary files a/scratch/v9-final-review/v9-t80-locales.png and /dev/null differ diff --git a/scripts/test-product-flow.ps1 b/scripts/test-product-flow.ps1 index 8cfd3f2..c275050 100644 --- a/scripts/test-product-flow.ps1 +++ b/scripts/test-product-flow.ps1 @@ -27,7 +27,7 @@ function Write-Check([string]$message) { if ($Source) { Write-Check "Release tests" - & dotnet test $solution -c Release --no-restore + & dotnet test $solution -c Release if ($LASTEXITCODE -ne 0) { throw "dotnet test failed." } Write-Check "Browser JavaScript syntax" @@ -38,6 +38,17 @@ if ($Source) { if ($LASTEXITCODE -ne 0) { throw "JavaScript syntax check failed: $($_.FullName)" } } + Write-Check "Managed connector Worker tests" + $workerRoot = Join-Path $repoRoot "workers\vibedeck-connect-code" + Push-Location $workerRoot + try { + & $node.Source --test + if ($LASTEXITCODE -ne 0) { throw "Managed connector Worker tests failed." } + } + finally { + Pop-Location + } + Write-Check "Product PowerShell syntax" foreach ($relative in @( "scripts\install-windows-product.ps1", @@ -45,7 +56,8 @@ if ($Source) { "scripts\uninstall-windows-product.ps1", "scripts\package-windows-setup.ps1", "scripts\package-windows-notifications.ps1", - "scripts\test-product-flow.ps1" + "scripts\test-product-flow.ps1", + "src\PhoneMonitor.Host\Installers\install-virtual-display.ps1" )) { $path = Join-Path $repoRoot $relative $tokens = $null