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