* feat(zec2_rotatekeys): rotate/reset server-side secrets without exposing values
New tool for the leaked/overwritten prod .env case: -Rotate KEY regenerates a
key ON THE SERVER (openssl rand -hex 32) so the value never leaves the box;
-Set KEY takes an operator-known value from a masked prompt and streams it over
SSH stdin (never a command arg, never echoed). Backs the server .env up to a
timestamped .bak first, updates keys atomically (match-or-append), auto-detects
backend/.env from deploy.preserve, restarts only with -Restart, and -WhatIf
previews the plan. Docs added to README + CHANGELOG.
* fix(zec2_rotatekeys): recreate container on -Restart so the new .env loads
A plain 'docker compose restart' reuses the container's existing environment
and would NOT pick up env_file changes, leaving the app on the old secrets
after a rotation. -Restart now runs 'up -d --force-recreate <svc>', the
reliable way to apply the new .env. Docs updated to match.
* feat(zstart): support uvicorn/ASGI apps via a startApp config field
Python projects could only be started as `python -m <startModule>`, so
FastAPI/ASGI apps that run under uvicorn (like evo-ai:
`uvicorn app.main:app`) couldn't be started by zstart in either port.
Add an optional `startApp` field. When set, zstart runs
`uvicorn <startApp> --host <bind-host> --port <ports.dev> --reload` via
the venv python's -m (no PATH juggling), integrating zstart's existing
bind-host and dev-port handling. startApp takes precedence over
startModule; a python project still needs one or the other. Applied to
bash and PowerShell, documented in the README + example configs.
* feat(zstart): warn when falling back to system python (no project venv)
A python project with no .venv (or only a Windows .venv when on WSL)
silently ran under the system interpreter, which usually lacks the
project's deps - producing a cryptic ModuleNotFoundError far from the
cause. Now zstart prints a clear warning naming the missing venv and the
one-liner to create it, before starting. Bash + PowerShell.
* fix(bash): zstart --detached no longer hangs on the tracking FIFO
Detached mode forked the long-lived server while it still inherited the
ztokens tracking fds (the capture FIFO on 1/2, saved stdout/stderr on
3/4). The parent's EXIT-trap footer runs `tee` on that FIFO and waits for
EOF, which never came while the server held it open - so `zstart
--detached` (and zstartd / zrestart --detached) hung instead of
returning. detach() now redirects stdin<-/dev/null, stdout/stderr->log
and closes fd 3/4 before exec'ing the server. Verified on WSL: detached
returns in 0s and the server still boots.
* fix(zstart): git-pull pre-step can't hang on a credential prompt
start.gitPull ran `git pull --ff-only` before starting the server; in an
environment with no cached git credentials (e.g. WSL against an HTTPS
GitHub remote) git prompted "Username for 'https://github.com':" and the
whole start blocked on stdin. Run the pull with GIT_TERMINAL_PROMPT=0 so
it fails fast, log a clear "auto-pull skipped" note, and start with the
current checkout. Bash + PowerShell.
zkill now accepts 'all', expanding to every project that has a ports.dev
(edge/docker stacks with no local dev server are skipped) - matching
zdeploy all / zbackup all. Ported to both the PowerShell (ZKillOnly.ps1)
and bash (bash/zkill) versions; README + CHANGELOG updated.
* feat(bash): native bash port of all z-scripts for Linux/macOS/WSL
Full port: zhelpers.sh library (jq config, ssh, http/tcp, archive builder,
build-version, motd, port-kill), all commands (zstart/zkill/zrestart/zstop,
zdeploy with 5 kind handlers, zec2/zec2online/zrepair, zbackup/zbackup_ec2/
zsync/zbackup_and_sync, zstart_docker, zsetup_mail, setup_backup_schedule via
cron), Unix-path zconfig.example.json, and a bash/README.md.
Verified: bash -n clean on all scripts; archive exclusions, config semantics,
and zec2 tested against the real config and live server from Git Bash. Needs a
Linux/macOS/WSL shakedown for lsof/rsync/nohup paths before merging.
* chore: pin line endings (.gitattributes) - bash LF, powershell CRLF
* docs(readme): point Linux/macOS/WSL users at the bash port
* fix(bash): don't run the Windows venv python.exe on WSL/Linux/macOS
zstart's venv detection fell back to .venv/Scripts/python.exe (a Windows
binary) whenever it existed. On a Windows-built project accessed from WSL that
file sits on the mount and looks executable, so it got picked and failed with
'exec format error' instead of falling through to python3. Guard that branch to
Windows-family shells (msys/cygwin), where a .exe can actually run.
Verified on WSL: zstart --detached now backgrounds a stdlib app via python3,
serves HTTP 200, logs to /tmp/zstart-<key>.log, and zkill terminates it and
frees the port.
* feat(bash): add token-usage tracking to the bash port (#6)
Adds z_track_start/z_track_stop + z_record to zhelpers.sh and wires
z_track_start into every command script. Each run now captures its own output
volume (FIFO+tee, ANSI stripped), prints the '--- N lines / N chars / ~N tokens
est. (Claude Code) ---' footer, and appends one JSONL row per top-level run in
the same shape as the PowerShell tokens.jsonl. A nested-run guard keeps
zrestart from double-counting its zkill/zstart children.
Data dir precedence: $ZTOKENS_DATA, config ztokens.dataDir, sibling
../../ztokens/data, else ~/.ztokens/data. Docs + example config updated.
Verified on WSL (isolated data dir): single run records correctly; nested
zrestart produces one combined record, not three; est = round(chars/3.5).
The project-directory replacement preserved only ./.env, silently
destroying every other server-side file (.env.db, staged signing keys,
certs) on every deploy — and the vite kind preserved nothing at all.
- preserve all .env* files at the project root by default
- new deploy.preserve array for additional files/directories
- implemented via tar to the home dir before the wipe, extract after
the unzip; server-side copies win over zip contents (same semantics
./.env always had)
- helpers deliberately avoid embedded quotes and $( ): PowerShell 5.1
strips embedded double quotes when passing args to ssh.exe, which
silently corrupts remote commands (discovered when v1 of this fix
failed exactly that way)
Fixes#2
Projects not published through the edge proxy had a false-PASS problem:
the fallback reachability check hit http://<server-ip>/, which the
proxy's default vhost happily answers for apps that never started.
- new Test-DeployHealth: checks the app FROM the server over SSH
(curl localhost:<port><path>), optional expected substring
- opt in per project: "verify": { "port", "path", "expect" }
- projects with neither domain nor verify are reported NOT verified
instead of green-lighting the proxy's default page
- example config + README + changelog updated
Per-run captures are measured; the ~26,500/day total multiplies them by assumed
typical run counts (zdeploy/zrestart at 10-15/day dominate). Label that boundary
explicitly in README, ELEVATOR_PITCH, and TOKEN_SAVINGS so the daily figure isn't
read as a direct measurement.
- One headline number everywhere: ~26,500 measured tokens/day (README said 3,000-7,000; ELEVATOR_PITCH said 157,000-540,000)
- Measurement note: measured output volume, estimated tokenization; /3.5 is conservative for code-heavy output
- Raw-orchestration column explicitly labeled an upper bound, not a prediction
- Measured dollar column priced at input rates (blended kept for est-raw only); note on re-sent context tokens
- Untrack md/Z-ScriptTokenData.md (superseded internal notes; md/ gitignored)
Config-driven PowerShell scripts to run infrastructure tasks (deploy, restart, backup, diagnostics) yourself instead of having an AI agent orchestrate them, to save agent tokens. Environment specifics live in zconfig.json (gitignored).