@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/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var sdk = require('@haven_ai/sdk');
3
4
  var crypto = require('crypto');
4
5
  var ethers = require('ethers');
5
6
  var promises = require('fs/promises');
@@ -9,8 +10,8 @@ var child_process = require('child_process');
9
10
  var util = require('util');
10
11
  var yaml = require('yaml');
11
12
  var mcp = require('@haven_ai/mcp');
12
- var sdk = require('@haven_ai/sdk');
13
13
  var signer = require('@haven_ai/signer');
14
+ var fs = require('fs');
14
15
  var url = require('url');
15
16
 
16
17
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -48,6 +49,10 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
48
49
  }
49
50
  })
50
51
  }),
52
+ getConnectorStatus: (setupId, apiKey) => request(fetchImpl, `${root}/agent-connection-setups/${encodeURIComponent(setupId)}/connector-status`, {
53
+ method: "GET",
54
+ headers: { Authorization: `Bearer ${apiKey}` }
55
+ }),
51
56
  updateInstallStatus: async (setupId, apiKey, input) => {
52
57
  await request(fetchImpl, `${root}/agent-connection-setups/${encodeURIComponent(setupId)}/install-status`, {
53
58
  method: "POST",
@@ -74,6 +79,14 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
74
79
  }
75
80
  };
76
81
  }
