@haven_ai/connect 0.5.0-alpha.1 → 0.7.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 +12 -0
- package/dist/cli.cjs +64 -24
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +64 -24
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +64 -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 +64 -24
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -619,9 +619,9 @@ var init_runtime_manifest = __esm({
|
|
|
619
619
|
mcpPackage: "@haven_ai/mcp",
|
|
620
620
|
mcpVersion: mcp.MCP_VERSION,
|
|
621
621
|
sdkPackage: "@haven_ai/sdk",
|
|
622
|
-
sdkVersion: "0.
|
|
622
|
+
sdkVersion: "0.7.0-alpha.0",
|
|
623
623
|
signerPackage: "@haven_ai/signer",
|
|
624
|
-
signerVersion: "0.
|
|
624
|
+
signerVersion: "0.7.0-alpha.0",
|
|
625
625
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
626
626
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
627
627
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -4450,7 +4450,7 @@ var init_runtime = __esm({
|
|
|
4450
4450
|
init_tombstone();
|
|
4451
4451
|
init_local_mcp_runtime();
|
|
4452
4452
|
init_runtime_manifest();
|
|
4453
|
-
exports.CONNECTOR_VERSION = "0.
|
|
4453
|
+
exports.CONNECTOR_VERSION = "0.7.0-alpha.0";
|
|
4454
4454
|
CONNECTOR_CLIENT_IDENTITY = `@haven_ai/connect/${exports.CONNECTOR_VERSION}`;
|
|
4455
4455
|
exports.CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
4456
4456
|
failureOutcomesByError = /* @__PURE__ */ new WeakMap();
|
|
@@ -4933,9 +4933,23 @@ function rollUpLevel(checks) {
|
|
|
4933
4933
|
function runtimeFlagFor(runtime) {
|
|
4934
4934
|
return normalizeRuntimeName(runtime) ? ` --runtime ${runtime}` : "";
|
|
4935
4935
|
}
|
|
4936
|
-
function
|
|
4937
|
-
|
|
4938
|
-
|
|
4936
|
+
async function pathExists3(path) {
|
|
4937
|
+
try {
|
|
4938
|
+
await promises.stat(path);
|
|
4939
|
+
return true;
|
|
4940
|
+
} catch {
|
|
4941
|
+
return false;
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
function credentialsDirFlagFor(credentialsDir) {
|
|
4945
|
+
if (!credentialsDir) return "";
|
|
4946
|
+
const quoted = /^[\w@%+=:,./~-]+$/.test(credentialsDir) ? credentialsDir : `'${credentialsDir.replace(/'/g, `'\\''`)}'`;
|
|
4947
|
+
return ` --credentials-dir ${quoted}`;
|
|
4948
|
+
}
|
|
4949
|
+
function repairCommandFor(runtime, suffix = "", credentialsDir) {
|
|
4950
|
+
const dirFlag = credentialsDirFlagFor(credentialsDir);
|
|
4951
|
+
if (normalizeRuntimeName(runtime)) return `Run: ${RERUN} --doctor --repair --runtime ${runtime}${dirFlag}${suffix}`;
|
|
4952
|
+
return `Run: ${RERUN} --doctor --repair --runtime <runtime>${dirFlag}${suffix.replace(/\.$/, "")} \u2014 --repair needs the runtime named; one of: ${RUNTIME_FLAG_VALUE_LIST.join(", ")}.`;
|
|
4939
4953
|
}
|
|
4940
4954
|
async function resolveDoctorRuntime(input, directory) {
|
|
4941
4955
|
const explicit = input.runtime.trim();
|
|
@@ -4954,7 +4968,7 @@ async function discoverCredentialDirectory(homeDir, explicit) {
|
|
|
4954
4968
|
try {
|
|
4955
4969
|
entries = await promises.readdir(root);
|
|
4956
4970
|
} catch {
|
|
4957
|
-
return explicit ? { directory: explicit, others: [], parkedOnly: /* @__PURE__ */ new Set() } : { others: [], parkedOnly: /* @__PURE__ */ new Set() };
|
|
4971
|
+
return explicit ? { directory: explicit, others: [], parkedOnly: /* @__PURE__ */ new Set(), identityDirectories: [explicit] } : { others: [], parkedOnly: /* @__PURE__ */ new Set(), identityDirectories: [] };
|
|
4958
4972
|
}
|
|
4959
4973
|
const candidates = [];
|
|
4960
4974
|
const tombstonedOnly = [];
|
|
@@ -4979,20 +4993,23 @@ async function discoverCredentialDirectory(homeDir, explicit) {
|
|
|
4979
4993
|
}
|
|
4980
4994
|
const parkedOnlySet = new Set(parkedOnly);
|
|
4981
4995
|
candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
4996
|
+
const identityDirectories = candidates.map((c) => c.directory);
|
|
4982
4997
|
if (explicit) {
|
|
4983
4998
|
return {
|
|
4984
4999
|
directory: explicit,
|
|
4985
5000
|
others: [...candidates.map((c) => c.directory), ...tombstonedOnly, ...parkedOnly].filter((d) => d !== explicit),
|
|
4986
|
-
parkedOnly: parkedOnlySet
|
|
5001
|
+
parkedOnly: parkedOnlySet,
|
|
5002
|
+
identityDirectories: [explicit, ...identityDirectories.filter((d) => d !== explicit)]
|
|
4987
5003
|
};
|
|
4988
5004
|
}
|
|
4989
5005
|
if (candidates.length === 0 && tombstonedOnly.length === 0 && parkedOnly.length === 0) {
|
|
4990
|
-
return { others: [], parkedOnly: parkedOnlySet };
|
|
5006
|
+
return { others: [], parkedOnly: parkedOnlySet, identityDirectories };
|
|
4991
5007
|
}
|
|
4992
5008
|
return {
|
|
4993
5009
|
directory: candidates[0]?.directory,
|
|
4994
5010
|
others: [...candidates.slice(1).map((c) => c.directory), ...tombstonedOnly, ...parkedOnly],
|
|
4995
|
-
parkedOnly: parkedOnlySet
|
|
5011
|
+
parkedOnly: parkedOnlySet,
|
|
5012
|
+
identityDirectories
|
|
4996
5013
|
};
|
|
4997
5014
|
}
|
|
4998
5015
|
function agentIsWired(configText, names, slug, identity, sidecar, isPrimary, bareOwnerExists) {
|
|
@@ -5051,7 +5068,7 @@ function rekeyPendingVerdict(status, hostedDelegateAddress, runtime, slug) {
|
|
|
5051
5068
|
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
|
|
5052
5069
|
};
|
|
5053
5070
|
}
|
|
5054
|
-
async function runtimeSpecOverrideCheck(directory, sidecar, env) {
|
|
5071
|
+
async function runtimeSpecOverrideCheck(directory, sidecar, env, repairDir) {
|
|
5055
5072
|
const facts = [];
|
|
5056
5073
|
const installed = sidecar?.runtime_spec_override;
|
|
5057
5074
|
if (installed) {
|
|
@@ -5080,7 +5097,7 @@ async function runtimeSpecOverrideCheck(directory, sidecar, env) {
|
|
|
5080
5097
|
label: "Runtime spec override",
|
|
5081
5098
|
level: "failed",
|
|
5082
5099
|
detail: `runtime spec overridden \u2014 not the pinned manifest (${exports.MCP_RUNTIME_MANIFEST.signerPackage}@${exports.MCP_RUNTIME_MANIFEST.signerVersion}, ${exports.MCP_RUNTIME_MANIFEST.sdkPackage}@${exports.MCP_RUNTIME_MANIFEST.sdkVersion}). ${facts.join(". ")}.`,
|
|
5083
|
-
repair: `Developer override (#2424). To return to the pinned manifest: unset ${variables}, then run ${RERUN} --doctor --repair --runtime <runtime
|
|
5100
|
+
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.`
|
|
5084
5101
|
});
|
|
5085
5102
|
}
|
|
5086
5103
|
async function readMcpSidecarOverride(directory) {
|
|
@@ -5139,7 +5156,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5139
5156
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5140
5157
|
level: "failed",
|
|
5141
5158
|
detail: "No signer-runtime.json sidecar \u2014 the pinned signer runtime was never prepared (or a pre-#1586 npx config).",
|
|
5142
|
-
repair: repairCommandFor(input.runtime)
|
|
5159
|
+
repair: repairCommandFor(input.runtime, "", input.repairDir)
|
|
5143
5160
|
});
|
|
5144
5161
|
} else if (sidecar.runtime_spec_override) {
|
|
5145
5162
|
const matches = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -5151,7 +5168,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5151
5168
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5152
5169
|
level: matches ? "ok" : "failed",
|
|
5153
5170
|
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.`,
|
|
5154
|
-
...matches ? {} : { repair: repairCommandFor(input.runtime, " with the same HAVEN_*_SPEC variables set.") }
|
|
5171
|
+
...matches ? {} : { repair: repairCommandFor(input.runtime, " with the same HAVEN_*_SPEC variables set.", input.repairDir) }
|
|
5155
5172
|
});
|
|
5156
5173
|
} else {
|
|
5157
5174
|
const intact = await installedRuntimeMatchesVersions(sidecar.runtime_directory, sidecar.cli_path, {
|
|
@@ -5165,10 +5182,10 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5165
5182
|
label: "Signer runtime (preinstalled wrapper)",
|
|
5166
5183
|
level: ok ? "ok" : intact ? "advisory" : "failed",
|
|
5167
5184
|
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 ${exports.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.`,
|
|
5168
|
-
...ok ? {} : { repair: repairCommandFor(input.runtime) }
|
|
5185
|
+
...ok ? {} : { repair: repairCommandFor(input.runtime, "", input.repairDir) }
|
|
5169
5186
|
});
|
|
5170
5187
|
}
|
|
5171
|
-
const overrideCheck = await runtimeSpecOverrideCheck(directory, sidecar, deps.env ?? process.env);
|
|
5188
|
+
const overrideCheck = await runtimeSpecOverrideCheck(directory, sidecar, deps.env ?? process.env, input.repairDir);
|
|
5172
5189
|
if (overrideCheck) checks.push(overrideCheck);
|
|
5173
5190
|
const hostedUrl = identity?.hosted_mcp_url ?? (identity?.api_url ? `${identity.api_url}/mcp` : void 0);
|
|
5174
5191
|
if (identity?.api_key && hostedUrl) {
|
|
@@ -5258,7 +5275,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5258
5275
|
label: "Signer stdio handshake",
|
|
5259
5276
|
level: probe.status === "ok" ? "ok" : "failed",
|
|
5260
5277
|
detail: probe.status === "ok" ? `Signer started, listed ${probe.toolNames?.length ?? 0} tools${probe.serverInfo?.version ? ` (v${probe.serverInfo.version})` : ""}.${compatDetail}` : `Handshake failed: ${probe.status}.`,
|
|
5261
|
-
...probe.status === "ok" ? {} : { repair: repairCommandFor(input.runtime) }
|
|
5278
|
+
...probe.status === "ok" ? {} : { repair: repairCommandFor(input.runtime, "", input.repairDir) }
|
|
5262
5279
|
});
|
|
5263
5280
|
}
|
|
5264
5281
|
} else {
|
|
@@ -5267,7 +5284,7 @@ async function verdictsForAgent(entry, input, deps) {
|
|
|
5267
5284
|
label: "Signer stdio handshake",
|
|
5268
5285
|
level: "failed",
|
|
5269
5286
|
detail: "Skipped \u2014 no prepared signer runtime to probe.",
|
|
5270
|
-
repair: repairCommandFor(input.runtime)
|
|
5287
|
+
repair: repairCommandFor(input.runtime, "", input.repairDir)
|
|
5271
5288
|
});
|
|
5272
5289
|
}
|
|
5273
5290
|
return { checks, ...signerCapabilities ? { signerCapabilities } : {} };
|
|
@@ -5276,7 +5293,8 @@ async function runDoctor(input, deps = {}) {
|
|
|
5276
5293
|
const homeDir = deps.homeDir ?? os.homedir();
|
|
5277
5294
|
const checks = [];
|
|
5278
5295
|
let signerCapabilities;
|
|
5279
|
-
const { directory, others, parkedOnly } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5296
|
+
const { directory, others, parkedOnly, identityDirectories } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5297
|
+
const nameRepairDir = identityDirectories.length > 1 || Boolean(input.credentialsDir);
|
|
5280
5298
|
const resolution = await resolveDoctorRuntime(input, directory);
|
|
5281
5299
|
const runtime = resolution.runtime;
|
|
5282
5300
|
const input2 = { ...input, runtime };
|
|
@@ -5333,7 +5351,11 @@ async function runDoctor(input, deps = {}) {
|
|
|
5333
5351
|
...rekeyPending ? { rekeyPending } : {}
|
|
5334
5352
|
};
|
|
5335
5353
|
if (wired) {
|
|
5336
|
-
const result = await checksForAgent(
|
|
5354
|
+
const result = await checksForAgent(
|
|
5355
|
+
{ directory: dir, identity, sidecar },
|
|
5356
|
+
{ ...input2, ...nameRepairDir ? { repairDir: dir } : {} },
|
|
5357
|
+
deps
|
|
5358
|
+
);
|
|
5337
5359
|
entry.checks = result.checks;
|
|
5338
5360
|
capabilitiesByDirectory.set(dir, result.signerCapabilities);
|
|
5339
5361
|
} else if (rekeyPending) {
|
|
@@ -5362,7 +5384,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5362
5384
|
if (!primaryChecksById.has("credentials")) {
|
|
5363
5385
|
const result = await checksForAgent(
|
|
5364
5386
|
{ directory: primaryDirectory, identity: primaryIdentity, sidecar: primarySidecar },
|
|
5365
|
-
input2,
|
|
5387
|
+
{ ...input2, ...nameRepairDir ? { repairDir: primaryDirectory } : {} },
|
|
5366
5388
|
deps
|
|
5367
5389
|
);
|
|
5368
5390
|
signerCapabilities = result.signerCapabilities;
|
|
@@ -5403,7 +5425,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5403
5425
|
label: "Runtime MCP config",
|
|
5404
5426
|
level: "failed",
|
|
5405
5427
|
detail: `No runtime config at ${configPath}.`,
|
|
5406
|
-
repair: repairCommandFor(input2.runtime)
|
|
5428
|
+
repair: repairCommandFor(input2.runtime, "", nameRepairDir ? primaryDirectory : void 0)
|
|
5407
5429
|
});
|
|
5408
5430
|
} else {
|
|
5409
5431
|
const primaryIdentity = await readIdentity(primaryDirectory ?? "");
|
|
@@ -5417,7 +5439,7 @@ async function runDoctor(input, deps = {}) {
|
|
|
5417
5439
|
label: "Runtime MCP config",
|
|
5418
5440
|
level: ok ? "ok" : "failed",
|
|
5419
5441
|
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)" : ""}.`,
|
|
5420
|
-
...ok ? {} : { repair: repairCommandFor(input2.runtime) }
|
|
5442
|
+
...ok ? {} : { repair: repairCommandFor(input2.runtime, "", nameRepairDir ? primaryDirectory : void 0) }
|
|
5421
5443
|
});
|
|
5422
5444
|
}
|
|
5423
5445
|
for (const id of ["hosted_mcp", "identity_match", "rekey_pending"]) {
|
|
@@ -5560,7 +5582,25 @@ async function runDoctor(input, deps = {}) {
|
|
|
5560
5582
|
async function runRepair(input, deps = {}) {
|
|
5561
5583
|
const homeDir = deps.homeDir ?? os.homedir();
|
|
5562
5584
|
const messages = [];
|
|
5563
|
-
const { directory, others } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5585
|
+
const { directory, others, identityDirectories } = await discoverCredentialDirectory(homeDir, input.credentialsDir);
|
|
5586
|
+
if (!input.credentialsDir && identityDirectories.length > 1) {
|
|
5587
|
+
const lines = await Promise.all(
|
|
5588
|
+
identityDirectories.map(async (dir) => {
|
|
5589
|
+
const identity2 = await readIdentity(dir);
|
|
5590
|
+
const who = identity2?.agent_id ? `agent ${identity2.agent_id}` : "agent (no agent_id recorded)";
|
|
5591
|
+
const retired = !identity2?.api_key || await pathExists3(path.join(dir, TOMBSTONE_FILENAME));
|
|
5592
|
+
return retired ? ` \u2022 ${who} (${dir}): retired \u2014 not a repair target` : ` \u2022 ${who}: ${repairCommandFor(input.runtime, "", dir).replace(/^Run: /, "")}`;
|
|
5593
|
+
})
|
|
5594
|
+
);
|
|
5595
|
+
return {
|
|
5596
|
+
ok: false,
|
|
5597
|
+
messages: [
|
|
5598
|
+
`${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:`,
|
|
5599
|
+
...lines,
|
|
5600
|
+
"Not sure which agent is which? Compare the agent ids against the Haven agent page, or run --doctor first."
|
|
5601
|
+
]
|
|
5602
|
+
};
|
|
5603
|
+
}
|
|
5564
5604
|
if (others.length > 0) {
|
|
5565
5605
|
messages.push(`Note: ${others.length} other agent credential dir(s) exist \u2014 run --doctor for their status.`);
|
|
5566
5606
|
}
|