@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/cli.cjs +168 -22
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +168 -22
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +169 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -5
- package/dist/index.d.ts +50 -5
- package/dist/index.js +169 -23
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -209,9 +209,9 @@ var MCP_RUNTIME_MANIFEST = {
|
|
|
209
209
|
mcpPackage: "@haven_ai/mcp",
|
|
210
210
|
mcpVersion: MCP_VERSION,
|
|
211
211
|
sdkPackage: "@haven_ai/sdk",
|
|
212
|
-
sdkVersion: "0.1.
|
|
212
|
+
sdkVersion: "0.1.13-alpha.0",
|
|
213
213
|
signerPackage: "@haven_ai/signer",
|
|
214
|
-
signerVersion: "0.1.
|
|
214
|
+
signerVersion: "0.1.13-alpha.0",
|
|
215
215
|
minimumNodeVersion: "20.0.0",
|
|
216
216
|
supportedClients: ["codex-cli", "codex-desktop", "claude-code"],
|
|
217
217
|
requiredTools: registeredToolNames()
|
|
@@ -384,10 +384,16 @@ function buildHostedServer(hostedMcpUrl, apiKey, runtime) {
|
|
|
384
384
|
headers: { Authorization: `Bearer ${apiKey}` }
|
|
385
385
|
};
|
|
386
386
|
}
|
|
387
|
-
function
|
|
388
|
-
|
|
387
|
+
function resolveSignerLaunchSpec(input) {
|
|
388
|
+
return input.signerCommand ?? {
|
|
389
389
|
command: "npx",
|
|
390
|
-
args: ["-y",
|
|
390
|
+
args: ["-y", signerPackageSpec(), "--credentials", input.signerPath]
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function buildSignerServer(spec, runtime) {
|
|
394
|
+
const server = {
|
|
395
|
+
command: spec.command,
|
|
396
|
+
args: spec.args
|
|
391
397
|
};
|
|
392
398
|
if (runtime === "vscode" || runtime === "vscode-insiders") return { type: "stdio", ...server };
|
|
393
399
|
return server;
|
|
@@ -420,7 +426,7 @@ function mergeCodexToml(existingToml, localMcpCommand) {
|
|
|
420
426
|
`;
|
|
421
427
|
return merged;
|
|
422
428
|
}
|
|
423
|
-
function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey,
|
|
429
|
+
function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerSpec) {
|
|
424
430
|
let next = removeTomlTableTree(removeTomlTableTree(existingToml, "mcp_servers.haven"), "mcp_servers.haven_signer");
|
|
425
431
|
next = next.trimEnd();
|
|
426
432
|
const block = [
|
|
@@ -429,8 +435,8 @@ function mergeCodexTomlHosted(existingToml, hostedMcpUrl, apiKey, signerPath) {
|
|
|
429
435
|
`http_headers = { "Authorization" = ${tomlString(`Bearer ${apiKey}`)} }`,
|
|
430
436
|
"",
|
|
431
437
|
"[mcp_servers.haven_signer]",
|
|
432
|
-
|
|
433
|
-
`args = [
|
|
438
|
+
`command = ${tomlString(signerSpec.command)}`,
|
|
439
|
+
`args = [${signerSpec.args.map((arg) => tomlString(arg)).join(", ")}]`,
|
|
434
440
|
"startup_timeout_sec = 120"
|
|
435
441
|
].join("\n");
|
|
436
442
|
validateCodexToml(block, "Generated Codex Haven config");
|
|
@@ -447,7 +453,7 @@ async function writeJsonRuntimeConfig(input, target, serverRoot) {
|
|
|
447
453
|
existing,
|
|
448
454
|
serverRoot,
|
|
449
455
|
buildHostedServer(input.hostedMcpUrl, input.apiKey, input.runtime),
|
|
450
|
-
buildSignerServer(input
|
|
456
|
+
buildSignerServer(resolveSignerLaunchSpec(input), input.runtime)
|
|
451
457
|
);
|
|
452
458
|
await writeOwnerOnlyText(target, merged);
|
|
453
459
|
return {
|
|
@@ -503,7 +509,7 @@ async function writeCodexConfig(input) {
|
|
|
503
509
|
]
|
|
504
510
|
};
|
|
505
511
|
}
|
|
506
|
-
const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, input
|
|
512
|
+
const merged = mergeCodexTomlHosted(existing ?? "", input.hostedMcpUrl, input.apiKey, resolveSignerLaunchSpec(input));
|
|
507
513
|
await writeOwnerOnlyText(target, merged);
|
|
508
514
|
return {
|
|
509
515
|
hostedConfigured: true,
|
|
@@ -788,9 +794,6 @@ function configTargetLabel(runtime) {
|
|
|
788
794
|
return "runtime MCP config";
|
|
789
795
|
}
|
|
790
796
|
}
|
|
791
|
-
function signerPackageName() {
|
|
792
|
-
return signerPackageSpec();
|
|
793
|
-
}
|
|
794
797
|
async function acknowledgeLocalMcpConsent(identityPath, signerPath, log) {
|
|
795
798
|
try {
|
|
796
799
|
const input = await buildLocalMcpConsentInput(identityPath, signerPath);
|
|
@@ -904,7 +907,7 @@ async function probeLocalSignerCredential(signerPath) {
|
|
|
904
907
|
}
|
|
905
908
|
}
|
|
906
909
|
async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4) {
|
|
907
|
-
return new Promise((
|
|
910
|
+
return new Promise((resolve8) => {
|
|
908
911
|
const child = spawn(command, args, { stdio: ["pipe", "pipe", "ignore"] });
|
|
909
912
|
let stdout = "";
|
|
910
913
|
let settled = false;
|
|
@@ -914,7 +917,7 @@ async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4)
|
|
|
914
917
|
settled = true;
|
|
915
918
|
clearTimeout(timeout);
|
|
916
919
|
child.kill();
|
|
917
|
-
|
|
920
|
+
resolve8(result);
|
|
918
921
|
};
|
|
919
922
|
const timeout = setTimeout(() => finish({ status: "timeout" }), timeoutMs);
|
|
920
923
|
child.on("error", () => finish({ status: "process_error" }));
|
|
@@ -1152,6 +1155,126 @@ async function assertFileExists(path, label) {
|
|
|
1152
1155
|
throw new Error(`Missing ${label}: ${path}`);
|
|
1153
1156
|
}
|
|
1154
1157
|
}
|
|
1158
|
+
var execFileAsync2 = promisify(execFile);
|
|
1159
|
+
async function prepareSignerRuntime(input, deps = {}) {
|
|
1160
|
+
const homeDir = input.homeDir ?? homedir();
|
|
1161
|
+
const runtimeDirectory = resolve(homeDir, ".haven", "signer-runtime", MCP_RUNTIME_MANIFEST.signerVersion);
|
|
1162
|
+
const npmCacheDirectory = resolve(homeDir, ".haven", "npm-cache");
|
|
1163
|
+
const cliPath = join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "dist", "cli.js");
|
|
1164
|
+
const messages = [];
|
|
1165
|
+
await mkdir(runtimeDirectory, { recursive: true, mode: 448 });
|
|
1166
|
+
await chmod(runtimeDirectory, 448).catch(() => void 0);
|
|
1167
|
+
await mkdir(npmCacheDirectory, { recursive: true, mode: 448 });
|
|
1168
|
+
await chmod(npmCacheDirectory, 448).catch(() => void 0);
|
|
1169
|
+
if (await installedRuntimeMatches2(runtimeDirectory, cliPath)) {
|
|
1170
|
+
messages.push(`Using existing local Haven signer runtime ${signerPackageSpec()}.`);
|
|
1171
|
+
} else {
|
|
1172
|
+
await installRuntimePackages2(runtimeDirectory, npmCacheDirectory, deps.runCommand);
|
|
1173
|
+
messages.push(`Installed local Haven signer runtime ${signerPackageSpec()}.`);
|
|
1174
|
+
}
|
|
1175
|
+
await assertFileExists2(cliPath, "local Haven signer CLI");
|
|
1176
|
+
const wrapperPath = join(input.credentialDirectory, "bin", "haven-signer.mjs");
|
|
1177
|
+
await writeWrapper2({ wrapperPath, cliPath, signerPath: input.signerPath });
|
|
1178
|
+
await writeRuntimeSidecar2({
|
|
1179
|
+
path: join(input.credentialDirectory, "signer-runtime.json"),
|
|
1180
|
+
wrapperPath,
|
|
1181
|
+
runtimeDirectory,
|
|
1182
|
+
npmCacheDirectory,
|
|
1183
|
+
cliPath
|
|
1184
|
+
});
|
|
1185
|
+
messages.push(`Prepared stable local Haven signer wrapper: ${wrapperPath}`);
|
|
1186
|
+
return {
|
|
1187
|
+
command: wrapperPath,
|
|
1188
|
+
args: [],
|
|
1189
|
+
wrapperPath,
|
|
1190
|
+
runtimeDirectory,
|
|
1191
|
+
npmCacheDirectory,
|
|
1192
|
+
cliPath,
|
|
1193
|
+
messages
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
async function installRuntimePackages2(runtimeDirectory, npmCacheDirectory, runCommand) {
|
|
1197
|
+
const args = [
|
|
1198
|
+
"install",
|
|
1199
|
+
"--prefix",
|
|
1200
|
+
runtimeDirectory,
|
|
1201
|
+
"--cache",
|
|
1202
|
+
npmCacheDirectory,
|
|
1203
|
+
"--no-audit",
|
|
1204
|
+
"--no-fund",
|
|
1205
|
+
"--omit=dev",
|
|
1206
|
+
signerPackageSpec(),
|
|
1207
|
+
sdkPackageSpec()
|
|
1208
|
+
];
|
|
1209
|
+
try {
|
|
1210
|
+
if (runCommand) await runCommand("npm", args);
|
|
1211
|
+
else await execFileAsync2("npm", args, { timeout: 12e4, maxBuffer: 1024 * 1024 });
|
|
1212
|
+
} catch (err) {
|
|
1213
|
+
throw new Error(
|
|
1214
|
+
`Could not install local Haven signer runtime ${signerPackageSpec()}: ${err instanceof Error ? err.message : String(err)}`
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
async function installedRuntimeMatches2(runtimeDirectory, cliPath) {
|
|
1219
|
+
try {
|
|
1220
|
+
await assertFileExists2(cliPath, "local Haven signer CLI");
|
|
1221
|
+
const [signerPackage, sdkPackage] = await Promise.all([
|
|
1222
|
+
readPackageJson2(join(runtimeDirectory, "node_modules", "@haven_ai", "signer", "package.json")),
|
|
1223
|
+
readPackageJson2(join(runtimeDirectory, "node_modules", "@haven_ai", "sdk", "package.json"))
|
|
1224
|
+
]);
|
|
1225
|
+
return signerPackage.version === MCP_RUNTIME_MANIFEST.signerVersion && sdkPackage.version === MCP_RUNTIME_MANIFEST.sdkVersion;
|
|
1226
|
+
} catch {
|
|
1227
|
+
return false;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
async function readPackageJson2(path) {
|
|
1231
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
1232
|
+
}
|
|
1233
|
+
async function writeWrapper2(input) {
|
|
1234
|
+
await mkdir(dirname(input.wrapperPath), { recursive: true, mode: 448 });
|
|
1235
|
+
await chmod(dirname(input.wrapperPath), 448).catch(() => void 0);
|
|
1236
|
+
const source = [
|
|
1237
|
+
"#!/usr/bin/env node",
|
|
1238
|
+
"import { spawn } from 'node:child_process'",
|
|
1239
|
+
"",
|
|
1240
|
+
`const cliPath = ${JSON.stringify(input.cliPath)}`,
|
|
1241
|
+
`const signerPath = ${JSON.stringify(input.signerPath)}`,
|
|
1242
|
+
"",
|
|
1243
|
+
"const child = spawn(process.execPath, [cliPath, '--credentials', signerPath, ...process.argv.slice(2)], {",
|
|
1244
|
+
" stdio: 'inherit',",
|
|
1245
|
+
"})",
|
|
1246
|
+
"",
|
|
1247
|
+
"child.on('exit', (code, signal) => {",
|
|
1248
|
+
" if (signal) process.kill(process.pid, signal)",
|
|
1249
|
+
" else process.exit(code ?? 1)",
|
|
1250
|
+
"})",
|
|
1251
|
+
""
|
|
1252
|
+
].join("\n");
|
|
1253
|
+
await writeFile(input.wrapperPath, source, { mode: 448 });
|
|
1254
|
+
await chmod(input.wrapperPath, 448).catch(() => void 0);
|
|
1255
|
+
}
|
|
1256
|
+
async function writeRuntimeSidecar2(input) {
|
|
1257
|
+
const value = {
|
|
1258
|
+
signer_package: MCP_RUNTIME_MANIFEST.signerPackage,
|
|
1259
|
+
signer_version: MCP_RUNTIME_MANIFEST.signerVersion,
|
|
1260
|
+
sdk_package: MCP_RUNTIME_MANIFEST.sdkPackage,
|
|
1261
|
+
sdk_version: MCP_RUNTIME_MANIFEST.sdkVersion,
|
|
1262
|
+
wrapper_path: input.wrapperPath,
|
|
1263
|
+
runtime_directory: input.runtimeDirectory,
|
|
1264
|
+
npm_cache_directory: input.npmCacheDirectory,
|
|
1265
|
+
cli_path: input.cliPath
|
|
1266
|
+
};
|
|
1267
|
+
await writeFile(input.path, `${JSON.stringify(value, null, 2)}
|
|
1268
|
+
`, { mode: 384 });
|
|
1269
|
+
await chmod(input.path, 384).catch(() => void 0);
|
|
1270
|
+
}
|
|
1271
|
+
async function assertFileExists2(path, label) {
|
|
1272
|
+
try {
|
|
1273
|
+
await access(path);
|
|
1274
|
+
} catch {
|
|
1275
|
+
throw new Error(`Missing ${label}: ${path}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1155
1278
|
async function acknowledgeLocalSignerConsent(signerPath, log) {
|
|
1156
1279
|
try {
|
|
1157
1280
|
const input = await buildSignerConsentInput(signerPath);
|
|
@@ -1223,7 +1346,7 @@ function writeLogChunk2(log, chunk) {
|
|
|
1223
1346
|
}
|
|
1224
1347
|
|
|
1225
1348
|
// src/runtime-install.ts
|
|
1226
|
-
var
|
|
1349
|
+
var execFileAsync3 = promisify(execFile);
|
|
1227
1350
|
async function installRuntime(input, deps = {}) {
|
|
1228
1351
|
const runtime = normalizeRuntime(input.runtime, deps.env);
|
|
1229
1352
|
const profile = runtimeProfile(runtime, deps.env);
|
|
@@ -1284,7 +1407,20 @@ async function installRuntime(input, deps = {}) {
|
|
|
1284
1407
|
]
|
|
1285
1408
|
};
|
|
1286
1409
|
}
|
|
1287
|
-
|
|
1410
|
+
let signerCommand;
|
|
1411
|
+
if (!localRuntime) {
|
|
1412
|
+
try {
|
|
1413
|
+
const signerRuntime = await prepareSignerForRuntime(input, deps);
|
|
1414
|
+
signerCommand = { command: signerRuntime.command, args: signerRuntime.args };
|
|
1415
|
+
consentMessages.push(...signerRuntime.messages);
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
consentMessages.push(
|
|
1418
|
+
`Could not pre-install the local Haven signer; falling back to npx launch: ${err instanceof Error ? err.message : String(err)}`
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
const signerRuntimePrepared = localRuntime ? void 0 : signerCommand !== void 0;
|
|
1423
|
+
const configResult = runtime === "claude-code" ? localRuntime ? await configureClaudeCode(deps, localRuntimeInstall?.command ?? "") : await configureClaudeCodeHosted(deps, input, signerCommand) : await writeRuntimeConfig({
|
|
1288
1424
|
runtime,
|
|
1289
1425
|
hostedMcpUrl: input.hostedMcpUrl,
|
|
1290
1426
|
apiKey: input.apiKey,
|
|
@@ -1292,6 +1428,7 @@ async function installRuntime(input, deps = {}) {
|
|
|
1292
1428
|
signerPath: input.signerPath,
|
|
1293
1429
|
credentialDirectory: input.credentialDirectory,
|
|
1294
1430
|
localMcpCommand: localRuntimeInstall?.command,
|
|
1431
|
+
signerCommand,
|
|
1295
1432
|
homeDir: deps.homeDir,
|
|
1296
1433
|
mode: localRuntime ? "local" : "hosted"
|
|
1297
1434
|
});
|
|
@@ -1323,6 +1460,7 @@ async function installRuntime(input, deps = {}) {
|
|
|
1323
1460
|
localMcpAcknowledged: localMcpConsent?.acknowledged,
|
|
1324
1461
|
activationCommand: configResult.activationCommand,
|
|
1325
1462
|
skillInstalled: skillInstall?.installed,
|
|
1463
|
+
signerRuntimePrepared,
|
|
1326
1464
|
messages: [...consentMessages, ...localRuntimeInstall?.messages ?? [], ...configResult.messages, ...localProbeMessages, ...skillInstall?.messages ?? []]
|
|
1327
1465
|
};
|
|
1328
1466
|
}
|
|
@@ -1379,7 +1517,7 @@ async function configureClaudeCode(deps, localMcpCommand) {
|
|
|
1379
1517
|
};
|
|
1380
1518
|
}
|
|
1381
1519
|
}
|
|
1382
|
-
async function configureClaudeCodeHosted(deps, input) {
|
|
1520
|
+
async function configureClaudeCodeHosted(deps, input, signerCommand) {
|
|
1383
1521
|
const runCommand = deps.runCommand ?? defaultRunCommand;
|
|
1384
1522
|
const hostedJson = JSON.stringify({
|
|
1385
1523
|
type: "http",
|
|
@@ -1388,8 +1526,8 @@ async function configureClaudeCodeHosted(deps, input) {
|
|
|
1388
1526
|
});
|
|
1389
1527
|
const signerJson = JSON.stringify({
|
|
1390
1528
|
type: "stdio",
|
|
1391
|
-
command: "npx",
|
|
1392
|
-
args: ["-y", signerPackageSpec(), "--credentials", input.signerPath],
|
|
1529
|
+
command: signerCommand?.command ?? "npx",
|
|
1530
|
+
args: signerCommand?.args ?? ["-y", signerPackageSpec(), "--credentials", input.signerPath],
|
|
1393
1531
|
env: {}
|
|
1394
1532
|
});
|
|
1395
1533
|
try {
|
|
@@ -1430,7 +1568,7 @@ async function configureClaudeCodeHosted(deps, input) {
|
|
|
1430
1568
|
}
|
|
1431
1569
|
}
|
|
1432
1570
|
async function defaultRunCommand(command, args) {
|
|
1433
|
-
await
|
|
1571
|
+
await execFileAsync3(command, args, { timeout: 1e4 });
|
|
1434
1572
|
}
|
|
1435
1573
|
async function installClaudeSkill(homeDir) {
|
|
1436
1574
|
try {
|
|
@@ -1513,6 +1651,14 @@ async function prepareRuntimeForLocalMcp(input, deps) {
|
|
|
1513
1651
|
homeDir: deps.homeDir
|
|
1514
1652
|
});
|
|
1515
1653
|
}
|
|
1654
|
+
async function prepareSignerForRuntime(input, deps) {
|
|
1655
|
+
const prepare = deps.prepareSignerRuntime ?? ((runtimeInput) => prepareSignerRuntime(runtimeInput, { runCommand: deps.runCommand }));
|
|
1656
|
+
return prepare({
|
|
1657
|
+
credentialDirectory: input.credentialDirectory,
|
|
1658
|
+
signerPath: input.signerPath,
|
|
1659
|
+
homeDir: deps.homeDir
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1516
1662
|
async function runLocalMcpProbe(runtimeInstall, deps) {
|
|
1517
1663
|
const probe = deps.probeLocalMcpTools ?? probeLocalMcpTools;
|
|
1518
1664
|
try {
|
|
@@ -1529,7 +1675,7 @@ function localRuntimePrepareErrorCode(err) {
|
|
|
1529
1675
|
}
|
|
1530
1676
|
|
|
1531
1677
|
// src/runtime.ts
|
|
1532
|
-
var CONNECTOR_VERSION = "0.1.
|
|
1678
|
+
var CONNECTOR_VERSION = "0.1.13-alpha.0";
|
|
1533
1679
|
async function runConnect(options, deps = {}) {
|
|
1534
1680
|
const connectorVersion = options.connectorVersion ?? CONNECTOR_VERSION;
|
|
1535
1681
|
const api = deps.api ?? createConnectApiClient(options.apiBaseUrl);
|