@tridha643/hestia 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tridha643/hestia",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Per-worktree isolated development stacks for humans and coding agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -130,6 +130,62 @@ Hestia owns the process; surface whatever error code comes back (most often
130
130
  `dns-route-required` on a first-time branch/worktree) instead of working
131
131
  around it by hand.
132
132
 
133
+ ## Shared hostnames (externally-pinned URLs)
134
+
135
+ Decide the routing mode by who controls the external side:
136
+
137
+ - **Independent ingestion** (you open the URL; the external app accepts many
138
+ callback URLs): keep per-branch `expose` — full isolation, no arbitration.
139
+ - **Dependent ingestion** (the external side is pinned to ONE URL: a Slack
140
+ app's request URL, a third-party webhook consumer, a strict OAuth
141
+ allowlist): use a SHARED hostname. One stable URL, machine-owned, held by
142
+ exactly one worktree at a time; hestiad routes each request to the holder.
143
+
144
+ ```bash
145
+ hestia expose slack --shared tri-slack --tunnel tri --json # declare + claim
146
+ # The URL defaults to <name>.<zone>. Point ANY FQDN you control (any zone):
147
+ hestia expose slack --shared slk --hostname slack.acme.com --tunnel tri --json
148
+ # Several handles can share ONE hostname, split by URL path prefix (longest wins):
149
+ hestia expose slack --shared slk --hostname acme.com --path /webhooks/slack --tunnel tri --json
150
+ hestia expose stripe --shared str --hostname acme.com --path /webhooks/stripe --tunnel tri --json
151
+ hestia claim tri-slack --wait --json # queue durably; returns when granted
152
+ hestia claim tri-slack --cancel --json # leave the queue
153
+ hestia release tri-slack --json # hand to the next in queue
154
+ hestia share list --json # who holds / who waits (with full URL)
155
+ hestia share requests --json # pending consent requests for you
156
+ hestia share allow tri-slack --json # holder consents — handover now
157
+ hestia share deny tri-slack --json # holder declines — requester stays queued
158
+ ```
159
+
160
+ The hostname is arbitrary (any subdomain on any zone you control; apex domains
161
+ need pre-existing DNS). `--path` routes by longest prefix at segment boundaries
162
+ (`/slack` matches `/slack/events`, never `/slackbot`); a request no path covers
163
+ is 404, a declared-but-unclaimed path is 503. cloudflared sees one rule per
164
+ hostname — all path splitting happens in hestiad, so adding a path to an
165
+ existing hostname needs no connector restart.
166
+
167
+ In the Fleet TUI (`hestia tui`), press **`s`** to open the shared-hostnames
168
+ panel: it lists every declared name with its holder and durable FIFO queue
169
+ (denied waiters marked). `j/k` select; **`c`** claims the selected name as the
170
+ currently-selected stack; **`a`/`x`** allow/deny the head as the holder;
171
+ **`r`** releases. It reads the same daemon state as `hestia share list`.
172
+
173
+ Protocol invariants agents must respect:
174
+
175
+ - Claims are **consent-based**: a held name is never stolen. `claim --wait`
176
+ queues; the holder decides with `share allow`/`share deny`, and `release`/
177
+ `down`/a crashed stack grants the queue head automatically.
178
+ - The queue is **durable** (survives daemon restarts and CLI timeouts). Your
179
+ blocked `claim --wait` returning success IS the grant notification; if it
180
+ timed out, your position is kept — re-run `claim --wait` to re-attach.
181
+ - While holding a shared name, check `hestia share requests` at natural
182
+ breakpoints and answer allow/deny — another agent may be blocked on you.
183
+ - Holder switches are hestiad route-table updates: zero connector restarts,
184
+ zero DNS writes. Declaring a NEW shared hostname restarts the connector
185
+ once (~2-5 s public blip) and requires the same wildcard DNS as named mode.
186
+ - `down`/`stop` of the serving workload auto-releases; re-`up` does NOT
187
+ auto-reclaim — claiming is always an explicit `hestia claim`.
188
+
133
189
  ## Post-up health sweep
134
190
 
135
191
  After every `hestia up` (and again after `expose`), run `hestia doctor --json`
