@haven_ai/connect 0.0.0-dev.202609042048.ad6cc9b → 0.0.0-dev.202609050705.51c3d92
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/README.md +15 -3
- package/dist/cli.cjs +38 -16
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +38 -16
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +38 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -4
- package/dist/index.d.ts +41 -4
- package/dist/index.js +38 -16
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -169,11 +169,11 @@ Pass `--json` when a launcher needs a machine-readable completion record. Connec
|
|
|
169
169
|
writes progress and human recovery notes to stderr and exactly one JSON object
|
|
170
170
|
to stdout, with `schema_version: 1` and `outcome` set to `complete`,
|
|
171
171
|
`action_required`, or `failed`. Structured runs skip the interactive
|
|
172
|
-
budget-approval wait so the record is emitted promptly;
|
|
173
|
-
|
|
172
|
+
budget-approval wait so the record is emitted promptly; open `approval.url`
|
|
173
|
+
whenever ready and verify later with the read-only `haven_get_agent`
|
|
174
174
|
tool. The object includes runtime/topology status,
|
|
175
175
|
probe result, activation and next-action guidance, approval state/expiry (null
|
|
176
|
-
when the backend does not provide an approval expiry)
|
|
176
|
+
when the backend does not provide an approval expiry) and `approval.url`, the two
|
|
177
177
|
read-only verification tools, `hosted_mcp_url`, `superseded_agent_ids`, and —
|
|
178
178
|
on a run that replaced existing wiring — `superseded_agents_retired_locally`
|
|
179
179
|
with `retired_agent_ids`. It
|
|
@@ -182,6 +182,18 @@ contents, full credential paths, or full delegate address. The same redacted
|
|
|
182
182
|
object is available to library callers as `runConnect(...).outcome`; the older
|
|
183
183
|
fields remain for additive compatibility.
|
|
184
184
|
|
|
185
|
+
`approval.url` (#2528) is the absolute link to this setup's budget approval,
|
|
186
|
+
returned by the backend at register. Present only when `approval.required` is
|
|
187
|
+
`true` **and** the backend is new enough to send one — a deployment older than
|
|
188
|
+
#2528 omits the key entirely, which is why a caller must test for it rather
|
|
189
|
+
than assume it. In prose mode the same link replaces "Return to Haven" in the
|
|
190
|
+
printed next steps. It carries no secret (the setup token never appears in it),
|
|
191
|
+
and it is the ONLY approval link a caller should use: the outcome carries no
|
|
192
|
+
setup id, so there is nothing to assemble one from — relay the whole link or
|
|
193
|
+
none. The connector also reports `run_mode` (`json` or `prose`) to the backend
|
|
194
|
+
at register, so Haven can tell an automated setup from a narrated one; it is
|
|
195
|
+
sent, not returned, and appears in no output.
|
|
196
|
+
|
|
185
197
|
`hosted_mcp_url` is the hosted MCP endpoint this run wired up — **not** the
|
|
186
198
|
backend URL you passed as `--api`. The hosted MCP server is a separate
|
|
187
199
|
deployment, so the two differing is intended topology, not an environment
|
package/dist/cli.cjs
CHANGED
|
@@ -55,6 +55,7 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
|
|
|
55
55
|
runtime: input.runtime,
|
|
56
56
|
connector_version: input.connectorVersion,
|
|
57
57
|
mcp_server_name: input.mcpServerName,
|
|
58
|
+
run_mode: input.runMode,
|
|
58
59
|
connector_context: input.connectorContext,
|
|
59
60
|
install_capabilities: input.installCapabilities && {
|
|
60
61
|
can_write_runtime_config: input.installCapabilities.canWriteRuntimeConfig,
|
|
@@ -535,9 +536,9 @@ var init_runtime_manifest = __esm({
|
|
|
535
536
|
mcpPackage: "@haven_ai/mcp",
|
|
536
537
|
mcpVersion: mcp.MCP_VERSION,
|
|
537
538
|
sdkPackage: "@haven_ai/sdk",
|
|
538
|
-
sdkVersion: "0.0.0-dev.
|
|
539
|
+
sdkVersion: "0.0.0-dev.202609050705.51c3d92",
|
|
539
540
|
signerPackage: "@haven_ai/signer",
|
|
540
|
-
signerVersion: "0.0.0-dev.
|
|
541
|
+
signerVersion: "0.0.0-dev.202609050705.51c3d92",
|
|
541
542
|
// Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
|
|
542
543
|
// while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
|
|
543
544
|
// so the guard that was supposed to enforce the floor waved Node v23 through
|
|
@@ -4388,7 +4389,7 @@ async function pathExists2(path) {
|
|
|
4388
4389
|
init_unwire();
|
|
4389
4390
|
init_local_mcp_runtime();
|
|
4390
4391
|
init_runtime_manifest();
|
|
4391
|
-
var CONNECTOR_VERSION = "0.0.0-dev.
|
|
4392
|
+
var CONNECTOR_VERSION = "0.0.0-dev.202609050705.51c3d92";
|
|
4392
4393
|
var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
|
|
4393
4394
|
var failureOutcomesByError = /* @__PURE__ */ new WeakMap();
|
|
4394
4395
|
function failureOutcomeFor(runtimeHint, error) {
|
|
@@ -4536,6 +4537,9 @@ async function executeConnect(options, deps, trace) {
|
|
|
4536
4537
|
// slug — `serverNamesFor` is the one place the naming rule lives, and
|
|
4537
4538
|
// the hosted name is what a user pastes into an MCP config.
|
|
4538
4539
|
mcpServerName: serverNamesFor(serverName).hosted,
|
|
4540
|
+
// #2528: 'prose' is the default because it is what a caller who says
|
|
4541
|
+
// nothing is doing — the library entry point is not a --json run.
|
|
4542
|
+
runMode: options.runMode ?? "prose",
|
|
4539
4543
|
connectorContext: {
|
|
4540
4544
|
environment_label: options.environmentLabel ?? "Local workspace",
|
|
4541
4545
|
config_target: installCapabilities.canWriteRuntimeConfig ? "agent runtime MCP config" : "local credential files"
|
|
@@ -4623,7 +4627,7 @@ async function executeConnect(options, deps, trace) {
|
|
|
4623
4627
|
environmentLabel: options.environmentLabel ?? "Local workspace"
|
|
4624
4628
|
});
|
|
4625
4629
|
if (!early.errorCode || early.errorCode === "manual_runtime_setup_required") {
|
|
4626
|
-
log(approveBudgetCta(setup));
|
|
4630
|
+
log(approveBudgetCta(setup, registration.approval_url));
|
|
4627
4631
|
}
|
|
4628
4632
|
} catch {
|
|
4629
4633
|
}
|
|
@@ -4709,7 +4713,7 @@ async function executeConnect(options, deps, trace) {
|
|
|
4709
4713
|
if (narrateApprovalWait && !runtimeInstall.errorCode) {
|
|
4710
4714
|
approval = await waitForBudgetApproval(api, registration.setup_id, localApiKey, log, options.approvalWait);
|
|
4711
4715
|
}
|
|
4712
|
-
printNextSteps(runtimeInstall, log, approval);
|
|
4716
|
+
printNextSteps(runtimeInstall, log, approval, registration.approval_url);
|
|
4713
4717
|
const outcome = completionOutcome({
|
|
4714
4718
|
runtimeInstall,
|
|
4715
4719
|
delegateAddress: registration.delegate_address,
|
|
@@ -4718,7 +4722,8 @@ async function executeConnect(options, deps, trace) {
|
|
|
4718
4722
|
supersededAgentsRetiredLocally,
|
|
4719
4723
|
...replacing ? { retiredAgentIds } : {},
|
|
4720
4724
|
setupChallengeExpiresAt: setup.challenge.expires_at,
|
|
4721
|
-
approvalRequired: registration.agent_status === "pending_approval"
|
|
4725
|
+
approvalRequired: registration.agent_status === "pending_approval",
|
|
4726
|
+
approvalUrl: registration.approval_url
|
|
4722
4727
|
});
|
|
4723
4728
|
if (await recordConnectOutcome(deps, credentialPaths.directory, outcome)) {
|
|
4724
4729
|
log(`Saved this run's outcome to ${CONNECT_OUTCOME_FILENAME} in the agent's credential directory.`);
|
|
@@ -4751,7 +4756,16 @@ function completionOutcome(input) {
|
|
|
4751
4756
|
instruction: manualSetup ? "Finish the manual MCP setup using the secret-free references shown in normal Connect output, then start a fresh session." : runtimeProfile(runtimeInstall.runtime).activationInstruction
|
|
4752
4757
|
},
|
|
4753
4758
|
next_action: nextAction2,
|
|
4754
|
-
approval: {
|
|
4759
|
+
approval: {
|
|
4760
|
+
required: input.approvalRequired,
|
|
4761
|
+
expires_at: null,
|
|
4762
|
+
// Only when there is something to approve AND the backend supplied a
|
|
4763
|
+
// link. Never synthesised here: the connector does not know the
|
|
4764
|
+
// dashboard's origin, and a guessed URL is worse than none — it is the
|
|
4765
|
+
// "do not invent one" rule the agent runbook states, applied to the
|
|
4766
|
+
// tool rather than the agent.
|
|
4767
|
+
...input.approvalRequired && input.approvalUrl ? { url: input.approvalUrl } : {}
|
|
4768
|
+
},
|
|
4755
4769
|
verification: {
|
|
4756
4770
|
tools: ["haven_get_agent", "haven_get_allowances"],
|
|
4757
4771
|
instruction: runtimeVerificationInstruction(runtimeInstall.runtime)
|
|
@@ -4872,12 +4886,13 @@ function printSetupSummary(setup, log) {
|
|
|
4872
4886
|
}
|
|
4873
4887
|
log(`Setup challenge expires at ${setup.challenge.expires_at}. If it expires, return to Haven for a fresh setup and rerun Connect \u2014 do not reuse or paste credentials.`);
|
|
4874
4888
|
}
|
|
4875
|
-
function approveBudgetCta(setup) {
|
|
4889
|
+
function approveBudgetCta(setup, approvalUrl) {
|
|
4890
|
+
const where = approvalUrl ? `at ${approvalUrl}` : "in the Haven dashboard";
|
|
4876
4891
|
const budgetPhrase = setup.agent_budget.length > 0 ? setup.agent_budget.map((budget) => `up to ${describeSetupBudget(budget)}`).join(", ") : void 0;
|
|
4877
4892
|
if (budgetPhrase) {
|
|
4878
|
-
return `\u2192 Action needed: approve this agent's budget \u2014 ${budgetPhrase} from ${setup.haven_wallet.name} on ${setup.haven_wallet.network} \u2014
|
|
4893
|
+
return `\u2192 Action needed: approve this agent's budget \u2014 ${budgetPhrase} from ${setup.haven_wallet.name} on ${setup.haven_wallet.network} \u2014 ${where}. The approval button is live now; setup continues here in the meantime.`;
|
|
4879
4894
|
}
|
|
4880
|
-
return
|
|
4895
|
+
return `\u2192 Action needed: approve this agent's budget ${where} \u2014 the approval button is live now. Setup continues here in the meantime.`;
|
|
4881
4896
|
}
|
|
4882
4897
|
function describeSetupBudget(budget) {
|
|
4883
4898
|
return describeApprovedBudget({
|
|
@@ -4999,11 +5014,12 @@ async function waitForBudgetApproval(api, setupId, apiKey, log, options = {}) {
|
|
|
4999
5014
|
);
|
|
5000
5015
|
return "pending";
|
|
5001
5016
|
}
|
|
5002
|
-
function completionHandoffLines(result, approval) {
|
|
5017
|
+
function completionHandoffLines(result, approval, approvalUrl) {
|
|
5018
|
+
const approveStep = approvalUrl ? `Approve the budget at ${approvalUrl}. Approval \u2014 not restarting \u2014 unlocks Haven tools.` : "Return to Haven and approve the budget. Approval \u2014 not restarting \u2014 unlocks Haven tools.";
|
|
5003
5019
|
if (result.errorCode === "manual_runtime_setup_required") {
|
|
5004
5020
|
return [
|
|
5005
5021
|
"Next steps:",
|
|
5006
|
-
|
|
5022
|
+
`1. ${approveStep}`,
|
|
5007
5023
|
"2. Finish the manual MCP setup using the secret-free file references printed above, then start a fresh session in your runtime.",
|
|
5008
5024
|
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
5009
5025
|
];
|
|
@@ -5029,7 +5045,7 @@ function completionHandoffLines(result, approval) {
|
|
|
5029
5045
|
}
|
|
5030
5046
|
return [
|
|
5031
5047
|
"Next steps:",
|
|
5032
|
-
|
|
5048
|
+
`1. ${approveStep}`,
|
|
5033
5049
|
`2. ${activation}`,
|
|
5034
5050
|
`3. ${runtimeVerificationInstruction(result.runtime)}`
|
|
5035
5051
|
];
|
|
@@ -5070,8 +5086,8 @@ async function listOtherAgentIds(baseDir, currentDirectory) {
|
|
|
5070
5086
|
}
|
|
5071
5087
|
return ids;
|
|
5072
5088
|
}
|
|
5073
|
-
function printNextSteps(result, log, approval) {
|
|
5074
|
-
for (const line of completionHandoffLines(result, approval)) log(line);
|
|
5089
|
+
function printNextSteps(result, log, approval, approvalUrl) {
|
|
5090
|
+
for (const line of completionHandoffLines(result, approval, approvalUrl)) log(line);
|
|
5075
5091
|
}
|
|
5076
5092
|
|
|
5077
5093
|
// src/args.ts
|
|
@@ -5583,7 +5599,13 @@ async function runCli(argv, io = {
|
|
|
5583
5599
|
// configure. --json is the automation contract — it must fail with a
|
|
5584
5600
|
// machine-readable code, never block on stdin. runConnect additionally
|
|
5585
5601
|
// requires a real TTY before it prompts.
|
|
5586
|
-
interactive: !parsed.json
|
|
5602
|
+
interactive: !parsed.json,
|
|
5603
|
+
// #2528: reported to the backend at register, so the funnel can tell a
|
|
5604
|
+
// machine-readable run from a narrated one. Read from the SAME
|
|
5605
|
+
// `parsed.json` the three flags above use, rather than inferred later
|
|
5606
|
+
// from `waitForApproval` — that flag is already false for a prose run
|
|
5607
|
+
// with no TTY (#2484), so inferring would mislabel real prose runs.
|
|
5608
|
+
runMode: parsed.json ? "json" : "prose"
|
|
5587
5609
|
},
|
|
5588
5610
|
{
|
|
5589
5611
|
log: (message) => (parsed.json ? io.stderr : io.stdout)(`${message}
|