@haven_ai/connect 0.1.34-alpha.0 → 0.1.36-alpha.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/README.md +255 -37
- package/dist/cli.cjs +620 -115
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +623 -118
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +620 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +257 -7
- package/dist/index.d.ts +257 -7
- package/dist/index.js +622 -117
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -7,10 +7,33 @@ signing key and API key locally, stores them locally, and sends Haven only the
|
|
|
7
7
|
public signing address, proof signature, and API-key hash. Haven never receives
|
|
8
8
|
the private key or plaintext API key.
|
|
9
9
|
|
|
10
|
+
## Are you an AI agent whose user has no Haven account yet?
|
|
11
|
+
|
|
12
|
+
Read **`/for-agents.md`** on the Haven host your user gave you — or
|
|
13
|
+
[the copy in this repository](https://github.com/d-hinders/Haven-AI/blob/dev/packages/frontend/public/for-agents.md)
|
|
14
|
+
if you do not have that host yet.
|
|
15
|
+
|
|
16
|
+
Your user creates the account and the passkey: those are theirs, they need a
|
|
17
|
+
human, and you should never ask for their password. You can do everything else
|
|
18
|
+
— including running the connector command from the setup prompt they paste you,
|
|
19
|
+
and managing the account from the shell with `@haven_ai/cli`.
|
|
20
|
+
|
|
10
21
|
```sh
|
|
11
|
-
npx -y @haven_ai/connect
|
|
22
|
+
npx -y @haven_ai/connect@<channel> --setup hv_setup_... --api https://api.haven.example --ack-local-tools --runtime claude-code
|
|
12
23
|
```
|
|
13
24
|
|
|
25
|
+
`<channel>` is a placeholder, like `hv_setup_...` and the API URL beside it:
|
|
26
|
+
**the Haven dashboard hands you the exact command to run — copy that one.** The
|
|
27
|
+
channel is per-deployment and has been since #2422: the backend's setup response
|
|
28
|
+
names the whole package in `connector_package`, production hands out
|
|
29
|
+
`@haven_ai/connect@alpha`, and a non-production deployment can be configured to
|
|
30
|
+
hand out another, such as `@haven_ai/connect@dev`. This README ships inside every
|
|
31
|
+
channel's tarball and is the npm landing page for all of them, so a literal here
|
|
32
|
+
would be wrong for every reader it did not describe (#2515).
|
|
33
|
+
Read `connector_package` rather than assuming any particular backend's channel. Pinning `@alpha` by hand against such a backend
|
|
34
|
+
installs a signer that skews against it — the signer refuses to sign an
|
|
35
|
+
`x402_expected_context_version` it does not know.
|
|
36
|
+
|
|
14
37
|
The connector writes owner-only credential files outside the project by default:
|
|
15
38
|
|
|
16
39
|
- `~/.haven/agents/<agent-id>/identity.json` contains the Haven API key.
|
|
@@ -80,7 +103,8 @@ already-running host, which is why the restart guidance below matters.
|
|
|
80
103
|
|
|
81
104
|
## Retiring an old agent directory
|
|
82
105
|
|
|
83
|
-
Re-running setup creates a NEW agent and retires nothing
|
|
106
|
+
Re-running setup without `--replace` creates a NEW agent and retires nothing
|
|
107
|
+
(with `--replace`, see [Running setup again](#running-setup-again)). Long-lived MCP hosts
|
|
84
108
|
(gateways, TUI workers, editors, desktop apps) load their MCP wiring once, at
|
|
85
109
|
process start — a host started before your latest setup keeps spawning the OLD
|
|
86
110
|
agent's signer path forever, and when that directory is later removed the spawn
|
|
@@ -93,9 +117,12 @@ minutes. Two rules follow:
|
|
|
93
117
|
2. **Tombstone a directory before (or instead of) deleting it:**
|
|
94
118
|
|
|
95
119
|
```
|
|
96
|
-
npx @haven_ai/connect
|
|
120
|
+
npx @haven_ai/connect@<channel> --tombstone ~/.haven/agents/<directory> --reason "superseded" --json
|
|
97
121
|
```
|
|
98
122
|
|
|
123
|
+
`<channel>` is the placeholder defined under the first example; this command
|
|
124
|
+
rewrites local files only, so any published connector does the same job.
|
|
125
|
+
|
|
99
126
|
This replaces the directory's signer wrapper with a diagnostic that logs the
|
|
100
127
|
retirement (agent id, date, reason, restart guidance) to the host's MCP
|
|
101
128
|
stderr log on every probe, and records it in `TOMBSTONE.json` for
|
|
@@ -123,10 +150,13 @@ Hermes) the `MCP_HAVEN_API_KEY` dotenv line behind, and the runtime quoted as
|
|
|
123
150
|
one agent while signing as another. `--unwire` is the erase half:
|
|
124
151
|
|
|
125
152
|
```
|
|
126
|
-
npx @haven_ai/connect
|
|
127
|
-
npx @haven_ai/connect
|
|
153
|
+
npx @haven_ai/connect@<channel> --unwire ~/.haven/agents/<directory> [--reason "..."]
|
|
154
|
+
npx @haven_ai/connect@<channel> --unwire --name research [--reason "..."]
|
|
128
155
|
```
|
|
129
156
|
|
|
157
|
+
`<channel>` is the placeholder defined under the first example; `--unwire`
|
|
158
|
+
touches local files only, so any published connector does the same job.
|
|
159
|
+
|
|
130
160
|
It tombstone-first (so a stale long-lived host still hears `HAVEN-TOMBSTONE`,
|
|
131
161
|
never a masked `ENOENT`), then removes THAT agent's hosted + signer pair from
|
|
132
162
|
every runtime config it appears in (Hermes YAML, Codex TOML, the Cursor / VS
|
|
@@ -150,17 +180,31 @@ Pass `--json` when a launcher needs a machine-readable completion record. Connec
|
|
|
150
180
|
writes progress and human recovery notes to stderr and exactly one JSON object
|
|
151
181
|
to stdout, with `schema_version: 1` and `outcome` set to `complete`,
|
|
152
182
|
`action_required`, or `failed`. Structured runs skip the interactive
|
|
153
|
-
budget-approval wait so the record is emitted promptly;
|
|
154
|
-
|
|
183
|
+
budget-approval wait so the record is emitted promptly; open `approval.url`
|
|
184
|
+
whenever ready and verify later with the read-only `haven_get_agent`
|
|
155
185
|
tool. The object includes runtime/topology status,
|
|
156
186
|
probe result, activation and next-action guidance, approval state/expiry (null
|
|
157
|
-
when the backend does not provide an approval expiry)
|
|
158
|
-
read-only verification tools, `hosted_mcp_url`,
|
|
187
|
+
when the backend does not provide an approval expiry) and `approval.url`, the two
|
|
188
|
+
read-only verification tools, `hosted_mcp_url`, `superseded_agent_ids`, and —
|
|
189
|
+
on a run that replaced existing wiring — `superseded_agents_retired_locally`
|
|
190
|
+
with `retired_agent_ids`. It
|
|
159
191
|
contains no API key, private key, credential
|
|
160
192
|
contents, full credential paths, or full delegate address. The same redacted
|
|
161
193
|
object is available to library callers as `runConnect(...).outcome`; the older
|
|
162
194
|
fields remain for additive compatibility.
|
|
163
195
|
|
|
196
|
+
`approval.url` (#2528) is the absolute link to this setup's budget approval,
|
|
197
|
+
returned by the backend at register. Present only when `approval.required` is
|
|
198
|
+
`true` **and** the backend is new enough to send one — a deployment older than
|
|
199
|
+
#2528 omits the key entirely, which is why a caller must test for it rather
|
|
200
|
+
than assume it. In prose mode the same link replaces "Return to Haven" in the
|
|
201
|
+
printed next steps. It carries no secret (the setup token never appears in it),
|
|
202
|
+
and it is the ONLY approval link a caller should use: the outcome carries no
|
|
203
|
+
setup id, so there is nothing to assemble one from — relay the whole link or
|
|
204
|
+
none. The connector also reports `run_mode` (`json` or `prose`) to the backend
|
|
205
|
+
at register, so Haven can tell an automated setup from a narrated one; it is
|
|
206
|
+
sent, not returned, and appears in no output.
|
|
207
|
+
|
|
164
208
|
`hosted_mcp_url` is the hosted MCP endpoint this run wired up — **not** the
|
|
165
209
|
backend URL you passed as `--api`. The hosted MCP server is a separate
|
|
166
210
|
deployment, so the two differing is intended topology, not an environment
|
|
@@ -168,11 +212,40 @@ mismatch. It is non-secret: the same string goes into your own MCP config file,
|
|
|
168
212
|
and the API key travels beside it in a header.
|
|
169
213
|
|
|
170
214
|
`superseded_agent_ids` lists the other agent directories on this machine. A
|
|
171
|
-
re-run mints a NEW agent and retires nothing, so those
|
|
172
|
-
live API and signing keys — revoke them on the Haven
|
|
173
|
-
replace them. Empty on a clean first run; an empty
|
|
174
|
-
since a scan that cannot read the credential root
|
|
175
|
-
failing a completed setup.
|
|
215
|
+
re-run mints a NEW agent, and without `--replace` retires nothing, so those
|
|
216
|
+
older agents still hold live API and signing keys — revoke them on the Haven
|
|
217
|
+
agent page if you meant to replace them. Empty on a clean first run; an empty
|
|
218
|
+
list here is not a guarantee, since a scan that cannot read the credential root
|
|
219
|
+
also yields one rather than failing a completed setup.
|
|
220
|
+
|
|
221
|
+
**The dashboard offers the revoke, never the connector (#2561).** The same ids
|
|
222
|
+
now ride the install-status report, so the Haven dashboard can put a
|
|
223
|
+
one-click revoke next to the setup that displaced them. The connector does not
|
|
224
|
+
and must not do it: `POST /agents/:id/revoke` is owner-authenticated, and an
|
|
225
|
+
agent credential retiring a sibling agent is the "agent editing its own
|
|
226
|
+
authority" the re-key routes refuse. Nothing is revoked automatically — the
|
|
227
|
+
owner clicks, one agent at a time.
|
|
228
|
+
|
|
229
|
+
On the REPORT the field is a tri-state, unlike the `--json` outcome above: a
|
|
230
|
+
list, `[]` when the scan ran and found none, and `null` when it could not run.
|
|
231
|
+
That is the same ambiguity this paragraph warns you about, made machine-
|
|
232
|
+
readable, so a dashboard never tells somebody their machine is clean when
|
|
233
|
+
nobody managed to read it. On a `--replace` run, `retired_agent_ids` names the
|
|
234
|
+
directories that were actually tombstoned and had their local key files removed
|
|
235
|
+
— **the collision set only**, never the whole `superseded_agent_ids` list, which
|
|
236
|
+
also names named agents that coexist with the replaced bare pair and are
|
|
237
|
+
untouched — and `superseded_agents_retired_locally` is `true` when that
|
|
238
|
+
retirement covered every collision entry (`false`: the install ended with an
|
|
239
|
+
error code and the retirement was skipped, or one entry failed). Both fields
|
|
240
|
+
are absent on any other run and say nothing about the backend, where nothing is
|
|
241
|
+
revoked.
|
|
242
|
+
|
|
243
|
+
A `wiring_collision` refusal (a non-interactive bare setup over a live
|
|
244
|
+
previous agent, #2551) carries `error.superseded_agent_ids` and
|
|
245
|
+
`error.suggested_name` — the ids the human needs in order to decide, and a
|
|
246
|
+
valid `--name` the run can be re-issued with — with `next_action:
|
|
247
|
+
relay_wiring_collision_to_user`. It is a relay, not a retry hint: do not append
|
|
248
|
+
`--replace` or `--name` on the agent's own initiative.
|
|
176
249
|
|
|
177
250
|
For a recoverable install, configuration, probe, consent, or manual-runtime
|
|
178
251
|
condition, inspect `error.code` and `error.next_action`, then follow the safe
|
|
@@ -221,12 +294,25 @@ an extra "about to create agent X, proceed?" gate. That is deliberate: the
|
|
|
221
294
|
consent already happened when the user minted the one-time setup prompt in the
|
|
222
295
|
Haven dashboard, which enumerates exactly what the command may do. The setup
|
|
223
296
|
stays cancellable from the dashboard throughout, and the registered agent
|
|
224
|
-
starts `pending_approval` with zero
|
|
225
|
-
until the user approves the budget in Haven.
|
|
226
|
-
|
|
297
|
+
starts `pending_approval` with zero spending authority — no budgeted spend can
|
|
298
|
+
move until the user approves the budget in Haven. The exact sweep-recovery
|
|
299
|
+
routes remain available only to recover a stranded delegate balance and do not
|
|
300
|
+
grant spending authority. A CLI-side confirmation would add friction without
|
|
301
|
+
adding a security boundary. (The local-signer tool-exposure
|
|
227
302
|
acknowledgement is a separate, machine-checkable consent about what the local
|
|
228
303
|
MCP tools expose, not a registration gate.)
|
|
229
304
|
|
|
305
|
+
The one question Connect does put before registration is not about the
|
|
306
|
+
agent being created but about the one already here: a **wiring collision**
|
|
307
|
+
([#2551](https://github.com/d-hinders/Haven-AI/issues/2551)). When the bare
|
|
308
|
+
`haven` / `haven-signer` pair on this machine already belongs to a different
|
|
309
|
+
agent whose directory still holds a live key, proceeding would silently
|
|
310
|
+
re-point that pair — the state `--doctor` reports as a still-spend-capable
|
|
311
|
+
`superseded` directory. That choice (replace it, or install alongside under a
|
|
312
|
+
name) belongs to the user, and it is asked *before* the key is minted or the
|
|
313
|
+
agent registered so that declining leaves no orphaned `pending_approval` agent
|
|
314
|
+
behind. See [Running setup again](#running-setup-again).
|
|
315
|
+
|
|
230
316
|
## Running setup again
|
|
231
317
|
|
|
232
318
|
Each setup prompt is one-time and each successful run creates a **new** agent
|
|
@@ -235,7 +321,7 @@ already-configured machine behaves as follows (characterized in
|
|
|
235
321
|
`storage.test.ts`, `config-writers.test.ts`, `runtime.test.ts`, and
|
|
236
322
|
`runtime-install.test.ts`, #1544/#1569):
|
|
237
323
|
|
|
238
|
-
- **Re-running an already-consumed
|
|
324
|
+
- **Re-running an already-consumed connector command** fails cleanly before any
|
|
239
325
|
credential file or runtime configuration is touched — Haven refuses the
|
|
240
326
|
consumed setup when Connect resolves it (or, in a rare concurrent-run race,
|
|
241
327
|
at registration). The key pair minted for the attempt exists only in memory
|
|
@@ -244,17 +330,44 @@ already-configured machine behaves as follows (characterized in
|
|
|
244
330
|
credentials into its own directory under `~/.haven/agents/<agent-id>/`,
|
|
245
331
|
alongside the previous agent's directory, which stays byte-identical.
|
|
246
332
|
Nothing is rotated, revoked, or deleted locally.
|
|
247
|
-
- **
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
333
|
+
- **A bare re-run over a live previous agent is a decision, not a default
|
|
334
|
+
([#2551](https://github.com/d-hinders/Haven-AI/issues/2551)).** Before
|
|
335
|
+
minting a key or registering, Connect scans the credential root for a
|
|
336
|
+
bare-pair directory that still holds a usable key — the same reading
|
|
337
|
+
`--doctor` classifies as `wired` or `superseded`; `retired`, `orphaned`,
|
|
338
|
+
`parked` and **named** directories never count. If it finds one:
|
|
339
|
+
- an **interactive terminal** is asked to choose — **replace** (below) or
|
|
340
|
+
**install alongside** under a name Connect proposes from the agent's
|
|
341
|
+
display name (e.g. `payment-agent`), collision-checked against the
|
|
342
|
+
directories already there;
|
|
343
|
+
- a **non-interactive run** (`--json`, CI, an agent tool call, a pipe)
|
|
344
|
+
refuses with `wiring_collision` — nothing written, token still unused —
|
|
345
|
+
naming the superseded agent ids and the two flags that resolve it. The
|
|
346
|
+
refusal is written as a **relay instruction**: an agent running the
|
|
347
|
+
dashboard's command may append only `--json` (and `--runtime` after a
|
|
348
|
+
runtime refusal), so it must hand the choice to its user rather than add
|
|
349
|
+
a flag itself, and re-run only with the flag the user picks.
|
|
350
|
+
- **`--replace`** is the unattended answer "yes, replace". `--name <slug>`
|
|
351
|
+
installs alongside. Passing both is a usage error — they contradict.
|
|
352
|
+
- **Replacing re-points the bare pair, then retires the previous directory
|
|
353
|
+
locally.** Connect owns the `haven` and `haven-signer` entries (and the
|
|
354
|
+
managed Codex/Hermes equivalents) and re-points them at the new agent's
|
|
355
|
+
credentials; unrelated MCP servers and configuration are preserved. Once
|
|
356
|
+
the runtime install has actually completed, each superseded directory is
|
|
357
|
+
tombstoned and its local key files removed — the same teardown `--unwire`
|
|
358
|
+
performs — so `--doctor` reads it as `retired` rather than still
|
|
359
|
+
spend-capable. If the install ends with an error code the retirement is
|
|
360
|
+
**skipped**, because the old wiring may still be the only working one; the
|
|
361
|
+
outcome's `superseded_agents_retired_locally` says which happened and
|
|
362
|
+
`retired_agent_ids` names exactly the directories it reached. With
|
|
252
363
|
`--name`, each agent owns its own suffixed pair and they coexist; see
|
|
253
364
|
[Running several agents in one runtime](#running-several-agents-in-one-runtime).
|
|
254
|
-
- **The previous agent is not revoked by a re-run
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
365
|
+
- **The previous agent is not revoked by a re-run — with or without
|
|
366
|
+
`--replace`.** Local retirement is local: its authority remains whatever
|
|
367
|
+
its on-chain rules and the Haven agent page say. Revoke agents you no
|
|
368
|
+
longer use from the Haven dashboard. Connect never calls revoke — that
|
|
369
|
+
route is owner-authenticated, and an agent credential revoking a sibling
|
|
370
|
+
agent would be an agent editing its own authority.
|
|
258
371
|
- **A re-run never overwrites an existing credential file.** A write that would
|
|
259
372
|
collide with an existing `identity.json`/`signer.json`/`agent.json` is
|
|
260
373
|
refused outright (and a partially failed write rolls itself back), so a
|
|
@@ -271,10 +384,14 @@ directory, so several agents coexist in one runtime instead of replacing each
|
|
|
271
384
|
other:
|
|
272
385
|
|
|
273
386
|
```sh
|
|
274
|
-
npx -y @haven_ai/connect
|
|
387
|
+
npx -y @haven_ai/connect@<channel> --setup hv_setup_... --api https://api.haven.example \
|
|
275
388
|
--name research --runtime claude-code
|
|
276
389
|
```
|
|
277
390
|
|
|
391
|
+
As above, `<channel>` is a placeholder like the rest of this line: take the
|
|
392
|
+
package from the setup response's `connector_package`
|
|
393
|
+
and add `--name` to the command the dashboard gave you.
|
|
394
|
+
|
|
278
395
|
| | Without `--name` | With `--name research` |
|
|
279
396
|
|---|---|---|
|
|
280
397
|
| MCP entries | `haven`, `haven-signer` | `haven-research`, `haven-signer-research` |
|
|
@@ -313,16 +430,24 @@ design. So it runs in two phases with the dashboard between them:
|
|
|
313
430
|
|
|
314
431
|
```sh
|
|
315
432
|
# 1. On this machine: generate the new key, print its public address.
|
|
316
|
-
npx -y @haven_ai/connect
|
|
433
|
+
npx -y @haven_ai/connect@<channel> --rekey [--name research]
|
|
317
434
|
|
|
318
435
|
# 2. In the dashboard: agent → Replace signing key → paste that address.
|
|
319
436
|
# Sign the steps. It shows a new API key ONCE.
|
|
320
437
|
|
|
321
438
|
# 3. Back here: write the new credentials and rewire this agent's MCP pair.
|
|
322
|
-
npx -y @haven_ai/connect
|
|
439
|
+
npx -y @haven_ai/connect@<channel> --rekey-finish --api-key sk_agent_... \
|
|
323
440
|
--runtime claude-code [--name research]
|
|
324
441
|
```
|
|
325
442
|
|
|
443
|
+
**Phase one prints the exact phase-two command — prefer it over the line above.**
|
|
444
|
+
Since [#2423](https://github.com/d-hinders/Haven-AI/issues/2423) the connector
|
|
445
|
+
builds that command from the npm dist-tag **it** was published under, so a build
|
|
446
|
+
installed from a non-production channel tells you to finish with that same
|
|
447
|
+
channel rather than sending you to production mid-re-key. `@alpha` is what
|
|
448
|
+
production hands out and is right for a production install; it is not right for
|
|
449
|
+
every install, which is why the tool computes it and this page cannot.
|
|
450
|
+
|
|
326
451
|
Between the two phases nothing has changed: the agent keeps working on its old
|
|
327
452
|
key until you finish. Phase one refuses up front what the backend would refuse
|
|
328
453
|
anyway — a legacy-rail account, a revoked agent — so you find out before signing
|
|
@@ -349,12 +474,19 @@ across the rest is yours.
|
|
|
349
474
|
## Diagnosing a stuck setup: `--doctor` / `--repair` (#1589)
|
|
350
475
|
|
|
351
476
|
```bash
|
|
352
|
-
npx @haven_ai/connect
|
|
353
|
-
npx @haven_ai/connect
|
|
477
|
+
npx @haven_ai/connect@<channel> --doctor --runtime codex-desktop
|
|
478
|
+
npx @haven_ai/connect@<channel> --doctor --repair --runtime codex-desktop
|
|
354
479
|
```
|
|
355
480
|
|
|
481
|
+
`<channel>` is the placeholder defined under the first example — and here it is
|
|
482
|
+
not indifferent: `signer_runtime` compares the sidecar against the manifest of
|
|
483
|
+
the connector **that runs the check**, so a doctor from another channel reports
|
|
484
|
+
a skew that is not there. Use the channel your dashboard hands out.
|
|
485
|
+
|
|
356
486
|
`--doctor` is read-only and needs NO setup token: it checks the runtime config,
|
|
357
|
-
the agent credential files, the pinned signer runtime install,
|
|
487
|
+
the agent credential files, the pinned signer runtime install (and, since
|
|
488
|
+
#2424, whether that install was made under a local runtime-spec override —
|
|
489
|
+
see the last section of this file), the hosted MCP
|
|
358
490
|
(authorized `tools/list`), and starts the local signer for a real stdio
|
|
359
491
|
handshake — reporting its advertised compat versions. Every failing check
|
|
360
492
|
prints one concrete repair action; the exit code is non-zero on any failure.
|
|
@@ -362,10 +494,14 @@ Add `--json` for a machine-readable report. No secret material is ever
|
|
|
362
494
|
printed.
|
|
363
495
|
|
|
364
496
|
`--doctor` also probes every OTHER agent credential directory it did not
|
|
365
|
-
select (#1688). A re-run of setup mints a NEW agent and
|
|
366
|
-
a directory from a previous setup
|
|
367
|
-
authenticates — meaning any host that started
|
|
368
|
-
spending as the agent you believe you replaced.
|
|
497
|
+
select (#1688). A re-run of setup mints a NEW agent and, unless it ran with
|
|
498
|
+
`--replace` (#2551), retires nothing, so a directory from a previous setup
|
|
499
|
+
can hold an API key that still authenticates — meaning any host that started
|
|
500
|
+
before the re-run keeps spending as the agent you believe you replaced. Since
|
|
501
|
+
#2551 a bare setup no longer reaches that state silently: it asks at a
|
|
502
|
+
terminal and refuses everywhere else, so a `superseded` directory now means
|
|
503
|
+
someone chose it — a `--replace` whose install failed, an older connector, or
|
|
504
|
+
a directory this scan could not classify. A superseded directory
|
|
369
505
|
whose key is still live is a FAILING check naming the agent id, with the
|
|
370
506
|
repair spelled out: revoke it on the Haven agent page, then remove the
|
|
371
507
|
directory. An already-revoked one reports as informational; an unreachable
|
|
@@ -381,3 +517,85 @@ which.
|
|
|
381
517
|
`--repair` re-runs what setup already owns — reinstall the pinned signer
|
|
382
518
|
runtime, rewrite the wrapper + sidecar, and re-write the runtime config from
|
|
383
519
|
the STORED credentials. It never touches keys and never needs a new token.
|
|
520
|
+
|
|
521
|
+
## Installing an unpublished signer / SDK / MCP build (`HAVEN_SIGNER_SPEC`, #2424)
|
|
522
|
+
|
|
523
|
+
Setup installs the connector's **pinned** siblings — `@haven_ai/signer@<pin>`
|
|
524
|
+
and `@haven_ai/sdk@<pin>` into `~/.haven/signer-runtime/<pin>`, and for
|
|
525
|
+
`--local` also `@haven_ai/mcp@<pin>` into `~/.haven/mcp-runtime/<pin>`. That
|
|
526
|
+
is right for every user and wrong for the one developer iterating on the
|
|
527
|
+
signer or SDK, who otherwise has to publish to find out whether a change works
|
|
528
|
+
end to end. Three environment variables name a different spec:
|
|
529
|
+
|
|
530
|
+
| Variable | Replaces | Read by |
|
|
531
|
+
|---|---|---|
|
|
532
|
+
| `HAVEN_SIGNER_SPEC` | `@haven_ai/signer@<pin>` | the signer runtime (default topology) |
|
|
533
|
+
| `HAVEN_SDK_SPEC` | `@haven_ai/sdk@<pin>` | both runtimes — each installs the SDK |
|
|
534
|
+
| `HAVEN_MCP_SPEC` | `@haven_ai/mcp@<pin>` | the `--local` MCP runtime |
|
|
535
|
+
|
|
536
|
+
A value is anything `npm install` accepts for that package: a checkout
|
|
537
|
+
(`file:/abs/path/to/packages/signer`), a tarball from `npm pack`
|
|
538
|
+
(`/abs/haven_ai-signer-0.0.0.tgz`), or an explicit version
|
|
539
|
+
(`@haven_ai/signer@<version>`). Set it in the shell that runs the setup
|
|
540
|
+
command — the command itself is unchanged:
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
HAVEN_SIGNER_SPEC=file:$PWD/packages/signer npx @haven_ai/connect@<channel> --setup <token> --runtime claude-code
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
`<channel>` is the placeholder defined under the first example.
|
|
547
|
+
|
|
548
|
+
Environment variables rather than a flag, deliberately: the install runs from
|
|
549
|
+
three entry points (`--setup`, `--doctor --repair`, `--rekey-finish`) and all
|
|
550
|
+
three honour the same variables, so a re-key cannot silently reinstall the
|
|
551
|
+
registry build; and the connector command is minted by the dashboard and pasted
|
|
552
|
+
verbatim, often by an agent, so the override sits beside it instead of being
|
|
553
|
+
spliced into a line the developer did not write.
|
|
554
|
+
|
|
555
|
+
**What an active override changes:**
|
|
556
|
+
|
|
557
|
+
- The runtime directory is `~/.haven/signer-runtime/override-<hash>` (or
|
|
558
|
+
`mcp-runtime/override-<hash>`), keyed by a short hash of the **resolved**
|
|
559
|
+
specs — overridden and pinned alike — so it can never poison the
|
|
560
|
+
version-named directory the normal path reuses, and a pinned-sibling bump
|
|
561
|
+
gets a fresh one.
|
|
562
|
+
- The install is **never reused** from an earlier run: a rebuilt `file:`
|
|
563
|
+
package must not be shadowed by a cache hit.
|
|
564
|
+
- Setup prints `RUNTIME SPEC OVERRIDE ACTIVE …` first, naming each variable
|
|
565
|
+
and the pin it replaced; `--rekey-finish` prints the same line.
|
|
566
|
+
- `signer-runtime.json` / `mcp-runtime.json` record the override under
|
|
567
|
+
`runtime_spec_override`, and their `*_version` fields hold what npm actually
|
|
568
|
+
installed rather than the manifest pins.
|
|
569
|
+
- The wrapper the agent client launches carries a
|
|
570
|
+
`// HAVEN RUNTIME SPEC OVERRIDE (#2424): …` comment.
|
|
571
|
+
- `--doctor` reports a failing `runtime_spec_override` check — "runtime spec
|
|
572
|
+
overridden — not the pinned manifest" — whenever the sidecar says the
|
|
573
|
+
install ran under one **or** a `HAVEN_*_SPEC` variable is set in the shell
|
|
574
|
+
running the doctor (a `--repair` from that shell would install it). The
|
|
575
|
+
override is legitimate; the finding is its record. Under an override the
|
|
576
|
+
`signer_runtime` check compares the directory against the sidecar's own
|
|
577
|
+
record, not the manifest.
|
|
578
|
+
|
|
579
|
+
**What it never changes:** the post-setup handshake probe still requires
|
|
580
|
+
every tool in the manifest's `requiredTools` / `requiredSignerTools`, so a
|
|
581
|
+
local build that dropped a tool fails setup exactly like a bad registry
|
|
582
|
+
version would. A set-but-malformed value — empty, containing whitespace or a
|
|
583
|
+
shell metacharacter — is refused **before** npm runs and before anything is
|
|
584
|
+
written, with a message naming the variable. With no variable set, nothing
|
|
585
|
+
here runs: the install arguments, directory, sidecar and wrapper are
|
|
586
|
+
byte-for-byte what they were before the override existed (pinned by exact
|
|
587
|
+
characterization tests in `signer-runtime.test.ts` and
|
|
588
|
+
`local-mcp-runtime.test.ts`).
|
|
589
|
+
|
|
590
|
+
To return to the pinned manifest: unset the variables and run
|
|
591
|
+
`--doctor --repair --runtime <runtime>` (or re-run setup). The override
|
|
592
|
+
directories live under `~/.haven` like every other runtime directory, so the
|
|
593
|
+
same reset that removes `~/.haven` removes them.
|
|
594
|
+
|
|
595
|
+
That is the loop for a build that has **not** merged. For one that has — a
|
|
596
|
+
`@dev` snapshot of all five packages, published from every package-touching
|
|
597
|
+
push to `dev` — and for the owner steps that make the dev dashboard hand out
|
|
598
|
+
`npx -y @haven_ai/connect@dev …` in the first place, see the repository runbook
|
|
599
|
+
[`docs/operations/package-dev-channel.md`](https://github.com/d-hinders/Haven-AI/blob/dev/docs/operations/package-dev-channel.md).
|
|
600
|
+
The two compose: `@dev` picks the connector, these variables pick what it
|
|
601
|
+
installs.
|