@@ -142,6 +198,11 @@ issues, resolve the ones that are safe to resolve:
142
198
  `.gitignore`.
143
199
  - `orphan-mirror:<project>` for a worktree path that no longer exists —
144
200
  `hestia down --project <project>`.
201
+ - `tunnel:<name>:local-orphans` — Hestia-owned replicas whose argv still
202
+ contains `~/.hestia/tunnel/<uuid>/` after a lost pidfile. The daemon
203
+ sweep / next reconcile reaps them automatically; do **not** start another
204
+ `cloudflared`, and do **not** treat other Conductor worktrees as needing
205
+ their own connector (one machine-global connector serves every worktree).
145
206
  - `launchd` referencing a stale/missing binary path — `hestia daemon
146
207
  install` (idempotent; only rewrites the plist, doesn't touch running
147
208
  workloads).
@@ -156,15 +217,11 @@ issues, resolve the ones that are safe to resolve:
156
217
  exact `wildcardTarget` CNAME the human needs to add at their provider.
157
218
  - **Investigate, then ask before acting** (machine-wide, shared across other
158
219
  worktrees/repos, hard to reverse):
159
- - `tunnel:<uuid>:connectors` reporting N registered vs 0 run by Hestia
160
- this means foreign `cloudflared` processes (possibly from other active
161
- Conductor workspaces, or leaked from a different repo's own test suite,
162
- e.g. hestia's own e2e fixtures under `.../test/fixtures/tunnel-stub/`)
163
- are registered against the same tunnel. Identify them with `ps aux |
164
- grep cloudflared` and `cloudflared tunnel list`, but do **not** kill any
165
- of them without the user's explicit go-ahead — one of those processes
166
- may belong to another live workspace. Report the count, PIDs, and ages
167
- found, and let the human decide what to stop.
220
+ - `tunnel:<name>:connectors` reporting N registered vs 0/1 run by Hestia
221
+ **with no local-orphans row** — a truly foreign connector (argv lacks the
222
+ hestia tunnel path, e.g. `cloudflared tunnel run --token …` or a hand-run
223
+ `tunnel run`). Identify with `ps -Ao pid,lstart,command | grep cloudflared`
224
+ and ask the human before killing anything Hestia did not start.
168
225
 
169
226
  ## Inspect and finish
170
227
 
@@ -201,9 +258,14 @@ workloads can. Named volumes are retained unless `--destroy` is explicit.
201
258
  | `proc-ready-timeout` | inspect logs; use `--no-port` only for non-servers |
202
259
  | `stack-limit` | down an owned stack or retry with `--wait=120` |
203
260
  | `dns-route-required` | `cloudflared tunnel route dns <uuid> '*.<zone>'` once, then retry |
204
- | `tunnel-busy` | stop the foreign connector; do not kill processes Hestia did not start identify via `ps aux \| grep cloudflared` + `cloudflared tunnel list`, then confirm with the human before killing anything (see "Post-up health sweep") |
261
+ | `tunnel-busy` | stop the foreign connector; hestia-owned orphans (`~/.hestia/tunnel/<uuid>/` in argv) are auto-reapedonly confirm with the human before killing processes whose argv lacks that path |
205
262
  | `route-origin-unavailable` | restart the workload through Hestia |
206
263
  | `backend-not-stoppable` | use `hestia down` for Docker workloads |
264
+ | `shared-not-found` | `hestia share list` for declared names; `expose <svc> --shared <name>` declares one |
265
+ | `shared-held` | queued durably — `hestia claim <name> --wait` to block on the grant; ask the holder to `share allow` |
266
+ | `shared-not-holder` | only the holding worktree may allow/deny/release; check `hestia share list` |
267
+ | `shared-conflict` | the name or hostname is already declared differently; pick another name or release+remove the old one |
268
+ | `shared-requires-named-tunnel` | pass `--tunnel <name>` — shared hostnames need stable DNS, quick tunnels rotate |
207
269
 
208
270
  `--json` failures are `{ "error": { "code", "message", "details"? } }`.
209
271
  `hestia logs --json` is NDJSON, one `LogLine` per line.