@adapt-toolkit/a2adapt 0.9.2 → 0.9.3

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.
@@ -3,7 +3,7 @@
3
3
  "name": "a2adapt",
4
4
  "displayName": "a2adapt",
5
5
  "description": "Secure agent-to-agent communication channel over ADAPT: self-sovereign pubkey identity, end-to-end encryption, plan-first execution.",
6
- "version": "0.9.2",
6
+ "version": "0.9.3",
7
7
  "author": {
8
8
  "name": "Adapt Toolkit"
9
9
  },
package/dist/index.js CHANGED
@@ -22512,7 +22512,7 @@ function writeIdentityFile(target, opts, overwrite = false) {
22512
22512
  }
22513
22513
 
22514
22514
  // src/index.ts
22515
- var VERSION = true ? "0.9.2" : "0.0.0-dev";
22515
+ var VERSION = true ? "0.9.3" : "0.0.0-dev";
22516
22516
  var CONFIG = loadConfig();
22517
22517
  var STATE_DIR = CONFIG.stateDir;
22518
22518
  var BROKER_URL = CONFIG.brokerUrl;
@@ -22560,6 +22560,14 @@ var registrarAdBlob = null;
22560
22560
  var sessionBinding = /* @__PURE__ */ new Map();
22561
22561
  var bindingOwner = /* @__PURE__ */ new Map();
22562
22562
  var evictedSessions = /* @__PURE__ */ new Set();
22563
+ var lastActivity = /* @__PURE__ */ new Map();
22564
+ var SESSION_STALE_MS = 3e4;
22565
+ function isSessionAlive(sid) {
22566
+ if (!serversBySession.has(sid)) return false;
22567
+ const last = lastActivity.get(sid);
22568
+ if (last !== void 0 && Date.now() - last > SESSION_STALE_MS) return false;
22569
+ return true;
22570
+ }
22563
22571
  var bindingsSnapshotPath = () => join2(STATE_DIR, "bindings.json");
22564
22572
  function persistBindings() {
22565
22573
  try {
@@ -23112,15 +23120,21 @@ ${json}`);
23112
23120
  const sid = getSessionId();
23113
23121
  const holder = bindingOwner.get(name);
23114
23122
  if (holder && holder !== sid) {
23115
- if (!force) {
23123
+ if (!isSessionAlive(holder)) {
23124
+ log(`auto-reclaiming "${name}" from stale session ${holder.slice(0, 8)}\u2026`);
23125
+ sessionBinding.delete(holder);
23126
+ lastActivity.delete(holder);
23127
+ bindingOwner.delete(name);
23128
+ } else if (!force) {
23116
23129
  return textResult(
23117
23130
  `choose_identity declined: "${name}" is currently bound to another session. Do not retry with force=true on your own \u2014 tell the user the identity is in use elsewhere and ask whether to forcibly rebind it here; only retry with force=true after they explicitly confirm.`,
23118
23131
  true
23119
23132
  );
23133
+ } else {
23134
+ evictedSessions.add(holder);
23135
+ sessionBinding.delete(holder);
23136
+ bindingOwner.delete(name);
23120
23137
  }
23121
- evictedSessions.add(holder);
23122
- sessionBinding.delete(holder);
23123
- bindingOwner.delete(name);
23124
23138
  }
23125
23139
  bindSession(sid, name);
23126
23140
  const id = identities.get(name);
@@ -23527,6 +23541,22 @@ async function main() {
23527
23541
  log("booting wrapper\u2026");
23528
23542
  await bootWrapper();
23529
23543
  startGcTimer();
23544
+ const sessionGcTimer = setInterval(() => {
23545
+ const now = Date.now();
23546
+ for (const [sid, last] of lastActivity) {
23547
+ if (now - last > SESSION_STALE_MS && !transports[sid]) {
23548
+ const name = sessionBinding.get(sid);
23549
+ if (name && bindingOwner.get(name) === sid) bindingOwner.delete(name);
23550
+ sessionBinding.delete(sid);
23551
+ evictedSessions.delete(sid);
23552
+ lastActivity.delete(sid);
23553
+ serversBySession.delete(sid);
23554
+ persistBindings();
23555
+ log(`session ${sid.slice(0, 8)}\u2026 reaped (stale)`);
23556
+ }
23557
+ }
23558
+ }, SESSION_STALE_MS);
23559
+ sessionGcTimer.unref();
23530
23560
  log(`wrapper ready (identities=${identities.size}), starting HTTP server\u2026`);
23531
23561
  const transports = {};
23532
23562
  const httpServer = createHttpServer(async (req, res) => {
@@ -23546,12 +23576,14 @@ async function main() {
23546
23576
  const body = await readBody(req);
23547
23577
  const sessionId = req.headers["mcp-session-id"];
23548
23578
  if (sessionId && transports[sessionId]) {
23579
+ lastActivity.set(sessionId, Date.now());
23549
23580
  await transports[sessionId].handleRequest(req, res, body);
23550
23581
  } else if (!sessionId && isInitializeRequest(body)) {
23551
23582
  const transport = new StreamableHTTPServerTransport({
23552
23583
  sessionIdGenerator: () => randomUUID(),
23553
23584
  onsessioninitialized: (sid) => {
23554
23585
  transports[sid] = transport;
23586
+ lastActivity.set(sid, Date.now());
23555
23587
  serversBySession.set(sid, server);
23556
23588
  log(`session ${sid.slice(0, 8)}\u2026 initialized`);
23557
23589
  }
@@ -23562,6 +23594,7 @@ async function main() {
23562
23594
  if (sid) {
23563
23595
  delete transports[sid];
23564
23596
  serversBySession.delete(sid);
23597
+ lastActivity.delete(sid);
23565
23598
  const name = sessionBinding.get(sid);
23566
23599
  if (name && bindingOwner.get(name) === sid) bindingOwner.delete(name);
23567
23600
  sessionBinding.delete(sid);
@@ -23583,6 +23616,10 @@ async function main() {
23583
23616
  res.end("Invalid or missing session ID");
23584
23617
  return;
23585
23618
  }
23619
+ lastActivity.set(sessionId, Date.now());
23620
+ res.on("close", () => {
23621
+ lastActivity.set(sessionId, Date.now());
23622
+ });
23586
23623
  await transports[sessionId].handleRequest(req, res);
23587
23624
  } else if (req.method === "DELETE") {
23588
23625
  const sessionId = req.headers["mcp-session-id"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adapt-toolkit/a2adapt",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "MCP server daemon for a2adapt — one native ADAPT wrapper hosting N self-sovereign identities, exposing secure agent-to-agent messaging tools over HTTP (Streamable HTTP). Run `a2adapt-mcp start`.",
5
5
  "type": "module",
6
6
  "license": "MIT",