@haven_ai/connect 0.0.0-dev.202609181713.990ba70 → 0.0.0-dev.202609181807.87b28b1
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.cjs +74 -24
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +74 -24
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +74 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +74 -24
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/cli.cjs
CHANGED
|
@@ -533,6 +533,16 @@ async function writeConnectOutcomeRecord(directory, outcome, warn) {
|
|
|
533
533
|
await restrictPermissions(path$1, 384, warn);
|
|
534
534
|
return path$1;
|
|
535
535
|
}
|
|
536
|
+
async function readConnectOutcomeRuntime(directory) {
|
|
537
|
+
try {
|
|
538
|
+
const parsed = JSON.parse(await promises.readFile(path.join(directory, CONNECT_OUTCOME_FILENAME), "utf8"));
|
|
539
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
540
|
+
const runtime = parsed.runtime;
|
|
541
|
+
return typeof runtime === "string" && runtime.length > 0 ? runtime : null;
|
|
542
|
+
} catch {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
536
546
|
var REKEY_PENDING_FILENAME, REKEY_PENDING_TTL_MS, CONNECT_OUTCOME_FILENAME;
|
|
537
547
|
var init_storage = __esm({
|
|
538
548
|
"src/storage.ts"() {
|
|
@@ -557,9 +567,9 @@ var init_runtime_manifest = __esm({
|
|
|
557
567
|
mcpPackage: "@haven_ai/mcp",
|
|
558
568
|
mcpVersion: mcp.MCP_VERSION,
|
|
559
569
|
sdkPackage: "@haven_ai/sdk",
|
|
560
|
-
sdkVersion: "0.0.0-dev.
|
|
570
|
+
sdkVersion: "0.0.0-dev.202609181807.87b28b1",
|
|
561
571
|
signerPackage: "@haven_ai/signer",
|
|
562
|
-
signerVersion: "0.0.0-dev.
|
|
572
|
+
signerVersion: "0.0.0-dev.202609181807.87b28b1",
|
|
563
573
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
564
574
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
565
575
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -3520,6 +3530,20 @@ __export(doctor_exports, {
|
|
|
3520
3530
|
runDoctor: () => runDoctor,
|
|
3521
3531
|
runRepair: () => runRepair
|
|
3522
3532
|
});
|
|
3533
|
+
function runtimeFlagFor(runtime) {
|
|
3534
|
+
return normalizeRuntimeName(runtime) ? ` --runtime ${runtime}` : "";
|
|
3535
|
+
}
|
|
3536
|
+
async function resolveDoctorRuntime(input, directory) {
|
|
3537
|
+
const explicit = input.runtime.trim();
|
|
3538
|
+
if (explicit) return { runtime: explicit, origin: "flag" };
|
|
3539
|
+
if (directory) {
|
|
3540
|
+
const recorded = await readConnectOutcomeRuntime(directory);
|
|
3541
|
+
if (recorded !== null && normalizeRuntimeName(recorded)) {
|
|
3542
|
+
return { runtime: recorded, origin: "record" };
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
return { runtime: "", origin: "unknown" };
|
|
3546
|
+
}
|
|
3523
3547
|
async function discoverCredentialDirectory(homeDir, explicit) {
|
|
3524
3548
|
const root = explicit ? path.dirname(explicit) : path.join(homeDir, ".haven", "agents");
|
|
3525
3549
|
let entries = [];
|
|
@@ -3600,7 +3624,7 @@ function rekeyPendingCheck(status, hostedDelegateAddress, runtime, slug) {
|
|
|
3600
3624
|
label,
|
|
3601
3625
|
ok: false,
|
|
3602
3626
|
detail: `A re-key started ${started} has COMPLETED on Haven \u2014 the agent's signing address is already ${address}, the one this machine generated \u2014 but the local half was never finished, so the credential files here still hold the old key. Parked at ${status.path}.` + (status.state === "expired" ? " The local file is also past its 24h TTL, which --rekey-finish refuses, so the finish command below will not accept it any more." : ""),
|
|
3603
|
-
repair: status.state === "expired" ? `The parked key expired. Start again \u2014 ${RERUN} --rekey${nameFlag} \u2014 and re-run "Replace signing key" on the Haven agent page with the new address it prints.` : `Run: ${RERUN} --rekey-finish${nameFlag} --api-key <the key the agent page showed you
|
|
3627
|
+
repair: status.state === "expired" ? `The parked key expired. Start again \u2014 ${RERUN} --rekey${nameFlag} \u2014 and re-run "Replace signing key" on the Haven agent page with the new address it prints.` : `Run: ${RERUN} --rekey-finish${nameFlag} --api-key <the key the agent page showed you>${runtimeFlagFor(runtime)}`
|
|
3604
3628
|
};
|
|
3605
3629
|
}
|
|
3606
3630
|
const wedgeNote = "Haven is NOT yet on this address, so the re-key did not complete. This machine cannot tell whether the on-chain revoke on the agent page already ran: if it did not, closing this costs nothing; if it did, the agent's old delegations are revoked, no new ones were issued, and only an owner re-grant restores its spend authority (#1868). Check the agent page before assuming the harmless case.";
|
|
@@ -3701,7 +3725,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3701
3725
|
label: "Signer runtime (preinstalled wrapper)",
|
|
3702
3726
|
ok: false,
|
|
3703
3727
|
detail: "No signer-runtime.json sidecar \u2014 the pinned signer runtime was never prepared (or a pre-#1586 npx config).",
|
|
3704
|
-
repair: `Run: ${RERUN} --doctor --repair
|
|
3728
|
+
repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input.runtime)}`
|
|
3705
3729
|
});
|
|
3706
3730
|
} else if (sidecar.runtime_spec_override) {
|
|
3707
3731
|
const matches = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -3713,7 +3737,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3713
3737
|
label: "Signer runtime (preinstalled wrapper)",
|
|
3714
3738
|
ok: matches,
|
|
3715
3739
|
detail: matches ? `Installed ${sidecar.signer_package}@${sidecar.signer_version} at ${sidecar.runtime_directory} (override install \u2014 see runtime_spec_override)` : `Override runtime directory is stale or empty (${sidecar.runtime_directory}) \u2014 the CLI or package versions are missing.`,
|
|
3716
|
-
...matches ? {} : { repair: `Run: ${RERUN} --doctor --repair
|
|
3740
|
+
...matches ? {} : { repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input.runtime)} with the same HAVEN_*_SPEC variables set.` }
|
|
3717
3741
|
});
|
|
3718
3742
|
} else {
|
|
3719
3743
|
const intact = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -3727,7 +3751,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3727
3751
|
label: "Signer runtime (preinstalled wrapper)",
|
|
3728
3752
|
ok,
|
|
3729
3753
|
detail: ok ? `Installed ${sidecar.signer_package}@${sidecar.signer_version} at ${sidecar.runtime_directory}` : intact ? `Installed version ${sidecar.signer_version} does not match the connector's pinned ${MCP_RUNTIME_MANIFEST.signerVersion} \u2014 intact, but outdated.` : `Runtime directory is stale or empty (${sidecar.runtime_directory}) \u2014 the CLI or package versions are missing.`,
|
|
3730
|
-
...ok ? {} : { repair: `Run: ${RERUN} --doctor --repair
|
|
3754
|
+
...ok ? {} : { repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input.runtime)}` }
|
|
3731
3755
|
});
|
|
3732
3756
|
}
|
|
3733
3757
|
const overrideCheck = await runtimeSpecOverrideCheck(directory, sidecar, deps.env ?? process.env);
|
|
@@ -3768,7 +3792,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3768
3792
|
label: "Hosted identity matches the local signing key",
|
|
3769
3793
|
ok: false,
|
|
3770
3794
|
detail: probe.status === "unauthorized" ? "The stored API key was rejected, so the agent it authenticates as cannot be compared with the local signing key." : `Could not read the hosted identity (${probe.status}) \u2014 the comparison did not happen, so it cannot be reported as a match.`,
|
|
3771
|
-
repair: probe.status === "unauthorized" ? `Re-run the full setup with a fresh token: ${RERUN} --setup <token>.` : `Restore network access to the Haven API, then re-run: ${RERUN} --doctor
|
|
3795
|
+
repair: probe.status === "unauthorized" ? `Re-run the full setup with a fresh token: ${RERUN} --setup <token>.` : `Restore network access to the Haven API, then re-run: ${RERUN} --doctor${runtimeFlagFor(input.runtime)}`
|
|
3772
3796
|
});
|
|
3773
3797
|
} else if (!localDelegate) {
|
|
3774
3798
|
checks.push({
|
|
@@ -3820,7 +3844,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3820
3844
|
label: "Signer stdio handshake",
|
|
3821
3845
|
ok: probe.status === "ok",
|
|
3822
3846
|
detail: probe.status === "ok" ? `Signer started, listed ${probe.toolNames?.length ?? 0} tools${probe.serverInfo?.version ? ` (v${probe.serverInfo.version})` : ""}.${compatDetail}` : `Handshake failed: ${probe.status}.`,
|
|
3823
|
-
...probe.status === "ok" ? {} : { repair: `Run: ${RERUN} --doctor --repair
|
|
3847
|
+
...probe.status === "ok" ? {} : { repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input.runtime)}` }
|
|
3824
3848
|
});
|
|
3825
3849
|
}
|
|
3826
3850
|
} else {
|
|
@@ -3829,7 +3853,7 @@ async function checksForAgent(entry, input, deps) {
|
|
|
3829
3853
|
label: "Signer stdio handshake",
|
|
3830
3854
|
ok: false,
|
|
3831
3855
|
detail: "Skipped \u2014 no prepared signer runtime to probe.",
|
|
3832
|
-
repair: `Run: ${RERUN} --doctor --repair
|
|
3856
|
+
repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input.runtime)}`
|
|
3833
3857
|
});
|
|
3834
3858
|
}
|
|
3835
3859
|
return { checks, ...signerCapabilities ? { signerCapabilities } : {} };
|
|
@@ -3839,7 +3863,10 @@ async function runDoctor(input, deps = {}) {
|
|
|
3839
3863
|
const checks = [];
|
|
3840
3864
|
let signerCapabilities;
|
|
3841
3865
|
const { directory, others, parkedOnly } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
3842
|
-
const
|
|
3866
|
+
const resolution = await resolveDoctorRuntime(input, directory);
|
|
3867
|
+
const runtime = resolution.runtime;
|
|
3868
|
+
const input2 = { ...input, runtime };
|
|
3869
|
+
const configPath = runtimeConfigPathFor(input2.runtime, homeDir);
|
|
3843
3870
|
let configText = null;
|
|
3844
3871
|
if (configPath !== null) {
|
|
3845
3872
|
try {
|
|
@@ -3876,7 +3903,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
3876
3903
|
// A tombstone is a deliberate record and outranks the discovery tell:
|
|
3877
3904
|
// a retired directory that also holds a parked key stays `retired`.
|
|
3878
3905
|
classification: tombstone ? "retired" : parkedOnly.has(dir) ? "parked" : "orphaned",
|
|
3879
|
-
checks: rekeyPending ? [rekeyPendingCheck(rekeyPending, void 0,
|
|
3906
|
+
checks: rekeyPending ? [rekeyPendingCheck(rekeyPending, void 0, input2.runtime, slug)] : [],
|
|
3880
3907
|
...rekeyPending ? { rekeyPending } : {}
|
|
3881
3908
|
});
|
|
3882
3909
|
continue;
|
|
@@ -3891,11 +3918,11 @@ async function runDoctor(input, deps = {}) {
|
|
|
3891
3918
|
...rekeyPending ? { rekeyPending } : {}
|
|
3892
3919
|
};
|
|
3893
3920
|
if (wired) {
|
|
3894
|
-
const result = await checksForAgent({ directory: dir, identity, sidecar },
|
|
3921
|
+
const result = await checksForAgent({ directory: dir, identity, sidecar }, input2, deps);
|
|
3895
3922
|
entry.checks = result.checks;
|
|
3896
3923
|
capabilitiesByDirectory.set(dir, result.signerCapabilities);
|
|
3897
3924
|
} else if (rekeyPending) {
|
|
3898
|
-
entry.checks = [rekeyPendingCheck(rekeyPending, void 0,
|
|
3925
|
+
entry.checks = [rekeyPendingCheck(rekeyPending, void 0, input2.runtime, slug)];
|
|
3899
3926
|
}
|
|
3900
3927
|
inventory.push(entry);
|
|
3901
3928
|
}
|
|
@@ -3920,7 +3947,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
3920
3947
|
if (!primaryChecksById.has("credentials")) {
|
|
3921
3948
|
const result = await checksForAgent(
|
|
3922
3949
|
{ directory: primaryDirectory, identity: primaryIdentity, sidecar: primarySidecar },
|
|
3923
|
-
|
|
3950
|
+
input2,
|
|
3924
3951
|
deps
|
|
3925
3952
|
);
|
|
3926
3953
|
signerCapabilities = result.signerCapabilities;
|
|
@@ -3931,12 +3958,20 @@ async function runDoctor(input, deps = {}) {
|
|
|
3931
3958
|
if (check) checks.push(check);
|
|
3932
3959
|
}
|
|
3933
3960
|
}
|
|
3934
|
-
if (configPath === null) {
|
|
3961
|
+
if (configPath === null && input2.runtime === "") {
|
|
3962
|
+
checks.push({
|
|
3963
|
+
id: "runtime_config",
|
|
3964
|
+
label: "Runtime MCP config",
|
|
3965
|
+
ok: false,
|
|
3966
|
+
detail: `Runtime is unknown \u2014 no runtime flag was given and the connector's record in ${primaryDirectory ?? input.credentialsDir ?? "~/.haven/agents"} carries no resolvable ${CONNECT_OUTCOME_FILENAME} runtime. The runtime config was NOT checked. Re-run the doctor naming the runtime \u2014 one of: ${RUNTIME_FLAG_VALUE_LIST.join(", ")}.`,
|
|
3967
|
+
repair: `Re-run the doctor naming the runtime \u2014 one of: ${RUNTIME_FLAG_VALUE_LIST.join(", ")}.`
|
|
3968
|
+
});
|
|
3969
|
+
} else if (configPath === null) {
|
|
3935
3970
|
checks.push({
|
|
3936
3971
|
id: "runtime_config",
|
|
3937
3972
|
label: "Runtime MCP config",
|
|
3938
3973
|
ok: true,
|
|
3939
|
-
detail: `Runtime '${
|
|
3974
|
+
detail: `Runtime '${input2.runtime}' is configured through its own CLI or by hand (${input2.runtime === "other" ? "manual runtime" : "CLI-managed"}) and has no file-based config the connector owns \u2014 skipping the file check.`
|
|
3940
3975
|
});
|
|
3941
3976
|
} else if (configText === null) {
|
|
3942
3977
|
checks.push({
|
|
@@ -3944,7 +3979,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
3944
3979
|
label: "Runtime MCP config",
|
|
3945
3980
|
ok: false,
|
|
3946
3981
|
detail: `No runtime config at ${configPath}.`,
|
|
3947
|
-
repair: `Run: ${RERUN} --doctor --repair
|
|
3982
|
+
repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input2.runtime)}`
|
|
3948
3983
|
});
|
|
3949
3984
|
} else {
|
|
3950
3985
|
const primaryIdentity = await readIdentity(primaryDirectory ?? "");
|
|
@@ -3958,7 +3993,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
3958
3993
|
label: "Runtime MCP config",
|
|
3959
3994
|
ok,
|
|
3960
3995
|
detail: ok ? `Config at ${configPath} references the hosted server and the prepared signer wrapper.` : signerViaNpx ? `Config at ${configPath} still launches the signer via npx \u2014 the pre-#1586 shape that cannot start under a 120s startup timeout.` : `Config at ${configPath} is missing the Haven entries${primarySidecar && !wrapperReferenced ? " (or references a different signer wrapper)" : ""}.`,
|
|
3961
|
-
...ok ? {} : { repair: `Run: ${RERUN} --doctor --repair
|
|
3996
|
+
...ok ? {} : { repair: `Run: ${RERUN} --doctor --repair${runtimeFlagFor(input2.runtime)}` }
|
|
3962
3997
|
});
|
|
3963
3998
|
}
|
|
3964
3999
|
for (const id of ["hosted_mcp", "identity_match", "rekey_pending"]) {
|
|
@@ -4031,18 +4066,18 @@ async function runDoctor(input, deps = {}) {
|
|
|
4031
4066
|
}
|
|
4032
4067
|
const signerProcess = primaryChecksById.get("signer_process");
|
|
4033
4068
|
if (signerProcess) checks.push(signerProcess);
|
|
4034
|
-
const restart = restartRequiredForRuntime(
|
|
4069
|
+
const restart = restartRequiredForRuntime(input2.runtime, deps.env);
|
|
4035
4070
|
checks.push({
|
|
4036
4071
|
id: "restart",
|
|
4037
4072
|
label: "Runtime restart",
|
|
4038
4073
|
ok: true,
|
|
4039
|
-
detail: restart ? "This runtime loads MCP config at startup \u2014 restart it after any repair before expecting the tools to appear." : "No restart requirement known for this runtime."
|
|
4074
|
+
detail: restart ? "This runtime loads MCP config at startup \u2014 restart it after any repair before expecting the tools to appear." : input2.runtime === "" ? "Runtime is unknown \u2014 whether a restart is needed cannot be determined. Re-run the doctor naming the runtime for a definitive answer." : "No restart requirement known for this runtime."
|
|
4040
4075
|
});
|
|
4041
4076
|
const wiredOk = inventory.filter((entry) => entry.classification === "wired").every((entry) => entry.checks.every((check) => check.ok));
|
|
4042
4077
|
return {
|
|
4043
4078
|
version: 1,
|
|
4044
4079
|
ok: checks.every((check) => check.ok) && wiredOk,
|
|
4045
|
-
runtime:
|
|
4080
|
+
runtime: input2.runtime,
|
|
4046
4081
|
credentialDirectory: primaryDirectory,
|
|
4047
4082
|
checks,
|
|
4048
4083
|
agents: inventory,
|
|
@@ -4062,6 +4097,21 @@ async function runRepair(input, deps = {}) {
|
|
|
4062
4097
|
messages: [`No agent credentials found to repair \u2014 run the full setup: ${RERUN} --setup <token>.`]
|
|
4063
4098
|
};
|
|
4064
4099
|
}
|
|
4100
|
+
const resolution = await resolveDoctorRuntime(input, directory);
|
|
4101
|
+
if (resolution.origin === "record") {
|
|
4102
|
+
messages.push(`Runtime not given \u2014 resolved '${resolution.runtime}' from ${path.join(directory, CONNECT_OUTCOME_FILENAME)}.`);
|
|
4103
|
+
}
|
|
4104
|
+
const runtime = resolution.runtime;
|
|
4105
|
+
const input2 = { ...input, runtime };
|
|
4106
|
+
if (runtime === "") {
|
|
4107
|
+
return {
|
|
4108
|
+
ok: false,
|
|
4109
|
+
messages: [
|
|
4110
|
+
"Runtime is unknown \u2014 no runtime flag was given and the connector record carries no resolvable runtime.",
|
|
4111
|
+
`Repair rewrites the runtime config, so it will not guess. Re-run repair naming the runtime \u2014 one of: ${RUNTIME_FLAG_VALUE_LIST.join(", ")}.`
|
|
4112
|
+
]
|
|
4113
|
+
};
|
|
4114
|
+
}
|
|
4065
4115
|
let identity;
|
|
4066
4116
|
try {
|
|
4067
4117
|
identity = JSON.parse(await promises.readFile(path.join(directory, "identity.json"), "utf8"));
|
|
@@ -4071,7 +4121,7 @@ async function runRepair(input, deps = {}) {
|
|
|
4071
4121
|
if (!identity.api_key || !(identity.hosted_mcp_url || identity.api_url)) {
|
|
4072
4122
|
return { ok: false, messages: ["identity.json lacks the stored API key / hosted URL \u2014 re-run the full setup."] };
|
|
4073
4123
|
}
|
|
4074
|
-
const configPath = runtimeConfigPathFor(
|
|
4124
|
+
const configPath = runtimeConfigPathFor(input2.runtime, homeDir);
|
|
4075
4125
|
if (configPath) {
|
|
4076
4126
|
try {
|
|
4077
4127
|
const existing = await promises.readFile(configPath, "utf8");
|
|
@@ -4098,7 +4148,7 @@ async function runRepair(input, deps = {}) {
|
|
|
4098
4148
|
const names = serverNamesFor(serverName);
|
|
4099
4149
|
messages.push(`Rewriting MCP entries ${names.hosted} / ${names.signer}${serverName ? ` (agent "${serverName}")` : " (unnamed pair)"} \u2014 no other pair is touched.`);
|
|
4100
4150
|
const configResult = await writeRuntimeConfig({
|
|
4101
|
-
runtime:
|
|
4151
|
+
runtime: input2.runtime,
|
|
4102
4152
|
hostedMcpUrl: identity.hosted_mcp_url ?? `${identity.api_url}/mcp`,
|
|
4103
4153
|
apiKey: identity.api_key,
|
|
4104
4154
|
identityPath: path.join(directory, "identity.json"),
|
|
@@ -4429,7 +4479,7 @@ async function pathExists2(path) {
|
|
|
4429
4479
|
init_unwire();
|
|
4430
4480
|
init_local_mcp_runtime();
|
|
4431
4481
|
init_runtime_manifest();
|
|
4432
|
-
var CONNECTOR_VERSION = "0.0.0-dev.
|
|
4482
|
+
var CONNECTOR_VERSION = "0.0.0-dev.202609181807.87b28b1";
|
|
4433
4483
|
var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
4434
4484
|
var failureOutcomesByError = /* @__PURE__ */ new WeakMap();
|
|
4435
4485
|
function failureOutcomeFor(runtimeHint, error) {
|