82
+ var ConnectRequestError = class extends Error {
83
+ constructor(message, status) {
84
+ super(message);
85
+ this.status = status;
86
+ this.name = "ConnectRequestError";
87
+ }
88
+ status;
89
+ };
77
90
  async function request(fetchImpl, url, init) {
78
91
  const response = await fetchImpl(url, {
79
92
  ...init,
@@ -86,7 +99,7 @@ async function request(fetchImpl, url, init) {
86
99
  const body = text ? JSON.parse(text) : null;
87
100
  if (!response.ok) {
88
101
  const message = body?.error ?? body?.message ?? `${response.status} ${response.statusText}`;
89
- throw new Error(`Haven setup request failed: ${message}`);
102
+ throw new ConnectRequestError(`Haven setup request failed: ${message}`, response.status);
90
103
  }
91
104
  return body;
92
105
  }
@@ -239,9 +252,9 @@ var MCP_RUNTIME_MANIFEST = {
239
252
  mcpPackage: "@haven_ai/mcp",
240
253
  mcpVersion: mcp.MCP_VERSION,
241
254
  sdkPackage: "@haven_ai/sdk",
242
- sdkVersion: "0.1.23-alpha.0",
255
+ sdkVersion: "0.1.23-alpha.2",
243
256
  signerPackage: "@haven_ai/signer",
244
- signerVersion: "0.1.23-alpha.0",
257
+ signerVersion: "0.1.23-alpha.2",
245
258
  // Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
246
259
  // while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
247
260
  // so the guard that was supposed to enforce the floor waved Node v23 through
@@ -1940,7 +1953,7 @@ function localRuntimePrepareErrorCode(err) {
1940
1953
  }
1941
1954
 
1942
1955
  // src/runtime.ts
1943
- var CONNECTOR_VERSION = "0.1.23-alpha.0";
1956
+ var CONNECTOR_VERSION = "0.1.23-alpha.2";
1944
1957
  var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
1945
1958
  async function runConnect(options, deps = {}) {
1946
1959
  assertSupportedNodeVersion(deps.nodeVersion, MCP_RUNTIME_MANIFEST.minimumNodeVersion);
@@ -2054,7 +2067,6 @@ async function runConnect(options, deps = {}) {
2054
2067
  } else {
2055
2068
  log("Haven setup on this machine is complete.");
2056
2069
  }
2057
- printNextSteps(runtimeInstall, log);
2058
2070
  try {
2059
2071
  await api.updateInstallStatus(registration.setup_id, localApiKey, {
2060
2072
  runtime: runtimeInstall.runtime,
@@ -2077,6 +2089,10 @@ async function runConnect(options, deps = {}) {
2077
2089
  } catch (err) {
2078
2090
  log(`Could not report install status to Haven: ${err instanceof Error ? err.message : String(err)}`);
2079
2091
  }
2092
+ if (options.waitForApproval !== false && !runtimeInstall.errorCode) {
2093
+ await waitForBudgetApproval(api, registration.setup_id, localApiKey, log, options.approvalWait);
2094
+ }
2095
+ printNextSteps(runtimeInstall, log);
2080
2096
  return {
2081
2097
  setupId: registration.setup_id,
2082
2098
  agentId: registration.agent_id,
@@ -2192,6 +2208,61 @@ function printRuntimeInstall(result, log) {
2192
2208
  log("Local Haven signer still needs runtime setup.");
2193
2209
  }
2194
2210
  }
2211
+ function formatAtomicAmount(atomic, decimals) {
2212
+ const s = atomic.toString().padStart(decimals + 1, "0");
2213
+ const intPart = s.slice(0, s.length - decimals) || "0";
2214
+ const fracPart = s.slice(s.length - decimals).replace(/0+$/, "");
2215
+ return fracPart ? `${intPart}.${fracPart}` : intPart;
2216
+ }
2217
+ function describeResetPeriod(resetPeriodMin) {
2218
+ if (resetPeriodMin === 1440) return "per day";
2219
+ if (resetPeriodMin === 60) return "per hour";
2220
+ if (resetPeriodMin === 0) return "with no automatic reset";
2221
+ return `per ${resetPeriodMin} minutes`;
2222
+ }
2223
+ function describeApprovedBudget(budget) {
2224
+ const token = sdk.resolveTokenFromAddress(budget.token_address);
2225
+ const amount = token ? `${formatAtomicAmount(BigInt(budget.amount), token.decimals)} ${budget.token_symbol}` : `${budget.amount} ${budget.token_symbol} (atomic units)`;
2226
+ return `${amount} ${describeResetPeriod(budget.reset_period_min)}`;
2227
+ }
2228
+ async function waitForBudgetApproval(api, setupId, apiKey, log, options = {}) {
2229
+ const intervalMs = options.intervalMs ?? 5e3;
2230
+ const timeoutMs = options.timeoutMs ?? 18e4;
2231
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
2232
+ const maxPolls = Math.max(1, Math.floor(timeoutMs / intervalMs));
2233
+ const remindEvery = Math.max(1, Math.floor(3e4 / intervalMs));
2234
+ log("Registered with Haven \u2014 waiting for you to approve the budget in the dashboard\u2026");
2235
+ for (let i = 0; i < maxPolls; i++) {
2236
+ await sleep(intervalMs);
2237
+ let status;
2238
+ try {
2239
+ status = await api.getConnectorStatus(setupId, apiKey);
2240
+ } catch (err) {
2241
+ if (err instanceof ConnectRequestError && (err.status === 401 || err.status === 404)) {
2242
+ log("This setup ended in Haven \u2014 start a fresh connection from the dashboard when ready.");
2243
+ return "ended";
2244
+ }
2245
+ continue;
2246
+ }
2247
+ if (status.status === "active") {
2248
+ log(
2249
+ 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."
2250
+ );
2251
+ return "approved";
2252
+ }
2253
+ if (status.status === "cancelled" || status.status === "expired" || status.status === "failed") {
2254
+ log(`This setup ended in Haven (${status.status}) \u2014 start a fresh connection from the dashboard when ready.`);
2255
+ return "ended";
2256
+ }
2257
+ if ((i + 1) % remindEvery === 0) {
2258
+ log("Still waiting for budget approval in Haven\u2026");
2259
+ }
2260
+ }
2261
+ log(
2262
+ "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."
2263
+ );
2264
+ return "pending";
2265
+ }
2195
2266
  function completionHandoffLines(result) {
2196
2267
  if (result.errorCode === "manual_runtime_setup_required") {
2197
2268
  return [
@@ -2326,11 +2397,14 @@ async function runCli(argv, io = {
2326
2397
  return 0;
2327
2398
  }
2328
2399
  try {
2329
- const result = await runConnect(parsed.options, {
2330
- log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
2400
+ const result = await runConnect(
2401
+ { ...parsed.options, waitForApproval: !parsed.json },
2402
+ {
2403
+ log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
2331
2404
  `),
2332
- redactPaths: parsed.json
2333
- });
2405
+ redactPaths: parsed.json
2406
+ }
2407
+ );
2334
2408
  if (parsed.json) io.stdout(`${JSON.stringify(result.outcome)}
2335
2409
  `);
2336
2410
  return 0;
@@ -2349,7 +2423,15 @@ async function main() {
2349
2423
  const exitCode = await runCli(process.argv.slice(2));
2350
2424
  if (exitCode !== 0) process.exitCode = exitCode;
2351
2425
  }
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();
2426
+ function isCliEntrypoint(argvPath = process.argv[1], moduleUrl = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))) {
2427
+ if (!argvPath) return false;
2428
+ try {
2429
+ return fs.realpathSync(argvPath) === fs.realpathSync(url.fileURLToPath(moduleUrl));
2430
+ } catch {
2431
+ return url.pathToFileURL(argvPath).href === moduleUrl;
2432
+ }
2433
+ }
2434
+ if (isCliEntrypoint()) void main();
2353
2435
 
2354
2436
  exports.CONNECTOR_VERSION = CONNECTOR_VERSION;
2355
2437
  exports.CONNECT_OUTCOME_SCHEMA_VERSION = CONNECT_OUTCOME_SCHEMA_VERSION;