Metadata-Version: 2.3
Name: takopi-preview
Version: 0.1.2
Summary: Tailscale preview command plugin for Takopi
Keywords: takopi,tailscale,preview
Author: ZKP2P
License: MIT License
         
         Copyright (c) 2025 ZKP2P
         
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
         
         The above copyright notice and this permission notice shall be included in all
         copies or substantial portions of the Software.
         
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         SOFTWARE.
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Requires-Dist: takopi>=0.20.0
Requires-Python: >=3.14
Project-URL: Homepage, https://takopi.dev
Description-Content-Type: text/markdown

# takopi-preview

tailscale-backed preview command plugin for takopi. starts a dev server (optional),
exposes it inside your tailnet via `tailscale serve`, and tracks preview sessions
by project/worktree context.

published as the `takopi-preview` package. the command id is `preview`.

## features

- `/preview` commands to start, list, stop, and clean up previews
- tailnet-only urls (no public ingress) with `tailscale serve`
- per-project overrides for ports and dev commands
- optional dev server auto-start with `{port}` substitution
- session registry with ttl expiration and state recovery
- allowlist support for sensitive commands (like `killall`)

## requirements

- python 3.14+
- takopi >= 0.20
- tailscale installed and authenticated on the host (`tailscale up`)
- dev server binds to 127.0.0.1 (tailscale proxies locally)
- security groups should not expose the dev server port publicly

## install

install into the same environment as takopi.

```sh
uv tool install -U takopi
uv tool install -U takopi --with takopi-transport-slack --with takopi-preview
```

or, with a virtualenv:

```sh
pip install takopi-transport-slack takopi-preview
```

## setup

1. install tailscale on the host and authenticate it (`tailscale up`).
2. ensure magicdns is enabled so `DEVICE.TAILNET.ts.net` resolves.
3. run takopi with your transport (slack or telegram) as usual.

## configuration

add to `~/.takopi/takopi.toml`:

```toml
[plugins]
enabled = ["takopi-transport-slack", "takopi-preview"]

[plugins.preview]
provider = "tailscale"
default_port = 3000
dev_command = "pnpm dev -- --host 127.0.0.1 --port {port}"
auto_start = true
ttl_minutes = 120
allowed_user_ids = [123456789]

# optional env injection for the dev server
[plugins.preview.env]
NODE_ENV = "development"

# advanced overrides
tailscale_bin = "tailscale"
local_host = "127.0.0.1"

# per-project overrides (Takopi project tables are strict, so use plugins.preview.projects)
[plugins.preview.projects.myapp]
port = 5173
dev_command = "npm run dev -- --host 127.0.0.1 --port {port}"
```

notes:

- `dev_command` may include `{port}`; it will be substituted at runtime.
- `dev_command` is required when `auto_start = true`. set `auto_start = false` to manage the dev server yourself.
- Inline `--dev`/`--` overrides enable auto-start for that run; use `--no-start` to force manual mode.
- To require an explicit command each run, omit `dev_command` and set `auto_start = false`, then pass `--dev` or `--`.
- `ttl_minutes = 0` disables expiration.
- empty `allowed_user_ids` means no allowlist enforcement.

## commands

- `/preview start [port]`: start a preview for the current context
- `/preview start [port] --dev "<command>"`: override the dev command for this run
- `/preview start [port] -- <command>`: shorthand for an inline dev command
- `/preview list`: show active previews (url, port, uptime, context)
- `/preview stop [id|port]`: stop a preview (defaults to current context)
- `/preview killall`: stop all previews (restricted by allowlist)
- `/preview help`: usage help

## workflow

1. choose a context: `/myapp @feat/login` or reply in an existing thread.
2. run `/preview start` (or `/preview start 5173`).
3. open the returned url, for example:

```
https://DEVICE.TAILNET.ts.net/preview/5173
```

4. stop when done: `/preview stop` or `/preview stop 5173`.

## state and ttl

sessions are stored in memory and persisted to:

- `~/.takopi/state/preview.json`

dev server logs (when auto-started) are written to:

- `~/.takopi/state/preview-logs/<session>.log`

`ttl_minutes` controls automatic expiration; expired sessions are cleaned up
on the next command invocation.

## errors

- missing tailscale: follow the install docs and run `tailscale up`.
- serve disabled: enable serve for your tailnet (Tailscale admin UI) if you see the "Serve is not enabled" error.
- port already in use: run `/preview list` or pick a new port.
- dev server failures: the error includes log tail + log path.

## spec alignment

this implementation follows the webapp preview workflow spec:

- [x] command surface: start/list/stop/killall/help
- [x] config in `[plugins.preview]` with per-project overrides
- [x] tailscale serve + dns from `tailscale status --json`
- [x] tailnet-only https urls
- [x] in-memory registry + state file under `~/.takopi/state/preview.json`
- [x] ttl-based expiration (`ttl_minutes`)
- [x] allowlist enforcement via `allowed_user_ids`

## license

mit
