Metadata-Version: 2.5
Name: vibe-saver
Version: 0.2.2
Summary: Recover a Power Apps Vibe application's source from a browser network trace (HAR).
Project-URL: Homepage, https://github.com/jack-work/vibe-saver
Project-URL: Issues, https://github.com/jack-work/vibe-saver/issues
Author: Jack Kelliher
License: MIT
Keywords: har,powerapps,recovery,support,vibe
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: certifi>=2024.2.2
Requires-Dist: questionary>=2.0
Requires-Dist: rich>=13.7
Description-Content-Type: text/markdown

# Vibe Saver

Recover a Power Apps **Vibe** application's source code from a browser network
trace, when the project no longer opens in the authoring experience.

Published code apps keep their source in blob storage, and the Power Apps API
hands the browser a temporary download link for it (`codeAppSourceUri`). If you
record a network trace while loading your app list, that link is in the trace.
This tool finds it and downloads the ZIP.

## Run it

Nothing installed, no Python, no uv:

```sh
curl -LsSf https://raw.githubusercontent.com/jack-work/vibe-saver/main/scripts/run.sh | sh
```
```powershell
irm https://raw.githubusercontent.com/jack-work/vibe-saver/main/scripts/run.ps1 | iex
```

Those fetch a standalone binary from the latest release and run it. Each
release also carries the binaries directly, if you would rather download one:
`vibe-saver-linux-x86_64`, `vibe-saver-macos-arm64`,
`vibe-saver-windows-x86_64.exe`.

With [uv](https://docs.astral.sh/uv/), which supplies its own Python:

```sh
uvx vibe-saver
```

With pip, or on NixOS:

```sh
pip install vibe-saver && vibe-saver
nix run nixpkgs#uv -- tool run vibe-saver
```

The bare command runs the guided flow: it explains how to record the trace,
finds the capture, downloads your source, arranges it for upload, and prints
the path to hand to Vibe.

## The layout Vibe expects

The archive the platform returns is rooted at the application. Vibe wants a
project tree, so `repack` rewrites it to mirror a Vibe project export:

```
project/project.json
project/apps/<app>/...
```

`dist/` is dropped, since the build regenerates it and an export omits it, and
no directory entries are written.

## Verbs

The guided flow is optional; every stage is usable on its own.

| Command | Does |
|---|---|
| `vibe-saver` | guided recovery |
| `vibe-saver discover [DIR]` | list `.har` captures, newest first |
| `vibe-saver list --har F` | every application in a capture |
| `vibe-saver find --har F --app-id ID` | one application (`--json` for scripts) |
| `vibe-saver fetch --har F --app-id ID` | download the source ZIP as it comes |
| `vibe-saver repack --zip F` | rearrange a source ZIP into the project layout |
| `vibe-saver instructions [--upload]` | print the guidance text alone |

`--app-id` accepts either a bare id or a whole player URL.

## Recording the trace

`vibe-saver instructions` prints the full version:

1. Open developer tools on `make.powerapps.com` and select **Network**.
2. **Start recording, then reload**, then click **Apps**.
3. Save the recording as a `.har` file.

The order matters. If the app list loaded before recording started, the
download links are not in the file and nothing can be recovered from it.

## About the trace file

A `.har` holds temporary download links for the applications your account can
reach, and they work for anyone with the file until they expire, a few days
later. The trace is read on your own machine; this tool uploads nothing. Delete
the `.har` when you are finished.

## Layout

```
src/vibe_saver/
  core/     logic only: HAR streaming, lookup, SAS, download, discovery
  cli/      prompts, instructional text, the wizard, argument parsing
```

Two runtime dependencies, both pure Python: [rich](https://github.com/Textualize/rich)
draws, [questionary](https://github.com/tmbo/questionary) asks. Rich turns on
virtual-terminal mode on Windows and drops to ASCII box drawing on legacy
consoles, so the same code looks right on Windows Terminal, cmd.exe, macOS and
Linux. Neither needs a compiler, so `uvx` starts without a build step and
PyInstaller freezes them without custom hooks.

`core` never prints and never exits; it raises `VibeSaverError` subclasses that
carry a plain-language `hint`. That separation is what lets the same steps be
driven later by something other than a terminal.

Large captures are read incrementally with `json.JSONDecoder.raw_decode`. On a
152 MB trace (261 entries, largest single response body 60 MB):

| | peak RSS | time |
|---|---|---|
| `json.load` | 769 MB | 5.1 s |
| `vibe_saver.core.harstream` | 147 MB | 7.4 s |

Two seconds buys a 5x smaller footprint. The ceiling is the largest single
entry, not the file, so a 500 MB capture stays survivable.

## Development

```sh
uv sync
uv run pytest
```
