@haven_ai/connect 0.1.23-alpha.0 → 0.1.23-alpha.2
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 +94 -11
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +8 -1
- package/dist/cli.d.ts +8 -1
- package/dist/cli.js +95 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +93 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -4
- package/dist/index.d.ts +43 -4
- package/dist/index.js +94 -12
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/cli.d.cts
CHANGED
|
@@ -4,5 +4,12 @@ interface CliIo {
|
|
|
4
4
|
stderr: (message: string) => void;
|
|
5
5
|
}
|
|
6
6
|
declare function runCli(argv: string[], io?: CliIo): Promise<number>;
|
|
7
|
+
/**
|
|
8
|
+
* npm executes package bins through a `node_modules/.bin` symlink. Node keeps
|
|
9
|
+
* that symlink in `process.argv[1]`, whereas `import.meta.url` identifies the
|
|
10
|
+
* real module path. Resolve both sides before comparing so a published
|
|
11
|
+
* `haven-connect` bin starts, while an ordinary `runCli` import remains inert.
|
|
12
|
+
*/
|
|
13
|
+
declare function isCliEntrypoint(argvPath?: string | undefined, moduleUrl?: string): boolean;
|
|
7
14
|
|
|
8
|
-
export { type CliIo, runCli };
|
|
15
|
+
export { type CliIo, isCliEntrypoint, runCli };
|
package/dist/cli.d.ts
CHANGED
|
@@ -4,5 +4,12 @@ interface CliIo {
|
|
|
4
4
|
stderr: (message: string) => void;
|
|
5
5
|
}
|
|
6
6
|
declare function runCli(argv: string[], io?: CliIo): Promise<number>;
|
|
7
|
+
/**
|
|
8
|
+
* npm executes package bins through a `node_modules/.bin` symlink. Node keeps
|
|
9
|
+
* that symlink in `process.argv[1]`, whereas `import.meta.url` identifies the
|
|
10
|
+
* real module path. Resolve both sides before comparing so a published
|
|
11
|
+
* `haven-connect` bin starts, while an ordinary `runCli` import remains inert.
|
|
12
|
+
*/
|
|
13
|
+
declare function isCliEntrypoint(argvPath?: string | undefined, moduleUrl?: string): boolean;
|
|
7
14
|
|
|
8
|
-
export { type CliIo, runCli };
|
|
15
|
+
export { type CliIo, isCliEntrypoint, runCli };
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { realpathSync } from 'fs';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
4
|
+
import { HAVEN_MINIMUM_NODE_VERSION, isSupportedNodeVersion, unsupportedNodeVersionMessage, SKILL_FOLDER_NAME, HAVEN_SKILL_MD, resolveTokenFromAddress } from '@haven_ai/sdk';
|
|
3
5
|
import crypto from 'crypto';
|
|
4
6
|
import { Wallet } from 'ethers';
|
|
5
7
|
import { mkdir, rm, chmod, access, writeFile, readFile, unlink } from 'fs/promises';
|
|
@@ -9,7 +11,6 @@ import { execFile, spawn } from 'child_process';
|
|
|
9
11
|
import { promisify } from 'util';
|
|
10
12
|
import { parseDocument, isMap, stringify } from 'yaml';
|
|
11
13
|
import { registeredToolNames, MCP_VERSION, ensureConsent, computeConsentHash, loadCredentials, consentInputFromClient } from '@haven_ai/mcp';
|
|
12
|
-
import { HAVEN_MINIMUM_NODE_VERSION, isSupportedNodeVersion, unsupportedNodeVersionMessage, SKILL_FOLDER_NAME, HAVEN_SKILL_MD } from '@haven_ai/sdk';
|
|
13
14
|
import { ensureSignerConsent, computeSignerConsentHash, loadSignerCredentials, createEdgeSigner, toolSchemas } from '@haven_ai/signer';
|
|
14
15
|
|
|
15
16
|
// src/api.ts
|
|
@@ -42,6 +43,10 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
|
|
|
42
43
|
}
|
|
43
44
|
})
|
|
44
45
|
}),
|
|
46
|
+
getConnectorStatus: (setupId, apiKey) => request(fetchImpl, `${root}/agent-connection-setups/${encodeURIComponent(setupId)}/connector-status`, {
|
|
47
|
+
method: "GET",
|
|
48
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
49
|
+
}),
|
|
45
50
|
updateInstallStatus: async (setupId, apiKey, input) => {
|
|
46
51
|
await request(fetchImpl, `${root}/agent-connection-setups/${encodeURIComponent(setupId)}/install-status`, {
|
|
47
52
|
method: "POST",
|
|
@@ -68,6 +73,14 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
|
|
|
68
73
|
}
|
|
69
74
|
};
|
|
70
75
|
}
|
|
76
|
+
var ConnectRequestError = class extends Error {
|
|
77
|
+
constructor(message, status) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.status = status;
|
|
80
|
+
this.name = "ConnectRequestError";
|
|
81
|
+
}
|
|
82
|
+
status;
|
|
83
|
+
};
|
|
71
84
|
async function request(fetchImpl, url, init) {
|
|
72
85
|
const response = await fetchImpl(url, {
|
|
73
86
|
...init,
|
|
@@ -80,7 +93,7 @@ async function request(fetchImpl, url, init) {
|
|
|
80
93
|
const body = text ? JSON.parse(text) : null;
|
|
81
94
|
if (!response.ok) {
|
|
82
95
|
const message = body?.error ?? body?.message ?? `${response.status} ${response.statusText}`;
|
|
83
|
-
throw new
|
|
96
|
+
throw new ConnectRequestError(`Haven setup request failed: ${message}`, response.status);
|
|
84
97
|
}
|
|
85
98
|
return body;
|
|
86
99
|
}
|
|
@@ -233,9 +246,9 @@ var MCP_RUNTIME_MANIFEST = {
|
|
|
233
246
|
mcpPackage: "@haven_ai/mcp",
|
|
234
247
|
mcpVersion: MCP_VERSION,
|
|
235
248
|
sdkPackage: "@haven_ai/sdk",
|
|
236
|
-
sdkVersion: "0.1.23-alpha.
|
|
249
|
+
sdkVersion: "0.1.23-alpha.2",
|
|
237
250
|
signerPackage: "@haven_ai/signer",
|
|
238
|
-
signerVersion: "0.1.23-alpha.
|
|
251
|
+
signerVersion: "0.1.23-alpha.2",
|
|
239
252
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
240
253
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
241
254
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -1934,7 +1947,7 @@ function localRuntimePrepareErrorCode(err) {
|
|
|
1934
1947
|
}
|
|
1935
1948
|
|
|
1936
1949
|
// src/runtime.ts
|
|
1937
|
-
var CONNECTOR_VERSION = "0.1.23-alpha.
|
|
1950
|
+
var CONNECTOR_VERSION = "0.1.23-alpha.2";
|
|
1938
1951
|
var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
1939
1952
|
async function runConnect(options, deps = {}) {
|
|
1940
1953
|
assertSupportedNodeVersion(deps.nodeVersion, MCP_RUNTIME_MANIFEST.minimumNodeVersion);
|
|
@@ -2048,7 +2061,6 @@ async function runConnect(options, deps = {}) {
|
|
|
2048
2061
|
} else {
|
|
2049
2062
|
log("Haven setup on this machine is complete.");
|
|
2050
2063
|
}
|
|
2051
|
-
printNextSteps(runtimeInstall, log);
|
|
2052
2064
|
try {
|
|
2053
2065
|
await api.updateInstallStatus(registration.setup_id, localApiKey, {
|
|
2054
2066
|
runtime: runtimeInstall.runtime,
|
|
@@ -2071,6 +2083,10 @@ async function runConnect(options, deps = {}) {
|
|
|
2071
2083
|
} catch (err) {
|
|
2072
2084
|
log(`Could not report install status to Haven: ${err instanceof Error ? err.message : String(err)}`);
|
|
2073
2085
|
}
|
|
2086
|
+
if (options.waitForApproval !== false && !runtimeInstall.errorCode) {
|
|
2087
|
+
await waitForBudgetApproval(api, registration.setup_id, localApiKey, log, options.approvalWait);
|
|
2088
|
+
}
|
|
2089
|
+
printNextSteps(runtimeInstall, log);
|
|
2074
2090
|
return {
|
|
2075
2091
|
setupId: registration.setup_id,
|
|
2076
2092
|
agentId: registration.agent_id,
|
|
@@ -2186,6 +2202,61 @@ function printRuntimeInstall(result, log) {
|
|
|
2186
2202
|
log("Local Haven signer still needs runtime setup.");
|
|
2187
2203
|
}
|
|
2188
2204
|
}
|
|
2205
|
+
function formatAtomicAmount(atomic, decimals) {
|
|
2206
|
+
const s = atomic.toString().padStart(decimals + 1, "0");
|
|
2207
|
+
const intPart = s.slice(0, s.length - decimals) || "0";
|
|
2208
|
+
const fracPart = s.slice(s.length - decimals).replace(/0+$/, "");
|
|
2209
|
+
return fracPart ? `${intPart}.${fracPart}` : intPart;
|
|
2210
|
+
}
|
|
2211
|
+
function describeResetPeriod(resetPeriodMin) {
|
|
2212
|
+
if (resetPeriodMin === 1440) return "per day";
|
|
2213
|
+
if (resetPeriodMin === 60) return "per hour";
|
|
2214
|
+
if (resetPeriodMin === 0) return "with no automatic reset";
|
|
2215
|
+
return `per ${resetPeriodMin} minutes`;
|
|
2216
|
+
}
|
|
2217
|
+
function describeApprovedBudget(budget) {
|
|
2218
|
+
const token = resolveTokenFromAddress(budget.token_address);
|
|
2219
|
+
const amount = token ? `${formatAtomicAmount(BigInt(budget.amount), token.decimals)} ${budget.token_symbol}` : `${budget.amount} ${budget.token_symbol} (atomic units)`;
|
|
2220
|
+
return `${amount} ${describeResetPeriod(budget.reset_period_min)}`;
|
|
2221
|
+
}
|
|
2222
|
+
async function waitForBudgetApproval(api, setupId, apiKey, log, options = {}) {
|
|
2223
|
+
const intervalMs = options.intervalMs ?? 5e3;
|
|
2224
|
+
const timeoutMs = options.timeoutMs ?? 18e4;
|
|
2225
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
|
|
2226
|
+
const maxPolls = Math.max(1, Math.floor(timeoutMs / intervalMs));
|
|
2227
|
+
const remindEvery = Math.max(1, Math.floor(3e4 / intervalMs));
|
|
2228
|
+
log("Registered with Haven \u2014 waiting for you to approve the budget in the dashboard\u2026");
|
|
2229
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
2230
|
+
await sleep(intervalMs);
|
|
2231
|
+
let status;
|
|
2232
|
+
try {
|
|
2233
|
+
status = await api.getConnectorStatus(setupId, apiKey);
|
|
2234
|
+
} catch (err) {
|
|
2235
|
+
if (err instanceof ConnectRequestError && (err.status === 401 || err.status === 404)) {
|
|
2236
|
+
log("This setup ended in Haven \u2014 start a fresh connection from the dashboard when ready.");
|
|
2237
|
+
return "ended";
|
|
2238
|
+
}
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
if (status.status === "active") {
|
|
2242
|
+
log(
|
|
2243
|
+
status.approved_budget ? `Budget approved \u{1F389} \u2014 I can now spend up to ${describeApprovedBudget(status.approved_budget)} from your Haven wallet.` : "Budget approved \u{1F389} \u2014 the agent can now spend within its Haven rules."
|
|
2244
|
+
);
|
|
2245
|
+
return "approved";
|
|
2246
|
+
}
|
|
2247
|
+
if (status.status === "cancelled" || status.status === "expired" || status.status === "failed") {
|
|
2248
|
+
log(`This setup ended in Haven (${status.status}) \u2014 start a fresh connection from the dashboard when ready.`);
|
|
2249
|
+
return "ended";
|
|
2250
|
+
}
|
|
2251
|
+
if ((i + 1) % remindEvery === 0) {
|
|
2252
|
+
log("Still waiting for budget approval in Haven\u2026");
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
log(
|
|
2256
|
+
"Budget approval is still pending in Haven. Approve it in the dashboard whenever you are ready \u2014 the agent tools unlock the moment you do. Verify later with the read-only haven_get_agent tool."
|
|
2257
|
+
);
|
|
2258
|
+
return "pending";
|
|
2259
|
+
}
|
|
2189
2260
|
function completionHandoffLines(result) {
|
|
2190
2261
|
if (result.errorCode === "manual_runtime_setup_required") {
|
|
2191
2262
|
return [
|
|
@@ -2322,11 +2393,14 @@ async function runCli(argv, io = {
|
|
|
2322
2393
|
return 0;
|
|
2323
2394
|
}
|
|
2324
2395
|
try {
|
|
2325
|
-
const result = await runConnect(
|
|
2326
|
-
|
|
2396
|
+
const result = await runConnect(
|
|
2397
|
+
{ ...parsed.options, waitForApproval: !parsed.json },
|
|
2398
|
+
{
|
|
2399
|
+
log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
|
|
2327
2400
|
`),
|
|
2328
|
-
|
|
2329
|
-
|
|
2401
|
+
redactPaths: parsed.json
|
|
2402
|
+
}
|
|
2403
|
+
);
|
|
2330
2404
|
if (parsed.json) io.stdout(`${JSON.stringify(result.outcome)}
|
|
2331
2405
|
`);
|
|
2332
2406
|
return 0;
|
|
@@ -2345,8 +2419,16 @@ async function main() {
|
|
|
2345
2419
|
const exitCode = await runCli(process.argv.slice(2));
|
|
2346
2420
|
if (exitCode !== 0) process.exitCode = exitCode;
|
|
2347
2421
|
}
|
|
2348
|
-
|
|
2422
|
+
function isCliEntrypoint(argvPath = process.argv[1], moduleUrl = import.meta.url) {
|
|
2423
|
+
if (!argvPath) return false;
|
|
2424
|
+
try {
|
|
2425
|
+
return realpathSync(argvPath) === realpathSync(fileURLToPath(moduleUrl));
|
|
2426
|
+
} catch {
|
|
2427
|
+
return pathToFileURL(argvPath).href === moduleUrl;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
if (isCliEntrypoint()) void main();
|
|
2349
2431
|
|
|
2350
|
-
export { runCli };
|
|
2432
|
+
export { isCliEntrypoint, runCli };
|
|
2351
2433
|
//# sourceMappingURL=cli.js.map
|
|
2352
2434
|
//# sourceMappingURL=cli.js.map
|