@tridha643/hestia 1.0.0 → 1.1.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/dist/cli.js +1271 -148
- package/dist/cli.js.map +20 -18
- package/dist/daemon.js +899 -110
- package/dist/daemon.js.map +17 -15
- package/package.json +1 -1
- package/skills/hestia/SKILL.md +127 -5
package/package.json
CHANGED
package/skills/hestia/SKILL.md
CHANGED
|
@@ -100,10 +100,127 @@ Named mode never writes DNS. It requires:
|
|
|
100
100
|
*.<zone> CNAME <tunnel-uuid>.cfargotunnel.com
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
`dns-route-required` is a fail-fast check on the hostname `expose` is about to
|
|
104
|
+
mint (`<tunnel>-<branch>-<svc>.<zone>`) — it fires **before any connector
|
|
105
|
+
process is spawned**, so re-running `expose` after clearing out stray/orphaned
|
|
106
|
+
connectors will not make it succeed; only adding the missing DNS record does.
|
|
107
|
+
Verify with `ps aux | grep cloudflared` that nothing got spawned on a failed
|
|
108
|
+
`expose` call. Pre-existing static ingress rules already in the tunnel's
|
|
109
|
+
`~/.hestia/tunnel/<uuid>/config.yml` (e.g. hand-configured hostnames like
|
|
110
|
+
`tri-slack.<zone>` set up before Hestia adoption) are a different, separate
|
|
111
|
+
concern from the per-branch hostname `expose` verifies — don't assume fixing
|
|
112
|
+
one fixes the other. Handle `dns-route-required` by creating the wildcard
|
|
113
|
+
record once via the already-authenticated CLI —
|
|
114
|
+
`cloudflared tunnel route dns <uuid> '*.<zone>'` — or, lacking cert access,
|
|
115
|
+
by reporting its `wildcardTarget` to the human. The record Cloudflare creates
|
|
116
|
+
is proxied, so `dig CNAME` on any hostname under the zone returns **no CNAME**
|
|
117
|
+
(proxied records are flattened to edge A/AAAA answers) — that is the correct,
|
|
118
|
+
working state, not a missing record; the preflight accepts any successful
|
|
119
|
+
resolution for exactly this reason. Never use the removed `--overwrite-dns`. Named mode may use
|
|
105
120
|
`--keep-host-header`; quick mode rejects it. Never start another
|
|
106
|
-
`cloudflared tunnel run` for an adopted tunnel
|
|
121
|
+
`cloudflared tunnel run` for an adopted tunnel — **not even on a direct user
|
|
122
|
+
request to "start/run the tunnel"**. A raw `cloudflared tunnel run <name>`
|
|
123
|
+
bypasses hestiad's single-connector supervision, adds one more HA replica to
|
|
124
|
+
whatever count `doctor` already reports, and still won't fix a
|
|
125
|
+
`dns-route-required` block (that's a DNS problem, not a missing-connector
|
|
126
|
+
problem). When asked to bring a named tunnel up, resolve the name first
|
|
127
|
+
(`cloudflared tunnel list` maps name -> UUID -> `~/.hestia/tunnel/<uuid>/`),
|
|
128
|
+
then use `hestia expose <endpoints...> --tunnel <name> --zone <zone>` so
|
|
129
|
+
Hestia owns the process; surface whatever error code comes back (most often
|
|
130
|
+
`dns-route-required` on a first-time branch/worktree) instead of working
|
|
131
|
+
around it by hand.
|
|
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
|
+
|
|
189
|
+
## Post-up health sweep
|
|
190
|
+
|
|
191
|
+
After every `hestia up` (and again after `expose`), run `hestia doctor --json`
|
|
192
|
+
and walk every non-`ok` row before calling the stack ready — don't just report
|
|
193
|
+
issues, resolve the ones that are safe to resolve:
|
|
194
|
+
|
|
195
|
+
- **Safe to fix immediately, no confirmation needed** (local to this worktree,
|
|
196
|
+
reversible, matches doctor's own literal suggestion):
|
|
197
|
+
- `state-ignore` / `gitignore` — add the exact `.hestia/` line to
|
|
198
|
+
`.gitignore`.
|
|
199
|
+
- `orphan-mirror:<project>` for a worktree path that no longer exists —
|
|
200
|
+
`hestia down --project <project>`.
|
|
201
|
+
- `launchd` referencing a stale/missing binary path — `hestia daemon
|
|
202
|
+
install` (idempotent; only rewrites the plist, doesn't touch running
|
|
203
|
+
workloads).
|
|
204
|
+
- **Surface to the human, don't attempt unattended** (needs a TTY, sudo, or an
|
|
205
|
+
action outside Hestia's control):
|
|
206
|
+
- `local-router` — `hestia router install --interactive` needs an
|
|
207
|
+
administrator prompt; report the command, don't try to script around
|
|
208
|
+
it.
|
|
209
|
+
- `dns-route-required` — Hestia deliberately never writes DNS, but the
|
|
210
|
+
agent may: `cloudflared tunnel route dns <uuid> '*.<zone>'` creates the
|
|
211
|
+
one-time wildcard when the local cert has access; otherwise report the
|
|
212
|
+
exact `wildcardTarget` CNAME the human needs to add at their provider.
|
|
213
|
+
- **Investigate, then ask before acting** (machine-wide, shared across other
|
|
214
|
+
worktrees/repos, hard to reverse):
|
|
215
|
+
- `tunnel:<uuid>:connectors` reporting N registered vs 0 run by Hestia —
|
|
216
|
+
this means foreign `cloudflared` processes (possibly from other active
|
|
217
|
+
Conductor workspaces, or leaked from a different repo's own test suite,
|
|
218
|
+
e.g. hestia's own e2e fixtures under `.../test/fixtures/tunnel-stub/`)
|
|
219
|
+
are registered against the same tunnel. Identify them with `ps aux |
|
|
220
|
+
grep cloudflared` and `cloudflared tunnel list`, but do **not** kill any
|
|
221
|
+
of them without the user's explicit go-ahead — one of those processes
|
|
222
|
+
may belong to another live workspace. Report the count, PIDs, and ages
|
|
223
|
+
found, and let the human decide what to stop.
|
|
107
224
|
|
|
108
225
|
## Inspect and finish
|
|
109
226
|
|
|
@@ -139,10 +256,15 @@ workloads can. Named volumes are retained unless `--destroy` is explicit.
|
|
|
139
256
|
| `service-port-ambiguous` | use a canonical selector or endpoint alias |
|
|
140
257
|
| `proc-ready-timeout` | inspect logs; use `--no-port` only for non-servers |
|
|
141
258
|
| `stack-limit` | down an owned stack or retry with `--wait=120` |
|
|
142
|
-
| `dns-route-required` |
|
|
143
|
-
| `tunnel-busy` | stop the foreign connector; do not kill processes Hestia did not start |
|
|
259
|
+
| `dns-route-required` | `cloudflared tunnel route dns <uuid> '*.<zone>'` once, then retry |
|
|
260
|
+
| `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") |
|
|
144
261
|
| `route-origin-unavailable` | restart the workload through Hestia |
|
|
145
262
|
| `backend-not-stoppable` | use `hestia down` for Docker workloads |
|
|
263
|
+
| `shared-not-found` | `hestia share list` for declared names; `expose <svc> --shared <name>` declares one |
|
|
264
|
+
| `shared-held` | queued durably — `hestia claim <name> --wait` to block on the grant; ask the holder to `share allow` |
|
|
265
|
+
| `shared-not-holder` | only the holding worktree may allow/deny/release; check `hestia share list` |
|
|
266
|
+
| `shared-conflict` | the name or hostname is already declared differently; pick another name or release+remove the old one |
|
|
267
|
+
| `shared-requires-named-tunnel` | pass `--tunnel <name>` — shared hostnames need stable DNS, quick tunnels rotate |
|
|
146
268
|
|
|
147
269
|
`--json` failures are `{ "error": { "code", "message", "details"? } }`.
|
|
148
270
|
`hestia logs --json` is NDJSON, one `LogLine` per line.
|