Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ jobs:
cache: npm

- run: npm ci
- run: npm run typecheck
- run: npm run build
- run: npm test
# Runs the suite and enforces the coverage thresholds in vitest.config.ts.
- run: npm run test:coverage
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
dist/
*.tgz
coverage/
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## 0.3.0 - 2026-08-01

### Added

- **View counts.** Each deployment tracks how many times its page was actually
viewed (HTML page loads only — bundle assets, 404s and HEAD requests don't
count) plus when it was last seen. Shown in `uptool list`, persisted across
daemon restarts, and kept when you redeploy with `--update`.
- **`uptool list --json`** — machine-readable output for scripts and for the
LLM agent driving uptool. Access keys of protected deployments are never
included.
- **`uptool logs`** — print the daemon log without going through
`uptool status`. Supports `-n <lines>` (default 50) and `-f` to follow, which
survives log rotation. Reads the file directly, so it works even when the
daemon is down — which is when you need it.

### Fixed

- **Request bodies with multi-byte characters over ~64 KB were silently
corrupted.** The API decoded each TCP chunk separately, so an accented letter
or emoji split across a chunk boundary became a replacement character.
- **`uptool deploy --name <name>` printed the random slug URL** instead of the
name-based one, even though the deployment was reachable at the name.
- **The live-reload WebSocket ignored `--protect`.** A protected deployment's
reload socket accepted any client, leaking the fact that a private deployment
had been updated. It now requires the same credentials as the page, and dead
sockets are reaped by a heartbeat instead of accumulating.
- **The public server answered every HTTP method as if it were GET**, including
returning a body for `HEAD`. Now only GET and HEAD are served; anything else
gets a 405.
- **`uptool status` mangled log lines at the 16 KB read boundary**, truncating a
line and turning a split multi-byte character into `�`.
- A failed background flush of the manifest could take down the daemon as an
uncaught exception; it's now logged, with the in-memory state authoritative.

### Removed (BREAKING)

- **MCP server** (`uptool mcp`). uptool is CLI-only now — an agent that already
has a shell doesn't need a second MCP surface exposing the same commands.
Replacement: call the CLI directly (`uptool deploy`, `uptool list`, etc.).
- **Admin web UI** (`uptool admin` and the `GET /admin` API route). Same
reasoning — one surface to keep in sync instead of two. Use `uptool list`,
`uptool rm`, `uptool rollback` from the CLI instead.

## 0.2.0

Previous release.
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,28 +198,31 @@ uptool touch x7k2mq9a # renew with the configured default ttl

```bash
uptool list
# x7k2mq http://x7k2mq.mydev.com [dashboard.html] expires in 71h 45m
# x7k2mq http://x7k2mq.mydev.com [dashboard.html] expires in 71h 45m 3 hits · last seen 12m ago
# a9f3kd2p http://a9f3kd2p.mydev.com [draft.html] expires in 20h 3m never viewed
```

### Remove a deployment
View counts track HTML page loads only — assets inside a bundle, 404s and
`HEAD` requests don't inflate the number. They survive daemon restarts and
`--update` redeploys.

For scripts (or for the LLM driving uptool), `--json` emits the full record:

```bash
uptool rm x7k2mq
uptool list --json
# [{"slug":"x7k2mq","url":"http://x7k2mq.mydev.com","filename":"dashboard.html",
# "created":1754006400000,"expires":1754265600000,"hits":3,
# "last_seen":1754092800000,"protected":false}]
```

### Admin page
Access keys of protected deployments are never included in either output.

### Remove a deployment

```bash
uptool admin
uptool rm x7k2mq
```

Opens a 100% local, token-authenticated web UI (served by the internal API on
`127.0.0.1:<api_port>`, no CORS, no external assets or CDNs) listing every
deployment — slug, name, filename, created/expires as relative times, a lock
icon for protected deploys, a preview link to the public URL, and a Delete
button per row. Auto-refreshes every 10s. The token is passed once in the URL
and immediately scrubbed from the browser's address bar.

### Daemon control

```bash
Expand All @@ -228,6 +231,17 @@ uptool status # check if running + last 10 log lines
uptool status --json # machine-readable health for monitoring (exit 1 if unhealthy)
```

### Logs

```bash
uptool logs # last 50 lines of ~/.uptool/server.log
uptool logs -n 200 # last 200 lines
uptool logs -f # follow as it grows (Ctrl-C to stop)
```

Reads the log file directly — no daemon or config needed, so it still works
when the daemon is down, which is usually when you want it.

### Run as a systemd service (Linux)

Survives reboots and restarts on failure:
Expand Down
Loading
Loading