@haven_ai/connect 0.1.12-alpha.0 → 0.1.14-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/dist/cli.cjs CHANGED
@@ -215,9 +215,9 @@ var MCP_RUNTIME_MANIFEST = {
215
215
  mcpPackage: "@haven_ai/mcp",
216
216
  mcpVersion: mcp.MCP_VERSION,
217
217
  sdkPackage: "@haven_ai/sdk",
218
- sdkVersion: "0.1.12-alpha.0",
218
+ sdkVersion: "0.1.14-alpha.0",
219
219
  signerPackage: "@haven_ai/signer",
220
- signerVersion: "0.1.12-alpha.0",
220
+ signerVersion: "0.1.14-alpha.0",
221
221
  minimumNodeVersion: "20.0.0",
222
222
  supportedClients: ["codex-cli", "codex-desktop", "claude-code"],
223
223
  requiredTools: mcp.registeredToolNames()
@@ -390,10 +390,16 @@ function buildHostedServer(hostedMcpUrl, apiKey, runtime) {
390
390
  headers: { Authorization: `Bearer ${apiKey}` }
391
391
  };
392
392
  }
393
- function buildSignerServer(signerPath, runtime) {
394
- const server = {
393
+ function resolveSignerLaunchSpec(input) {
394
+ return input.signerCommand ?? {
395
395
  command: "npx",
396
- args: ["-y", signerPackageName(), "--credentials", signerPath]
396
+ args: ["-y", signerPackageSpec(), "--credentials", input.signerPath]
397
+ };
398
+ }
399
+ function buildSignerServer(spec, runtime) {
400
+ const server = {
401
+ command: spec.command,
402
+ args: spec.args
397
403
  };
398
404
  if (runtime === "vscode" || runtime === "vscode-insiders") return { type: "stdio", ...server };
399
405
  return server;
@@ -426,7 +432,7 @@ function mergeCodexToml(existingToml, localMcpCommand) {
426
432
  `;
427
433
  return merged;
428
434
  }
429
- function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
435
+ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerSpec) {
430
436
  let next = removeTomlTableTree(removeTomlTableTree(existingToml, "mcp_servers.haven"), "mcp_servers.haven_signer");
431
437
  next = next.trimEnd();
432
438
  const block = [
@@ -435,8 +441,8 @@ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
435
441
  `http_headers = { "Authorization" = ${tomlString(`Bearer ${apiKey}`)} }`,
436
442
  "",
437
443
  "[mcp_servers.haven_signer]",
438
- 'command = "npx"',
439
- `args = ["-y", ${tomlString(signerPackageSpec())}, "--credentials", ${tomlString(signerPath)}]`,
444
+ `command = ${tomlString(signerSpec.command)}`,
445
+ `args = [${signerSpec.args.map((arg) => tomlString(arg)).join(", ")}]`,
440
446
  "startup_timeout_sec = 120"
441
447
  ].join("\n");
442
448
  validateCodexToml(block, "Generated Codex Haven config");
@@ -453,7 +459,7 @@ async function writeJsonRuntimeConfig(input, target, serverRoot) {
453
459
  existing,
454
460
  serverRoot,
455
461
  buildHostedServer(input.hostedMcpUrl, input.apiKey, input.runtime),
456
- buildSignerServer(input.signerPath, input.runtime)
462
+ buildSignerServer(resolveSignerLaunchSpec(input), input.runtime)
457
463
  );
458
464
  await writeOwnerOnlyText(target, merged);
459
465
  return {
@@ -509,7 +515,7 @@ async function writeCodexConfig(input) {
509
515
  ]
510
516
  };
511
517
  }
512
- const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, input.signerPath);
518
+ const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, resolveSignerLaunchSpec(input));
513
519
  await writeOwnerOnlyText(target, merged);
514
520
  return {
515
521
  hostedConfigured: true,
@@ -794,9 +800,6 @@ function configTargetLabel(runtime) {
794
800
  return "runtime MCP config";
795
801
  }
796
802
  }
797
- function signerPackageName() {
798
- return signerPackageSpec();
799
- }
800
803
  async function acknowledgeLocalMcpConsent(identityPath, signerPath, log) {
801
804
  try {
802
805
  const input = await buildLocalMcpConsentInput(identityPath, signerPath);
@@ -910,7 +913,7 @@ async function probeLocalSignerCredential(signerPath) {
910
913
  }
911
914
  }
912
915
  async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4) {
913
- return new Promise((resolve7) => {
916
+ return new Promise((resolve8) => {
914
917
  const child = child_process.spawn(command, args, { stdio: ["pipe", "pipe", "ignore"] });
915
918
  let stdout = "";
916
919
  let settled = false;
@@ -920,7 +923,7 @@ async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4)
920
923
  settled = true;
921
924
  clearTimeout(timeout);
922
925
  child.kill();
923
- resolve7(result);
926
+ resolve8(result);
924
927
  };
925
928
  const timeout = setTimeout(() => finish({ status: "timeout" }), timeoutMs);
926
929
  child.on("error", () => finish({ status: "process_error" }));
@@ -1158,6 +1161,126 @@ async function assertFileExists(path, label) {
1158
1161
  throw new Error(`Missing ${label}: ${path}`);
1159
1162
  }
1160
1163
  }
1164
+ var execFileAsync2 = util.promisify(child_process.execFile);
1165
+ async function prepareSignerRuntime(input, deps = {}) {
1166
+ const homeDir = input.homeDir ?? os.homedir();
1167
+ const runtimeDirectory = path.resolve(homeDir, ".haven", "signer-runtime", MCP_RUNTIME_MANIFEST.signerVersion);
1168
+ const npmCacheDirectory = path.resolve(homeDir, ".haven", "npm-cache");
1169
+ const cliPath = path.join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "dist", "cli.js");
1170
+ const messages = [];
1171
+ await promises.mkdir(runtimeDirectory, { recursive: true, mode: 448 });
1172
+ await promises.chmod(runtimeDirectory, 448).catch(() => void 0);
1173
+ await promises.mkdir(npmCacheDirectory, { recursive: true, mode: 448 });
1174
+ await promises.chmod(npmCacheDirectory, 448).catch(() => void 0);
1175
+ if (await installedRuntimeMatches2(runtimeDirectory, cliPath)) {
1176
+ messages.push(`Using existing local Haven signer runtime ${signerPackageSpec()}.`);
1177
+ } else {
1178
+ await installRuntimePackages2(runtimeDirectory, npmCacheDirectory, deps.runCommand);
1179
+ messages.push(`Installed local Haven signer runtime ${signerPackageSpec()}.`);
1180
+ }
1181
+ await assertFileExists2(cliPath, "local Haven signer CLI");
1182
+ const wrapperPath = path.join(input.credentialDirectory, "bin", "haven-signer.mjs");
1183
+ await writeWrapper2({ wrapperPath, cliPath, signerPath: input.signerPath });
1184
+ await writeRuntimeSidecar2({
1185
+ path: path.join(input.credentialDirectory, "signer-runtime.json"),
1186
+ wrapperPath,
1187
+ runtimeDirectory,
1188
+ npmCacheDirectory,
1189
+ cliPath
1190
+ });
1191
+ messages.push(`Prepared stable local Haven signer wrapper: ${wrapperPath}`);
1192
+ return {
1193
+ command: wrapperPath,
1194
+ args: [],
1195
+ wrapperPath,
1196
+ runtimeDirectory,
1197
+ npmCacheDirectory,
1198
+ cliPath,
1199
+ messages
1200
+ };
1201
+ }
1202
+ async function installRuntimePackages2(runtimeDirectory, npmCacheDirectory, runCommand) {
1203
+ const args = [
1204
+ "install",
1205
+ "--prefix",
1206
+ runtimeDirectory,
1207
+ "--cache",
1208
+ npmCacheDirectory,
1209
+ "--no-audit",
1210
+ "--no-fund",
1211
+ "--omit=dev",
1212
+ signerPackageSpec(),
1213
+ sdkPackageSpec()
1214
+ ];
1215
+ try {
1216
+ if (runCommand) await runCommand("npm", args);
1217
+ else await execFileAsync2("npm", args, { timeout: 12e4, maxBuffer: 1024 * 1024 });
1218
+ } catch (err) {
1219
+ throw new Error(
1220
+ `Could not install local Haven signer runtime ${signerPackageSpec()}: ${err instanceof Error ? err.message : String(err)}`
1221
+ );
1222
+ }
1223
+ }
1224
+ async function installedRuntimeMatches2(runtimeDirectory, cliPath) {
1225
+ try {
1226
+ await assertFileExists2(cliPath, "local Haven signer CLI");
1227
+ const [signerPackage, sdkPackage] = await Promise.all([
1228
+ readPackageJson2(path.join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "package.json")),
1229
+ readPackageJson2(path.join(runtimeDirectory, "node_modules", "@haven_ai", "sdk", "package.json"))
1230
+ ]);
1231
+ return signerPackage.version === MCP_RUNTIME_MANIFEST.signerVersion && sdkPackage.version === MCP_RUNTIME_MANIFEST.sdkVersion;
1232
+ } catch {
1233
+ return false;
1234
+ }
1235
+ }
1236
+ async function readPackageJson2(path) {
1237
+ return JSON.parse(await promises.readFile(path, "utf8"));
1238
+ }
1239
+ async function writeWrapper2(input) {
1240
+ await promises.mkdir(path.dirname(input.wrapperPath), { recursive: true, mode: 448 });
1241
+ await promises.chmod(path.dirname(input.wrapperPath), 448).catch(() => void 0);
1242
+ const source = [
1243
+ "#!/usr/bin/env node",
1244
+ "import { spawn } from 'node:child_process'",
1245
+ "",
1246
+ `const cliPath = ${JSON.stringify(input.cliPath)}`,
1247
+ `const signerPath = ${JSON.stringify(input.signerPath)}`,
1248
+ "",
1249
+ "const child = spawn(process.execPath, [cliPath, '--credentials', signerPath, ...process.argv.slice(2)], {",
1250
+ " stdio: 'inherit',",
1251
+ "})",
1252
+ "",
1253
+ "child.on('exit', (code, signal) => {",
1254
+ " if (signal) process.kill(process.pid, signal)",
1255
+ " else process.exit(code ?? 1)",
1256
+ "})",
1257
+ ""
1258
+ ].join("\n");
1259
+ await promises.writeFile(input.wrapperPath, source, { mode: 448 });
1260
+ await promises.chmod(input.wrapperPath, 448).catch(() => void 0);
1261
+ }
1262
+ async function writeRuntimeSidecar2(input) {
1263
+ const value = {
1264
+ signer_package: MCP_RUNTIME_MANIFEST.signerPackage,
1265
+ signer_version: MCP_RUNTIME_MANIFEST.signerVersion,
1266
+ sdk_package: MCP_RUNTIME_MANIFEST.sdkPackage,
1267
+ sdk_version: MCP_RUNTIME_MANIFEST.sdkVersion,
1268
+ wrapper_path: input.wrapperPath,
1269
+ runtime_directory: input.runtimeDirectory,
1270
+ npm_cache_directory: input.npmCacheDirectory,
1271
+ cli_path: input.cliPath
1272
+ };
1273
+ await promises.writeFile(input.path, `${JSON.stringify(value, null, 2)}
1274
+ `, { mode: 384 });
1275
+ await promises.chmod(input.path, 384).catch(() => void 0);
1276
+ }
1277
+ async function assertFileExists2(path, label) {
1278
+ try {
1279
+ await promises.access(path);
1280
+ } catch {
1281
+ throw new Error(`Missing ${label}: ${path}`);
1282
+ }
1283
+ }
1161
1284
  async function acknowledgeLocalSignerConsent(signerPath, log) {
1162
1285
  try {
1163
1286
  const input = await buildSignerConsentInput(signerPath);
@@ -1229,7 +1352,7 @@ function writeLogChunk2(log, chunk) {
1229
1352
  }
1230
1353
 
1231
1354
  // src/runtime-install.ts
1232
- var execFileAsync2 = util.promisify(child_process.execFile);
1355
+ var execFileAsync3 = util.promisify(child_process.execFile);
1233
1356
  async function installRuntime(input, deps = {}) {
1234
1357
  const runtime = normalizeRuntime(input.runtime, deps.env);
1235
1358
  const profile = runtimeProfile(runtime, deps.env);
@@ -1290,7 +1413,20 @@ async function installRuntime(input, deps = {}) {
1290
1413
  ]
1291
1414
  };
1292
1415
  }
1293
- const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input) : await writeRuntimeConfig({
1416
+ let signerCommand;
1417
+ if (!localRuntime) {
1418
+ try {
1419
+ const signerRuntime = await prepareSignerForRuntime(input, deps);
1420
+ signerCommand = { command: signerRuntime.command, args: signerRuntime.args };
1421
+ consentMessages.push(...signerRuntime.messages);
1422
+ } catch (err) {
1423
+ consentMessages.push(
1424
+ `Could not pre-install the local Haven signer; falling back to npx launch: ${err instanceof Error ? err.message : String(err)}`
1425
+ );
1426
+ }
1427
+ }
1428
+ const signerRuntimePrepared = localRuntime ? void 0 : signerCommand !== void 0;
1429
+ const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input, signerCommand) : await writeRuntimeConfig({
1294
1430
  runtime,
1295
1431
  hostedMcpUrl: input.hostedMcpUrl,
1296
1432
  apiKey: input.apiKey,
@@ -1298,6 +1434,7 @@ async function installRuntime(input, deps = {}) {
1298
1434
  signerPath: input.signerPath,
1299
1435
  credentialDirectory: input.credentialDirectory,
1300
1436
  localMcpCommand: localRuntimeInstall?.command,
1437
+ signerCommand,
1301
1438
  homeDir: deps.homeDir,
1302
1439
  mode: localRuntime ? "local" : "hosted"
1303
1440
  });
@@ -1329,6 +1466,7 @@ async function installRuntime(input, deps = {}) {
1329
1466
  localMcpAcknowledged: localMcpConsent?.acknowledged,
1330
1467
  activationCommand: configResult.activationCommand,
1331
1468
  skillInstalled: skillInstall?.installed,
1469
+ signerRuntimePrepared,
1332
1470
  messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
1333
1471
  };
1334
1472
  }
@@ -1385,7 +1523,7 @@ async function configureClaudeCode(deps, localMcpCommand) {
1385
1523
  };
1386
1524
  }
1387
1525
  }
1388
- async function configureClaudeCodeHosted(deps, input) {
1526
+ async function configureClaudeCodeHosted(deps, input, signerCommand) {
1389
1527
  const runCommand = deps.runCommand ?? defaultRunCommand;
1390
1528
  const hostedJson = JSON.stringify({
1391
1529
  type: "http",
@@ -1394,8 +1532,8 @@ async function configureClaudeCodeHosted(deps, input) {
1394
1532
  });
1395
1533
  const signerJson = JSON.stringify({
1396
1534
  type: "stdio",
1397
- command: "npx",
1398
- args: ["-y", signerPackageSpec(), "--credentials", input.signerPath],
1535
+ command: signerCommand?.command ?? "npx",
1536
+ args: signerCommand?.args ?? ["-y", signerPackageSpec(), "--credentials", input.signerPath],
1399
1537
  env: {}
1400
1538
  });
1401
1539
  try {
@@ -1436,7 +1574,7 @@ async function configureClaudeCodeHosted(deps, input) {
1436
1574
  }
1437
1575
  }
1438
1576
  async function defaultRunCommand(command, args) {
1439
- await execFileAsync2(command, args, { timeout: 1e4 });
1577
+ await execFileAsync3(command, args, { timeout: 1e4 });
1440
1578
  }
1441
1579
  async function installClaudeSkill(homeDir) {
1442
1580
  try {
@@ -1519,6 +1657,14 @@ async function prepareRuntimeForLocalMcp(input, deps) {
1519
1657
  homeDir: deps.homeDir
1520
1658
  });
1521
1659
  }
1660
+ async function prepareSignerForRuntime(input, deps) {
1661
+ const prepare = deps.prepareSignerRuntime ?? ((runtimeInput) => prepareSignerRuntime(runtimeInput, { runCommand: deps.runCommand }));
1662
+ return prepare({
1663
+ credentialDirectory: input.credentialDirectory,
1664
+ signerPath: input.signerPath,
1665
+ homeDir: deps.homeDir
1666
+ });
1667
+ }
1522
1668
  async function runLocalMcpProbe(runtimeInstall, deps) {
1523
1669
  const probe = deps.probeLocalMcpTools ?? probeLocalMcpTools;
1524
1670
  try {
@@ -1535,7 +1681,7 @@ function localRuntimePrepareErrorCode(err) {
1535
1681
  }
1536
1682
 
1537
1683
  // src/runtime.ts
1538
- var CONNECTOR_VERSION = "0.1.12-alpha.0";
1684
+ var CONNECTOR_VERSION = "0.1.14-alpha.0";
1539
1685
  async function runConnect(options, deps = {}) {
1540
1686
  const connectorVersion = options.connectorVersion ?? CONNECTOR_VERSION;
1541
1687
  const api = deps.api ?? createConnectApiClient(options.apiBaseUrl);