# ExcelRewind Companion (Windows)

A tiny local helper the ExcelRewind add-in talks to over `127.0.0.1`. It does
the few things the Office.js task pane **cannot**: enumerate the other Excel
workbooks you have open, hand their bytes to the add-in (so cross-workbook
VLOOKUP references can be resolved), and stream cell-change events for those
*other* workbooks while you record.

The pane already records your **primary** workbook itself. The Companion
records only the *others*, and is explicitly told which workbook to exclude, so
you never get double events.

This helper is **optional**. Without it, ExcelRewind still records the primary
workbook exactly as before; cross-workbook references fall back to the recorded
cell values.

---

## What it can and can't do

**Can**
- List currently-open workbooks (name, path, saved state).
- Copy an open workbook's bytes on request (`SaveCopyAs` to a temp file, up to
  100 MB) so the add-in can attach the referenced source.
- Watch `Application.SheetChange` across all open workbooks and report edits
  (value + formula) for every workbook *except* the excluded primary.

**Can't / won't**
- **Never launches Excel.** It only *attaches* to an Excel that is already
  running (`GetActiveObject`). If Excel isn't open, `excelDetected` is `false`.
- Never modifies your workbooks. Copies are read-only snapshots to a temp file
  that is deleted immediately after sending.
- Only listens on loopback (`127.0.0.1`), only accepts the ExcelRewind add-in
  origins (CORS-locked), and requires a paired token on every real endpoint.

---

## Install

1. Unzip anywhere.
2. Run in PowerShell:
   ```powershell
   .\install-companion.ps1            # install + Start-Menu shortcut, launch now
   .\install-companion.ps1 -AutoStart # also start automatically at login
   .\install-companion.ps1 -Uninstall # remove everything it installed
   ```
3. In the add-in, connect. The Companion pops a native dialog —
   **"Allow the ExcelRewind add-in to connect to the Companion?"** — click
   **Yes** once to pair. The pairing token is stored at
`%APPDATA%\ExcelRewind\`. It is picked up on next launch — no rebuild needed.

### Unsigned / SmartScreen note
The `.exe` is unsigned, so Windows SmartScreen may warn on first run
("Windows protected your PC"). Click **More info → Run anyway**. It runs
entirely on your machine and only listens on loopback. (A code-signing
certificate removes this warning; not yet applied.)

---

## How the add-in finds it

The Companion binds the first free port in **38743–38747** and answers an
unauthenticated `GET /status` with
`{product:"excelrewind-companion", version, excelDetected}`. The pane port-scans
that range and looks for that product marker. The live port is also written to
`%APPDATA%\ExcelRewind\`. It is picked up on next launch — no rebuild needed.

---

## API (loopback only)

| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET  | `/status` | none | product marker + `excelDetected` |
| POST | `/pair` | none | native confirm → `{token}` (or 403) |
| GET  | `/workspace` | bearer | open workbooks `[{name,fullName,saved}]` |
| GET  | `/file?name=Book2.xlsx` | bearer | bytes of an open workbook (404 if not open, 413 if >100 MB) |
| POST | `/record/start` `{exclude:"Primary.xlsx"}` | bearer | begin cross-workbook capture |
| POST | `/record/stop` | bearer | stop |
| GET  | `/record/events?since=<seq>` | bearer | `{events:[{seq,t,workbook,sheet,cell,value,formula}], dropped}` |

Events coalesce per cell over 500 ms; the buffer is bounded to 5000 (drop-oldest,
with a `dropped` counter). Recording auto-stops after 30 s with no
`/record/events` poll.

---

## Build from source

Requires **native** Windows Python 3.10+ (the MSYS/MinGW `python` on PATH will
NOT work — pywin32 wheels only match native `win_amd64`). Use the py launcher's
`-3.10-64`.

```powershell
.\build.ps1     # venv → deps → PyInstaller onefile → zip into the add-in origin
```

If PyInstaller is unavailable, run from source instead:

```powershell
.\run.ps1       # bootstraps .venv and runs companion.main
```

Tests (no real Excel — FakeExcel-driven, safe to run anywhere):

```powershell
.\.venv\Scripts\python.exe .\tests\test_server.py
```

---

## Risk register (implemented mitigations)

| ID | Risk | Mitigation |
|---|---|---|
| R2 | Excel not running | attach-only via `GetActiveObject`; `excelDetected:false`, never launch |
| R3 | Double events (primary counted twice) | `/record/start {exclude}` filters the primary in the SheetChange sink |
| R4 | Port collision | first free of 38743–38747 |
| R5 | Silent connection | native `MessageBoxW` pairing before any token is issued |
| R6 | File extraction failure | per-step try/except → precise 404/413/500 with reason |
| R7 | Event floods | 500 ms per-cell coalesce + bounded deque (5000, drop-oldest + counter) |
| R8 | COM single-apartment contention | one STA thread owns all COM; HTTP threads queue with 2 s timeout → 503 `excel-busy` |
| R12 | Runaway recording | auto-stop after 30 s with no poll |

All COM traffic is confined to one STA thread; every COM call is wrapped for
`com_error`, retrying `RPC_E_CALL_REJECTED` up to 3× with 200 ms backoff.

## Custom tray icon (branding)

To replace the drawn green “R” tray icon with your logo, drop a `icon.png`,
`logo.png`, or `icon.ico` next to `ExcelRewindCompanion.exe`, or in
`%APPDATA%\ExcelRewind\`. It is picked up on next launch — no rebuild needed.
