@haven_ai/connect 0.1.22-alpha.0 → 0.1.23-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 +47 -7
- package/dist/cli.cjs +226 -62
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +7 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +225 -62
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +232 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -6
- package/dist/index.d.ts +62 -6
- package/dist/index.js +230 -55
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -11,7 +11,9 @@ var yaml = require('yaml');
|
|
|
11
11
|
var mcp = require('@haven_ai/mcp');
|
|
12
12
|
var sdk = require('@haven_ai/sdk');
|
|
13
13
|
var signer = require('@haven_ai/signer');
|
|
14
|
+
var url = require('url');
|
|
14
15
|
|
|
16
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
15
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
18
|
|
|
17
19
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
@@ -180,11 +182,12 @@ async function writeCredentialFiles(input) {
|
|
|
180
182
|
agentPath,
|
|
181
183
|
{
|
|
182
184
|
agent_id: input.agentId,
|
|
185
|
+
delegate_address: input.delegateAddress,
|
|
183
186
|
safe_address: input.safeAddress,
|
|
184
187
|
chain_id: input.chainId,
|
|
185
188
|
network: input.network,
|
|
186
189
|
agent_budget: input.agentBudget,
|
|
187
|
-
note: "Non-secret orientation for the agent: identity + configured budget. Contains no API key or signing key. For the live remaining budget, call haven_get_allowances."
|
|
190
|
+
note: "Non-secret orientation for the agent: public delegate/Haven wallet identity + configured budget. Contains no API key or signing key. For the live remaining budget, call haven_get_allowances."
|
|
188
191
|
},
|
|
189
192
|
input.warn
|
|
190
193
|
);
|
|
@@ -236,9 +239,9 @@ var MCP_RUNTIME_MANIFEST = {
|
|
|
236
239
|
mcpPackage: "@haven_ai/mcp",
|
|
237
240
|
mcpVersion: mcp.MCP_VERSION,
|
|
238
241
|
sdkPackage: "@haven_ai/sdk",
|
|
239
|
-
sdkVersion: "0.1.
|
|
242
|
+
sdkVersion: "0.1.23-alpha.0",
|
|
240
243
|
signerPackage: "@haven_ai/signer",
|
|
241
|
-
signerVersion: "0.1.
|
|
244
|
+
signerVersion: "0.1.23-alpha.0",
|
|
242
245
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
243
246
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
244
247
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -1400,55 +1403,64 @@ var RUNTIME_PROFILES = {
|
|
|
1400
1403
|
id: "claude-code",
|
|
1401
1404
|
label: "Claude Code",
|
|
1402
1405
|
restartMode: "restart-session",
|
|
1403
|
-
canWriteRuntimeConfig: true
|
|
1406
|
+
canWriteRuntimeConfig: true,
|
|
1407
|
+
activationInstruction: "Start a new Claude Code session so it loads the Haven MCP entries."
|
|
1404
1408
|
},
|
|
1405
1409
|
"codex-cli": {
|
|
1406
1410
|
id: "codex-cli",
|
|
1407
1411
|
label: "Codex CLI",
|
|
1408
1412
|
restartMode: "restart-session",
|
|
1409
|
-
canWriteRuntimeConfig: true
|
|
1413
|
+
canWriteRuntimeConfig: true,
|
|
1414
|
+
activationInstruction: "Start a fresh Codex CLI session (for example, run `codex resume --last`)."
|
|
1410
1415
|
},
|
|
1411
1416
|
"codex-desktop": {
|
|
1412
1417
|
id: "codex-desktop",
|
|
1413
1418
|
label: "Codex Desktop",
|
|
1414
1419
|
restartMode: "restart-session",
|
|
1415
|
-
canWriteRuntimeConfig: true
|
|
1420
|
+
canWriteRuntimeConfig: true,
|
|
1421
|
+
activationInstruction: "Quit and reopen Codex Desktop so it loads the Haven MCP entries."
|
|
1416
1422
|
},
|
|
1417
1423
|
cursor: {
|
|
1418
1424
|
id: "cursor",
|
|
1419
1425
|
label: "Cursor",
|
|
1420
1426
|
restartMode: "hot-reload",
|
|
1421
|
-
canWriteRuntimeConfig: true
|
|
1427
|
+
canWriteRuntimeConfig: true,
|
|
1428
|
+
activationInstruction: "Wait for Cursor to hot-reload the Haven MCP entries; no app restart is required."
|
|
1422
1429
|
},
|
|
1423
1430
|
vscode: {
|
|
1424
1431
|
id: "vscode",
|
|
1425
1432
|
label: "VS Code",
|
|
1426
1433
|
restartMode: "hot-reload",
|
|
1427
|
-
canWriteRuntimeConfig: true
|
|
1434
|
+
canWriteRuntimeConfig: true,
|
|
1435
|
+
activationInstruction: "Wait for VS Code to hot-reload the Haven MCP entries; no app restart is required."
|
|
1428
1436
|
},
|
|
1429
1437
|
"vscode-insiders": {
|
|
1430
1438
|
id: "vscode-insiders",
|
|
1431
1439
|
label: "VS Code Insiders",
|
|
1432
1440
|
restartMode: "hot-reload",
|
|
1433
|
-
canWriteRuntimeConfig: true
|
|
1441
|
+
canWriteRuntimeConfig: true,
|
|
1442
|
+
activationInstruction: "Wait for VS Code Insiders to hot-reload the Haven MCP entries; no app restart is required."
|
|
1434
1443
|
},
|
|
1435
1444
|
"claude-desktop": {
|
|
1436
1445
|
id: "claude-desktop",
|
|
1437
1446
|
label: "Claude Desktop",
|
|
1438
1447
|
restartMode: "restart-app",
|
|
1439
|
-
canWriteRuntimeConfig: true
|
|
1448
|
+
canWriteRuntimeConfig: true,
|
|
1449
|
+
activationInstruction: "Quit and reopen Claude Desktop so it loads the Haven MCP entries."
|
|
1440
1450
|
},
|
|
1441
1451
|
hermes: {
|
|
1442
1452
|
id: "hermes",
|
|
1443
1453
|
label: "Hermes Agent",
|
|
1444
1454
|
restartMode: "restart-session",
|
|
1445
|
-
canWriteRuntimeConfig: true
|
|
1455
|
+
canWriteRuntimeConfig: true,
|
|
1456
|
+
activationInstruction: "Start a new Hermes session; in Hermes Gateway, run `/restart` instead."
|
|
1446
1457
|
},
|
|
1447
1458
|
other: {
|
|
1448
1459
|
id: "other",
|
|
1449
1460
|
label: "Other agent runtime",
|
|
1450
1461
|
restartMode: "manual",
|
|
1451
|
-
canWriteRuntimeConfig: false
|
|
1462
|
+
canWriteRuntimeConfig: false,
|
|
1463
|
+
activationInstruction: "Finish the manual MCP setup shown above, then start a fresh session in that runtime."
|
|
1452
1464
|
}
|
|
1453
1465
|
};
|
|
1454
1466
|
var RUNTIME_ALIASES = {
|
|
@@ -1500,8 +1512,9 @@ function restartRequiredForRuntime(runtime, env = process.env) {
|
|
|
1500
1512
|
const mode = runtimeProfile(runtime, env).restartMode;
|
|
1501
1513
|
return mode === "restart-session" || mode === "restart-app";
|
|
1502
1514
|
}
|
|
1503
|
-
function
|
|
1504
|
-
|
|
1515
|
+
function runtimeVerificationInstruction(runtime) {
|
|
1516
|
+
const label = RUNTIME_PROFILES[runtime].label;
|
|
1517
|
+
return `In ${label}, run the read-only \`haven_get_agent\` and \`haven_get_allowances\` tools to confirm the Haven wallet and live budget. Do not sign, fund, or create a payment to verify setup.`;
|
|
1505
1518
|
}
|
|
1506
1519
|
function normalizeRuntimeName(runtime) {
|
|
1507
1520
|
const key = runtime?.trim().toLowerCase();
|
|
@@ -1687,11 +1700,12 @@ async function installRuntime(input, deps = {}) {
|
|
|
1687
1700
|
probeLocalSignerCredential(input.signerPath),
|
|
1688
1701
|
localProbePromise
|
|
1689
1702
|
]);
|
|
1690
|
-
const hostedOk = configResult.hostedConfigured && hostedProbe.status
|
|
1703
|
+
const hostedOk = configResult.hostedConfigured && hostedProbe.status === "ok";
|
|
1691
1704
|
const localMcpOk = configResult.runtimeMcpMode === "local_stdio" && configResult.localMcpConfigured && signerCredentialReady && Boolean(localMcpConsent?.acknowledged) && localMcpProbe?.status === "ok";
|
|
1692
1705
|
const signerOk = configResult.runtimeMcpMode === "local_stdio" ? localMcpOk : configResult.signerConfigured && signerCredentialReady && Boolean(signerConsent?.acknowledged);
|
|
1693
1706
|
const restartRequired = configResult.restartRequired || restartRequiredForRuntime(runtime, deps.env);
|
|
1694
|
-
const errorCode = configResult.errorCode ?? (configResult.runtimeMcpMode === "local_stdio" ? localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbe?.status) : signerConsentErrorCode(signerCredentialReady, signerConsent));
|
|
1707
|
+
const errorCode = configResult.errorCode ?? (configResult.runtimeMcpMode === "local_stdio" ? localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbe?.status) : hostedMcpErrorCode(configResult.hostedConfigured, hostedProbe.status) ?? signerConsentErrorCode(signerCredentialReady, signerConsent));
|
|
1708
|
+
const hostedProbeMessages = configResult.hostedConfigured && hostedProbe.status !== "ok" ? [`Hosted Haven MCP probe failed: ${hostedProbe.status}.`] : configResult.hostedConfigured ? ["Verified hosted Haven MCP tools with a read-only handshake."] : [];
|
|
1695
1709
|
const localProbeMessages = localMcpProbe && localMcpProbe.status !== "ok" ? [`Local Haven MCP handshake failed: ${localMcpProbe.status}.`] : localMcpProbe?.status === "ok" ? ["Verified local Haven MCP tools with a stdio handshake."] : [];
|
|
1696
1710
|
const skillInstall = runtime === "claude-code" && !configResult.errorCode ? await installClaudeSkill(deps.homeDir) : void 0;
|
|
1697
1711
|
return {
|
|
@@ -1710,7 +1724,7 @@ async function installRuntime(input, deps = {}) {
|
|
|
1710
1724
|
activationCommand: configResult.activationCommand,
|
|
1711
1725
|
skillInstalled: skillInstall?.installed,
|
|
1712
1726
|
signerRuntimePrepared,
|
|
1713
|
-
messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
|
|
1727
|
+
messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...hostedProbeMessages, ...localProbeMessages, ...skillInstall?.messages ?? []]
|
|
1714
1728
|
};
|
|
1715
1729
|
}
|
|
1716
1730
|
function runtimeInstallCapabilities(runtime, env = process.env) {
|
|
@@ -1871,6 +1885,10 @@ function signerConsentErrorCode(signerCredentialReady, signerConsent) {
|
|
|
1871
1885
|
if (!signerConsent?.acknowledged) return "local_signer_ack_required";
|
|
1872
1886
|
return void 0;
|
|
1873
1887
|
}
|
|
1888
|
+
function hostedMcpErrorCode(hostedConfigured, hostedProbeStatus) {
|
|
1889
|
+
if (!hostedConfigured || hostedProbeStatus === "ok") return void 0;
|
|
1890
|
+
return `hosted_mcp_probe_${hostedProbeStatus}`;
|
|
1891
|
+
}
|
|
1874
1892
|
function localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbeStatus) {
|
|
1875
1893
|
if (!signerCredentialReady) return "local_signer_credential_unavailable";
|
|
1876
1894
|
if (!localMcpConsent?.acknowledged) return "local_mcp_ack_required";
|
|
@@ -1922,13 +1940,17 @@ function localRuntimePrepareErrorCode(err) {
|
|
|
1922
1940
|
}
|
|
1923
1941
|
|
|
1924
1942
|
// src/runtime.ts
|
|
1925
|
-
var CONNECTOR_VERSION = "0.1.
|
|
1943
|
+
var CONNECTOR_VERSION = "0.1.23-alpha.0";
|
|
1944
|
+
var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
1926
1945
|
async function runConnect(options, deps = {}) {
|
|
1927
1946
|
assertSupportedNodeVersion(deps.nodeVersion, MCP_RUNTIME_MANIFEST.minimumNodeVersion);
|
|
1928
1947
|
const connectorVersion = options.connectorVersion ?? CONNECTOR_VERSION;
|
|
1929
1948
|
const api = deps.api ?? createConnectApiClient(options.apiBaseUrl);
|
|
1930
|
-
const log = secureLogger(
|
|
1931
|
-
|
|
1949
|
+
const log = secureLogger(
|
|
1950
|
+
deps.log ?? ((message) => process.stdout.write(`${message}
|
|
1951
|
+
`)),
|
|
1952
|
+
deps.redactPaths === true
|
|
1953
|
+
);
|
|
1932
1954
|
const writeCredentials = deps.writeCredentials ?? writeCredentialFiles;
|
|
1933
1955
|
const preflightStorage = deps.preflightStorage ?? preflightCredentialStorage;
|
|
1934
1956
|
const runRuntimeInstall = deps.installRuntime ?? installRuntime;
|
|
@@ -1949,6 +1971,7 @@ async function runConnect(options, deps = {}) {
|
|
|
1949
1971
|
connectorVersion,
|
|
1950
1972
|
runtime: options.runtime
|
|
1951
1973
|
});
|
|
1974
|
+
assertSetupChallengeIsUsable(setup.challenge.expires_at);
|
|
1952
1975
|
printSetupSummary(setup, log);
|
|
1953
1976
|
await preflightStorage({ baseDir: options.credentialsDir, warn: log });
|
|
1954
1977
|
log("Checked local credential storage \u2014 all clear.");
|
|
@@ -1957,21 +1980,31 @@ async function runConnect(options, deps = {}) {
|
|
|
1957
1980
|
log("Minting a fresh signing key and API key \u2014 both stay on this machine.");
|
|
1958
1981
|
const proofSignature = await localKey.signChallenge(setup.challenge.message);
|
|
1959
1982
|
log("Introducing your agent to Haven\u2026");
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1983
|
+
let registration;
|
|
1984
|
+
try {
|
|
1985
|
+
registration = await api.registerSetup({
|
|
1986
|
+
setupToken: options.setupToken,
|
|
1987
|
+
connectorVersion,
|
|
1988
|
+
runtime: options.runtime,
|
|
1989
|
+
challengeId: setup.challenge.id,
|
|
1990
|
+
delegateAddress: localKey.address,
|
|
1991
|
+
proofSignature,
|
|
1992
|
+
apiKeyHash: hashAgentApiKey(localApiKey),
|
|
1993
|
+
apiKeyPrefix: agentApiKeyPrefix(localApiKey),
|
|
1994
|
+
connectorContext: {
|
|
1995
|
+
environment_label: options.environmentLabel ?? "Local workspace",
|
|
1996
|
+
config_target: installCapabilities.canWriteRuntimeConfig ? "agent runtime MCP config" : "local credential files"
|
|
1997
|
+
},
|
|
1998
|
+
installCapabilities
|
|
1999
|
+
});
|
|
2000
|
+
} catch (err) {
|
|
2001
|
+
if (isExpiredSetupChallenge(err)) {
|
|
2002
|
+
throw new Error(
|
|
2003
|
+
"The Haven setup challenge expired while connecting. Return to Haven, start a fresh connection, and run its new Connect command. Do not reuse or paste credentials."
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
throw err;
|
|
2007
|
+
}
|
|
1975
2008
|
log(`Registered signing address with Haven: ${shortAddress(registration.delegate_address)}.`);
|
|
1976
2009
|
log("Tucking your credentials away safely on disk\u2026");
|
|
1977
2010
|
const credentialPaths = await writeCredentials({
|
|
@@ -2048,7 +2081,69 @@ async function runConnect(options, deps = {}) {
|
|
|
2048
2081
|
setupId: registration.setup_id,
|
|
2049
2082
|
agentId: registration.agent_id,
|
|
2050
2083
|
delegateAddress: registration.delegate_address,
|
|
2051
|
-
credentialPaths
|
|
2084
|
+
credentialPaths,
|
|
2085
|
+
outcome: completionOutcome({
|
|
2086
|
+
runtimeInstall,
|
|
2087
|
+
delegateAddress: registration.delegate_address,
|
|
2088
|
+
setupChallengeExpiresAt: setup.challenge.expires_at,
|
|
2089
|
+
approvalRequired: registration.agent_status === "pending_approval"
|
|
2090
|
+
})
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
function completionOutcome(input) {
|
|
2094
|
+
const { runtimeInstall } = input;
|
|
2095
|
+
const manualSetup = runtimeInstall.errorCode === "manual_runtime_setup_required";
|
|
2096
|
+
const nextAction2 = runtimeInstall.nextUserAction;
|
|
2097
|
+
const outcome = {
|
|
2098
|
+
schema_version: CONNECT_OUTCOME_SCHEMA_VERSION,
|
|
2099
|
+
outcome: runtimeInstall.errorCode ? "action_required" : "complete",
|
|
2100
|
+
runtime: runtimeInstall.runtime,
|
|
2101
|
+
topology: runtimeInstall.runtimeMcpMode,
|
|
2102
|
+
configuration: {
|
|
2103
|
+
hosted_mcp: runtimeInstall.hostedMcpConfigured,
|
|
2104
|
+
local_signer: runtimeInstall.localSignerConfigured,
|
|
2105
|
+
local_mcp: runtimeInstall.localMcpConfigured
|
|
2106
|
+
},
|
|
2107
|
+
probe: { result: runtimeInstall.probeResult },
|
|
2108
|
+
activation: {
|
|
2109
|
+
restart_required: runtimeInstall.restartRequired,
|
|
2110
|
+
instruction: manualSetup ? "Finish the manual MCP setup using the secret-free references shown in normal Connect output, then start a fresh session." : runtimeProfile(runtimeInstall.runtime).activationInstruction
|
|
2111
|
+
},
|
|
2112
|
+
next_action: nextAction2,
|
|
2113
|
+
approval: { required: input.approvalRequired, expires_at: null },
|
|
2114
|
+
verification: {
|
|
2115
|
+
tools: ["haven_get_agent", "haven_get_allowances"],
|
|
2116
|
+
instruction: runtimeVerificationInstruction(runtimeInstall.runtime)
|
|
2117
|
+
},
|
|
2118
|
+
// The backend contract supplies a 20-byte address. If an unexpected
|
|
2119
|
+
// malformed value arrives, do not echo it into an automation-facing
|
|
2120
|
+
// record; the human log has already been redacted separately.
|
|
2121
|
+
delegate_address: /^0x[0-9a-fA-F]{40}$/.test(input.delegateAddress) ? shortAddress(input.delegateAddress) : "[delegate-address-redacted]",
|
|
2122
|
+
...input.setupChallengeExpiresAt ? { setup_challenge_expires_at: input.setupChallengeExpiresAt } : {},
|
|
2123
|
+
...runtimeInstall.errorCode ? { error: { code: runtimeInstall.errorCode, next_action: nextAction2 } } : {}
|
|
2124
|
+
};
|
|
2125
|
+
return outcome;
|
|
2126
|
+
}
|
|
2127
|
+
function failedConnectOutcome(runtimeHint, error) {
|
|
2128
|
+
const message = error instanceof Error ? error.message : "";
|
|
2129
|
+
const code = /Node\.js >=/i.test(message) ? "unsupported_node_version" : /setup challenge.*expired|expired or invalid/i.test(message) ? "setup_challenge_expired_or_invalid" : /only available for Claude Code and Codex/i.test(message) ? "local_mcp_unsupported_runtime" : "connect_failed";
|
|
2130
|
+
const runtime = normalizeRuntime(runtimeHint);
|
|
2131
|
+
const nextAction2 = code === "setup_challenge_expired_or_invalid" ? "return_to_haven_for_fresh_setup" : code === "unsupported_node_version" ? "install_supported_node_and_rerun_connect" : code === "local_mcp_unsupported_runtime" ? "rerun_without_local_mcp" : "review_the_safe_error_output_and_start_a_fresh_haven_setup_if_needed";
|
|
2132
|
+
return {
|
|
2133
|
+
schema_version: CONNECT_OUTCOME_SCHEMA_VERSION,
|
|
2134
|
+
outcome: "failed",
|
|
2135
|
+
runtime,
|
|
2136
|
+
topology: "unknown",
|
|
2137
|
+
configuration: { hosted_mcp: false, local_signer: false, local_mcp: false },
|
|
2138
|
+
probe: { result: "not_run" },
|
|
2139
|
+
activation: { restart_required: false, instruction: "Resolve the reported problem before activating Haven tools." },
|
|
2140
|
+
next_action: nextAction2,
|
|
2141
|
+
approval: { required: false, expires_at: null },
|
|
2142
|
+
verification: {
|
|
2143
|
+
tools: ["haven_get_agent", "haven_get_allowances"],
|
|
2144
|
+
instruction: "After a successful setup and activation, verify only with haven_get_agent and haven_get_allowances."
|
|
2145
|
+
},
|
|
2146
|
+
error: { code, next_action: nextAction2 }
|
|
2052
2147
|
};
|
|
2053
2148
|
}
|
|
2054
2149
|
function printSetupSummary(setup, log) {
|
|
@@ -2061,10 +2156,26 @@ function printSetupSummary(setup, log) {
|
|
|
2061
2156
|
);
|
|
2062
2157
|
}
|
|
2063
2158
|
}
|
|
2064
|
-
log(`Setup challenge expires at ${setup.challenge.expires_at}.`);
|
|
2159
|
+
log(`Setup challenge expires at ${setup.challenge.expires_at}. If it expires, return to Haven for a fresh setup and rerun Connect \u2014 do not reuse or paste credentials.`);
|
|
2160
|
+
}
|
|
2161
|
+
function assertSetupChallengeIsUsable(expiresAt) {
|
|
2162
|
+
const expiresAtMs = Date.parse(expiresAt);
|
|
2163
|
+
if (!Number.isNaN(expiresAtMs) && expiresAtMs > Date.now()) return;
|
|
2164
|
+
throw new Error(
|
|
2165
|
+
"This Haven setup challenge is expired or invalid. Return to Haven, start a fresh connection, and rerun Connect. No local credentials were written."
|
|
2166
|
+
);
|
|
2065
2167
|
}
|
|
2066
|
-
function
|
|
2067
|
-
return (
|
|
2168
|
+
function isExpiredSetupChallenge(err) {
|
|
2169
|
+
return err instanceof Error && /(?:setup )?challenge.*expir|expir.*(?:setup )?challenge/i.test(err.message);
|
|
2170
|
+
}
|
|
2171
|
+
function secureLogger(log, redactPaths = false) {
|
|
2172
|
+
return (message) => {
|
|
2173
|
+
let safe = redactSecrets(message);
|
|
2174
|
+
if (redactPaths) {
|
|
2175
|
+
safe = safe.replace(/(?:~|\/)[^\s`"']*\/(?:identity|signer|agent)\.json\b/g, "[credential-file-redacted]").replace(/(?:~|\/)[^\s`"']*\/\.env\b/g, "[credential-env-redacted]");
|
|
2176
|
+
}
|
|
2177
|
+
log(safe);
|
|
2178
|
+
};
|
|
2068
2179
|
}
|
|
2069
2180
|
function printRuntimeInstall(result, log) {
|
|
2070
2181
|
for (const message of result.messages) log(message);
|
|
@@ -2081,17 +2192,30 @@ function printRuntimeInstall(result, log) {
|
|
|
2081
2192
|
log("Local Haven signer still needs runtime setup.");
|
|
2082
2193
|
}
|
|
2083
2194
|
}
|
|
2084
|
-
function
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
} else {
|
|
2093
|
-
log("After you approve, the Haven tools should appear in this runtime shortly.");
|
|
2195
|
+
function completionHandoffLines(result) {
|
|
2196
|
+
if (result.errorCode === "manual_runtime_setup_required") {
|
|
2197
|
+
return [
|
|
2198
|
+
"Next steps:",
|
|
2199
|
+
"1. Return to Haven and approve the agent rules. Approval \u2014 not restarting \u2014 unlocks Haven tools.",
|
|
2200
|
+
"2. Finish the manual MCP setup using the secret-free file references printed above, then start a fresh session in your runtime.",
|
|
2201
|
+
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
2202
|
+
];
|
|
2094
2203
|
}
|
|
2204
|
+
if (result.errorCode) {
|
|
2205
|
+
return [
|
|
2206
|
+
"Recovery: runtime setup is not complete. Resolve the reported problem, then return to Haven for a fresh connection and run its new Connect command. Do not manually edit runtime config or paste credentials into prompts, logs, or config."
|
|
2207
|
+
];
|
|
2208
|
+
}
|
|
2209
|
+
const profile = runtimeProfile(result.runtime);
|
|
2210
|
+
return [
|
|
2211
|
+
"Next steps:",
|
|
2212
|
+
"1. Return to Haven and approve the agent rules. Approval \u2014 not restarting \u2014 unlocks Haven tools.",
|
|
2213
|
+
`2. ${profile.activationInstruction}`,
|
|
2214
|
+
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
2215
|
+
];
|
|
2216
|
+
}
|
|
2217
|
+
function printNextSteps(result, log) {
|
|
2218
|
+
for (const line of completionHandoffLines(result)) log(line);
|
|
2095
2219
|
}
|
|
2096
2220
|
|
|
2097
2221
|
// src/args.ts
|
|
@@ -2101,10 +2225,13 @@ function parseArgs(argv, env = process.env) {
|
|
|
2101
2225
|
connectorVersion: CONNECTOR_VERSION
|
|
2102
2226
|
};
|
|
2103
2227
|
let help = false;
|
|
2228
|
+
let json = false;
|
|
2104
2229
|
for (let i = 0; i < argv.length; i += 1) {
|
|
2105
2230
|
const arg = argv[i];
|
|
2106
2231
|
if (arg === "--help" || arg === "-h") {
|
|
2107
2232
|
help = true;
|
|
2233
|
+
} else if (arg === "--json") {
|
|
2234
|
+
json = true;
|
|
2108
2235
|
} else if (arg === "--setup" || arg === "--setup-token") {
|
|
2109
2236
|
options.setupToken = requireValue(argv, ++i, arg);
|
|
2110
2237
|
} else if (arg === "--api" || arg === "--api-url") {
|
|
@@ -2131,7 +2258,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
2131
2258
|
}
|
|
2132
2259
|
}
|
|
2133
2260
|
if (help) {
|
|
2134
|
-
return { options, help };
|
|
2261
|
+
return { options, help, json };
|
|
2135
2262
|
}
|
|
2136
2263
|
if (!options.setupToken) {
|
|
2137
2264
|
throw new Error("Missing --setup <hv_setup_...> setup token.");
|
|
@@ -2140,7 +2267,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
2140
2267
|
throw new Error("Missing --api <Haven API URL>.");
|
|
2141
2268
|
}
|
|
2142
2269
|
options.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
|
|
2143
|
-
return { options, help };
|
|
2270
|
+
return { options, help, json };
|
|
2144
2271
|
}
|
|
2145
2272
|
function helpText() {
|
|
2146
2273
|
return [
|
|
@@ -2162,9 +2289,10 @@ function helpText() {
|
|
|
2162
2289
|
" --ack-signer Backward-compatible alias for --ack-local-tools.",
|
|
2163
2290
|
" --local Advanced: install the fully-local Haven MCP (no hosted dependency).",
|
|
2164
2291
|
" Only available for Claude Code and Codex. Default is hosted MCP + local signer.",
|
|
2292
|
+
" --json Emit one versioned, secret-free result object on stdout; progress stays on stderr.",
|
|
2165
2293
|
" --help Show this help.",
|
|
2166
2294
|
"",
|
|
2167
|
-
"The connector never prints the private key and never sends it to Haven."
|
|
2295
|
+
"The connector never prints the private key and never sends it to Haven. JSON output never includes credential contents or full credential paths."
|
|
2168
2296
|
].join("\n");
|
|
2169
2297
|
}
|
|
2170
2298
|
function requireValue(argv, index, option) {
|
|
@@ -2174,12 +2302,63 @@ function requireValue(argv, index, option) {
|
|
|
2174
2302
|
}
|
|
2175
2303
|
return value;
|
|
2176
2304
|
}
|
|
2305
|
+
async function runCli(argv, io = {
|
|
2306
|
+
stdout: (message) => process.stdout.write(message),
|
|
2307
|
+
stderr: (message) => process.stderr.write(message)
|
|
2308
|
+
}) {
|
|
2309
|
+
const wantsJson = argv.includes("--json");
|
|
2310
|
+
let parsed;
|
|
2311
|
+
try {
|
|
2312
|
+
parsed = parseArgs(argv);
|
|
2313
|
+
} catch (err) {
|
|
2314
|
+
if (wantsJson) {
|
|
2315
|
+
io.stdout(`${JSON.stringify(failedConnectOutcome(void 0, err))}
|
|
2316
|
+
`);
|
|
2317
|
+
} else {
|
|
2318
|
+
io.stderr(`${redactSecrets(err instanceof Error ? err.message : String(err))}
|
|
2319
|
+
`);
|
|
2320
|
+
}
|
|
2321
|
+
return 1;
|
|
2322
|
+
}
|
|
2323
|
+
if (parsed.help) {
|
|
2324
|
+
io.stdout(`${helpText()}
|
|
2325
|
+
`);
|
|
2326
|
+
return 0;
|
|
2327
|
+
}
|
|
2328
|
+
try {
|
|
2329
|
+
const result = await runConnect(parsed.options, {
|
|
2330
|
+
log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
|
|
2331
|
+
`),
|
|
2332
|
+
redactPaths: parsed.json
|
|
2333
|
+
});
|
|
2334
|
+
if (parsed.json) io.stdout(`${JSON.stringify(result.outcome)}
|
|
2335
|
+
`);
|
|
2336
|
+
return 0;
|
|
2337
|
+
} catch (err) {
|
|
2338
|
+
if (parsed.json) {
|
|
2339
|
+
io.stdout(`${JSON.stringify(failedConnectOutcome(parsed.options.runtime, err))}
|
|
2340
|
+
`);
|
|
2341
|
+
} else {
|
|
2342
|
+
io.stderr(`${redactSecrets(err instanceof Error ? err.message : String(err))}
|
|
2343
|
+
`);
|
|
2344
|
+
}
|
|
2345
|
+
return 1;
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
async function main() {
|
|
2349
|
+
const exitCode = await runCli(process.argv.slice(2));
|
|
2350
|
+
if (exitCode !== 0) process.exitCode = exitCode;
|
|
2351
|
+
}
|
|
2352
|
+
if (process.argv[1] && url.pathToFileURL(process.argv[1]).href === (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))) void main();
|
|
2177
2353
|
|
|
2178
2354
|
exports.CONNECTOR_VERSION = CONNECTOR_VERSION;
|
|
2355
|
+
exports.CONNECT_OUTCOME_SCHEMA_VERSION = CONNECT_OUTCOME_SCHEMA_VERSION;
|
|
2179
2356
|
exports.MCP_RUNTIME_MANIFEST = MCP_RUNTIME_MANIFEST;
|
|
2357
|
+
exports.completionOutcome = completionOutcome;
|
|
2180
2358
|
exports.createConnectApiClient = createConnectApiClient;
|
|
2181
2359
|
exports.defaultAgentDirectory = defaultAgentDirectory;
|
|
2182
2360
|
exports.delegateKeyFromPrivateKey = delegateKeyFromPrivateKey;
|
|
2361
|
+
exports.failedConnectOutcome = failedConnectOutcome;
|
|
2183
2362
|
exports.generateDelegateKey = generateDelegateKey;
|
|
2184
2363
|
exports.helpText = helpText;
|
|
2185
2364
|
exports.installRuntime = installRuntime;
|
|
@@ -2188,6 +2367,7 @@ exports.normalizeRuntime = normalizeRuntime;
|
|
|
2188
2367
|
exports.parseArgs = parseArgs;
|
|
2189
2368
|
exports.prepareSignerRuntime = prepareSignerRuntime;
|
|
2190
2369
|
exports.redactSecrets = redactSecrets;
|
|
2370
|
+
exports.runCli = runCli;
|
|
2191
2371
|
exports.runConnect = runConnect;
|
|
2192
2372
|
exports.runtimeInstallCapabilities = runtimeInstallCapabilities;
|
|
2193
2373
|
exports.runtimeProfile = runtimeProfile;
|