@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.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import { Wallet } from 'ethers';
|
|
3
|
-
import { mkdir, rm,
|
|
3
|
+
import { mkdir, rm, chmod, access, writeFile, readFile, unlink } from 'fs/promises';
|
|
4
4
|
import { homedir, platform } from 'os';
|
|
5
5
|
import { join, resolve, dirname } from 'path';
|
|
6
6
|
import { execFile, spawn } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
8
8
|
import { parseDocument, isMap, stringify } from 'yaml';
|
|
9
9
|
import { registeredToolNames, MCP_VERSION, ensureConsent, computeConsentHash, loadCredentials, consentInputFromClient } from '@haven_ai/mcp';
|
|
10
|
-
import { HAVEN_MINIMUM_NODE_VERSION,
|
|
10
|
+
import { HAVEN_MINIMUM_NODE_VERSION, isSupportedNodeVersion, unsupportedNodeVersionMessage, SKILL_FOLDER_NAME, HAVEN_SKILL_MD } from '@haven_ai/sdk';
|
|
11
11
|
import { ensureSignerConsent, computeSignerConsentHash, loadSignerCredentials, createEdgeSigner, toolSchemas } from '@haven_ai/signer';
|
|
12
|
+
import { pathToFileURL } from 'url';
|
|
12
13
|
|
|
13
14
|
// src/api.ts
|
|
14
15
|
function createConnectApiClient(baseUrl, fetchImpl = fetch) {
|
|
@@ -174,11 +175,12 @@ async function writeCredentialFiles(input) {
|
|
|
174
175
|
agentPath,
|
|
175
176
|
{
|
|
176
177
|
agent_id: input.agentId,
|
|
178
|
+
delegate_address: input.delegateAddress,
|
|
177
179
|
safe_address: input.safeAddress,
|
|
178
180
|
chain_id: input.chainId,
|
|
179
181
|
network: input.network,
|
|
180
182
|
agent_budget: input.agentBudget,
|
|
181
|
-
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."
|
|
183
|
+
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."
|
|
182
184
|
},
|
|
183
185
|
input.warn
|
|
184
186
|
);
|
|
@@ -230,9 +232,9 @@ var MCP_RUNTIME_MANIFEST = {
|
|
|
230
232
|
mcpPackage: "@haven_ai/mcp",
|
|
231
233
|
mcpVersion: MCP_VERSION,
|
|
232
234
|
sdkPackage: "@haven_ai/sdk",
|
|
233
|
-
sdkVersion: "0.1.
|
|
235
|
+
sdkVersion: "0.1.23-alpha.0",
|
|
234
236
|
signerPackage: "@haven_ai/signer",
|
|
235
|
-
signerVersion: "0.1.
|
|
237
|
+
signerVersion: "0.1.23-alpha.0",
|
|
236
238
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
237
239
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
238
240
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -1394,55 +1396,64 @@ var RUNTIME_PROFILES = {
|
|
|
1394
1396
|
id: "claude-code",
|
|
1395
1397
|
label: "Claude Code",
|
|
1396
1398
|
restartMode: "restart-session",
|
|
1397
|
-
canWriteRuntimeConfig: true
|
|
1399
|
+
canWriteRuntimeConfig: true,
|
|
1400
|
+
activationInstruction: "Start a new Claude Code session so it loads the Haven MCP entries."
|
|
1398
1401
|
},
|
|
1399
1402
|
"codex-cli": {
|
|
1400
1403
|
id: "codex-cli",
|
|
1401
1404
|
label: "Codex CLI",
|
|
1402
1405
|
restartMode: "restart-session",
|
|
1403
|
-
canWriteRuntimeConfig: true
|
|
1406
|
+
canWriteRuntimeConfig: true,
|
|
1407
|
+
activationInstruction: "Start a fresh Codex CLI session (for example, run `codex resume --last`)."
|
|
1404
1408
|
},
|
|
1405
1409
|
"codex-desktop": {
|
|
1406
1410
|
id: "codex-desktop",
|
|
1407
1411
|
label: "Codex Desktop",
|
|
1408
1412
|
restartMode: "restart-session",
|
|
1409
|
-
canWriteRuntimeConfig: true
|
|
1413
|
+
canWriteRuntimeConfig: true,
|
|
1414
|
+
activationInstruction: "Quit and reopen Codex Desktop so it loads the Haven MCP entries."
|
|
1410
1415
|
},
|
|
1411
1416
|
cursor: {
|
|
1412
1417
|
id: "cursor",
|
|
1413
1418
|
label: "Cursor",
|
|
1414
1419
|
restartMode: "hot-reload",
|
|
1415
|
-
canWriteRuntimeConfig: true
|
|
1420
|
+
canWriteRuntimeConfig: true,
|
|
1421
|
+
activationInstruction: "Wait for Cursor to hot-reload the Haven MCP entries; no app restart is required."
|
|
1416
1422
|
},
|
|
1417
1423
|
vscode: {
|
|
1418
1424
|
id: "vscode",
|
|
1419
1425
|
label: "VS Code",
|
|
1420
1426
|
restartMode: "hot-reload",
|
|
1421
|
-
canWriteRuntimeConfig: true
|
|
1427
|
+
canWriteRuntimeConfig: true,
|
|
1428
|
+
activationInstruction: "Wait for VS Code to hot-reload the Haven MCP entries; no app restart is required."
|
|
1422
1429
|
},
|
|
1423
1430
|
"vscode-insiders": {
|
|
1424
1431
|
id: "vscode-insiders",
|
|
1425
1432
|
label: "VS Code Insiders",
|
|
1426
1433
|
restartMode: "hot-reload",
|
|
1427
|
-
canWriteRuntimeConfig: true
|
|
1434
|
+
canWriteRuntimeConfig: true,
|
|
1435
|
+
activationInstruction: "Wait for VS Code Insiders to hot-reload the Haven MCP entries; no app restart is required."
|
|
1428
1436
|
},
|
|
1429
1437
|
"claude-desktop": {
|
|
1430
1438
|
id: "claude-desktop",
|
|
1431
1439
|
label: "Claude Desktop",
|
|
1432
1440
|
restartMode: "restart-app",
|
|
1433
|
-
canWriteRuntimeConfig: true
|
|
1441
|
+
canWriteRuntimeConfig: true,
|
|
1442
|
+
activationInstruction: "Quit and reopen Claude Desktop so it loads the Haven MCP entries."
|
|
1434
1443
|
},
|
|
1435
1444
|
hermes: {
|
|
1436
1445
|
id: "hermes",
|
|
1437
1446
|
label: "Hermes Agent",
|
|
1438
1447
|
restartMode: "restart-session",
|
|
1439
|
-
canWriteRuntimeConfig: true
|
|
1448
|
+
canWriteRuntimeConfig: true,
|
|
1449
|
+
activationInstruction: "Start a new Hermes session; in Hermes Gateway, run `/restart` instead."
|
|
1440
1450
|
},
|
|
1441
1451
|
other: {
|
|
1442
1452
|
id: "other",
|
|
1443
1453
|
label: "Other agent runtime",
|
|
1444
1454
|
restartMode: "manual",
|
|
1445
|
-
canWriteRuntimeConfig: false
|
|
1455
|
+
canWriteRuntimeConfig: false,
|
|
1456
|
+
activationInstruction: "Finish the manual MCP setup shown above, then start a fresh session in that runtime."
|
|
1446
1457
|
}
|
|
1447
1458
|
};
|
|
1448
1459
|
var RUNTIME_ALIASES = {
|
|
@@ -1494,8 +1505,9 @@ function restartRequiredForRuntime(runtime, env = process.env) {
|
|
|
1494
1505
|
const mode = runtimeProfile(runtime, env).restartMode;
|
|
1495
1506
|
return mode === "restart-session" || mode === "restart-app";
|
|
1496
1507
|
}
|
|
1497
|
-
function
|
|
1498
|
-
|
|
1508
|
+
function runtimeVerificationInstruction(runtime) {
|
|
1509
|
+
const label = RUNTIME_PROFILES[runtime].label;
|
|
1510
|
+
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.`;
|
|
1499
1511
|
}
|
|
1500
1512
|
function normalizeRuntimeName(runtime) {
|
|
1501
1513
|
const key = runtime?.trim().toLowerCase();
|
|
@@ -1681,11 +1693,12 @@ async function installRuntime(input, deps = {}) {
|
|
|
1681
1693
|
probeLocalSignerCredential(input.signerPath),
|
|
1682
1694
|
localProbePromise
|
|
1683
1695
|
]);
|
|
1684
|
-
const hostedOk = configResult.hostedConfigured && hostedProbe.status
|
|
1696
|
+
const hostedOk = configResult.hostedConfigured && hostedProbe.status === "ok";
|
|
1685
1697
|
const localMcpOk = configResult.runtimeMcpMode === "local_stdio" && configResult.localMcpConfigured && signerCredentialReady && Boolean(localMcpConsent?.acknowledged) && localMcpProbe?.status === "ok";
|
|
1686
1698
|
const signerOk = configResult.runtimeMcpMode === "local_stdio" ? localMcpOk : configResult.signerConfigured && signerCredentialReady && Boolean(signerConsent?.acknowledged);
|
|
1687
1699
|
const restartRequired = configResult.restartRequired || restartRequiredForRuntime(runtime, deps.env);
|
|
1688
|
-
const errorCode = configResult.errorCode ?? (configResult.runtimeMcpMode === "local_stdio" ? localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbe?.status) : signerConsentErrorCode(signerCredentialReady, signerConsent));
|
|
1700
|
+
const errorCode = configResult.errorCode ?? (configResult.runtimeMcpMode === "local_stdio" ? localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbe?.status) : hostedMcpErrorCode(configResult.hostedConfigured, hostedProbe.status) ?? signerConsentErrorCode(signerCredentialReady, signerConsent));
|
|
1701
|
+
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."] : [];
|
|
1689
1702
|
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."] : [];
|
|
1690
1703
|
const skillInstall = runtime === "claude-code" && !configResult.errorCode ? await installClaudeSkill(deps.homeDir) : void 0;
|
|
1691
1704
|
return {
|
|
@@ -1704,7 +1717,7 @@ async function installRuntime(input, deps = {}) {
|
|
|
1704
1717
|
activationCommand: configResult.activationCommand,
|
|
1705
1718
|
skillInstalled: skillInstall?.installed,
|
|
1706
1719
|
signerRuntimePrepared,
|
|
1707
|
-
messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
|
|
1720
|
+
messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...hostedProbeMessages, ...localProbeMessages, ...skillInstall?.messages ?? []]
|
|
1708
1721
|
};
|
|
1709
1722
|
}
|
|
1710
1723
|
function runtimeInstallCapabilities(runtime, env = process.env) {
|
|
@@ -1865,6 +1878,10 @@ function signerConsentErrorCode(signerCredentialReady, signerConsent) {
|
|
|
1865
1878
|
if (!signerConsent?.acknowledged) return "local_signer_ack_required";
|
|
1866
1879
|
return void 0;
|
|
1867
1880
|
}
|
|
1881
|
+
function hostedMcpErrorCode(hostedConfigured, hostedProbeStatus) {
|
|
1882
|
+
if (!hostedConfigured || hostedProbeStatus === "ok") return void 0;
|
|
1883
|
+
return `hosted_mcp_probe_${hostedProbeStatus}`;
|
|
1884
|
+
}
|
|
1868
1885
|
function localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbeStatus) {
|
|
1869
1886
|
if (!signerCredentialReady) return "local_signer_credential_unavailable";
|
|
1870
1887
|
if (!localMcpConsent?.acknowledged) return "local_mcp_ack_required";
|
|
@@ -1916,13 +1933,17 @@ function localRuntimePrepareErrorCode(err) {
|
|
|
1916
1933
|
}
|
|
1917
1934
|
|
|
1918
1935
|
// src/runtime.ts
|
|
1919
|
-
var CONNECTOR_VERSION = "0.1.
|
|
1936
|
+
var CONNECTOR_VERSION = "0.1.23-alpha.0";
|
|
1937
|
+
var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
1920
1938
|
async function runConnect(options, deps = {}) {
|
|
1921
1939
|
assertSupportedNodeVersion(deps.nodeVersion, MCP_RUNTIME_MANIFEST.minimumNodeVersion);
|
|
1922
1940
|
const connectorVersion = options.connectorVersion ?? CONNECTOR_VERSION;
|
|
1923
1941
|
const api = deps.api ?? createConnectApiClient(options.apiBaseUrl);
|
|
1924
|
-
const log = secureLogger(
|
|
1925
|
-
|
|
1942
|
+
const log = secureLogger(
|
|
1943
|
+
deps.log ?? ((message) => process.stdout.write(`${message}
|
|
1944
|
+
`)),
|
|
1945
|
+
deps.redactPaths === true
|
|
1946
|
+
);
|
|
1926
1947
|
const writeCredentials = deps.writeCredentials ?? writeCredentialFiles;
|
|
1927
1948
|
const preflightStorage = deps.preflightStorage ?? preflightCredentialStorage;
|
|
1928
1949
|
const runRuntimeInstall = deps.installRuntime ?? installRuntime;
|
|
@@ -1943,6 +1964,7 @@ async function runConnect(options, deps = {}) {
|
|
|
1943
1964
|
connectorVersion,
|
|
1944
1965
|
runtime: options.runtime
|
|
1945
1966
|
});
|
|
1967
|
+
assertSetupChallengeIsUsable(setup.challenge.expires_at);
|
|
1946
1968
|
printSetupSummary(setup, log);
|
|
1947
1969
|
await preflightStorage({ baseDir: options.credentialsDir, warn: log });
|
|
1948
1970
|
log("Checked local credential storage \u2014 all clear.");
|
|
@@ -1951,21 +1973,31 @@ async function runConnect(options, deps = {}) {
|
|
|
1951
1973
|
log("Minting a fresh signing key and API key \u2014 both stay on this machine.");
|
|
1952
1974
|
const proofSignature = await localKey.signChallenge(setup.challenge.message);
|
|
1953
1975
|
log("Introducing your agent to Haven\u2026");
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1976
|
+
let registration;
|
|
1977
|
+
try {
|
|
1978
|
+
registration = await api.registerSetup({
|
|
1979
|
+
setupToken: options.setupToken,
|
|
1980
|
+
connectorVersion,
|
|
1981
|
+
runtime: options.runtime,
|
|
1982
|
+
challengeId: setup.challenge.id,
|
|
1983
|
+
delegateAddress: localKey.address,
|
|
1984
|
+
proofSignature,
|
|
1985
|
+
apiKeyHash: hashAgentApiKey(localApiKey),
|
|
1986
|
+
apiKeyPrefix: agentApiKeyPrefix(localApiKey),
|
|
1987
|
+
connectorContext: {
|
|
1988
|
+
environment_label: options.environmentLabel ?? "Local workspace",
|
|
1989
|
+
config_target: installCapabilities.canWriteRuntimeConfig ? "agent runtime MCP config" : "local credential files"
|
|
1990
|
+
},
|
|
1991
|
+
installCapabilities
|
|
1992
|
+
});
|
|
1993
|
+
} catch (err) {
|
|
1994
|
+
if (isExpiredSetupChallenge(err)) {
|
|
1995
|
+
throw new Error(
|
|
1996
|
+
"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."
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
throw err;
|
|
2000
|
+
}
|
|
1969
2001
|
log(`Registered signing address with Haven: ${shortAddress(registration.delegate_address)}.`);
|
|
1970
2002
|
log("Tucking your credentials away safely on disk\u2026");
|
|
1971
2003
|
const credentialPaths = await writeCredentials({
|
|
@@ -2042,7 +2074,69 @@ async function runConnect(options, deps = {}) {
|
|
|
2042
2074
|
setupId: registration.setup_id,
|
|
2043
2075
|
agentId: registration.agent_id,
|
|
2044
2076
|
delegateAddress: registration.delegate_address,
|
|
2045
|
-
credentialPaths
|
|
2077
|
+
credentialPaths,
|
|
2078
|
+
outcome: completionOutcome({
|
|
2079
|
+
runtimeInstall,
|
|
2080
|
+
delegateAddress: registration.delegate_address,
|
|
2081
|
+
setupChallengeExpiresAt: setup.challenge.expires_at,
|
|
2082
|
+
approvalRequired: registration.agent_status === "pending_approval"
|
|
2083
|
+
})
|
|
2084
|
+
};
|
|
2085
|
+
}
|
|
2086
|
+
function completionOutcome(input) {
|
|
2087
|
+
const { runtimeInstall } = input;
|
|
2088
|
+
const manualSetup = runtimeInstall.errorCode === "manual_runtime_setup_required";
|
|
2089
|
+
const nextAction2 = runtimeInstall.nextUserAction;
|
|
2090
|
+
const outcome = {
|
|
2091
|
+
schema_version: CONNECT_OUTCOME_SCHEMA_VERSION,
|
|
2092
|
+
outcome: runtimeInstall.errorCode ? "action_required" : "complete",
|
|
2093
|
+
runtime: runtimeInstall.runtime,
|
|
2094
|
+
topology: runtimeInstall.runtimeMcpMode,
|
|
2095
|
+
configuration: {
|
|
2096
|
+
hosted_mcp: runtimeInstall.hostedMcpConfigured,
|
|
2097
|
+
local_signer: runtimeInstall.localSignerConfigured,
|
|
2098
|
+
local_mcp: runtimeInstall.localMcpConfigured
|
|
2099
|
+
},
|
|
2100
|
+
probe: { result: runtimeInstall.probeResult },
|
|
2101
|
+
activation: {
|
|
2102
|
+
restart_required: runtimeInstall.restartRequired,
|
|
2103
|
+
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
|
|
2104
|
+
},
|
|
2105
|
+
next_action: nextAction2,
|
|
2106
|
+
approval: { required: input.approvalRequired, expires_at: null },
|
|
2107
|
+
verification: {
|
|
2108
|
+
tools: ["haven_get_agent", "haven_get_allowances"],
|
|
2109
|
+
instruction: runtimeVerificationInstruction(runtimeInstall.runtime)
|
|
2110
|
+
},
|
|
2111
|
+
// The backend contract supplies a 20-byte address. If an unexpected
|
|
2112
|
+
// malformed value arrives, do not echo it into an automation-facing
|
|
2113
|
+
// record; the human log has already been redacted separately.
|
|
2114
|
+
delegate_address: /^0x[0-9a-fA-F]{40}$/.test(input.delegateAddress) ? shortAddress(input.delegateAddress) : "[delegate-address-redacted]",
|
|
2115
|
+
...input.setupChallengeExpiresAt ? { setup_challenge_expires_at: input.setupChallengeExpiresAt } : {},
|
|
2116
|
+
...runtimeInstall.errorCode ? { error: { code: runtimeInstall.errorCode, next_action: nextAction2 } } : {}
|
|
2117
|
+
};
|
|
2118
|
+
return outcome;
|
|
2119
|
+
}
|
|
2120
|
+
function failedConnectOutcome(runtimeHint, error) {
|
|
2121
|
+
const message = error instanceof Error ? error.message : "";
|
|
2122
|
+
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";
|
|
2123
|
+
const runtime = normalizeRuntime(runtimeHint);
|
|
2124
|
+
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";
|
|
2125
|
+
return {
|
|
2126
|
+
schema_version: CONNECT_OUTCOME_SCHEMA_VERSION,
|
|
2127
|
+
outcome: "failed",
|
|
2128
|
+
runtime,
|
|
2129
|
+
topology: "unknown",
|
|
2130
|
+
configuration: { hosted_mcp: false, local_signer: false, local_mcp: false },
|
|
2131
|
+
probe: { result: "not_run" },
|
|
2132
|
+
activation: { restart_required: false, instruction: "Resolve the reported problem before activating Haven tools." },
|
|
2133
|
+
next_action: nextAction2,
|
|
2134
|
+
approval: { required: false, expires_at: null },
|
|
2135
|
+
verification: {
|
|
2136
|
+
tools: ["haven_get_agent", "haven_get_allowances"],
|
|
2137
|
+
instruction: "After a successful setup and activation, verify only with haven_get_agent and haven_get_allowances."
|
|
2138
|
+
},
|
|
2139
|
+
error: { code, next_action: nextAction2 }
|
|
2046
2140
|
};
|
|
2047
2141
|
}
|
|
2048
2142
|
function printSetupSummary(setup, log) {
|
|
@@ -2055,10 +2149,26 @@ function printSetupSummary(setup, log) {
|
|
|
2055
2149
|
);
|
|
2056
2150
|
}
|
|
2057
2151
|
}
|
|
2058
|
-
log(`Setup challenge expires at ${setup.challenge.expires_at}.`);
|
|
2152
|
+
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.`);
|
|
2153
|
+
}
|
|
2154
|
+
function assertSetupChallengeIsUsable(expiresAt) {
|
|
2155
|
+
const expiresAtMs = Date.parse(expiresAt);
|
|
2156
|
+
if (!Number.isNaN(expiresAtMs) && expiresAtMs > Date.now()) return;
|
|
2157
|
+
throw new Error(
|
|
2158
|
+
"This Haven setup challenge is expired or invalid. Return to Haven, start a fresh connection, and rerun Connect. No local credentials were written."
|
|
2159
|
+
);
|
|
2059
2160
|
}
|
|
2060
|
-
function
|
|
2061
|
-
return (
|
|
2161
|
+
function isExpiredSetupChallenge(err) {
|
|
2162
|
+
return err instanceof Error && /(?:setup )?challenge.*expir|expir.*(?:setup )?challenge/i.test(err.message);
|
|
2163
|
+
}
|
|
2164
|
+
function secureLogger(log, redactPaths = false) {
|
|
2165
|
+
return (message) => {
|
|
2166
|
+
let safe = redactSecrets(message);
|
|
2167
|
+
if (redactPaths) {
|
|
2168
|
+
safe = safe.replace(/(?:~|\/)[^\s`"']*\/(?:identity|signer|agent)\.json\b/g, "[credential-file-redacted]").replace(/(?:~|\/)[^\s`"']*\/\.env\b/g, "[credential-env-redacted]");
|
|
2169
|
+
}
|
|
2170
|
+
log(safe);
|
|
2171
|
+
};
|
|
2062
2172
|
}
|
|
2063
2173
|
function printRuntimeInstall(result, log) {
|
|
2064
2174
|
for (const message of result.messages) log(message);
|
|
@@ -2075,17 +2185,30 @@ function printRuntimeInstall(result, log) {
|
|
|
2075
2185
|
log("Local Haven signer still needs runtime setup.");
|
|
2076
2186
|
}
|
|
2077
2187
|
}
|
|
2078
|
-
function
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
} else {
|
|
2087
|
-
log("After you approve, the Haven tools should appear in this runtime shortly.");
|
|
2188
|
+
function completionHandoffLines(result) {
|
|
2189
|
+
if (result.errorCode === "manual_runtime_setup_required") {
|
|
2190
|
+
return [
|
|
2191
|
+
"Next steps:",
|
|
2192
|
+
"1. Return to Haven and approve the agent rules. Approval \u2014 not restarting \u2014 unlocks Haven tools.",
|
|
2193
|
+
"2. Finish the manual MCP setup using the secret-free file references printed above, then start a fresh session in your runtime.",
|
|
2194
|
+
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
2195
|
+
];
|
|
2088
2196
|
}
|
|
2197
|
+
if (result.errorCode) {
|
|
2198
|
+
return [
|
|
2199
|
+
"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."
|
|
2200
|
+
];
|
|
2201
|
+
}
|
|
2202
|
+
const profile = runtimeProfile(result.runtime);
|
|
2203
|
+
return [
|
|
2204
|
+
"Next steps:",
|
|
2205
|
+
"1. Return to Haven and approve the agent rules. Approval \u2014 not restarting \u2014 unlocks Haven tools.",
|
|
2206
|
+
`2. ${profile.activationInstruction}`,
|
|
2207
|
+
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
2208
|
+
];
|
|
2209
|
+
}
|
|
2210
|
+
function printNextSteps(result, log) {
|
|
2211
|
+
for (const line of completionHandoffLines(result)) log(line);
|
|
2089
2212
|
}
|
|
2090
2213
|
|
|
2091
2214
|
// src/args.ts
|
|
@@ -2095,10 +2218,13 @@ function parseArgs(argv, env = process.env) {
|
|
|
2095
2218
|
connectorVersion: CONNECTOR_VERSION
|
|
2096
2219
|
};
|
|
2097
2220
|
let help = false;
|
|
2221
|
+
let json = false;
|
|
2098
2222
|
for (let i = 0; i < argv.length; i += 1) {
|
|
2099
2223
|
const arg = argv[i];
|
|
2100
2224
|
if (arg === "--help" || arg === "-h") {
|
|
2101
2225
|
help = true;
|
|
2226
|
+
} else if (arg === "--json") {
|
|
2227
|
+
json = true;
|
|
2102
2228
|
} else if (arg === "--setup" || arg === "--setup-token") {
|
|
2103
2229
|
options.setupToken = requireValue(argv, ++i, arg);
|
|
2104
2230
|
} else if (arg === "--api" || arg === "--api-url") {
|
|
@@ -2125,7 +2251,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
2125
2251
|
}
|
|
2126
2252
|
}
|
|
2127
2253
|
if (help) {
|
|
2128
|
-
return { options, help };
|
|
2254
|
+
return { options, help, json };
|
|
2129
2255
|
}
|
|
2130
2256
|
if (!options.setupToken) {
|
|
2131
2257
|
throw new Error("Missing --setup <hv_setup_...> setup token.");
|
|
@@ -2134,7 +2260,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
2134
2260
|
throw new Error("Missing --api <Haven API URL>.");
|
|
2135
2261
|
}
|
|
2136
2262
|
options.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
|
|
2137
|
-
return { options, help };
|
|
2263
|
+
return { options, help, json };
|
|
2138
2264
|
}
|
|
2139
2265
|
function helpText() {
|
|
2140
2266
|
return [
|
|
@@ -2156,9 +2282,10 @@ function helpText() {
|
|
|
2156
2282
|
" --ack-signer Backward-compatible alias for --ack-local-tools.",
|
|
2157
2283
|
" --local Advanced: install the fully-local Haven MCP (no hosted dependency).",
|
|
2158
2284
|
" Only available for Claude Code and Codex. Default is hosted MCP + local signer.",
|
|
2285
|
+
" --json Emit one versioned, secret-free result object on stdout; progress stays on stderr.",
|
|
2159
2286
|
" --help Show this help.",
|
|
2160
2287
|
"",
|
|
2161
|
-
"The connector never prints the private key and never sends it to Haven."
|
|
2288
|
+
"The connector never prints the private key and never sends it to Haven. JSON output never includes credential contents or full credential paths."
|
|
2162
2289
|
].join("\n");
|
|
2163
2290
|
}
|
|
2164
2291
|
function requireValue(argv, index, option) {
|
|
@@ -2168,7 +2295,55 @@ function requireValue(argv, index, option) {
|
|
|
2168
2295
|
}
|
|
2169
2296
|
return value;
|
|
2170
2297
|
}
|
|
2298
|
+
async function runCli(argv, io = {
|
|
2299
|
+
stdout: (message) => process.stdout.write(message),
|
|
2300
|
+
stderr: (message) => process.stderr.write(message)
|
|
2301
|
+
}) {
|
|
2302
|
+
const wantsJson = argv.includes("--json");
|
|
2303
|
+
let parsed;
|
|
2304
|
+
try {
|
|
2305
|
+
parsed = parseArgs(argv);
|
|
2306
|
+
} catch (err) {
|
|
2307
|
+
if (wantsJson) {
|
|
2308
|
+
io.stdout(`${JSON.stringify(failedConnectOutcome(void 0, err))}
|
|
2309
|
+
`);
|
|
2310
|
+
} else {
|
|
2311
|
+
io.stderr(`${redactSecrets(err instanceof Error ? err.message : String(err))}
|
|
2312
|
+
`);
|
|
2313
|
+
}
|
|
2314
|
+
return 1;
|
|
2315
|
+
}
|
|
2316
|
+
if (parsed.help) {
|
|
2317
|
+
io.stdout(`${helpText()}
|
|
2318
|
+
`);
|
|
2319
|
+
return 0;
|
|
2320
|
+
}
|
|
2321
|
+
try {
|
|
2322
|
+
const result = await runConnect(parsed.options, {
|
|
2323
|
+
log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
|
|
2324
|
+
`),
|
|
2325
|
+
redactPaths: parsed.json
|
|
2326
|
+
});
|
|
2327
|
+
if (parsed.json) io.stdout(`${JSON.stringify(result.outcome)}
|
|
2328
|
+
`);
|
|
2329
|
+
return 0;
|
|
2330
|
+
} catch (err) {
|
|
2331
|
+
if (parsed.json) {
|
|
2332
|
+
io.stdout(`${JSON.stringify(failedConnectOutcome(parsed.options.runtime, err))}
|
|
2333
|
+
`);
|
|
2334
|
+
} else {
|
|
2335
|
+
io.stderr(`${redactSecrets(err instanceof Error ? err.message : String(err))}
|
|
2336
|
+
`);
|
|
2337
|
+
}
|
|
2338
|
+
return 1;
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
async function main() {
|
|
2342
|
+
const exitCode = await runCli(process.argv.slice(2));
|
|
2343
|
+
if (exitCode !== 0) process.exitCode = exitCode;
|
|
2344
|
+
}
|
|
2345
|
+
if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) void main();
|
|
2171
2346
|
|
|
2172
|
-
export { CONNECTOR_VERSION, MCP_RUNTIME_MANIFEST, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, prepareSignerRuntime, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
|
|
2347
|
+
export { CONNECTOR_VERSION, CONNECT_OUTCOME_SCHEMA_VERSION, MCP_RUNTIME_MANIFEST, completionOutcome, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, failedConnectOutcome, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, prepareSignerRuntime, redactSecrets, runCli, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
|
|
2173
2348
|
//# sourceMappingURL=index.js.map
|
|
2174
2349
|
//# sourceMappingURL=index.js.map
|