@haven_ai/connect 0.1.6-alpha → 0.1.10-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/index.d.cts CHANGED
@@ -31,6 +31,7 @@ interface UpdateInstallStatusInput {
31
31
  signerAcknowledged?: boolean;
32
32
  localMcpAcknowledged?: boolean;
33
33
  activationCommandAvailable?: boolean;
34
+ skillInstalled?: boolean;
34
35
  probeResult: string;
35
36
  restartRequired: boolean;
36
37
  nextUserAction: string;
@@ -167,6 +168,12 @@ interface RuntimeInstallInput {
167
168
  environmentLabel?: string;
168
169
  ackSigner?: boolean;
169
170
  ackLocalTools?: boolean;
171
+ /**
172
+ * Explicit opt-in to the local-stdio MCP topology (zero hosted dependency).
173
+ * Default is hosted MCP + local signer for every runtime; local MCP is only
174
+ * used when this is true and the runtime supports it.
175
+ */
176
+ localMcp?: boolean;
170
177
  }
171
178
  interface RuntimeInstallResult {
172
179
  runtime: RuntimeId;
@@ -183,6 +190,7 @@ interface RuntimeInstallResult {
183
190
  signerAcknowledged?: boolean;
184
191
  localMcpAcknowledged?: boolean;
185
192
  activationCommand?: string;
193
+ skillInstalled?: boolean;
186
194
  messages: string[];
187
195
  }
188
196
  interface RuntimeInstallDeps {
@@ -209,6 +217,7 @@ interface ConnectOptions {
209
217
  connectorVersion?: string;
210
218
  ackSigner?: boolean;
211
219
  ackLocalTools?: boolean;
220
+ localMcp?: boolean;
212
221
  }
213
222
  interface ConnectDeps {
214
223
  api?: ConnectApiClient;
@@ -237,4 +246,19 @@ declare function helpText(): string;
237
246
  declare function redactSecrets(value: string): string;
238
247
  declare function shortAddress(address: string): string;
239
248
 
240
- export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, type RegisterSetupInput, type RegisterSetupResponse, type ResolveSetupInput, type ResolvedSetup, type RuntimeId, type RuntimeInstallInput, type RuntimeInstallResult, type RuntimeProfile, type StoredCredentialPaths, type UpdateInstallStatusInput, type WriteCredentialInput, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, shortAddress, writeCredentialFiles };
249
+ declare const MCP_RUNTIME_MANIFEST: {
250
+ readonly mcpPackage: "@haven_ai/mcp";
251
+ readonly mcpVersion: "0.1.10-alpha.0";
252
+ readonly sdkPackage: "@haven_ai/sdk";
253
+ readonly sdkVersion: "0.1.10-alpha.0";
254
+ readonly signerPackage: "@haven_ai/signer";
255
+ readonly signerVersion: "0.1.10-alpha.0";
256
+ readonly minimumNodeVersion: "20.0.0";
257
+ readonly supportedClients: readonly ["codex-cli", "codex-desktop", "claude-code"];
258
+ readonly requiredTools: readonly string[];
259
+ };
260
+ declare function mcpPackageSpec(): string;
261
+ declare function sdkPackageSpec(): string;
262
+ declare function signerPackageSpec(): string;
263
+
264
+ export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, MCP_RUNTIME_MANIFEST, type RegisterSetupInput, type RegisterSetupResponse, type ResolveSetupInput, type ResolvedSetup, type RuntimeId, type RuntimeInstallInput, type RuntimeInstallResult, type RuntimeProfile, type StoredCredentialPaths, type UpdateInstallStatusInput, type WriteCredentialInput, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ interface UpdateInstallStatusInput {
31
31
  signerAcknowledged?: boolean;
32
32
  localMcpAcknowledged?: boolean;
33
33
  activationCommandAvailable?: boolean;
34
+ skillInstalled?: boolean;
34
35
  probeResult: string;
35
36
  restartRequired: boolean;
36
37
  nextUserAction: string;
@@ -167,6 +168,12 @@ interface RuntimeInstallInput {
167
168
  environmentLabel?: string;
168
169
  ackSigner?: boolean;
169
170
  ackLocalTools?: boolean;
171
+ /**
172
+ * Explicit opt-in to the local-stdio MCP topology (zero hosted dependency).
173
+ * Default is hosted MCP + local signer for every runtime; local MCP is only
174
+ * used when this is true and the runtime supports it.
175
+ */
176
+ localMcp?: boolean;
170
177
  }
171
178
  interface RuntimeInstallResult {
172
179
  runtime: RuntimeId;
@@ -183,6 +190,7 @@ interface RuntimeInstallResult {
183
190
  signerAcknowledged?: boolean;
184
191
  localMcpAcknowledged?: boolean;
185
192
  activationCommand?: string;
193
+ skillInstalled?: boolean;
186
194
  messages: string[];
187
195
  }
188
196
  interface RuntimeInstallDeps {
@@ -209,6 +217,7 @@ interface ConnectOptions {
209
217
  connectorVersion?: string;
210
218
  ackSigner?: boolean;
211
219
  ackLocalTools?: boolean;
220
+ localMcp?: boolean;
212
221
  }
213
222
  interface ConnectDeps {
214
223
  api?: ConnectApiClient;
@@ -237,4 +246,19 @@ declare function helpText(): string;
237
246
  declare function redactSecrets(value: string): string;
238
247
  declare function shortAddress(address: string): string;
239
248
 
240
- export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, type RegisterSetupInput, type RegisterSetupResponse, type ResolveSetupInput, type ResolvedSetup, type RuntimeId, type RuntimeInstallInput, type RuntimeInstallResult, type RuntimeProfile, type StoredCredentialPaths, type UpdateInstallStatusInput, type WriteCredentialInput, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, shortAddress, writeCredentialFiles };
249
+ declare const MCP_RUNTIME_MANIFEST: {
250
+ readonly mcpPackage: "@haven_ai/mcp";
251
+ readonly mcpVersion: "0.1.10-alpha.0";
252
+ readonly sdkPackage: "@haven_ai/sdk";
253
+ readonly sdkVersion: "0.1.10-alpha.0";
254
+ readonly signerPackage: "@haven_ai/signer";
255
+ readonly signerVersion: "0.1.10-alpha.0";
256
+ readonly minimumNodeVersion: "20.0.0";
257
+ readonly supportedClients: readonly ["codex-cli", "codex-desktop", "claude-code"];
258
+ readonly requiredTools: readonly string[];
259
+ };
260
+ declare function mcpPackageSpec(): string;
261
+ declare function sdkPackageSpec(): string;
262
+ declare function signerPackageSpec(): string;
263
+
264
+ export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, MCP_RUNTIME_MANIFEST, type RegisterSetupInput, type RegisterSetupResponse, type ResolveSetupInput, type ResolvedSetup, type RuntimeId, type RuntimeInstallInput, type RuntimeInstallResult, type RuntimeProfile, type StoredCredentialPaths, type UpdateInstallStatusInput, type WriteCredentialInput, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { join, resolve, dirname } from 'path';
6
6
  import { execFile, spawn } from 'child_process';
7
7
  import { promisify } from 'util';
8
8
  import { registeredToolNames, MCP_VERSION, ensureConsent, computeConsentHash, loadCredentials, consentInputFromClient } from '@haven_ai/mcp';
9
+ import { SKILL_FOLDER_NAME, HAVEN_SKILL_MD } from '@haven_ai/sdk';
9
10
  import { ensureSignerConsent, computeSignerConsentHash, loadSignerCredentials, createEdgeSigner, toolSchemas } from '@haven_ai/signer';
10
11
 
11
12
  // src/api.ts
@@ -53,6 +54,7 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
53
54
  signer_acknowledged: input.signerAcknowledged,
54
55
  local_mcp_acknowledged: input.localMcpAcknowledged,
55
56
  activation_command_available: input.activationCommandAvailable,
57
+ skill_installed: input.skillInstalled,
56
58
  probe_result: input.probeResult,
57
59
  restart_required: input.restartRequired,
58
60
  next_user_action: input.nextUserAction,
@@ -205,9 +207,9 @@ var MCP_RUNTIME_MANIFEST = {
205
207
  mcpPackage: "@haven_ai/mcp",
206
208
  mcpVersion: MCP_VERSION,
207
209
  sdkPackage: "@haven_ai/sdk",
208
- sdkVersion: "0.1.9",
210
+ sdkVersion: "0.1.10-alpha.0",
209
211
  signerPackage: "@haven_ai/signer",
210
- signerVersion: "0.1.3-alpha",
212
+ signerVersion: "0.1.10-alpha.0",
211
213
  minimumNodeVersion: "20.0.0",
212
214
  supportedClients: ["codex-cli", "codex-desktop", "claude-code"],
213
215
  requiredTools: registeredToolNames()
@@ -412,6 +414,26 @@ function mergeCodexToml(existingToml, localMcpCommand) {
412
414
  validateCodexToml(block, "Generated Codex Haven config");
413
415
  const merged = `${next ? `${next}
414
416
 
417
+ ` : ""}${block}
418
+ `;
419
+ return merged;
420
+ }
421
+ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
422
+ let next = removeTomlTableTree(removeTomlTableTree(existingToml, "mcp_servers.haven"), "mcp_servers.haven_signer");
423
+ next = next.trimEnd();
424
+ const block = [
425
+ "[mcp_servers.haven]",
426
+ `url = ${tomlString(hostedMcpUrl)}`,
427
+ `http_headers = { "Authorization" = ${tomlString(`Bearer ${apiKey}`)} }`,
428
+ "",
429
+ "[mcp_servers.haven_signer]",
430
+ 'command = "npx"',
431
+ `args = ["-y", ${tomlString(signerPackageSpec())}, "--credentials", ${tomlString(signerPath)}]`,
432
+ "startup_timeout_sec = 120"
433
+ ].join("\n");
434
+ validateCodexToml(block, "Generated Codex Haven config");
435
+ const merged = `${next ? `${next}
436
+
415
437
  ` : ""}${block}
416
438
  `;
417
439
  return merged;
@@ -452,27 +474,46 @@ async function writeJsonRuntimeConfig(input, target, serverRoot) {
452
474
  }
453
475
  async function writeCodexConfig(input) {
454
476
  const target = codexConfigPath(input.homeDir);
477
+ const local = input.mode === "local";
478
+ const restartMessage = runtimeRequiresHardRestart(input.runtime) ? "After Haven approval, restart Codex Desktop so it can load Haven tools." : "After Haven approval, Haven tools should appear in your next Codex message. If they don't, restart Codex to load them.";
455
479
  try {
456
480
  const existing = await readOptional(target);
457
- if (!input.localMcpCommand) {
458
- throw new Error("local MCP wrapper command is required");
481
+ if (local) {
482
+ if (!input.localMcpCommand) {
483
+ throw new Error("local MCP wrapper command is required");
484
+ }
485
+ const merged2 = mergeCodexToml(existing ?? "", input.localMcpCommand);
486
+ await writeOwnerOnlyText(target, merged2);
487
+ return {
488
+ hostedConfigured: false,
489
+ signerConfigured: true,
490
+ localMcpConfigured: true,
491
+ runtimeMcpMode: "local_stdio",
492
+ target: configTargetLabel(input.runtime),
493
+ changed: existing !== merged2,
494
+ restartRequired: true,
495
+ messages: [
496
+ `Updated local Haven MCP entry in ${configTargetLabel(input.runtime)}.`,
497
+ // Codex Desktop loads MCP servers at app launch; Codex CLI typically
498
+ // picks them up in the next session. Branch the copy so desktop users
499
+ // get the unambiguous instruction.
500
+ restartMessage
501
+ ]
502
+ };
459
503
  }
460
- const merged = mergeCodexToml(existing ?? "", input.localMcpCommand);
504
+ const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, input.signerPath);
461
505
  await writeOwnerOnlyText(target, merged);
462
506
  return {
463
- hostedConfigured: false,
507
+ hostedConfigured: true,
464
508
  signerConfigured: true,
465
- localMcpConfigured: true,
466
- runtimeMcpMode: "local_stdio",
509
+ localMcpConfigured: false,
510
+ runtimeMcpMode: "hosted_plus_signer",
467
511
  target: configTargetLabel(input.runtime),
468
512
  changed: existing !== merged,
469
513
  restartRequired: true,
470
514
  messages: [
471
- `Updated local Haven MCP entry in ${configTargetLabel(input.runtime)}.`,
472
- // Codex Desktop loads MCP servers at app launch; Codex CLI typically
473
- // picks them up in the next session. Branch the copy so desktop users
474
- // get the unambiguous instruction.
475
- runtimeRequiresHardRestart(input.runtime) ? "After Haven approval, restart Codex Desktop so it can load Haven tools." : "After Haven approval, Haven tools should appear in your next Codex message. If they don't, restart Codex to load them."
515
+ `Updated Haven MCP entries in ${configTargetLabel(input.runtime)}.`,
516
+ restartMessage
476
517
  ]
477
518
  };
478
519
  } catch (err) {
@@ -481,7 +522,7 @@ async function writeCodexConfig(input) {
481
522
  hostedConfigured: false,
482
523
  signerConfigured: false,
483
524
  localMcpConfigured: false,
484
- runtimeMcpMode: "local_stdio",
525
+ runtimeMcpMode: local ? "local_stdio" : "hosted_plus_signer",
485
526
  target: configTargetLabel(input.runtime),
486
527
  changed: false,
487
528
  restartRequired: true,
@@ -861,7 +902,7 @@ async function probeLocalSignerCredential(signerPath) {
861
902
  }
862
903
  }
863
904
  async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4) {
864
- return new Promise((resolve6) => {
905
+ return new Promise((resolve7) => {
865
906
  const child = spawn(command, args, { stdio: ["pipe", "pipe", "ignore"] });
866
907
  let stdout = "";
867
908
  let settled = false;
@@ -871,7 +912,7 @@ async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4)
871
912
  settled = true;
872
913
  clearTimeout(timeout);
873
914
  child.kill();
874
- resolve6(result);
915
+ resolve7(result);
875
916
  };
876
917
  const timeout = setTimeout(() => finish({ status: "timeout" }), timeoutMs);
877
918
  child.on("error", () => finish({ status: "process_error" }));
@@ -1184,7 +1225,7 @@ var execFileAsync2 = promisify(execFile);
1184
1225
  async function installRuntime(input, deps = {}) {
1185
1226
  const runtime = normalizeRuntime(input.runtime, deps.env);
1186
1227
  const profile = runtimeProfile(runtime, deps.env);
1187
- const localRuntime = usesLocalMcp(runtime);
1228
+ const localRuntime = input.localMcp === true && supportsLocalMcp(runtime);
1188
1229
  const consentMessages = [];
1189
1230
  const localMcpConsent = localRuntime ? await resolveLocalMcpConsent(input, consentMessages) : void 0;
1190
1231
  const signerConsent = localRuntime ? void 0 : await resolveSignerConsent(input, consentMessages);
@@ -1241,7 +1282,7 @@ async function installRuntime(input, deps = {}) {
1241
1282
  ]
1242
1283
  };
1243
1284
  }
1244
- const configResult = runtime === "claude-code" ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await writeRuntimeConfig({
1285
+ const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input) : await writeRuntimeConfig({
1245
1286
  runtime,
1246
1287
  hostedMcpUrl: input.hostedMcpUrl,
1247
1288
  apiKey: input.apiKey,
@@ -1249,7 +1290,8 @@ async function installRuntime(input, deps = {}) {
1249
1290
  signerPath: input.signerPath,
1250
1291
  credentialDirectory: input.credentialDirectory,
1251
1292
  localMcpCommand: localRuntimeInstall?.command,
1252
- homeDir: deps.homeDir
1293
+ homeDir: deps.homeDir,
1294
+ mode: localRuntime ? "local" : "hosted"
1253
1295
  });
1254
1296
  const localProbePromise = configResult.runtimeMcpMode === "local_stdio" && localRuntimeInstall ? runLocalMcpProbe(localRuntimeInstall, deps) : Promise.resolve(void 0);
1255
1297
  const [hostedProbe, signerCredentialReady, localMcpProbe] = await Promise.all([
@@ -1263,6 +1305,7 @@ async function installRuntime(input, deps = {}) {
1263
1305
  const restartRequired = configResult.restartRequired || restartRequiredForRuntime(runtime, deps.env);
1264
1306
  const errorCode = configResult.errorCode ?? (configResult.runtimeMcpMode === "local_stdio" ? localMcpErrorCode(signerCredentialReady, localMcpConsent, localMcpProbe?.status) : signerConsentErrorCode(signerCredentialReady, signerConsent));
1265
1307
  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."] : [];
1308
+ const skillInstall = runtime === "claude-code" && !configResult.errorCode ? await installClaudeSkill(deps.homeDir) : void 0;
1266
1309
  return {
1267
1310
  runtime,
1268
1311
  runtimeMcpMode: configResult.runtimeMcpMode,
@@ -1277,7 +1320,8 @@ async function installRuntime(input, deps = {}) {
1277
1320
  signerAcknowledged: signerConsent?.acknowledged,
1278
1321
  localMcpAcknowledged: localMcpConsent?.acknowledged,
1279
1322
  activationCommand: configResult.activationCommand,
1280
- messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages]
1323
+ skillInstalled: skillInstall?.installed,
1324
+ messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
1281
1325
  };
1282
1326
  }
1283
1327
  function runtimeInstallCapabilities(runtime, env = process.env) {
@@ -1333,9 +1377,75 @@ async function configureClaudeCode(deps, localMcpCommand) {
1333
1377
  };
1334
1378
  }
1335
1379
  }
1380
+ async function configureClaudeCodeHosted(deps, input) {
1381
+ const runCommand = deps.runCommand ?? defaultRunCommand;
1382
+ const hostedJson = JSON.stringify({
1383
+ type: "http",
1384
+ url: input.hostedMcpUrl,
1385
+ headers: { Authorization: `Bearer ${input.apiKey}` }
1386
+ });
1387
+ const signerJson = JSON.stringify({
1388
+ type: "stdio",
1389
+ command: "npx",
1390
+ args: ["-y", signerPackageSpec(), "--credentials", input.signerPath],
1391
+ env: {}
1392
+ });
1393
+ try {
1394
+ await runCommand("claude", ["mcp", "remove", "haven"]).catch(() => void 0);
1395
+ await runCommand("claude", ["mcp", "remove", "haven-signer"]).catch(() => void 0);
1396
+ await runCommand("claude", ["mcp", "add-json", "haven", hostedJson, "--scope", "user"]);
1397
+ await runCommand("claude", ["mcp", "add-json", "haven-signer", signerJson, "--scope", "user"]);
1398
+ const verified = await runCommand("claude", ["mcp", "get", "haven"]).then(() => true).catch(() => false);
1399
+ return {
1400
+ hostedConfigured: true,
1401
+ signerConfigured: true,
1402
+ localMcpConfigured: false,
1403
+ runtimeMcpMode: "hosted_plus_signer",
1404
+ target: "Claude Code MCP config",
1405
+ changed: true,
1406
+ restartRequired: true,
1407
+ messages: [
1408
+ "Updated hosted Haven MCP and local signer entries with Claude Code.",
1409
+ ...verified ? ["Verified Claude Code MCP entry."] : [],
1410
+ "After Haven approval, Haven tools should appear in your next Claude Code message. If they don't, restart the session to load them."
1411
+ ]
1412
+ };
1413
+ } catch (err) {
1414
+ return {
1415
+ hostedConfigured: false,
1416
+ signerConfigured: false,
1417
+ localMcpConfigured: false,
1418
+ runtimeMcpMode: "hosted_plus_signer",
1419
+ target: "Claude Code MCP config",
1420
+ changed: false,
1421
+ restartRequired: true,
1422
+ messages: [
1423
+ `Could not update Claude Code MCP config: ${err instanceof Error ? err.message : String(err)}`,
1424
+ "Install Claude Code or rerun the Haven setup command inside a Claude Code terminal."
1425
+ ],
1426
+ errorCode: "claude_code_config_failed"
1427
+ };
1428
+ }
1429
+ }
1336
1430
  async function defaultRunCommand(command, args) {
1337
1431
  await execFileAsync2(command, args, { timeout: 1e4 });
1338
1432
  }
1433
+ async function installClaudeSkill(homeDir) {
1434
+ try {
1435
+ const skillDir = resolve(homeDir ?? homedir(), ".claude", "skills", SKILL_FOLDER_NAME);
1436
+ await mkdir(skillDir, { recursive: true });
1437
+ await writeFile(join(skillDir, "SKILL.md"), HAVEN_SKILL_MD, "utf8");
1438
+ return {
1439
+ installed: true,
1440
+ messages: ["Installed the generic Haven payment skill (~/.claude/skills/haven-pay). It contains no secrets."]
1441
+ };
1442
+ } catch (err) {
1443
+ return {
1444
+ installed: false,
1445
+ messages: [`Could not install the Haven payment skill: ${err instanceof Error ? err.message : String(err)}. Download it from the Haven dashboard instead.`]
1446
+ };
1447
+ }
1448
+ }
1339
1449
  function buildProbeResult(mode, hostedConfigured, hostedStatus, signerReady, localMcpReady, localMcpProbeStatus) {
1340
1450
  if (mode === "local_stdio") {
1341
1451
  if (localMcpReady) return "local_stdio_mcp_ready";
@@ -1389,7 +1499,7 @@ function nextAction(runtime, restartMode, errorCode) {
1389
1499
  if (restartMode === "restart-session") return "return_to_haven_for_wallet_approval_then_restart_agent_session";
1390
1500
  return "return_to_haven_for_wallet_approval_then_configure_runtime";
1391
1501
  }
1392
- function usesLocalMcp(runtime) {
1502
+ function supportsLocalMcp(runtime) {
1393
1503
  return runtime === "codex-cli" || runtime === "codex-desktop" || runtime === "claude-code";
1394
1504
  }
1395
1505
  async function prepareRuntimeForLocalMcp(input, deps) {
@@ -1429,6 +1539,14 @@ async function runConnect(options, deps = {}) {
1429
1539
  const generateKey = deps.generateKey ?? generateDelegateKey;
1430
1540
  const generateLocalApiKey = deps.generateApiKey ?? generateAgentApiKey;
1431
1541
  const installCapabilities = runtimeInstallCapabilities(options.runtime);
1542
+ if (options.localMcp) {
1543
+ const resolvedRuntime = normalizeRuntime(options.runtime);
1544
+ if (!supportsLocalMcp(resolvedRuntime)) {
1545
+ throw new Error(
1546
+ `--local (fully-local Haven MCP) is only available for Claude Code and Codex. The detected runtime is ${runtimeProfile(resolvedRuntime).label}. Re-run without --local to use the default hosted MCP + local signer setup.`
1547
+ );
1548
+ }
1549
+ }
1432
1550
  const setup = await api.resolveSetup({
1433
1551
  setupToken: options.setupToken,
1434
1552
  connectorVersion,
@@ -1487,7 +1605,8 @@ async function runConnect(options, deps = {}) {
1487
1605
  credentialDirectory: credentialPaths.directory,
1488
1606
  environmentLabel: options.environmentLabel ?? "Local workspace",
1489
1607
  ackSigner: options.ackSigner,
1490
- ackLocalTools: options.ackLocalTools
1608
+ ackLocalTools: options.ackLocalTools,
1609
+ localMcp: options.localMcp
1491
1610
  });
1492
1611
  printRuntimeInstall(runtimeInstall, log);
1493
1612
  try {
@@ -1502,6 +1621,7 @@ async function runConnect(options, deps = {}) {
1502
1621
  signerAcknowledged: runtimeInstall.signerAcknowledged,
1503
1622
  localMcpAcknowledged: runtimeInstall.localMcpAcknowledged,
1504
1623
  activationCommandAvailable: Boolean(runtimeInstall.activationCommand),
1624
+ skillInstalled: runtimeInstall.skillInstalled,
1505
1625
  probeResult: runtimeInstall.probeResult,
1506
1626
  restartRequired: runtimeInstall.restartRequired,
1507
1627
  nextUserAction: runtimeInstall.nextUserAction,
@@ -1583,6 +1703,8 @@ function parseArgs(argv, env = process.env) {
1583
1703
  } else if (arg === "--ack-signer") {
1584
1704
  options.ackSigner = true;
1585
1705
  options.ackLocalTools = true;
1706
+ } else if (arg === "--local" || arg === "--local-mcp") {
1707
+ options.localMcp = true;
1586
1708
  } else if (arg === "--version") {
1587
1709
  process.stdout.write(`${CONNECTOR_VERSION}
1588
1710
  `);
@@ -1621,6 +1743,8 @@ function helpText() {
1621
1743
  " --environment-label <text> Non-sensitive label shown in Haven setup review.",
1622
1744
  " --ack-local-tools Write the one-time local Haven tools acknowledgement during setup.",
1623
1745
  " --ack-signer Backward-compatible alias for --ack-local-tools.",
1746
+ " --local Advanced: install the fully-local Haven MCP (no hosted dependency).",
1747
+ " Only available for Claude Code and Codex. Default is hosted MCP + local signer.",
1624
1748
  " --help Show this help.",
1625
1749
  "",
1626
1750
  "The connector never prints the private key and never sends it to Haven."
@@ -1634,6 +1758,6 @@ function requireValue(argv, index, option) {
1634
1758
  return value;
1635
1759
  }
1636
1760
 
1637
- export { CONNECTOR_VERSION, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, shortAddress, writeCredentialFiles };
1761
+ export { CONNECTOR_VERSION, MCP_RUNTIME_MANIFEST, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
1638
1762
  //# sourceMappingURL=index.js.map
1639
1763
  //# sourceMappingURL=index.js.map