@haven_ai/connect 0.0.0-dev.202609051302.7cc48d5 → 0.0.0-dev.202609051933.cc65a9d

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 CHANGED
@@ -215,8 +215,22 @@ and the API key travels beside it in a header.
215
215
  re-run mints a NEW agent, and without `--replace` retires nothing, so those
216
216
  older agents still hold live API and signing keys — revoke them on the Haven
217
217
  agent page if you meant to replace them. Empty on a clean first run; an empty
218
- list is not a guarantee, since a scan that cannot read the credential root also
219
- yields one rather than failing a completed setup. On a `--replace` run, `retired_agent_ids` names the
218
+ list here is not a guarantee, since a scan that cannot read the credential root
219
+ also yields one rather than failing a completed setup.
220
+
221
+ **The dashboard offers the revoke, never the connector (#2561).** The same ids
222
+ now ride the install-status report, so the Haven dashboard can put a
223
+ one-click revoke next to the setup that displaced them. The connector does not
224
+ and must not do it: `POST /agents/:id/revoke` is owner-authenticated, and an
225
+ agent credential retiring a sibling agent is the "agent editing its own
226
+ authority" the re-key routes refuse. Nothing is revoked automatically — the
227
+ owner clicks, one agent at a time.
228
+
229
+ On the REPORT the field is a tri-state, unlike the `--json` outcome above: a
230
+ list, `[]` when the scan ran and found none, and `null` when it could not run.
231
+ That is the same ambiguity this paragraph warns you about, made machine-
232
+ readable, so a dashboard never tells somebody their machine is clean when
233
+ nobody managed to read it. On a `--replace` run, `retired_agent_ids` names the
220
234
  directories that were actually tombstoned and had their local key files removed
221
235
  — **the collision set only**, never the whole `superseded_agent_ids` list, which
222
236
  also names named agents that coexist with the replaced bare pair and are
package/dist/cli.cjs CHANGED
@@ -91,7 +91,21 @@ function createConnectApiClient(baseUrl, fetchImpl = fetch) {
91
91
  restart_required: input.restartRequired,
92
92
  next_user_action: input.nextUserAction,
93
93
  error_code: input.errorCode ?? null,
94
- environment_label: input.environmentLabel
94
+ environment_label: input.environmentLabel,
95
+ // Three states on the wire, and ABSENT is a fourth (#2561 review).
96
+ // `?? null` alone collapsed the fourth into the third: a report that
97
+ // simply had nothing to say — the early config-written ping, which
98
+ // fires before the scan has started — asserted "the scan could not
99
+ // run" instead of leaving the key alone. Inert today, because the
100
+ // complete report overwrites it seconds later and nothing reads the
101
+ // row in between; a landmine the moment any caller relies on
102
+ // "absent = unchanged", which is what the backend's jsonb merge
103
+ // means and what this field's own contract says.
104
+ //
105
+ // So: a caller that passes the field says something (`null` included,
106
+ // deliberately, since "could not run" is a claim worth making); a
107
+ // caller that omits it says nothing.
108
+ ...input.supersededAgentIds !== void 0 ? { superseded_agent_ids: input.supersededAgentIds } : {}
95
109
  })
96
110
  });
97
111
  }
@@ -536,9 +550,9 @@ var init_runtime_manifest = __esm({
536
550
  mcpPackage: "@haven_ai/mcp",
537
551
  mcpVersion: mcp.MCP_VERSION,
538
552
  sdkPackage: "@haven_ai/sdk",
539
- sdkVersion: "0.0.0-dev.202609051302.7cc48d5",
553
+ sdkVersion: "0.0.0-dev.202609051933.cc65a9d",
540
554
  signerPackage: "@haven_ai/signer",
541
- signerVersion: "0.0.0-dev.202609051302.7cc48d5",
555
+ signerVersion: "0.0.0-dev.202609051933.cc65a9d",
542
556
  // Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
543
557
  // while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
544
558
  // so the guard that was supposed to enforce the floor waved Node v23 through
@@ -4389,7 +4403,7 @@ async function pathExists2(path) {
4389
4403
  init_unwire();
4390
4404
  init_local_mcp_runtime();
4391
4405
  init_runtime_manifest();
4392
- var CONNECTOR_VERSION = "0.0.0-dev.202609051302.7cc48d5";
4406
+ var CONNECTOR_VERSION = "0.0.0-dev.202609051933.cc65a9d";
4393
4407
  var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
4394
4408
  var failureOutcomesByError = /* @__PURE__ */ new WeakMap();
4395
4409
  function failureOutcomeFor(runtimeHint, error) {
@@ -4667,9 +4681,11 @@ async function executeConnect(options, deps, trace) {
4667
4681
  }
4668
4682
  }
4669
4683
  }
4684
+ let supersededScan = null;
4670
4685
  let supersededAgentIds = [];
4671
4686
  try {
4672
- supersededAgentIds = await listOtherAgentIds(options.credentialsDir, credentialPaths.directory);
4687
+ supersededScan = await listOtherAgentIds(options.credentialsDir, credentialPaths.directory);
4688
+ supersededAgentIds = supersededScan ?? [];
4673
4689
  if (supersededAgentsRetiredLocally === true) {
4674
4690
  log("");
4675
4691
  log(
@@ -4703,7 +4719,11 @@ async function executeConnect(options, deps, trace) {
4703
4719
  restartRequired: runtimeInstall.restartRequired,
4704
4720
  nextUserAction: runtimeInstall.nextUserAction,
4705
4721
  errorCode: runtimeInstall.errorCode,
4706
- environmentLabel: options.environmentLabel ?? "Local workspace"
4722
+ environmentLabel: options.environmentLabel ?? "Local workspace",
4723
+ // The raw scan result, `null` and all — NOT the flattened
4724
+ // `supersededAgentIds` the outcome carries. Flattening here would hand
4725
+ // the dashboard the same ambiguity this field exists to remove (#2561).
4726
+ supersededAgentIds: supersededScan
4707
4727
  });
4708
4728
  } catch (err) {
4709
4729
  log(`Could not report install status to Haven: ${err instanceof Error ? err.message : String(err)}`);
@@ -5066,7 +5086,7 @@ async function listOtherAgentIds(baseDir, currentDirectory) {
5066
5086
  try {
5067
5087
  entries = await promises.readdir(root);
5068
5088
  } catch {
5069
- return [];
5089
+ return null;
5070
5090
  }
5071
5091
  const ids = [];
5072
5092
  for (const entry of entries) {