Minor Changes
-
Add
jalth auth-key create --identity <email> --group <group>so headless devices can receive Access Group membership as they join.--groupnow fails fast unless--identityis also set, andjalth auth-key listincludes the stored group assignment. Headless devices enrolled through non-revoked, unexpiredoperatorsauth keys now satisfy operator-only Worker authorization while remaining blocked from admin-only procedures. Closes #92. (#93) -
Adds local commands for managing your jalth setup: (#74)
jalth doctor— check that WARP, DNS, the registry, and your peers are reachable. Add--fixto auto-repair common issues (some require sudo). Results group by status (failed → warnings → passed) with passing checks collapsed to a single line; pass-vto list every check.jalth bugreport— collect a diagnostic report for support. Tokens, secrets, emails, and public IPs are redacted; mesh CGNAT addresses are kept so issues remain debuggable.jalth config,jalth config get <key>,jalth config path— print your config, look up a single value, or show where the config file lives.jalth version— print the installed CLI version.jalth upandjalth down— connect to or disconnect from the mesh.jalth downrefuses to drop the connection while you’re SSH’d into a mesh device unless you confirm.jalth ping <device>andjalth ping --all— check reachability of one peer or every peer. Refusesjalth ping <yourself>with a clear message and excludes you from the interactive picker.
All commands support
--output json(orJALTH_OUTPUT=json) for scripting. Long-running commands show progress as they work: an animated spinner in a terminal, plain status lines in CI/non-TTY, and stderr-only progress under--output jsonso stdout stays machine-parseable. SetJALTH_NO_PROGRESS=1to silence progress entirely. Under--output json,jalth doctor --fixno longer pauses for confirmation prompts on risky/install-tier fixes — those skip silently unless you also pass--yes.jalth statusis now noticeably faster — typical responses drop from ~10 s to ~500 ms on busy meshes. Device liveness now reflects the last 15 minutes of WARP heartbeats instead of the last 24 hours, so a device that has been offline for more than ~15 minutes will correctly show as offline (previously it could remain marked online for up to a day). -
Add
jalth destroyfor full mesh teardown. The new admin-only command tears down per-device WARP registrations, every auth-key service token (including those whose owning auth key was previously revoked but whose CF-side delete failed), the WARP enrollment app, jalth Access Groups, the Email OTP IdP and SSH CA when jalth created them, the device profile, restores connectivity settings to their pre-init values, detaches the Worker Custom Domain after earlier cleanup is clean, deletes the D1 database, and self-deletes the Worker script. The TTY flow uses a typed-confirm prompt (retype the team name, no--yesshortcut); non-interactive callers (--output jsonor non-TTY) must pass--confirm <mesh-name>matching the server-side team name. The Worker halts before custom-domain detach if any phase 4–5 cleanup fails (per-device errors, auth-key token failures, Access Group list/delete failures, IdP / SSH CA / device profile / connectivity failures), and skips the Worker self-delete if the D1 delete itself fails — D1 and the Worker stay live in both cases so the operator can re-runjalth destroyafter fixing the underlying CF API issue. If a retry needs to reach a Worker whose custom domain was already detached, authenticated tRPC calls fall back from the detached-domain 404 to workers.dev. After a clean Worker self-delete is scheduled, the CLI polls/apiuntil it 404s; on timeout it prints manual recovery instructions (wrangler delete jalth) and leaves the local config ($JALTH_CONFIG_DIR/config.json, default~/.jalth/config.json) in place so the operator retains context for manual recovery. A passive straggler scan after the per-device cleanup loop counts orphaned WARP registrations that look jalth-owned and surfaces a dashboard link — no automatic deletion. Closes #80. (#83) -
Add repeatable
jalth auth-key create --tagmetadata andjalth devices --taginventory filtering, with richerjalth devices --jsonrows that include role, status, services, routes, tags, and activity fields. Devices enrolled before this release keep empty tag arrays until they rejoin through a tagged auth key. Closes #130. (#135) -
jalth doctornow checks cloudflared service health, verifies the cloudflared DNS resolver override, and warns when an SSO-enrolled device token is close to expiry.mesh.statusnow includes each device’s headless enrollment flag plus token activity and expiry timestamps so clients can distinguish SSO devices from auth-key devices. Closes #68 and #69. (#118) -
Add
jalth domain get,jalth domain set <domain>, andjalth domain removeso admins can attach, inspect, replace, and remove the mesh Worker Custom Domain after init. The Worker now resolves the Cloudflare zone with its bound API token, stores the resolved custom-domain ID for cleanup, rejects removal while services are active, and restores local CLI config to the workers.dev fallback on removal. Closes #99. (#103) -
Add
jalth group ls,jalth group members,jalth group create, andjalth group deletefor reading built-in groups and managing custom Access Groups. Custom groups use thejalth-g-<name>Access Group name, andmembers,admins, andoperatorsremain reserved. Closes #97. (#101) -
Add
jalth group add <group> <email...>andjalth group remove <group> <email...>with--domain <domain>support so admins can manage Access Group membership after init. Membership updates are idempotent and preserve existing non-email rules such as service tokens. Closes #98. (#105) -
Add
jalth route add,jalth route ls, andjalth route removeso operators can route hostname patterns through a selected device tunnel. Route creation now configures the Gateway hostname route, preserves existing split tunnel includes while adding100.80.0.0/16, validates the via device tunnel, and warns when Gateway TLS decryption could break transparent HTTPS egress. Closes #112. (#117) -
Add
jalth leave,jalth devices,jalth devices list, andjalth devices remove [name]for removing devices from a mesh. Device cleanup now tears down mesh DNS, SSH access, service-token enrollment, WARP registration, and the device record with retry-friendly behavior when partial cleanup fails. (#81)jalth devices remove [name]is admin-only, supports an interactive picker in TTY mode, disables the current device in that picker, and shows the target IP, type, and owner before confirmation. Devices with attached services or routes cannot be removed yet because those teardown commands are not in this release.Closes #79. Closes #65.
-
jalth leavenow refuses withCONFLICTwhen this device is the last admin-capable enrolled device in the mesh, closing the footgun where the sole admin-capable device could leave and end up with a mesh that has no admin device able to issue admin operations. To proceed, promote another admin (jalth role set <email> adminand have that user runjalth join), or tear down the mesh entirely withjalth destroy. Headless devices and expired rows do not count as admin-capable. (#91)Leave now runs a server-side preflight before any local teardown, so a refusal (last-admin, expired token, destroy/leave lock) never strands the device with sshd config removed, WARP MDM file deleted, and the WARP daemon stopped. Previously the local-first ordering left the device WARP-disconnected on any late-stage worker refusal until the user rejoined.
-
Add
jalth serve --allow ...to protect HTTP services with Cloudflare Access rules for email, domain, group, IP, country, or everyone.jalth serve lsnow reports each service’s access state, and TCP services reject--allowwith--allow is not supported for TCP services (no browser login available).Closes #111. (#116) -
Add
jalth role setandjalth role lsso admins can manage effective admin, operator, and member access from the CLI. The Worker now exposes role-management procedures that update the built-in Access Groups and reject demoting the last active admin-capable identity. Closes #94. (#96) -
jalth servenow handles first-use domain setup interactively, accepts--proto https, supports--origin <url>, and opens the Access policy builder when--allowis passed without a value. Group allow rules now use jalth-managed Cloudflare Access Groups and can create missing custom groups interactively; JSON and non-TTY runs still require explicit values. Closes #129. (#136) -
Add
jalth serve <name> --port <port>andjalth serve lsfor exposing public HTTP/TCP services through each device’s managed Cloudflare Tunnel. Services now reserve stable hostnames, create proxied DNS CNAMEs, keep cloudflared configured with the DNS resolver override, and roll back reserved state when setup fails. Closes #109. (#114) -
jalth servenow publishes service exposure as one recoverable operation, andjalth stoptears it down with partial-failure reporting. Failed publishes roll back remote ingress, DNS, and Access resources; if cleanup cannot finish, the pending service reservation stays visible so retry can resume instead of losing partial state. Failed stops keep the service record and report the specific resource that still needs cleanup. Closes #137. (#139) -
Require
jalthCLI v0.3.0 or newer for Workers that expose the consolidated service lifecycle API. Older CLIs that still call the retired low-level service exposure procedures must upgrade before usingjalth serveorjalth stop. Closes #138. (#140) -
Add
jalth stop <name>andjalth stop --allto remove served services, clean up their Cloudflare resources, and uninstall the localcloudflaredservice only when the device tunnel is no longer used by services, routes, or SSH. JSON output includes per-service stop results even when only part of a batch fails. Closes #110. (#115) -
Add the tunnel and cloudflared service foundation needed by
jalth serve,jalth stop, andjalth route: devices can now create or reuse a remote-managed Cloudflare Tunnel, recover from externally deleted tunnel records, and prepare a reboot-safe cloudflared system service with the required DNS resolver override. This does not expose services or routes yet; those commands are implemented in follow-up phases. Closes #108. (#113)
Patch Changes
-
Tighten CLI behavior on non-interactive paths so
--output jsonand CI-style runs are predictable and machine-parseable. (#82)jalth ssh enablenow exits non-zero withkind: "permissions"when run as non-root in a non-TTY context with sudo available but unauthorized (configure NOPASSWD or pre-authenticate withsudo -v). Previously it returned{ ok: true, enabled: false }with exit 0, so automation could not distinguish a failed enablement from a successful one.jalth ssh enableandjalth ssh disablenow exit withkind: "subprocess"and the underlying spawn cause inlined whensudois missing fromPATH, the binary refuses to start, or thesudo -nprobe times out (default 5s). Previously every probe failure mapped tokind: "permissions"with a “configure NOPASSWD” message, which sent operators down the wrong remediation path on systems where the real fix is installing sudo or repairing a broken auth plugin.jalth ssh disable --output jsonnow emits{ ok: true, disabled: true }on success instead of writing the human-textSSH disabled.line to stdout — the JSON path no longer mixes machine-readable output with clack log lines.jalth leave,jalth ssh enable, andjalth ssh disableno longer callsudo -vinteractively in--output jsonor non-TTY runs; the privileged work still runs viasudo -n, and operators using those modes are expected to have pre-authenticated sudo or passwordless sudoers (perspecs/technical/02-cli.md§ 3.1.1).- Privileged steps in
jalth init,jalth upgrade, andjalth ssh enablenow cancel their spinners with a red ✗ on failure instead of leaving the terminal stuck onDoing X...after a sudo, network, or subprocess error.
-
jalth destroynow removes local SSH, WARP, and managed cloudflared state after the remote Worker is verified deleted. The command still preserves local config and skips local teardown when Worker self-delete cannot be verified, so operators keep the recovery path. Closes #127. (#128) -
jalth leave,jalth devices remove, andjalth destroynow clean served services, service DNS records, service Access apps, hostname routes, SSH targets, and device tunnels directly instead of requiringjalth stoporjalth route removefirst.jalth leavealso best-effort uninstalls the local managed cloudflared service after the remote leave succeeds. (#126) -
Fix
jalth leave,jalth devices remove, andjalth auth-key revokeso headless-device cleanup can remove the final WARP enrollment service-token rule without stranding active credentials. Devices with services or routes now fail immediately with the remove-first precondition, while real concurrent cleanup returnsA device leave is in progress — retry shortly.. (#83) -
Updated dependencies [
3d7812e,81c6e02,f702006,3468159,0387ddd,bceb70c,6347f04,199538d,567f599,bd7c202,c09b03c,81c6e02,f4cd064,59904f5,aa09a89,ee7e3ac,5b64573,9159450,7f7a43d,a6f8900]:- @jalth/api@0.4.0