@haven_ai/connect 0.6.0-alpha.0 → 0.8.0-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 +14 -1
- package/dist/cli.cjs +70 -31
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +70 -31
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +70 -31
- 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 +70 -31
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -613,9 +613,9 @@ var init_runtime_manifest = __esm({
|
|
|
613
613
|
mcpPackage: "@haven_ai/mcp",
|
|
614
614
|
mcpVersion: MCP_VERSION,
|
|
615
615
|
sdkPackage: "@haven_ai/sdk",
|
|
616
|
-
sdkVersion: "0.
|
|
616
|
+
sdkVersion: "0.8.0-alpha.0",
|
|
617
617
|
signerPackage: "@haven_ai/signer",
|
|
618
|
-
signerVersion: "0.
|
|
618
|
+
signerVersion: "0.8.0-alpha.0",
|
|
619
619
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
620
620
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
621
621
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -4444,7 +4444,7 @@ var init_runtime = __esm({
|
|
|
4444
4444
|
init_tombstone();
|
|
4445
4445
|
init_local_mcp_runtime();
|
|
4446
4446
|
init_runtime_manifest();
|
|
4447
|
-
CONNECTOR_VERSION = "0.
|
|
4447
|
+
CONNECTOR_VERSION = "0.8.0-alpha.0";
|
|
4448
4448
|
CONNECTOR_CLIENT_IDENTITY = `@haven_ai/connect/${CONNECTOR_VERSION}`;
|
|
4449
4449
|
CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
4450
4450
|
failureOutcomesByError = /* @__PURE__ */ new WeakMap();
|
|
@@ -4927,9 +4927,23 @@ function rollUpLevel(checks) {
|
|
|
4927
4927
|
function runtimeFlagFor(runtime) {
|
|
4928
4928
|
return normalizeRuntimeName(runtime) ? ` --runtime ${runtime}` : "";
|
|
4929
4929
|
}
|
|
4930
|
-
function
|
|
4931
|
-
|
|
4932
|
-
|
|
4930
|
+
async function pathExists3(path) {
|
|
4931
|
+
try {
|
|
4932
|
+
await stat(path);
|
|
4933
|
+
return true;
|
|
4934
|
+
} catch {
|
|
4935
|
+
return false;
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
function credentialsDirFlagFor(credentialsDir) {
|
|
4939
|
+
if (!credentialsDir) return "";
|
|
4940
|
+
const quoted = /^[\w@%+=:,./~-]+$/.test(credentialsDir) ? credentialsDir : `'${credentialsDir.replace(/'/g, `'\\''`)}'`;
|
|
4941
|
+
return ` --credentials-dir ${quoted}`;
|
|
4942
|
+
}
|
|
4943
|
+
function repairCommandFor(runtime, suffix = "", credentialsDir) {
|
|
4944
|
+
const dirFlag = credentialsDirFlagFor(credentialsDir);
|
|
4945
|
+
if (normalizeRuntimeName(runtime)) return `Run: ${RERUN} --doctor --repair --runtime ${runtime}${dirFlag}${suffix}`;
|
|
4946
|
+
return `Run: ${RERUN} --doctor --repair --runtime <runtime>${dirFlag}${suffix.replace(/\.$/, "")} \u2014 --repair needs the runtime named; one of: ${RUNTIME_FLAG_VALUE_LIST.join(", ")}.`;
|
|
4933
4947
|
}
|
|
4934
4948
|
async function resolveDoctorRuntime(input, directory) {
|
|
4935
4949
|
const explicit = input.runtime.trim();
|
|
@@ -4948,45 +4962,47 @@ async function discoverCredentialDirectory(homeDir, explicit) {
|
|
|
4948
4962
|
try {
|
|
4949
4963
|
entries = await readdir(root);
|
|
4950
4964
|
} catch {
|
|
4951
|
-
return explicit ? { directory: explicit, others: [], parkedOnly: /* @__PURE__ */ new Set() } : { others: [], parkedOnly: /* @__PURE__ */ new Set() };
|
|
4965
|
+
return explicit ? { directory: explicit, others: [], parkedOnly: /* @__PURE__ */ new Set(), identityDirectories: [explicit] } : { others: [], parkedOnly: /* @__PURE__ */ new Set(), identityDirectories: [] };
|
|
4952
4966
|
}
|
|
4953
4967
|
const candidates = [];
|
|
4954
4968
|
const tombstonedOnly = [];
|
|
4955
4969
|
const parkedOnly = [];
|
|
4956
4970
|
for (const entry of entries) {
|
|
4957
4971
|
const directory = join(root, entry);
|
|
4972
|
+
if (await pathExists3(join(directory, TOMBSTONE_FILENAME))) {
|
|
4973
|
+
tombstonedOnly.push(directory);
|
|
4974
|
+
continue;
|
|
4975
|
+
}
|
|
4958
4976
|
try {
|
|
4959
4977
|
const s = await stat(join(directory, "identity.json"));
|
|
4960
4978
|
candidates.push({ directory, mtimeMs: s.mtimeMs });
|
|
4961
4979
|
} catch {
|
|
4962
4980
|
try {
|
|
4963
|
-
await stat(join(directory,
|
|
4964
|
-
|
|
4981
|
+
await stat(join(directory, REKEY_PENDING_FILENAME));
|
|
4982
|
+
parkedOnly.push(directory);
|
|
4965
4983
|
} catch {
|
|
4966
|
-
try {
|
|
4967
|
-
await stat(join(directory, REKEY_PENDING_FILENAME));
|
|
4968
|
-
parkedOnly.push(directory);
|
|
4969
|
-
} catch {
|
|
4970
|
-
}
|
|
4971
4984
|
}
|
|
4972
4985
|
}
|
|
4973
4986
|
}
|
|
4974
4987
|
const parkedOnlySet = new Set(parkedOnly);
|
|
4975
4988
|
candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
4989
|
+
const identityDirectories = candidates.map((c) => c.directory);
|
|
4976
4990
|
if (explicit) {
|
|
4977
4991
|
return {
|
|
4978
4992
|
directory: explicit,
|
|
4979
4993
|
others: [...candidates.map((c) => c.directory), ...tombstonedOnly, ...parkedOnly].filter((d) => d !== explicit),
|
|
4980
|
-
parkedOnly: parkedOnlySet
|
|
4994
|
+
parkedOnly: parkedOnlySet,
|
|
4995
|
+
identityDirectories: [explicit, ...identityDirectories.filter((d) => d !== explicit)]
|
|
4981
4996
|
};
|
|
4982
4997
|
}
|
|
4983
4998
|
if (candidates.length === 0 && tombstonedOnly.length === 0 && parkedOnly.length === 0) {
|
|
4984
|
-
return { others: [], parkedOnly: parkedOnlySet };
|
|
4999
|
+
return { others: [], parkedOnly: parkedOnlySet, identityDirectories };
|
|
4985
5000
|
}
|
|
4986
5001
|
return {
|
|
4987
5002
|
directory: candidates[0]?.directory,
|
|
4988
5003
|
others: [...candidates.slice(1).map((c) => c.directory), ...tombstonedOnly, ...parkedOnly],
|
|
4989
|
-
parkedOnly: parkedOnlySet
|
|
5004
|
+
parkedOnly: parkedOnlySet,
|
|
5005
|
+
identityDirectories
|
|
4990
5006
|
};
|
|
4991
5007
|
}
|
|
4992
5008
|
function agentIsWired(configText, names, slug, identity, sidecar, isPrimary, bareOwnerExists) {
|
|
@@ -5045,7 +5061,7 @@ function rekeyPendingVerdict(status, hostedDelegateAddress, runtime, slug) {
|
|
|
5045
5061
|
detail: `A re-key started ${started} is still open (expires ${status.expiresAt ?? "unknown"}). Paste this address into "Replace signing key" on the Haven agent page: ${address}. Parked at ${status.path}. ` + wedgeNote
|
|
5046
5062
|
};
|
|
5047
5063
|
}
|
|
5048
|
-
async function runtimeSpecOverrideCheck(directory, sidecar, env) {
|
|
5064
|
+
async function runtimeSpecOverrideCheck(directory, sidecar, env, repairDir) {
|
|
5049
5065
|
const facts = [];
|
|
5050
5066
|
const installed = sidecar?.runtime_spec_override;
|
|
5051
5067
|
if (installed) {
|
|
@@ -5074,7 +5090,7 @@ async function runtimeSpecOverrideCheck(directory, sidecar, env) {
|
|
|
5074
5090
|
label: "Runtime spec override",
|
|
5075
5091
|
level: "failed",
|
|
5076
5092
|
detail: `runtime spec overridden \u2014 not the pinned manifest (${MCP_RUNTIME_MANIFEST.signerPackage}@${MCP_RUNTIME_MANIFEST.signerVersion}, ${MCP_RUNTIME_MANIFEST.sdkPackage}@${MCP_RUNTIME_MANIFEST.sdkVersion}). ${facts.join(". ")}.`,
|
|
5077
|
-
repair: `Developer override (#2424). To return to the pinned manifest: unset ${variables}, then run ${RERUN} --doctor --repair --runtime <runtime
|
|
5093
|
+
repair: `Developer override (#2424). To return to the pinned manifest: unset ${variables}, then run ${RERUN} --doctor --repair --runtime <runtime>${credentialsDirFlagFor(repairDir)}. If the override is intentional, this finding is the record of it.`
|
|
5078
5094
|
});
|
|
5079
5095
|
}
|
|
5080
5096
|
async function readMcpSidecarOverride(directory) {
|
|
@@ -5133,7 +5149,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5133
5149
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5134
5150
|
level: "failed",
|
|
5135
5151
|
detail: "No signer-runtime.json sidecar \u2014 the pinned signer runtime was never prepared (or a pre-#1586 npx config).",
|
|
5136
|
-
repair: repairCommandFor(input.runtime)
|
|
5152
|
+
repair: repairCommandFor(input.runtime, "", input.repairDir)
|
|
5137
5153
|
});
|
|
5138
5154
|
} else if (sidecar.runtime_spec_override) {
|
|
5139
5155
|
const matches = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -5145,7 +5161,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5145
5161
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5146
5162
|
level: matches ? "ok" : "failed",
|
|
5147
5163
|
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.`,
|
|
5148
|
-
...matches ? {} : { repair: repairCommandFor(input.runtime, " with the same HAVEN_*_SPEC variables set.") }
|
|
5164
|
+
...matches ? {} : { repair: repairCommandFor(input.runtime, " with the same HAVEN_*_SPEC variables set.", input.repairDir) }
|
|
5149
5165
|
});
|
|
5150
5166
|
} else {
|
|
5151
5167
|
const intact = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -5159,10 +5175,10 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5159
5175
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5160
5176
|
level: ok ? "ok" : intact ? "advisory" : "failed",
|
|
5161
5177
|
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.`,
|
|
5162
|
-
...ok ? {} : { repair: repairCommandFor(input.runtime) }
|
|
5178
|
+
...ok ? {} : { repair: repairCommandFor(input.runtime, "", input.repairDir) }
|
|
5163
5179
|
});
|
|
5164
5180
|
}
|
|
5165
|
-
const overrideCheck = await runtimeSpecOverrideCheck(directory, sidecar, deps.env ?? process.env);
|
|
5181
|
+
const overrideCheck = await runtimeSpecOverrideCheck(directory, sidecar, deps.env ?? process.env, input.repairDir);
|
|
5166
5182
|
if (overrideCheck) checks.push(overrideCheck);
|
|
5167
5183
|
const hostedUrl = identity?.hosted_mcp_url ?? (identity?.api_url ? `${identity.api_url}/mcp` : void 0);
|
|
5168
5184
|
if (identity?.api_key && hostedUrl) {
|
|
@@ -5252,7 +5268,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5252
5268
|
label: "Signer stdio handshake",
|
|
5253
5269
|
level: probe.status === "ok" ? "ok" : "failed",
|
|
5254
5270
|
detail: probe.status === "ok" ? `Signer started, listed ${probe.toolNames?.length ?? 0} tools${probe.serverInfo?.version ? ` (v${probe.serverInfo.version})` : ""}.${compatDetail}` : `Handshake failed: ${probe.status}.`,
|
|
5255
|
-
...probe.status === "ok" ? {} : { repair: repairCommandFor(input.runtime) }
|
|
5271
|
+
...probe.status === "ok" ? {} : { repair: repairCommandFor(input.runtime, "", input.repairDir) }
|
|
5256
5272
|
});
|
|
5257
5273
|
}
|
|
5258
5274
|
} else {
|
|
@@ -5261,7 +5277,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5261
5277
|
label: "Signer stdio handshake",
|
|
5262
5278
|
level: "failed",
|
|
5263
5279
|
detail: "Skipped \u2014 no prepared signer runtime to probe.",
|
|
5264
|
-
repair: repairCommandFor(input.runtime)
|
|
5280
|
+
repair: repairCommandFor(input.runtime, "", input.repairDir)
|
|
5265
5281
|
});
|
|
5266
5282
|
}
|
|
5267
5283
|
return { checks, ...signerCapabilities ? { signerCapabilities } : {} };
|
|
@@ -5270,7 +5286,8 @@ async function runDoctor(input, deps = {}) {
|
|
|
5270
5286
|
const homeDir = deps.homeDir ?? homedir();
|
|
5271
5287
|
const checks = [];
|
|
5272
5288
|
let signerCapabilities;
|
|
5273
|
-
const { directory, others, parkedOnly } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5289
|
+
const { directory, others, parkedOnly, identityDirectories } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5290
|
+
const nameRepairDir = identityDirectories.length > 1 || Boolean(input.credentialsDir);
|
|
5274
5291
|
const resolution = await resolveDoctorRuntime(input, directory);
|
|
5275
5292
|
const runtime = resolution.runtime;
|
|
5276
5293
|
const input2 = { ...input, runtime };
|
|
@@ -5327,7 +5344,11 @@ async function runDoctor(input, deps = {}) {
|
|
|
5327
5344
|
...rekeyPending ? { rekeyPending } : {}
|
|
5328
5345
|
};
|
|
5329
5346
|
if (wired) {
|
|
5330
|
-
const result = await checksForAgent(
|
|
5347
|
+
const result = await checksForAgent(
|
|
5348
|
+
{ directory: dir, identity, sidecar },
|
|
5349
|
+
{ ...input2, ...nameRepairDir ? { repairDir: dir } : {} },
|
|
5350
|
+
deps
|
|
5351
|
+
);
|
|
5331
5352
|
entry.checks = result.checks;
|
|
5332
5353
|
capabilitiesByDirectory.set(dir, result.signerCapabilities);
|
|
5333
5354
|
} else if (rekeyPending) {
|
|
@@ -5356,7 +5377,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5356
5377
|
if (!primaryChecksById.has("credentials")) {
|
|
5357
5378
|
const result = await checksForAgent(
|
|
5358
5379
|
{ directory: primaryDirectory, identity: primaryIdentity, sidecar: primarySidecar },
|
|
5359
|
-
input2,
|
|
5380
|
+
{ ...input2, ...nameRepairDir ? { repairDir: primaryDirectory } : {} },
|
|
5360
5381
|
deps
|
|
5361
5382
|
);
|
|
5362
5383
|
signerCapabilities = result.signerCapabilities;
|
|
@@ -5397,7 +5418,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5397
5418
|
label: "Runtime MCP config",
|
|
5398
5419
|
level: "failed",
|
|
5399
5420
|
detail: `No runtime config at ${configPath}.`,
|
|
5400
|
-
repair: repairCommandFor(input2.runtime)
|
|
5421
|
+
repair: repairCommandFor(input2.runtime, "", nameRepairDir ? primaryDirectory : void 0)
|
|
5401
5422
|
});
|
|
5402
5423
|
} else {
|
|
5403
5424
|
const primaryIdentity = await readIdentity(primaryDirectory ?? "");
|
|
@@ -5411,7 +5432,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5411
5432
|
label: "Runtime MCP config",
|
|
5412
5433
|
level: ok ? "ok" : "failed",
|
|
5413
5434
|
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)" : ""}.`,
|
|
5414
|
-
...ok ? {} : { repair: repairCommandFor(input2.runtime) }
|
|
5435
|
+
...ok ? {} : { repair: repairCommandFor(input2.runtime, "", nameRepairDir ? primaryDirectory : void 0) }
|
|
5415
5436
|
});
|
|
5416
5437
|
}
|
|
5417
5438
|
for (const id of ["hosted_mcp", "identity_match", "rekey_pending"]) {
|
|
@@ -5554,7 +5575,25 @@ async function runDoctor(input, deps = {}) {
|
|
|
5554
5575
|
async function runRepair(input, deps = {}) {
|
|
5555
5576
|
const homeDir = deps.homeDir ?? homedir();
|
|
5556
5577
|
const messages = [];
|
|
5557
|
-
const { directory, others } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5578
|
+
const { directory, others, identityDirectories } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5579
|
+
if (!input.credentialsDir && identityDirectories.length > 1) {
|
|
5580
|
+
const lines = await Promise.all(
|
|
5581
|
+
identityDirectories.map(async (dir) => {
|
|
5582
|
+
const identity2 = await readIdentity(dir);
|
|
5583
|
+
const who = identity2?.agent_id ? `agent ${identity2.agent_id}` : "agent (no agent_id recorded)";
|
|
5584
|
+
const retired = !identity2?.api_key || await pathExists3(join(dir, TOMBSTONE_FILENAME));
|
|
5585
|
+
return retired ? ` \u2022 ${who} (${dir}): retired \u2014 not a repair target` : ` \u2022 ${who}: ${repairCommandFor(input.runtime, "", dir).replace(/^Run: /, "")}`;
|
|
5586
|
+
})
|
|
5587
|
+
);
|
|
5588
|
+
return {
|
|
5589
|
+
ok: false,
|
|
5590
|
+
messages: [
|
|
5591
|
+
`${identityDirectories.length} agent credential directories exist on this machine, and a repair rewrites the runtime config from ONE of them. Name the agent to repair with --credentials-dir \u2014 nothing was changed:`,
|
|
5592
|
+
...lines,
|
|
5593
|
+
"Not sure which agent is which? Compare the agent ids against the Haven agent page, or run --doctor first."
|
|
5594
|
+
]
|
|
5595
|
+
};
|
|
5596
|
+
}
|
|
5558
5597
|
if (others.length > 0) {
|
|
5559
5598
|
messages.push(`Note: ${others.length} other agent credential dir(s) exist \u2014 run --doctor for their status.`);
|
|
5560
5599
|
}
|