@haven_ai/connect 0.0.0-dev.202609230656.9b1d80a → 0.0.0-dev.202609231741.b88d644

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
@@ -159,7 +159,9 @@ minutes. Two rules follow:
159
159
  This replaces the directory's signer wrapper with a diagnostic that logs the
160
160
  retirement (agent id, date, reason, restart guidance) to the host's MCP
161
161
  stderr log on every probe, and records it in `TOMBSTONE.json` for
162
- `--doctor`. It touches no key material and revokes nothing — revoke the
162
+ `--doctor` — with a copy in `~/.haven/tombstones/` (or `.tombstones/` inside
163
+ a custom credentials root), so the retirement stays visible after the
164
+ directory is deleted. It touches no key material and revokes nothing — revoke the
163
165
  agent on the Haven agent page yourself. Delete the tombstone only once every
164
166
  long-lived host has been restarted.
165
167
 
package/dist/cli.cjs CHANGED
@@ -619,9 +619,9 @@ var init_runtime_manifest = __esm({
619
619
  mcpPackage: "@haven_ai/mcp",
620
620
  mcpVersion: mcp.MCP_VERSION,
621
621
  sdkPackage: "@haven_ai/sdk",
622
- sdkVersion: "0.0.0-dev.202609230656.9b1d80a",
622
+ sdkVersion: "0.0.0-dev.202609231741.b88d644",
623
623
  signerPackage: "@haven_ai/signer",
624
- signerVersion: "0.0.0-dev.202609230656.9b1d80a",
624
+ signerVersion: "0.0.0-dev.202609231741.b88d644",
625
625
  // Sourced from the SDK, never a literal (#1161). This field read '20.0.0'
626
626
  // while every package's `engines` said `>=24` and the docs said `>=24.0.0`,
627
627
  // so the guard that was supposed to enforce the floor waved Node v23 through
@@ -1590,7 +1590,7 @@ async function probeLocalSignerCredential(signerPath) {
1590
1590
  }
1591
1591
  }
1592
1592
  async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4) {
1593
- return new Promise((resolve10) => {
1593
+ return new Promise((resolve11) => {
1594
1594
  const child = child_process.spawn(command, args, { stdio: ["pipe", "pipe", "ignore"] });
1595
1595
  let stdout = "";
1596
1596
  let settled = false;
@@ -1602,7 +1602,7 @@ async function probeLocalMcpTools(command, args, requiredTools, timeoutMs = 1e4)
1602
1602
  settled = true;
1603
1603
  clearTimeout(timeout);
1604
1604
  child.kill();
1605
- resolve10(result);
1605
+ resolve11(result);
1606
1606
  };
1607
1607
  const timeout = setTimeout(() => finish({ status: "timeout" }), timeoutMs);
1608
1608
  child.on("error", () => finish({ status: "process_error" }));
@@ -3000,16 +3000,28 @@ var init_runtime_install = __esm({
3000
3000
  // src/tombstone.ts
3001
3001
  var tombstone_exports = {};
3002
3002
  __export(tombstone_exports, {
3003
+ ROOT_TOMBSTONES_DIRNAME: () => ROOT_TOMBSTONES_DIRNAME,
3003
3004
  TOMBSTONE_FILENAME: () => TOMBSTONE_FILENAME,
3004
3005
  TOMBSTONE_MARKER: () => TOMBSTONE_MARKER,
3005
3006
  defaultTombstonesDir: () => defaultTombstonesDir,
3006
3007
  readAgentTombstone: () => readAgentTombstone,
3007
3008
  readTombstoneRecords: () => readTombstoneRecords,
3009
+ tombstonesDirForAgentDirectory: () => tombstonesDirForAgentDirectory,
3010
+ tombstonesDirForCredentialRoot: () => tombstonesDirForCredentialRoot,
3008
3011
  writeAgentTombstone: () => writeAgentTombstone
3009
3012
  });
3010
3013
  function defaultTombstonesDir(baseDir) {
3011
3014
  return path.join(baseDir ?? path.join(os.homedir(), ".haven"), "tombstones");
3012
3015
  }
3016
+ function tombstonesDirForCredentialRoot(credentialRoot, homeDir = os.homedir()) {
3017
+ if (!credentialRoot) return defaultTombstonesDir(path.join(homeDir, ".haven"));
3018
+ const root = path.resolve(credentialRoot);
3019
+ if (root === path.resolve(homeDir, ".haven", "agents")) return defaultTombstonesDir(path.join(homeDir, ".haven"));
3020
+ return path.join(root, ROOT_TOMBSTONES_DIRNAME);
3021
+ }
3022
+ function tombstonesDirForAgentDirectory(directory, homeDir = os.homedir()) {
3023
+ return tombstonesDirForCredentialRoot(path.dirname(path.resolve(directory)), homeDir);
3024
+ }
3013
3025
  async function readTombstoneRecords(tombstonesDir) {
3014
3026
  const root = tombstonesDir ?? defaultTombstonesDir();
3015
3027
  let entries = [];
@@ -3100,12 +3112,13 @@ async function readAgentTombstone(directory) {
3100
3112
  return null;
3101
3113
  }
3102
3114
  }
3103
- var TOMBSTONE_FILENAME, MIRROR_MODE, TOMBSTONE_MARKER;
3115
+ var TOMBSTONE_FILENAME, ROOT_TOMBSTONES_DIRNAME, MIRROR_MODE, TOMBSTONE_MARKER;
3104
3116
  var init_tombstone = __esm({
3105
3117
  "src/tombstone.ts"() {
3106
3118
  init_redact();
3107
3119
  init_connect_error();
3108
3120
  TOMBSTONE_FILENAME = "TOMBSTONE.json";
3121
+ ROOT_TOMBSTONES_DIRNAME = ".tombstones";
3109
3122
  MIRROR_MODE = 384;
3110
3123
  TOMBSTONE_MARKER = "HAVEN-TOMBSTONE";
3111
3124
  }
@@ -4330,7 +4343,8 @@ async function runDoctor(input, deps = {}) {
4330
4343
  if (retired.length > 0) parts.push(`tombstoned (keys removed): ${retired.join(", ")}`);
4331
4344
  if (unverifiable.length > 0) parts.push(`could not verify: ${unverifiable.join(", ")}`);
4332
4345
  const knownIds = new Set([...inventory].map((e) => e.agentId ?? path.basename(e.directory)));
4333
- const ghostRecords = (await readTombstoneRecords(path.join(homeDir, ".haven", "tombstones"))).filter(
4346
+ const ledgerDir = input.credentialsDir ? tombstonesDirForAgentDirectory(input.credentialsDir, homeDir) : path.join(homeDir, ".haven", "tombstones");
4347
+ const ghostRecords = (await readTombstoneRecords(ledgerDir)).filter(
4334
4348
  (rec) => !knownIds.has(rec.agent_id)
4335
4349
  );
4336
4350
  if (ghostRecords.length > 0) {
@@ -4828,9 +4842,10 @@ async function pathExists2(path) {
4828
4842
 
4829
4843
  // src/runtime.ts
4830
4844
  init_unwire();
4845
+ init_tombstone();
4831
4846
  init_local_mcp_runtime();
4832
4847
  init_runtime_manifest();
4833
- var CONNECTOR_VERSION = "0.0.0-dev.202609230656.9b1d80a";
4848
+ var CONNECTOR_VERSION = "0.0.0-dev.202609231741.b88d644";
4834
4849
  var CONNECT_OUTCOME_SCHEMA_VERSION = 1;
4835
4850
  var failureOutcomesByError = /* @__PURE__ */ new WeakMap();
4836
4851
  function failureOutcomeFor(runtimeHint, error) {
@@ -5132,7 +5147,10 @@ async function executeConnect(options, deps, trace) {
5132
5147
  directory: entry.directory,
5133
5148
  agentId: entry.agentId,
5134
5149
  reason: "replaced by a new setup (--replace)",
5135
- replacedBy: registration.agent_id
5150
+ replacedBy: registration.agent_id,
5151
+ // #3251: the ledger follows this run's credential root (default
5152
+ // root → ~/.haven/tombstones, as before; any other → <root>/.tombstones).
5153
+ tombstonesDir: tombstonesDirForCredentialRoot(options.credentialsDir)
5136
5154
  });
5137
5155
  await teardownLocalKeyMaterial(entry.directory, await readIdentityFile(entry.directory));
5138
5156
  await clearMcpServerBinding(entry.directory);
@@ -5459,7 +5477,7 @@ function describeWaitBound(timeoutMs) {
5459
5477
  async function waitForBudgetApproval(api, setupId, apiKey, log, options = {}) {
5460
5478
  const intervalMs = options.intervalMs ?? 5e3;
5461
5479
  const timeoutMs = options.timeoutMs ?? 18e4;
5462
- const sleep = options.sleep ?? ((ms) => new Promise((resolve10) => setTimeout(resolve10, ms)));
5480
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms)));
5463
5481
  const maxPolls = Math.max(1, Math.floor(timeoutMs / intervalMs));
5464
5482
  const remindEvery = Math.max(1, Math.floor(3e4 / intervalMs));
5465
5483
  let waitingAnnounced = false;
@@ -5932,7 +5950,7 @@ async function runCli(argv, io = {
5932
5950
  return 0;
5933
5951
  }
5934
5952
  if (parsed.tombstone) {
5935
- const { writeAgentTombstone: writeAgentTombstone2 } = await Promise.resolve().then(() => (init_tombstone(), tombstone_exports));
5953
+ const { writeAgentTombstone: writeAgentTombstone2, tombstonesDirForAgentDirectory: tombstonesDirForAgentDirectory2 } = await Promise.resolve().then(() => (init_tombstone(), tombstone_exports));
5936
5954
  const { readFile: readFile15 } = await import('fs/promises');
5937
5955
  const { join: join13 } = await import('path');
5938
5956
  try {
@@ -5948,7 +5966,11 @@ async function runCli(argv, io = {
5948
5966
  directory: parsed.tombstone.directory,
5949
5967
  agentId,
5950
5968
  reason: parsed.tombstone.reason ?? "retired by operator via --tombstone",
5951
- replacedBy: parsed.tombstone.replacedBy
5969
+ replacedBy: parsed.tombstone.replacedBy,
5970
+ // #3251: the ledger of the root that holds the retired directory —
5971
+ // ~/.haven/agents/<x> → ~/.haven/tombstones, exactly as before; a
5972
+ // directory under any other root → <root>/.tombstones.
5973
+ tombstonesDir: tombstonesDirForAgentDirectory2(parsed.tombstone.directory)
5952
5974
  });
5953
5975
  if (parsed.json) {
5954
5976
  io.stdout(`${redactSecrets(JSON.stringify({ tombstoned: true, ...info }))}
@@ -5977,6 +5999,7 @@ async function runCli(argv, io = {
5977
5999
  }
5978
6000
  if (parsed.unwire) {
5979
6001
  const { unwireAgent: unwireAgent2 } = await Promise.resolve().then(() => (init_unwire(), unwire_exports));
6002
+ const { tombstonesDirForAgentDirectory: tombstonesDirForAgentDirectory2 } = await Promise.resolve().then(() => (init_tombstone(), tombstone_exports));
5980
6003
  const { homedir: homedir11 } = await import('os');
5981
6004
  const { join: join13 } = await import('path');
5982
6005
  const homeDir = homedir11();
@@ -5989,7 +6012,14 @@ async function runCli(argv, io = {
5989
6012
  reason: parsed.unwire.reason,
5990
6013
  replacedBy: parsed.unwire.replacedBy,
5991
6014
  destroyKeyMaterial: parsed.unwire.destroyKeyMaterial,
5992
- homeDir
6015
+ homeDir,
6016
+ // #3251: the ledger of the root that holds the directory being
6017
+ // retired. Derived from the RESOLVED directory, not from
6018
+ // --credentials-dir: `--unwire --credentials-dir <path>` names the agent
6019
+ // directory itself, not a root. ~/.haven/agents/<slug> →
6020
+ // ~/.haven/tombstones, exactly as before; any other root →
6021
+ // <root>/.tombstones.
6022
+ tombstonesDir: tombstonesDirForAgentDirectory2(directory, homeDir)
5993
6023
  });
5994
6024
  const failures = result.runtimes.filter((r) => r.status === "refused" || r.status === "unreadable");
5995
6025
  const retained = result.teardown.status === "retained";