@haven_ai/connect 0.1.12-alpha.0 → 0.1.13-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
@@ -160,6 +160,42 @@ interface PreparedLocalMcpRuntime {
160
160
  messages: string[];
161
161
  }
162
162
 
163
+ interface PrepareSignerRuntimeInput {
164
+ credentialDirectory: string;
165
+ signerPath: string;
166
+ homeDir?: string;
167
+ }
168
+ interface PreparedSignerRuntime {
169
+ /** Absolute command to register as the signer MCP `command`. */
170
+ command: string;
171
+ /** Args to register alongside `command` (credentials are baked into the wrapper). */
172
+ args: string[];
173
+ wrapperPath: string;
174
+ runtimeDirectory: string;
175
+ npmCacheDirectory: string;
176
+ cliPath: string;
177
+ messages: string[];
178
+ }
179
+ interface SignerRuntimeDeps {
180
+ runCommand?: (command: string, args: string[]) => Promise<void>;
181
+ }
182
+ /**
183
+ * Pre-install the edge signer into a version-pinned, connector-managed
184
+ * directory and write a stable wrapper that launches it with an absolute Node
185
+ * path. The signer MCP is then registered as `command: <wrapper>` instead of a
186
+ * runtime `npx -y @haven_ai/signer@…` invocation.
187
+ *
188
+ * Why: launching the signer via bare `npx` at every MCP spawn made it depend on
189
+ * the PATH/environment the agent runtime hands the stdio subprocess, which is
190
+ * not the user's interactive shell — the failure mode that left `haven-signer`
191
+ * stuck at "Failed to connect" while the hosted HTTP server connected fine. The
192
+ * local MCP topology already avoids this with the same pre-install + wrapper
193
+ * pattern (see prepareLocalMcpRuntime); this brings the default hosted+signer
194
+ * topology to parity. Version stays pinned (no unpinned `npm i -g`), and the
195
+ * wrapper lives under ~/.haven so the reset flow already cleans it up.
196
+ */
197
+ declare function prepareSignerRuntime(input: PrepareSignerRuntimeInput, deps?: SignerRuntimeDeps): Promise<PreparedSignerRuntime>;
198
+
163
199
  interface RuntimeInstallInput {
164
200
  runtime?: string;
165
201
  hostedMcpUrl: string;
@@ -193,6 +229,14 @@ interface RuntimeInstallResult {
193
229
  localMcpAcknowledged?: boolean;
194
230
  activationCommand?: string;
195
231
  skillInstalled?: boolean;
232
+ /**
233
+ * Hosted topology only: true when the signer was pre-installed and registered
234
+ * via its absolute wrapper, false when prep failed and it fell back to the
235
+ * fragile runtime-`npx` launch. Undefined for local/manual topologies that
236
+ * do not run the signer as a separate MCP. Lets callers/tests detect the
237
+ * silent npx fallback instead of treating every write as fully healthy.
238
+ */
239
+ signerRuntimePrepared?: boolean;
196
240
  messages: string[];
197
241
  }
198
242
  interface RuntimeInstallDeps {
@@ -201,6 +245,7 @@ interface RuntimeInstallDeps {
201
245
  fetch?: typeof fetch;
202
246
  runCommand?: (command: string, args: string[]) => Promise<void>;
203
247
  prepareLocalMcpRuntime?: (input: PrepareLocalMcpRuntimeInput) => Promise<PreparedLocalMcpRuntime>;
248
+ prepareSignerRuntime?: (input: PrepareSignerRuntimeInput) => Promise<PreparedSignerRuntime>;
204
249
  probeLocalMcpTools?: (command: string, args: string[], requiredTools: readonly string[]) => Promise<LocalMcpProbeResult>;
205
250
  }
206
251
  declare function installRuntime(input: RuntimeInstallInput, deps?: RuntimeInstallDeps): Promise<RuntimeInstallResult>;
@@ -209,7 +254,7 @@ declare function runtimeInstallCapabilities(runtime: string | undefined, env?: N
209
254
  restartRequired: boolean;
210
255
  };
211
256
 
212
- declare const CONNECTOR_VERSION = "0.1.12-alpha.0";
257
+ declare const CONNECTOR_VERSION = "0.1.13-alpha.0";
213
258
  interface ConnectOptions {
214
259
  setupToken: string;
215
260
  apiBaseUrl: string;
@@ -250,11 +295,11 @@ declare function shortAddress(address: string): string;
250
295
 
251
296
  declare const MCP_RUNTIME_MANIFEST: {
252
297
  readonly mcpPackage: "@haven_ai/mcp";
253
- readonly mcpVersion: "0.1.12-alpha.0";
298
+ readonly mcpVersion: "0.1.13-alpha.0";
254
299
  readonly sdkPackage: "@haven_ai/sdk";
255
- readonly sdkVersion: "0.1.12-alpha.0";
300
+ readonly sdkVersion: "0.1.13-alpha.0";
256
301
  readonly signerPackage: "@haven_ai/signer";
257
- readonly signerVersion: "0.1.12-alpha.0";
302
+ readonly signerVersion: "0.1.13-alpha.0";
258
303
  readonly minimumNodeVersion: "20.0.0";
259
304
  readonly supportedClients: readonly ["codex-cli", "codex-desktop", "claude-code"];
260
305
  readonly requiredTools: readonly string[];
@@ -263,4 +308,4 @@ declare function mcpPackageSpec(): string;
263
308
  declare function sdkPackageSpec(): string;
264
309
  declare function signerPackageSpec(): string;
265
310
 
266
- 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 };
311
+ export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, MCP_RUNTIME_MANIFEST, type PrepareSignerRuntimeInput, type PreparedSignerRuntime, 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, prepareSignerRuntime, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
package/dist/index.d.ts CHANGED
@@ -160,6 +160,42 @@ interface PreparedLocalMcpRuntime {
160
160
  messages: string[];
161
161
  }
162
162
 
163
+ interface PrepareSignerRuntimeInput {
164
+ credentialDirectory: string;
165
+ signerPath: string;
166
+ homeDir?: string;
167
+ }
168
+ interface PreparedSignerRuntime {
169
+ /** Absolute command to register as the signer MCP `command`. */
170
+ command: string;
171
+ /** Args to register alongside `command` (credentials are baked into the wrapper). */
172
+ args: string[];
173
+ wrapperPath: string;
174
+ runtimeDirectory: string;
175
+ npmCacheDirectory: string;
176
+ cliPath: string;
177
+ messages: string[];
178
+ }
179
+ interface SignerRuntimeDeps {
180
+ runCommand?: (command: string, args: string[]) => Promise<void>;
181
+ }
182
+ /**
183
+ * Pre-install the edge signer into a version-pinned, connector-managed
184
+ * directory and write a stable wrapper that launches it with an absolute Node
185
+ * path. The signer MCP is then registered as `command: <wrapper>` instead of a
186
+ * runtime `npx -y @haven_ai/signer@…` invocation.
187
+ *
188
+ * Why: launching the signer via bare `npx` at every MCP spawn made it depend on
189
+ * the PATH/environment the agent runtime hands the stdio subprocess, which is
190
+ * not the user's interactive shell — the failure mode that left `haven-signer`
191
+ * stuck at "Failed to connect" while the hosted HTTP server connected fine. The
192
+ * local MCP topology already avoids this with the same pre-install + wrapper
193
+ * pattern (see prepareLocalMcpRuntime); this brings the default hosted+signer
194
+ * topology to parity. Version stays pinned (no unpinned `npm i -g`), and the
195
+ * wrapper lives under ~/.haven so the reset flow already cleans it up.
196
+ */
197
+ declare function prepareSignerRuntime(input: PrepareSignerRuntimeInput, deps?: SignerRuntimeDeps): Promise<PreparedSignerRuntime>;
198
+
163
199
  interface RuntimeInstallInput {
164
200
  runtime?: string;
165
201
  hostedMcpUrl: string;
@@ -193,6 +229,14 @@ interface RuntimeInstallResult {
193
229
  localMcpAcknowledged?: boolean;
194
230
  activationCommand?: string;
195
231
  skillInstalled?: boolean;
232
+ /**
233
+ * Hosted topology only: true when the signer was pre-installed and registered
234
+ * via its absolute wrapper, false when prep failed and it fell back to the
235
+ * fragile runtime-`npx` launch. Undefined for local/manual topologies that
236
+ * do not run the signer as a separate MCP. Lets callers/tests detect the
237
+ * silent npx fallback instead of treating every write as fully healthy.
238
+ */
239
+ signerRuntimePrepared?: boolean;
196
240
  messages: string[];
197
241
  }
198
242
  interface RuntimeInstallDeps {
@@ -201,6 +245,7 @@ interface RuntimeInstallDeps {
201
245
  fetch?: typeof fetch;
202
246
  runCommand?: (command: string, args: string[]) => Promise<void>;
203
247
  prepareLocalMcpRuntime?: (input: PrepareLocalMcpRuntimeInput) => Promise<PreparedLocalMcpRuntime>;
248
+ prepareSignerRuntime?: (input: PrepareSignerRuntimeInput) => Promise<PreparedSignerRuntime>;
204
249
  probeLocalMcpTools?: (command: string, args: string[], requiredTools: readonly string[]) => Promise<LocalMcpProbeResult>;
205
250
  }
206
251
  declare function installRuntime(input: RuntimeInstallInput, deps?: RuntimeInstallDeps): Promise<RuntimeInstallResult>;
@@ -209,7 +254,7 @@ declare function runtimeInstallCapabilities(runtime: string | undefined, env?: N
209
254
  restartRequired: boolean;
210
255
  };
211
256
 
212
- declare const CONNECTOR_VERSION = "0.1.12-alpha.0";
257
+ declare const CONNECTOR_VERSION = "0.1.13-alpha.0";
213
258
  interface ConnectOptions {
214
259
  setupToken: string;
215
260
  apiBaseUrl: string;
@@ -250,11 +295,11 @@ declare function shortAddress(address: string): string;
250
295
 
251
296
  declare const MCP_RUNTIME_MANIFEST: {
252
297
  readonly mcpPackage: "@haven_ai/mcp";
253
- readonly mcpVersion: "0.1.12-alpha.0";
298
+ readonly mcpVersion: "0.1.13-alpha.0";
254
299
  readonly sdkPackage: "@haven_ai/sdk";
255
- readonly sdkVersion: "0.1.12-alpha.0";
300
+ readonly sdkVersion: "0.1.13-alpha.0";
256
301
  readonly signerPackage: "@haven_ai/signer";
257
- readonly signerVersion: "0.1.12-alpha.0";
302
+ readonly signerVersion: "0.1.13-alpha.0";
258
303
  readonly minimumNodeVersion: "20.0.0";
259
304
  readonly supportedClients: readonly ["codex-cli", "codex-desktop", "claude-code"];
260
305
  readonly requiredTools: readonly string[];
@@ -263,4 +308,4 @@ declare function mcpPackageSpec(): string;
263
308
  declare function sdkPackageSpec(): string;
264
309
  declare function signerPackageSpec(): string;
265
310
 
266
- 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 };
311
+ export { CONNECTOR_VERSION, type ConnectApiClient, type ConnectDeps, type ConnectOptions, type ConnectResult, type LocalDelegateKey, MCP_RUNTIME_MANIFEST, type PrepareSignerRuntimeInput, type PreparedSignerRuntime, 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, prepareSignerRuntime, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
package/dist/index.js CHANGED
@@ -208,9 +208,9 @@ var MCP_RUNTIME_MANIFEST = {
208
208
  mcpPackage: "@haven_ai/mcp",
209
209
  mcpVersion: MCP_VERSION,
210
210
  sdkPackage: "@haven_ai/sdk",
211
- sdkVersion: "0.1.12-alpha.0",
211
+ sdkVersion: "0.1.13-alpha.0",
212
212
  signerPackage: "@haven_ai/signer",
213
- signerVersion: "0.1.12-alpha.0",
213
+ signerVersion: "0.1.13-alpha.0",
214
214
  minimumNodeVersion: "20.0.0",
215
215
  supportedClients: ["codex-cli", "codex-desktop", "claude-code"],
216
216
  requiredTools: registeredToolNames()
@@ -383,10 +383,16 @@ function buildHostedServer(hostedMcpUrl, apiKey, runtime) {
383
383
  headers: { Authorization: `Bearer ${apiKey}` }
384
384
  };
385
385
  }
386
- function buildSignerServer(signerPath, runtime) {
387
- const server = {
386
+ function resolveSignerLaunchSpec(input) {
387
+ return input.signerCommand ?? {
388
388
  command: "npx",
389
- args: ["-y", signerPackageName(), "--credentials", signerPath]
389
+ args: ["-y", signerPackageSpec(), "--credentials", input.signerPath]
390
+ };
391
+ }
392
+ function buildSignerServer(spec, runtime) {
393
+ const server = {
394
+ command: spec.command,
395
+ args: spec.args
390
396
  };
391
397
  if (runtime === "vscode" || runtime === "vscode-insiders") return { type: "stdio", ...server };
392
398
  return server;
@@ -419,7 +425,7 @@ function mergeCodexToml(existingToml, localMcpCommand) {
419
425
  `;
420
426
  return merged;
421
427
  }
422
- function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
428
+ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerSpec) {
423
429
  let next = removeTomlTableTree(removeTomlTableTree(existingToml, "mcp_servers.haven"), "mcp_servers.haven_signer");
424
430
  next = next.trimEnd();
425
431
  const block = [
@@ -428,8 +434,8 @@ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
428
434
  `http_headers = { "Authorization" = ${tomlString(`Bearer ${apiKey}`)} }`,
429
435
  "",
430
436
  "[mcp_servers.haven_signer]",
431
- 'command = "npx"',
432
- `args = ["-y", ${tomlString(signerPackageSpec())}, "--credentials", ${tomlString(signerPath)}]`,
437
+ `command = ${tomlString(signerSpec.command)}`,
438
+ `args = [${signerSpec.args.map((arg) => tomlString(arg)).join(", ")}]`,
433
439
  "startup_timeout_sec = 120"
434
440
  ].join("\n");
435
441
  validateCodexToml(block, "Generated Codex Haven config");
@@ -446,7 +452,7 @@ async function writeJsonRuntimeConfig(input, target, serverRoot) {
446
452
  existing,
447
453
  serverRoot,
448
454
  buildHostedServer(input.hostedMcpUrl, input.apiKey, input.runtime),
449
- buildSignerServer(input.signerPath, input.runtime)
455
+ buildSignerServer(resolveSignerLaunchSpec(input), input.runtime)
450
456
  );
451
457
  await writeOwnerOnlyText(target, merged);
452
458
  return {
@@ -502,7 +508,7 @@ async function writeCodexConfig(input) {
502
508
  ]
503
509
  };
504
510
  }
505
- const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, input.signerPath);
511
+ const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, resolveSignerLaunchSpec(input));
506
512
  await writeOwnerOnlyText(target, merged);
507
513
  return {
508
514
  hostedConfigured: true,
@@ -787,9 +793,6 @@ function configTargetLabel(runtime) {
787
793
  return "runtime MCP config";
788
794
  }
789
795
  }
790
- function signerPackageName() {
791
- return signerPackageSpec();
792
- }
793
796
  async function acknowledgeLocalMcpConsent(identityPath, signerPath, log) {
794
797
  try {
795
798
  const input = await buildLocalMcpConsentInput(identityPath, signerPath);
@@ -903,7 +906,7 @@ async function probeLocalSignerCredential(signerPath) {
903
906
  }
904
907
  }
905
908
  async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4) {
906
- return new Promise((resolve7) => {
909
+ return new Promise((resolve8) => {
907
910
  const child = spawn(command, args, { stdio: ["pipe", "pipe", "ignore"] });
908
911
  let stdout = "";
909
912
  let settled = false;
@@ -913,7 +916,7 @@ async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4)
913
916
  settled = true;
914
917
  clearTimeout(timeout);
915
918
  child.kill();
916
- resolve7(result);
919
+ resolve8(result);
917
920
  };
918
921
  const timeout = setTimeout(() => finish({ status: "timeout" }), timeoutMs);
919
922
  child.on("error", () => finish({ status: "process_error" }));
@@ -1151,6 +1154,126 @@ async function assertFileExists(path, label) {
1151
1154
  throw new Error(`Missing ${label}: ${path}`);
1152
1155
  }
1153
1156
  }
1157
+ var execFileAsync2 = promisify(execFile);
1158
+ async function prepareSignerRuntime(input, deps = {}) {
1159
+ const homeDir = input.homeDir ?? homedir();
1160
+ const runtimeDirectory = resolve(homeDir, ".haven", "signer-runtime", MCP_RUNTIME_MANIFEST.signerVersion);
1161
+ const npmCacheDirectory = resolve(homeDir, ".haven", "npm-cache");
1162
+ const cliPath = join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "dist", "cli.js");
1163
+ const messages = [];
1164
+ await mkdir(runtimeDirectory, { recursive: true, mode: 448 });
1165
+ await chmod(runtimeDirectory, 448).catch(() => void 0);
1166
+ await mkdir(npmCacheDirectory, { recursive: true, mode: 448 });
1167
+ await chmod(npmCacheDirectory, 448).catch(() => void 0);
1168
+ if (await installedRuntimeMatches2(runtimeDirectory, cliPath)) {
1169
+ messages.push(`Using existing local Haven signer runtime ${signerPackageSpec()}.`);
1170
+ } else {
1171
+ await installRuntimePackages2(runtimeDirectory, npmCacheDirectory, deps.runCommand);
1172
+ messages.push(`Installed local Haven signer runtime ${signerPackageSpec()}.`);
1173
+ }
1174
+ await assertFileExists2(cliPath, "local Haven signer CLI");
1175
+ const wrapperPath = join(input.credentialDirectory, "bin", "haven-signer.mjs");
1176
+ await writeWrapper2({ wrapperPath, cliPath, signerPath: input.signerPath });
1177
+ await writeRuntimeSidecar2({
1178
+ path: join(input.credentialDirectory, "signer-runtime.json"),
1179
+ wrapperPath,
1180
+ runtimeDirectory,
1181
+ npmCacheDirectory,
1182
+ cliPath
1183
+ });
1184
+ messages.push(`Prepared stable local Haven signer wrapper: ${wrapperPath}`);
1185
+ return {
1186
+ command: wrapperPath,
1187
+ args: [],
1188
+ wrapperPath,
1189
+ runtimeDirectory,
1190
+ npmCacheDirectory,
1191
+ cliPath,
1192
+ messages
1193
+ };
1194
+ }
1195
+ async function installRuntimePackages2(runtimeDirectory, npmCacheDirectory, runCommand) {
1196
+ const args = [
1197
+ "install",
1198
+ "--prefix",
1199
+ runtimeDirectory,
1200
+ "--cache",
1201
+ npmCacheDirectory,
1202
+ "--no-audit",
1203
+ "--no-fund",
1204
+ "--omit=dev",
1205
+ signerPackageSpec(),
1206
+ sdkPackageSpec()
1207
+ ];
1208
+ try {
1209
+ if (runCommand) await runCommand("npm", args);
1210
+ else await execFileAsync2("npm", args, { timeout: 12e4, maxBuffer: 1024 * 1024 });
1211
+ } catch (err) {
1212
+ throw new Error(
1213
+ `Could not install local Haven signer runtime ${signerPackageSpec()}: ${err instanceof Error ? err.message : String(err)}`
1214
+ );
1215
+ }
1216
+ }
1217
+ async function installedRuntimeMatches2(runtimeDirectory, cliPath) {
1218
+ try {
1219
+ await assertFileExists2(cliPath, "local Haven signer CLI");
1220
+ const [signerPackage, sdkPackage] = await Promise.all([
1221
+ readPackageJson2(join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "package.json")),
1222
+ readPackageJson2(join(runtimeDirectory, "node_modules", "@haven_ai", "sdk", "package.json"))
1223
+ ]);
1224
+ return signerPackage.version === MCP_RUNTIME_MANIFEST.signerVersion && sdkPackage.version === MCP_RUNTIME_MANIFEST.sdkVersion;
1225
+ } catch {
1226
+ return false;
1227
+ }
1228
+ }
1229
+ async function readPackageJson2(path) {
1230
+ return JSON.parse(await readFile(path, "utf8"));
1231
+ }
1232
+ async function writeWrapper2(input) {
1233
+ await mkdir(dirname(input.wrapperPath), { recursive: true, mode: 448 });
1234
+ await chmod(dirname(input.wrapperPath), 448).catch(() => void 0);
1235
+ const source = [
1236
+ "#!/usr/bin/env node",
1237
+ "import { spawn } from 'node:child_process'",
1238
+ "",
1239
+ `const cliPath = ${JSON.stringify(input.cliPath)}`,
1240
+ `const signerPath = ${JSON.stringify(input.signerPath)}`,
1241
+ "",
1242
+ "const child = spawn(process.execPath, [cliPath, '--credentials', signerPath, ...process.argv.slice(2)], {",
1243
+ " stdio: 'inherit',",
1244
+ "})",
1245
+ "",
1246
+ "child.on('exit', (code, signal) => {",
1247
+ " if (signal) process.kill(process.pid, signal)",
1248
+ " else process.exit(code ?? 1)",
1249
+ "})",
1250
+ ""
1251
+ ].join("\n");
1252
+ await writeFile(input.wrapperPath, source, { mode: 448 });
1253
+ await chmod(input.wrapperPath, 448).catch(() => void 0);
1254
+ }
1255
+ async function writeRuntimeSidecar2(input) {
1256
+ const value = {
1257
+ signer_package: MCP_RUNTIME_MANIFEST.signerPackage,
1258
+ signer_version: MCP_RUNTIME_MANIFEST.signerVersion,
1259
+ sdk_package: MCP_RUNTIME_MANIFEST.sdkPackage,
1260
+ sdk_version: MCP_RUNTIME_MANIFEST.sdkVersion,
1261
+ wrapper_path: input.wrapperPath,
1262
+ runtime_directory: input.runtimeDirectory,
1263
+ npm_cache_directory: input.npmCacheDirectory,
1264
+ cli_path: input.cliPath
1265
+ };
1266
+ await writeFile(input.path, `${JSON.stringify(value, null, 2)}
1267
+ `, { mode: 384 });
1268
+ await chmod(input.path, 384).catch(() => void 0);
1269
+ }
1270
+ async function assertFileExists2(path, label) {
1271
+ try {
1272
+ await access(path);
1273
+ } catch {
1274
+ throw new Error(`Missing ${label}: ${path}`);
1275
+ }
1276
+ }
1154
1277
  async function acknowledgeLocalSignerConsent(signerPath, log) {
1155
1278
  try {
1156
1279
  const input = await buildSignerConsentInput(signerPath);
@@ -1222,7 +1345,7 @@ function writeLogChunk2(log, chunk) {
1222
1345
  }
1223
1346
 
1224
1347
  // src/runtime-install.ts
1225
- var execFileAsync2 = promisify(execFile);
1348
+ var execFileAsync3 = promisify(execFile);
1226
1349
  async function installRuntime(input, deps = {}) {
1227
1350
  const runtime = normalizeRuntime(input.runtime, deps.env);
1228
1351
  const profile = runtimeProfile(runtime, deps.env);
@@ -1283,7 +1406,20 @@ async function installRuntime(input, deps = {}) {
1283
1406
  ]
1284
1407
  };
1285
1408
  }
1286
- const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input) : await writeRuntimeConfig({
1409
+ let signerCommand;
1410
+ if (!localRuntime) {
1411
+ try {
1412
+ const signerRuntime = await prepareSignerForRuntime(input, deps);
1413
+ signerCommand = { command: signerRuntime.command, args: signerRuntime.args };
1414
+ consentMessages.push(...signerRuntime.messages);
1415
+ } catch (err) {
1416
+ consentMessages.push(
1417
+ `Could not pre-install the local Haven signer; falling back to npx launch: ${err instanceof Error ? err.message : String(err)}`
1418
+ );
1419
+ }
1420
+ }
1421
+ const signerRuntimePrepared = localRuntime ? void 0 : signerCommand !== void 0;
1422
+ const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input, signerCommand) : await writeRuntimeConfig({
1287
1423
  runtime,
1288
1424
  hostedMcpUrl: input.hostedMcpUrl,
1289
1425
  apiKey: input.apiKey,
@@ -1291,6 +1427,7 @@ async function installRuntime(input, deps = {}) {
1291
1427
  signerPath: input.signerPath,
1292
1428
  credentialDirectory: input.credentialDirectory,
1293
1429
  localMcpCommand: localRuntimeInstall?.command,
1430
+ signerCommand,
1294
1431
  homeDir: deps.homeDir,
1295
1432
  mode: localRuntime ? "local" : "hosted"
1296
1433
  });
@@ -1322,6 +1459,7 @@ async function installRuntime(input, deps = {}) {
1322
1459
  localMcpAcknowledged: localMcpConsent?.acknowledged,
1323
1460
  activationCommand: configResult.activationCommand,
1324
1461
  skillInstalled: skillInstall?.installed,
1462
+ signerRuntimePrepared,
1325
1463
  messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
1326
1464
  };
1327
1465
  }
@@ -1378,7 +1516,7 @@ async function configureClaudeCode(deps, localMcpCommand) {
1378
1516
  };
1379
1517
  }
1380
1518
  }
1381
- async function configureClaudeCodeHosted(deps, input) {
1519
+ async function configureClaudeCodeHosted(deps, input, signerCommand) {
1382
1520
  const runCommand = deps.runCommand ?? defaultRunCommand;
1383
1521
  const hostedJson = JSON.stringify({
1384
1522
  type: "http",
@@ -1387,8 +1525,8 @@ async function configureClaudeCodeHosted(deps, input) {
1387
1525
  });
1388
1526
  const signerJson = JSON.stringify({
1389
1527
  type: "stdio",
1390
- command: "npx",
1391
- args: ["-y", signerPackageSpec(), "--credentials", input.signerPath],
1528
+ command: signerCommand?.command ?? "npx",
1529
+ args: signerCommand?.args ?? ["-y", signerPackageSpec(), "--credentials", input.signerPath],
1392
1530
  env: {}
1393
1531
  });
1394
1532
  try {
@@ -1429,7 +1567,7 @@ async function configureClaudeCodeHosted(deps, input) {
1429
1567
  }
1430
1568
  }
1431
1569
  async function defaultRunCommand(command, args) {
1432
- await execFileAsync2(command, args, { timeout: 1e4 });
1570
+ await execFileAsync3(command, args, { timeout: 1e4 });
1433
1571
  }
1434
1572
  async function installClaudeSkill(homeDir) {
1435
1573
  try {
@@ -1512,6 +1650,14 @@ async function prepareRuntimeForLocalMcp(input, deps) {
1512
1650
  homeDir: deps.homeDir
1513
1651
  });
1514
1652
  }
1653
+ async function prepareSignerForRuntime(input, deps) {
1654
+ const prepare = deps.prepareSignerRuntime ?? ((runtimeInput) => prepareSignerRuntime(runtimeInput, { runCommand: deps.runCommand }));
1655
+ return prepare({
1656
+ credentialDirectory: input.credentialDirectory,
1657
+ signerPath: input.signerPath,
1658
+ homeDir: deps.homeDir
1659
+ });
1660
+ }
1515
1661
  async function runLocalMcpProbe(runtimeInstall, deps) {
1516
1662
  const probe = deps.probeLocalMcpTools ?? probeLocalMcpTools;
1517
1663
  try {
@@ -1528,7 +1674,7 @@ function localRuntimePrepareErrorCode(err) {
1528
1674
  }
1529
1675
 
1530
1676
  // src/runtime.ts
1531
- var CONNECTOR_VERSION = "0.1.12-alpha.0";
1677
+ var CONNECTOR_VERSION = "0.1.13-alpha.0";
1532
1678
  async function runConnect(options, deps = {}) {
1533
1679
  const connectorVersion = options.connectorVersion ?? CONNECTOR_VERSION;
1534
1680
  const api = deps.api ?? createConnectApiClient(options.apiBaseUrl);
@@ -1767,6 +1913,6 @@ function requireValue(argv, index, option) {
1767
1913
  return value;
1768
1914
  }
1769
1915
 
1770
- export { CONNECTOR_VERSION, MCP_RUNTIME_MANIFEST, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
1916
+ export { CONNECTOR_VERSION, MCP_RUNTIME_MANIFEST, createConnectApiClient, defaultAgentDirectory, delegateKeyFromPrivateKey, generateDelegateKey, helpText, installRuntime, mcpPackageSpec, normalizeRuntime, parseArgs, prepareSignerRuntime, redactSecrets, runConnect, runtimeInstallCapabilities, runtimeProfile, sdkPackageSpec, shortAddress, signerPackageSpec, writeCredentialFiles };
1771
1917
  //# sourceMappingURL=index.js.map
1772
1918
  //# sourceMappingURL=index.js.map