@haven_ai/connect 0.0.0-dev.202610071809.5460535 → 0.0.0-dev.202610071831.a279c0e
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 +36 -12
- package/dist/cli.cjs +103 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +103 -20
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +103 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -4
- package/dist/index.d.ts +29 -4
- package/dist/index.js +103 -20
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -499,12 +499,24 @@ already-configured machine behaves as follows (characterized in
|
|
|
499
499
|
consumed setup when Connect resolves it (or, in a rare concurrent-run race,
|
|
500
500
|
at registration). The key pair minted for the attempt exists only in memory
|
|
501
501
|
and is discarded. Start a fresh connection from the Haven dashboard instead.
|
|
502
|
-
- **Running a fresh setup on a configured machine
|
|
503
|
-
credentials into its own directory under `~/.haven/agents/<
|
|
502
|
+
- **Running a fresh setup on a configured machine writes the new agent's
|
|
503
|
+
credentials into its own directory under `~/.haven/agents/<slug-or-id>/`,
|
|
504
504
|
alongside the previous agent's directory, which stays byte-identical.
|
|
505
|
-
Nothing is rotated, revoked, or deleted locally
|
|
505
|
+
Nothing is rotated, revoked, or deleted locally.**
|
|
506
|
+
- **A default setup names its pair from the agent's display name
|
|
507
|
+
([#3737](https://github.com/d-hinders/Haven-AI/issues/3737)) and never
|
|
508
|
+
collides.** Without `--name`, `--bare` or `--replace`, the connector derives
|
|
509
|
+
the slug itself (`proposeServerSlug`: slugified display name, `agent`
|
|
510
|
+
fallback, numeric suffix when taken) and wires `haven-<slug>` /
|
|
511
|
+
`haven-signer-<slug>` — de-collided against **every** directory under the
|
|
512
|
+
credential root (retired and key-removed ones included, so a slug freed by
|
|
513
|
+
`--unwire` is never reused), and marked `-dev` on a non-production backend
|
|
514
|
+
(Base Sepolia or any chain that is not Base mainnet 8453; an explicit
|
|
515
|
+
`--name` is used verbatim and never altered). Nothing is displaced, so
|
|
516
|
+
nothing is asked. `--bare` opts back into the unnamed pair.
|
|
506
517
|
- **A bare re-run over a live previous agent is a decision, not a default
|
|
507
|
-
([#2551](https://github.com/d-hinders/Haven-AI/issues/2551)).**
|
|
518
|
+
([#2551](https://github.com/d-hinders/Haven-AI/issues/2551)).** Only a run
|
|
519
|
+
that targets the bare pair — `--bare`, or `--replace` — can collide; before
|
|
508
520
|
minting a key or registering, Connect scans the credential root for a
|
|
509
521
|
bare-pair directory that still holds a usable key — the same reading
|
|
510
522
|
`--doctor` classifies as `wired` or `superseded`; `retired`, `orphaned`,
|
|
@@ -521,7 +533,9 @@ already-configured machine behaves as follows (characterized in
|
|
|
521
533
|
flag itself. The setup prompt then permits one re-run with the flag the
|
|
522
534
|
user picks (#3689), on top of `--json` and a `--runtime` retry.
|
|
523
535
|
- **`--replace`** is the unattended answer "yes, replace". `--name <slug>`
|
|
524
|
-
installs alongside.
|
|
536
|
+
installs alongside. `--bare` is the human opt-in to the unnamed pair and
|
|
537
|
+
refuses with `--name`. Passing `--replace --name` is a usage error — they
|
|
538
|
+
contradict.
|
|
525
539
|
- **Replacing re-points the bare pair, then retires the previous directory
|
|
526
540
|
locally.** Connect owns the `haven` and `haven-signer` entries (and the
|
|
527
541
|
managed Codex/Hermes equivalents) and re-points them at the new agent's
|
|
@@ -568,15 +582,17 @@ As above, `<channel>` is a placeholder like the rest of this line: take the
|
|
|
568
582
|
package from the setup response's `connector_package`
|
|
569
583
|
and add `--name` to the command the dashboard gave you.
|
|
570
584
|
|
|
571
|
-
| |
|
|
572
|
-
|
|
573
|
-
| MCP entries | `haven
|
|
574
|
-
| Credentials | `~/.haven/agents/<
|
|
585
|
+
| | Default (no `--name`) | `--name research` | `--bare` |
|
|
586
|
+
|---|---|---|---|
|
|
587
|
+
| MCP entries | `haven-<slug>`, `haven-signer-<slug>` (slug from the agent's display name, `-dev`-marked on a non-production backend) | `haven-research`, `haven-signer-research` | `haven`, `haven-signer` |
|
|
588
|
+
| Credentials | `~/.haven/agents/<slug>/` | `~/.haven/agents/research/` | `~/.haven/agents/<agent-id>/` |
|
|
575
589
|
|
|
576
590
|
A writer only ever touches the pair it owns, so adding a named agent cannot
|
|
577
|
-
disturb the bare pair or another named one.
|
|
578
|
-
to how the connector behaved before named pairs existed
|
|
579
|
-
wired needs changing
|
|
591
|
+
disturb the bare pair or another named one. **`--bare` wires the bare pair
|
|
592
|
+
byte-identically to how the connector behaved before named pairs existed**, so
|
|
593
|
+
nothing already wired needs changing — it is the one flag (besides
|
|
594
|
+
`--replace`) that reaches the unnamed pair, and it cannot be combined with
|
|
595
|
+
`--name`.
|
|
580
596
|
|
|
581
597
|
The slug is **1–32 lowercase letters, digits and single hyphens**, validated
|
|
582
598
|
before anything is written, and **immutable once wired** — it is the server name
|
|
@@ -616,6 +632,14 @@ npx -y @haven_ai/connect@<channel> --rekey-finish --api-key sk_agent_... \
|
|
|
616
632
|
--runtime claude-code [--name research]
|
|
617
633
|
```
|
|
618
634
|
|
|
635
|
+
**No `--name` needed when exactly one live agent is on the machine.** Since
|
|
636
|
+
[#3737](https://github.com/d-hinders/Haven-AI/issues/3737), `--rekey` without
|
|
637
|
+
`--name` selects the sole agent directory that still holds a stored API key —
|
|
638
|
+
tombstoned and key-removed directories left by `--unwire` do not count — and
|
|
639
|
+
the printed phase-two command carries that agent's exact `--name` when it has
|
|
640
|
+
one. With **several** live agents it refuses and lists them, so you must pass
|
|
641
|
+
`--name <slug>`; a bare agent needs no `--name`, exactly as before.
|
|
642
|
+
|
|
619
643
|
**Phase one prints the exact phase-two command — prefer it over the line above.**
|
|
620
644
|
Since [#2423](https://github.com/d-hinders/Haven-AI/issues/2423) the connector
|
|
621
645
|
builds that command from the npm dist-tag **it** was published under, so a build
|
package/dist/cli.cjs
CHANGED
|
@@ -325,6 +325,19 @@ async function readStoredCredentials(serverName, agentIdOrSlug, baseDir) {
|
|
|
325
325
|
`No Haven credentials at ${directory}. Nothing to re-key \u2014 connect this agent first, or pass the --name you wired it under.`
|
|
326
326
|
);
|
|
327
327
|
}
|
|
328
|
+
let discoveredSlug;
|
|
329
|
+
if (!key) {
|
|
330
|
+
const binding = await readJsonFile(path.join(directory, "mcp-server-binding.json"));
|
|
331
|
+
const hostedName = binding && typeof binding === "object" ? asString(binding.server_name) : void 0;
|
|
332
|
+
if (hostedName && hostedName.startsWith("haven-")) {
|
|
333
|
+
const slug = hostedName.slice("haven-".length);
|
|
334
|
+
try {
|
|
335
|
+
assertValidServerSlug(slug);
|
|
336
|
+
discoveredSlug = slug;
|
|
337
|
+
} catch {
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
328
341
|
const agent = await readJsonFile(path.join(directory, "agent.json")) ?? {};
|
|
329
342
|
const signer = await readJsonFile(path.join(directory, "signer.json")) ?? {};
|
|
330
343
|
const agentId = asString(identity.agent_id);
|
|
@@ -340,6 +353,7 @@ async function readStoredCredentials(serverName, agentIdOrSlug, baseDir) {
|
|
|
340
353
|
directory,
|
|
341
354
|
agentId,
|
|
342
355
|
apiKey,
|
|
356
|
+
...discoveredSlug ? { discoveredSlug } : {},
|
|
343
357
|
apiUrl,
|
|
344
358
|
hostedMcpUrl,
|
|
345
359
|
delegateAddress: asString(agent.delegate_address) ?? asString(signer.delegate_address),
|
|
@@ -368,7 +382,9 @@ async function discoverSoleAgentDirectory(baseDir) {
|
|
|
368
382
|
const candidates = [];
|
|
369
383
|
for (const entry of entries) {
|
|
370
384
|
const directory = path.join(root, entry);
|
|
371
|
-
|
|
385
|
+
const identity = await readJsonFile(path.join(directory, "identity.json"));
|
|
386
|
+
if (!identity) continue;
|
|
387
|
+
if (!asString(identity.api_key)) continue;
|
|
372
388
|
if (await readJsonFile(path.join(directory, "TOMBSTONE.json"))) continue;
|
|
373
389
|
candidates.push(directory);
|
|
374
390
|
}
|
|
@@ -598,6 +614,7 @@ async function listMcpServerBindings(baseDir, excludeDirectory) {
|
|
|
598
614
|
var REKEY_PENDING_FILENAME, REKEY_PENDING_TTL_MS, CONNECT_OUTCOME_FILENAME, MCP_SERVER_BINDING_FILENAME;
|
|
599
615
|
var init_storage = __esm({
|
|
600
616
|
"src/storage.ts"() {
|
|
617
|
+
init_server_names();
|
|
601
618
|
REKEY_PENDING_FILENAME = "rekey-pending.json";
|
|
602
619
|
REKEY_PENDING_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
603
620
|
CONNECT_OUTCOME_FILENAME = "last-connect-outcome.json";
|
|
@@ -620,9 +637,9 @@ var init_runtime_manifest = __esm({
|
|
|
620
637
|
mcpPackage: "@haven_ai/mcp",
|
|
621
638
|
mcpVersion: mcp.MCP_VERSION,
|
|
622
639
|
sdkPackage: "@haven_ai/sdk",
|
|
623
|
-
sdkVersion: "0.0.0-dev.
|
|
640
|
+
sdkVersion: "0.0.0-dev.202610071831.a279c0e",
|
|
624
641
|
signerPackage: "@haven_ai/signer",
|
|
625
|
-
signerVersion: "0.0.0-dev.
|
|
642
|
+
signerVersion: "0.0.0-dev.202610071831.a279c0e",
|
|
626
643
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
627
644
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
628
645
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -1035,7 +1052,9 @@ async function writeHermesConfig(input, deps) {
|
|
|
1035
1052
|
restartRequired: true,
|
|
1036
1053
|
messages: [
|
|
1037
1054
|
`Updated Haven MCP entries in ${target}; stored the hosted MCP identity in ${envTarget}.`,
|
|
1038
|
-
|
|
1055
|
+
// #3737: name the pair actually written — a bare run prints exactly the
|
|
1056
|
+
// historical sentence; a named run names its own pair.
|
|
1057
|
+
`Restart Hermes (start a new session; gateway users: /restart), then verify with \`hermes mcp list\`, \`hermes mcp test ${names.hosted}\`, and \`hermes mcp test ${names.signer}\`.`,
|
|
1039
1058
|
"If several long-lived Hermes processes are running (a gateway plus TUI workers), restart EVERY one: each loads its MCP wiring at startup, so a process started before this setup keeps using its old snapshot.",
|
|
1040
1059
|
"If no mcp_* tools appear after restart, ensure the MCP SDK is installed in Hermes: pip install mcp"
|
|
1041
1060
|
]
|
|
@@ -3392,17 +3411,45 @@ async function detectWiringCollision(input) {
|
|
|
3392
3411
|
suggestedServerName: proposeServerSlug(input.agentName, taken)
|
|
3393
3412
|
};
|
|
3394
3413
|
}
|
|
3395
|
-
function proposeServerSlug(agentName, taken) {
|
|
3396
|
-
let base = agentName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0,
|
|
3414
|
+
function proposeServerSlug(agentName, taken, maxBaseLength = 32) {
|
|
3415
|
+
let base = agentName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0, maxBaseLength).replace(/-+$/g, "");
|
|
3397
3416
|
if (!slugIsValid(base)) base = "agent";
|
|
3398
3417
|
if (!taken.has(base)) return base;
|
|
3399
3418
|
for (let n = 2; n < 1e3; n += 1) {
|
|
3400
3419
|
const suffix = `-${n}`;
|
|
3401
|
-
const candidate = `${base.slice(0,
|
|
3420
|
+
const candidate = `${base.slice(0, maxBaseLength - suffix.length).replace(/-+$/g, "")}${suffix}`;
|
|
3402
3421
|
if (slugIsValid(candidate) && !taken.has(candidate)) return candidate;
|
|
3403
3422
|
}
|
|
3404
3423
|
throw new Error(`Could not propose an unused server name for ${JSON.stringify(agentName)}.`);
|
|
3405
3424
|
}
|
|
3425
|
+
function deriveServerSlug(agentName, taken, markNonProduction) {
|
|
3426
|
+
const mark = "-dev";
|
|
3427
|
+
if (!markNonProduction) return proposeServerSlug(agentName, taken);
|
|
3428
|
+
const base = proposeServerSlug(agentName, taken, 32 - mark.length);
|
|
3429
|
+
if (base.endsWith(mark)) return base;
|
|
3430
|
+
const marked = `${base}${mark}`;
|
|
3431
|
+
if (!taken.has(marked)) return marked;
|
|
3432
|
+
return proposeServerSlug(marked, taken);
|
|
3433
|
+
}
|
|
3434
|
+
async function listTakenDirectoryNames(credentialsDir) {
|
|
3435
|
+
const root = defaultCredentialRoot(credentialsDir);
|
|
3436
|
+
let entries = [];
|
|
3437
|
+
try {
|
|
3438
|
+
entries = await promises.readdir(root);
|
|
3439
|
+
} catch {
|
|
3440
|
+
return /* @__PURE__ */ new Set();
|
|
3441
|
+
}
|
|
3442
|
+
const taken = /* @__PURE__ */ new Set();
|
|
3443
|
+
for (const entry of entries) {
|
|
3444
|
+
try {
|
|
3445
|
+
if (!(await promises.stat(path.join(root, entry))).isDirectory()) continue;
|
|
3446
|
+
} catch {
|
|
3447
|
+
continue;
|
|
3448
|
+
}
|
|
3449
|
+
taken.add(entry);
|
|
3450
|
+
}
|
|
3451
|
+
return taken;
|
|
3452
|
+
}
|
|
3406
3453
|
function slugIsValid(slug) {
|
|
3407
3454
|
try {
|
|
3408
3455
|
assertValidServerSlug(slug);
|
|
@@ -3802,7 +3849,16 @@ async function executeConnect(options, deps, trace) {
|
|
|
3802
3849
|
log("Checked local credential storage \u2014 all clear.");
|
|
3803
3850
|
let serverName = options.serverName;
|
|
3804
3851
|
let replacing;
|
|
3805
|
-
if (!serverName) {
|
|
3852
|
+
if (!serverName && options.deriveServerName) {
|
|
3853
|
+
const taken = await listTakenDirectoryNames(options.credentialsDir);
|
|
3854
|
+
const nonProduction = setup.haven_wallet.chain_id !== PRODUCTION_CHAIN_ID;
|
|
3855
|
+
serverName = deriveServerSlug(setup.agent.name, taken, nonProduction);
|
|
3856
|
+
await assertServerSlugAvailable(serverName, options.credentialsDir);
|
|
3857
|
+
const derivedNames = serverNamesFor(serverName);
|
|
3858
|
+
log(
|
|
3859
|
+
`Naming this agent's MCP pair from its display name: ${derivedNames.hosted} / ${derivedNames.signer}. Nothing was displaced; to wire the bare haven / haven-signer pair instead, re-run with --bare, or choose the name yourself with --name <slug>.`
|
|
3860
|
+
);
|
|
3861
|
+
} else if (!serverName) {
|
|
3806
3862
|
const collision = await detectWiringCollision({
|
|
3807
3863
|
credentialsDir: options.credentialsDir,
|
|
3808
3864
|
agentName: setup.agent.name
|
|
@@ -4077,6 +4133,9 @@ async function executeConnect(options, deps, trace) {
|
|
|
4077
4133
|
runtimeInstall,
|
|
4078
4134
|
delegateAddress: registration.delegate_address,
|
|
4079
4135
|
hostedMcpUrl: registration.hosted_mcp_url,
|
|
4136
|
+
// #3737: the resolved name — derived, explicit, or the bare pair — rides
|
|
4137
|
+
// the machine-readable outcome alongside the prose completion text.
|
|
4138
|
+
serverName,
|
|
4080
4139
|
supersededAgentIds,
|
|
4081
4140
|
supersededAgentsRetiredLocally,
|
|
4082
4141
|
...replacing ? { retiredAgentIds } : {},
|
|
@@ -4151,6 +4210,9 @@ function completionOutcome(input) {
|
|
|
4151
4210
|
// #3122: always emitted on a completed run (empty list included), for the
|
|
4152
4211
|
// same reason as superseded_agent_ids above.
|
|
4153
4212
|
existing_agents_before_write: input.existingAgentsBeforeWrite ?? [],
|
|
4213
|
+
// #3737: the resolved hosted server name — always present on a completed
|
|
4214
|
+
// run, bare pair included, so a caller never has to parse the prose.
|
|
4215
|
+
server_name: serverNamesFor(input.serverName).hosted,
|
|
4154
4216
|
...input.serverNameReboundFrom ? { server_name_rebound_from: input.serverNameReboundFrom } : {},
|
|
4155
4217
|
...input.setupChallengeExpiresAt ? { setup_challenge_expires_at: input.setupChallengeExpiresAt } : {},
|
|
4156
4218
|
...runtimeInstall.errorCode ? { error: { code: runtimeInstall.errorCode, next_action: nextAction2 } } : {}
|
|
@@ -4482,7 +4544,7 @@ async function listOtherAgentIds(baseDir, currentDirectory) {
|
|
|
4482
4544
|
function printNextSteps(result, log, approval, approvalUrl) {
|
|
4483
4545
|
for (const line of completionHandoffLines(result, approval, approvalUrl)) log(line);
|
|
4484
4546
|
}
|
|
4485
|
-
var CONNECTOR_VERSION, CONNECTOR_CLIENT_IDENTITY, CONNECT_OUTCOME_SCHEMA_VERSION, failureOutcomesByError, RERUN_HINT;
|
|
4547
|
+
var CONNECTOR_VERSION, PRODUCTION_CHAIN_ID, CONNECTOR_CLIENT_IDENTITY, CONNECT_OUTCOME_SCHEMA_VERSION, failureOutcomesByError, RERUN_HINT;
|
|
4486
4548
|
var init_runtime = __esm({
|
|
4487
4549
|
"src/runtime.ts"() {
|
|
4488
4550
|
init_api();
|
|
@@ -4499,7 +4561,8 @@ var init_runtime = __esm({
|
|
|
4499
4561
|
init_tombstone();
|
|
4500
4562
|
init_local_mcp_runtime();
|
|
4501
4563
|
init_runtime_manifest();
|
|
4502
|
-
CONNECTOR_VERSION = "0.0.0-dev.
|
|
4564
|
+
CONNECTOR_VERSION = "0.0.0-dev.202610071831.a279c0e";
|
|
4565
|
+
PRODUCTION_CHAIN_ID = 8453;
|
|
4503
4566
|
CONNECTOR_CLIENT_IDENTITY = `@haven_ai/connect/${CONNECTOR_VERSION}`;
|
|
4504
4567
|
CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
4505
4568
|
failureOutcomesByError = /* @__PURE__ */ new WeakMap();
|
|
@@ -4709,9 +4772,10 @@ async function startRekey(options, deps = {}) {
|
|
|
4709
4772
|
started_at: startedAt,
|
|
4710
4773
|
expires_at: expiresAt
|
|
4711
4774
|
});
|
|
4775
|
+
const finishName = options.serverName ?? stored.discoveredSlug;
|
|
4712
4776
|
const finishCommand = [
|
|
4713
4777
|
sdk.connectorRerunCommand("--rekey-finish"),
|
|
4714
|
-
|
|
4778
|
+
finishName ? `--name ${finishName}` : void 0,
|
|
4715
4779
|
"--api-key <the key the dashboard showed you>",
|
|
4716
4780
|
options.runtime ? `--runtime ${options.runtime}` : "--runtime <your runtime>"
|
|
4717
4781
|
].filter(Boolean).join(" ");
|
|
@@ -5770,6 +5834,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
5770
5834
|
let dryRun = false;
|
|
5771
5835
|
let unwireDir;
|
|
5772
5836
|
let replace = false;
|
|
5837
|
+
let bare = false;
|
|
5773
5838
|
for (let i = 0; i < argv.length; i += 1) {
|
|
5774
5839
|
const arg = argv[i];
|
|
5775
5840
|
if (arg === "--help" || arg === "-h") {
|
|
@@ -5817,6 +5882,8 @@ function parseArgs(argv, env = process.env) {
|
|
|
5817
5882
|
options.credentialsDir = requireValue(argv, ++i, arg);
|
|
5818
5883
|
} else if (arg === "--replace") {
|
|
5819
5884
|
replace = true;
|
|
5885
|
+
} else if (arg === "--bare") {
|
|
5886
|
+
bare = true;
|
|
5820
5887
|
} else if (arg === "--name") {
|
|
5821
5888
|
options.serverName = requireValue(argv, ++i, arg);
|
|
5822
5889
|
assertValidServerSlug(options.serverName);
|
|
@@ -5842,16 +5909,23 @@ function parseArgs(argv, env = process.env) {
|
|
|
5842
5909
|
if (help) {
|
|
5843
5910
|
return { options, help, json, doctor, repair, tombstone, rekey };
|
|
5844
5911
|
}
|
|
5845
|
-
if (replace) {
|
|
5912
|
+
if (replace || bare) {
|
|
5846
5913
|
if (rekeyPhase || tombstoneDir || unwire || doctor || repair || pruneSignerRuntimes2) {
|
|
5847
|
-
throw new Error("--replace belongs to a --setup run: it says what to do when the bare haven / haven-signer pair is already wired to another agent
|
|
5914
|
+
throw new Error(`${replace ? "--replace" : "--bare"} belongs to a --setup run: it says what to do when the bare haven / haven-signer pair is already wired to another agent.`);
|
|
5848
5915
|
}
|
|
5849
|
-
if (options.serverName) {
|
|
5916
|
+
if (bare && options.serverName) {
|
|
5850
5917
|
throw new Error(
|
|
5851
|
-
"--
|
|
5918
|
+
"--bare and --name contradict each other: --bare wires the bare haven / haven-signer pair, --name installs a named haven-<slug> pair. Pass one of them."
|
|
5852
5919
|
);
|
|
5853
5920
|
}
|
|
5854
|
-
|
|
5921
|
+
if (replace) {
|
|
5922
|
+
if (options.serverName) {
|
|
5923
|
+
throw new Error(
|
|
5924
|
+
"--replace and --name contradict each other: --replace overwrites the bare haven / haven-signer wiring, --name installs alongside it under its own pair. Pass one of them."
|
|
5925
|
+
);
|
|
5926
|
+
}
|
|
5927
|
+
options.replaceExistingWiring = true;
|
|
5928
|
+
}
|
|
5855
5929
|
}
|
|
5856
5930
|
if (destroyKeyMaterial && !unwire) {
|
|
5857
5931
|
throw new Error("--destroy-key-material only applies to --unwire.");
|
|
@@ -5925,6 +5999,9 @@ function parseArgs(argv, env = process.env) {
|
|
|
5925
5999
|
if (!options.apiBaseUrl) {
|
|
5926
6000
|
throw new Error("Missing --api <Haven API URL>.");
|
|
5927
6001
|
}
|
|
6002
|
+
if (!options.serverName && !bare && !replace) {
|
|
6003
|
+
options.deriveServerName = true;
|
|
6004
|
+
}
|
|
5928
6005
|
options.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
|
|
5929
6006
|
return { options, help, json, doctor, repair, tombstone, rekey };
|
|
5930
6007
|
}
|
|
@@ -5952,13 +6029,19 @@ function helpText() {
|
|
|
5952
6029
|
" --replace When this machine is already wired to a different Haven agent on the bare",
|
|
5953
6030
|
" haven / haven-signer pair, re-point that pair at the new agent and retire the",
|
|
5954
6031
|
" previous agent directory locally (tombstoned, local key files removed).",
|
|
5955
|
-
" Nothing is revoked \u2014 use Remove agent\u2026 on the Haven agent page.
|
|
5956
|
-
"
|
|
5957
|
-
" and an interactive terminal is asked
|
|
6032
|
+
" Nothing is revoked \u2014 use Remove agent\u2026 on the Haven agent page. Implies",
|
|
6033
|
+
" the bare pair. Without it (or --bare) a non-interactive run REFUSES such a",
|
|
6034
|
+
" collision (wiring_collision) and an interactive terminal is asked.",
|
|
6035
|
+
" --bare Wire the bare haven / haven-signer pair. Without --name a setup now names",
|
|
6036
|
+
" its pair from the agent's display name (haven-<slug> /",
|
|
6037
|
+
" haven-signer-<slug>, de-collided against this machine, ending -dev on a",
|
|
6038
|
+
" non-production backend), so adding an agent never has to displace anyone;",
|
|
6039
|
+
" --bare is the explicit opt-in to the unnamed pair. --name overrides it.",
|
|
5958
6040
|
" --name <slug> Wiring slug for a NAMED agent: writes haven-<slug> / haven-signer-<slug>",
|
|
5959
6041
|
" MCP entries and stores credentials at ~/.haven/agents/<slug>/, so several",
|
|
5960
6042
|
" agents can run side by side in one runtime. 1-32 lowercase letters, digits,",
|
|
5961
|
-
" single hyphens; immutable once wired.
|
|
6043
|
+
" single hyphens; immutable once wired. Without it the pair is named from the",
|
|
6044
|
+
" agent's display name; --bare wires the bare haven / haven-signer pair.",
|
|
5962
6045
|
" --ack-local-tools Write the one-time local Haven tools acknowledgement during setup.",
|
|
5963
6046
|
" --ack-signer Backward-compatible alias for --ack-local-tools.",
|
|
5964
6047
|
" --local Advanced: install the fully-local Haven MCP (no hosted dependency).",
|